diff --git a/daemon/call.c b/daemon/call.c index 470c5a473..fcdcf6e70 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2881,12 +2881,35 @@ static void media_set_siprec_label(struct call_media *other_media, struct call_m } __attribute__((nonnull(1))) -static unsigned int media_extmap_id(struct call_media *media) { +static unsigned int media_bundle_extmap_id(struct call_media *media) { + __auto_type ml = media->monologue; + // XXX slow search? for (unsigned int i = 1; i < 255; i++) { - if (!media->extmap_ops->lookup(media, i)) + if (media->extmap_ops->lookup(media, i)) + continue; + + // used by any other media in the bundle? + bool good = true; + // XXX even worse search + for (unsigned int j = 0; j < ml->medias->len; j++) { + __auto_type bundle_media = ml->medias->pdata[j]; + if (!bundle_media) + continue; + if (bundle_media == media) + continue; + if (bundle_media->bundle != media->bundle) + continue; + if (bundle_media->extmap_ops->lookup(bundle_media, i)) { + good = false; + break; + } + } + + if (good) return i; } + return -1u; } @@ -2958,7 +2981,8 @@ static void media_init_extmap(struct call_media *media, struct rtp_extension *ex t_hash_table_insert(media->extmap_ht, GUINT_TO_POINTER(ext->id), ext); - ext->handler = rtp_extension_get_handler(&ext->name); + if (!ext->handler.set) + ext->handler = rtp_extension_get_handler(&ext->name); if (ext->id > 0 && ext->id <= 14) media->extmap_a[ext->id - 1] = ext; @@ -3531,6 +3555,73 @@ static void monologue_bundle_set_sinks(struct call_monologue *ml) { } } +// see if any other media in a bundle has the extension already +static struct rtp_extension *monologue_ext_any_bundle(struct call_media *media, unsigned int id) { + __auto_type ml = media->monologue; + __auto_type bundle = media->bundle; + // XXX bit silly to do this in a loop + for (unsigned int i = 0; i < ml->medias->len; i++) { + __auto_type bundle_media = ml->medias->pdata[i]; + if (!bundle_media) + continue; + if (bundle_media->bundle != bundle) + continue; + if (bundle_media->extmap_id[id]) + return bundle_media->extmap_id[id]; + } + return NULL; +} + +__attribute__((nonnull(1))) +static void monologue_bundle_mid(struct call_monologue *ml) { + for (unsigned int i = 0; i < ml->medias->len; i++) { + __auto_type media = ml->medias->pdata[i]; + if (!media) + continue; + if (!media->bundle) + continue; + if (media->extmap_id[RTP_EXT_MID]) + continue; + + struct rtp_extension *new_ext; + + __auto_type ext = monologue_ext_any_bundle(media, RTP_EXT_MID); + if (ext) { + __auto_type ext_exist = media->extmap_ops->lookup(media, ext->id); + if (ext_exist) { + // XXX ideally we would support extension renumbering here + ilog(LOG_WARN, "RTP header extension collision for MID (%u vs " + "%u/'" STR_FORMAT "'), removing it in favour of MID", + ext->id, ext_exist->id, STR_FMT(&ext_exist->name)); + t_hash_table_remove(media->extmap_ht, GUINT_TO_POINTER(ext_exist->id)); + if (ext_exist->id <= 14) + media->extmap_a[ext_exist->id] = NULL; + t_queue_remove(&media->extmap, ext_exist); // XXX also not ideal + rtp_extension_free(ext_exist); + } + + new_ext = g_new(struct rtp_extension, 1); + *new_ext = *ext; + } + else { + unsigned int id = media_bundle_extmap_id(media); + if (id == -1u) { + ilog(LOG_WARN, "Out of IDs for RTP header extension"); + continue; + } + + new_ext = g_new(struct rtp_extension, 1); + *new_ext = media_rtp_ext_mid; + new_ext->id = id; + } + + new_ext->synthetic = true; + new_ext->accepted = true; + t_queue_push_tail(&media->extmap, new_ext); + media_init_extmap(media, new_ext); + } +} + __attribute__((nonnull(1, 2))) static void monologue_bundle_offer(struct call_monologue *ml, sdp_ng_flags *flags) { if (!flags->bundle_offer || flags->opmode != OP_OFFER) @@ -3570,27 +3661,11 @@ static void monologue_bundle_offer(struct call_monologue *ml, sdp_ng_flags *flag // set bundle group media->bundle = bundle; - // offer MID header extension - if (!media->extmap_id[RTP_EXT_MID]) { - unsigned int id = media_extmap_id(media); - if (id == -1u) - ilog(LOG_WARN, "Out of IDs for RTP header extension"); - else { - __auto_type ext = g_new0(struct rtp_extension, 1); - // XXX string duplication and duplicate lookup via init_extmap -> get_handler - ext->name = STR("urn:ietf:params:rtp-hdrext:sdes:mid"); - ext->id = id; - ext->synthetic = true; - t_queue_push_tail(&media->extmap, ext); - media_init_extmap(media, ext); - } - } - track_bundle_media_pt(media, exclude_pt); } - monologue_bundle_check_consistency(ml); - monologue_bundle_check_heads(ml); + // make sure MID is offered for all medias in a bundle + monologue_bundle_mid(ml); } __attribute__((nonnull(1, 2))) @@ -3885,6 +3960,7 @@ int monologue_offer_answer(struct call_monologue *monologues[2], sdp_streams_q * monologue_bundle_accept(sender_ml, flags); monologue_bundle_offer(receiver_ml, flags); monologue_bundle_check_consistency(receiver_ml); + monologue_bundle_check_heads(receiver_ml); monologue_bundle_set_fds(receiver_ml); monologue_bundle_set_sinks(sender_ml); monologue_bundle_set_sinks(receiver_ml); diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 53c8c6704..5617a55bf 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -2920,16 +2920,24 @@ static const rtp_ext_handler rtp_ext_mid = { .print = rtp_ext_mid_print, .kernel = rtp_ext_mid_kernel, .id = RTP_EXT_MID, + .set = true, }; rtp_ext_handler rtp_extension_get_handler(const str *name) { if (!str_cmp(name, "urn:ietf:params:rtp-hdrext:sdes:mid")) return rtp_ext_mid; - return (rtp_ext_handler) { .id = RTP_EXT_UNKNOWN }; + return (rtp_ext_handler) { .id = RTP_EXT_UNKNOWN, .set = true }; } +struct rtp_extension media_rtp_ext_mid = { + .name = STR_CONST("urn:ietf:params:rtp-hdrext:sdes:mid"), + .handler = rtp_ext_mid, +}; + static void media_packet_rtp_extension(struct packet_handler_ctx *phc, unsigned int id, const str *data) { - __auto_type ext = phc->mp.media->extmap_ops->lookup(phc->mp.media, id); + __auto_type media = phc->mp.media->bundle ?: phc->mp.media; + + __auto_type ext = media->extmap_ops->lookup(phc->mp.media, id); if (!ext) return; @@ -2945,7 +2953,9 @@ static void media_packet_rtp_extension(struct packet_handler_ctx *phc, unsigned } static void media_packet_rtp_extensions(struct packet_handler_ctx *phc) { - if (!phc->mp.media->extmap.length) + __auto_type media = phc->mp.media->bundle ?: phc->mp.media; + + if (!media->extmap.length) return; if (!phc->mp.extensions.len) return; diff --git a/include/media_socket.h b/include/media_socket.h index 2b9b7788e..a663e3bd5 100644 --- a/include/media_socket.h +++ b/include/media_socket.h @@ -327,6 +327,8 @@ typedef struct { RTP_EXT_UNKNOWN, } id; + + bool set; // used by rtp_extension_get_handler to detect non-init } rtp_ext_handler; struct rtp_extension { @@ -364,6 +366,8 @@ size_t extmap_print_long(void *, unsigned int, const str *); rtp_ext_handler rtp_extension_get_handler(const str *); +extern struct rtp_extension media_rtp_ext_mid; + extern local_intf_q all_local_interfaces; // read-only during runtime