From 4298a7e558e1cbdc85fa866d334744fc07cdd7a2 Mon Sep 17 00:00:00 2001 From: Donat Zenichev Date: Thu, 2 Jan 2025 11:20:44 +0100 Subject: [PATCH] MT#61630 moh: add support of sendrecv mode flag Sendrecv mode flag controls whether the sendrecv state is forced to sendrecv, instead of the default one sendonly, in the SDP body going towards recipient (the one who will receive the MoH media). Is declared as: moh=[mode=sendrecv] Can be useful for corner cases, where the remote side wants to see sendrecv state for whatever reason, when getting MoH media and hence also remain in sendrecv state in regards of the MoH originator. Must be advertised once during the session origination, nd then will affect the SDP body as soon as SDP sendonly body is received (from the behalf of one, who advertised MoH capabilities). Backwards compatibility: doesn't affect non-MoH calls. And doesn't affect offer/answer exchanges within MoH calls, which do not put the remote side on hold. Additionally: introduce a common function for the MoH flags handling: `call_ml_moh_handle_flags()`, which does all the required iterations/checks for the whole bunch of flags at once. Additionally: previously existing MoH tests adopted. Additionally: new test introduced to check the SDP content, when using mode sendrecv flag. Remark: this flag is not mutually exclusive with the zero-connection MoH flag. Change-Id: I5bf6699f6890d8b927107cc143a18116efe45087 --- daemon/call_interfaces.c | 6 +- daemon/media_player.c | 63 ++++++++++------- include/media_player.h | 2 +- t/auto-daemon-tests.pl | 145 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 182 insertions(+), 34 deletions(-) diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 54cb436ae..063ae634a 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -194,10 +194,8 @@ static const char* call_check_moh(struct call_monologue *from_ml, struct call_mo return errstr; /* mark player as used for MoH */ to_ml->player->moh = true; - /* check if originator wants to advertise zero address during moh */ - if (ML_ISSET(from_ml, MOH_ZEROCONN)) { - call_ml_moh_set_zeroconn(from_ml); - } + /* handle MoH related flags */ + call_ml_moh_handle_flags(from_ml, to_ml); } else if (call_ml_stops_moh(from_ml, to_ml, flags->opmode)) { /* whom to stop the moh audio */ diff --git a/daemon/media_player.c b/daemon/media_player.c index 9236f4640..0f7186cd7 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -1228,39 +1228,52 @@ bool call_ml_stops_moh(struct call_monologue *from_ml, struct call_monologue *to } /** - * Sets zero-connection for the first found subscription media with sendonly state - * and audio type. + * MOH_ZEROCONN: check if originator wants to advertise zero address during moh. + * Sets zero-connection for the first found subscription media with a sendonly state + * and audio type. + * MOH_SENDRECV: check if originator wants to use sendrecv state instead of the default + * one (sendonly) during moh. + * Sets the sendrecv state for the first found subscription media with a sendonly state + * and audio type. */ -void call_ml_moh_set_zeroconn(struct call_monologue *from_ml) { - for (int i = 0; i < from_ml->medias->len; i++) +void call_ml_moh_handle_flags(struct call_monologue *from_ml, struct call_monologue *to_ml) { +#ifdef WITH_TRANSCODING + if (!to_ml->player || + !ML_ISSET2(from_ml, MOH_ZEROCONN, MOH_SENDRECV)) { - struct call_media * media = from_ml->medias->pdata[i]; - if (!media || media->type_id != MT_AUDIO) - continue; - if (!MEDIA_ISSET(media, SEND) && MEDIA_ISSET(media, RECV)) - { - if (media->media_subscriptions.head) { - struct media_subscription * ms = media->media_subscriptions.head->data; - if (ms->media) { - struct packet_stream *ps; - __auto_type msl = ms->media->streams.head; - while (msl) - { - ps = msl->data; - if (PS_ISSET(ps, RTP)) { - ilog(LOG_DEBUG, "Forced packet stream of '"STR_FORMAT"' (media index: '%d') to zero_addr due to MoH zero-connection.", - STR_FMT(&ms->media->monologue->tag), ms->media->index); - PS_SET(ps, ZERO_ADDR); - return; /* stop */ - } - msl = msl->next; - } + return; + } + + struct call_media * media = to_ml->player->media; + if (media) { + /* check zero-connection */ + if (ML_ISSET(from_ml, MOH_ZEROCONN)) { + struct packet_stream *ps; + __auto_type msl = media->streams.head; + while (msl) + { + ps = msl->data; + if (PS_ISSET(ps, RTP)) { /* find RTP stream, and don't touch RTCP */ + ilog(LOG_DEBUG, "Forced packet stream of '"STR_FORMAT"' (media index: '%d')" + "to zero_addr due to MoH zero-connection.", + STR_FMT(&media->monologue->tag), media->index); + PS_SET(ps, ZERO_ADDR); + goto check_next; /* stop */ } + msl = msl->next; } } +check_next: + /* check mode sendrecv */ + if (ML_ISSET(from_ml, MOH_SENDRECV)) { + bf_set(&media->media_flags, MEDIA_FLAG_SEND | MEDIA_FLAG_RECV); + } } +#endif } + + const char * call_play_media_for_ml(struct call_monologue *ml, media_player_opts_t opts, sdp_ng_flags *flags) { diff --git a/include/media_player.h b/include/media_player.h index 128ee37bf..eeb81feb1 100644 --- a/include/media_player.h +++ b/include/media_player.h @@ -141,7 +141,7 @@ long long call_stop_media_for_ml(struct call_monologue *ml); bool call_ml_wants_moh(struct call_monologue *ml, enum ng_opmode opmode); bool call_ml_stops_moh(struct call_monologue *from_ml, struct call_monologue *to_ml, enum ng_opmode opmode); -void call_ml_moh_set_zeroconn(struct call_monologue *from_ml); +void call_ml_moh_handle_flags(struct call_monologue *from_ml, struct call_monologue *to_ml); void media_player_init(void); void media_player_free(void); diff --git a/t/auto-daemon-tests.pl b/t/auto-daemon-tests.pl index 214c18818..936dc38c5 100755 --- a/t/auto-daemon-tests.pl +++ b/t/auto-daemon-tests.pl @@ -26226,7 +26226,7 @@ $resp = rtpe_req('statistics', 'statistics'); ($sock_a, $sock_b) = new_call([qw(198.51.100.1 33041)], [qw(198.51.100.3 33042)]); # declare that offerer is capable of moh -offer('Music on hold - sendrecv', { ICE => 'remove', DTLS => 'off', moh => { blob => $wav_file, mode => 'sendrecv' } }, < 'remove', DTLS => 'off', moh => { blob => $wav_file } }, < 'remove', moh => { 'db-id' => '123', mode => 'sendrecv' } }, < 'remove', moh => { 'db-id' => '123' } }, < 'remove', DTLS => 'off', moh => { blob => $wav_file, connection => 'zero', mode => 'sendrecv' } }, < 'remove', DTLS => 'off', moh => { blob => $wav_file, connection => 'zero' } }, < 'remove', moh => { 'db-id' => '123', connection => 'zero', mode => 'sendrecv' } }, < 'remove', moh => { 'db-id' => '123', connection => 'zero' } }, < 'remove', DTLS => 'off', moh => { blob => $wav_file, mode => 'sendrecv' } }, < 'remove', moh => { 'db-id' => '123', mode => 'sendrecv' } }, < 'remove', DTLS => 'off' }, < 'remove' }, < 'remove', DTLS => 'off' }, < 'remove' }, <