From f1d37e9c93ef4e1eb57260032015ec9fec002a6c Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Wed, 27 Oct 2021 10:14:13 -0400 Subject: [PATCH] TT#147451 add support for SIPREC style SDPs Change-Id: I6a0bba30e8e356a44156571b7dc3b094176ef26e --- daemon/call.c | 23 +++ daemon/call_interfaces.c | 35 +++++ daemon/sdp.c | 6 + include/call.h | 1 + include/call_interfaces.h | 1 + perl/NGCP/Rtpengine/AutoTest.pm | 3 +- t/auto-daemon-tests-pubsub.pl | 254 +++++++++++++++++++++++++++++--- utils/rtpengine-ng-client | 4 +- 8 files changed, 304 insertions(+), 23 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 5656a1ada..7fda8f807 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2486,6 +2486,28 @@ static void __call_monologue_init_from_flags(struct call_monologue *ml, struct s } +static void __update_media_label(struct call_media *media, struct call_media *other_media, + struct sdp_ng_flags *flags) +{ + if (!media) + return; + if (!flags) + return; + + struct call *call = media->call; + + if (flags->siprec && flags->opmode == OP_REQUEST) { + if (!media->label.len) { + char buf[64]; + snprintf(buf, sizeof(buf), "%u", other_media->unique_id); + call_str_cpy_c(call, &media->label, buf); + } + // put same label on both sides + if (!other_media->label.len) + other_media->label = media->label; + } +} + // `media` can be NULL static int __media_init_from_flags(struct call_media *other_media, struct call_media *media, struct stream_params *sp, struct sdp_ng_flags *flags) @@ -2554,6 +2576,7 @@ static int __media_init_from_flags(struct call_media *other_media, struct call_m } } + __update_media_label(media, other_media, flags); __update_media_protocol(media, other_media, sp, flags); __update_media_id(media, other_media, sp, flags); __endpoint_loop_protect(sp, other_media); diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 76df9432d..c2225034a 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -822,6 +822,12 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) { case CSH_LOOKUP("all"): out->all = 1; break; + case CSH_LOOKUP("SIPREC"): + out->siprec = 1; + break; + case CSH_LOOKUP("siprec"): + out->siprec = 1; + break; case CSH_LOOKUP("fragment"): out->fragment = 1; break; @@ -2717,11 +2723,40 @@ const char *call_subscribe_request_ng(bencode_item_t *input, bencode_item_t *out struct call_monologue *source_ml = cs->monologue; bencode_dictionary_add_str_dup(output, "from-tag", &source_ml->tag); } + bencode_item_t *tag_medias = NULL, *media_labels = NULL; + if (flags.siprec) { + tag_medias = bencode_dictionary_add_list(output, "tag-medias"); + media_labels = bencode_dictionary_add_dictionary(output, "media-labels"); + } bencode_item_t *from_list = bencode_dictionary_add_list(output, "from-tags"); for (GList *l = srcs.head; l; l = l->next) { struct call_subscription *cs = l->data; struct call_monologue *source_ml = cs->monologue; bencode_list_add_str_dup(from_list, &source_ml->tag); + if (tag_medias) { + bencode_item_t *tag_label = bencode_list_add_dictionary(tag_medias); + bencode_dictionary_add_str(tag_label, "tag", &source_ml->tag); + if (source_ml->label.len) + bencode_dictionary_add_str(tag_label, "label", &source_ml->label); + bencode_item_t *medias = bencode_dictionary_add_list(tag_label, "medias"); + for (GList *k = source_ml->medias.head; k; k = k->next) { + struct call_media *media = k->data; + bencode_item_t *med_ent = bencode_list_add_dictionary(medias); + bencode_dictionary_add_integer(med_ent, "index", media->index); + bencode_dictionary_add_str(med_ent, "type", &media->type); + bencode_dictionary_add_str(med_ent, "label", &media->label); + + if (media_labels) { + bencode_item_t *label = + bencode_dictionary_add_dictionary(media_labels, media->label.s); + bencode_dictionary_add_str(label, "tag", &source_ml->tag); + bencode_dictionary_add_integer(label, "index", media->index); + bencode_dictionary_add_str(label, "type", &media->type); + if (source_ml->label.len) + bencode_dictionary_add_str(label, "label", &source_ml->label); + } + } + } } bencode_dictionary_add_str_dup(output, "to-tag", &dest_ml->tag); diff --git a/daemon/sdp.c b/daemon/sdp.c index f0a3f13a8..72dd028ba 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -2580,6 +2580,12 @@ static struct packet_stream *print_sdp_media_section(GString *s, struct call_med g_string_append(s, "\r\n"); } + if (media->label.len && flags && flags->siprec) { + g_string_append(s, "a=label:"); + g_string_append_printf(s, STR_FORMAT, STR_FMT(&media->label)); + g_string_append(s, "\r\n"); + } + if (is_active) { if (proto_is_rtp(media->protocol)) insert_codec_parameters(s, media); diff --git a/include/call.h b/include/call.h index 2e26d74ab..45cfc6235 100644 --- a/include/call.h +++ b/include/call.h @@ -363,6 +363,7 @@ struct call_media { struct ice_agent *ice_agent; str media_id; + str label; GQueue sdes_in, sdes_out; struct dtls_fingerprint fingerprint; /* as received */ const struct dtls_hash_func *fp_hash_func; // outgoing diff --git a/include/call_interfaces.h b/include/call_interfaces.h index 01584a074..61bc341fb 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -109,6 +109,7 @@ struct sdp_ng_flags { osrtp_offer:1, reset:1, all:1, + siprec:1, fragment:1, record_call:1, debug:1, diff --git a/perl/NGCP/Rtpengine/AutoTest.pm b/perl/NGCP/Rtpengine/AutoTest.pm index e4cd6790e..cc08b1ce1 100644 --- a/perl/NGCP/Rtpengine/AutoTest.pm +++ b/perl/NGCP/Rtpengine/AutoTest.pm @@ -160,7 +160,8 @@ sub subscribe_request { my ($name, $req, $sdp_exp) = @_; my $resp = rtpe_req('subscribe request', $name, $req); my @matches = sdp_match('subscribe request', $name, $resp->{sdp}, $sdp_exp); - return ($resp->{'from-tag'}, $resp->{'to-tag'}, $resp->{'from-tags'}, @matches); + return ($resp->{'from-tag'}, $resp->{'to-tag'}, $resp->{'from-tags'}, $resp->{'tag-medias'}, + $resp->{'media-labels'}, @matches); } sub subscribe_answer { my ($name, $req, $sdp) = @_; diff --git a/t/auto-daemon-tests-pubsub.pl b/t/auto-daemon-tests-pubsub.pl index 87dffae30..687626844 100755 --- a/t/auto-daemon-tests-pubsub.pl +++ b/t/auto-daemon-tests-pubsub.pl @@ -19,13 +19,225 @@ autotest_start(qw(--config-file=none -t -1 -i 203.0.113.1 -i 2001:db8:4321::1 my ($sock_a, $sock_b, $sock_c, $sock_d, $port_a, $port_b, $port_c, $ssrc_a, $ssrc_b, $resp, $sock_ax, $sock_bx, $port_ax, $port_bx, $port_d, $srtp_ctx_a, $srtp_ctx_b, $srtp_ctx_a_rev, $srtp_ctx_b_rev, $ufrag_a, $ufrag_b, - @ret1, @ret2, @ret3, @ret4, $srtp_key_a, $srtp_key_b, $ts, $seq, + @ret1, @ret2, @ret3, @ret4, $srtp_key_a, $srtp_key_b, $ts, $seq, $tag_medias, $media_labels, $ftr, $ttr, $fts, $ttr2); +new_call; + +($port_a) = offer('SIPREC sub', + { }, < ['all', 'SIPREC'] }, < ft(), + medias => [ + { + index => 1, + type => 'audio', + label => '1', + }, + ], + }, + { + tag => tt(), + medias => [ + { + index => 1, + type => 'audio', + label => '0', + }, + ], + }, +], 'tag-medias match'; +is_deeply $media_labels, { + '1' => { + index => 1, + type => 'audio', + tag => ft(), + }, + '0' => { + index => 1, + type => 'audio', + tag => tt(), + }, +}, 'media-labels match'; + + + +new_call; + +($port_a) = offer('SIPREC sub w label', + { label => 'caller' }, < 'called' }, < ['all', 'SIPREC'] }, < ft(), + label => 'caller', + medias => [ + { + index => 1, + type => 'audio', + label => '1', + }, + ], + }, + { + tag => tt(), + label => 'called', + medias => [ + { + index => 1, + type => 'audio', + label => '0', + }, + ], + }, +], 'tag-medias match'; +is_deeply $media_labels, { + '1' => { + index => 1, + type => 'audio', + tag => ft(), + label => 'caller', + }, + '0' => { + index => 1, + type => 'audio', + tag => tt(), + label => 'called', + }, +}, 'media-labels match'; + + + ($sock_a, $sock_b, $sock_c, $sock_d) = new_call([qw(198.51.100.14 6080)], [qw(198.51.100.14 6082)], [qw(198.51.100.14 6084)], [qw(198.51.100.14 6086)]); @@ -80,7 +292,7 @@ rcv($sock_a, $port_b, rtpm(0, 2000, 4000, 0x3456, "\x00" x 160)); snd($sock_a, $port_b, rtp(0, 4000, 7000, 0x6543, "\x00" x 160)); rcv($sock_b, $port_a, rtpm(0, 4000, 7000, 0x6543, "\x00" x 160)); -($ftr, $ttr, $fts, $port_c, undef, $port_d) = subscribe_request('"all" sub', +($ftr, $ttr, $fts, undef, undef, $port_c, undef, $port_d) = subscribe_request('"all" sub', { 'flags' => ['all'] }, < [ft(), tt()] }, < ['from-tags-' . ft(), 'from-tags-' . tt()] }, < [tt(), ft()] }, < ft() }, < ft(), codec => { transcode => ['PCMA'] } }, < ft(), codec => { transcode => ['PCMA'] } }, < ft() }, < 'foo' }, < 'bar' }, < ft(), 'transport-protocol' => 'RTP/SAVP', SDES => ['no-AEAD_AES_256_GCM', 'no-AEAD_AES_128_GCM'] }, < ft(), 'transport-protocol' => 'RTP/SAVP', SDES => ['no-AEAD_AES_256_GCM', 'no-AEAD_AES_128_GCM'] }, < ft(), 'transport-protocol' => 'RTP/AVP', }, < ft(), ICE => 'force' }, < ft() }, < ft() }, < ft() }, < ft() }, < ft() }, < ft(), codec => { strip => ['PCMA'], transcode => ['PCMU'] } }, < \$options{'always transcode'}, 'metadata=s' => \$options{'metadata'}, 'all' => \$options{'all'}, + 'siprec' => \$options{'SIPREC'}, + 'SIPREC' => \$options{'SIPREC'}, 'address=s' => \$options{'address'}, 'pad-crypto' => \$options{'pad crypto'}, 'generate-mid' => \$options{'generate mid'}, @@ -112,7 +114,7 @@ for my $x (split(/,/, 'from-tag,to-tag,call-id,transport protocol,media address, for my $x (split(/,/, 'TOS,delete-delay')) { defined($options{$x}) and $packet{$x} = $options{$x}; } -for my $x (split(/,/, 'trust address,symmetric,asymmetric,unidirectional,force,strict source,media handover,sip source address,reset,port latching,no rtcp attribute,full rtcp attribute,loop protect,record call,always transcode,all,pad crypto,generate mid,fragment,original sendrecv,symmetric codecs,asymmetric codecs,inject DTMF,generate RTCP,single codec,reorder codecs,pierce NAT,SIP-source-address,allow transcoding')) { +for my $x (split(/,/, 'trust address,symmetric,asymmetric,unidirectional,force,strict source,media handover,sip source address,reset,port latching,no rtcp attribute,full rtcp attribute,loop protect,record call,always transcode,all,SIPREC,pad crypto,generate mid,fragment,original sendrecv,symmetric codecs,asymmetric codecs,inject DTMF,generate RTCP,single codec,reorder codecs,pierce NAT,SIP-source-address,allow transcoding')) { defined($options{$x}) and push(@{$packet{flags}}, $x); } for my $x (split(/,/, 'origin,session connection,sdp version,username,session-name,zero-address')) {