diff --git a/daemon/call.c b/daemon/call.c index 776f6a0f8..f37836feb 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -2968,6 +2968,7 @@ int monologue_offer_answer(struct call_monologue *monologues[2], sdp_streams_q * struct call_monologue *receiver_ml = monologues[1]; unsigned int num_ports_this, num_ports_other; bool is_offer = (flags->opmode == OP_OFFER); + unsigned int medias_offset = 0; /* media indexes offset for case with media manipulations */ /* we must have a complete dialogue, even though the to-tag (monologue->tag) * may not be known yet */ @@ -2995,10 +2996,31 @@ int monologue_offer_answer(struct call_monologue *monologues[2], sdp_streams_q * * This affects later the sequencing of medias, e.g. for subscribe requests. */ + /* TODO: refactor this into something more good looking code */ + if (flags->sdp_media_remove[sp->type_id]) { + sp->rtp_endpoint.port = 0; /* pretend it was a zero stream */ + sender_media = __get_media(sender_ml, sp, flags, 0); + sender_media->media_sdp_id = sp->media_sdp_id; + __media_init_from_flags(sender_media, NULL, sp, flags); + num_ports_other = proto_num_ports(sp->num_ports, sender_media, flags, + (flags->rtcp_mux_demux || flags->rtcp_mux_accept) ? true : false); + __disable_streams(sender_media, num_ports_other); + medias_offset++; + + __init_interface(sender_media, &sp->direction[0], num_ports_other); + + if (sender_media->logical_intf == NULL) { + goto error_intf; + } + + ilog(LOG_DEBUG, "Media type '"STR_FORMAT"' is to be removed by SDP manipulations.", STR_FMT(&sp->type)); + continue; + } + /* OP_OFFER, receiver's side, get by index */ receiver_media = NULL; if (is_offer) - receiver_media = __get_media(receiver_ml, sp, flags, 0); + receiver_media = __get_media(receiver_ml, sp, flags, (medias_offset ? (sp->index - medias_offset) : 0)); /* OP_OFFER/OP_ANSWER, sender's side, get by index */ sender_media = __get_media(sender_ml, sp, flags, 0); diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 75eddbd48..ab661d656 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -642,6 +642,9 @@ err: ilog(LOG_WARN, "SDP manipulations: Ignoring invalid contents of string-pair list"); } +/** + * SDP attribute manipulation praser helpers. + */ static void ng_sdp_attr_media_iter(const ng_parser_t *parser, str *command_type, parser_arg command_value, helper_arg arg) { @@ -684,6 +687,27 @@ INLINE void ng_sdp_attr_manipulations(const ng_parser_t *parser, sdp_ng_flags *f ilog(LOG_WARN, "SDP manipulations: Wrong type for this type of command."); } +/** + * SDP media section manipulation parser helpers. + */ +static void ng_sdp_media_remove_iter(str *media_type, unsigned int i, helper_arg arg) +{ + enum media_type id = codec_get_type(media_type); + if (id == MT_UNKNOWN || id == MT_OTHER) + { + ilog(LOG_WARN, "SDP manipulations: unsupported SDP section '" STR_FORMAT "' targeted.", + STR_FMT(media_type)); + /* only known media types are supported */ + return; + } + arg.flags->sdp_media_remove[id] = true; +} +INLINE void ng_sdp_media_remove(const ng_parser_t *parser, sdp_ng_flags *flags, parser_arg value) { + if (!parser->is_list(value)) + return; + parser->list_iter(parser, value, ng_sdp_media_remove_iter, NULL, flags); +} + INLINE void ng_el_option(str *s, unsigned int idx, helper_arg arg) { sdp_ng_flags *out = arg.flags; switch (__csh_lookup(s)) { @@ -1290,6 +1314,8 @@ void call_ng_flags_init(sdp_ng_flags *out, enum call_opmode opmode) { out->volume = 9999; out->digit = -1; out->frequencies = g_array_new(false, false, sizeof(int)); + for (int i = 0; i < __MT_MAX; ++i) + out->sdp_media_remove[i] = false; } static void call_ng_direction_flag_iter(str *s, unsigned int i, helper_arg arg) { @@ -1883,6 +1909,12 @@ void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, h case CSH_LOOKUP("SDP-attr"): ng_sdp_attr_manipulations(parser, out, value); break; + case CSH_LOOKUP("sdp-media-remove"): + case CSH_LOOKUP("SDP-media-remove"): + case CSH_LOOKUP("sdp_media_remove"): + case CSH_LOOKUP("SDP_media_remove"): + ng_sdp_media_remove(parser, out, value); + break; case CSH_LOOKUP("set-label"): out->set_label = s; break; diff --git a/include/call_interfaces.h b/include/call_interfaces.h index 438ccb37f..736d13436 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -72,6 +72,8 @@ struct sdp_ng_flags { /* commands to manipulate attr lines in SDP */ struct sdp_manipulations * sdp_manipulations[__MT_MAX]; + /* types of medias to be removed by media lvl manipulations */ + bool sdp_media_remove[__MT_MAX]; enum { ICE_DEFAULT = 0, @@ -321,6 +323,7 @@ INLINE struct sdp_manipulations *sdp_manipulations_get_by_name(struct sdp_manipu return NULL; return sdp_manipulations_get_create_by_id(array, id); } + // set all WebRTC-specific attributes INLINE void ng_flags_webrtc(sdp_ng_flags *f) { f->transport_protocol = &transport_protocols[PROTO_UDP_TLS_RTP_SAVPF]; diff --git a/t/auto-daemon-tests.pl b/t/auto-daemon-tests.pl index 5b61cc084..ea09f9c9d 100755 --- a/t/auto-daemon-tests.pl +++ b/t/auto-daemon-tests.pl @@ -20541,6 +20541,124 @@ a=crypto:4 AES_256_CM_HMAC_SHA1_32 inline:CRYPTO256 SDP +# Arbitrary SDP media level manipulations + +new_call; + +offer('SDP media manipulations - remove video', { ICE => 'remove', DTLS => 'off', SDES => [ 'nonew' ], 'sdp-media-remove' => ['video']}, < 'remove' }, < 'remove', DTLS => 'off', SDES => [ 'nonew' ], 'sdp-media-remove' => ['audio']}, < 'remove' }, <