Browse Source

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
mr8.5.4
Richard Fuchs 5 years ago
parent
commit
105a423ba1
5 changed files with 166 additions and 45 deletions
  1. +22
    -12
      README.md
  2. +6
    -0
      daemon/call_interfaces.c
  3. +80
    -32
      daemon/codec.c
  4. +1
    -0
      include/call_interfaces.h
  5. +57
    -1
      t/auto-daemon-tests.pl

+ 22
- 12
README.md View File

@ -1041,16 +1041,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
@ -1078,15 +1087,16 @@ Optionally included keys are:
Additional options that can be appended to the codec string with additional slashes
are ptime and the `fmtp` string, for example `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`
@ -1100,8 +1110,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`


+ 6
- 0
daemon/call_interfaces.c View File

@ -827,6 +827,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))
@ -975,6 +978,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);
@ -985,6 +989,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)


+ 80
- 32
daemon/codec.c View File

@ -2235,21 +2235,38 @@ 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)
{
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);
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);
}
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;
__rtp_payload_type_add_recv(media, pt);
}
g_queue_free(q);
ret = 1;
}
return ret;
}
static int __codec_options_set1(struct rtp_payload_type *pt, const str *enc, GHashTable *codec_set) {
str *pt_str = g_hash_table_lookup(codec_set, enc);
@ -2277,6 +2294,24 @@ static void __codec_options_set(struct rtp_payload_type *pt, GHashTable *codec_s
if (__codec_options_set1(pt, &pt->encoding, codec_set))
return;
}
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)
{
@ -2287,7 +2322,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
@ -2311,39 +2348,48 @@ 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;
/* we steal the entire list to avoid duplicate allocs */
while ((pt = g_queue_pop_head(types))) {
__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));
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));
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(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);
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));
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);
}
// 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);
__revert_codec_strip(stripped, masked, codec, media, other_media);
}
if (!flags->asymmetric_codecs) {
@ -2369,7 +2415,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))
if ((strip_all == 1 || mask_all == 1)
&& __revert_codec_strip(stripped, masked, codec, media, other_media))
continue;
// also check if maybe the codec was never stripped
if (g_hash_table_lookup(media->codec_names_recv, codec)) {
@ -2442,5 +2489,6 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_
}
#endif
g_hash_table_destroy(removed);
g_hash_table_destroy(stripped);
g_hash_table_destroy(masked);
}

+ 1
- 0
include/call_interfaces.h View File

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


+ 57
- 1
t/auto-daemon-tests.pl View File

@ -1612,7 +1612,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
@ -1665,6 +1665,62 @@ SDP
new_call();
offer('gh 963 w mask all', { ICE => 'remove', codec => { mask => ['full'], 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