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
pull/1093/head
Richard Fuchs 5 years ago
parent 2ce7b6476e
commit 241c78c915

@ -1108,16 +1108,25 @@ Optionally included keys are:
all codecs and leave none that could be offered. In this case, the original all codecs and leave none that could be offered. In this case, the original
list of codecs will be left unchanged. 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 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 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 (`strip -> all` or `mask -> all`) except the ones given in the `except`
Codecs that were not present in the original list of codecs whitelist. Codecs that were not present in the original list of codecs
offered by the client will be ignored. offered by the client will be ignored.
This list also supports codec format parameters as per above. 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` * `transcode`
Similar to `offer` but allows codecs to be added to the list of offered codecs 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, interpreted as a key-value pair), it can be escaped by using two dashes instead,
e.g. `iLBC/8000/1///mode--30`. e.g. `iLBC/8000/1///mode--30`.
As a special case, if the `strip=all` option has been used and the `transcode` As a special case, if the `strip=all` or `mask=all` option has been used and
option is used on a codec that was originally present in the offer, then the `transcode` option is used on a codec that was originally present in the offer,
*rtpengine* will treat this codec the same as if it had been used with the `offer` then *rtpengine* will treat this codec the same as if it had been used with the
option, i.e. it will simply restore it from the list of stripped codecs and won't `offer` option, i.e. it will simply restore it from the list of stripped codecs and
actually engage transcoding for this codec. On the other hand, if a codec has 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 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 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 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` * `mask`
@ -1172,8 +1182,8 @@ Optionally included keys are:
hand, if `strip=opus, transcode=G723` were given, then Opus would be unavailable hand, if `strip=opus, transcode=G723` were given, then Opus would be unavailable
for transcoding. for transcoding.
As with the `strip` option, the special keyword `all` can be used to mask all As with the `strip` option, the special keywords `all` and `full` can be used
codecs that have been offered. to mask all codecs that have been offered.
* `set` * `set`

@ -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, if (call_ng_flags_prefix(out, s, "codec-offer-", call_ng_flags_codec_list,
&out->codec_offer)) &out->codec_offer))
return; return;
if (call_ng_flags_prefix(out, s, "codec-except-", call_ng_flags_str_ht,
&out->codec_except))
return;
#ifdef WITH_TRANSCODING #ifdef WITH_TRANSCODING
if (call_ng_flags_prefix(out, s, "transcode-", call_ng_flags_codec_list, if (call_ng_flags_prefix(out, s, "transcode-", call_ng_flags_codec_list,
&out->codec_transcode)) &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))) { 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, "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, "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 #ifdef WITH_TRANSCODING
call_ng_flags_list(out, dict, "transcode", call_ng_flags_codec_list, &out->codec_transcode); 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); 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) { static void call_ng_free_flags(struct sdp_ng_flags *flags) {
if (flags->codec_strip) if (flags->codec_strip)
g_hash_table_destroy(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) if (flags->codec_mask)
g_hash_table_destroy(flags->codec_mask); g_hash_table_destroy(flags->codec_mask);
if (flags->codec_set) if (flags->codec_set)

@ -2293,21 +2293,39 @@ static void __payload_queue_free(void *qq) {
GQueue *q = qq; GQueue *q = qq;
g_queue_free_full(q, (GDestroyNotify) payload_type_free); 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) struct call_media *media, struct call_media *other_media, struct supp_codec_tracker *sct)
{ {
GQueue *q = g_hash_table_lookup(removed, codec); int ret = 0;
if (!q)
return 0; GQueue *q = g_hash_table_lookup(stripped, codec);
ilog(LOG_DEBUG, "Restoring codec '" STR_FORMAT "' from stripped codecs (%u payload types)", if (q) {
STR_FMT(codec), q->length); ilog(LOG_DEBUG, "Restoring codec '" STR_FORMAT "' from stripped codecs (%u payload types)",
g_hash_table_steal(removed, codec); STR_FMT(codec), q->length);
for (GList *l = q->head; l; l = l->next) { g_hash_table_steal(stripped, codec);
struct rtp_payload_type *pt = l->data; for (GList *l = q->head; l; l = l->next) {
__rtp_payload_type_add(media, other_media, pt, sct); 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, static int __codec_options_set1(struct call *call, struct rtp_payload_type *pt, const str *enc,
GHashTable *codec_set) 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(supp_codecs);
g_list_free(clockrates); 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, void codec_rtp_payload_types(struct call_media *media, struct call_media *other_media,
GQueue *types, struct sdp_ng_flags *flags) 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 call *call = media->call;
struct rtp_payload_type *pt; struct rtp_payload_type *pt;
static const str str_all = STR_CONST_INIT("all"); 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; int strip_all = 0, mask_all = 0;
// start fresh // 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)) if (flags->codec_strip && g_hash_table_lookup(flags->codec_strip, &str_all))
strip_all = 1; 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)) if (flags->codec_mask && g_hash_table_lookup(flags->codec_mask, &str_all))
mask_all = 1; 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; struct supp_codec_tracker sct;
supp_codec_tracker_init(&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 __rtp_payload_type_dup(call, pt); // this takes care of string allocation
// codec stripping // codec stripping
if (flags->codec_strip) { if (__codec_ht_except(strip_all, flags->codec_strip, flags->codec_except, pt)) {
if (strip_all || g_hash_table_lookup(flags->codec_strip, &pt->encoding) ilog(LOG_DEBUG, "Stripping codec '" STR_FORMAT "'",
|| g_hash_table_lookup(flags->codec_strip, &pt->encoding_with_params)) STR_FMT(&pt->encoding_with_params));
{ codec_touched(pt, &sct, media);
ilog(LOG_DEBUG, "Stripping codec '" STR_FORMAT "'", GQueue *q = g_hash_table_lookup_queue_new(stripped, &pt->encoding);
STR_FMT(&pt->encoding_with_params)); g_queue_push_tail(q, __rtp_payload_type_copy(pt));
codec_touched(pt, &sct, media); q = g_hash_table_lookup_queue_new(stripped, &pt->encoding_with_params);
GQueue *q = g_hash_table_lookup_queue_new(removed, &pt->encoding); g_queue_push_tail(q, pt);
g_queue_push_tail(q, __rtp_payload_type_copy(pt)); continue;
q = g_hash_table_lookup_queue_new(removed, &pt->encoding_with_params);
g_queue_push_tail(q, pt);
continue;
}
} }
__codec_options_set(call, pt, flags->codec_set); __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))) // codec masking
__rtp_payload_type_add(media, other_media, pt, &sct); if (__codec_ht_except(mask_all, flags->codec_mask, flags->codec_except, pt)) {
else { ilog(LOG_DEBUG, "Masking codec '" STR_FORMAT "'",
STR_FMT(&pt->encoding_with_params));
codec_touched(pt, &sct, other_media); 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); __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 // now restore codecs that have been removed, but should be offered
for (GList *l = flags->codec_offer.head; l; l = l->next) { for (GList *l = flags->codec_offer.head; l; l = l->next) {
str *codec = l->data; 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) { 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, // and removed by a strip=all option,
// simply restore it from the original list and handle it the same way // simply restore it from the original list and handle it the same way
// as 'offer' // 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; continue;
// also check if maybe the codec was never stripped // also check if maybe the codec was never stripped
if (g_hash_table_lookup(media->codec_names_recv, codec)) { 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); 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); supp_codec_tracker_destroy(&sct);
} }

@ -38,6 +38,7 @@ struct sdp_ng_flags {
str address; str address;
sockaddr_t xmlrpc_callback; sockaddr_t xmlrpc_callback;
GHashTable *codec_strip; GHashTable *codec_strip;
GHashTable *codec_except;
GQueue codec_offer; GQueue codec_offer;
GQueue codec_transcode; GQueue codec_transcode;
GHashTable *codec_mask; GHashTable *codec_mask;

@ -3192,7 +3192,7 @@ SDP
new_call(); new_call();
offer('gh 963', { ICE => 'remove', codec => { mask => ['all'], transcode => ['PCMA','telephone-event'] } }, <<SDP); offer('gh 963', { ICE => 'remove', codec => { mask => ['full'], transcode => ['PCMA','telephone-event'] } }, <<SDP);
v=0 v=0
o=- 1822058533 1822058533 IN IP4 1.2.3.4 o=- 1822058533 1822058533 IN IP4 1.2.3.4
s=Asterisk s=Asterisk
@ -3245,6 +3245,62 @@ SDP
new_call();
offer('gh 963 w mask all', { ICE => 'remove', codec => { mask => ['all'], transcode => ['PCMA','telephone-event'] } }, <<SDP);
v=0
o=- 1822058533 1822058533 IN IP4 1.2.3.4
s=Asterisk
c=IN IP4 1.2.3.4
t=0 0
m=audio 27998 RTP/AVP 96 120
a=rtpmap:96 opus/48000/2
a=fmtp:96 useinbandfec=1;maxplaybackrate=16000;sprop-maxcapturerate=16000;maxaveragebitrate=12000;cbr=1
a=rtpmap:120 telephone-event/48000
a=fmtp:120 0-16
----------------------------------
v=0
o=- 1822058533 1822058533 IN IP4 1.2.3.4
s=Asterisk
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 8 96
a=rtpmap:8 PCMA/8000
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15
a=sendrecv
a=rtcp:PORT
SDP
answer('gh 963 w mask all', { ICE => 'remove', }, <<SDP);
v=0
o=- 3793596600 3793596601 IN IP4 172.17.0.2
s=pjmedia
t=0 0
m=audio 40935 RTP/AVP 8 96
c=IN IP4 172.17.0.2
a=rtpmap:8 PCMA/8000
a=rtpmap:96 telephone-event/8000
a=fmtp:96 0-15
----------------------------------
v=0
o=- 3793596600 3793596601 IN IP4 172.17.0.2
s=pjmedia
t=0 0
m=audio PORT RTP/AVP 96 120
c=IN IP4 203.0.113.1
a=rtpmap:96 opus/48000/2
a=rtpmap:120 telephone-event/48000
a=fmtp:96 useinbandfec=1;maxplaybackrate=16000;sprop-maxcapturerate=16000;maxaveragebitrate=12000;cbr=1
a=fmtp:120 0-16
a=sendrecv
a=rtcp:PORT
SDP
# symmetric-codec flag (GH 953) # symmetric-codec flag (GH 953)

Loading…
Cancel
Save