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
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`

@ -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)

@ -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);
}

@ -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;

@ -3192,7 +3192,7 @@ SDP
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
o=- 1822058533 1822058533 IN IP4 1.2.3.4
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)

Loading…
Cancel
Save