From 241c78c91573ea11a4b53fd88c9174ddb9f2a99d Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 11 Sep 2020 14:18:02 -0400 Subject: [PATCH] TT#92250 add codec-except option Additionally allow `except` and `offer` (and `transcode`) to revert masked codecs. Also adds `mask=full` and `strip=full` closes #1054 Change-Id: I93a2891f2a0b9d324f6804e38f992be73c46211a --- README.md | 34 ++++++++---- daemon/call_interfaces.c | 6 ++ daemon/codec.c | 114 +++++++++++++++++++++++++++----------- include/call_interfaces.h | 1 + t/auto-daemon-tests.pl | 58 ++++++++++++++++++- 5 files changed, 167 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 6aad98e73..068b3adcf 100644 --- a/README.md +++ b/README.md @@ -1108,16 +1108,25 @@ Optionally included keys are: all codecs and leave none that could be offered. In this case, the original list of codecs will be left unchanged. - * `offer` + The keyword `full` can also be used, which behaves the same as `all` with the + exception listed under `transcode` below. + + * `except` Contains a list of strings. Each string is the name of a codec that should be included in the list of codecs offered. This is primarily useful to block all - codecs (`strip -> all`) except the ones given in the `offer` whitelist. - Codecs that were not present in the original list of codecs + codecs (`strip -> all` or `mask -> all`) except the ones given in the `except` + whitelist. Codecs that were not present in the original list of codecs offered by the client will be ignored. This list also supports codec format parameters as per above. + * `offer` + + This is identical to `except` but additionally allows the codec order to be + changed. So the first codec listed in `offer` will be the primary (preferred) + codec in the output SDP, even if it wasn't originally so. + * `transcode` Similar to `offer` but allows codecs to be added to the list of offered codecs @@ -1150,15 +1159,16 @@ Optionally included keys are: interpreted as a key-value pair), it can be escaped by using two dashes instead, e.g. `iLBC/8000/1///mode--30`. - As a special case, if the `strip=all` option has been used and the `transcode` - option is used on a codec that was originally present in the offer, then - *rtpengine* will treat this codec the same as if it had been used with the `offer` - option, i.e. it will simply restore it from the list of stripped codecs and won't - actually engage transcoding for this codec. On the other hand, if a codec has - been stripped explicitly by name using the `strip` option and then used again + As a special case, if the `strip=all` or `mask=all` option has been used and + the `transcode` option is used on a codec that was originally present in the offer, + then *rtpengine* will treat this codec the same as if it had been used with the + `offer` option, i.e. it will simply restore it from the list of stripped codecs and + won't actually engage transcoding for this codec. On the other hand, if a codec has + been stripped explicitly by name using the `strip` or `mask` option and then used again with the `transcode` option, then the codec will not simply be restored from the list of stripped codecs, but instead a new transcoded instance of the codec will - be inserted into the offer. + be inserted into the offer. (This special exception does not apply to `mask=full` + or `strip=full`.) * `mask` @@ -1172,8 +1182,8 @@ Optionally included keys are: hand, if `strip=opus, transcode=G723` were given, then Opus would be unavailable for transcoding. - As with the `strip` option, the special keyword `all` can be used to mask all - codecs that have been offered. + As with the `strip` option, the special keywords `all` and `full` can be used + to mask all codecs that have been offered. * `set` diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index b9cdc211a..97ad27315 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -837,6 +837,9 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) { if (call_ng_flags_prefix(out, s, "codec-offer-", call_ng_flags_codec_list, &out->codec_offer)) return; + if (call_ng_flags_prefix(out, s, "codec-except-", call_ng_flags_str_ht, + &out->codec_except)) + return; #ifdef WITH_TRANSCODING if (call_ng_flags_prefix(out, s, "transcode-", call_ng_flags_codec_list, &out->codec_transcode)) @@ -1003,6 +1006,7 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu if (opmode == OP_OFFER && (dict = bencode_dictionary_get_expect(input, "codec", BENCODE_DICTIONARY))) { call_ng_flags_list(out, dict, "strip", call_ng_flags_str_ht, &out->codec_strip); call_ng_flags_list(out, dict, "offer", call_ng_flags_codec_list, &out->codec_offer); + call_ng_flags_list(out, dict, "except", call_ng_flags_str_ht, &out->codec_except); #ifdef WITH_TRANSCODING call_ng_flags_list(out, dict, "transcode", call_ng_flags_codec_list, &out->codec_transcode); call_ng_flags_list(out, dict, "mask", call_ng_flags_str_ht, &out->codec_mask); @@ -1013,6 +1017,8 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu static void call_ng_free_flags(struct sdp_ng_flags *flags) { if (flags->codec_strip) g_hash_table_destroy(flags->codec_strip); + if (flags->codec_except) + g_hash_table_destroy(flags->codec_except); if (flags->codec_mask) g_hash_table_destroy(flags->codec_mask); if (flags->codec_set) diff --git a/daemon/codec.c b/daemon/codec.c index 95337fba0..461635605 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -2293,21 +2293,39 @@ static void __payload_queue_free(void *qq) { GQueue *q = qq; g_queue_free_full(q, (GDestroyNotify) payload_type_free); } -static int __revert_codec_strip(GHashTable *removed, const str *codec, +static int __revert_codec_strip(GHashTable *stripped, GHashTable *masked, const str *codec, struct call_media *media, struct call_media *other_media, struct supp_codec_tracker *sct) { - GQueue *q = g_hash_table_lookup(removed, codec); - if (!q) - return 0; - ilog(LOG_DEBUG, "Restoring codec '" STR_FORMAT "' from stripped codecs (%u payload types)", - STR_FMT(codec), q->length); - g_hash_table_steal(removed, codec); - for (GList *l = q->head; l; l = l->next) { - struct rtp_payload_type *pt = l->data; - __rtp_payload_type_add(media, other_media, pt, sct); + int ret = 0; + + GQueue *q = g_hash_table_lookup(stripped, codec); + if (q) { + ilog(LOG_DEBUG, "Restoring codec '" STR_FORMAT "' from stripped codecs (%u payload types)", + STR_FMT(codec), q->length); + g_hash_table_steal(stripped, codec); + for (GList *l = q->head; l; l = l->next) { + struct rtp_payload_type *pt = l->data; + __rtp_payload_type_add(media, other_media, pt, sct); + } + g_queue_free(q); + ret = 1; } - g_queue_free(q); - return 1; + + q = g_hash_table_lookup(masked, codec); + if (q) { + ilog(LOG_DEBUG, "Restoring codec '" STR_FORMAT "' from masked codecs (%u payload types)", + STR_FMT(codec), q->length); + g_hash_table_steal(masked, codec); + for (GList *l = q->head; l; l = l->next) { + struct rtp_payload_type *pt = l->data; + pt->for_transcoding = 1; + __rtp_payload_type_add_recv(media, pt, 1, sct); + } + g_queue_free(q); + ret = 1; + } + + return ret; } static int __codec_options_set1(struct call *call, struct rtp_payload_type *pt, const str *enc, GHashTable *codec_set) @@ -2436,6 +2454,24 @@ static void supp_codecs_fixup(struct supp_codec_tracker *sct, struct call_media g_list_free(supp_codecs); g_list_free(clockrates); } +int __codec_ht_except(int all_flag, GHashTable *yes_ht, GHashTable *no_ht, struct rtp_payload_type *pt) { + int do_this = 0; + if (all_flag) + do_this = 1; + if (yes_ht) { + if (g_hash_table_lookup(yes_ht, &pt->encoding)) + do_this = 1; + else if (g_hash_table_lookup(yes_ht, &pt->encoding_with_params)) + do_this = 1; + } + if (no_ht) { + if (g_hash_table_lookup(no_ht, &pt->encoding)) + do_this = 0; + else if (g_hash_table_lookup(no_ht, &pt->encoding_with_params)) + do_this = 0; + } + return do_this; +} void codec_rtp_payload_types(struct call_media *media, struct call_media *other_media, GQueue *types, struct sdp_ng_flags *flags) { @@ -2446,7 +2482,9 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_ struct call *call = media->call; struct rtp_payload_type *pt; static const str str_all = STR_CONST_INIT("all"); - GHashTable *removed = g_hash_table_new_full(str_case_hash, str_case_equal, NULL, __payload_queue_free); + static const str str_full = STR_CONST_INIT("full"); + GHashTable *stripped = g_hash_table_new_full(str_case_hash, str_case_equal, NULL, __payload_queue_free); + GHashTable *masked = g_hash_table_new_full(str_case_hash, str_case_equal, NULL, __payload_queue_free); int strip_all = 0, mask_all = 0; // start fresh @@ -2470,8 +2508,12 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_ if (flags->codec_strip && g_hash_table_lookup(flags->codec_strip, &str_all)) strip_all = 1; + if (flags->codec_strip && g_hash_table_lookup(flags->codec_strip, &str_all)) + strip_all = 2; if (flags->codec_mask && g_hash_table_lookup(flags->codec_mask, &str_all)) mask_all = 1; + else if (flags->codec_mask && g_hash_table_lookup(flags->codec_mask, &str_full)) + mask_all = 2; struct supp_codec_tracker sct; supp_codec_tracker_init(&sct); @@ -2481,34 +2523,38 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_ __rtp_payload_type_dup(call, pt); // this takes care of string allocation // codec stripping - if (flags->codec_strip) { - if (strip_all || g_hash_table_lookup(flags->codec_strip, &pt->encoding) - || g_hash_table_lookup(flags->codec_strip, &pt->encoding_with_params)) - { - ilog(LOG_DEBUG, "Stripping codec '" STR_FORMAT "'", - STR_FMT(&pt->encoding_with_params)); - codec_touched(pt, &sct, media); - GQueue *q = g_hash_table_lookup_queue_new(removed, &pt->encoding); - g_queue_push_tail(q, __rtp_payload_type_copy(pt)); - q = g_hash_table_lookup_queue_new(removed, &pt->encoding_with_params); - g_queue_push_tail(q, pt); - continue; - } + if (__codec_ht_except(strip_all, flags->codec_strip, flags->codec_except, pt)) { + ilog(LOG_DEBUG, "Stripping codec '" STR_FORMAT "'", + STR_FMT(&pt->encoding_with_params)); + codec_touched(pt, &sct, media); + GQueue *q = g_hash_table_lookup_queue_new(stripped, &pt->encoding); + g_queue_push_tail(q, __rtp_payload_type_copy(pt)); + q = g_hash_table_lookup_queue_new(stripped, &pt->encoding_with_params); + g_queue_push_tail(q, pt); + continue; } + __codec_options_set(call, pt, flags->codec_set); - if (!mask_all && (!flags->codec_mask || !g_hash_table_lookup(flags->codec_mask, &pt->encoding)) - && (!flags->codec_mask || !g_hash_table_lookup(flags->codec_mask, &pt->encoding_with_params))) - __rtp_payload_type_add(media, other_media, pt, &sct); - else { + + // codec masking + if (__codec_ht_except(mask_all, flags->codec_mask, flags->codec_except, pt)) { + ilog(LOG_DEBUG, "Masking codec '" STR_FORMAT "'", + STR_FMT(&pt->encoding_with_params)); codec_touched(pt, &sct, other_media); + GQueue *q = g_hash_table_lookup_queue_new(masked, &pt->encoding); + g_queue_push_tail(q, __rtp_payload_type_copy(pt)); + q = g_hash_table_lookup_queue_new(stripped, &pt->encoding_with_params); + g_queue_push_tail(q, __rtp_payload_type_copy(pt)); __rtp_payload_type_add_send(other_media, pt); } + else + __rtp_payload_type_add(media, other_media, pt, &sct); } // now restore codecs that have been removed, but should be offered for (GList *l = flags->codec_offer.head; l; l = l->next) { str *codec = l->data; - __revert_codec_strip(removed, codec, media, other_media, &sct); + __revert_codec_strip(stripped, masked, codec, media, other_media, &sct); } if (!flags->asymmetric_codecs) { @@ -2534,7 +2580,8 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_ // and removed by a strip=all option, // simply restore it from the original list and handle it the same way // as 'offer' - if (strip_all && __revert_codec_strip(removed, codec, media, other_media, &sct)) + if ((strip_all == 1 || mask_all == 1) + && __revert_codec_strip(stripped, masked, codec, media, other_media, &sct)) continue; // also check if maybe the codec was never stripped if (g_hash_table_lookup(media->codec_names_recv, codec)) { @@ -2608,6 +2655,7 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_ supp_codecs_fixup(&sct, media); - g_hash_table_destroy(removed); + g_hash_table_destroy(stripped); + g_hash_table_destroy(masked); supp_codec_tracker_destroy(&sct); } diff --git a/include/call_interfaces.h b/include/call_interfaces.h index dc8161679..2673d7a65 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -38,6 +38,7 @@ struct sdp_ng_flags { str address; sockaddr_t xmlrpc_callback; GHashTable *codec_strip; + GHashTable *codec_except; GQueue codec_offer; GQueue codec_transcode; GHashTable *codec_mask; diff --git a/t/auto-daemon-tests.pl b/t/auto-daemon-tests.pl index a08fba3c4..8ff73105f 100755 --- a/t/auto-daemon-tests.pl +++ b/t/auto-daemon-tests.pl @@ -3192,7 +3192,7 @@ SDP new_call(); -offer('gh 963', { ICE => 'remove', codec => { mask => ['all'], transcode => ['PCMA','telephone-event'] } }, < 'remove', codec => { mask => ['full'], transcode => ['PCMA','telephone-event'] } }, < 'remove', codec => { mask => ['all'], transcode => ['PCMA','telephone-event'] } }, < 'remove', }, <