module-rtp: fix sender timestamps

This commit is contained in:
Wim Taymans 2023-03-01 10:54:00 +01:00
parent 7c04b42e38
commit dda5ed696b
3 changed files with 78 additions and 23 deletions

View file

@ -279,8 +279,8 @@ static void send_apple_midi_cmd_in(struct session *sess, bool ctrl)
iov[0].iov_base = &hdr;
iov[0].iov_len = sizeof(hdr);
iov[1].iov_base = sess->name;
iov[1].iov_len = strlen(sess->name);
iov[1].iov_base = impl->session_name;
iov[1].iov_len = strlen(impl->session_name)+1;
spa_zero(msg);
msg.msg_name = ctrl ? &sess->ctrl_addr : &sess->data_addr;
@ -476,6 +476,7 @@ static struct session *find_session_by_addr_name(struct impl *impl,
{
struct session *sess;
spa_list_for_each(sess, &impl->sessions, link) {
pw_log_info("'%s' '%s'", sess->name, name);
if (cmp_ip(sa, &sess->ctrl_addr) &&
spa_streq(sess->name, name))
return sess;
@ -511,10 +512,13 @@ static void parse_apple_midi_cmd_in(struct impl *impl, bool ctrl, uint8_t *buffe
struct rtp_apple_midi reply;
struct session *sess;
bool success = true;
uint32_t initiator = ntohl(hdr->initiator);
uint32_t initiator, ssrc;
char addr[128];
uint16_t port = 0;
initiator = ntohl(hdr->initiator);
ssrc = ntohl(hdr->ssrc);
get_ip(sa, addr, sizeof(addr), &port);
pw_log_info("IN from %s:%d %s", addr, port, hdr->name);
@ -529,13 +533,14 @@ static void parse_apple_midi_cmd_in(struct impl *impl, bool ctrl, uint8_t *buffe
success = false;
}
} else {
struct pw_properties *props;
props = pw_properties_new("sess.name", hdr->name, NULL);
pw_properties_setf(props, "rtp.initiator", "%u", initiator);
pw_properties_setf(props, "rtp.receiver-ssrc", "%u", ssrc);
pw_log_info("got control IN request %08x", initiator);
sess = make_session(impl,
pw_properties_new(
"sess.name", hdr->name,
"rtp.initiator", initiator,
"rtp.receiver-ssrc", ntohl(hdr->ssrc),
NULL));
sess = make_session(impl, props);
if (sess == NULL) {
pw_log_warn("failed to make session: %m");
success = false;
@ -553,6 +558,7 @@ static void parse_apple_midi_cmd_in(struct impl *impl, bool ctrl, uint8_t *buffe
success = false;
} else {
pw_log_info("got data IN request %08x", initiator);
sess->remote_ssrc = ssrc;
sess->data_addr = *sa;
sess->data_len = salen;
sess->data_ready = true;
@ -568,8 +574,8 @@ static void parse_apple_midi_cmd_in(struct impl *impl, bool ctrl, uint8_t *buffe
iov[0].iov_base = &reply;
iov[0].iov_len = sizeof(reply);
iov[1].iov_base = sess->name;
iov[1].iov_len = strlen(sess->name);
iov[1].iov_base = impl->session_name;
iov[1].iov_len = strlen(impl->session_name)+1;
spa_zero(msg);
msg.msg_name = sa;
@ -602,6 +608,7 @@ static void parse_apple_midi_cmd_ok(struct impl *impl, bool ctrl, uint8_t *buffe
send_apple_midi_cmd_in(sess, false);
} else {
pw_log_info("got data OK %08x", initiator);
sess->remote_ssrc = ntohl(hdr->ssrc);
sess->data_ready = true;
}
}

View file

@ -0,0 +1,43 @@
/* PipeWire */
/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans <wim.taymans@gmail.com> */
/* SPDX-License-Identifier: MIT */
#ifndef PIPEWIRE_APPLE_MIDI_H
#define PIPEWIRE_APPLE_MIDI_H
#ifdef __cplusplus
extern "C" {
#endif
struct rtp_apple_midi {
uint32_t cmd;
uint32_t protocol;
uint32_t initiator;
uint32_t ssrc;
char name[0];
} __attribute__ ((packed));
struct rtp_apple_midi_ck {
uint32_t cmd;
uint32_t ssrc;
uint8_t count;
uint8_t padding[3];
uint32_t ts1_h;
uint32_t ts1_l;
uint32_t ts2_h;
uint32_t ts2_l;
uint32_t ts3_h;
uint32_t ts3_l;
} __attribute__ ((packed));
#define APPLE_MIDI_CMD_IN ((0xffff << 16) | 'I'<<8 | 'N')
#define APPLE_MIDI_CMD_NO ((0xffff << 16) | 'N'<<8 | 'O')
#define APPLE_MIDI_CMD_OK ((0xffff << 16) | 'O'<<8 | 'K')
#define APPLE_MIDI_CMD_CK ((0xffff << 16) | 'C'<<8 | 'K')
#define APPLE_MIDI_CMD_BY ((0xffff << 16) | 'B'<<8 | 'Y')
#ifdef __cplusplus
}
#endif
#endif /* PIPEWIRE_APPLE_MIDI_H */

View file

@ -337,7 +337,7 @@ static int write_event(uint8_t *p, uint32_t value, void *ev, uint32_t size)
}
static void flush_midi_packets(struct impl *impl,
struct spa_pod_sequence *sequence, uint32_t timestamp)
struct spa_pod_sequence *sequence, uint32_t timestamp, uint32_t rate)
{
struct spa_pod_control *c;
struct rtp_header header;
@ -363,7 +363,7 @@ static void flush_midi_packets(struct impl *impl,
SPA_POD_SEQUENCE_FOREACH(sequence, c) {
void *ev;
uint32_t size, delta;
uint32_t size, delta, offset;
if (c->type != SPA_CONTROL_Midi)
continue;
@ -371,8 +371,10 @@ static void flush_midi_packets(struct impl *impl,
ev = SPA_POD_BODY(&c->value),
size = SPA_POD_BODY_SIZE(&c->value);
offset = c->offset * impl->rate / rate;
if (len > 0 && (len + size > impl->mtu ||
c->offset - base > impl->psamples)) {
offset - base > impl->psamples)) {
/* flush packet when we have one and when it's either
* too large or has too much data. */
if (len < 16) {
@ -389,7 +391,7 @@ static void flush_midi_packets(struct impl *impl,
pw_log_debug("sending %d timestamp:%d %u %u",
len, timestamp + base,
c->offset, impl->psamples);
offset, impl->psamples);
rtp_stream_emit_send_packet(impl, iov, 3);
impl->seq++;
@ -397,15 +399,15 @@ static void flush_midi_packets(struct impl *impl,
}
if (len == 0) {
/* start new packet */
base = prev_offset = c->offset;
base = prev_offset = offset;
header.sequence_number = htons(impl->seq);
header.timestamp = htonl(impl->ts_offset + timestamp + base);
memcpy(&impl->buffer[len], ev, size);
len += size;
} else {
delta = c->offset - prev_offset;
prev_offset = c->offset;
delta = offset - prev_offset;
prev_offset = offset;
len += write_event(&impl->buffer[len], delta, ev, size);
}
}
@ -434,7 +436,7 @@ static void process_midi_capture(void *data)
struct impl *impl = data;
struct pw_buffer *buf;
struct spa_data *d;
uint32_t offs, size, timestamp;
uint32_t offs, size, timestamp, rate;
struct spa_pod *pod;
void *ptr;
@ -447,10 +449,13 @@ static void process_midi_capture(void *data)
offs = SPA_MIN(d[0].chunk->offset, d[0].maxsize);
size = SPA_MIN(d[0].chunk->size, d[0].maxsize - offs);
if (SPA_LIKELY(impl->io_position))
timestamp = impl->io_position->clock.position;
else
if (SPA_LIKELY(impl->io_position)) {
rate = impl->io_position->clock.rate.denom;
timestamp = impl->io_position->clock.position * impl->rate / rate;
} else {
rate = 10000;
timestamp = 0;
}
ptr = SPA_PTROFF(d[0].data, offs, void);
@ -465,7 +470,7 @@ static void process_midi_capture(void *data)
impl->have_sync = true;
}
flush_midi_packets(impl, (struct spa_pod_sequence*)pod, timestamp);
flush_midi_packets(impl, (struct spa_pod_sequence*)pod, timestamp, rate);
done:
pw_stream_queue_buffer(impl->stream, buf);