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
pull/1897/head
Donat Zenichev 11 months ago
parent 3cc3b6d56c
commit 4298a7e558

@ -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 */

@ -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)
{

@ -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);

@ -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' } }, <<SDP);
offer('Music on hold - sendrecv', { ICE => 'remove', DTLS => 'off', moh => { blob => $wav_file } }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
@ -26247,7 +26247,7 @@ a=rtcp:PORT
SDP
# declare that answerer is capable of moh (fake db-id)
answer('Music on hold - sendrecv', { ICE => 'remove', moh => { 'db-id' => '123', mode => 'sendrecv' } }, <<SDP);
answer('Music on hold - sendrecv', { ICE => 'remove', moh => { 'db-id' => '123' } }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
@ -26363,7 +26363,7 @@ SDP
($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 and declared zero-connection', { ICE => 'remove', DTLS => 'off', moh => { blob => $wav_file, connection => 'zero', mode => 'sendrecv' } }, <<SDP);
offer('Music on hold - sendrecv and declared zero-connection', { ICE => 'remove', DTLS => 'off', moh => { blob => $wav_file, connection => 'zero' } }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
@ -26384,7 +26384,7 @@ a=rtcp:PORT
SDP
# declare that answerer is capable of moh (fake db-id)
answer('Music on hold - sendrecv and declared zero-connection', { ICE => 'remove', moh => { 'db-id' => '123', connection => 'zero', mode => 'sendrecv' } }, <<SDP);
answer('Music on hold - sendrecv and declared zero-connection', { ICE => 'remove', moh => { 'db-id' => '123', connection => 'zero' } }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
@ -26495,6 +26495,143 @@ a=sendrecv
a=rtcp:PORT
SDP
# test MoH sendrecv mode
($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 and declared sendrecv mode', { ICE => 'remove', DTLS => 'off', moh => { blob => $wav_file, mode => 'sendrecv' } }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 33041 RTP/AVP 8
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
# declare that answerer is capable of moh (fake db-id)
answer('Music on hold - sendrecv and declared sendrecv mode', { ICE => 'remove', moh => { 'db-id' => '123', mode => 'sendrecv' } }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 33042 RTP/AVP 8
c=IN IP4 198.51.100.3
a=sendrecv
--------------------------------------
v=0
o=- 1545997027 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
# offerer puts on hold
offer('Music on hold - MoH set by offerer and declared sendrecv mode', { ICE => 'remove', DTLS => 'off' }, <<SDP);
v=0
o=- 1545997028 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 33041 RTP/AVP 8
c=IN IP4 198.51.100.1
a=sendonly
----------------------------------
v=0
o=- 1545997028 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
# test received packets on the recepient side
(undef, $seq, $ts, $ssrc) = rcv($sock_b, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1));
rcv($sock_b, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2));
rcv($sock_b, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3));
rcv($sock_b, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4));
rcv($sock_b, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5));
answer('Music on hold - MoH set by offerer and declared sendrecv mode', { ICE => 'remove' }, <<SDP);
v=0
o=- 1545997028 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 33042 RTP/AVP 8
c=IN IP4 198.51.100.3
a=sendrecv
--------------------------------------
v=0
o=- 1545997028 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
# offerer puts off hold
offer('Music on hold - MoH put off by offerer and declared sendrecv mode', { ICE => 'remove', DTLS => 'off' }, <<SDP);
v=0
o=- 1545997029 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio 33041 RTP/AVP 8
c=IN IP4 198.51.100.1
a=sendrecv
----------------------------------
v=0
o=- 1545997029 1 IN IP4 198.51.100.1
s=tester
t=0 0
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
#rcv_no($sock_b);
answer('Music on hold - MoH put off by offerer and declared sendrecv mode', { ICE => 'remove' }, <<SDP);
v=0
o=- 1545997029 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio 33042 RTP/AVP 8
c=IN IP4 198.51.100.3
a=sendrecv
--------------------------------------
v=0
o=- 1545997029 1 IN IP4 198.51.100.3
s=tester
t=0 0
m=audio PORT RTP/AVP 8
c=IN IP4 203.0.113.1
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
# SDP version tests
new_call;

Loading…
Cancel
Save