diff --git a/daemon/codec.c b/daemon/codec.c index 80c4f1d41..d349ec961 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -1334,7 +1334,7 @@ static void __rtcp_timer_run(struct codec_timer *ct) { if (!ssrc_out[u]) // end of list break; // coverity[use : FALSE] - rtcp_send_report(media, ssrc_out[u]); + rtcp_send_report(media, ssrc_out[u], NULL); } rwlock_unlock_r(&rt->call->master_lock); diff --git a/daemon/media_player.c b/daemon/media_player.c index 7249ef90e..b7cd369d0 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -310,12 +310,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_ctx *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; timeval_add_usec(&ssrc_out->next_rtcp, 5000000 + (ssl_random() % 2000000)); @@ -412,6 +413,7 @@ out: log_info_pop(); } +// sink->lock is held static void __send_timer_rtcp(struct send_timer *st, struct ssrc_ctx *ssrc_out) { // do we send RTCP? if (!ssrc_out) @@ -440,9 +442,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_ctx_put(&ssrc_out); rwlock_unlock_r(&call->master_lock); diff --git a/daemon/rtcp.c b/daemon/rtcp.c index 69dc394a9..6944a3889 100644 --- a/daemon/rtcp.c +++ b/daemon/rtcp.c @@ -1552,8 +1552,10 @@ void rtcp_receiver_reports(GQueue *out, struct ssrc_hash *hash, struct call_mono // 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_ctx *ssrc_out) { +// if a `ps` is locked, it must be passed as argument +void rtcp_send_report(struct call_media *media, struct ssrc_ctx *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 @@ -1564,16 +1566,15 @@ void rtcp_send_report(struct call_media *media, struct ssrc_ctx *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); @@ -1625,6 +1626,11 @@ void rtcp_send_report(struct call_media *media, struct ssrc_ctx *ssrc_out) { struct ssrc_receiver_report *srr = g_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 cfc41fc33..0a9c30708 100644 --- a/include/rtcp.h +++ b/include/rtcp.h @@ -39,6 +39,7 @@ void rtcp_init(void); void rtcp_receiver_reports(GQueue *out, struct ssrc_hash *hash, struct call_monologue *ml); -void rtcp_send_report(struct call_media *media, struct ssrc_ctx *ssrc_out); +void rtcp_send_report(struct call_media *media, struct ssrc_ctx *ssrc_out, + const struct packet_stream *locked); #endif