Browse Source

support new `asymmetric codecs` flag

Change-Id: I244b3576be19658ecc2af353e427e95aea4fca70
changes/47/21747/1
Richard Fuchs 8 years ago
parent
commit
8562bdee70
5 changed files with 133 additions and 9 deletions
  1. +18
    -0
      README.md
  2. +2
    -0
      daemon/call_interfaces.c
  3. +45
    -5
      daemon/codec.c
  4. +1
    -0
      include/call_interfaces.h
  5. +67
    -4
      t/transcode-test.c

+ 18
- 0
README.md View File

@ -1188,6 +1188,24 @@ Optionally included keys are:
which means that it's applied only to the one side doing the signalling that is being
handled (i.e. the side doing the `offer` or the `answer`).
- asymmetric codecs
This flag is relevant to transcoding scenarios. By default, if an RTP client rejects a
codec that was offered to it (by not including it in the answer SDP), *rtpengine* will
assume that this client will also not send this codec (in addition to not wishing to
receive it). With this flag given, *rtpengine* will not make this assumption, meaning
that *rtpengine* will expect to potentially receive a codec from an RTP client even if
that RTP client rejected this codec in its answer SDP.
The effective difference is that when *rtpengine* is instructed to offer a new codec for
transcoding to an RTP client, and then this RTP client rejects this codec, by default
*rtpengine* is then able to shut down its transcoding engine and revert to non-transcoding
operation for this call. With this flag given however, *rtpengine* would not be able
to shut down its transcoding engine in this case, resulting in potentially different media
flow, and potentially transcoding media when it otherwise would not have to.
This flag should be given as part of the `answer` message.
* `replace`
Similar to the `flags` list. Controls which parts of the SDP body should be rewritten.


+ 2
- 0
daemon/call_interfaces.c View File

