From 09ccc3bf8ff410aa48f8d55dd32c708e506e7bb9 Mon Sep 17 00:00:00 2001 From: Donat Zenichev Date: Tue, 1 Apr 2025 11:58:31 +0200 Subject: [PATCH] MT#62272 moh: introduce mode=reflect This mode is only supposed to be used by cases when: - in-dialog offerer doesn't have own MoH capabilities; and - still want the recipient to hear the MoH music; hence - an offerer checks whether a recipient is capable of MoH, and launches a player based on given capabilities; - the rest functions the same as with usual MoH hold; Other information: - `mode=reflect` is only to be used within dialog, so, it's not meant for a session origination, and hence stands alone from other MoH option flags that actually give a metadata (e.g. blob data) - `mode=reflect` hence contradicts with `mode=sendrecv` which in its turn serves another purpose Usage: - `moh => { mode => 'reflect' }` Change-Id: I8d0d55f2711c6b47bfca17691582c1ffe66eae3d --- daemon/call_interfaces.c | 2 ++ daemon/media_player.c | 38 ++++++++++++++++++++++++++++---------- include/call_interfaces.h | 1 + include/media_player.h | 2 +- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 415838a37..10acb6671 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -866,6 +866,8 @@ static void call_ng_flags_moh(const ng_parser_t *parser, str *key, parser_arg va parser->get_str(value, &mode); if (!str_cmp(&mode, "sendrecv")) out->moh_sendrecv = true; + else if (!str_cmp(&mode, "reflect")) + out->moh_reflect = true; break; default: ilog(LOG_WARN, "Unknown 'moh' flag encountered: '" STR_FORMAT "'", diff --git a/daemon/media_player.c b/daemon/media_player.c index a9aa1a3ca..5b7b5c206 100644 --- a/daemon/media_player.c +++ b/daemon/media_player.c @@ -1489,9 +1489,16 @@ static bool media_player_add_file(struct media_player *mp, media_player_opts_t o } #endif -bool call_ml_wants_moh(struct call_monologue *ml, enum ng_opmode opmode) +/** + * When to_ml is given, check MoH capabilities of it, + * because then an offerer wants to use them instead of its own (from_ml). + */ +bool call_ml_wants_moh(struct call_monologue *from_ml, struct call_monologue *to_ml, + enum ng_opmode opmode) { - if (opmode == OP_OFFER && call_ml_sendonly_inactive(ml) && + struct call_monologue *ml = to_ml ? : from_ml; + + if (opmode == OP_OFFER && call_ml_sendonly_inactive(from_ml) && (ml->moh_db_id > 0 || ml->moh_file.len || ml->moh_blob.len)) { return true; @@ -1522,8 +1529,12 @@ bool call_ml_stops_moh(struct call_monologue *from_ml, struct call_monologue *to */ void call_ml_moh_handle_flags(struct call_monologue *from_ml, struct call_monologue *to_ml) { #ifdef WITH_TRANSCODING + + /* if from_ml not given, then it's a reflected MoH, use capabilities of to_ml */ + struct call_monologue *moh_ml = from_ml ? : to_ml; + if (!to_ml->player || - !ML_ISSET2(from_ml, MOH_ZEROCONN, MOH_SENDRECV)) + !ML_ISSET2(moh_ml, MOH_ZEROCONN, MOH_SENDRECV)) { return; } @@ -1531,7 +1542,7 @@ void call_ml_moh_handle_flags(struct call_monologue *from_ml, struct call_monolo struct call_media * media = to_ml->player->media; if (media) { /* check zero-connection */ - if (ML_ISSET(from_ml, MOH_ZEROCONN)) { + if (ML_ISSET(moh_ml, MOH_ZEROCONN)) { struct packet_stream *ps; __auto_type msl = media->streams.head; while (msl) @@ -1549,7 +1560,7 @@ void call_ml_moh_handle_flags(struct call_monologue *from_ml, struct call_monolo } check_next: /* check mode sendrecv */ - if (ML_ISSET(from_ml, MOH_SENDRECV)) { + if (ML_ISSET(moh_ml, MOH_SENDRECV)) { bf_set(&media->media_flags, MEDIA_FLAG_SEND | MEDIA_FLAG_RECV); bf_set(&media->media_flags, MEDIA_FLAG_FAKE_SENDRECV); @@ -1569,9 +1580,16 @@ const char * call_check_moh(struct call_monologue *from_ml, struct call_monologu sdp_ng_flags *flags) { #ifdef WITH_TRANSCODING - if (!flags->moh_double_hold && call_ml_wants_moh(from_ml, flags->opmode)) + + /* offerer might want to use MoH capabilities of the other monologue. + * e.g. when offerer lacks own MoH capabilities, but wants other side to hear MoH sound during the hold. + */ + bool reflected = flags->moh_reflect ? true : false; + + if (!flags->moh_double_hold && call_ml_wants_moh(from_ml, (reflected ? to_ml : NULL), flags->opmode)) { const char *errstr = NULL; + struct call_monologue *moh_ml = reflected ? to_ml : from_ml; if (flags->repeat_duration != -1) ilog(LOG_DEBUG, "Repeat-duration given via flags, but the configuration source will be used!"); @@ -1583,9 +1601,9 @@ const char * call_check_moh(struct call_monologue *from_ml, struct call_monologu .start_pos = 0, .block_egress = 1, .codec_set = flags->codec_set, - .file = from_ml->moh_file, - .blob = from_ml->moh_blob, - .db_id = from_ml->moh_db_id, + .file = moh_ml->moh_file, + .blob = moh_ml->moh_blob, + .db_id = moh_ml->moh_db_id, .moh = 1, /* mark as moh enabled */ ); @@ -1597,7 +1615,7 @@ const char * call_check_moh(struct call_monologue *from_ml, struct call_monologu } /* handle MoH related flags */ - call_ml_moh_handle_flags(from_ml, to_ml); + call_ml_moh_handle_flags((reflected ? NULL : from_ml), to_ml); ilog(LOG_DEBUG, "Music on hold triggered with coming SDP offer."); diff --git a/include/call_interfaces.h b/include/call_interfaces.h index b95f01976..a2b76d3cc 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -291,6 +291,7 @@ RTPE_NG_FLAGS_STR_CASE_HT_PARAMS moh_zero_connection:1, /* by default sendonly */ moh_sendrecv:1, + moh_reflect:1, /* prevents double MoH holds */ moh_double_hold:1; }; diff --git a/include/media_player.h b/include/media_player.h index 0405e0843..22963ed5f 100644 --- a/include/media_player.h +++ b/include/media_player.h @@ -139,7 +139,7 @@ void media_player_add_packet(struct media_player *mp, char *buf, size_t len, const char * call_play_media_for_ml(struct call_monologue *ml, media_player_opts_t opts, sdp_ng_flags *flags); 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_wants_moh(struct call_monologue *from_ml, struct call_monologue *to_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_handle_flags(struct call_monologue *from_ml, struct call_monologue *to_ml);