diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 150cf42f2..6180a48e6 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -609,6 +609,8 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) { out->reset = 1; else if (!str_cmp(s, "all")) out->all = 1; + else if (!str_cmp(s, "fragment")) + out->fragment = 1; else if (!str_cmp(s, "port-latching")) out->port_latching = 1; else if (!str_cmp(s, "generate-mid")) @@ -833,7 +835,7 @@ static const char *call_offer_answer_ng(bencode_item_t *input, } errstr = "Failed to parse SDP"; - if (sdp_parse(&sdp, &parsed)) + if (sdp_parse(&sdp, &parsed, &flags)) goto out; if (flags.loop_protect && sdp_is_duplicate(&parsed)) { @@ -854,7 +856,8 @@ static const char *call_offer_answer_ng(bencode_item_t *input, * to establish session with another rtpengine2 even though rtpengine1 * might have persisted part of the session. rtpengine2 deletes previous * call in memory and recreates an OWN call in redis */ - if (opmode == OP_OFFER) { + // SDP fragments for trickle ICE must always operate on an existing call + if (opmode == OP_OFFER && !flags.fragment) { if (call) { if (IS_FOREIGN_CALL(call)) { /* destroy call and create new one */ @@ -909,8 +912,11 @@ static const char *call_offer_answer_ng(bencode_item_t *input, recording_start(call, NULL, &flags.metadata); ret = monologue_offer_answer(monologue, &streams, &flags); - if (!ret) - ret = sdp_replace(chopper, &parsed, monologue->active_dialogue, &flags); + if (!ret) { + // SDP fragments for trickle ICE are consumed with no replacement returned + if (!flags.fragment) + ret = sdp_replace(chopper, &parsed, monologue->active_dialogue, &flags); + } struct recording *recording = call->recording; if (recording != NULL) { @@ -943,7 +949,8 @@ static const char *call_offer_answer_ng(bencode_item_t *input, if (ret) goto out; - bencode_dictionary_add_string(output, "sdp", chopper->output->str); + if (chopper->output->len) + bencode_dictionary_add_string(output, "sdp", chopper->output->str); errstr = NULL; out: diff --git a/daemon/sdp.c b/daemon/sdp.c index 43a0c4a59..4ab9fd100 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -877,7 +877,7 @@ static int parse_attribute(struct sdp_attribute *a) { return ret; } -int sdp_parse(str *body, GQueue *sessions) { +int sdp_parse(str *body, GQueue *sessions, const struct sdp_ng_flags *flags) { char *b, *end, *value, *line_end, *next_line; struct sdp_session *session = NULL; struct sdp_media *media = NULL; @@ -915,8 +915,12 @@ int sdp_parse(str *body, GQueue *sessions) { } errstr = "SDP doesn't start with a session definition"; - if (!session && b[0] != 'v') - goto error; + if (!session && b[0] != 'v') { + if (!flags->fragment) + goto error; + else + goto new_session; // allowed for trickle ICE SDP fragments + } str value_str; str_init_len(&value_str, value, line_end - value); @@ -929,6 +933,7 @@ int sdp_parse(str *body, GQueue *sessions) { if (value[0] != '0') goto error; +new_session: session = g_slice_alloc0(sizeof(*session)); g_queue_init(&session->media_streams); attrs_init(&session->attributes); diff --git a/include/call_interfaces.h b/include/call_interfaces.h index b39a6e012..f106bb5a3 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -59,6 +59,7 @@ struct sdp_ng_flags { dtls_passive:1, reset:1, all:1, + fragment:1, record_call:1, loop_protect:1, always_transcode:1, diff --git a/include/sdp.h b/include/sdp.h index 3f208b75e..ee548ee25 100644 --- a/include/sdp.h +++ b/include/sdp.h @@ -19,7 +19,7 @@ struct sdp_chopper { void sdp_init(void); -int sdp_parse(str *body, GQueue *sessions); +int sdp_parse(str *body, GQueue *sessions, const struct sdp_ng_flags *); int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *); void sdp_free(GQueue *sessions); int sdp_replace(struct sdp_chopper *, GQueue *, struct call_monologue *, struct sdp_ng_flags *); diff --git a/utils/rtpengine-ng-client b/utils/rtpengine-ng-client index f5dfb7f48..f1a517759 100755 --- a/utils/rtpengine-ng-client +++ b/utils/rtpengine-ng-client @@ -62,6 +62,7 @@ GetOptions( 'address=s' => \$options{'address'}, 'pad-crypto' => \$options{'pad crypto'}, 'generate-mid' => \$options{'generate mid'}, + 'fragment' => \$options{'fragment'}, ) or die; my $cmd = shift(@ARGV) or die; @@ -74,7 +75,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,force,strict source,media handover,sip source address,reset,port latching,no rtcp attribute,loop protect,record call,always transcode,all,pad crypto,generate mid')) { +for my $x (split(/,/, 'trust address,symmetric,asymmetric,force,strict source,media handover,sip source address,reset,port latching,no rtcp attribute,loop protect,record call,always transcode,all,pad crypto,generate mid,fragment')) { defined($options{$x}) and push(@{$packet{flags}}, $x); } for my $x (split(/,/, 'origin,session connection')) {