@ -618,6 +618,8 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) {
out->loop_protect = 1;
else if (!str_cmp(s, "always-transcode"))
out->always_transcode = 1;
else if (!str_cmp(s, "asymmetric-codecs"))
out->asymmetric_codecs = 1;
else {
// handle values aliases from other dictionaries
if (call_ng_flags_prefix(out, s, "SDES-", ng_sdes_option, NULL))


+ 45
- 5
daemon/codec.c View File

@ -145,18 +145,27 @@ static void __ensure_codec_def(struct rtp_payload_type *pt, struct call_media *m
if (!pt->codec_def->pseudocodec && (!pt->codec_def->support_encoding || !pt->codec_def->support_decoding))
pt->codec_def = NULL;
}
static GList *__delete_receiver_codec(struct call_media *receiver, GList *link) {
static GList *__delete_x_codec(GList *link, GHashTable *codecs, GHashTable *codec_names, GQueue *codecs_prefs) {
struct rtp_payload_type *pt = link->data;
g_hash_table_remove(receiver->codecs_recv, &pt->payload_type);
g_hash_table_remove(receiver->codec_names_recv, &pt->encoding);
g_hash_table_remove(receiver->codec_names_recv, &pt->encoding_with_params);
g_hash_table_remove(codecs, &pt->payload_type);
g_hash_table_remove(codec_names, &pt->encoding);
g_hash_table_remove(codec_names, &pt->encoding_with_params);
GList *next = link->next;
g_queue_delete_link(&receiver->codecs_prefs_recv, link);
g_queue_delete_link(codecs_prefs, link);
payload_type_free(pt);
return next;
}
static GList *__delete_receiver_codec(struct call_media *receiver, GList *link) {
return __delete_x_codec(link, receiver->codecs_recv, receiver->codec_names_recv,
&receiver->codecs_prefs_recv);
}
static GList *__delete_send_codec(struct call_media *sender, GList *link) {
return __delete_x_codec(link, sender->codecs_send, sender->codec_names_send,
&sender->codecs_prefs_send);
}
// call must be locked in W
void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
@ -244,6 +253,22 @@ void codec_handlers_update(struct call_media *receiver, struct call_media *sink,
}
}
}
else {
if (!flags || !flags->asymmetric_codecs) {
// in the other case (not transcoding), we can eliminate rejected codecs from our
// `send` list if the receiver cannot receive it.
for (GList *l = receiver->codecs_prefs_send.head; l;) {
struct rtp_payload_type *pt = l->data;
if (g_hash_table_lookup(receiver->codec_names_recv, &pt->encoding)) {
l = l->next;
continue;
}
ilog(LOG_DEBUG, "Eliminating asymmetric outbound codec " STR_FORMAT,
STR_FMT(&pt->encoding_with_params));
l = __delete_send_codec(receiver, l);
}
}
}
for (GList *l = receiver->codecs_prefs_recv.head; l; ) {
struct rtp_payload_type *pt = l->data;
@ -980,6 +1005,21 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_
__revert_codec_strip(removed, codec, media, other_media);
}
if (!flags->asymmetric_codecs) {
// eliminate rejected codecs from the reverse direction. a rejected codec is missing
// from the `send` list. also remove it from the `receive` list.
for (GList *l = other_media->codecs_prefs_recv.head; l;) {
pt = l->data;
if (g_hash_table_lookup(other_media->codec_names_send, &pt->encoding)) {
l = l->next;
continue;
}
ilog(LOG_DEBUG, "Eliminating asymmetric inbound codec " STR_FORMAT,
STR_FMT(&pt->encoding_with_params));
l = __delete_receiver_codec(other_media, l);
}
}
#ifdef WITH_TRANSCODING
// add transcode codecs
for (GList *l = flags->codec_transcode.head; l; l = l->next) {


+ 1
- 0
include/call_interfaces.h View File

@ -60,6 +60,7 @@ struct sdp_ng_flags {
record_call:1,
loop_protect:1,
always_transcode:1,
asymmetric_codecs:1,
supports_load_limit:1,
dtls_off:1,
sdes_off:1,


+ 67
- 4
t/transcode-test.c View File

@ -72,6 +72,7 @@ static void __sdp_pt_fmt(int num, str codec, int clockrate, str full_codec, str
#define sdp_pt(num, codec, clockrate) sdp_pt_fmt(num, codec, clockrate, "")
static void offer() {
printf("offer\n");
codec_rtp_payload_types(media_B, media_A, &rtp_types, &flags);
codec_handlers_update(media_B, media_A, &flags);
g_queue_clear(&rtp_types);
@ -79,6 +80,7 @@ static void offer() {
}
static void answer() {
printf("answer\n");
codec_rtp_payload_types(media_A, media_B, &rtp_types, &flags);
codec_handlers_update(media_A, media_B, &flags);
}
@ -259,6 +261,46 @@ int main() {
packet(B, 8, PCMA_payload, 8, PCMA_payload);
end();
// plain with two offered and one answered
start();
sdp_pt(0, PCMU, 8000);
sdp_pt(8, PCMA, 8000);
offer();
expect(A, recv, "");
expect(A, send, "0/PCMU/8000 8/PCMA/8000");
expect(B, recv, "0/PCMU/8000 8/PCMA/8000");
expect(B, send, "");
sdp_pt(8, PCMA, 8000);
answer();
expect(A, recv, "8/PCMA/8000");
expect(A, send, "8/PCMA/8000");
expect(B, recv, "8/PCMA/8000");
expect(B, send, "8/PCMA/8000");
packet(A, 8, PCMA_payload, 8, PCMA_payload);
packet(B, 8, PCMA_payload, 8, PCMA_payload);
end();
// plain with two offered and one answered + asymmetric codecs
start();
sdp_pt(0, PCMU, 8000);
sdp_pt(8, PCMA, 8000);
offer();
expect(A, recv, "");
expect(A, send, "0/PCMU/8000 8/PCMA/8000");
expect(B, recv, "0/PCMU/8000 8/PCMA/8000");
expect(B, send, "");
sdp_pt(8, PCMA, 8000);
flags.asymmetric_codecs = 1;
answer();
expect(A, recv, "8/PCMA/8000");
expect(A, send, "0/PCMU/8000 8/PCMA/8000");
expect(B, recv, "0/PCMU/8000 8/PCMA/8000");
expect(B, send, "8/PCMA/8000");
packet(A, 0, PCMU_payload, 0, PCMU_payload);
packet(A, 8, PCMA_payload, 8, PCMA_payload);
packet(B, 8, PCMA_payload, 8, PCMA_payload);
end();
// plain with two offered and two answered + always-transcode one way
start();
flags.always_transcode = 1;
@ -340,10 +382,31 @@ int main() {
answer();
expect(A, recv, "0/PCMU/8000");
expect(A, send, "0/PCMU/8000");
expect(B, recv, "8/PCMA/8000");
expect(B, send, "8/PCMA/8000");
packet(A, 0, PCMU_payload, 8, PCMA_payload);
packet(B, 8, PCMA_payload, 0, PCMU_payload);
end();
// same as above, but allow asymmetric codecs
start();
sdp_pt(0, PCMU, 8000);
transcode(PCMA);
offer();
expect(A, recv, "");
expect(A, send, "0/PCMU/8000");
expect(B, recv, "0/PCMU/8000 8/PCMA/8000");
expect(B, send, "");
sdp_pt(8, PCMA, 8000);
flags.asymmetric_codecs = 1;
answer();
expect(A, recv, "0/PCMU/8000");
expect(A, send, "0/PCMU/8000");
expect(B, recv, "0/PCMU/8000 8/PCMA/8000");
expect(B, send, "8/PCMA/8000");
packet(A, 0, PCMU_payload, 8, PCMA_payload);
packet(B, 8, PCMA_payload, 0, PCMU_payload);
packet(B, 0, PCMU_payload, 0, PCMU_payload);
end();
{
@ -364,7 +427,7 @@ int main() {
answer();
expect(A, recv, "0/PCMU/8000");
expect(A, send, "0/PCMU/8000");
expect(B, recv, "0/PCMU/8000 96/AMR-WB/16000/octet-align=1");
expect(B, recv, "96/AMR-WB/16000/octet-align=1");
expect(B, send, "96/AMR-WB/16000/octet-align=1");
packet_seq(A, 0, PCMU_payload, 0, 0, -1, ""); // nothing due to resampling buffer
packet_seq_nf(A, 0, PCMU_payload, 160, 1, 96, AMR_WB_payload);
@ -385,7 +448,7 @@ int main() {
answer();
expect(A, recv, "96/AMR-WB/16000/octet-align=1");
expect(A, send, "96/AMR-WB/16000/octet-align=1");
expect(B, recv, "96/AMR-WB/16000/octet-align=1 0/PCMU/8000");
expect(B, recv, "0/PCMU/8000");
expect(B, send, "0/PCMU/8000");
packet_seq(B, 0, PCMU_payload, 0, 0, -1, ""); // nothing due to resampling buffer
packet_seq_nf(B, 0, PCMU_payload, 160, 1, 96, AMR_WB_payload);
@ -406,7 +469,7 @@ int main() {
answer();
expect(A, recv, "96/AMR-WB/16000");
expect(A, send, "96/AMR-WB/16000");
expect(B, recv, "96/AMR-WB/16000 0/PCMU/8000");
expect(B, recv, "0/PCMU/8000");
expect(B, send, "0/PCMU/8000");
packet_seq(B, 0, PCMU_payload, 0, 0, -1, ""); // nothing due to resampling buffer
packet_seq_nf(B, 0, PCMU_payload, 160, 1, 96, AMR_WB_payload_noe);
@ -429,7 +492,7 @@ int main() {
answer();
expect(A, recv, "8/PCMA/8000");
expect(A, send, "8/PCMA/8000");
expect(B, recv, "8/PCMA/8000 9/G722/8000");
expect(B, recv, "9/G722/8000");
expect(B, send, "9/G722/8000");
packet_seq(A, 8, PCMA_payload, 0, 0, -1, ""); // nothing due to resampling
packet_seq_nf(A, 8, PCMA_payload, 160, 1, 9, G722_payload);


Loading…
Cancel
Save