Merge branch 'master' into 'fix_san_build'

# Conflicts:
#   src/modules/module-rtp/apple-midi.h
This commit is contained in:
Wim Taymans 2023-03-10 10:10:25 +00:00
commit 2429674970
7 changed files with 124 additions and 8 deletions

View file

@ -527,6 +527,34 @@ static void recv_state_changed(void *data, bool started, const char *error)
} }
} }
static void recv_send_feedback(void *data, uint32_t seqnum)
{
struct session *sess = data;
struct impl *impl = sess->impl;
struct iovec iov[1];
struct msghdr msg;
struct rtp_apple_midi_rs hdr;
if (!sess->ctrl_ready || !sess->receiving)
return;
spa_zero(hdr);
hdr.cmd = htonl(APPLE_MIDI_CMD_RS);
hdr.ssrc = htonl(sess->ssrc);
hdr.seqnum = htonl(seqnum);
iov[0].iov_base = &hdr;
iov[0].iov_len = sizeof(hdr);
spa_zero(msg);
msg.msg_name = &sess->ctrl_addr;
msg.msg_namelen = sess->ctrl_len;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
send_packet(impl->ctrl_source->fd, &msg);
}
static const struct rtp_stream_events send_stream_events = { static const struct rtp_stream_events send_stream_events = {
RTP_VERSION_STREAM_EVENTS, RTP_VERSION_STREAM_EVENTS,
.destroy = send_destroy, .destroy = send_destroy,
@ -538,6 +566,7 @@ static const struct rtp_stream_events recv_stream_events = {
RTP_VERSION_STREAM_EVENTS, RTP_VERSION_STREAM_EVENTS,
.destroy = recv_destroy, .destroy = recv_destroy,
.state_changed = recv_state_changed, .state_changed = recv_state_changed,
.send_feedback = recv_send_feedback,
}; };
static void free_session(struct session *sess) static void free_session(struct session *sess)
@ -784,6 +813,31 @@ static void parse_apple_midi_cmd_ok(struct impl *impl, bool ctrl, uint8_t *buffe
} }
} }
static void parse_apple_midi_cmd_no(struct impl *impl, bool ctrl, uint8_t *buffer,
ssize_t len, struct sockaddr_storage *sa, socklen_t salen)
{
struct rtp_apple_midi *hdr = (struct rtp_apple_midi*)buffer;
uint32_t initiator = ntohl(hdr->initiator);
struct session *sess;
sess = find_session_by_initiator(impl, initiator, ctrl);
if (sess == NULL || !sess->we_initiated) {
pw_log_warn("received NO from nonexisting session %u", initiator);
return;
}
if (ctrl) {
pw_log_info("got ctrl NO %08x %u", initiator, sess->data_ready);
sess->ctrl_ready = false;
} else {
pw_log_info("got data NO %08x %u, session canceled", initiator,
sess->ctrl_ready);
sess->data_ready = false;
if (!sess->ctrl_ready)
session_update_state(sess, SESSION_STATE_INIT);
}
}
static void parse_apple_midi_cmd_ck(struct impl *impl, bool ctrl, uint8_t *buffer, static void parse_apple_midi_cmd_ck(struct impl *impl, bool ctrl, uint8_t *buffer,
ssize_t len, struct sockaddr_storage *sa, socklen_t salen) ssize_t len, struct sockaddr_storage *sa, socklen_t salen)
{ {
@ -878,6 +932,24 @@ static void parse_apple_midi_cmd_by(struct impl *impl, bool ctrl, uint8_t *buffe
} }
} }
static void parse_apple_midi_cmd_rs(struct impl *impl, bool ctrl, uint8_t *buffer,
ssize_t len, struct sockaddr_storage *sa, socklen_t salen)
{
struct rtp_apple_midi_rs *hdr = (struct rtp_apple_midi_rs*)buffer;
struct session *sess;
uint32_t ssrc, seqnum;
ssrc = ntohl(hdr->ssrc);
sess = find_session_by_ssrc(impl, ssrc);
if (sess == NULL) {
pw_log_warn("unknown SSRC %u", ssrc);
return;
}
seqnum = ntohl(hdr->seqnum);
pw_log_debug("got RS seqnum %u", seqnum);
}
static void parse_apple_midi_cmd(struct impl *impl, bool ctrl, uint8_t *buffer, static void parse_apple_midi_cmd(struct impl *impl, bool ctrl, uint8_t *buffer,
ssize_t len, struct sockaddr_storage *sa, socklen_t salen) ssize_t len, struct sockaddr_storage *sa, socklen_t salen)
{ {
@ -889,12 +961,18 @@ static void parse_apple_midi_cmd(struct impl *impl, bool ctrl, uint8_t *buffer,
case APPLE_MIDI_CMD_OK: case APPLE_MIDI_CMD_OK:
parse_apple_midi_cmd_ok(impl, ctrl, buffer, len, sa, salen); parse_apple_midi_cmd_ok(impl, ctrl, buffer, len, sa, salen);
break; break;
case APPLE_MIDI_CMD_NO:
parse_apple_midi_cmd_no(impl, ctrl, buffer, len, sa, salen);
break;
case APPLE_MIDI_CMD_CK: case APPLE_MIDI_CMD_CK:
parse_apple_midi_cmd_ck(impl, ctrl, buffer, len, sa, salen); parse_apple_midi_cmd_ck(impl, ctrl, buffer, len, sa, salen);
break; break;
case APPLE_MIDI_CMD_BY: case APPLE_MIDI_CMD_BY:
parse_apple_midi_cmd_by(impl, ctrl, buffer, len, sa, salen); parse_apple_midi_cmd_by(impl, ctrl, buffer, len, sa, salen);
break; break;
case APPLE_MIDI_CMD_RS:
parse_apple_midi_cmd_rs(impl, ctrl, buffer, len, sa, salen);
break;
default: default:
break; break;
} }

View file

@ -32,11 +32,18 @@ struct rtp_apple_midi_ck {
uint32_t ts3_l; uint32_t ts3_l;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct rtp_apple_midi_rs {
uint32_t cmd;
uint32_t ssrc;
uint32_t seqnum;
} __attribute__ ((packed));
#define APPLE_MIDI_CMD_IN (0xffff0000 | 'I'<<8 | 'N') #define APPLE_MIDI_CMD_IN (0xffff0000 | 'I'<<8 | 'N')
#define APPLE_MIDI_CMD_NO (0xffff0000 | 'N'<<8 | 'O') #define APPLE_MIDI_CMD_NO (0xffff0000 | 'N'<<8 | 'O')
#define APPLE_MIDI_CMD_OK (0xffff0000 | 'O'<<8 | 'K') #define APPLE_MIDI_CMD_OK (0xffff0000 | 'O'<<8 | 'K')
#define APPLE_MIDI_CMD_CK (0xffff0000 | 'C'<<8 | 'K') #define APPLE_MIDI_CMD_CK (0xffff0000 | 'C'<<8 | 'K')
#define APPLE_MIDI_CMD_BY (0xffff0000 | 'B'<<8 | 'Y') #define APPLE_MIDI_CMD_BY (0xffff0000 | 'B'<<8 | 'Y')
#define APPLE_MIDI_CMD_RS (0xffff0000 | 'R'<<8 | 'S')
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -142,7 +142,7 @@ static int receive_rtp_audio(struct impl *impl, uint8_t *buffer, ssize_t len)
if (!impl->have_sync) { if (!impl->have_sync) {
pw_log_info("sync to timestamp:%u seq:%u ts_offset:%u SSRC:%u target:%u direct:%u", pw_log_info("sync to timestamp:%u seq:%u ts_offset:%u SSRC:%u target:%u direct:%u",
write, impl->seq-1, impl->ts_offset, impl->ssrc, timestamp, seq, impl->ts_offset, impl->ssrc,
impl->target_buffer, impl->direct_timestamp); impl->target_buffer, impl->direct_timestamp);
/* we read from timestamp, keeping target_buffer of data /* we read from timestamp, keeping target_buffer of data

View file

@ -126,6 +126,13 @@ static int get_midi_size(uint8_t *p, uint32_t avail)
} }
return size; return size;
} }
static int parse_journal(struct impl *impl, uint8_t *packet, uint16_t seq, uint32_t len)
{
struct rtp_midi_journal *j = (struct rtp_midi_journal*)packet;
uint16_t seqnum = ntohs(j->checkpoint_seqnum);
rtp_stream_emit_send_feedback(impl, seqnum);
return 0;
}
static double get_time(struct impl *impl) static double get_time(struct impl *impl)
{ {
@ -143,8 +150,8 @@ static double get_time(struct impl *impl)
return t; return t;
} }
static int receive_midi(struct impl *impl, uint8_t *packet, static int receive_midi(struct impl *impl, uint8_t *packet, uint32_t timestamp,
uint32_t timestamp, uint32_t payload_offset, uint32_t plen) uint16_t seq, uint32_t payload_offset, uint32_t plen)
{ {
uint32_t write; uint32_t write;
struct rtp_midi_header *hdr; struct rtp_midi_header *hdr;
@ -160,7 +167,7 @@ static int receive_midi(struct impl *impl, uint8_t *packet,
* midi events and render them in the corresponding cycle */ * midi events and render them in the corresponding cycle */
if (!impl->have_sync) { if (!impl->have_sync) {
pw_log_info("sync to timestamp:%u seq:%u ts_offset:%u SSRC:%u direct:%d", pw_log_info("sync to timestamp:%u seq:%u ts_offset:%u SSRC:%u direct:%d",
timestamp, impl->seq-1, impl->ts_offset, impl->ssrc, timestamp, seq, impl->ts_offset, impl->ssrc,
impl->direct_timestamp); impl->direct_timestamp);
impl->have_sync = true; impl->have_sync = true;
} }
@ -186,7 +193,7 @@ static int receive_midi(struct impl *impl, uint8_t *packet,
spa_dll_set_bw(&impl->dll, SPA_DLL_BW_MIN, 256, impl->rate); spa_dll_set_bw(&impl->dll, SPA_DLL_BW_MIN, 256, impl->rate);
pw_log_info("sync to timestamp:%u seq:%u ts_offset:%u SSRC:%u direct:%d", pw_log_info("sync to timestamp:%u seq:%u ts_offset:%u SSRC:%u direct:%d",
timestamp, impl->seq-1, impl->ts_offset, impl->ssrc, timestamp, seq, impl->ts_offset, impl->ssrc,
impl->direct_timestamp); impl->direct_timestamp);
impl->have_sync = true; impl->have_sync = true;
impl->ring.readindex = impl->ring.writeindex; impl->ring.readindex = impl->ring.writeindex;
@ -221,6 +228,8 @@ static int receive_midi(struct impl *impl, uint8_t *packet,
pw_log_warn("invalid packet %d > %d", end, plen); pw_log_warn("invalid packet %d > %d", end, plen);
return -EINVAL; return -EINVAL;
} }
if (hdr->j)
parse_journal(impl, &packet[end], seq, plen - end);
ptr = SPA_PTROFF(impl->buffer, write & BUFFER_MASK2, void); ptr = SPA_PTROFF(impl->buffer, write & BUFFER_MASK2, void);
@ -258,6 +267,8 @@ static int receive_midi(struct impl *impl, uint8_t *packet,
write += b.state.offset; write += b.state.offset;
spa_ringbuffer_write_update(&impl->ring, write); spa_ringbuffer_write_update(&impl->ring, write);
return 0; return 0;
} }
@ -297,7 +308,7 @@ static int receive_rtp_midi(struct impl *impl, uint8_t *buffer, ssize_t len)
impl->receiving = true; impl->receiving = true;
return receive_midi(impl, buffer, timestamp, hlen, len); return receive_midi(impl, buffer, timestamp, seq, hlen, len);
short_packet: short_packet:
pw_log_warn("short packet received"); pw_log_warn("short packet received");

View file

@ -58,17 +58,34 @@ struct rtp_midi_header {
unsigned z:1; unsigned z:1;
unsigned j:1; unsigned j:1;
unsigned b:1; unsigned b:1;
uint8_t len_b;
#elif __BYTE_ORDER == __BIG_ENDIAN #elif __BYTE_ORDER == __BIG_ENDIAN
unsigned b:1; unsigned b:1;
unsigned j:1; unsigned j:1;
unsigned z:1; unsigned z:1;
unsigned p:1; unsigned p:1;
unsigned len:4; unsigned len:4;
uint8_t len_b;
#endif #endif
uint8_t len_b;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct rtp_midi_journal {
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned totchan:4;
unsigned H:1;
unsigned A:1;
unsigned Y:1;
unsigned S:1;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned S:1;
unsigned Y:1;
unsigned A:1;
unsigned H:1;
unsigned totchan:4;
#endif
uint16_t checkpoint_seqnum;
} __attribute__ ((packed));
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -31,6 +31,7 @@
#define rtp_stream_emit_destroy(s) rtp_stream_emit(s, destroy, 0) #define rtp_stream_emit_destroy(s) rtp_stream_emit(s, destroy, 0)
#define rtp_stream_emit_state_changed(s,n,e) rtp_stream_emit(s, state_changed,0,n,e) #define rtp_stream_emit_state_changed(s,n,e) rtp_stream_emit(s, state_changed,0,n,e)
#define rtp_stream_emit_send_packet(s,i,l) rtp_stream_emit(s, send_packet,0,i,l) #define rtp_stream_emit_send_packet(s,i,l) rtp_stream_emit(s, send_packet,0,i,l)
#define rtp_stream_emit_send_feedback(s,seq) rtp_stream_emit(s, send_feedback,0,seq)
struct impl { struct impl {
struct spa_audio_info info; struct spa_audio_info info;

View file

@ -32,6 +32,8 @@ struct rtp_stream_events {
void (*state_changed) (void *data, bool started, const char *error); void (*state_changed) (void *data, bool started, const char *error);
void (*send_packet) (void *data, struct iovec *iov, size_t iovlen); void (*send_packet) (void *data, struct iovec *iov, size_t iovlen);
void (*send_feedback) (void *data, uint32_t senum);
}; };
struct rtp_stream *rtp_stream_new(struct pw_core *core, struct rtp_stream *rtp_stream_new(struct pw_core *core,