diff --git a/daemon/call.c b/daemon/call.c index fe30be7a2..7f089fe60 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2637,6 +2637,7 @@ static void __media_init_from_flags(struct call_media *other_media, struct call_ struct stream_params *sp, struct sdp_ng_flags *flags) { struct call *call = other_media->call; + GQueue *additional_attributes = &sp->attributes; /* attributes in str format */ if (flags && flags->opmode == OP_OFFER && flags->reset) { if (media) @@ -2719,6 +2720,19 @@ static void __media_init_from_flags(struct call_media *other_media, struct call_ } } + /* moved as plain text attributes, required later by sdp_create() + * ssrc + * other (unknown type) + */ + if (media && additional_attributes && additional_attributes->head) { + g_queue_clear_full(&media->sdp_attributes, free); + for (const GList *l = additional_attributes->head; l; l = l->next) { + str *source_attr = l->data; + str * destination_attr = str_dup(source_attr); + g_queue_push_tail(&media->sdp_attributes, destination_attr); + } + } + // codec and RTP payload types handling if (sp->ptime > 0) { if (media && !MEDIA_ISSET(media, PTIME_OVERRIDE)) diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 5acdb7fbc..5c690e3ce 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -2078,7 +2078,7 @@ static const char *call_offer_answer_ng(struct ng_buffer *ngbuf, bencode_item_t ret = monologue_offer_answer(monologues, &streams, &flags); if (!ret) - ret = sdp_replace(chopper, &parsed, to_ml, &flags); + ret = sdp_replace(chopper, &parsed, to_ml, &flags, true); if (!ret) save_last_sdp(from_ml, &sdp, &parsed, &streams); @@ -3415,7 +3415,7 @@ const char *call_publish_ng(struct ng_buffer *ngbuf, bencode_item_t *input, benc if (ret) ilog(LOG_ERR, "Publish error"); // XXX close call? handle errors? - ret = sdp_create(&sdp_out, ml, &flags); + ret = sdp_create(&sdp_out, ml, &flags, true); if (!ret) { save_last_sdp(ml, &sdp_in, &parsed, &streams); bencode_buffer_destroy_add(output->buffer, g_free, sdp_out.s); @@ -3491,12 +3491,12 @@ const char *call_subscribe_request_ng(bencode_item_t *input, bencode_item_t *out return "Failed to request subscription"; if (chopper && sdp_ml) { - ret = sdp_replace(chopper, &sdp_ml->last_in_sdp_parsed, dest_ml, &flags); + ret = sdp_replace(chopper, &sdp_ml->last_in_sdp_parsed, dest_ml, &flags, false); if (ret) return "Failed to rewrite SDP"; } else { /* create new SDP */ - ret = sdp_create(&sdp_out, dest_ml, &flags); + ret = sdp_create(&sdp_out, dest_ml, &flags, false); } /* place return output SDP */ diff --git a/daemon/janus.c b/daemon/janus.c index 3694f812c..b3cb92878 100644 --- a/daemon/janus.c +++ b/daemon/janus.c @@ -630,7 +630,7 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan return "Subscribe error"; /* create SDP */ - ret = sdp_create(jsep_sdp_out, dest_ml, &flags); + ret = sdp_create(jsep_sdp_out, dest_ml, &flags, true); if (!dest_ml->janus_session) dest_ml->janus_session = obj_get(session); @@ -865,7 +865,7 @@ static const char *janus_videoroom_configure(struct websocket_message *wm, struc // XXX check there's only one audio and one video stream? AUTO_CLEANUP(str sdp_out, str_free_dup) = STR_NULL; - ret = sdp_create(&sdp_out, ml, &flags); + ret = sdp_create(&sdp_out, ml, &flags, true); if (ret) return "Publish error"; diff --git a/daemon/sdp.c b/daemon/sdp.c index d4eb61a77..b1bc64b88 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -258,6 +258,13 @@ struct sdp_attribute { ATTR_T38FAXTRANSCODINGMMR, ATTR_T38FAXTRANSCODINGJBIG, ATTR_T38FAXRATEMANAGEMENT, + ATTR_T38MAXBITRATE, + ATTR_T38FAXMAXBUFFER, + ATTR_XG726BITORDER, + ATTR_MAXPTIME, + ATTR_DIRECTION, + ATTR_LABEL, + ATTR_MSID, ATTR_TLS_ID, ATTR_END_OF_CANDIDATES, } attr; @@ -1171,6 +1178,27 @@ static int parse_attribute(struct sdp_attribute *a) { case CSH_LOOKUP("T38FaxRateManagement"): ret = parse_attribute_t38faxratemanagement(a); break; + case CSH_LOOKUP("T38MaxBitRate"): + a->attr = ATTR_T38MAXBITRATE; + break; + case CSH_LOOKUP("T38FaxMaxBuffer"): + a->attr = ATTR_T38FAXMAXBUFFER; + break; + case CSH_LOOKUP("xg726bitorder"): + a->attr = ATTR_XG726BITORDER; + break; + case CSH_LOOKUP("maxptime"): + a->attr = ATTR_MAXPTIME; + break; + case CSH_LOOKUP("label"): + a->attr = ATTR_LABEL; + break; + case CSH_LOOKUP("direction"): + a->attr = ATTR_DIRECTION; + break; + case CSH_LOOKUP("msid"): + a->attr = ATTR_MSID; + break; } return ret; @@ -1618,6 +1646,7 @@ static void sp_free(void *p) { codec_store_cleanup(&s->codecs); ice_candidates_free(&s->ice_candidates); crypto_params_sdes_queue_clear(&s->sdes_params); + g_queue_clear_full(&s->attributes, free); g_slice_free1(sizeof(*s), s); } @@ -1781,6 +1810,30 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl cps->params.session_params.unauthenticated_srtp = attr->crypto.unauthenticated_srtp; } + /* a=ssrc, move them via plain text attributes, required later by sdp_create() */ + attrs = attr_list_get_by_id(&media->attributes, ATTR_SSRC); + for (GList *ll = attrs ? attrs->head : NULL; ll; ll = ll->next) { + attr = ll->data; + str * ret = str_dup(&attr->line_value); + g_queue_push_tail(&sp->attributes, ret); + } + + /* a=msid, move via plain text attributes, required later by sdp_create() */ + attrs = attr_list_get_by_id(&media->attributes, ATTR_MSID); + for (GList *ll = attrs ? attrs->head : NULL; ll; ll = ll->next) { + attr = ll->data; + str * ret = str_dup(&attr->line_value); + g_queue_push_tail(&sp->attributes, ret); + } + + /* move all other unknown type attributes also, required later by sdp_create() */ + attrs = attr_list_get_by_id(&media->attributes, ATTR_OTHER); + for (GList *ll = attrs ? attrs->head : NULL; ll; ll = ll->next) { + attr = ll->data; + str * ret = str_dup(&attr->line_value); + g_queue_push_tail(&sp->attributes, ret); + } + /* a=sendrecv/sendonly/recvonly/inactive */ SP_SET(sp, SEND); SP_SET(sp, RECV); @@ -2087,11 +2140,10 @@ static void insert_codec_parameters(GString *s, struct call_media *cm, } } -static void insert_sdp_attributes(GString *gs, struct call_media *cm) { +static void insert_sdp_attributes(GString *gs, struct call_media *cm, struct sdp_ng_flags *flags) { for (GList *l = cm->sdp_attributes.head; l; l = l->next) { str *s = l->data; - g_string_append_printf(gs, "a=" STR_FORMAT "\r\n", - STR_FMT(s)); + append_attr_to_gstring(gs, s->s, NULL, flags, cm->type_id); } } @@ -2343,7 +2395,7 @@ strip_with_subst: /* processing existing media attributes (those present in offer/answer) */ static int process_media_attributes(struct sdp_chopper *chop, struct sdp_media *sdp, - struct sdp_ng_flags *flags, struct call_media *media) + struct sdp_ng_flags *flags, struct call_media *media, bool strip_attr_other) { GList *l; struct sdp_attributes *attrs = &sdp->attributes; @@ -2401,6 +2453,17 @@ static int process_media_attributes(struct sdp_chopper *chop, struct sdp_media * goto strip; break; + /* strip all unknown type attributes if required, additionally: + * ssrc + * everything related to T38 + */ + case ATTR_OTHER: + case ATTR_SSRC: + case ATTR_MSID: + if (strip_attr_other) + goto strip; + break; + default: break; } @@ -2447,6 +2510,16 @@ static int process_media_attributes(struct sdp_chopper *chop, struct sdp_media * break; goto strip; + /* strip all unknown type attributes if required, additionally: + * ssrc + */ + case ATTR_OTHER: + case ATTR_SSRC: + case ATTR_MSID: + if (strip_attr_other) + goto strip; + break; + default: break; } @@ -2864,7 +2937,8 @@ static void append_attr_to_gstring(GString *s, char * name, const str * value, /* first check if the originally present attribute is to be removed */ if (sdp_manipulate_remove(sdp_manipulations, &attr)) { - ilog(LOG_DEBUG, "Cannot insert: '%s' because prevented by SDP manipulations (remove)", name); + ilog(LOG_DEBUG, "Cannot insert: '" STR_FORMAT "' because prevented by SDP manipulations (remove)", + STR_FMT(&attr)); return; } @@ -2898,7 +2972,8 @@ static void append_attr_int_to_gstring(GString *s, char * name, const int * valu /* first check if the originally present attribute is to be removed */ if (sdp_manipulate_remove(sdp_manipulations, &attr)) { - ilog(LOG_DEBUG, "Cannot insert: '%s' because prevented by SDP manipulations (remove)", name); + ilog(LOG_DEBUG, "Cannot insert: '" STR_FORMAT "' because prevented by SDP manipulations (remove)", + STR_FMT(&attr)); return; } @@ -2969,7 +3044,10 @@ static void print_sdp_session_section(GString *s, struct sdp_ng_flags *flags, static struct packet_stream *print_sdp_media_section(GString *s, struct call_media *media, struct sdp_media *sdp_media, struct sdp_ng_flags *flags, - GList *rtp_ps_link, bool is_active, bool force_end_of_ice) + GList *rtp_ps_link, + bool is_active, + bool force_end_of_ice, + bool print_other_attrs) { struct packet_stream *rtp_ps = rtp_ps_link->data; struct packet_stream *ps_rtcp = NULL; @@ -2983,7 +3061,9 @@ static struct packet_stream *print_sdp_media_section(GString *s, struct call_med if (proto_is_rtp(media->protocol)) insert_codec_parameters(s, media, flags); - insert_sdp_attributes(s, media); + /* all unknown type attributes will be added here */ + if (print_other_attrs) + insert_sdp_attributes(s, media, flags); /* print sendrecv */ if (!flags->original_sendrecv) @@ -3027,7 +3107,7 @@ static struct packet_stream *print_sdp_media_section(GString *s, struct call_med static const char *replace_sdp_media_section(struct sdp_chopper *chop, struct call_media *call_media, struct sdp_media *sdp_media, GList *rtp_ps_link, struct sdp_ng_flags *flags, - const bool keep_zero_address) + const bool keep_zero_address, bool print_other_attrs) { const char *err = NULL; struct packet_stream *ps = rtp_ps_link->data; @@ -3068,8 +3148,9 @@ static const char *replace_sdp_media_section(struct sdp_chopper *chop, struct ca goto next; } + /* all unknown type attributes will stripped here */ err = "failed to process media attributes"; - if (process_media_attributes(chop, sdp_media, flags, call_media)) + if (process_media_attributes(chop, sdp_media, flags, call_media, true)) goto error; copy_up_to_end_of(chop, &sdp_media->s); @@ -3079,7 +3160,7 @@ static const char *replace_sdp_media_section(struct sdp_chopper *chop, struct ca next: print_sdp_media_section(chop->output, call_media, sdp_media, flags, rtp_ps_link, is_active, - attr_get_by_id(&sdp_media->attributes, ATTR_END_OF_CANDIDATES)); + attr_get_by_id(&sdp_media->attributes, ATTR_END_OF_CANDIDATES), print_other_attrs); return NULL; error: @@ -3089,7 +3170,7 @@ error: /* called with call->master_lock held in W */ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologue *monologue, - struct sdp_ng_flags *flags) + struct sdp_ng_flags *flags, bool print_other_attrs) { struct sdp_session *session; struct sdp_media *sdp_media; @@ -3246,7 +3327,8 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu call_media->protocol = prtp; err = replace_sdp_media_section(chop, call_media, sdp_media, rtp_ps_link, flags, - keep_zero_address); + keep_zero_address, + print_other_attrs); *chop = chop_copy; call_media->protocol = proto; if (err) @@ -3256,7 +3338,8 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu err = replace_sdp_media_section(chop, call_media, sdp_media, rtp_ps_link, flags, - keep_zero_address); + keep_zero_address, + print_other_attrs); if (err) goto error; @@ -3299,7 +3382,9 @@ error: return -1; } -int sdp_create(str *out, struct call_monologue *monologue, struct sdp_ng_flags *flags) { +int sdp_create(str *out, struct call_monologue *monologue, struct sdp_ng_flags *flags, + bool print_other_attrs) +{ const char *err = NULL; GString *s = NULL; @@ -3362,7 +3447,7 @@ int sdp_create(str *out, struct call_monologue *monologue, struct sdp_ng_flags * g_string_append_printf(s, "\r\nc=IN %s %s\r\n", rtp_ps->selected_sfd->local_intf->advertised_address.addr.family->rfc_name, sockaddr_print_buf(&rtp_ps->selected_sfd->local_intf->advertised_address.addr)); - print_sdp_media_section(s, media, NULL, flags, rtp_ps_link, true, false); + print_sdp_media_section(s, media, NULL, flags, rtp_ps_link, true, false, print_other_attrs); } out->len = s->len; diff --git a/include/call.h b/include/call.h index b5d114231..1a9316d46 100644 --- a/include/call.h +++ b/include/call.h @@ -322,6 +322,7 @@ struct stream_params { const struct transport_protocol *protocol; str format_str; GQueue sdes_params; // slice-alloc'd + GQueue attributes; /* just some other attributes */ str direction[2]; sockfamily_t *desired_family; struct dtls_fingerprint fingerprint; diff --git a/include/sdp.h b/include/sdp.h index d5c3c033e..0a3b188e3 100644 --- a/include/sdp.h +++ b/include/sdp.h @@ -33,9 +33,11 @@ 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_streams_free(GQueue *); void sdp_free(GQueue *sessions); -int sdp_replace(struct sdp_chopper *, GQueue *, struct call_monologue *, struct sdp_ng_flags *); +int sdp_replace(struct sdp_chopper *, GQueue *, struct call_monologue *, struct sdp_ng_flags *, + bool print_other_attrs); int sdp_is_duplicate(GQueue *sessions); -int sdp_create(str *out, struct call_monologue *, struct sdp_ng_flags *flags); +int sdp_create(str *out, struct call_monologue *, struct sdp_ng_flags *flags, + bool print_other_attrs); const char *sdp_get_sendrecv(struct call_media *media); int sdp_parse_candidate(struct ice_candidate *cand, const str *s); // returns -1, 0, 1 diff --git a/t/auto-daemon-tests-websocket.py b/t/auto-daemon-tests-websocket.py index ba0db5331..b4af8b8b3 100644 --- a/t/auto-daemon-tests-websocket.py +++ b/t/auto-daemon-tests-websocket.py @@ -1725,6 +1725,11 @@ class TestVideoroom(unittest.TestCase): "a=rtpmap:111 opus/48000/2\r\n" "a=fmtp:111 useinbandfec=1; minptime=10\r\n" "a=rtcp-fb:111 transport-cc\r\n" + "a=ssrc:677770262 cname:NMNDwVd66x2SfiO0\r\n" + "a=ssrc:677770262 msid:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC 2de0f1b0-3a39-450e-9804-8305ec87452b\r\n" + "a=ssrc:677770262 mslabel:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC\r\n" + "a=ssrc:677770262 label:2de0f1b0-3a39-450e-9804-8305ec87452b\r\n" + "a=msid:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC 2de0f1b0-3a39-450e-9804-8305ec87452b\r\n" "a=sendonly\r\n" "a=rtcp-mux\r\n" "a=setup:actpass\r\n" @@ -1744,6 +1749,17 @@ class TestVideoroom(unittest.TestCase): "a=rtcp-fb:96 ccm fir\r\n" "a=rtcp-fb:96 nack\r\n" "a=rtcp-fb:96 nack pli\r\n" + "a=ssrc:3005569364 cname:NMNDwVd66x2SfiO0\r\n" + "a=ssrc:3005569364 msid:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC 6d6ec7a7-e3d7-4c82-b03c-45e017713abd\r\n" + "a=ssrc:3005569364 mslabel:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC\r\n" + "a=ssrc:3005569364 label:6d6ec7a7-e3d7-4c82-b03c-45e017713abd\r\n" + "a=ssrc:2001490794 cname:NMNDwVd66x2SfiO0\r\n" + "a=ssrc:2001490794 msid:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC 6d6ec7a7-e3d7-4c82-b03c-45e017713abd\r\n" + "a=ssrc:2001490794 mslabel:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC\r\n" + "a=ssrc:2001490794 label:6d6ec7a7-e3d7-4c82-b03c-45e017713abd\r\n" + "a=msid:hJifdaJwqEqHxSG0pVbs1DrLAwiHqz7fKlqC 6d6ec7a7-e3d7-4c82-b03c-45e017713abd\r\n" + "a=rtcp-rsize\r\n" + "a=ssrc-group:FID 3005569364 2001490794\r\n" "a=sendonly\r\n" "a=rtcp-mux\r\n" "a=setup:actpass\r\n" diff --git a/t/auto-daemon-tests.pl b/t/auto-daemon-tests.pl index 784b8e49a..202aec060 100755 --- a/t/auto-daemon-tests.pl +++ b/t/auto-daemon-tests.pl @@ -119,15 +119,15 @@ t=0 0 a=extmap-allow-mixed a=msid-semantic: WMS 61cc3524-d456-4497-b92e-2babd3d83d84 m=audio PORT RTP/SAVPF 96 97 -a=msid:61cc3524-d456-4497-b92e-2babd3d83d84 02c5b74b-b03e-44a6-b175-6639fa009f2d -a=ssrc:889323910 cname:OCP1KqOq/lFpZRp0 -a=ssrc:889323910 msid:61cc3524-d456-4497-b92e-2babd3d83d84 02c5b74b-b03e-44a6-b175-6639fa009f2d -a=rtcp-xr:voip-metrics a=mid:1 a=rtpmap:96 opus/48000/2 a=fmtp:96 useinbandfec=1 a=rtpmap:97 telephone-event/48000 a=fmtp:97 0-15 +a=ssrc:889323910 cname:OCP1KqOq/lFpZRp0 +a=ssrc:889323910 msid:61cc3524-d456-4497-b92e-2babd3d83d84 02c5b74b-b03e-44a6-b175-6639fa009f2d +a=msid:61cc3524-d456-4497-b92e-2babd3d83d84 02c5b74b-b03e-44a6-b175-6639fa009f2d +a=rtcp-xr:voip-metrics a=sendonly a=rtcp:PORT a=rtcp-mux @@ -179,10 +179,10 @@ a=extmap-allow-mixed a=msid-semantic: WMS 4d091157-8680-47a2-b124-36b52fefea19 m=audio PORT RTP/AVP 0 126 c=IN IP4 203.0.113.1 -a=msid:4d091157-8680-47a2-b124-36b52fefea19 ed2eaf3a-926c-4c1a-a315-e02458e05292 -a=ssrc:572293880 cname:pHBBuw7Qa5BaQ36a a=rtpmap:0 PCMU/8000 a=rtpmap:126 telephone-event/8000 +a=ssrc:572293880 cname:pHBBuw7Qa5BaQ36a +a=msid:4d091157-8680-47a2-b124-36b52fefea19 ed2eaf3a-926c-4c1a-a315-e02458e05292 a=recvonly a=ptime:20 SDP @@ -231,14 +231,14 @@ a=extmap-allow-mixed a=msid-semantic: WMS 4d091157-8680-47a2-b124-36b52fefea19 m=audio PORT RTP/AVP 0 8 9 96 c=IN IP4 203.0.113.1 -a=msid:4d091157-8680-47a2-b124-36b52fefea19 ed2eaf3a-926c-4c1a-a315-e02458e05292 -a=ssrc:572293880 cname:pHBBuw7Qa5BaQ36a a=mid:1 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:9 G722/8000 a=rtpmap:96 telephone-event/8000 a=fmtp:96 0-15 +a=ssrc:572293880 cname:pHBBuw7Qa5BaQ36a +a=msid:4d091157-8680-47a2-b124-36b52fefea19 ed2eaf3a-926c-4c1a-a315-e02458e05292 a=sendrecv a=ptime:20 SDP @@ -285,22 +285,20 @@ a=extmap-allow-mixed a=msid-semantic: WMS 4d091157-8680-47a2-b124-36b52fefea19 m=audio PORT RTP/AVP 0 8 9 96 c=IN IP4 203.0.113.1 -a=msid:4d091157-8680-47a2-b124-36b52fefea19 ed2eaf3a-926c-4c1a-a315-e02458e05292 -a=ssrc:572293880 cname:pHBBuw7Qa5BaQ36a a=mid:1 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 a=rtpmap:9 G722/8000 a=rtpmap:96 telephone-event/8000 a=fmtp:96 0-15 +a=ssrc:572293880 cname:pHBBuw7Qa5BaQ36a +a=msid:4d091157-8680-47a2-b124-36b52fefea19 ed2eaf3a-926c-4c1a-a315-e02458e05292 a=sendrecv a=ptime:20 SDP - - new_call; offer('AMR asymmetric, control', {}, <