diff --git a/daemon/media_socket.c b/daemon/media_socket.c index c4cab2c7a..0d69ecb05 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -1696,6 +1696,14 @@ static const char *kernelize_target(kernelize_state *s, struct packet_stream *st u++; } + for (u = 0; u < RTP_EXT_NUM; u++) { + __auto_type ext = media->extmap_id[u]; + if (!ext) + continue; + if (ext->handler.kernel) + ext->handler.kernel(s, stream->component, media); + } + recording_stream_kernel_info(stream, reti); if (!proto_is_rtp(media->protocol)) @@ -2857,11 +2865,51 @@ static ssize_t rtp_ext_mid_print(void *dst, struct rtp_extension *ext, struct ca return -1; return media->extmap_ops->print(dst, ext->id, &media->media_id); } +__attribute__((nonnull(1, 3))) +static void rtp_ext_mid_kernel(kernelize_state *s, unsigned int component, struct call_media *media) { + struct call_media *bundle = media->bundle; + if (!bundle) + return; + if (!bundle->extmap_id[RTP_EXT_MID]) + return; + if (bundle->extmap_id[RTP_EXT_MID]->id != bundle->extmap_id[RTP_EXT_MID]->id) + return; + + s->reti.extmap = 1; + s->reti.extmap_mid = bundle->extmap_id[RTP_EXT_MID]->id; + + struct call_monologue *ml = bundle->monologue; + + for (unsigned int i = 0; i < ml->medias->len; i++) { + media = ml->medias->pdata[i]; + if (!media) + continue; + if (media->bundle != bundle) + continue; + if (!media->media_id.len) + continue; + unsigned int idx = media->index - 1; + if (idx >= RTPE_NUM_OUTPUT_MEDIA) + continue; // warn? + if (media->media_id.len > 255) + continue; + + s->reti.mid_output[idx].len = media->media_id.len; + memcpy(s->reti.mid_output[idx].mid, media->media_id.s, media->media_id.len); + + struct packet_stream *bundle_ps = get_media_component(media, component); + if (!bundle_ps) + continue; // log as error? + + fill_media_sinks(s, idx, bundle_ps); + } +} static const rtp_ext_handler rtp_ext_mid = { .parse = rtp_ext_mid_parse, .len = rtp_ext_mid_len, .print = rtp_ext_mid_print, + .kernel = rtp_ext_mid_kernel, .id = RTP_EXT_MID, }; diff --git a/include/media_socket.h b/include/media_socket.h index 6821fbe30..0f4b57a41 100644 --- a/include/media_socket.h +++ b/include/media_socket.h @@ -317,6 +317,8 @@ typedef struct { ssize_t (*len)(struct call_media *); ssize_t (*print)(void *dst, struct rtp_extension *, struct call_media *); + void (*kernel)(kernelize_state *, unsigned int component, struct call_media *); + enum { RTP_EXT_MID = 0, diff --git a/kernel-module/xt_RTPENGINE.c b/kernel-module/xt_RTPENGINE.c index bc1b180cf..303544fa7 100644 --- a/kernel-module/xt_RTPENGINE.c +++ b/kernel-module/xt_RTPENGINE.c @@ -1765,6 +1765,8 @@ static int proc_list_show(struct seq_file *f, void *v) { seq_printf(f, " forward-RTCP"); if (g->target.rtcp_fb_fw) seq_printf(f, " forward-RTCP-FB"); + if (g->target.extmap) + seq_printf(f, " extmap[%u]", g->target.extmap_mid); seq_printf(f, "\n"); seq_printf(f, " output groups:"); @@ -1773,11 +1775,22 @@ static int proc_list_show(struct seq_file *f, void *v) { != g->target.media_output_idxs[i].rtp_end_idx || g->target.media_output_idxs[i].rtcp_start_idx != g->target.media_output_idxs[i].rtcp_end_idx) - seq_printf(f, " [%u]=(%u->%u/%u->%u)", i, - g->target.media_output_idxs[i].rtp_start_idx, - g->target.media_output_idxs[i].rtp_end_idx, - g->target.media_output_idxs[i].rtcp_start_idx, - g->target.media_output_idxs[i].rtcp_end_idx); + { + if (g->target.mid_output[i].len) + seq_printf(f, " [%u/'%.*s']=(%u->%u/%u->%u)", i, + (int) g->target.mid_output[i].len, + g->target.mid_output[i].mid, + g->target.media_output_idxs[i].rtp_start_idx, + g->target.media_output_idxs[i].rtp_end_idx, + g->target.media_output_idxs[i].rtcp_start_idx, + g->target.media_output_idxs[i].rtcp_end_idx); + else + seq_printf(f, " [%u]=(%u->%u/%u->%u)", i, + g->target.media_output_idxs[i].rtp_start_idx, + g->target.media_output_idxs[i].rtp_end_idx, + g->target.media_output_idxs[i].rtcp_start_idx, + g->target.media_output_idxs[i].rtcp_end_idx); + } } seq_printf(f, "\n"); @@ -6279,6 +6292,74 @@ static void rtp_stats(struct rtpengine_target *g, struct rtp_parsed *rtp, s64 ar } +static unsigned int rtp_mid_ext_media_find(const char *mid, size_t len, + const struct rtpengine_target_info *tg) +{ + if (len == 0) + return -1u; + + // XXX not an efficient search + for (unsigned int i = 0; i < RTPE_NUM_OUTPUT_MEDIA; i++) { + if (len != tg->mid_output[i].len) + continue; + if (!memcmp(tg->mid_output[i].mid, mid, len)) + return i; + } + + return -1u; +} +static unsigned int rtp_mid_ext_media_short(const struct rtp_parsed *rtp, + const struct rtpengine_target_info *tg) +{ + size_t left = rtp->extension_len; + unsigned char *r = rtp->extension; + // XXX duplicates filter code somewhat + while (left >= 1) { + if (*r == 0) { + r++; + left--; + continue; + } + + uint8_t id = *r >> 4; + uint8_t len = (*r & 0xf) + 1; + r++; + left--; + if (len > left) + break; + + if (id == tg->extmap_mid) + return rtp_mid_ext_media_find(r, len, tg); + + r += len; + left -= len; + } + return -1u; +} +static unsigned int rtp_mid_ext_media_long(const struct rtp_parsed *rtp, + const struct rtpengine_target_info *tg) +{ + return -1u; +} +static unsigned int rtp_mid_ext_media(const struct rtp_parsed *rtp, + const struct rtpengine_target_info *tg) +{ + if (!rtp->ext_hdr) + return -1u; + if (!tg->extmap) + return -1u; + if (!tg->extmap_mid) + return -1u; + + if (ntohs(rtp->ext_hdr->undefined) == 0xbede) + return rtp_mid_ext_media_short(rtp, tg); + else if ((ntohs(rtp->ext_hdr->undefined) & 0xfff0) == 0x0100) + return rtp_mid_ext_media_long(rtp, tg); + + return -1u; +} + + static unsigned int rtpengine46(struct sk_buff *skb, struct sk_buff *oskb, struct rtpengine_table *t, struct re_address *src, struct re_address *dst, uint8_t in_tos, const struct xt_action_param *par) @@ -6393,6 +6474,8 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct sk_buff *oskb, // RTP ok rtp_pt_idx = rtp_payload_type(rtp.rtp_header, &g->target, &g->last_pt); + output_group_idx = rtp_mid_ext_media(&rtp, &g->target); + // Pass to userspace if SSRC has changed. // Look for matching SSRC index if any SSRC were given ssrc_idx = target_find_ssrc(g, rtp.rtp_header->ssrc); @@ -6413,7 +6496,8 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct sk_buff *oskb, goto out; } else { - output_group_idx = g->target.pt_media_idx[rtp_pt_idx]; + if (output_group_idx == -1u) + output_group_idx = g->target.pt_media_idx[rtp_pt_idx]; if (ssrc_idx >= 0 && g->target.ssrc_stats[ssrc_idx]) { atomic_set(&g->target.ssrc_stats[ssrc_idx]->last_pt, @@ -6479,6 +6563,8 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct sk_buff *oskb, } // output + if (output_group_idx == -1u) + output_group_idx = 0; output_group = &g->target.media_output_idxs[output_group_idx]; start_idx = (is_rtcp != NOT_RTCP) ? output_group->rtcp_start_idx : output_group->rtp_start_idx; end_idx = (is_rtcp != NOT_RTCP) ? output_group->rtcp_end_idx : output_group->rtp_end_idx; diff --git a/kernel-module/xt_RTPENGINE.h b/kernel-module/xt_RTPENGINE.h index b7c327cb1..a5e1fff3c 100644 --- a/kernel-module/xt_RTPENGINE.h +++ b/kernel-module/xt_RTPENGINE.h @@ -107,10 +107,16 @@ struct rtpengine_target_info { unsigned int pt_media_idx[RTPE_NUM_PAYLOAD_TYPES]; // same idx as pt_stats unsigned int num_payload_types; + uint8_t extmap_mid; + struct { + char mid[255]; + size_t len; + } mid_output[RTPE_NUM_OUTPUT_MEDIA]; + struct interface_stats_block *iface_stats; // for ingress stats struct stream_stats *stats; // for ingress stats - unsigned int __unused1:1, + unsigned int extmap:1, dtls:1, stun:1, rtp:1,