diff --git a/README.md b/README.md index 0a7a3aa3f..4d5a698ae 100644 --- a/README.md +++ b/README.md @@ -992,6 +992,18 @@ Optionally included keys are: been requested for transcoding. Note that not all codecs support all packetization intervals. + The selected ptime (which represents the duration of a single media packet in milliseconds) + will be used towards the endpoint receiving this offer, even if the matching answer + prefers a different ptime. + + This option is ignored in `answer` messages. See below for the reverse. + +* `ptime-reverse` + + This is the reciprocal to `ptime`. It sets the ptime to be used towards the endpoint + who has sent the offer. It will be inserted in the `answer` SDP. This option is also + ignored in `answer` messages. + * `supports` Contains a list of strings. Each string indicates support for an additional feature diff --git a/daemon/call.c b/daemon/call.c index 205158288..e92d443bf 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -1870,11 +1870,21 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams, // codec and RTP payload types handling if (sp->ptime > 0) { - media->ptime = sp->ptime; - other_media->ptime = sp->ptime; + if (!MEDIA_ISSET(media, PTIME_OVERRIDE)) + media->ptime = sp->ptime; + if (!MEDIA_ISSET(other_media, PTIME_OVERRIDE)) + other_media->ptime = sp->ptime; } - if (flags && flags->ptime > 0) + if (flags && flags->ptime > 0) { media->ptime = flags->ptime; + MEDIA_SET(media, PTIME_OVERRIDE); + MEDIA_SET(other_media, PTIME_OVERRIDE); + } + if (flags && flags->rev_ptime > 0) { + other_media->ptime = flags->rev_ptime; + MEDIA_SET(media, PTIME_OVERRIDE); + MEDIA_SET(other_media, PTIME_OVERRIDE); + } codec_rtp_payload_types(media, other_media, &sp->rtp_payload_types, flags); codec_handlers_update(media, other_media, flags); diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index e0e646a9b..11f4220e6 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -807,7 +807,13 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu out->tos = bencode_dictionary_get_int_str(input, "TOS", 256); bencode_get_alt(input, "record-call", "record call", &out->record_call_str); bencode_dictionary_get_str(input, "metadata", &out->metadata); - out->ptime = bencode_dictionary_get_int_str(input, "ptime", 0); + + if (opmode == OP_OFFER) { + out->ptime = bencode_dictionary_get_int_str(input, "ptime", 0); + out->rev_ptime = bencode_dictionary_get_int_str(input, "ptime-reverse", 0); + if (out->rev_ptime == 0) + out->rev_ptime = bencode_dictionary_get_int_str(input, "ptime reverse", 0); + } if (bencode_dictionary_get_str(input, "xmlrpc-callback", &s)) { if (sockaddr_parse_any_str(&out->xmlrpc_callback, &s)) diff --git a/daemon/codec.c b/daemon/codec.c index 7e2649850..218627a16 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -1252,6 +1252,9 @@ void __rtp_payload_type_add_recv(struct call_media *media, { if (!pt) return; + // update ptime in case it was overridden + if (media->ptime > 0) + pt->ptime = media->ptime; g_hash_table_insert(media->codecs_recv, &pt->payload_type, pt); __rtp_payload_type_add_name(media->codec_names_recv, pt); g_queue_push_tail(&media->codecs_prefs_recv, pt); @@ -1262,6 +1265,9 @@ void __rtp_payload_type_add_send(struct call_media *other_media, { if (!pt) return; + // update ptime in case it was overridden + if (other_media->ptime > 0) + pt->ptime = other_media->ptime; g_hash_table_insert(other_media->codecs_send, &pt->payload_type, pt); __rtp_payload_type_add_name(other_media->codec_names_send, pt); g_queue_push_tail(&other_media->codecs_prefs_send, pt); @@ -1277,8 +1283,8 @@ void __rtp_payload_type_add_send_dup(struct call_media *other_media, static void __rtp_payload_type_add(struct call_media *media, struct call_media *other_media, struct rtp_payload_type *pt) { - __rtp_payload_type_add_recv(media, pt); __rtp_payload_type_add_send_dup(other_media, pt); + __rtp_payload_type_add_recv(media, pt); } static void __payload_queue_free(void *qq) { @@ -1428,6 +1434,7 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_ STR_FMT(&pt->encoding_with_params), pt->payload_type); __rtp_payload_type_add_recv(media, pt); } + #endif g_hash_table_destroy(removed); diff --git a/include/call.h b/include/call.h index cb567c404..18232e4ff 100644 --- a/include/call.h +++ b/include/call.h @@ -147,6 +147,7 @@ enum call_type { #define MEDIA_FLAG_ICE_CONTROLLING 0x00200000 #define MEDIA_FLAG_LOOP_CHECK 0x00400000 #define MEDIA_FLAG_TRANSCODE 0x00800000 +#define MEDIA_FLAG_PTIME_OVERRIDE 0x01000000 /* access macros */ #define SP_ISSET(p, f) bf_isset(&(p)->sp_flags, SP_FLAG_ ## f) diff --git a/include/call_interfaces.h b/include/call_interfaces.h index d70431585..3e59aed1f 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -37,7 +37,8 @@ struct sdp_ng_flags { GQueue codec_transcode; GHashTable *codec_mask; GHashTable *codec_set; - int ptime; + int ptime, + rev_ptime; GHashTable *sdes_no; int asymmetric:1, no_redis_update:1, diff --git a/t/auto-daemon-tests.pl b/t/auto-daemon-tests.pl index bccce7c5e..9d02b1d79 100755 --- a/t/auto-daemon-tests.pl +++ b/t/auto-daemon-tests.pl @@ -2040,6 +2040,79 @@ rcv($sock_a, $port_b, rtpm(0, 4002, 5800, $ssrc, "\x88" x 400)); +($sock_a, $sock_b) = new_call([qw(198.51.100.1 3012)], [qw(198.51.100.3 3014)]); + +($port_a) = offer('ptime=50 in, change to 30, response 30, no change', { + ICE => 'remove', replace => ['origin'], ptime => 30 }, < 'remove', replace => ['origin'] }, <B: 2x 50 ms -> 3x 30 ms (plus 10 ms left) +snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\00" x 400)); +($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\00" x 240)); +snd($sock_a, $port_b, rtp(0, 1001, 3400, 0x1234, "\00" x 400)); +rcv($sock_b, $port_a, rtpm(0, 1001, 3240, $ssrc, "\00" x 240)); +rcv($sock_b, $port_a, rtpm(0, 1002, 3480, $ssrc, "\00" x 240)); +# A->B: add another 20 ms for another full 30 ms +snd($sock_a, $port_b, rtp(0, 1002, 3800, 0x1234, "\00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1003, 3720, $ssrc, "\00" x 240)); + +# B->A: 4x 30 ms -> 2x 50 ms (plus 20 ms left) +snd($sock_b, $port_a, rtp(0, 4000, 5000, 0x4567, "\x88" x 240)); +Time::HiRes::usleep(20000); # 20 ms, needed to ensure that packet 1000 is received first +snd($sock_b, $port_a, rtp(0, 4001, 5240, 0x4567, "\x88" x 240)); +($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 5000, -1, "\x88" x 400)); +snd($sock_b, $port_a, rtp(0, 4002, 5480, 0x4567, "\x88" x 240)); +snd($sock_b, $port_a, rtp(0, 4003, 5720, 0x4567, "\x88" x 240)); +rcv($sock_a, $port_b, rtpm(0, 4001, 5400, $ssrc, "\x88" x 400)); +# B->A: add another 30 ms for another full 50 ms +snd($sock_b, $port_a, rtp(0, 4004, 5960, 0x4567, "\x88" x 240)); +rcv($sock_a, $port_b, rtpm(0, 4002, 5800, $ssrc, "\x88" x 400)); + + + + END { if ($rtpe_pid) { kill('INT', $rtpe_pid) or die;