From bce7dcf05fc56acb67506545be8cc23eb5bf5cd2 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 19 Dec 2024 15:14:32 -0400 Subject: [PATCH] MT#61368 add dialogue_connect() This function connects two call legs (two monologues), possibly from different call IDs, into a single media flow. It pays attention to media types and automatically engages transcoding if needed. The order of media sections of different types can be differend between the call legs that are being connected. Subsequent reinvites will produce SDPs with the media sections in the correct order. Change-Id: I40c3363997de169edc553733d52acdfd9f0181ad --- daemon/call.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/call.h | 1 + 2 files changed, 61 insertions(+) diff --git a/daemon/call.c b/daemon/call.c index 13af61366..378c2eecb 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -3747,6 +3747,66 @@ int monologue_unsubscribe(struct call_monologue *dst_ml, sdp_ng_flags *flags) { } +__attribute__((nonnull(1, 2, 3))) +void dialogue_connect(struct call_monologue *src_ml, struct call_monologue *dst_ml, sdp_ng_flags *flags) { + // for each source media, find a usable destination media + for (unsigned int i = 0; i < src_ml->medias->len; i++) { + __auto_type src_media = src_ml->medias->pdata[i]; + if (!src_media) + continue; + + struct call_media *dst_media = NULL; + + // try a=mid first if there is one + if (src_media->media_id.len) { + dst_media = t_hash_table_lookup(dst_ml->media_ids, &src_media->media_id); + // type must still match + if (str_cmp_str(&dst_media->type, &src_media->type)) + dst_media = NULL; + } + + // otherwise try by index + if (!dst_media) { + for (unsigned int j = 0; j < dst_ml->medias->len; j++) { + unsigned int dx = (j + i) % dst_ml->medias->len; + dst_media = dst_ml->medias->pdata[dx]; + if (!dst_media) + continue; + // if type matches, we can connect + if (!str_cmp_str(&dst_media->type, &src_media->type)) + break; + dst_media = NULL; + } + } + + // anything found? + if (!dst_media) { + ilog(LOG_WARN, "Unable to find usable media (type '" STR_FORMAT "') to connect call", + STR_FMT(&src_media->type)); + continue; + } + + __media_unconfirm(src_media, "connect"); + __media_unconfirm(dst_media, "connect"); + + g_auto(medias_q) medias = TYPED_GQUEUE_INIT; + + __subscribe_medias_both_ways(src_media, dst_media, false, &medias); + + __medias_unconfirm(&medias, "connect"); + + codec_handlers_update(src_media, dst_media, + .allow_asymmetric = !!flags->allow_asymmetric_codecs); + codec_handlers_update(dst_media, src_media, + .allow_asymmetric = !!flags->allow_asymmetric_codecs); + + __update_init_subscribers(src_media, NULL, NULL, flags->opmode); + __update_init_subscribers(dst_media, NULL, NULL, flags->opmode); + __update_init_medias(&medias, flags->opmode); + } +} + + static int __rtp_stats_sort(const void *ap, const void *bp) { diff --git a/include/call.h b/include/call.h index ead6cc2d8..0f0e04876 100644 --- a/include/call.h +++ b/include/call.h @@ -848,6 +848,7 @@ int monologue_subscribe_request(const subscription_q *srms, struct call_monologu int monologue_subscribe_answer(struct call_monologue *dst, sdp_ng_flags *flags, sdp_streams_q *streams); int monologue_unsubscribe(struct call_monologue *dst, sdp_ng_flags *); +void dialogue_connect(struct call_monologue *, struct call_monologue *, sdp_ng_flags *); void monologue_destroy(struct call_monologue *ml); int call_delete_branch_by_id(const str *callid, const str *branch, const str *fromtag, const str *totag, ng_command_ctx_t *, int delete_delay);