From cec0afa25e1c0b29be8d93433dec3a52ddc67514 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 11 Aug 2025 08:33:21 -0400 Subject: [PATCH] MT#55283 clean up RTCP send locking Fixes regression from Ib4285e7aae RTCP multiplexing requires the RTCP sender to maybe lock the same output stream, maybe lock some other one. Allow for both. Change-Id: I6fcef32e656f8f0de46ad777f11a19c259ce35c7 --- daemon/codec.c | 2 +- daemon/media_player.c | 7 +++++-- daemon/rtcp.c | 22 ++++++++++++++-------- include/rtcp.h | 3 ++- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index 480c627e1..6c76c819e 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -1371,7 +1371,7 @@ static void __rtcp_timer_run(struct codec_timer *ct) { for (GList *l = ssrc_out.head; l; l = l->next) { struct ssrc_entry_call *se = l->data; - rtcp_send_report(media, se); + rtcp_send_report(media, se, NULL); } rwlock_unlock_r(&rt->call->master_lock); diff --git a/daemon/media_player.c b/daemon/media_player.c index adb7f9e58..ef369f1ee 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -306,12 +306,13 @@ struct send_timer *send_timer_new(struct packet_stream *ps) { // call is locked in R // ssrc_out is locked +// st->sink is locked static void send_timer_rtcp(struct send_timer *st, struct ssrc_entry_call *ssrc_out) { struct call_media *media = st->sink ? st->sink->media : NULL; if (!media) return; - rtcp_send_report(media, ssrc_out); + rtcp_send_report(media, ssrc_out, st->sink); ssrc_out->next_rtcp = rtpe_now; ssrc_out->next_rtcp += 5000000 + (ssl_random() % 2000000); @@ -408,6 +409,7 @@ out: log_info_pop(); } +// sink->lock is held static void __send_timer_rtcp(struct send_timer *st, struct ssrc_entry_call *ssrc_out) { // do we send RTCP? if (!ssrc_out) @@ -436,9 +438,10 @@ static void send_timer_send_lock(struct send_timer *st, struct codec_packet *cp) __send_timer_send_common(st, cp); + __send_timer_rtcp(st, ssrc_out); + mutex_unlock(&st->sink->lock); - __send_timer_rtcp(st, ssrc_out); ssrc_entry_release(ssrc_out); rwlock_unlock_r(&call->master_lock); diff --git a/daemon/rtcp.c b/daemon/rtcp.c index 67d4a9a7f..173ce7ff1 100644 --- a/daemon/rtcp.c +++ b/daemon/rtcp.c @@ -1550,8 +1550,10 @@ static void rtcp_receiver_reports(ssrc_q *out, struct ssrc_hash *hash) { // call must be locked in R -// no in_lock or out_lock must be held -void rtcp_send_report(struct call_media *media, struct ssrc_entry_call *ssrc_out) { +// if a `ps` is locked, it must be passed as argument +void rtcp_send_report(struct call_media *media, struct ssrc_entry_call *ssrc_out, + const struct packet_stream *locked) +{ // figure out where to send it struct packet_stream *ps = media->streams.head->data; // crypto context is held separately @@ -1562,16 +1564,15 @@ void rtcp_send_report(struct call_media *media, struct ssrc_entry_call *ssrc_out else { if (PS_ISSET(rtcp_ps, RTCP)) ps = rtcp_ps; - else - rtcp_ps = ps; } - LOCK(&ps->lock); + if (ps != locked) + mutex_lock(&ps->lock); - if (!ps->selected_sfd || !rtcp_ps->selected_sfd) - return; + if (!ps->selected_sfd) + goto out; if (ps->selected_sfd->socket.fd == -1 || ps->endpoint.address.family == NULL) - return; + goto out; log_info_stream_fd(ps->selected_sfd); @@ -1623,6 +1624,11 @@ void rtcp_send_report(struct call_media *media, struct ssrc_entry_call *ssrc_out struct ssrc_receiver_report *srr = t_queue_pop_head(&srrs); g_free(srr); } + +out: + if (ps != locked) + mutex_unlock(&ps->lock); + } diff --git a/include/rtcp.h b/include/rtcp.h index aa6a0995f..e38c45d29 100644 --- a/include/rtcp.h +++ b/include/rtcp.h @@ -30,6 +30,7 @@ rtcp_filter_func rtcp_avpf2avp_filter; void rtcp_init(void); -void rtcp_send_report(struct call_media *media, struct ssrc_entry_call *ssrc_out); +void rtcp_send_report(struct call_media *media, struct ssrc_entry_call *ssrc_out, + const struct packet_stream *locked); #endif