From c27ecf4828b52535271fec7be6282ba0a1f0877c Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 10 Mar 2026 08:50:17 -0400 Subject: [PATCH] MT#55283 facilitate media reuse for updated subs For a repeated subscribe-request on an existing monologue, make sure that existing media sections are re-used for the same subscriptions as they were previously, and only create new ones in an append-only fashion for media subs which didn't previously exist. Change-Id: I410c6af17eb31a5c5c43c78a7f82ba867f8480b7 --- daemon/call.c | 55 +++++++++++++++++++++++++++++++++++++------------- include/call.h | 9 +++++++-- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 3fe46f998..b9015ae1e 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -4038,7 +4038,9 @@ void media_subscriptions_clear(subscription_q *q) { i_queue_clear_full(q, media_subscription_free); } -static void __unsubscribe_media_link(struct call_media *which, struct media_subscription *ms) +__attribute__((nonnull(1, 2))) +static inline void __unsubscribe_media_link_store(struct call_media *which, struct media_subscription *ms, + subscription_store_ht ht) { struct media_subscription *rev_ms = ms->reverse; struct call_media *from = ms->media; @@ -4055,11 +4057,23 @@ static void __unsubscribe_media_link(struct call_media *which, struct media_subs t_hash_table_remove(from->media_subscribers_ht, rev_ms->media); g_free(ms); - g_free(rev_ms); + + if (t_hash_table_is_set(ht)) + t_hash_table_insert(ht, from, rev_ms); + else + g_free(rev_ms); } + +__attribute__((nonnull(1, 2))) +static void __unsubscribe_media_link(struct call_media *which, struct media_subscription *ms) +{ + __unsubscribe_media_link_store(which, ms, subscription_store_ht_null()); +} + /** * Unsubscribe one particular media subscriber from this call media. */ +__attribute__((nonnull(1, 2))) bool __unsubscribe_media(struct call_media *which, struct call_media *from) { if (!t_hash_table_is_set(which->media_subscriptions_ht) @@ -4098,23 +4112,27 @@ static void __unsubscribe_all_offer_answer_medias(struct call_media *cm, medias_ __unsubscribe_media(cm, other_cm); } } -static void __unsubscribe_medias_from_all(struct call_monologue *ml) { + +__attribute__((nonnull(1))) +static inline void __unsubscribe_medias_from_all(struct call_monologue *ml, subscription_store_ht ht) +{ for (int i = 0; i < ml->medias->len; i++) { - struct call_media * media = ml->medias->pdata[i]; + struct call_media *media = ml->medias->pdata[i]; if (!media) continue; IQUEUE_FOREACH_SAFE(&media->media_subscriptions, subscription) - __unsubscribe_media_link(media, subscription); + __unsubscribe_media_link_store(media, subscription, ht); } } + /** * Check whether this monologue medias are subscribed to a single other monologue medias. */ struct call_monologue *ml_medias_subscribed_to_single_ml(struct call_monologue *ml) { /* detect monologues multiplicity */ - struct call_monologue * return_ml = NULL; + struct call_monologue *return_ml = NULL; for (unsigned int i = 0; i < ml->medias->len; i++) { struct call_media *media = ml->medias->pdata[i]; @@ -4129,7 +4147,7 @@ struct call_monologue *ml_medias_subscribed_to_single_ml(struct call_monologue * } return return_ml; } -struct media_subscription *__add_media_subscription(struct call_media * which, struct call_media * to, +struct media_subscription *__add_media_subscription(struct call_media *which, struct call_media *to, const struct sink_attrs *attrs) { struct media_subscription *ret; @@ -4359,9 +4377,9 @@ int monologue_publish(struct call_monologue *ml, sdp_streams_q *streams, sdp_ng_ } /* called with call->master_lock held in W */ -__attribute__((nonnull(1, 2, 3, 4))) +__attribute__((nonnull(1, 2, 3))) static int monologue_subscribe_request1(struct call_media *src_media, struct call_monologue *dst_ml, - sdp_ng_flags *flags, unsigned int *index) + sdp_ng_flags *flags, subscription_store_ht ht) { unsigned int idx_diff = 0, rev_idx_diff = 0; g_auto(str_ht) mid_tracker_dst = str_ht_new(); @@ -4369,8 +4387,16 @@ static int monologue_subscribe_request1(struct call_media *src_media, struct cal struct stream_params *sp = &src_media->sp; - struct call_media *dst_media = call_get_media(dst_ml, &src_media->type, src_media->type_id, - NULL, false, (*index)++, mid_tracker_dst); + // check if we have a matching existing subscription + struct call_media *dst_media = NULL; + __auto_type ms = t_hash_table_lookup(ht, src_media); + if (ms) + dst_media = ms->media; + if (!dst_media) { + // new media needed + dst_media = call_get_media(dst_ml, &src_media->type, src_media->type_id, + NULL, false, dst_ml->medias->len + 1, mid_tracker_dst); + } /* subscribe dst_ml (subscriber) to src_ml, don't forget to carry the egress flag, if required */ __add_media_subscription(dst_media, src_media, &(struct sink_attrs) { .egress = !!flags->egress }); @@ -4446,12 +4472,13 @@ static int monologue_subscribe_request1(struct call_media *src_media, struct cal return 0; } + /* called with call->master_lock held in W */ __attribute__((nonnull(1, 2, 3))) int monologue_subscribe_request(const subscription_q *srms, struct call_monologue *dst_ml, sdp_ng_flags *flags) { - unsigned int index = 1; /* running counter for output/dst medias */ + g_auto(subscription_store_ht) ht = subscription_store_ht_new(); - __unsubscribe_medias_from_all(dst_ml); + __unsubscribe_medias_from_all(dst_ml, ht); __call_monologue_init_from_flags(dst_ml, NULL, flags); IQUEUE_FOREACH(srms, ms) { @@ -4459,7 +4486,7 @@ int monologue_subscribe_request(const subscription_q *srms, struct call_monologu if (!src_media) continue; - int ret = monologue_subscribe_request1(src_media, dst_ml, flags, &index); + int ret = monologue_subscribe_request1(src_media, dst_ml, flags, ht); if (ret) return -1; diff --git a/include/call.h b/include/call.h index b017a8375..1a23ac195 100644 --- a/include/call.h +++ b/include/call.h @@ -853,8 +853,8 @@ struct media_subscription *__add_media_subscription(struct call_media * which, s bool __unsubscribe_media(struct call_media * which, struct call_media * from); struct media_subscription *call_ml_get_top_ms(struct call_monologue *ml); bool call_ml_sendonly_inactive(struct call_monologue *ml); -struct media_subscription *call_media_get_top_ms(struct call_media * cm); -struct media_subscription *call_get_media_subscription(subscription_ht ht, struct call_media * cm); +struct media_subscription *call_media_get_top_ms(struct call_media *cm); +struct media_subscription *call_get_media_subscription(subscription_ht ht, struct call_media *cm); struct call_monologue *ml_medias_subscribed_to_single_ml(struct call_monologue *ml); __attribute__((nonnull(1))) @@ -931,6 +931,11 @@ bool __init_stream(struct packet_stream *ps); const rtp_payload_type *__rtp_stats_codec(struct call_media *m); + +TYPED_GHASHTABLE(subscription_store_ht, struct call_media, struct media_subscription, + media_direct_hash, media_direct_eq, NULL, media_subscription_free) + + #include "str.h" #include "rtp.h"