From ffe187f1166c22f5d204c97534e786fdbfc10052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Ned=C5=BEibovi=C4=87?= Date: Thu, 28 Jan 2021 18:05:44 +0100 Subject: [PATCH 01/13] Implementation of control-ng via TCP. --- daemon/bencode.c | 109 ++++++++++++++++++++++++++++++++ daemon/control_ng.c | 145 +++++++++++++++++++++++++++++++++++++++++-- daemon/main.c | 17 ++++- include/bencode.h | 4 +- include/control_ng.h | 5 +- include/main.h | 1 + t/Makefile | 4 +- 7 files changed, 273 insertions(+), 12 deletions(-) diff --git a/daemon/bencode.c b/daemon/bencode.c index 4b4eb12e5..934b59cfa 100644 --- a/daemon/bencode.c +++ b/daemon/bencode.c @@ -703,3 +703,112 @@ void bencode_buffer_destroy_add(bencode_buffer_t *buf, free_func_t func, void *p li->next = buf->free_list; buf->free_list = li; } + +static int __bencode_string(const char *s, int offset, int len) { + int pos; + unsigned long long sl; + char *end; + + for (pos = offset + 1; s[pos] != 0x3a && isdigit(s[pos]) && pos < len; ++pos); + if (pos == len) + return -1; + + sl = strtoul(s + offset + 1, &end, 10); + if (s + offset + 1 == end || end != s + pos) + return -2; + + if (pos + sl > len) + return -1; + + return pos + sl + 1; +} + +static int __bencode_integer(const char *s, int offset, int len) { + int pos; + + if (s[offset + 1] == 0x2d) { + if (offset + 3 < len && s[offset + 2] == 0x30 && s[offset + 3] == 0x65) { + return -2; + } + ++offset; + } + + if (s[offset + 1] == 0x65) + return -2; + + if (s[offset + 1] == 0x30) { + if (offset + 2 < len && s[offset + 2] == 0x65) + return offset + 3; + return -2; + } + + for (pos = offset + 1; s[pos] != 0x65 && pos < len; ++pos) { + if (s[pos] < 0x30 || s[pos] > 0x39) + return -2; + } + + if (pos == len) + return -1; + + return pos + 1; +} + +static int __bencode_next(const char *s, int offset, int len); + +static int __bencode_list(const char *s, int offset, int len) { + for (++offset; s[offset] != 0x65 && offset < len;) { + offset = __bencode_next(s, offset, len); + if (offset < 0) + return offset; + } + + if (offset == len) + return -1; + + return offset + 1; +} + +static int __bencode_dictionary(const char *s, int offset, int len) { + for (++offset; s[offset] != 0x65 && offset < len;) { + offset = __bencode_string(s, offset - 1, len); + if (offset < 0) + return offset; + offset = __bencode_next(s, offset, len); + if (offset < 0) + return offset; + } + + if (offset == len) + return -1; + + return offset + 1; +} + +static int __bencode_next(const char *s, int offset, int len) { + if (offset >= len) + return -1; + switch(s[offset]) { + case 0x69: + return __bencode_integer(s, offset, len); + case 0x6c: + return __bencode_list(s, offset, len); + case 0x64: + return __bencode_dictionary(s, offset, len); + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + return __bencode_string(s, offset - 1, len); + } + return -2; +} + +int bencode_valid(const char *s, int len) { + return __bencode_next(s, 0, len); +} diff --git a/daemon/control_ng.c b/daemon/control_ng.c index 91a7cbfa2..b6807bf39 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -1,5 +1,6 @@ #include "control_ng.h" +#include #include #include #include @@ -16,10 +17,14 @@ #include "log_funcs.h" #include "main.h" #include "statistics.h" - +#include "streambuf.h" +#include "str.h" +#include "tcp_listener.h" mutex_t rtpe_cngs_lock; +mutex_t tcp_connections_lock; GHashTable *rtpe_cngs_hash; +GHashTable *tcp_connections_hash; struct control_ng *rtpe_control_ng; static struct cookie_cache ng_cookie_cache; @@ -42,7 +47,6 @@ const char *ng_command_strings_short[NGC_COUNT] = { "PlayDTMF", "Stats", }; - static void timeval_update_request_time(struct request_time *request, const struct timeval *offer_diff) { // lock offers mutex_lock(&request->lock); @@ -390,7 +394,6 @@ out: return funcret; } - static void control_ng_send(str *cookie, str *body, const endpoint_t *sin, void *p1) { socket_t *ul = p1; struct iovec iov[3]; @@ -408,13 +411,88 @@ static void control_ng_send(str *cookie, str *body, const endpoint_t *sin, void socket_sendiov(ul, iov, iovlen, sin); } - static void control_ng_incoming(struct obj *obj, struct udp_buffer *udp_buf) { control_ng_process(&udp_buf->str, &udp_buf->sin, udp_buf->addr, control_ng_send, udp_buf->listener, &udp_buf->obj); } +static void control_incoming(struct streambuf_stream *s) { + ilog(LOG_INFO, "New TCP control ng connection from %s", s->addr); + mutex_lock(&tcp_connections_lock); + g_hash_table_insert(tcp_connections_hash, s->addr, s); + mutex_unlock(&tcp_connections_lock); + ilog(LOG_DEBUG, "TCP connections map size: %d", g_hash_table_size(tcp_connections_hash)); +} + +static void control_closed(struct streambuf_stream *s) { + ilog(LOG_INFO, "TCP control ng connection from %s is closing", s->addr); + mutex_lock(&tcp_connections_lock); + g_hash_table_remove(tcp_connections_hash, s->addr); + mutex_unlock(&tcp_connections_lock); + ilog(LOG_DEBUG, "TCP connections map size: %d", g_hash_table_size(tcp_connections_hash)); +} + +static str *chunk_message(struct streambuf *b) { + char *p = NULL; + int len, to_del, bsize; + str *ret = NULL; + + mutex_lock(&b->lock); + + for (;;) { + if (b->eof) + break; + + p = memchr(b->buf->str, ' ', b->buf->len); + if (!p) + break; + + len = p - b->buf->str; + if (len == b->buf->len) + break; + + ++p; /* bencode dictionary here */ + bsize = bencode_valid(p, b->buf->str + b->buf->len - p); + if (bsize < 0) + break; /* not enough data to parse bencoded dictionary */ + + p += bsize; + len = p - b->buf->str; + to_del = len; + + ret = str_alloc(len); + memcpy(ret->s, b->buf->str, len); + ret->len = len; + g_string_erase(b->buf, 0, to_del); + + break; + } + + mutex_unlock(&b->lock); + return ret; +} + +static void control_stream_readable(struct streambuf_stream *s) { + str *data; + + ilog(LOG_DEBUG, "Got %ld bytes from %s", s->inbuf->buf->len, s->addr); + while ((data = chunk_message(s->inbuf))) { + ilog(LOG_DEBUG, "Got control ng message from %s", s->addr); + control_ng_process(data, &s->sock.remote, s->addr, control_ng_send, &s->sock, s->parent); + free(data); + } + + if (streambuf_bufsize(s->inbuf) > 1024) { + ilog(LOG_WARNING, "Buffer length exceeded in control connection from %s", s->addr); + goto close; + } + + return; + + close: + streambuf_stream_close(s); +} void control_ng_free(void *p) { struct control_ng *c = p; @@ -433,9 +511,12 @@ void control_ng_free(void *p) { poller_del_item(c->poller, c->udp_listeners[1].fd); close_socket(&c->udp_listeners[0]); close_socket(&c->udp_listeners[1]); + streambuf_listener_shutdown(&c->tcp_listeners[0]); + streambuf_listener_shutdown(&c->tcp_listeners[1]); + if (tcp_connections_hash) + g_hash_table_destroy(tcp_connections_hash); } - struct control_ng *control_ng_new(struct poller *p, endpoint_t *ep, unsigned char tos) { struct control_ng *c; @@ -463,9 +544,63 @@ struct control_ng *control_ng_new(struct poller *p, endpoint_t *ep, unsigned cha fail2: obj_put(c); return NULL; +} + +struct control_ng *control_ng_tcp_new(struct poller *p, endpoint_t *ep, struct control_ng *ctrl_ng) { + if (!p) + return NULL; + + if (!ctrl_ng) { + ctrl_ng = obj_alloc0("control_ng", sizeof(*ctrl_ng), NULL); + ctrl_ng->udp_listeners[0].fd = -1; + ctrl_ng->udp_listeners[1].fd = -1; + } + + ctrl_ng->poller = p; + + if (streambuf_listener_init(&ctrl_ng->tcp_listeners[0], p, ep, + control_incoming, control_stream_readable, + control_closed, + NULL, + &ctrl_ng->obj)) { + ilog(LOG_ERR, "Failed to open TCP control port: %s", strerror(errno)); + goto fail; + } + if (ipv46_any_convert(ep)) { + if (streambuf_listener_init(&ctrl_ng->tcp_listeners[1], p, ep, + control_incoming, control_stream_readable, + control_closed, + NULL, + &ctrl_ng->obj)) { + ilog(LOG_ERR, "Failed to open TCP control port: %s", strerror(errno)); + goto fail; + } + } + + tcp_connections_hash = g_hash_table_new(g_str_hash, g_str_equal); + mutex_init(&tcp_connections_lock); + return ctrl_ng; + +fail: + obj_put(ctrl_ng); + return NULL; +} + +static void notify_tcp_client(gpointer key, gpointer value, gpointer user_data) { + struct streambuf_stream *s = (struct streambuf_stream *)value; + str *to_send = (str *)user_data; + char cookie_buf[16]; + str cookie = STR_CONST_INIT_LEN(cookie_buf, sizeof(cookie_buf)); + rand_hex_str(cookie_buf, sizeof(cookie_buf) / 2); + control_ng_send(&cookie, to_send, &s->sock.remote, &s->sock); } +void notify_ng_tcp_clients(str *data) { + mutex_lock(&tcp_connections_lock); + g_hash_table_foreach(tcp_connections_hash, notify_tcp_client, data); + mutex_unlock(&tcp_connections_lock); +} void control_ng_init() { mutex_init(&rtpe_cngs_lock); diff --git a/daemon/main.c b/daemon/main.c index db3ba905f..bec3d985f 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -368,6 +368,7 @@ static void options(int *argc, char ***argv) { AUTO_CLEANUP_GBUF(listenps); AUTO_CLEANUP_GBUF(listenudps); AUTO_CLEANUP_GBUF(listenngs); + AUTO_CLEANUP_GBUF(listenngtcps); AUTO_CLEANUP_GBUF(listencli); AUTO_CLEANUP_GBUF(graphitep); AUTO_CLEANUP_GBUF(graphite_prefix_s); @@ -400,6 +401,7 @@ static void options(int *argc, char ***argv) { { "listen-tcp", 'l', 0, G_OPTION_ARG_STRING, &listenps, "TCP port to listen on", "[IP:]PORT" }, { "listen-udp", 'u', 0, G_OPTION_ARG_STRING, &listenudps, "UDP port to listen on", "[IP46|HOSTNAME:]PORT" }, { "listen-ng", 'n', 0, G_OPTION_ARG_STRING, &listenngs, "UDP port to listen on, NG protocol", "[IP46|HOSTNAME:]PORT" }, + { "listen-tcp-ng", 'N', 0, G_OPTION_ARG_STRING, &listenngtcps, "TCP port to listen on, NG protocol", "[IP46|HOSTNAME:]PORT" }, { "listen-cli", 'c', 0, G_OPTION_ARG_STRING, &listencli, "UDP port to listen on, CLI", "[IP46|HOSTNAME:]PORT" }, { "graphite", 'g', 0, G_OPTION_ARG_STRING, &graphitep, "Address of the graphite server", "IP46|HOSTNAME:PORT" }, { "graphite-interval", 'G', 0, G_OPTION_ARG_INT, &rtpe_config.graphite_interval, "Graphite send interval in seconds", "INT" }, @@ -504,8 +506,8 @@ static void options(int *argc, char ***argv) { if (!if_a) die("Missing option --interface"); - if (!listenps && !listenudps && !listenngs) - die("Missing option --listen-tcp, --listen-udp or --listen-ng"); + if (!listenps && !listenudps && !listenngs && !listenngtcps) + die("Missing option --listen-tcp, --listen-udp or --listen-ng or --listen-tcp-ng"); struct ifaddrs *ifas; if (getifaddrs(&ifas)) { @@ -552,6 +554,10 @@ static void options(int *argc, char ***argv) { if (endpoint_parse_any_getaddrinfo(&rtpe_config.ng_listen_ep, listenngs)) die("Invalid IP or port '%s' (--listen-ng)", listenngs); } + if (listenngtcps) { + if (endpoint_parse_any_getaddrinfo(&rtpe_config.ng_tcp_listen_ep, listenngtcps)) + die("Invalid IP or port '%s' (--listen-tcp-ng)", listenngtcps); + } if (listencli) {if (endpoint_parse_any_getaddrinfo(&rtpe_config.cli_listen_ep, listencli)) die("Invalid IP or port '%s' (--listen-cli)", listencli); @@ -787,6 +793,7 @@ void fill_initial_rtpe_cfg(struct rtpengine_config* ini_rtpe_cfg) { ini_rtpe_cfg->tcp_listen_ep = rtpe_config.tcp_listen_ep; ini_rtpe_cfg->udp_listen_ep = rtpe_config.udp_listen_ep; ini_rtpe_cfg->ng_listen_ep = rtpe_config.ng_listen_ep; + ini_rtpe_cfg->ng_tcp_listen_ep = rtpe_config.ng_tcp_listen_ep; ini_rtpe_cfg->cli_listen_ep = rtpe_config.cli_listen_ep; ini_rtpe_cfg->redis_ep = rtpe_config.redis_ep; ini_rtpe_cfg->redis_write_ep = rtpe_config.redis_write_ep; @@ -957,6 +964,12 @@ no_kernel: die("Failed to open UDP control connection port"); } + if (rtpe_config.ng_tcp_listen_ep.port) { + rtpe_control_ng = control_ng_tcp_new(rtpe_poller, &rtpe_config.ng_tcp_listen_ep, rtpe_control_ng); + if (!rtpe_control_ng) + die("Failed to open TCP control connection port"); + } + rtpe_cli = NULL; if (rtpe_config.cli_listen_ep.port) { interfaces_exclude_port(rtpe_config.cli_listen_ep.port); diff --git a/include/bencode.h b/include/bencode.h index fb7a1efc5..e729c9b70 100644 --- a/include/bencode.h +++ b/include/bencode.h @@ -301,8 +301,8 @@ INLINE bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char * /* Identical to bencode_decode_expect() but takes a "str" argument. */ INLINE bencode_item_t *bencode_decode_expect_str(bencode_buffer_t *buf, const str *s, bencode_type_t expect); - - +/* Returns the number of bytes that could successfully be decoded from 's', -1 if more bytes are needed or -2 on error */ +int bencode_valid(const char *s, int len); /*** DICTIONARY LOOKUP & EXTRACTION ***/ diff --git a/include/control_ng.h b/include/control_ng.h index c5d61f39b..c275ae45a 100644 --- a/include/control_ng.h +++ b/include/control_ng.h @@ -5,9 +5,9 @@ #include "udp_listener.h" #include "socket.h" #include "str.h" +#include "tcp_listener.h" #include "bencode.h" - struct poller; enum ng_command { @@ -48,6 +48,7 @@ struct control_ng_stats { struct control_ng { struct obj obj; socket_t udp_listeners[2]; + struct streambuf_listener tcp_listeners[2]; struct poller *poller; }; @@ -62,6 +63,8 @@ extern const char *ng_command_strings[NGC_COUNT]; extern const char *ng_command_strings_short[NGC_COUNT]; struct control_ng *control_ng_new(struct poller *, endpoint_t *, unsigned char); +struct control_ng *control_ng_tcp_new(struct poller *, endpoint_t *, struct control_ng *); +void notify_ng_tcp_clients(str *); void control_ng_init(void); void control_ng_cleanup(void); int control_ng_process(str *buf, const endpoint_t *sin, char *addr, diff --git a/include/main.h b/include/main.h index cf715df82..067e1e190 100644 --- a/include/main.h +++ b/include/main.h @@ -54,6 +54,7 @@ struct rtpengine_config { endpoint_t tcp_listen_ep; endpoint_t udp_listen_ep; endpoint_t ng_listen_ep; + endpoint_t ng_tcp_listen_ep; endpoint_t cli_listen_ep; endpoint_t redis_ep; endpoint_t redis_write_ep; diff --git a/t/Makefile b/t/Makefile index f184159d5..6b4bf4126 100644 --- a/t/Makefile +++ b/t/Makefile @@ -72,7 +72,7 @@ LIBSRCS+= codeclib.c resample.c socket.c streambuf.c dtmflib.c DAEMONSRCS+= codec.c call.c ice.c kernel.c media_socket.c stun.c bencode.c poller.c \ dtls.c recording.c statistics.c rtcp.c redis.c iptables.c graphite.c \ cookie_cache.c udp_listener.c homer.c load.c cdr.c dtmf.c timerthread.c \ - media_player.c jitter_buffer.c t38.c + media_player.c jitter_buffer.c t38.c tcp_listener.c HASHSRCS+= call_interfaces.c control_ng.c sdp.c endif @@ -164,7 +164,7 @@ transcode-test: transcode-test.o $(COMMONOBJS) codeclib.o resample.o codec.o ssr rtcp.o redis.o iptables.o graphite.o call_interfaces.strhash.o sdp.strhash.o rtp.o crypto.o \ control_ng.strhash.o \ streambuf.o cookie_cache.o udp_listener.o homer.o load.o cdr.o dtmf.o timerthread.o \ - media_player.o jitter_buffer.o dtmflib.o t38.o + media_player.o jitter_buffer.o dtmflib.o t38.o tcp_listener.o payload-tracker-test: payload-tracker-test.o $(COMMONOBJS) ssrc.o aux.o auxlib.o rtp.o crypto.o codeclib.o \ resample.o dtmflib.o From c548a3ca4be494532a8c14c55a5dcae69751572a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Ned=C5=BEibovi=C4=87?= Date: Thu, 28 Jan 2021 18:05:44 +0100 Subject: [PATCH 02/13] Implementation of control-ng via TCP. --- daemon/bencode.c | 109 ++++++++++++++++++++++++++++++++ daemon/control_ng.c | 145 +++++++++++++++++++++++++++++++++++++++++-- daemon/main.c | 17 ++++- include/bencode.h | 4 +- include/control_ng.h | 5 +- include/main.h | 1 + t/Makefile | 4 +- 7 files changed, 273 insertions(+), 12 deletions(-) diff --git a/daemon/bencode.c b/daemon/bencode.c index 4b4eb12e5..934b59cfa 100644 --- a/daemon/bencode.c +++ b/daemon/bencode.c @@ -703,3 +703,112 @@ void bencode_buffer_destroy_add(bencode_buffer_t *buf, free_func_t func, void *p li->next = buf->free_list; buf->free_list = li; } + +static int __bencode_string(const char *s, int offset, int len) { + int pos; + unsigned long long sl; + char *end; + + for (pos = offset + 1; s[pos] != 0x3a && isdigit(s[pos]) && pos < len; ++pos); + if (pos == len) + return -1; + + sl = strtoul(s + offset + 1, &end, 10); + if (s + offset + 1 == end || end != s + pos) + return -2; + + if (pos + sl > len) + return -1; + + return pos + sl + 1; +} + +static int __bencode_integer(const char *s, int offset, int len) { + int pos; + + if (s[offset + 1] == 0x2d) { + if (offset + 3 < len && s[offset + 2] == 0x30 && s[offset + 3] == 0x65) { + return -2; + } + ++offset; + } + + if (s[offset + 1] == 0x65) + return -2; + + if (s[offset + 1] == 0x30) { + if (offset + 2 < len && s[offset + 2] == 0x65) + return offset + 3; + return -2; + } + + for (pos = offset + 1; s[pos] != 0x65 && pos < len; ++pos) { + if (s[pos] < 0x30 || s[pos] > 0x39) + return -2; + } + + if (pos == len) + return -1; + + return pos + 1; +} + +static int __bencode_next(const char *s, int offset, int len); + +static int __bencode_list(const char *s, int offset, int len) { + for (++offset; s[offset] != 0x65 && offset < len;) { + offset = __bencode_next(s, offset, len); + if (offset < 0) + return offset; + } + + if (offset == len) + return -1; + + return offset + 1; +} + +static int __bencode_dictionary(const char *s, int offset, int len) { + for (++offset; s[offset] != 0x65 && offset < len;) { + offset = __bencode_string(s, offset - 1, len); + if (offset < 0) + return offset; + offset = __bencode_next(s, offset, len); + if (offset < 0) + return offset; + } + + if (offset == len) + return -1; + + return offset + 1; +} + +static int __bencode_next(const char *s, int offset, int len) { + if (offset >= len) + return -1; + switch(s[offset]) { + case 0x69: + return __bencode_integer(s, offset, len); + case 0x6c: + return __bencode_list(s, offset, len); + case 0x64: + return __bencode_dictionary(s, offset, len); + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + return __bencode_string(s, offset - 1, len); + } + return -2; +} + +int bencode_valid(const char *s, int len) { + return __bencode_next(s, 0, len); +} diff --git a/daemon/control_ng.c b/daemon/control_ng.c index 91a7cbfa2..b6807bf39 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -1,5 +1,6 @@ #include "control_ng.h" +#include #include #include #include @@ -16,10 +17,14 @@ #include "log_funcs.h" #include "main.h" #include "statistics.h" - +#include "streambuf.h" +#include "str.h" +#include "tcp_listener.h" mutex_t rtpe_cngs_lock; +mutex_t tcp_connections_lock; GHashTable *rtpe_cngs_hash; +GHashTable *tcp_connections_hash; struct control_ng *rtpe_control_ng; static struct cookie_cache ng_cookie_cache; @@ -42,7 +47,6 @@ const char *ng_command_strings_short[NGC_COUNT] = { "PlayDTMF", "Stats", }; - static void timeval_update_request_time(struct request_time *request, const struct timeval *offer_diff) { // lock offers mutex_lock(&request->lock); @@ -390,7 +394,6 @@ out: return funcret; } - static void control_ng_send(str *cookie, str *body, const endpoint_t *sin, void *p1) { socket_t *ul = p1; struct iovec iov[3]; @@ -408,13 +411,88 @@ static void control_ng_send(str *cookie, str *body, const endpoint_t *sin, void socket_sendiov(ul, iov, iovlen, sin); } - static void control_ng_incoming(struct obj *obj, struct udp_buffer *udp_buf) { control_ng_process(&udp_buf->str, &udp_buf->sin, udp_buf->addr, control_ng_send, udp_buf->listener, &udp_buf->obj); } +static void control_incoming(struct streambuf_stream *s) { + ilog(LOG_INFO, "New TCP control ng connection from %s", s->addr); + mutex_lock(&tcp_connections_lock); + g_hash_table_insert(tcp_connections_hash, s->addr, s); + mutex_unlock(&tcp_connections_lock); + ilog(LOG_DEBUG, "TCP connections map size: %d", g_hash_table_size(tcp_connections_hash)); +} + +static void control_closed(struct streambuf_stream *s) { + ilog(LOG_INFO, "TCP control ng connection from %s is closing", s->addr); + mutex_lock(&tcp_connections_lock); + g_hash_table_remove(tcp_connections_hash, s->addr); + mutex_unlock(&tcp_connections_lock); + ilog(LOG_DEBUG, "TCP connections map size: %d", g_hash_table_size(tcp_connections_hash)); +} + +static str *chunk_message(struct streambuf *b) { + char *p = NULL; + int len, to_del, bsize; + str *ret = NULL; + + mutex_lock(&b->lock); + + for (;;) { + if (b->eof) + break; + + p = memchr(b->buf->str, ' ', b->buf->len); + if (!p) + break; + + len = p - b->buf->str; + if (len == b->buf->len) + break; + + ++p; /* bencode dictionary here */ + bsize = bencode_valid(p, b->buf->str + b->buf->len - p); + if (bsize < 0) + break; /* not enough data to parse bencoded dictionary */ + + p += bsize; + len = p - b->buf->str; + to_del = len; + + ret = str_alloc(len); + memcpy(ret->s, b->buf->str, len); + ret->len = len; + g_string_erase(b->buf, 0, to_del); + + break; + } + + mutex_unlock(&b->lock); + return ret; +} + +static void control_stream_readable(struct streambuf_stream *s) { + str *data; + + ilog(LOG_DEBUG, "Got %ld bytes from %s", s->inbuf->buf->len, s->addr); + while ((data = chunk_message(s->inbuf))) { + ilog(LOG_DEBUG, "Got control ng message from %s", s->addr); + control_ng_process(data, &s->sock.remote, s->addr, control_ng_send, &s->sock, s->parent); + free(data); + } + + if (streambuf_bufsize(s->inbuf) > 1024) { + ilog(LOG_WARNING, "Buffer length exceeded in control connection from %s", s->addr); + goto close; + } + + return; + + close: + streambuf_stream_close(s); +} void control_ng_free(void *p) { struct control_ng *c = p; @@ -433,9 +511,12 @@ void control_ng_free(void *p) { poller_del_item(c->poller, c->udp_listeners[1].fd); close_socket(&c->udp_listeners[0]); close_socket(&c->udp_listeners[1]); + streambuf_listener_shutdown(&c->tcp_listeners[0]); + streambuf_listener_shutdown(&c->tcp_listeners[1]); + if (tcp_connections_hash) + g_hash_table_destroy(tcp_connections_hash); } - struct control_ng *control_ng_new(struct poller *p, endpoint_t *ep, unsigned char tos) { struct control_ng *c; @@ -463,9 +544,63 @@ struct control_ng *control_ng_new(struct poller *p, endpoint_t *ep, unsigned cha fail2: obj_put(c); return NULL; +} + +struct control_ng *control_ng_tcp_new(struct poller *p, endpoint_t *ep, struct control_ng *ctrl_ng) { + if (!p) + return NULL; + + if (!ctrl_ng) { + ctrl_ng = obj_alloc0("control_ng", sizeof(*ctrl_ng), NULL); + ctrl_ng->udp_listeners[0].fd = -1; + ctrl_ng->udp_listeners[1].fd = -1; + } + + ctrl_ng->poller = p; + + if (streambuf_listener_init(&ctrl_ng->tcp_listeners[0], p, ep, + control_incoming, control_stream_readable, + control_closed, + NULL, + &ctrl_ng->obj)) { + ilog(LOG_ERR, "Failed to open TCP control port: %s", strerror(errno)); + goto fail; + } + if (ipv46_any_convert(ep)) { + if (streambuf_listener_init(&ctrl_ng->tcp_listeners[1], p, ep, + control_incoming, control_stream_readable, + control_closed, + NULL, + &ctrl_ng->obj)) { + ilog(LOG_ERR, "Failed to open TCP control port: %s", strerror(errno)); + goto fail; + } + } + + tcp_connections_hash = g_hash_table_new(g_str_hash, g_str_equal); + mutex_init(&tcp_connections_lock); + return ctrl_ng; + +fail: + obj_put(ctrl_ng); + return NULL; +} + +static void notify_tcp_client(gpointer key, gpointer value, gpointer user_data) { + struct streambuf_stream *s = (struct streambuf_stream *)value; + str *to_send = (str *)user_data; + char cookie_buf[16]; + str cookie = STR_CONST_INIT_LEN(cookie_buf, sizeof(cookie_buf)); + rand_hex_str(cookie_buf, sizeof(cookie_buf) / 2); + control_ng_send(&cookie, to_send, &s->sock.remote, &s->sock); } +void notify_ng_tcp_clients(str *data) { + mutex_lock(&tcp_connections_lock); + g_hash_table_foreach(tcp_connections_hash, notify_tcp_client, data); + mutex_unlock(&tcp_connections_lock); +} void control_ng_init() { mutex_init(&rtpe_cngs_lock); diff --git a/daemon/main.c b/daemon/main.c index db3ba905f..bec3d985f 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -368,6 +368,7 @@ static void options(int *argc, char ***argv) { AUTO_CLEANUP_GBUF(listenps); AUTO_CLEANUP_GBUF(listenudps); AUTO_CLEANUP_GBUF(listenngs); + AUTO_CLEANUP_GBUF(listenngtcps); AUTO_CLEANUP_GBUF(listencli); AUTO_CLEANUP_GBUF(graphitep); AUTO_CLEANUP_GBUF(graphite_prefix_s); @@ -400,6 +401,7 @@ static void options(int *argc, char ***argv) { { "listen-tcp", 'l', 0, G_OPTION_ARG_STRING, &listenps, "TCP port to listen on", "[IP:]PORT" }, { "listen-udp", 'u', 0, G_OPTION_ARG_STRING, &listenudps, "UDP port to listen on", "[IP46|HOSTNAME:]PORT" }, { "listen-ng", 'n', 0, G_OPTION_ARG_STRING, &listenngs, "UDP port to listen on, NG protocol", "[IP46|HOSTNAME:]PORT" }, + { "listen-tcp-ng", 'N', 0, G_OPTION_ARG_STRING, &listenngtcps, "TCP port to listen on, NG protocol", "[IP46|HOSTNAME:]PORT" }, { "listen-cli", 'c', 0, G_OPTION_ARG_STRING, &listencli, "UDP port to listen on, CLI", "[IP46|HOSTNAME:]PORT" }, { "graphite", 'g', 0, G_OPTION_ARG_STRING, &graphitep, "Address of the graphite server", "IP46|HOSTNAME:PORT" }, { "graphite-interval", 'G', 0, G_OPTION_ARG_INT, &rtpe_config.graphite_interval, "Graphite send interval in seconds", "INT" }, @@ -504,8 +506,8 @@ static void options(int *argc, char ***argv) { if (!if_a) die("Missing option --interface"); - if (!listenps && !listenudps && !listenngs) - die("Missing option --listen-tcp, --listen-udp or --listen-ng"); + if (!listenps && !listenudps && !listenngs && !listenngtcps) + die("Missing option --listen-tcp, --listen-udp or --listen-ng or --listen-tcp-ng"); struct ifaddrs *ifas; if (getifaddrs(&ifas)) { @@ -552,6 +554,10 @@ static void options(int *argc, char ***argv) { if (endpoint_parse_any_getaddrinfo(&rtpe_config.ng_listen_ep, listenngs)) die("Invalid IP or port '%s' (--listen-ng)", listenngs); } + if (listenngtcps) { + if (endpoint_parse_any_getaddrinfo(&rtpe_config.ng_tcp_listen_ep, listenngtcps)) + die("Invalid IP or port '%s' (--listen-tcp-ng)", listenngtcps); + } if (listencli) {if (endpoint_parse_any_getaddrinfo(&rtpe_config.cli_listen_ep, listencli)) die("Invalid IP or port '%s' (--listen-cli)", listencli); @@ -787,6 +793,7 @@ void fill_initial_rtpe_cfg(struct rtpengine_config* ini_rtpe_cfg) { ini_rtpe_cfg->tcp_listen_ep = rtpe_config.tcp_listen_ep; ini_rtpe_cfg->udp_listen_ep = rtpe_config.udp_listen_ep; ini_rtpe_cfg->ng_listen_ep = rtpe_config.ng_listen_ep; + ini_rtpe_cfg->ng_tcp_listen_ep = rtpe_config.ng_tcp_listen_ep; ini_rtpe_cfg->cli_listen_ep = rtpe_config.cli_listen_ep; ini_rtpe_cfg->redis_ep = rtpe_config.redis_ep; ini_rtpe_cfg->redis_write_ep = rtpe_config.redis_write_ep; @@ -957,6 +964,12 @@ no_kernel: die("Failed to open UDP control connection port"); } + if (rtpe_config.ng_tcp_listen_ep.port) { + rtpe_control_ng = control_ng_tcp_new(rtpe_poller, &rtpe_config.ng_tcp_listen_ep, rtpe_control_ng); + if (!rtpe_control_ng) + die("Failed to open TCP control connection port"); + } + rtpe_cli = NULL; if (rtpe_config.cli_listen_ep.port) { interfaces_exclude_port(rtpe_config.cli_listen_ep.port); diff --git a/include/bencode.h b/include/bencode.h index fb7a1efc5..e729c9b70 100644 --- a/include/bencode.h +++ b/include/bencode.h @@ -301,8 +301,8 @@ INLINE bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char * /* Identical to bencode_decode_expect() but takes a "str" argument. */ INLINE bencode_item_t *bencode_decode_expect_str(bencode_buffer_t *buf, const str *s, bencode_type_t expect); - - +/* Returns the number of bytes that could successfully be decoded from 's', -1 if more bytes are needed or -2 on error */ +int bencode_valid(const char *s, int len); /*** DICTIONARY LOOKUP & EXTRACTION ***/ diff --git a/include/control_ng.h b/include/control_ng.h index c5d61f39b..c275ae45a 100644 --- a/include/control_ng.h +++ b/include/control_ng.h @@ -5,9 +5,9 @@ #include "udp_listener.h" #include "socket.h" #include "str.h" +#include "tcp_listener.h" #include "bencode.h" - struct poller; enum ng_command { @@ -48,6 +48,7 @@ struct control_ng_stats { struct control_ng { struct obj obj; socket_t udp_listeners[2]; + struct streambuf_listener tcp_listeners[2]; struct poller *poller; }; @@ -62,6 +63,8 @@ extern const char *ng_command_strings[NGC_COUNT]; extern const char *ng_command_strings_short[NGC_COUNT]; struct control_ng *control_ng_new(struct poller *, endpoint_t *, unsigned char); +struct control_ng *control_ng_tcp_new(struct poller *, endpoint_t *, struct control_ng *); +void notify_ng_tcp_clients(str *); void control_ng_init(void); void control_ng_cleanup(void); int control_ng_process(str *buf, const endpoint_t *sin, char *addr, diff --git a/include/main.h b/include/main.h index cf715df82..067e1e190 100644 --- a/include/main.h +++ b/include/main.h @@ -54,6 +54,7 @@ struct rtpengine_config { endpoint_t tcp_listen_ep; endpoint_t udp_listen_ep; endpoint_t ng_listen_ep; + endpoint_t ng_tcp_listen_ep; endpoint_t cli_listen_ep; endpoint_t redis_ep; endpoint_t redis_write_ep; diff --git a/t/Makefile b/t/Makefile index f184159d5..6b4bf4126 100644 --- a/t/Makefile +++ b/t/Makefile @@ -72,7 +72,7 @@ LIBSRCS+= codeclib.c resample.c socket.c streambuf.c dtmflib.c DAEMONSRCS+= codec.c call.c ice.c kernel.c media_socket.c stun.c bencode.c poller.c \ dtls.c recording.c statistics.c rtcp.c redis.c iptables.c graphite.c \ cookie_cache.c udp_listener.c homer.c load.c cdr.c dtmf.c timerthread.c \ - media_player.c jitter_buffer.c t38.c + media_player.c jitter_buffer.c t38.c tcp_listener.c HASHSRCS+= call_interfaces.c control_ng.c sdp.c endif @@ -164,7 +164,7 @@ transcode-test: transcode-test.o $(COMMONOBJS) codeclib.o resample.o codec.o ssr rtcp.o redis.o iptables.o graphite.o call_interfaces.strhash.o sdp.strhash.o rtp.o crypto.o \ control_ng.strhash.o \ streambuf.o cookie_cache.o udp_listener.o homer.o load.o cdr.o dtmf.o timerthread.o \ - media_player.o jitter_buffer.o dtmflib.o t38.o + media_player.o jitter_buffer.o dtmflib.o t38.o tcp_listener.o payload-tracker-test: payload-tracker-test.o $(COMMONOBJS) ssrc.o aux.o auxlib.o rtp.o crypto.o codeclib.o \ resample.o dtmflib.o From f805d881fa64cb581f14b11e7096e57b25ce670a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Ned=C5=BEibovi=C4=87?= Date: Thu, 28 Jan 2021 18:09:10 +0100 Subject: [PATCH 03/13] Add missing include. --- daemon/bencode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/bencode.c b/daemon/bencode.c index 934b59cfa..bd019913e 100644 --- a/daemon/bencode.c +++ b/daemon/bencode.c @@ -5,7 +5,7 @@ #include #include #include - +#include /* set to 0 for alloc debugging, e.g. through valgrind */ #define BENCODE_MIN_BUFFER_PIECE_LEN 512 From 11d11aed907d60e435ca81c7694d0468e45a76e5 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 28 Jan 2021 13:41:28 -0500 Subject: [PATCH 04/13] TT#14008 clean up some tests Looks like packet order can be an issue in some cases Change-Id: Ib8fb8c553c9d0f2919b24dda1e15e5a23832c619 --- t/auto-daemon-tests-reorder.pl | 7406 ++++++++++++-------------------- t/auto-daemon-tests.pl | 7 + 2 files changed, 2822 insertions(+), 4591 deletions(-) diff --git a/t/auto-daemon-tests-reorder.pl b/t/auto-daemon-tests-reorder.pl index c39b5b21e..e8fc65fe3 100755 --- a/t/auto-daemon-tests-reorder.pl +++ b/t/auto-daemon-tests-reorder.pl @@ -2046,1355 +2046,1268 @@ rcv($sock_a, $port_b, rtpm(0, 5000, 7000, -1, "\x00" x 160)); -if ($amr_tests) { -# AMR-WB mode tests -($sock_a, $sock_b) = new_call([qw(198.51.100.10 3000)], [qw(198.51.100.10 3002)]); +new_call; -($port_a) = offer('PCM -> AMR-WB default', - { ICE => 'remove', replace => ['origin'], codec => { transcode => ['AMR-WB'] } }, < 'remove', + flags => ['inject-DTMF'], + codec => {transcode => ['G722']}, + }, < AMR-WB default', - { ICE => 'remove', replace => ['origin'] }, < 'remove', + flags => ['inject-DTMF'], + }, < AMR-WB force bitrate', - { ICE => 'remove', replace => ['origin'], codec => { transcode => ['AMR-WB/16000/1/23850'] } }, < 'remove', + flags => [], + codec => {transcode => ['G722']}, + }, < AMR-WB force bitrate', - { ICE => 'remove', replace => ['origin'] }, < 'remove', + flags => [], + }, < AMR-WB answer mode-set', - { ICE => 'remove', replace => ['origin'], codec => { transcode => ['AMR-WB/16000/1/23850'] } }, < { + mask => ['all'], + transcode => ['G722', 'opus/48000/1', 'PCMA', 'telephone-event'] + }, + }, < AMR-WB answer mode-set', - { ICE => 'remove', replace => ['origin'] }, < AMR-WB offer mode-set', - { ICE => 'remove', replace => ['origin'], codec => { transcode => ['AMR-WB/16000/1/23850//mode-set=0,1,2,3,4,5'] } }, < 'remove', + flags => [], + codec => {transcode => ['G722']}, + }, < AMR-WB offer mode-set', - { ICE => 'remove', replace => ['origin'] }, < 'remove', + flags => [], + }, < AMR-WB offer mode-set, restrict answer', - { ICE => 'remove', replace => ['origin'], codec => { transcode => ['AMR-WB/16000/1/23850//mode-set=0,1,2,3,4,5'] } }, < 'remove', + flags => [], + codec => {transcode => ['G722']}, + }, < AMR-WB offer mode-set, restrict answer', - { ICE => 'remove', replace => ['origin'] }, < 'remove', + flags => [], + }, < PCM default', - { ICE => 'remove', replace => ['origin'], codec => { transcode => ['PCMA'] } }, < 'remove', + flags => [], + codec => {transcode => ['G722']}, + }, < PCM default', - { ICE => 'remove', replace => ['origin'] }, < 'remove', + flags => ['single codec'], + }, < PCM force bitrate', - { ICE => 'remove', replace => ['origin'], codec => { transcode => ['PCMA'], - 'set' => ['AMR-WB/16000/1/23850'] } }, < 'remove', + flags => [], + }, < PCM force bitrate', - { ICE => 'remove', replace => ['origin'] }, < 'remove', + flags => [], + }, < PCM offer mode-set', - { ICE => 'remove', replace => ['origin'], codec => { transcode => ['PCMA'], - 'set' => ['AMR-WB/16000/1/23850'] } }, < 'remove', + flags => [], + }, < PCM offer mode-set', - { ICE => 'remove', replace => ['origin'] }, < 'remove', + flags => ['single codec'], + }, < PCM CMR', - { ICE => 'remove', replace => ['origin'], codec => { transcode => ['PCMA'], - 'set' => ['AMR-WB/16000/1/23850'] } }, < 'remove', + flags => [], + codec => {transcode => ['opus']}, + }, < PCM CMR', - { ICE => 'remove', replace => ['origin'] }, < 'remove', + flags => ['single codec'], + }, < 'remove', replace => ['origin'], codec => { transcode => ['PCMA'], - 'set' => ['AMR-WB/16000/1/23850'] } }, < 'remove', + flags => [], + codec => {mask => ['all'], transcode => ['opus/48000/1', 'PCMA', 'telephone-event']}, + }, < 'remove', replace => ['origin'] }, < 'remove', + flags => ['single codec'], + }, < 'remove', replace => ['origin'], codec => { transcode => ['PCMA'], - 'set' => ['AMR-WB/16000/1/6600'] } }, < 'remove', + flags => [], + codec => {transcode => ['PCMA']}, + }, < 'remove', replace => ['origin'] }, < 'remove', + flags => ["codec-mask-all", "codec-strip-telephone-event", "codec-transcode-PCMU", "codec-transcode-G722", "codec-transcode-t38", "codec-offer-telephone-event", "port-latching"], + 'to-tag' => tt(), + }, < 'remove', replace => ['origin'], codec => { transcode => ['PCMA'], - 'set' => ['AMR-WB/16000/1////CMR-interval=200'] } }, < 'remove', + flags => ["trust-address", "symmetric-codecs"], + }, < 'remove', replace => ['origin'] }, < 'remove', + flags => ["codec-mask-all", "codec-strip-telephone-event", "codec-transcode-PCMU", "codec-transcode-G722", "codec-transcode-t38", "codec-offer-telephone-event", "port-latching"], + 'to-tag' => tt(), + }, < PCM CMR w/ mode-change-interval', - { ICE => 'remove', replace => ['origin'], codec => { transcode => ['PCMA'], - 'set' => ['AMR-WB/16000/1/23850///mode-change-interval=200'] } }, < 'remove', 'transport-protocol' => 'RTP/AVP', + }, < PCM CMR w/ mode-change-interval', - { ICE => 'remove', replace => ['origin'] }, < 'remove', + }, < 'remove', replace => ['origin'], codec => { transcode => ['PCMA'], - 'set' => ['AMR-WB/16000/1/23850///mode-change-interval=200'] } }, < 'remove', 'transport-protocol' => 'RTP/AVP', + 'DTLS-reverse' => 'passive', + }, < 'remove', replace => ['origin'] }, < 'remove', + }, < 'remove', 'transport-protocol' => 'RTP/AVP', 'rtcp-mux' => ['demux'], + }, < 'remove', replace => ['origin'], codec => { - 'transcode' => ['AMR-WB/16000/1/23850//octet-align=1/mode-change-interval=200'] } }, < 'remove', }, < 'remove', replace => ['origin'] }, < 'remove', }, < ft(), blob => $wav_file }); +is $resp->{duration}, 100, 'media duration'; +($seq, $ts, $ssrc) = rcv($sock_a, $port_b, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); +# SR LEN SSRC NTP1 NTP2 RTP PACKETS OCTETS SSRC LOST SEQ JITTER LAST SR DLSR CNAME +@ret1 = rcv($sock_ax, $port_bx, qr/^\x81\xc8\x00\x0c(.{4})(.{4})(.{4})(.{4})\x00\x00\x00\x01\x00\x00\x00\xac\x00\x00\x12\x34\x00\x00\x00\x00\x00\x00\x03\xe8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xca\x00\x05(.{4})\x01\x0c([0-9a-f]{12})\x00\x00$/s); +is $ret1[0], $ssrc, 'SSRC matches'; +is $ret1[3], $ts, 'TS matches'; +is $ret1[4], $ssrc, 'SSRC matches'; -} +rtpe_req('delete', "delete", { 'from-tag' => ft() }); -new_call; -offer('DTMF-inject w tp-e', { - ICE => 'remove', - flags => ['inject-DTMF'], - codec => {transcode => ['G722']}, - }, < 'remove', }, < 'remove', - flags => ['inject-DTMF'], - }, < 'remove', }, < 'remove', - flags => [], - codec => {transcode => ['G722']}, - }, < ft(), blob => $wav_file }); +is $resp->{duration}, 100, 'media duration'; -answer('symmetric codecs w missing answer codec, no flag', { - ICE => 'remove', - flags => [], - }, < ft() }); -new_call; -offer('some t/c options with answer only non-t/c codec', { - codec => { - mask => ['all'], - transcode => ['G722', 'opus/48000/1', 'PCMA', 'telephone-event'] - }, - }, < 'remove', - flags => [], - codec => {transcode => ['G722']}, - }, < 'remove', - flags => [], - }, < 'remove', }, < 'remove', - flags => [], - codec => {transcode => ['G722']}, - }, < 'remove', codec => { mask => ['full'], transcode => ['PCMA','telephone-event'] } }, < 'remove', - flags => [], - }, < 'remove', }, < 'remove', - flags => [], - codec => {transcode => ['G722']}, - }, < 'remove', codec => { mask => ['all'], transcode => ['PCMA','telephone-event'] } }, < 'remove', - flags => ['single codec'], - }, < 'remove', }, < 'remove', - flags => [], - }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', - flags => [], - }, < 'remove', }, < 'remove', - flags => [], - }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', - flags => ['single codec'], - }, < 'remove', flags => ['symmetric codecs'] }, < 'remove', - flags => [], - codec => {transcode => ['opus']}, - }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', - flags => ['single codec'], - }, < 'remove', }, < 'remove', - flags => [], - codec => {mask => ['all'], transcode => ['opus/48000/1', 'PCMA', 'telephone-event']}, - }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', - flags => ['single codec'], - }, < 'remove', flags => ['symmetric codecs'] }, < 'remove', - flags => [], - codec => {transcode => ['PCMA']}, - }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', }, < 'remove', - flags => ["codec-mask-all", "codec-strip-telephone-event", "codec-transcode-PCMU", "codec-transcode-G722", "codec-transcode-t38", "codec-offer-telephone-event", "port-latching"], - 'to-tag' => tt(), - }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', - flags => ["trust-address", "symmetric-codecs"], - }, < 'remove', flags => ['symmetric codecs'] }, < 'remove', - flags => ["codec-mask-all", "codec-strip-telephone-event", "codec-transcode-PCMU", "codec-transcode-G722", "codec-transcode-t38", "codec-offer-telephone-event", "port-latching"], - 'to-tag' => tt(), - }, < [ 'decode' ], ICE => 'remove', + }, < ft() }); -# DTLS-reverse flag -new_call; -offer('DTLS-reverse not set', { - ICE => 'remove', 'transport-protocol' => 'RTP/AVP', - }, < 'remove', + }, < 'remove', - }, < 'remove', + }, < 'remove', 'transport-protocol' => 'RTP/AVP', - 'DTLS-reverse' => 'passive', - }, < 'remove', 'T.38' => [ 'force' ], + }, < 'remove', - }, < 'remove', + }, < ft() }); -# DTLS early start with ICE (GH 1035 TT 84804) -($sock_a, $sock_b, $sock_c, $sock_d) = new_call([qw(198.51.100.4 2000)], [qw(198.51.100.4 2001)], [qw(198.51.100.8 3000)], [qw(198.51.100.8 3001)]); -offer('ICE offer with DTLS', { - ICE => 'remove', 'transport-protocol' => 'RTP/AVP', 'rtcp-mux' => ['demux'], - }, < 'remove', + }, < 'remove', }, < 'remove', + }, < 'remove', }, < 'remove', 'T.38' => [ 'decode' ], + }, < ft(), blob => $wav_file }); -is $resp->{duration}, 100, 'media duration'; - -($seq, $ts, $ssrc) = rcv($sock_a, $port_b, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); -# SR LEN SSRC NTP1 NTP2 RTP PACKETS OCTETS SSRC LOST SEQ JITTER LAST SR DLSR CNAME -@ret1 = rcv($sock_ax, $port_bx, qr/^\x81\xc8\x00\x0c(.{4})(.{4})(.{4})(.{4})\x00\x00\x00\x01\x00\x00\x00\xac\x00\x00\x12\x34\x00\x00\x00\x00\x00\x00\x03\xe8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xca\x00\x05(.{4})\x01\x0c([0-9a-f]{12})\x00\x00$/s); -is $ret1[0], $ssrc, 'SSRC matches'; -is $ret1[3], $ts, 'TS matches'; -is $ret1[4], $ssrc, 'SSRC matches'; +answer('T.38 reverse re-invite', { ICE => 'remove' }, < ft() }); @@ -4022,2602 +4005,995 @@ rtpe_req('delete', "delete", { 'from-tag' => ft() }); -($sock_a, $sock_ax, $sock_b, $sock_bx) = new_call( - [qw(198.51.100.1 7400)], - [qw(198.51.100.1 7401)], - [qw(198.51.100.3 7402)], - [qw(198.51.100.3 7403)], -); -($port_a, $port_ax) = offer('RTCP player w/ previous SR', { ICE => 'remove', }, < 'remove', + }, < 'remove', }, < 'remove', + }, < 'remove', 'T.38' => [ 'force' ], + }, < 'remove', + }, < ft(), blob => $wav_file }); -is $resp->{duration}, 100, 'media duration'; - -($seq, $ts, $ssrc) = rcv($sock_a, $port_b, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); -# SR LEN SSRC NTP1 NTP2 RTP PACKETS OCTETS SSRC LOST SEQ JITTER LAST SR DLSR CNAME -@ret1 = rcv($sock_ax, $port_bx, qr/^\x81\xc8\x00\x0c(.{4})(.{4})(.{4})(.{4})\x00\x00\x00\x01\x00\x00\x00\xac\x00\x00\x12\x34\x00\x00\x00\x00\x00\x00\x03\xe8\x00\x00\x00\x00\x56\x78\x9a\xbc(.{4})\x81\xca\x00\x05(.{4})\x01\x0c([0-9a-f]{12})\x00\x00$/s); -is $ret1[0], $ssrc, 'SSRC matches'; -is $ret1[3], $ts, 'TS matches'; -cmp_ok $ret1[4], '<', 1000, 'DSLR ok'; -is $ret1[5], $ssrc, 'SSRC matches'; - -rtpe_req('delete', "delete", { 'from-tag' => ft() }); +rtpe_req('delete', "delete", { 'from-tag' => ft() }); -# MSRP (GH 959) - new_call(); -offer('gh 959 media c=', { ICE => 'remove', }, < 'remove', + }, < 'remove', + }, < 'remove', 'T.38' => [ 'decode' ], + }, < 'remove', }, < 'remove' }, < ft() }); +new_call; - - -# PT collisions (GH 963) - -new_call(); - -offer('gh 963', { ICE => 'remove', codec => { mask => ['full'], transcode => ['PCMA','telephone-event'] } }, < 'remove', 'T.38' => [ 'force', 'FEC' ], + }, < 'remove', }, < ft() }); -new_call(); -offer('gh 963 w mask all', { ICE => 'remove', codec => { mask => ['all'], transcode => ['PCMA','telephone-event'] } }, < 'remove', }, < 'force-relay', flags => [qw(SDES-off)], 'transport-protocol' => 'UDP/TLS/RTP/SAVPF', + 'rtcp-mux' => [qw(accept offer)], 'via-branch' => 'z9hG4bK9463.af303705.113', + }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', flags => ['symmetric codecs'] }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', flags => ['symmetric codecs'] }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', }, < 'remove', codec => { transcode => ['G722'] } }, < 'remove', flags => ['symmetric codecs'] }, < [ 'decode' ], ICE => 'remove', - }, < ft() }); - - - - - - -new_call(); - -offer('T.38 forward re-invite', { ICE => 'remove', - }, < 'remove', - }, < 'remove', 'T.38' => [ 'force' ], - }, < 'remove', - }, < ft() }); - - - - -new_call(); - -offer('T.38 reverse re-invite', { ICE => 'remove', - }, < 'remove', - }, < 'remove', 'T.38' => [ 'decode' ], - }, < 'remove' }, < ft() }); - - - - - - -new_call(); - -offer('T.38 forward re-invite w/ unsupported codec', { ICE => 'remove', - }, < 'remove', - }, < 'remove', 'T.38' => [ 'force' ], - }, < 'remove', - }, < ft() }); - - - - -new_call(); - -offer('T.38 reverse re-invite w/ unsupported codec', { ICE => 'remove', - }, < 'remove', - }, < 'remove', 'T.38' => [ 'decode' ], - }, < 'remove' }, < ft() }); - - - -new_call; - -offer('T.38 FEC invite', { ICE => 'remove', 'T.38' => [ 'force', 'FEC' ], - }, < ft() }); - - - - - -# github issue 850 - -new_call; - -@ret1 = offer('gh 850', - { - ICE => 'force-relay', flags => [qw(SDES-off)], 'transport-protocol' => 'UDP/TLS/RTP/SAVPF', - 'rtcp-mux' => [qw(accept offer)], 'via-branch' => 'z9hG4bK9463.af303705.113', - }, < 'force-relay', flags => [qw(SDES-off)], 'transport-protocol' => 'UDP/TLS/RTP/SAVPF', - 'rtcp-mux' => [qw(accept offer)], 'via-branch' => 'z9hG4bK9463.af303705.113', - }, < 'remove', replace => ['origin'], codec => { transcode => ['PCMA'] } }, < 'remove', replace => ['origin'] }, < 'remove', replace => ['origin'], codec => { transcode => ['PCMA'] } }, < 'remove', replace => ['origin'] }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < ft(), code => '0', volume => 10, duration => 100 }); - -snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96 | 0x80, 1002, 3320, $ssrc, "\x00\x0a\x00\xa0")); -snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1003, 3320, $ssrc, "\x00\x0a\x01\x40")); -snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1004, 3320, $ssrc, "\x00\x0a\x01\xe0")); -snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1005, 3320, $ssrc, "\x00\x0a\x02\x80")); -snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1006, 3320, $ssrc, "\x00\x0a\x03\x20")); -snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1007, 3320, $ssrc, "\x00\x8a\x03\xc0")); -rcv($sock_b, $port_a, rtpm(96, 1008, 3320, $ssrc, "\x00\x8a\x03\xc0")); -rcv($sock_b, $port_a, rtpm(96, 1009, 3320, $ssrc, "\x00\x8a\x03\xc0")); -snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1010, 4280, $ssrc, "\x00" x 160)); - - - -snd($sock_b, $port_a, rtp(0, 4000, 8000, 0x6543, "\x00" x 160)); -($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 8000, -1, "\x00" x 160)); -snd($sock_b, $port_a, rtp(0, 4001, 8160, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4001, 8160, $ssrc, "\x00" x 160)); - -$resp = rtpe_req('play DTMF', 'inject DTMF towards A', - { 'from-tag' => tt(), code => '*', volume => 10, duration => 100 }); - -snd($sock_b, $port_a, rtp(0, 4002, 8320, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(96 | 0x80, 4002, 8320, $ssrc, "\x0a\x0a\x00\xa0")); -snd($sock_b, $port_a, rtp(0, 4003, 8480, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(96, 4003, 8320, $ssrc, "\x0a\x0a\x01\x40")); -snd($sock_b, $port_a, rtp(0, 4004, 8640, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(96, 4004, 8320, $ssrc, "\x0a\x0a\x01\xe0")); -snd($sock_b, $port_a, rtp(0, 4005, 8800, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(96, 4005, 8320, $ssrc, "\x0a\x0a\x02\x80")); -snd($sock_b, $port_a, rtp(0, 4006, 8960, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(96, 4006, 8320, $ssrc, "\x0a\x0a\x03\x20")); -snd($sock_b, $port_a, rtp(0, 4007, 9120, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(96, 4007, 8320, $ssrc, "\x0a\x8a\x03\xc0")); -rcv($sock_a, $port_b, rtpm(96, 4008, 8320, $ssrc, "\x0a\x8a\x03\xc0")); -rcv($sock_a, $port_b, rtpm(96, 4009, 8320, $ssrc, "\x0a\x8a\x03\xc0")); -snd($sock_b, $port_a, rtp(0, 4008, 9280, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4010, 9280, $ssrc, "\x00" x 160)); - - - - - -# transcoding, RFC payload type present on both sides - -($sock_a, $sock_b) = new_call([qw(198.51.100.1 6110)], [qw(198.51.100.3 6112)]); - -($port_a) = offer('transcoding, RFC payload type present on both sides', - { ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'], - codec => { transcode => ['PCMA'] }}, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < ft(), code => '0', volume => 10, duration => 100 }); - -snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96 | 0x80, 1002, 3320, $ssrc, "\x00\x0a\x00\xa0")); -snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1003, 3320, $ssrc, "\x00\x0a\x01\x40")); -snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1004, 3320, $ssrc, "\x00\x0a\x01\xe0")); -snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1005, 3320, $ssrc, "\x00\x0a\x02\x80")); -snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1006, 3320, $ssrc, "\x00\x0a\x03\x20")); -snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1007, 3320, $ssrc, "\x00\x8a\x03\xc0")); -rcv($sock_b, $port_a, rtpm(96, 1008, 3320, $ssrc, "\x00\x8a\x03\xc0")); -rcv($sock_b, $port_a, rtpm(96, 1009, 3320, $ssrc, "\x00\x8a\x03\xc0")); -snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1010, 4280, $ssrc, "\x2a" x 160)); - - - -snd($sock_b, $port_a, rtp(8, 4000, 8000, 0x6543, "\x2a" x 160)); -($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 8000, -1, "\x00" x 160)); -snd($sock_b, $port_a, rtp(8, 4001, 8160, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4001, 8160, $ssrc, "\x00" x 160)); - -$resp = rtpe_req('play DTMF', 'inject DTMF towards A', - { 'from-tag' => tt(), code => '#', volume => -10, duration => 100 }); - -snd($sock_b, $port_a, rtp(8, 4002, 8320, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(96 | 0x80, 4002, 8320, $ssrc, "\x0b\x0a\x00\xa0")); -snd($sock_b, $port_a, rtp(8, 4003, 8480, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(96, 4003, 8320, $ssrc, "\x0b\x0a\x01\x40")); -snd($sock_b, $port_a, rtp(8, 4004, 8640, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(96, 4004, 8320, $ssrc, "\x0b\x0a\x01\xe0")); -snd($sock_b, $port_a, rtp(8, 4005, 8800, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(96, 4005, 8320, $ssrc, "\x0b\x0a\x02\x80")); -snd($sock_b, $port_a, rtp(8, 4006, 8960, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(96, 4006, 8320, $ssrc, "\x0b\x0a\x03\x20")); -snd($sock_b, $port_a, rtp(8, 4007, 9120, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(96, 4007, 8320, $ssrc, "\x0b\x8a\x03\xc0")); -rcv($sock_a, $port_b, rtpm(96, 4008, 8320, $ssrc, "\x0b\x8a\x03\xc0")); -rcv($sock_a, $port_b, rtpm(96, 4009, 8320, $ssrc, "\x0b\x8a\x03\xc0")); -snd($sock_b, $port_a, rtp(8, 4008, 9280, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4010, 9280, $ssrc, "\x00" x 160)); - - - -# no transcoding, no RFC payload type present - -($sock_a, $sock_b) = new_call([qw(198.51.100.1 6014)], [qw(198.51.100.3 6016)]); - -($port_a) = offer('no transcoding, no RFC payload type present', - { ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < ft(), code => 'C', volume => 5, duration => 120, pause => 110 }); - -snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1002, 3320, $ssrc, "\xff\x93\x94\xbc\x2e\x56\xbf\x2b\x13\x1b\xa7\x8e\x98\x47\x25\x41\xe2\x24\x16\x2b\x99\x8e\x9f\x28\x1e\x3d\x5b\x23\x1c\xdf\x92\x8f\xb6\x1c\x1c\x40\x5d\x26\x25\xaa\x8f\x95\x3b\x15\x1d\x5e\xde\x2c\x38\x9d\x8f\x9e\x1f\x11\x20\xc0\xc1\x37\xdd\x99\x92\xb7\x15\x10\x2c\xac\xb5\x49\xb8\x97\x99\x37\x0f\x13\x58\xa0\xae\x67\xae\x99\xa4\x1f\x0d\x1a\xae\x9b\xad\x7b\xad\x9d\xbf\x16\x0e\x27\x9d\x98\xb0\x55\xb1\xa6\x3a\x11\x11\x63\x95\x98\xbf\x3e\xbb\xb4\x26\x10\x1a\xa9\x90\x9a\x4e\x30\xce\xd4\x1e\x12\x29\x99\x8e\xa1\x2d\x29\x6d\x4b\x1c\x18\xef\x91\x8f\xb6\x1f\x24\x57\x3e\x1d\x20\xa9\x8e\x95\x3e\x19\x23\x67\x3e\x21\x31\x9c\x8e\x9e\x22\x14\x26\xcd\x4a")); -snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1003, 3480, $ssrc, "\x2a\xdf\x96\x90\xb5\x17\x13\x2f\xb6\xf5\x36\xb1\x93\x96\x39\x10\x15\x55\xaa\xc8\x4c\xa7\x95\xa0\x1f\x0e\x1b\xb4\xa1\xbd\xed\xa4\x99\xbb\x15\x0e\x27\xa0\x9d\xbd\xda\xa4\x9f\x39\x10\x11\x58\x98\x9c\xc8\xf9\xa9\xac\x23\x0e\x19\xab\x92\x9e\x59\x4c\xb0\xca\x1b\x10\x27\x9a\x90\xa5\x35\x3a\xbe\x43\x18\x15\x6c\x92\x91\xb7\x26\x30\xd6\x32\x18\x1d\xa9\x8e\x96\x44\x1d\x2d\xfc\x2e\x1b\x2d\x9a\x8d\x9e\x25\x19\x2d\xe7\x2f\x20\xea\x94\x8f\xb3\x19\x17\x36\xc8\x36\x2c\xae\x90\x95\x3b\x12\x18\x55\xb7\x43\x3e\xa1\x91\x9e\x1f\x0f\x1d\xba\xac\x64\xe8\x9d\x95\xb7\x15\x0e\x29\xa6\xa6\xda\xc3\x9d\x9b\x39\x0f\x11\x51\x9c\xa2\xd8\xbe\x9f\xa7\x21\x0e\x18\xad")); -snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1004, 3640, $ssrc, "\x96\xa3\x68\xc4\xa5\xc2\x19\x0e\x26\x9c\x93\xa9\x3f\xdb\xae\x3e\x14\x12\x5b\x93\x93\xb9\x2e\x51\xbe\x2c\x14\x1b\xa9\x8f\x97\x4c\x25\x3f\xde\x25\x16\x2a\x9a\x8e\x9e\x29\x1e\x3b\x5e\x24\x1b\x7b\x92\x8f\xb2\x1c\x1c\x3e\x61\x27\x25\xac\x8f\x94\x3e\x15\x1c\x59\xdb\x2d\x37\x9e\x8f\x9d\x20\x11\x1f\xc2\xbf\x38\xea\x99\x92\xb4\x16\x10\x2b\xad\xb4\x49\xba\x98\x98\x3a\x0f\x12\x4e\xa1\xad\x68\xaf\x99\xa3\x20\x0d\x19\xb0\x9b\xac\x7b\xae\x9d\xbc\x17\x0e\x25\x9e\x98\xaf\x55\xb2\xa6\x3d\x12\x11\x52\x96\x97\xbd\x3e\xbc\xb3\x28\x10\x19\xab\x90\x9a\x54\x2f\xd0\xcf\x1f\x12\x27\x9a\x8e\xa0\x2e\x28\x66\x4e\x1d\x18\x62\x92\x8f\xb2\x20\x23\x53\x3f\x1d\x1f")); -snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1005, 3800, $ssrc, "\xab\x8e\x94\x44\x19\x22\x61\x40\x21\x2f\x9c\x8e\x9d\x23\x14\x25\xce\x4d\x2a\xf7\x96\x8f\xb1\x18\x13\x2e\xb7\xe8\x36\xb3\x94\x96\x3c\x10\x15\x4d\xaa\xc5\x4b\xa8\x95\x9f\x20\x0e\x1a\xb6\xa0\xbc\xf5\xa4\x99\xb8\x16\x0e\x26\xa1\x9d\xbb\xdd\xa5\x9f\x3c\x10\x10\x4c\x99\x9b\xc5\x78\xaa\xac\x24\x0f\x18\xac\x93\x9d\x5f\x4a\xb1\xc7\x1c\x0f\x25\x9b\x90\xa3\x36\x39\xbf\x47\x18\x14\x56\x92\x90\xb4\x27\x2f\xd7\x34\x18\x1c\xab\x8e\x95\x4b\x1d\x2c\xfe\x2f\x1b\x2c\x9b\x8d\x9d\x27\x19\x2c\xe7\x30\x20\x6d\x94\x8f\xaf\x1a\x17\x34\xc8\x37\x2b\xaf\x91\x94\x3f\x12\x18\x4e\xb6\x45\x3d\xa3\x91\x9e\x20\x0f\x1c\xbc\xab\x6c\xf5\x9e\x95\xb3\x16\x0e\x27\xa7\xa5")); -snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1006, 3960, $ssrc, "\xd6\xc6\x9d\x9b\x3d\x0f\x11\x49\x9c\xa1\xd4\xbf\x9f\xa6\x22\x0e\x18\xaf\x96\xa2\x6e\xc6\xa5\xbe\x19\x0e\x24\x9d\x93\xa8\x40\xe1\xae\x42\x15\x12\x4e\x94\x93\xb7\x2e\x4e\xbe\x2d\x14\x1a\xab\x8f\x97\x52\x25\x3e\xdc\x26\x16\x28\x9b\x8e\x9e\x2b\x1e\x3a\x61\x25\x1b\x5d\x93\x8f\xaf\x1d\x1c\x3d\x67\x27\x24\xad\x8f\x93\x45\x15\x1c\x53\xd7\x2d\x35\x9f\x8f\x9c\x22\x11\x1f\xc5\xbe\x38\x7a\x9a\x91\xb0\x17\x10\x29\xad\xb3\x4a\xbc\x98\x98\x3e\x10\x12\x48\xa1\xad\x6a\xb1\x9a\xa1\x21\x0e\x18\xb3\x9b\xab\x7d\xaf\x9d\xb9\x18\x0e\x23\x9f\x97\xae\x55\xb4\xa5\x40\x12\x10\x49\x96\x97\xbb\x3d\xbd\xb2\x29\x10\x18\xac\x90\x99\x5d\x2f\xd4\xcd\x1f\x12\x25\x9b")); -snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1007, 4120, $ssrc, "\x8e\x9f\x2f\x28\x5f\x51\x1d\x17\x52\x92\x8f\xaf\x20\x22\x50\x42\x1e\x1f\xad\x8e\x93\x4b\x19\x21\x5d\x42\x22\x2e\x9d\x8e\x9c\x25\x14\x24\xd0\x4f\x2a\x68\x97\x8f\xae\x18\x12\x2c\xb7\xdf\x36\xb6\x94\x95\x41\x11\x14\x48\xaa\xc3\x4a\xaa\x95\x9e\x21\x0e\x19\xb8\xa0\xba\xfe\xa5\x99\xb4\x17\x0e\x24\xa2\x9c\xba\xe0\xa6\x9e\x40\x10\x10\x45\x99\x9b\xc2\x6d\xaa\xab\x26\x0f\x17\xae\x93\x9c\x6a\x48\xb2\xc3\x1c\x0f\x23\x9c\x90\xa2\x37\x38\xbf\x4b\x19\x14\x4b\x93\x90\xb1\x27\x2e\xd8\x36\x19\x1c\xad\x8e\x94\x52\x1d\x2b\x7d\x30\x1b\x2a\x9c\x8d\x9c\x28\x19\x2b\xe7\x31\x20\x5a\x95\x8f\xad\x1a\x16\x32\xc8\x39\x2b\xb2\x91\x94\x46\x13\x17\x4a\xb6\x48\x3c")); -# pause -snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1008, 4280, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1009, 4440, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1009, 4440, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1010, 4600, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1011, 4760, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1011, 4760, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1012, 4920, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1012, 4920, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1013, 5080, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1013, 5080, $ssrc, "\xff" x 80 . "\x00" x 80)); - - - -snd($sock_b, $port_a, rtp(0, 4000, 8000, 0x6543, "\x00" x 160)); -($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 8000, -1, "\x00" x 160)); -snd($sock_b, $port_a, rtp(0, 4001, 8160, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4001, 8160, $ssrc, "\x00" x 160)); - -$resp = rtpe_req('play DTMF', 'inject DTMF towards A', - { 'from-tag' => tt(), code => '4', volume => 3, duration => 150, pause => 100 }); - -snd($sock_b, $port_a, rtp(0, 4002, 8320, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4002, 8320, $ssrc, "\xff\x90\x8a\x93\xd9\x1b\x18\x27\x65\xe5\x33\x29\x4c\x9e\x8f\x91\xb8\x15\x09\x0d\x32\x98\x8e\x96\xbb\x2c\x2b\x4c\xd8\x34\x1c\x18\x2e\x9d\x8c\x8c\xa5\x1a\x0b\x0d\x27\xa3\x97\x9e\xbd\x4f\xc4\xaa\xb2\x2c\x12\x0e\x1e\xa1\x8b\x8a\x9c\x25\x0e\x10\x25\xb7\xa7\xb7\x5e\xcb\xa2\x98\x9f\x30\x0f\x0a\x16\xae\x8d\x8a\x98\x3a\x18\x19\x2c\xdd\xfd\x30\x2b\xce\x99\x8e\x95\x4c\x0f\x09\x10\xdf\x93\x8e\x9a\xec\x28\x2c\x56\xee\x2d\x1a\x1a\x48\x97\x8b\x8e\xba\x14\x0a\x0f\x39\x9d\x96\xa1\xcd\x4e\xbe\xab\xbe\x23\x10\x10\x2b\x99\x8a\x8c\xa7\x1b\x0d\x12\x2f\xad\xa7\xbc\x5e\xbd\x9f\x99\xa8\x23\x0d\x0b\x1d\x9f\x8b\x8c\x9f\x29\x16\x1b\x34\xcd\x60\x2f\x2f\xb6\x96")); -snd($sock_b, $port_a, rtp(0, 4003, 8480, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4003, 8480, $ssrc, "\x8e\x9b\x2b\x0c\x09\x17\xae\x8f\x8e\x9e\x3f\x25\x2e\x65\x5c\x28\x1a\x1e\xc2\x92\x8a\x92\x44\x0f\x0a\x14\xd6\x99\x97\xa6\x7c\x4e\xba\xad\xe5\x1d\x0f\x13\x49\x92\x89\x8e\xbe\x15\x0d\x16\x43\xa8\xa7\xc1\x66\xb5\x9d\x9a\xb6\x1b\x0c\x0d\x2b\x98\x8a\x8d\xab\x1f\x15\x1d\x3f\xc7\x52\x2e\x39\xaa\x93\x8f\xa3\x1e\x0b\x0b\x1e\x9f\x8d\x8f\xa7\x30\x23\x31\x7c\x4a\x24\x1a\x24\xac\x8e\x8b\x99\x28\x0c\x0a\x1a\xb0\x96\x98\xac\x4f\x53\xb7\xaf\x44\x19\x0f\x18\xba\x8e\x89\x93\x3f\x10\x0d\x1a\xd5\xa3\xa8\xca\xf9\xae\x9c\x9d\xec\x16\x0b\x10\x4e\x91\x89\x90\xc6\x1a\x14\x20\x55\xc3\x4a\x2f\x49\xa2\x91\x92\xb2\x17\x09\x0c\x2d\x99\x8d\x92\xb3\x29\x23\x36\xf2")); -snd($sock_b, $port_a, rtp(0, 4004, 8640, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4004, 8640, $ssrc, "\x3e\x20\x1b\x2d\xa0\x8d\x8c\xa1\x1c\x0a\x0c\x22\xa3\x94\x9a\xb5\x44\x5c\xb5\xb6\x32\x16\x0f\x1e\xa6\x8c\x8a\x99\x28\x0e\x0e\x20\xb7\xa1\xab\xd4\xdb\xaa\x9c\xa1\x38\x11\x0b\x15\xb5\x8d\x8a\x96\x3f\x16\x15\x26\xdd\xc2\x43\x31\xdf\x9d\x90\x96\x6d\x11\x09\x0f\x5a\x93\x8c\x97\xd2\x23\x23\x3b\xf6\x37\x1f\x1d\x40\x9a\x8c\x8e\xb2\x15\x09\x0e\x31\x9c\x93\x9c\xc2\x3e\x74\xb4\xbf\x29\x14\x11\x29\x9b\x8a\x8b\xa3\x1c\x0d\x0f\x2a\xab\x9f\xad\xe0\xcc\xa6\x9c\xa9\x28\x0e\x0c\x1c\xa2\x8b\x8b\x9c\x2a\x14\x17\x2c\xc6\xc4\x3e\x36\xbd\x99\x90\x9b\x30\x0d\x09\x15\xb3\x8f\x8d\x9b\x42\x1f\x25\x42\x70\x30\x1e\x1f\xcf\x95\x8b\x92\x58\x0f\x09\x12\x6f\x98\x93")); -snd($sock_b, $port_a, rtp(0, 4005, 8800, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4005, 8800, $ssrc, "\x9f\xe5\x3b\xe2\xb5\xd9\x21\x12\x14\x3e\x95\x89\x8d\xb6\x16\x0c\x13\x3a\xa4\x9f\xb1\xf1\xc0\xa3\x9d\xb4\x1e\x0d\x0d\x27\x99\x8a\x8c\xa7\x1f\x12\x19\x37\xbc\xc8\x3c\x3c\xaf\x97\x91\xa2\x21\x0b\x0a\x1c\xa2\x8d\x8e\xa2\x2f\x1e\x28\x4c\x5d\x2c\x1e\x25\xb0\x90\x8c\x98\x2c\x0c\x0a\x18\xb4\x94\x94\xa6\x4d\x3a\xd4\xb8\x4f\x1d\x11\x18\xc5\x8f\x89\x91\x4d\x10\x0c\x17\xec\x9f\xa0\xb8\xff\xba\xa1\x9f\xd3\x19\x0c\x0f\x3f\x92\x89\x8f\xbb\x19\x11\x1c\x48\xb8\xce\x3b\x4a\xa8\x95\x93\xaf\x19\x0a\x0c\x29\x99\x8c\x8f\xad\x27\x1d\x2b\x59\x4f\x29\x1e\x2d\xa5\x8e\x8d\x9f\x1e\x0b\x0b\x1e\xa4\x91\x96\xad\x3e\x3b\xcc\xbc\x3a\x1a\x12\x1e\xaa\x8d\x8a\x98\x2b")); -snd($sock_b, $port_a, rtp(0, 4006, 8960, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4006, 8960, $ssrc, "\x0e\x0c\x1d\xb8\x9d\xa2\xbe\xf9\xb4\xa0\xa3\x3f\x14\x0c\x14\xbd\x8e\x89\x93\x49\x15\x12\x1f\xe7\xb5\xd9\x3c\x7c\xa1\x93\x97\xd5\x13\x09\x0e\x45\x93\x8b\x93\xc4\x20\x1d\x2e\x6b\x46\x26\x1f\x3d\x9d\x8d\x8e\xae\x17\x09\x0d\x2c\x9c\x90\x98\xba\x36\x3d\xc7\xc4\x2e\x17\x13\x27\x9e\x8b\x8b\x9f\x1e\x0c\x0e\x25\xaa\x9c\xa5\xc8\xe8\xae\xa0\xaa\x2d\x10\x0c\x1b\xa6\x8c\x8a\x9a\x2c\x12\x13\x27\xc3\xb3\xed\x3e\xc8\x9d\x93\x9b\x38\x0f\x09\x13\xba\x8f\x8b\x98\x4a\x1d\x1e\x34\xf9\x3e\x24\x23\xea\x98\x8c\x92\xdf\x10\x09\x0f\x4d\x97\x90\x9c\xd2\x31\x3f\xc5\xd6\x28\x16\x16\x39\x97\x8a\x8d\xaf\x17\x0b\x10\x32\xa2\x9b\xa8\xd6\xd9\xac\xa1\xb3\x22\x0e\x0e")); -snd($sock_b, $port_a, rtp(0, 4007, 9120, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4007, 9120, $ssrc, "\x24\x9b\x8a\x8b\xa2\x1f\x10\x15\x2f\xb8\xb4\x68\x43\xb8\x9a\x94\xa1\x25\x0c\x0a\x1a\xa5\x8d\x8c\x9e\x30\x1b\x1f\x3c\xee\x38\x23\x28\xb8\x93\x8d\x97\x31\x0d\x09\x15\xb9\x93\x90\xa0\x4f\x2f\x46\xc4\x5e\x21\x15\x19\xd7\x91\x89\x90\x7b\x10\x0b\x14\x5b\x9d\x9c\xad\xed\xcd\xa9\xa3\xca\x1c\x0d\x10\x38\x94\x89\x8e\xb3\x19\x0f\x18\x3e\xb0\xb5\x59\x4d\xae\x98\x95\xad\x1c\x0b\x0c\x25\x9b\x8b\x8e\xa9\x26\x1a\x22\x46\xf5\x33\x23\x2e\xaa\x90\x8d\x9e\x21\x0b\x0a\x1c\xa6\x90\x92\xa8\x3b\x2e\x4d\xc7\x43\x1e\x15\x1e\xaf\x8e\x8a\x96\x2e\x0e\x0b\x1a\xbb\x9b\x9d\xb2\x68\xc5\xa8\xa7\x4c\x17\x0d\x14\xcb\x8f\x89\x91\x5e\x14\x0f\x1c\x6e\xad\xb8\x52\x68\xa8")); -snd($sock_b, $port_a, rtp(0, 4008, 9280, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4008, 9280, $ssrc, "\x97\x98\xc7\x16\x0a\x0e\x3a\x94\x8a\x90\xbb\x1e\x1a\x27\x56\x6f\x2f\x25\x3b\xa0\x8e\x8f\xaa\x19\x09\x0c\x28\x9c\x8f\x95\xb2\x31\x2e\x59\xcc\x37\x1b\x16\x26\xa1\x8c\x8b\x9d\x1f\x0c\x0c\x20\xab\x99\x9e\xbb\x5d\xbe\xa7\xac\x32\x13\x0d\x1a\xab\x8c\x89\x97\x2e\x10\x10\x21\xc3\xab\xbc\x4f\xd4\xa2\x96\x9c\x3f\x10\x0a\x12\xc4\x8f\x8a\x95\x57\x1b\x1a\x2b\xfd\x5d\x2d\x27\x62\x9b\x8e\x92\xc9\x12\x09\x0e\x3f\x97\x8e\x98\xc6\x2c\x2f\x6b\xd9\x2e\x1a\x18\x34\x9a\x8b\x8d\xab\x18\x0a\x0e\x2d\xa1\x98\xa1\xc7\x5b\xb9\xa7\xb4\x27\x10\x0e\x22\x9d\x8a\x8b\x9f\x20\x0e\x12\x2a\xb4\xaa\xc0\x50\xc0\x9e\x97\xa1\x2a\x0e\x0a\x19\xa8\x8c\x8b\x9b\x31\x18\x1b\x31")); -snd($sock_b, $port_a, rtp(0, 4009, 9440, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4009, 9440, $ssrc, "\xda\x50\x2c\x2b\xc0\x97\x8e\x97\x39\x0e\x09\x13\xbf\x92\x8e\x9c\x57\x29\x31\xef\x72\x28\x19\x1b\x6d\x94\x8a\x8f\xce\x11\x0a\x11\x48\x9c\x98\xa5\xdc\x5e\xb5\xa9\xc6\x1f\x0f\x10\x31\x96\x89\x8d\xad\x19\x0e\x15\x37\xac\xaa\xc8\x57\xb7\x9c\x98\xac\x1e\x0c\x0c\x21\x9c\x8b\x8d\xa4\x25\x17\x1d\x3b\xcf\x48\x2b\x30\xae\x93\x8e" . "\xff" x 80)); -# pause -snd($sock_b, $port_a, rtp(0, 4010, 9600, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4010, 9600, $ssrc, "\xff" x 160)); -snd($sock_b, $port_a, rtp(0, 4011, 9760, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4011, 9760, $ssrc, "\xff" x 160)); -snd($sock_b, $port_a, rtp(0, 4012, 9920, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4012, 9920, $ssrc, "\xff" x 160)); -snd($sock_b, $port_a, rtp(0, 4013, 10080, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4013, 10080, $ssrc, "\xff" x 160)); -snd($sock_b, $port_a, rtp(0, 4014, 10240, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4014, 10240, $ssrc, "\xff" x 80 . "\x00" x 80)); - - - - -# transcoding, no RFC payload type present - -($sock_a, $sock_b) = new_call([qw(198.51.100.1 6018)], [qw(198.51.100.3 6020)]); - -($port_a) = offer('transcoding, no RFC payload type present', - { ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'], - codec => { transcode => ['PCMA'] } }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < ft(), code => 'C', volume => 5, duration => 120 }); - -snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1002, 3320, $ssrc, "\xd5\xb9\xbe\x97\x05\x70\xea\x01\x3e\x31\x82\xa5\xb2\x63\x0f\x69\xc1\x0f\x3d\x06\xb3\xa4\x8a\x03\x35\x14\x75\x0e\x36\xcc\xb8\xa5\x9d\x36\x36\x68\x49\x0d\x0c\x81\xa5\xbf\x16\x3f\x37\x4f\xcf\x07\x13\xb4\xa5\xb4\x0a\x3b\x0b\xeb\xe9\x12\xc9\xb3\xb8\x92\x3c\x3a\x07\x87\x9c\x61\x93\xb2\xb3\x12\x25\x39\x76\x8b\x85\x5a\x85\xb3\x8e\x35\x24\x30\x85\xb1\x87\x57\x84\xb7\xeb\x3c\x24\x0d\xb4\xb2\x9b\x70\x98\x8c\x11\x3b\x38\x41\xbf\xb2\xeb\x15\x96\x9f\x0d\x3a\x30\x83\xba\xb1\x7b\x1b\xfa\xf2\x34\x39\x03\xb0\xa5\x88\x04\x03\x5f\x67\x37\x32\xdd\xb8\xba\x9d\x35\x0e\x71\x15\x37\x0a\x80\xa4\xbf\x15\x33\x09\x45\x15\x0b\x18\xb6\xa4\xb4\x08\x3f\x0d\xe5\x66")); -snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1003, 3480, $ssrc, "\x00\xcd\xbc\xba\x9c\x3d\x39\x1a\x9d\xd1\x1d\x98\xbe\xbd\x10\x3a\x3f\x73\x80\xe0\x64\x82\xbf\x8b\x35\x24\x31\x9f\x8b\x94\xdf\x8e\xb3\x96\x3c\x24\x02\x8b\xb7\x94\xf4\x8f\xb5\x10\x3a\x3b\x76\xb2\xb6\xe0\xd6\x80\x87\x09\x25\x33\x81\xb9\xb4\x74\x64\x9b\xe6\x31\x3a\x0d\xb1\xba\x8f\x1c\x11\x95\x6f\x32\x3f\x5e\xb8\xbb\x92\x0d\x1a\xf0\x19\x32\x37\x83\xa4\xbc\x6d\x37\x07\xd4\x04\x31\x07\xb1\xa4\xb4\x0c\x33\x04\xc5\x05\x0b\xd8\xbe\xa5\x9e\x30\x3d\x1d\xe0\x1d\x06\x84\xbb\xbf\x16\x38\x33\x73\x92\x6f\x15\x88\xbb\xb5\x35\x25\x37\x91\x86\x46\xda\xb7\xbf\x92\x3c\x25\x03\x8d\x8c\xf4\xef\xb7\xb6\x10\x25\x3b\x7f\xb6\x89\xf6\x95\xb5\x82\x0b\x24\x33\x84")); -snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1004, 3640, $ssrc, "\xbd\x8e\x5a\xec\x8c\xee\x33\x24\x0c\xb6\xbe\x80\x6b\xf5\x85\x6a\x3f\x39\x4a\xbe\xbe\x90\x05\x7f\x95\x06\x3e\x31\x80\xa5\xbd\x64\x0f\x6b\xcc\x0c\x3d\x00\xb0\xa4\xb5\x00\x34\x16\x4e\x0e\x36\x57\xb9\xa5\x99\x36\x36\x6a\x43\x0d\x0f\x86\xa5\xbe\x15\x3f\x36\x77\xf5\x07\x12\xb4\xa5\xb4\x0b\x3b\x0a\xee\xeb\x13\xd8\xb0\xb8\x9f\x3c\x3a\x01\x87\x9f\x66\x91\xb2\xb3\x11\x25\x39\x7a\x8b\x84\x5b\x9a\xb0\x89\x0a\x24\x33\x9b\xb1\x87\x54\x85\xb7\x97\x3d\x24\x0c\xb4\xb2\x9a\x73\x99\x8c\x14\x38\x3b\x7c\xbc\xbd\x94\x15\x97\x9e\x02\x3a\x33\x81\xba\xb0\x73\x1a\xfe\xf9\x35\x39\x02\xb1\xa4\x8a\x05\x03\x44\x7a\x37\x32\x40\xb8\xa5\x99\x0a\x0e\x72\x6b\x34\x35")); -snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1005, 3800, $ssrc, "\x81\xa4\xbe\x6c\x33\x08\x43\x68\x08\x1a\xb7\xa4\xb7\x0e\x3f\x0c\xfb\x65\x00\xd1\xbd\xba\x98\x32\x39\x04\x92\xdb\x1d\x9e\xbe\xbc\x17\x3a\x3f\x65\x80\xed\x67\x83\xbf\xb5\x0a\x24\x30\x9d\x8b\x97\xd0\x8f\xb3\x93\x3c\x24\x0c\x88\xb7\x96\xc9\x8c\xb5\x17\x3a\x3a\x64\xb3\xb6\xed\x56\x80\x86\x0f\x25\x32\x87\xb9\xb7\x4d\x66\x98\xe3\x36\x3a\x0c\xb1\xba\x8e\x1d\x10\xea\x63\x33\x3f\x70\xb9\xbb\x9f\x0d\x05\xf1\x1f\x33\x36\x81\xa4\xbf\x67\x34\x06\xd5\x05\x31\x06\xb6\xa4\xb7\x0d\x33\x07\xc5\x1a\x0a\x5f\xbe\xa5\x9a\x30\x3d\x1f\xe0\x12\x06\x9a\xbb\xbf\x6b\x39\x32\x7b\x9d\x62\x14\x89\xbb\xb4\x0b\x25\x36\x97\x86\x5e\xd1\xb4\xbf\x9e\x3c\x24\x0d\x82\x8c")); -snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1006, 3960, $ssrc, "\xf0\xe2\xb7\xb1\x14\x3a\x3b\x61\xb6\x88\xf3\xeb\xb5\x8d\x09\x24\x32\x85\xbd\x89\x5c\xe2\x8c\x95\x30\x24\x0e\xb7\xb9\x83\x68\xc3\x85\x6e\x3f\x38\x7a\xbe\xb9\x92\x05\x7a\x95\x07\x3e\x30\x86\xa5\xbd\x7c\x0f\x15\xcb\x0d\x3d\x03\xb1\xa4\xb4\x01\x34\x11\x40\x0f\x36\x48\xb9\xa5\x85\x37\x36\x14\x45\x02\x0f\x84\xa5\xbe\x6d\x3c\x36\x7d\xf1\x04\x1c\xb5\xa5\xb7\x09\x3b\x35\xed\xea\x13\x57\xb0\xb8\x9b\x3d\x3a\x00\x84\x9e\x66\x97\xb2\xb2\x15\x3a\x38\x60\x8b\x87\x58\x98\xb0\x88\x08\x24\x32\x9e\xb1\x86\x54\x9a\xb7\x90\x32\x24\x0e\xb5\xb2\x84\x73\x9f\x8c\x68\x38\x3b\x61\xbc\xbd\x96\x14\x94\x99\x03\x3b\x32\x87\xba\xb3\x48\x1a\xf2\xe5\x0a\x39\x0c\xb1")); -snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1007, 4120, $ssrc, "\xa4\xb5\x1a\x02\x4c\x7f\x37\x32\x7c\xb9\xa5\x9a\x0a\x09\x7e\x6e\x34\x35\x87\xa5\xbe\x67\x33\x0b\x48\x6e\x08\x05\xb7\xa4\xb6\x0f\x3f\x0e\xfe\x79\x00\x5a\xbd\xa5\x85\x32\x39\x07\x92\xcd\x1d\x9d\xbe\xbc\x69\x3b\x3e\x60\x80\xef\x66\x80\xbf\xb5\x08\x24\x30\x90\x8b\x91\xd5\x8c\xb3\x9f\x3d\x24\x0e\x89\xb7\x91\xc2\x8c\xb5\x68\x3b\x3a\x6d\xb3\xb1\xee\x5c\x81\x81\x0c\x25\x3d\x85\xb9\xb7\x58\x60\x99\xef\x37\x3a\x0e\xb6\xba\x89\x12\x13\xeb\x67\x33\x3e\x67\xb9\xba\x98\x02\x05\xf7\x1d\x33\x36\x87\xa4\xbe\x7c\x34\x01\x54\x1a\x31\x01\xb6\xa4\xb6\x03\x33\x06\xda\x18\x0a\x75\xbf\xa5\x84\x31\x3d\x19\xe0\x10\x01\x99\xbb\xbe\x62\x39\x3d\x66\x9d\x60\x17")); -# pause -snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1008, 4280, $ssrc, "\xd5" x 160)); -snd($sock_a, $port_b, rtp(0, 1009, 4440, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1009, 4440, $ssrc, "\xd5" x 160)); -snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1010, 4600, $ssrc, "\xd5" x 160)); -snd($sock_a, $port_b, rtp(0, 1011, 4760, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1011, 4760, $ssrc, "\xd5" x 160)); -snd($sock_a, $port_b, rtp(0, 1012, 4920, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1012, 4920, $ssrc, "\xd5" x 160)); -snd($sock_a, $port_b, rtp(0, 1013, 5080, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(8, 1013, 5080, $ssrc, "\x2a" x 160)); - - - - -snd($sock_b, $port_a, rtp(8, 4000, 8000, 0x6543, "\x2a" x 160)); -($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 8000, -1, "\x00" x 160)); -snd($sock_b, $port_a, rtp(8, 4001, 8160, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4001, 8160, $ssrc, "\x00" x 160)); - -$resp = rtpe_req('play DTMF', 'inject DTMF towards A', - { 'from-tag' => tt(), code => '4', volume => 3, duration => 150 }); - -snd($sock_b, $port_a, rtp(8, 4002, 8320, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4002, 8320, $ssrc, "\xff\x90\x8a\x93\xd9\x1b\x18\x27\x65\xe5\x33\x29\x4c\x9e\x8f\x91\xb8\x15\x09\x0d\x32\x98\x8e\x96\xbb\x2c\x2b\x4c\xd8\x34\x1c\x18\x2e\x9d\x8c\x8c\xa5\x1a\x0b\x0d\x27\xa3\x97\x9e\xbd\x4f\xc4\xaa\xb2\x2c\x12\x0e\x1e\xa1\x8b\x8a\x9c\x25\x0e\x10\x25\xb7\xa7\xb7\x5e\xcb\xa2\x98\x9f\x30\x0f\x0a\x16\xae\x8d\x8a\x98\x3a\x18\x19\x2c\xdd\xfd\x30\x2b\xce\x99\x8e\x95\x4c\x0f\x09\x10\xdf\x93\x8e\x9a\xec\x28\x2c\x56\xee\x2d\x1a\x1a\x48\x97\x8b\x8e\xba\x14\x0a\x0f\x39\x9d\x96\xa1\xcd\x4e\xbe\xab\xbe\x23\x10\x10\x2b\x99\x8a\x8c\xa7\x1b\x0d\x12\x2f\xad\xa7\xbc\x5e\xbd\x9f\x99\xa8\x23\x0d\x0b\x1d\x9f\x8b\x8c\x9f\x29\x16\x1b\x34\xcd\x60\x2f\x2f\xb6\x96")); -snd($sock_b, $port_a, rtp(8, 4003, 8480, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4003, 8480, $ssrc, "\x8e\x9b\x2b\x0c\x09\x17\xae\x8f\x8e\x9e\x3f\x25\x2e\x65\x5c\x28\x1a\x1e\xc2\x92\x8a\x92\x44\x0f\x0a\x14\xd6\x99\x97\xa6\x7c\x4e\xba\xad\xe5\x1d\x0f\x13\x49\x92\x89\x8e\xbe\x15\x0d\x16\x43\xa8\xa7\xc1\x66\xb5\x9d\x9a\xb6\x1b\x0c\x0d\x2b\x98\x8a\x8d\xab\x1f\x15\x1d\x3f\xc7\x52\x2e\x39\xaa\x93\x8f\xa3\x1e\x0b\x0b\x1e\x9f\x8d\x8f\xa7\x30\x23\x31\x7c\x4a\x24\x1a\x24\xac\x8e\x8b\x99\x28\x0c\x0a\x1a\xb0\x96\x98\xac\x4f\x53\xb7\xaf\x44\x19\x0f\x18\xba\x8e\x89\x93\x3f\x10\x0d\x1a\xd5\xa3\xa8\xca\xf9\xae\x9c\x9d\xec\x16\x0b\x10\x4e\x91\x89\x90\xc6\x1a\x14\x20\x55\xc3\x4a\x2f\x49\xa2\x91\x92\xb2\x17\x09\x0c\x2d\x99\x8d\x92\xb3\x29\x23\x36\xf2")); -snd($sock_b, $port_a, rtp(8, 4004, 8640, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4004, 8640, $ssrc, "\x3e\x20\x1b\x2d\xa0\x8d\x8c\xa1\x1c\x0a\x0c\x22\xa3\x94\x9a\xb5\x44\x5c\xb5\xb6\x32\x16\x0f\x1e\xa6\x8c\x8a\x99\x28\x0e\x0e\x20\xb7\xa1\xab\xd4\xdb\xaa\x9c\xa1\x38\x11\x0b\x15\xb5\x8d\x8a\x96\x3f\x16\x15\x26\xdd\xc2\x43\x31\xdf\x9d\x90\x96\x6d\x11\x09\x0f\x5a\x93\x8c\x97\xd2\x23\x23\x3b\xf6\x37\x1f\x1d\x40\x9a\x8c\x8e\xb2\x15\x09\x0e\x31\x9c\x93\x9c\xc2\x3e\x74\xb4\xbf\x29\x14\x11\x29\x9b\x8a\x8b\xa3\x1c\x0d\x0f\x2a\xab\x9f\xad\xe0\xcc\xa6\x9c\xa9\x28\x0e\x0c\x1c\xa2\x8b\x8b\x9c\x2a\x14\x17\x2c\xc6\xc4\x3e\x36\xbd\x99\x90\x9b\x30\x0d\x09\x15\xb3\x8f\x8d\x9b\x42\x1f\x25\x42\x70\x30\x1e\x1f\xcf\x95\x8b\x92\x58\x0f\x09\x12\x6f\x98\x93")); -snd($sock_b, $port_a, rtp(8, 4005, 8800, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4005, 8800, $ssrc, "\x9f\xe5\x3b\xe2\xb5\xd9\x21\x12\x14\x3e\x95\x89\x8d\xb6\x16\x0c\x13\x3a\xa4\x9f\xb1\xf1\xc0\xa3\x9d\xb4\x1e\x0d\x0d\x27\x99\x8a\x8c\xa7\x1f\x12\x19\x37\xbc\xc8\x3c\x3c\xaf\x97\x91\xa2\x21\x0b\x0a\x1c\xa2\x8d\x8e\xa2\x2f\x1e\x28\x4c\x5d\x2c\x1e\x25\xb0\x90\x8c\x98\x2c\x0c\x0a\x18\xb4\x94\x94\xa6\x4d\x3a\xd4\xb8\x4f\x1d\x11\x18\xc5\x8f\x89\x91\x4d\x10\x0c\x17\xec\x9f\xa0\xb8\xff\xba\xa1\x9f\xd3\x19\x0c\x0f\x3f\x92\x89\x8f\xbb\x19\x11\x1c\x48\xb8\xce\x3b\x4a\xa8\x95\x93\xaf\x19\x0a\x0c\x29\x99\x8c\x8f\xad\x27\x1d\x2b\x59\x4f\x29\x1e\x2d\xa5\x8e\x8d\x9f\x1e\x0b\x0b\x1e\xa4\x91\x96\xad\x3e\x3b\xcc\xbc\x3a\x1a\x12\x1e\xaa\x8d\x8a\x98\x2b")); -snd($sock_b, $port_a, rtp(8, 4006, 8960, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4006, 8960, $ssrc, "\x0e\x0c\x1d\xb8\x9d\xa2\xbe\xf9\xb4\xa0\xa3\x3f\x14\x0c\x14\xbd\x8e\x89\x93\x49\x15\x12\x1f\xe7\xb5\xd9\x3c\x7c\xa1\x93\x97\xd5\x13\x09\x0e\x45\x93\x8b\x93\xc4\x20\x1d\x2e\x6b\x46\x26\x1f\x3d\x9d\x8d\x8e\xae\x17\x09\x0d\x2c\x9c\x90\x98\xba\x36\x3d\xc7\xc4\x2e\x17\x13\x27\x9e\x8b\x8b\x9f\x1e\x0c\x0e\x25\xaa\x9c\xa5\xc8\xe8\xae\xa0\xaa\x2d\x10\x0c\x1b\xa6\x8c\x8a\x9a\x2c\x12\x13\x27\xc3\xb3\xed\x3e\xc8\x9d\x93\x9b\x38\x0f\x09\x13\xba\x8f\x8b\x98\x4a\x1d\x1e\x34\xf9\x3e\x24\x23\xea\x98\x8c\x92\xdf\x10\x09\x0f\x4d\x97\x90\x9c\xd2\x31\x3f\xc5\xd6\x28\x16\x16\x39\x97\x8a\x8d\xaf\x17\x0b\x10\x32\xa2\x9b\xa8\xd6\xd9\xac\xa1\xb3\x22\x0e\x0e")); -snd($sock_b, $port_a, rtp(8, 4007, 9120, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4007, 9120, $ssrc, "\x24\x9b\x8a\x8b\xa2\x1f\x10\x15\x2f\xb8\xb4\x68\x43\xb8\x9a\x94\xa1\x25\x0c\x0a\x1a\xa5\x8d\x8c\x9e\x30\x1b\x1f\x3c\xee\x38\x23\x28\xb8\x93\x8d\x97\x31\x0d\x09\x15\xb9\x93\x90\xa0\x4f\x2f\x46\xc4\x5e\x21\x15\x19\xd7\x91\x89\x90\x7b\x10\x0b\x14\x5b\x9d\x9c\xad\xed\xcd\xa9\xa3\xca\x1c\x0d\x10\x38\x94\x89\x8e\xb3\x19\x0f\x18\x3e\xb0\xb5\x59\x4d\xae\x98\x95\xad\x1c\x0b\x0c\x25\x9b\x8b\x8e\xa9\x26\x1a\x22\x46\xf5\x33\x23\x2e\xaa\x90\x8d\x9e\x21\x0b\x0a\x1c\xa6\x90\x92\xa8\x3b\x2e\x4d\xc7\x43\x1e\x15\x1e\xaf\x8e\x8a\x96\x2e\x0e\x0b\x1a\xbb\x9b\x9d\xb2\x68\xc5\xa8\xa7\x4c\x17\x0d\x14\xcb\x8f\x89\x91\x5e\x14\x0f\x1c\x6e\xad\xb8\x52\x68\xa8")); -snd($sock_b, $port_a, rtp(8, 4008, 9280, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4008, 9280, $ssrc, "\x97\x98\xc7\x16\x0a\x0e\x3a\x94\x8a\x90\xbb\x1e\x1a\x27\x56\x6f\x2f\x25\x3b\xa0\x8e\x8f\xaa\x19\x09\x0c\x28\x9c\x8f\x95\xb2\x31\x2e\x59\xcc\x37\x1b\x16\x26\xa1\x8c\x8b\x9d\x1f\x0c\x0c\x20\xab\x99\x9e\xbb\x5d\xbe\xa7\xac\x32\x13\x0d\x1a\xab\x8c\x89\x97\x2e\x10\x10\x21\xc3\xab\xbc\x4f\xd4\xa2\x96\x9c\x3f\x10\x0a\x12\xc4\x8f\x8a\x95\x57\x1b\x1a\x2b\xfd\x5d\x2d\x27\x62\x9b\x8e\x92\xc9\x12\x09\x0e\x3f\x97\x8e\x98\xc6\x2c\x2f\x6b\xd9\x2e\x1a\x18\x34\x9a\x8b\x8d\xab\x18\x0a\x0e\x2d\xa1\x98\xa1\xc7\x5b\xb9\xa7\xb4\x27\x10\x0e\x22\x9d\x8a\x8b\x9f\x20\x0e\x12\x2a\xb4\xaa\xc0\x50\xc0\x9e\x97\xa1\x2a\x0e\x0a\x19\xa8\x8c\x8b\x9b\x31\x18\x1b\x31")); -snd($sock_b, $port_a, rtp(8, 4009, 9440, 0x6543, "\x2a" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4009, 9440, $ssrc, "\xda\x50\x2c\x2b\xc0\x97\x8e\x97\x39\x0e\x09\x13\xbf\x92\x8e\x9c\x57\x29\x31\xef\x72\x28\x19\x1b\x6d\x94\x8a\x8f\xce\x11\x0a\x11\x48\x9c\x98\xa5\xdc\x5e\xb5\xa9\xc6\x1f\x0f\x10\x31\x96\x89\x8d\xad\x19\x0e\x15\x37\xac\xaa\xc8\x57\xb7\x9c\x98\xac\x1e\x0c\x0c\x21\x9c\x8b\x8d\xa4\x25\x17\x1d\x3b\xcf\x48\x2b\x30\xae\x93\x8e" . "\xff" x 80)); -# pause -snd($sock_b, $port_a, rtp(0, 4010, 9600, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4010, 9600, $ssrc, "\xff" x 160)); -snd($sock_b, $port_a, rtp(0, 4011, 9760, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4011, 9760, $ssrc, "\xff" x 160)); -snd($sock_b, $port_a, rtp(0, 4012, 9920, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4012, 9920, $ssrc, "\xff" x 160)); -snd($sock_b, $port_a, rtp(0, 4013, 10080, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4013, 10080, $ssrc, "\xff" x 160)); -snd($sock_b, $port_a, rtp(0, 4014, 10240, 0x6543, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4014, 10240, $ssrc, "\xff" x 80 . "\x00" x 80)); - - - - -# multiple consecutive DTMF events - -($sock_a, $sock_b) = new_call([qw(198.51.100.1 6024)], [qw(198.51.100.3 6026)]); - -($port_a) = offer('multiple consecutive DTMF events', - { ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < ft(), code => 'C', volume => 5, duration => 100 }); -$resp = rtpe_req('play DTMF', 'inject DTMF towards B', - { 'from-tag' => ft(), code => '4', volume => 5, duration => 100 }); - -snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1002, 3320, $ssrc, "\xff\x93\x94\xbc\x2e\x56\xbf\x2b\x13\x1b\xa7\x8e\x98\x47\x25\x41\xe2\x24\x16\x2b\x99\x8e\x9f\x28\x1e\x3d\x5b\x23\x1c\xdf\x92\x8f\xb6\x1c\x1c\x40\x5d\x26\x25\xaa\x8f\x95\x3b\x15\x1d\x5e\xde\x2c\x38\x9d\x8f\x9e\x1f\x11\x20\xc0\xc1\x37\xdd\x99\x92\xb7\x15\x10\x2c\xac\xb5\x49\xb8\x97\x99\x37\x0f\x13\x58\xa0\xae\x67\xae\x99\xa4\x1f\x0d\x1a\xae\x9b\xad\x7b\xad\x9d\xbf\x16\x0e\x27\x9d\x98\xb0\x55\xb1\xa6\x3a\x11\x11\x63\x95\x98\xbf\x3e\xbb\xb4\x26\x10\x1a\xa9\x90\x9a\x4e\x30\xce\xd4\x1e\x12\x29\x99\x8e\xa1\x2d\x29\x6d\x4b\x1c\x18\xef\x91\x8f\xb6\x1f\x24\x57\x3e\x1d\x20\xa9\x8e\x95\x3e\x19\x23\x67\x3e\x21\x31\x9c\x8e\x9e\x22\x14\x26\xcd\x4a")); -snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1003, 3480, $ssrc, "\x2a\xdf\x96\x90\xb5\x17\x13\x2f\xb6\xf5\x36\xb1\x93\x96\x39\x10\x15\x55\xaa\xc8\x4c\xa7\x95\xa0\x1f\x0e\x1b\xb4\xa1\xbd\xed\xa4\x99\xbb\x15\x0e\x27\xa0\x9d\xbd\xda\xa4\x9f\x39\x10\x11\x58\x98\x9c\xc8\xf9\xa9\xac\x23\x0e\x19\xab\x92\x9e\x59\x4c\xb0\xca\x1b\x10\x27\x9a\x90\xa5\x35\x3a\xbe\x43\x18\x15\x6c\x92\x91\xb7\x26\x30\xd6\x32\x18\x1d\xa9\x8e\x96\x44\x1d\x2d\xfc\x2e\x1b\x2d\x9a\x8d\x9e\x25\x19\x2d\xe7\x2f\x20\xea\x94\x8f\xb3\x19\x17\x36\xc8\x36\x2c\xae\x90\x95\x3b\x12\x18\x55\xb7\x43\x3e\xa1\x91\x9e\x1f\x0f\x1d\xba\xac\x64\xe8\x9d\x95\xb7\x15\x0e\x29\xa6\xa6\xda\xc3\x9d\x9b\x39\x0f\x11\x51\x9c\xa2\xd8\xbe\x9f\xa7\x21\x0e\x18\xad")); -snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1004, 3640, $ssrc, "\x96\xa3\x68\xc4\xa5\xc2\x19\x0e\x26\x9c\x93\xa9\x3f\xdb\xae\x3e\x14\x12\x5b\x93\x93\xb9\x2e\x51\xbe\x2c\x14\x1b\xa9\x8f\x97\x4c\x25\x3f\xde\x25\x16\x2a\x9a\x8e\x9e\x29\x1e\x3b\x5e\x24\x1b\x7b\x92\x8f\xb2\x1c\x1c\x3e\x61\x27\x25\xac\x8f\x94\x3e\x15\x1c\x59\xdb\x2d\x37\x9e\x8f\x9d\x20\x11\x1f\xc2\xbf\x38\xea\x99\x92\xb4\x16\x10\x2b\xad\xb4\x49\xba\x98\x98\x3a\x0f\x12\x4e\xa1\xad\x68\xaf\x99\xa3\x20\x0d\x19\xb0\x9b\xac\x7b\xae\x9d\xbc\x17\x0e\x25\x9e\x98\xaf\x55\xb2\xa6\x3d\x12\x11\x52\x96\x97\xbd\x3e\xbc\xb3\x28\x10\x19\xab\x90\x9a\x54\x2f\xd0\xcf\x1f\x12\x27\x9a\x8e\xa0\x2e\x28\x66\x4e\x1d\x18\x62\x92\x8f\xb2\x20\x23\x53\x3f\x1d\x1f")); -snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1005, 3800, $ssrc, "\xab\x8e\x94\x44\x19\x22\x61\x40\x21\x2f\x9c\x8e\x9d\x23\x14\x25\xce\x4d\x2a\xf7\x96\x8f\xb1\x18\x13\x2e\xb7\xe8\x36\xb3\x94\x96\x3c\x10\x15\x4d\xaa\xc5\x4b\xa8\x95\x9f\x20\x0e\x1a\xb6\xa0\xbc\xf5\xa4\x99\xb8\x16\x0e\x26\xa1\x9d\xbb\xdd\xa5\x9f\x3c\x10\x10\x4c\x99\x9b\xc5\x78\xaa\xac\x24\x0f\x18\xac\x93\x9d\x5f\x4a\xb1\xc7\x1c\x0f\x25\x9b\x90\xa3\x36\x39\xbf\x47\x18\x14\x56\x92\x90\xb4\x27\x2f\xd7\x34\x18\x1c\xab\x8e\x95\x4b\x1d\x2c\xfe\x2f\x1b\x2c\x9b\x8d\x9d\x27\x19\x2c\xe7\x30\x20\x6d\x94\x8f\xaf\x1a\x17\x34\xc8\x37\x2b\xaf\x91\x94\x3f\x12\x18\x4e\xb6\x45\x3d\xa3\x91\x9e\x20\x0f\x1c\xbc\xab\x6c\xf5\x9e\x95\xb3\x16\x0e\x27\xa7\xa5")); -snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1006, 3960, $ssrc, "\xd6\xc6\x9d\x9b\x3d\x0f\x11\x49\x9c\xa1\xd4\xbf\x9f\xa6\x22\x0e\x18\xaf\x96\xa2\x6e\xc6\xa5\xbe\x19\x0e\x24\x9d\x93\xa8\x40\xe1\xae\x42\x15\x12\x4e\x94\x93\xb7\x2e\x4e\xbe\x2d\x14\x1a\xab\x8f\x97\x52\x25\x3e\xdc\x26\x16\x28\x9b\x8e\x9e\x2b\x1e\x3a\x61\x25\x1b\x5d\x93\x8f\xaf\x1d\x1c\x3d\x67\x27\x24\xad\x8f\x93\x45\x15\x1c\x53\xd7\x2d\x35\x9f\x8f\x9c\x22\x11\x1f\xc5\xbe\x38\x7a\x9a\x91\xb0\x17\x10\x29\xad\xb3\x4a\xbc\x98\x98\x3e\x10\x12\x48\xa1\xad\x6a\xb1\x9a\xa1\x21\x0e\x18\xb3\x9b\xab\x7d\xaf\x9d\xb9\x18\x0e\x23\x9f\x97\xae\x55\xb4\xa5\x40\x12\x10\x49\x96\x97\xbb\x3d\xbd\xb2\x29\x10\x18\xac\x90\x99\x5d\x2f\xd4\xcd\x1f\x12\x25\x9b")); -# pause -snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1007, 4120, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1008, 4280, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1009, 4440, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1009, 4440, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1010, 4600, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1011, 4760, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1011, 4760, $ssrc, "\xff" x 160)); -# next event -snd($sock_a, $port_b, rtp(0, 1012, 4920, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1012, 4920, $ssrc, "\xff\x96\x8e\x99\xdd\x1f\x1d\x2c\x69\xe9\x39\x2d\x50\xa3\x95\x97\xbd\x1a\x0e\x12\x38\x9d\x93\x9b\xbf\x30\x2f\x4f\xdc\x39\x20\x1d\x33\xa2\x90\x91\xaa\x1f\x0f\x12\x2c\xa9\x9c\xa3\xc2\x55\xc9\xaf\xb8\x30\x18\x14\x24\xa7\x8f\x8e\xa0\x2a\x14\x16\x2a\xbc\xac\xbc\x61\xcf\xa8\x9d\xa6\x36\x15\x0f\x1b\xb4\x92\x8f\x9d\x3e\x1d\x1e\x31\xe0\xfe\x36\x30\xd3\x9e\x94\x9b\x50\x15\x0d\x17\xe3\x99\x93\x9e\xee\x2c\x30\x5b\xf0\x32\x1f\x1f\x4c\x9c\x8f\x94\xbe\x19\x0e\x15\x3d\xa2\x9b\xa7\xd2\x52\xc3\xaf\xc4\x29\x16\x16\x2f\x9e\x8e\x90\xac\x20\x13\x18\x34\xb2\xac\xc0\x61\xc2\xa5\x9d\xad\x29\x12\x10\x23\xa5\x8f\x90\xa5\x2d\x1b\x1f\x39\xd1\x65\x34\x36\xbb\x9b")); -snd($sock_a, $port_b, rtp(0, 1013, 5080, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1013, 5080, $ssrc, "\x94\x9f\x2f\x11\x0e\x1c\xb3\x95\x94\xa4\x45\x2a\x33\x69\x60\x2d\x1e\x23\xc7\x98\x8f\x98\x49\x15\x0e\x1a\xda\x9d\x9c\xab\x7d\x53\xbe\xb1\xe8\x22\x15\x19\x4d\x98\x8d\x94\xc3\x1b\x12\x1b\x48\xac\xac\xc7\x69\xba\xa2\x9f\xbb\x1f\x10\x12\x2f\x9c\x8e\x93\xb0\x25\x1a\x22\x44\xcb\x57\x34\x3d\xae\x99\x96\xa9\x23\x0f\x0f\x24\xa6\x93\x96\xac\x36\x29\x37\x7c\x4e\x29\x1e\x29\xb0\x94\x8f\x9e\x2d\x11\x0f\x1f\xb6\x9b\x9d\xb0\x55\x58\xbc\xb5\x49\x1e\x15\x1d\xbe\x94\x8e\x99\x45\x17\x12\x1f\xd9\xa9\xad\xce\xfa\xb3\xa0\xa2\xef\x1b\x0f\x16\x52\x97\x8e\x96\xcb\x1e\x1a\x26\x59\xc8\x4e\x35\x4d\xa8\x97\x98\xb8\x1c\x0e\x11\x31\x9d\x91\x98\xb9\x2d\x29\x3b\xf5")); -snd($sock_a, $port_b, rtp(0, 1014, 5240, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1014, 5240, $ssrc, "\x43\x27\x1f\x32\xa6\x92\x91\xa7\x21\x0f\x10\x28\xa9\x99\x9e\xba\x49\x60\xba\xbb\x38\x1b\x16\x23\xab\x90\x8e\x9e\x2d\x14\x13\x26\xbc\xa7\xaf\xd8\xde\xae\xa0\xa7\x3d\x17\x0f\x1a\xba\x93\x8e\x9b\x44\x1b\x1b\x2b\xe0\xc8\x48\x37\xe4\xa2\x96\x9b\x6f\x17\x0e\x15\x5d\x99\x91\x9c\xd7\x29\x29\x3f\xf8\x3c\x24\x21\x46\x9e\x90\x94\xb8\x1a\x0e\x14\x37\xa1\x99\xa1\xc8\x43\x76\xba\xc5\x2d\x19\x17\x2d\xa0\x8f\x8f\xa8\x21\x11\x16\x2e\xaf\xa6\xb2\xe5\xcf\xab\xa0\xad\x2d\x14\x10\x20\xa8\x90\x8f\xa1\x2e\x19\x1c\x31\xcb\xc9\x44\x3b\xc2\x9e\x96\x9f\x36\x13\x0e\x1a\xb8\x95\x92\xa0\x48\x26\x2a\x48\x73\x36\x23\x25\xd4\x9a\x90\x98\x5c\x15\x0e\x18\x72\x9c\x99")); -snd($sock_a, $port_b, rtp(0, 1015, 5400, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1015, 5400, $ssrc, "\xa6\xe8\x3f\xe7\xba\xdd\x27\x18\x1a\x43\x9a\x8e\x93\xbb\x1b\x10\x19\x3e\xaa\xa5\xb7\xf4\xc6\xa9\xa2\xba\x23\x12\x12\x2c\x9e\x8e\x91\xac\x25\x18\x1e\x3c\xc1\xcd\x41\x40\xb5\x9c\x97\xa8\x27\x10\x0f\x21\xa8\x92\x93\xa8\x35\x24\x2c\x50\x61\x30\x23\x2b\xb7\x97\x90\x9d\x31\x11\x0e\x1c\xb9\x9a\x9a\xab\x52\x3f\xd9\xbc\x54\x22\x18\x1d\xca\x96\x8e\x97\x52\x17\x10\x1c\xef\xa5\xa6\xbc\xff\xbe\xa7\xa5\xd8\x1d\x10\x16\x45\x98\x8e\x95\xbf\x1e\x17\x20\x4d\xbc\xd2\x3f\x4e\xad\x9a\x99\xb4\x1e\x0e\x10\x2d\x9e\x90\x96\xb2\x2c\x22\x2f\x5c\x54\x2d\x24\x32\xaa\x94\x91\xa5\x24\x0f\x0f\x24\xaa\x98\x9b\xb2\x43\x3f\xcf\xc0\x3e\x1e\x18\x23\xaf\x92\x8e\x9c\x2f")); -snd($sock_a, $port_b, rtp(0, 1016, 5560, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1016, 5560, $ssrc, "\x13\x11\x21\xbd\xa2\xa8\xc3\xfa\xb9\xa6\xa9\x45\x19\x10\x1a\xc2\x94\x8e\x99\x4e\x1a\x18\x26\xeb\xba\xdd\x40\x7d\xa7\x99\x9c\xda\x19\x0e\x14\x4a\x99\x90\x99\xc9\x26\x23\x34\x6d\x4b\x2b\x25\x41\xa1\x92\x94\xb3\x1c\x0e\x12\x30\xa0\x96\x9d\xbe\x3b\x41\xcc\xc9\x34\x1c\x19\x2c\xa3\x8f\x8f\xa5\x23\x10\x13\x2a\xaf\xa0\xaa\xcd\xeb\xb4\xa6\xae\x31\x16\x11\x1f\xab\x90\x8e\x9e\x30\x18\x19\x2c\xc8\xb9\xf0\x43\xcc\xa2\x99\x9f\x3c\x14\x0e\x19\xbe\x95\x90\x9d\x4e\x22\x24\x3a\xfa\x43\x2a\x28\xec\x9d\x91\x98\xe4\x16\x0d\x16\x51\x9c\x96\xa0\xd7\x37\x45\xca\xda\x2c\x1b\x1b\x3d\x9c\x8e\x92\xb4\x1c\x0f\x16\x38\xa8\xa0\xad\xda\xdd\xb0\xa7\xb9\x28\x14\x13")); -# pause -snd($sock_a, $port_b, rtp(0, 1017, 5720, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1017, 5720, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1018, 5880, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1018, 5880, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1019, 6040, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1019, 6040, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1020, 6200, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1020, 6200, $ssrc, "\xff" x 160)); -snd($sock_a, $port_b, rtp(0, 1021, 6360, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1021, 6360, $ssrc, "\xff" x 160)); -# resume -snd($sock_a, $port_b, rtp(0, 1022, 6520, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1022, 6520, $ssrc, "\x00" x 160)); - - - - -# RFC payload type present - -($sock_a, $sock_b) = new_call([qw(198.51.100.1 6010)], [qw(198.51.100.3 6012)]); - -($port_a) = offer('multi- no transcoding, RFC payload type present', - { ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'force-relay', flags => [qw(SDES-off)], 'transport-protocol' => 'UDP/TLS/RTP/SAVPF', + 'rtcp-mux' => [qw(accept offer)], 'via-branch' => 'z9hG4bK9463.af303705.113', + }, < ft(), code => '0', volume => 10, duration => 100 }); -$resp = rtpe_req('play DTMF', 'inject DTMF towards B', - { 'from-tag' => ft(), code => '1', volume => 6, duration => 100 }); - -snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96 | 0x80, 1002, 3320, $ssrc, "\x00\x0a\x00\xa0")); -snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1003, 3320, $ssrc, "\x00\x0a\x01\x40")); -snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1004, 3320, $ssrc, "\x00\x0a\x01\xe0")); -snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1005, 3320, $ssrc, "\x00\x0a\x02\x80")); -snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1006, 3320, $ssrc, "\x00\x0a\x03\x20")); -snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1007, 3320, $ssrc, "\x00\x8a\x03\xc0")); -rcv($sock_b, $port_a, rtpm(96, 1008, 3320, $ssrc, "\x00\x8a\x03\xc0")); -rcv($sock_b, $port_a, rtpm(96, 1009, 3320, $ssrc, "\x00\x8a\x03\xc0")); -snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1010, 4280, $ssrc, "\x00" x 160)); -snd($sock_a, $port_b, rtp(0, 1009, 4440, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1011, 4440, $ssrc, "\x00" x 160)); -snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1012, 4600, $ssrc, "\x00" x 160)); -snd($sock_a, $port_b, rtp(0, 1011, 4760, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1013, 4760, $ssrc, "\x00" x 160)); -snd($sock_a, $port_b, rtp(0, 1012, 4920, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96 | 0x80, 1014, 4920, $ssrc, "\x01\x06\x00\xa0")); -snd($sock_a, $port_b, rtp(0, 1013, 5080, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1015, 4920, $ssrc, "\x01\x06\x01\x40")); -snd($sock_a, $port_b, rtp(0, 1014, 5240, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1016, 4920, $ssrc, "\x01\x06\x01\xe0")); -snd($sock_a, $port_b, rtp(0, 1015, 5400, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1017, 4920, $ssrc, "\x01\x06\x02\x80")); -snd($sock_a, $port_b, rtp(0, 1016, 5560, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1018, 4920, $ssrc, "\x01\x06\x03\x20")); -snd($sock_a, $port_b, rtp(0, 1017, 5720, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(96, 1019, 4920, $ssrc, "\x01\x86\x03\xc0")); -rcv($sock_b, $port_a, rtpm(96, 1020, 4920, $ssrc, "\x01\x86\x03\xc0")); -rcv($sock_b, $port_a, rtpm(96, 1021, 4920, $ssrc, "\x01\x86\x03\xc0")); -snd($sock_a, $port_b, rtp(0, 1018, 5880, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1022, 5880, $ssrc, "\x00" x 160)); +is $ret1[2], $ret1[3], 'rtp rport 1'; +is $ret1[5], $ret1[6], 'rtp rport 2'; +if (0) { -# SDP in/out tests, various ICE options +# github issue 854 -new_call; +($sock_a, $sock_b) = new_call([qw(198.51.100.1 7326)], [qw(198.51.100.3 7328)]); -offer('plain SDP, no ICE', { ICE => 'remove' }, < 'remove', replace => ['origin'], codec => { transcode => ['PCMA'] } }, < 'remove' }, < 'remove', replace => ['origin'] }, < 'default' }, < 'remove', replace => ['origin'], codec => { transcode => ['PCMA'] } }, < 'default' }, < 'remove', replace => ['origin'] }, < 'optional' }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'remove' }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'remove' }, < ft(), code => '0', volume => 10, duration => 100 }); + +snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96 | 0x80, 1002, 3320, $ssrc, "\x00\x0a\x00\xa0")); +snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1003, 3320, $ssrc, "\x00\x0a\x01\x40")); +snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1004, 3320, $ssrc, "\x00\x0a\x01\xe0")); +snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1005, 3320, $ssrc, "\x00\x0a\x02\x80")); +snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1006, 3320, $ssrc, "\x00\x0a\x03\x20")); +snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1007, 3320, $ssrc, "\x00\x8a\x03\xc0")); +rcv($sock_b, $port_a, rtpm(96, 1008, 3320, $ssrc, "\x00\x8a\x03\xc0")); +rcv($sock_b, $port_a, rtpm(96, 1009, 3320, $ssrc, "\x00\x8a\x03\xc0")); +snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1010, 4280, $ssrc, "\x00" x 160)); + + + +snd($sock_b, $port_a, rtp(0, 4000, 8000, 0x6543, "\x00" x 160)); +($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 8000, -1, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 4001, 8160, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4001, 8160, $ssrc, "\x00" x 160)); + +$resp = rtpe_req('play DTMF', 'inject DTMF towards A', + { 'from-tag' => tt(), code => '*', volume => 10, duration => 100 }); + +snd($sock_b, $port_a, rtp(0, 4002, 8320, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(96 | 0x80, 4002, 8320, $ssrc, "\x0a\x0a\x00\xa0")); +snd($sock_b, $port_a, rtp(0, 4003, 8480, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(96, 4003, 8320, $ssrc, "\x0a\x0a\x01\x40")); +snd($sock_b, $port_a, rtp(0, 4004, 8640, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(96, 4004, 8320, $ssrc, "\x0a\x0a\x01\xe0")); +snd($sock_b, $port_a, rtp(0, 4005, 8800, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(96, 4005, 8320, $ssrc, "\x0a\x0a\x02\x80")); +snd($sock_b, $port_a, rtp(0, 4006, 8960, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(96, 4006, 8320, $ssrc, "\x0a\x0a\x03\x20")); +snd($sock_b, $port_a, rtp(0, 4007, 9120, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(96, 4007, 8320, $ssrc, "\x0a\x8a\x03\xc0")); +rcv($sock_a, $port_b, rtpm(96, 4008, 8320, $ssrc, "\x0a\x8a\x03\xc0")); +rcv($sock_a, $port_b, rtpm(96, 4009, 8320, $ssrc, "\x0a\x8a\x03\xc0")); +snd($sock_b, $port_a, rtp(0, 4008, 9280, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4010, 9280, $ssrc, "\x00" x 160)); + + + + + +# transcoding, RFC payload type present on both sides + +($sock_a, $sock_b) = new_call([qw(198.51.100.1 6110)], [qw(198.51.100.3 6112)]); + +($port_a) = offer('transcoding, RFC payload type present on both sides', + { ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'], + codec => { transcode => ['PCMA'] }}, < 'optional' }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < '3.4.5.6', - flags => ['full-rtcp-attribute'], ICE => 'optional', }, < ft(), code => '0', volume => 10, duration => 100 }); + +snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96 | 0x80, 1002, 3320, $ssrc, "\x00\x0a\x00\xa0")); +snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1003, 3320, $ssrc, "\x00\x0a\x01\x40")); +snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1004, 3320, $ssrc, "\x00\x0a\x01\xe0")); +snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1005, 3320, $ssrc, "\x00\x0a\x02\x80")); +snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1006, 3320, $ssrc, "\x00\x0a\x03\x20")); +snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1007, 3320, $ssrc, "\x00\x8a\x03\xc0")); +rcv($sock_b, $port_a, rtpm(96, 1008, 3320, $ssrc, "\x00\x8a\x03\xc0")); +rcv($sock_b, $port_a, rtpm(96, 1009, 3320, $ssrc, "\x00\x8a\x03\xc0")); +snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1010, 4280, $ssrc, "\x2a" x 160)); + + + +snd($sock_b, $port_a, rtp(8, 4000, 8000, 0x6543, "\x2a" x 160)); +($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 8000, -1, "\x00" x 160)); +snd($sock_b, $port_a, rtp(8, 4001, 8160, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4001, 8160, $ssrc, "\x00" x 160)); + +$resp = rtpe_req('play DTMF', 'inject DTMF towards A', + { 'from-tag' => tt(), code => '#', volume => -10, duration => 100 }); + +snd($sock_b, $port_a, rtp(8, 4002, 8320, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(96 | 0x80, 4002, 8320, $ssrc, "\x0b\x0a\x00\xa0")); +snd($sock_b, $port_a, rtp(8, 4003, 8480, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(96, 4003, 8320, $ssrc, "\x0b\x0a\x01\x40")); +snd($sock_b, $port_a, rtp(8, 4004, 8640, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(96, 4004, 8320, $ssrc, "\x0b\x0a\x01\xe0")); +snd($sock_b, $port_a, rtp(8, 4005, 8800, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(96, 4005, 8320, $ssrc, "\x0b\x0a\x02\x80")); +snd($sock_b, $port_a, rtp(8, 4006, 8960, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(96, 4006, 8320, $ssrc, "\x0b\x0a\x03\x20")); +snd($sock_b, $port_a, rtp(8, 4007, 9120, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(96, 4007, 8320, $ssrc, "\x0b\x8a\x03\xc0")); +rcv($sock_a, $port_b, rtpm(96, 4008, 8320, $ssrc, "\x0b\x8a\x03\xc0")); +rcv($sock_a, $port_b, rtpm(96, 4009, 8320, $ssrc, "\x0b\x8a\x03\xc0")); +snd($sock_b, $port_a, rtp(8, 4008, 9280, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4010, 9280, $ssrc, "\x00" x 160)); -new_call; -offer('ICE SDP, default ICE option', { ICE => 'optional' }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'optional' }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'force' }, < ft(), code => 'C', volume => 5, duration => 120, pause => 110 }); + +snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1002, 3320, $ssrc, "\xff\x93\x94\xbc\x2e\x56\xbf\x2b\x13\x1b\xa7\x8e\x98\x47\x25\x41\xe2\x24\x16\x2b\x99\x8e\x9f\x28\x1e\x3d\x5b\x23\x1c\xdf\x92\x8f\xb6\x1c\x1c\x40\x5d\x26\x25\xaa\x8f\x95\x3b\x15\x1d\x5e\xde\x2c\x38\x9d\x8f\x9e\x1f\x11\x20\xc0\xc1\x37\xdd\x99\x92\xb7\x15\x10\x2c\xac\xb5\x49\xb8\x97\x99\x37\x0f\x13\x58\xa0\xae\x67\xae\x99\xa4\x1f\x0d\x1a\xae\x9b\xad\x7b\xad\x9d\xbf\x16\x0e\x27\x9d\x98\xb0\x55\xb1\xa6\x3a\x11\x11\x63\x95\x98\xbf\x3e\xbb\xb4\x26\x10\x1a\xa9\x90\x9a\x4e\x30\xce\xd4\x1e\x12\x29\x99\x8e\xa1\x2d\x29\x6d\x4b\x1c\x18\xef\x91\x8f\xb6\x1f\x24\x57\x3e\x1d\x20\xa9\x8e\x95\x3e\x19\x23\x67\x3e\x21\x31\x9c\x8e\x9e\x22\x14\x26\xcd\x4a")); +snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1003, 3480, $ssrc, "\x2a\xdf\x96\x90\xb5\x17\x13\x2f\xb6\xf5\x36\xb1\x93\x96\x39\x10\x15\x55\xaa\xc8\x4c\xa7\x95\xa0\x1f\x0e\x1b\xb4\xa1\xbd\xed\xa4\x99\xbb\x15\x0e\x27\xa0\x9d\xbd\xda\xa4\x9f\x39\x10\x11\x58\x98\x9c\xc8\xf9\xa9\xac\x23\x0e\x19\xab\x92\x9e\x59\x4c\xb0\xca\x1b\x10\x27\x9a\x90\xa5\x35\x3a\xbe\x43\x18\x15\x6c\x92\x91\xb7\x26\x30\xd6\x32\x18\x1d\xa9\x8e\x96\x44\x1d\x2d\xfc\x2e\x1b\x2d\x9a\x8d\x9e\x25\x19\x2d\xe7\x2f\x20\xea\x94\x8f\xb3\x19\x17\x36\xc8\x36\x2c\xae\x90\x95\x3b\x12\x18\x55\xb7\x43\x3e\xa1\x91\x9e\x1f\x0f\x1d\xba\xac\x64\xe8\x9d\x95\xb7\x15\x0e\x29\xa6\xa6\xda\xc3\x9d\x9b\x39\x0f\x11\x51\x9c\xa2\xd8\xbe\x9f\xa7\x21\x0e\x18\xad")); +snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1004, 3640, $ssrc, "\x96\xa3\x68\xc4\xa5\xc2\x19\x0e\x26\x9c\x93\xa9\x3f\xdb\xae\x3e\x14\x12\x5b\x93\x93\xb9\x2e\x51\xbe\x2c\x14\x1b\xa9\x8f\x97\x4c\x25\x3f\xde\x25\x16\x2a\x9a\x8e\x9e\x29\x1e\x3b\x5e\x24\x1b\x7b\x92\x8f\xb2\x1c\x1c\x3e\x61\x27\x25\xac\x8f\x94\x3e\x15\x1c\x59\xdb\x2d\x37\x9e\x8f\x9d\x20\x11\x1f\xc2\xbf\x38\xea\x99\x92\xb4\x16\x10\x2b\xad\xb4\x49\xba\x98\x98\x3a\x0f\x12\x4e\xa1\xad\x68\xaf\x99\xa3\x20\x0d\x19\xb0\x9b\xac\x7b\xae\x9d\xbc\x17\x0e\x25\x9e\x98\xaf\x55\xb2\xa6\x3d\x12\x11\x52\x96\x97\xbd\x3e\xbc\xb3\x28\x10\x19\xab\x90\x9a\x54\x2f\xd0\xcf\x1f\x12\x27\x9a\x8e\xa0\x2e\x28\x66\x4e\x1d\x18\x62\x92\x8f\xb2\x20\x23\x53\x3f\x1d\x1f")); +snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1005, 3800, $ssrc, "\xab\x8e\x94\x44\x19\x22\x61\x40\x21\x2f\x9c\x8e\x9d\x23\x14\x25\xce\x4d\x2a\xf7\x96\x8f\xb1\x18\x13\x2e\xb7\xe8\x36\xb3\x94\x96\x3c\x10\x15\x4d\xaa\xc5\x4b\xa8\x95\x9f\x20\x0e\x1a\xb6\xa0\xbc\xf5\xa4\x99\xb8\x16\x0e\x26\xa1\x9d\xbb\xdd\xa5\x9f\x3c\x10\x10\x4c\x99\x9b\xc5\x78\xaa\xac\x24\x0f\x18\xac\x93\x9d\x5f\x4a\xb1\xc7\x1c\x0f\x25\x9b\x90\xa3\x36\x39\xbf\x47\x18\x14\x56\x92\x90\xb4\x27\x2f\xd7\x34\x18\x1c\xab\x8e\x95\x4b\x1d\x2c\xfe\x2f\x1b\x2c\x9b\x8d\x9d\x27\x19\x2c\xe7\x30\x20\x6d\x94\x8f\xaf\x1a\x17\x34\xc8\x37\x2b\xaf\x91\x94\x3f\x12\x18\x4e\xb6\x45\x3d\xa3\x91\x9e\x20\x0f\x1c\xbc\xab\x6c\xf5\x9e\x95\xb3\x16\x0e\x27\xa7\xa5")); +snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1006, 3960, $ssrc, "\xd6\xc6\x9d\x9b\x3d\x0f\x11\x49\x9c\xa1\xd4\xbf\x9f\xa6\x22\x0e\x18\xaf\x96\xa2\x6e\xc6\xa5\xbe\x19\x0e\x24\x9d\x93\xa8\x40\xe1\xae\x42\x15\x12\x4e\x94\x93\xb7\x2e\x4e\xbe\x2d\x14\x1a\xab\x8f\x97\x52\x25\x3e\xdc\x26\x16\x28\x9b\x8e\x9e\x2b\x1e\x3a\x61\x25\x1b\x5d\x93\x8f\xaf\x1d\x1c\x3d\x67\x27\x24\xad\x8f\x93\x45\x15\x1c\x53\xd7\x2d\x35\x9f\x8f\x9c\x22\x11\x1f\xc5\xbe\x38\x7a\x9a\x91\xb0\x17\x10\x29\xad\xb3\x4a\xbc\x98\x98\x3e\x10\x12\x48\xa1\xad\x6a\xb1\x9a\xa1\x21\x0e\x18\xb3\x9b\xab\x7d\xaf\x9d\xb9\x18\x0e\x23\x9f\x97\xae\x55\xb4\xa5\x40\x12\x10\x49\x96\x97\xbb\x3d\xbd\xb2\x29\x10\x18\xac\x90\x99\x5d\x2f\xd4\xcd\x1f\x12\x25\x9b")); +snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1007, 4120, $ssrc, "\x8e\x9f\x2f\x28\x5f\x51\x1d\x17\x52\x92\x8f\xaf\x20\x22\x50\x42\x1e\x1f\xad\x8e\x93\x4b\x19\x21\x5d\x42\x22\x2e\x9d\x8e\x9c\x25\x14\x24\xd0\x4f\x2a\x68\x97\x8f\xae\x18\x12\x2c\xb7\xdf\x36\xb6\x94\x95\x41\x11\x14\x48\xaa\xc3\x4a\xaa\x95\x9e\x21\x0e\x19\xb8\xa0\xba\xfe\xa5\x99\xb4\x17\x0e\x24\xa2\x9c\xba\xe0\xa6\x9e\x40\x10\x10\x45\x99\x9b\xc2\x6d\xaa\xab\x26\x0f\x17\xae\x93\x9c\x6a\x48\xb2\xc3\x1c\x0f\x23\x9c\x90\xa2\x37\x38\xbf\x4b\x19\x14\x4b\x93\x90\xb1\x27\x2e\xd8\x36\x19\x1c\xad\x8e\x94\x52\x1d\x2b\x7d\x30\x1b\x2a\x9c\x8d\x9c\x28\x19\x2b\xe7\x31\x20\x5a\x95\x8f\xad\x1a\x16\x32\xc8\x39\x2b\xb2\x91\x94\x46\x13\x17\x4a\xb6\x48\x3c")); +# pause +snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1008, 4280, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1009, 4440, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1009, 4440, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1010, 4600, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1011, 4760, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1011, 4760, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1012, 4920, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1012, 4920, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1013, 5080, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1013, 5080, $ssrc, "\xff" x 80 . "\x00" x 80)); + + + +snd($sock_b, $port_a, rtp(0, 4000, 8000, 0x6543, "\x00" x 160)); +($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 8000, -1, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 4001, 8160, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4001, 8160, $ssrc, "\x00" x 160)); + +$resp = rtpe_req('play DTMF', 'inject DTMF towards A', + { 'from-tag' => tt(), code => '4', volume => 3, duration => 150, pause => 100 }); + +snd($sock_b, $port_a, rtp(0, 4002, 8320, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4002, 8320, $ssrc, "\xff\x90\x8a\x93\xd9\x1b\x18\x27\x65\xe5\x33\x29\x4c\x9e\x8f\x91\xb8\x15\x09\x0d\x32\x98\x8e\x96\xbb\x2c\x2b\x4c\xd8\x34\x1c\x18\x2e\x9d\x8c\x8c\xa5\x1a\x0b\x0d\x27\xa3\x97\x9e\xbd\x4f\xc4\xaa\xb2\x2c\x12\x0e\x1e\xa1\x8b\x8a\x9c\x25\x0e\x10\x25\xb7\xa7\xb7\x5e\xcb\xa2\x98\x9f\x30\x0f\x0a\x16\xae\x8d\x8a\x98\x3a\x18\x19\x2c\xdd\xfd\x30\x2b\xce\x99\x8e\x95\x4c\x0f\x09\x10\xdf\x93\x8e\x9a\xec\x28\x2c\x56\xee\x2d\x1a\x1a\x48\x97\x8b\x8e\xba\x14\x0a\x0f\x39\x9d\x96\xa1\xcd\x4e\xbe\xab\xbe\x23\x10\x10\x2b\x99\x8a\x8c\xa7\x1b\x0d\x12\x2f\xad\xa7\xbc\x5e\xbd\x9f\x99\xa8\x23\x0d\x0b\x1d\x9f\x8b\x8c\x9f\x29\x16\x1b\x34\xcd\x60\x2f\x2f\xb6\x96")); +snd($sock_b, $port_a, rtp(0, 4003, 8480, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4003, 8480, $ssrc, "\x8e\x9b\x2b\x0c\x09\x17\xae\x8f\x8e\x9e\x3f\x25\x2e\x65\x5c\x28\x1a\x1e\xc2\x92\x8a\x92\x44\x0f\x0a\x14\xd6\x99\x97\xa6\x7c\x4e\xba\xad\xe5\x1d\x0f\x13\x49\x92\x89\x8e\xbe\x15\x0d\x16\x43\xa8\xa7\xc1\x66\xb5\x9d\x9a\xb6\x1b\x0c\x0d\x2b\x98\x8a\x8d\xab\x1f\x15\x1d\x3f\xc7\x52\x2e\x39\xaa\x93\x8f\xa3\x1e\x0b\x0b\x1e\x9f\x8d\x8f\xa7\x30\x23\x31\x7c\x4a\x24\x1a\x24\xac\x8e\x8b\x99\x28\x0c\x0a\x1a\xb0\x96\x98\xac\x4f\x53\xb7\xaf\x44\x19\x0f\x18\xba\x8e\x89\x93\x3f\x10\x0d\x1a\xd5\xa3\xa8\xca\xf9\xae\x9c\x9d\xec\x16\x0b\x10\x4e\x91\x89\x90\xc6\x1a\x14\x20\x55\xc3\x4a\x2f\x49\xa2\x91\x92\xb2\x17\x09\x0c\x2d\x99\x8d\x92\xb3\x29\x23\x36\xf2")); +snd($sock_b, $port_a, rtp(0, 4004, 8640, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4004, 8640, $ssrc, "\x3e\x20\x1b\x2d\xa0\x8d\x8c\xa1\x1c\x0a\x0c\x22\xa3\x94\x9a\xb5\x44\x5c\xb5\xb6\x32\x16\x0f\x1e\xa6\x8c\x8a\x99\x28\x0e\x0e\x20\xb7\xa1\xab\xd4\xdb\xaa\x9c\xa1\x38\x11\x0b\x15\xb5\x8d\x8a\x96\x3f\x16\x15\x26\xdd\xc2\x43\x31\xdf\x9d\x90\x96\x6d\x11\x09\x0f\x5a\x93\x8c\x97\xd2\x23\x23\x3b\xf6\x37\x1f\x1d\x40\x9a\x8c\x8e\xb2\x15\x09\x0e\x31\x9c\x93\x9c\xc2\x3e\x74\xb4\xbf\x29\x14\x11\x29\x9b\x8a\x8b\xa3\x1c\x0d\x0f\x2a\xab\x9f\xad\xe0\xcc\xa6\x9c\xa9\x28\x0e\x0c\x1c\xa2\x8b\x8b\x9c\x2a\x14\x17\x2c\xc6\xc4\x3e\x36\xbd\x99\x90\x9b\x30\x0d\x09\x15\xb3\x8f\x8d\x9b\x42\x1f\x25\x42\x70\x30\x1e\x1f\xcf\x95\x8b\x92\x58\x0f\x09\x12\x6f\x98\x93")); +snd($sock_b, $port_a, rtp(0, 4005, 8800, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4005, 8800, $ssrc, "\x9f\xe5\x3b\xe2\xb5\xd9\x21\x12\x14\x3e\x95\x89\x8d\xb6\x16\x0c\x13\x3a\xa4\x9f\xb1\xf1\xc0\xa3\x9d\xb4\x1e\x0d\x0d\x27\x99\x8a\x8c\xa7\x1f\x12\x19\x37\xbc\xc8\x3c\x3c\xaf\x97\x91\xa2\x21\x0b\x0a\x1c\xa2\x8d\x8e\xa2\x2f\x1e\x28\x4c\x5d\x2c\x1e\x25\xb0\x90\x8c\x98\x2c\x0c\x0a\x18\xb4\x94\x94\xa6\x4d\x3a\xd4\xb8\x4f\x1d\x11\x18\xc5\x8f\x89\x91\x4d\x10\x0c\x17\xec\x9f\xa0\xb8\xff\xba\xa1\x9f\xd3\x19\x0c\x0f\x3f\x92\x89\x8f\xbb\x19\x11\x1c\x48\xb8\xce\x3b\x4a\xa8\x95\x93\xaf\x19\x0a\x0c\x29\x99\x8c\x8f\xad\x27\x1d\x2b\x59\x4f\x29\x1e\x2d\xa5\x8e\x8d\x9f\x1e\x0b\x0b\x1e\xa4\x91\x96\xad\x3e\x3b\xcc\xbc\x3a\x1a\x12\x1e\xaa\x8d\x8a\x98\x2b")); +snd($sock_b, $port_a, rtp(0, 4006, 8960, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4006, 8960, $ssrc, "\x0e\x0c\x1d\xb8\x9d\xa2\xbe\xf9\xb4\xa0\xa3\x3f\x14\x0c\x14\xbd\x8e\x89\x93\x49\x15\x12\x1f\xe7\xb5\xd9\x3c\x7c\xa1\x93\x97\xd5\x13\x09\x0e\x45\x93\x8b\x93\xc4\x20\x1d\x2e\x6b\x46\x26\x1f\x3d\x9d\x8d\x8e\xae\x17\x09\x0d\x2c\x9c\x90\x98\xba\x36\x3d\xc7\xc4\x2e\x17\x13\x27\x9e\x8b\x8b\x9f\x1e\x0c\x0e\x25\xaa\x9c\xa5\xc8\xe8\xae\xa0\xaa\x2d\x10\x0c\x1b\xa6\x8c\x8a\x9a\x2c\x12\x13\x27\xc3\xb3\xed\x3e\xc8\x9d\x93\x9b\x38\x0f\x09\x13\xba\x8f\x8b\x98\x4a\x1d\x1e\x34\xf9\x3e\x24\x23\xea\x98\x8c\x92\xdf\x10\x09\x0f\x4d\x97\x90\x9c\xd2\x31\x3f\xc5\xd6\x28\x16\x16\x39\x97\x8a\x8d\xaf\x17\x0b\x10\x32\xa2\x9b\xa8\xd6\xd9\xac\xa1\xb3\x22\x0e\x0e")); +snd($sock_b, $port_a, rtp(0, 4007, 9120, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4007, 9120, $ssrc, "\x24\x9b\x8a\x8b\xa2\x1f\x10\x15\x2f\xb8\xb4\x68\x43\xb8\x9a\x94\xa1\x25\x0c\x0a\x1a\xa5\x8d\x8c\x9e\x30\x1b\x1f\x3c\xee\x38\x23\x28\xb8\x93\x8d\x97\x31\x0d\x09\x15\xb9\x93\x90\xa0\x4f\x2f\x46\xc4\x5e\x21\x15\x19\xd7\x91\x89\x90\x7b\x10\x0b\x14\x5b\x9d\x9c\xad\xed\xcd\xa9\xa3\xca\x1c\x0d\x10\x38\x94\x89\x8e\xb3\x19\x0f\x18\x3e\xb0\xb5\x59\x4d\xae\x98\x95\xad\x1c\x0b\x0c\x25\x9b\x8b\x8e\xa9\x26\x1a\x22\x46\xf5\x33\x23\x2e\xaa\x90\x8d\x9e\x21\x0b\x0a\x1c\xa6\x90\x92\xa8\x3b\x2e\x4d\xc7\x43\x1e\x15\x1e\xaf\x8e\x8a\x96\x2e\x0e\x0b\x1a\xbb\x9b\x9d\xb2\x68\xc5\xa8\xa7\x4c\x17\x0d\x14\xcb\x8f\x89\x91\x5e\x14\x0f\x1c\x6e\xad\xb8\x52\x68\xa8")); +snd($sock_b, $port_a, rtp(0, 4008, 9280, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4008, 9280, $ssrc, "\x97\x98\xc7\x16\x0a\x0e\x3a\x94\x8a\x90\xbb\x1e\x1a\x27\x56\x6f\x2f\x25\x3b\xa0\x8e\x8f\xaa\x19\x09\x0c\x28\x9c\x8f\x95\xb2\x31\x2e\x59\xcc\x37\x1b\x16\x26\xa1\x8c\x8b\x9d\x1f\x0c\x0c\x20\xab\x99\x9e\xbb\x5d\xbe\xa7\xac\x32\x13\x0d\x1a\xab\x8c\x89\x97\x2e\x10\x10\x21\xc3\xab\xbc\x4f\xd4\xa2\x96\x9c\x3f\x10\x0a\x12\xc4\x8f\x8a\x95\x57\x1b\x1a\x2b\xfd\x5d\x2d\x27\x62\x9b\x8e\x92\xc9\x12\x09\x0e\x3f\x97\x8e\x98\xc6\x2c\x2f\x6b\xd9\x2e\x1a\x18\x34\x9a\x8b\x8d\xab\x18\x0a\x0e\x2d\xa1\x98\xa1\xc7\x5b\xb9\xa7\xb4\x27\x10\x0e\x22\x9d\x8a\x8b\x9f\x20\x0e\x12\x2a\xb4\xaa\xc0\x50\xc0\x9e\x97\xa1\x2a\x0e\x0a\x19\xa8\x8c\x8b\x9b\x31\x18\x1b\x31")); +snd($sock_b, $port_a, rtp(0, 4009, 9440, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4009, 9440, $ssrc, "\xda\x50\x2c\x2b\xc0\x97\x8e\x97\x39\x0e\x09\x13\xbf\x92\x8e\x9c\x57\x29\x31\xef\x72\x28\x19\x1b\x6d\x94\x8a\x8f\xce\x11\x0a\x11\x48\x9c\x98\xa5\xdc\x5e\xb5\xa9\xc6\x1f\x0f\x10\x31\x96\x89\x8d\xad\x19\x0e\x15\x37\xac\xaa\xc8\x57\xb7\x9c\x98\xac\x1e\x0c\x0c\x21\x9c\x8b\x8d\xa4\x25\x17\x1d\x3b\xcf\x48\x2b\x30\xae\x93\x8e" . "\xff" x 80)); +# pause +snd($sock_b, $port_a, rtp(0, 4010, 9600, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4010, 9600, $ssrc, "\xff" x 160)); +snd($sock_b, $port_a, rtp(0, 4011, 9760, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4011, 9760, $ssrc, "\xff" x 160)); +snd($sock_b, $port_a, rtp(0, 4012, 9920, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4012, 9920, $ssrc, "\xff" x 160)); +snd($sock_b, $port_a, rtp(0, 4013, 10080, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4013, 10080, $ssrc, "\xff" x 160)); +snd($sock_b, $port_a, rtp(0, 4014, 10240, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4014, 10240, $ssrc, "\xff" x 80 . "\x00" x 80)); + + + + +# transcoding, no RFC payload type present + +($sock_a, $sock_b) = new_call([qw(198.51.100.1 6018)], [qw(198.51.100.3 6020)]); + +($port_a) = offer('transcoding, no RFC payload type present', + { ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'], + codec => { transcode => ['PCMA'] } }, < 'optional' }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'force' }, < ft(), code => 'C', volume => 5, duration => 120 }); + +snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1002, 3320, $ssrc, "\xd5\xb9\xbe\x97\x05\x70\xea\x01\x3e\x31\x82\xa5\xb2\x63\x0f\x69\xc1\x0f\x3d\x06\xb3\xa4\x8a\x03\x35\x14\x75\x0e\x36\xcc\xb8\xa5\x9d\x36\x36\x68\x49\x0d\x0c\x81\xa5\xbf\x16\x3f\x37\x4f\xcf\x07\x13\xb4\xa5\xb4\x0a\x3b\x0b\xeb\xe9\x12\xc9\xb3\xb8\x92\x3c\x3a\x07\x87\x9c\x61\x93\xb2\xb3\x12\x25\x39\x76\x8b\x85\x5a\x85\xb3\x8e\x35\x24\x30\x85\xb1\x87\x57\x84\xb7\xeb\x3c\x24\x0d\xb4\xb2\x9b\x70\x98\x8c\x11\x3b\x38\x41\xbf\xb2\xeb\x15\x96\x9f\x0d\x3a\x30\x83\xba\xb1\x7b\x1b\xfa\xf2\x34\x39\x03\xb0\xa5\x88\x04\x03\x5f\x67\x37\x32\xdd\xb8\xba\x9d\x35\x0e\x71\x15\x37\x0a\x80\xa4\xbf\x15\x33\x09\x45\x15\x0b\x18\xb6\xa4\xb4\x08\x3f\x0d\xe5\x66")); +snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1003, 3480, $ssrc, "\x00\xcd\xbc\xba\x9c\x3d\x39\x1a\x9d\xd1\x1d\x98\xbe\xbd\x10\x3a\x3f\x73\x80\xe0\x64\x82\xbf\x8b\x35\x24\x31\x9f\x8b\x94\xdf\x8e\xb3\x96\x3c\x24\x02\x8b\xb7\x94\xf4\x8f\xb5\x10\x3a\x3b\x76\xb2\xb6\xe0\xd6\x80\x87\x09\x25\x33\x81\xb9\xb4\x74\x64\x9b\xe6\x31\x3a\x0d\xb1\xba\x8f\x1c\x11\x95\x6f\x32\x3f\x5e\xb8\xbb\x92\x0d\x1a\xf0\x19\x32\x37\x83\xa4\xbc\x6d\x37\x07\xd4\x04\x31\x07\xb1\xa4\xb4\x0c\x33\x04\xc5\x05\x0b\xd8\xbe\xa5\x9e\x30\x3d\x1d\xe0\x1d\x06\x84\xbb\xbf\x16\x38\x33\x73\x92\x6f\x15\x88\xbb\xb5\x35\x25\x37\x91\x86\x46\xda\xb7\xbf\x92\x3c\x25\x03\x8d\x8c\xf4\xef\xb7\xb6\x10\x25\x3b\x7f\xb6\x89\xf6\x95\xb5\x82\x0b\x24\x33\x84")); +snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1004, 3640, $ssrc, "\xbd\x8e\x5a\xec\x8c\xee\x33\x24\x0c\xb6\xbe\x80\x6b\xf5\x85\x6a\x3f\x39\x4a\xbe\xbe\x90\x05\x7f\x95\x06\x3e\x31\x80\xa5\xbd\x64\x0f\x6b\xcc\x0c\x3d\x00\xb0\xa4\xb5\x00\x34\x16\x4e\x0e\x36\x57\xb9\xa5\x99\x36\x36\x6a\x43\x0d\x0f\x86\xa5\xbe\x15\x3f\x36\x77\xf5\x07\x12\xb4\xa5\xb4\x0b\x3b\x0a\xee\xeb\x13\xd8\xb0\xb8\x9f\x3c\x3a\x01\x87\x9f\x66\x91\xb2\xb3\x11\x25\x39\x7a\x8b\x84\x5b\x9a\xb0\x89\x0a\x24\x33\x9b\xb1\x87\x54\x85\xb7\x97\x3d\x24\x0c\xb4\xb2\x9a\x73\x99\x8c\x14\x38\x3b\x7c\xbc\xbd\x94\x15\x97\x9e\x02\x3a\x33\x81\xba\xb0\x73\x1a\xfe\xf9\x35\x39\x02\xb1\xa4\x8a\x05\x03\x44\x7a\x37\x32\x40\xb8\xa5\x99\x0a\x0e\x72\x6b\x34\x35")); +snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1005, 3800, $ssrc, "\x81\xa4\xbe\x6c\x33\x08\x43\x68\x08\x1a\xb7\xa4\xb7\x0e\x3f\x0c\xfb\x65\x00\xd1\xbd\xba\x98\x32\x39\x04\x92\xdb\x1d\x9e\xbe\xbc\x17\x3a\x3f\x65\x80\xed\x67\x83\xbf\xb5\x0a\x24\x30\x9d\x8b\x97\xd0\x8f\xb3\x93\x3c\x24\x0c\x88\xb7\x96\xc9\x8c\xb5\x17\x3a\x3a\x64\xb3\xb6\xed\x56\x80\x86\x0f\x25\x32\x87\xb9\xb7\x4d\x66\x98\xe3\x36\x3a\x0c\xb1\xba\x8e\x1d\x10\xea\x63\x33\x3f\x70\xb9\xbb\x9f\x0d\x05\xf1\x1f\x33\x36\x81\xa4\xbf\x67\x34\x06\xd5\x05\x31\x06\xb6\xa4\xb7\x0d\x33\x07\xc5\x1a\x0a\x5f\xbe\xa5\x9a\x30\x3d\x1f\xe0\x12\x06\x9a\xbb\xbf\x6b\x39\x32\x7b\x9d\x62\x14\x89\xbb\xb4\x0b\x25\x36\x97\x86\x5e\xd1\xb4\xbf\x9e\x3c\x24\x0d\x82\x8c")); +snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1006, 3960, $ssrc, "\xf0\xe2\xb7\xb1\x14\x3a\x3b\x61\xb6\x88\xf3\xeb\xb5\x8d\x09\x24\x32\x85\xbd\x89\x5c\xe2\x8c\x95\x30\x24\x0e\xb7\xb9\x83\x68\xc3\x85\x6e\x3f\x38\x7a\xbe\xb9\x92\x05\x7a\x95\x07\x3e\x30\x86\xa5\xbd\x7c\x0f\x15\xcb\x0d\x3d\x03\xb1\xa4\xb4\x01\x34\x11\x40\x0f\x36\x48\xb9\xa5\x85\x37\x36\x14\x45\x02\x0f\x84\xa5\xbe\x6d\x3c\x36\x7d\xf1\x04\x1c\xb5\xa5\xb7\x09\x3b\x35\xed\xea\x13\x57\xb0\xb8\x9b\x3d\x3a\x00\x84\x9e\x66\x97\xb2\xb2\x15\x3a\x38\x60\x8b\x87\x58\x98\xb0\x88\x08\x24\x32\x9e\xb1\x86\x54\x9a\xb7\x90\x32\x24\x0e\xb5\xb2\x84\x73\x9f\x8c\x68\x38\x3b\x61\xbc\xbd\x96\x14\x94\x99\x03\x3b\x32\x87\xba\xb3\x48\x1a\xf2\xe5\x0a\x39\x0c\xb1")); +snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1007, 4120, $ssrc, "\xa4\xb5\x1a\x02\x4c\x7f\x37\x32\x7c\xb9\xa5\x9a\x0a\x09\x7e\x6e\x34\x35\x87\xa5\xbe\x67\x33\x0b\x48\x6e\x08\x05\xb7\xa4\xb6\x0f\x3f\x0e\xfe\x79\x00\x5a\xbd\xa5\x85\x32\x39\x07\x92\xcd\x1d\x9d\xbe\xbc\x69\x3b\x3e\x60\x80\xef\x66\x80\xbf\xb5\x08\x24\x30\x90\x8b\x91\xd5\x8c\xb3\x9f\x3d\x24\x0e\x89\xb7\x91\xc2\x8c\xb5\x68\x3b\x3a\x6d\xb3\xb1\xee\x5c\x81\x81\x0c\x25\x3d\x85\xb9\xb7\x58\x60\x99\xef\x37\x3a\x0e\xb6\xba\x89\x12\x13\xeb\x67\x33\x3e\x67\xb9\xba\x98\x02\x05\xf7\x1d\x33\x36\x87\xa4\xbe\x7c\x34\x01\x54\x1a\x31\x01\xb6\xa4\xb6\x03\x33\x06\xda\x18\x0a\x75\xbf\xa5\x84\x31\x3d\x19\xe0\x10\x01\x99\xbb\xbe\x62\x39\x3d\x66\x9d\x60\x17")); +# pause +snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1008, 4280, $ssrc, "\xd5" x 160)); +snd($sock_a, $port_b, rtp(0, 1009, 4440, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1009, 4440, $ssrc, "\xd5" x 160)); +snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1010, 4600, $ssrc, "\xd5" x 160)); +snd($sock_a, $port_b, rtp(0, 1011, 4760, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1011, 4760, $ssrc, "\xd5" x 160)); +snd($sock_a, $port_b, rtp(0, 1012, 4920, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1012, 4920, $ssrc, "\xd5" x 160)); +snd($sock_a, $port_b, rtp(0, 1013, 5080, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1013, 5080, $ssrc, "\x2a" x 160)); + + + + +snd($sock_b, $port_a, rtp(8, 4000, 8000, 0x6543, "\x2a" x 160)); +($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 8000, -1, "\x00" x 160)); +snd($sock_b, $port_a, rtp(8, 4001, 8160, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4001, 8160, $ssrc, "\x00" x 160)); + +$resp = rtpe_req('play DTMF', 'inject DTMF towards A', + { 'from-tag' => tt(), code => '4', volume => 3, duration => 150 }); + +snd($sock_b, $port_a, rtp(8, 4002, 8320, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4002, 8320, $ssrc, "\xff\x90\x8a\x93\xd9\x1b\x18\x27\x65\xe5\x33\x29\x4c\x9e\x8f\x91\xb8\x15\x09\x0d\x32\x98\x8e\x96\xbb\x2c\x2b\x4c\xd8\x34\x1c\x18\x2e\x9d\x8c\x8c\xa5\x1a\x0b\x0d\x27\xa3\x97\x9e\xbd\x4f\xc4\xaa\xb2\x2c\x12\x0e\x1e\xa1\x8b\x8a\x9c\x25\x0e\x10\x25\xb7\xa7\xb7\x5e\xcb\xa2\x98\x9f\x30\x0f\x0a\x16\xae\x8d\x8a\x98\x3a\x18\x19\x2c\xdd\xfd\x30\x2b\xce\x99\x8e\x95\x4c\x0f\x09\x10\xdf\x93\x8e\x9a\xec\x28\x2c\x56\xee\x2d\x1a\x1a\x48\x97\x8b\x8e\xba\x14\x0a\x0f\x39\x9d\x96\xa1\xcd\x4e\xbe\xab\xbe\x23\x10\x10\x2b\x99\x8a\x8c\xa7\x1b\x0d\x12\x2f\xad\xa7\xbc\x5e\xbd\x9f\x99\xa8\x23\x0d\x0b\x1d\x9f\x8b\x8c\x9f\x29\x16\x1b\x34\xcd\x60\x2f\x2f\xb6\x96")); +snd($sock_b, $port_a, rtp(8, 4003, 8480, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4003, 8480, $ssrc, "\x8e\x9b\x2b\x0c\x09\x17\xae\x8f\x8e\x9e\x3f\x25\x2e\x65\x5c\x28\x1a\x1e\xc2\x92\x8a\x92\x44\x0f\x0a\x14\xd6\x99\x97\xa6\x7c\x4e\xba\xad\xe5\x1d\x0f\x13\x49\x92\x89\x8e\xbe\x15\x0d\x16\x43\xa8\xa7\xc1\x66\xb5\x9d\x9a\xb6\x1b\x0c\x0d\x2b\x98\x8a\x8d\xab\x1f\x15\x1d\x3f\xc7\x52\x2e\x39\xaa\x93\x8f\xa3\x1e\x0b\x0b\x1e\x9f\x8d\x8f\xa7\x30\x23\x31\x7c\x4a\x24\x1a\x24\xac\x8e\x8b\x99\x28\x0c\x0a\x1a\xb0\x96\x98\xac\x4f\x53\xb7\xaf\x44\x19\x0f\x18\xba\x8e\x89\x93\x3f\x10\x0d\x1a\xd5\xa3\xa8\xca\xf9\xae\x9c\x9d\xec\x16\x0b\x10\x4e\x91\x89\x90\xc6\x1a\x14\x20\x55\xc3\x4a\x2f\x49\xa2\x91\x92\xb2\x17\x09\x0c\x2d\x99\x8d\x92\xb3\x29\x23\x36\xf2")); +snd($sock_b, $port_a, rtp(8, 4004, 8640, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4004, 8640, $ssrc, "\x3e\x20\x1b\x2d\xa0\x8d\x8c\xa1\x1c\x0a\x0c\x22\xa3\x94\x9a\xb5\x44\x5c\xb5\xb6\x32\x16\x0f\x1e\xa6\x8c\x8a\x99\x28\x0e\x0e\x20\xb7\xa1\xab\xd4\xdb\xaa\x9c\xa1\x38\x11\x0b\x15\xb5\x8d\x8a\x96\x3f\x16\x15\x26\xdd\xc2\x43\x31\xdf\x9d\x90\x96\x6d\x11\x09\x0f\x5a\x93\x8c\x97\xd2\x23\x23\x3b\xf6\x37\x1f\x1d\x40\x9a\x8c\x8e\xb2\x15\x09\x0e\x31\x9c\x93\x9c\xc2\x3e\x74\xb4\xbf\x29\x14\x11\x29\x9b\x8a\x8b\xa3\x1c\x0d\x0f\x2a\xab\x9f\xad\xe0\xcc\xa6\x9c\xa9\x28\x0e\x0c\x1c\xa2\x8b\x8b\x9c\x2a\x14\x17\x2c\xc6\xc4\x3e\x36\xbd\x99\x90\x9b\x30\x0d\x09\x15\xb3\x8f\x8d\x9b\x42\x1f\x25\x42\x70\x30\x1e\x1f\xcf\x95\x8b\x92\x58\x0f\x09\x12\x6f\x98\x93")); +snd($sock_b, $port_a, rtp(8, 4005, 8800, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4005, 8800, $ssrc, "\x9f\xe5\x3b\xe2\xb5\xd9\x21\x12\x14\x3e\x95\x89\x8d\xb6\x16\x0c\x13\x3a\xa4\x9f\xb1\xf1\xc0\xa3\x9d\xb4\x1e\x0d\x0d\x27\x99\x8a\x8c\xa7\x1f\x12\x19\x37\xbc\xc8\x3c\x3c\xaf\x97\x91\xa2\x21\x0b\x0a\x1c\xa2\x8d\x8e\xa2\x2f\x1e\x28\x4c\x5d\x2c\x1e\x25\xb0\x90\x8c\x98\x2c\x0c\x0a\x18\xb4\x94\x94\xa6\x4d\x3a\xd4\xb8\x4f\x1d\x11\x18\xc5\x8f\x89\x91\x4d\x10\x0c\x17\xec\x9f\xa0\xb8\xff\xba\xa1\x9f\xd3\x19\x0c\x0f\x3f\x92\x89\x8f\xbb\x19\x11\x1c\x48\xb8\xce\x3b\x4a\xa8\x95\x93\xaf\x19\x0a\x0c\x29\x99\x8c\x8f\xad\x27\x1d\x2b\x59\x4f\x29\x1e\x2d\xa5\x8e\x8d\x9f\x1e\x0b\x0b\x1e\xa4\x91\x96\xad\x3e\x3b\xcc\xbc\x3a\x1a\x12\x1e\xaa\x8d\x8a\x98\x2b")); +snd($sock_b, $port_a, rtp(8, 4006, 8960, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4006, 8960, $ssrc, "\x0e\x0c\x1d\xb8\x9d\xa2\xbe\xf9\xb4\xa0\xa3\x3f\x14\x0c\x14\xbd\x8e\x89\x93\x49\x15\x12\x1f\xe7\xb5\xd9\x3c\x7c\xa1\x93\x97\xd5\x13\x09\x0e\x45\x93\x8b\x93\xc4\x20\x1d\x2e\x6b\x46\x26\x1f\x3d\x9d\x8d\x8e\xae\x17\x09\x0d\x2c\x9c\x90\x98\xba\x36\x3d\xc7\xc4\x2e\x17\x13\x27\x9e\x8b\x8b\x9f\x1e\x0c\x0e\x25\xaa\x9c\xa5\xc8\xe8\xae\xa0\xaa\x2d\x10\x0c\x1b\xa6\x8c\x8a\x9a\x2c\x12\x13\x27\xc3\xb3\xed\x3e\xc8\x9d\x93\x9b\x38\x0f\x09\x13\xba\x8f\x8b\x98\x4a\x1d\x1e\x34\xf9\x3e\x24\x23\xea\x98\x8c\x92\xdf\x10\x09\x0f\x4d\x97\x90\x9c\xd2\x31\x3f\xc5\xd6\x28\x16\x16\x39\x97\x8a\x8d\xaf\x17\x0b\x10\x32\xa2\x9b\xa8\xd6\xd9\xac\xa1\xb3\x22\x0e\x0e")); +snd($sock_b, $port_a, rtp(8, 4007, 9120, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4007, 9120, $ssrc, "\x24\x9b\x8a\x8b\xa2\x1f\x10\x15\x2f\xb8\xb4\x68\x43\xb8\x9a\x94\xa1\x25\x0c\x0a\x1a\xa5\x8d\x8c\x9e\x30\x1b\x1f\x3c\xee\x38\x23\x28\xb8\x93\x8d\x97\x31\x0d\x09\x15\xb9\x93\x90\xa0\x4f\x2f\x46\xc4\x5e\x21\x15\x19\xd7\x91\x89\x90\x7b\x10\x0b\x14\x5b\x9d\x9c\xad\xed\xcd\xa9\xa3\xca\x1c\x0d\x10\x38\x94\x89\x8e\xb3\x19\x0f\x18\x3e\xb0\xb5\x59\x4d\xae\x98\x95\xad\x1c\x0b\x0c\x25\x9b\x8b\x8e\xa9\x26\x1a\x22\x46\xf5\x33\x23\x2e\xaa\x90\x8d\x9e\x21\x0b\x0a\x1c\xa6\x90\x92\xa8\x3b\x2e\x4d\xc7\x43\x1e\x15\x1e\xaf\x8e\x8a\x96\x2e\x0e\x0b\x1a\xbb\x9b\x9d\xb2\x68\xc5\xa8\xa7\x4c\x17\x0d\x14\xcb\x8f\x89\x91\x5e\x14\x0f\x1c\x6e\xad\xb8\x52\x68\xa8")); +snd($sock_b, $port_a, rtp(8, 4008, 9280, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4008, 9280, $ssrc, "\x97\x98\xc7\x16\x0a\x0e\x3a\x94\x8a\x90\xbb\x1e\x1a\x27\x56\x6f\x2f\x25\x3b\xa0\x8e\x8f\xaa\x19\x09\x0c\x28\x9c\x8f\x95\xb2\x31\x2e\x59\xcc\x37\x1b\x16\x26\xa1\x8c\x8b\x9d\x1f\x0c\x0c\x20\xab\x99\x9e\xbb\x5d\xbe\xa7\xac\x32\x13\x0d\x1a\xab\x8c\x89\x97\x2e\x10\x10\x21\xc3\xab\xbc\x4f\xd4\xa2\x96\x9c\x3f\x10\x0a\x12\xc4\x8f\x8a\x95\x57\x1b\x1a\x2b\xfd\x5d\x2d\x27\x62\x9b\x8e\x92\xc9\x12\x09\x0e\x3f\x97\x8e\x98\xc6\x2c\x2f\x6b\xd9\x2e\x1a\x18\x34\x9a\x8b\x8d\xab\x18\x0a\x0e\x2d\xa1\x98\xa1\xc7\x5b\xb9\xa7\xb4\x27\x10\x0e\x22\x9d\x8a\x8b\x9f\x20\x0e\x12\x2a\xb4\xaa\xc0\x50\xc0\x9e\x97\xa1\x2a\x0e\x0a\x19\xa8\x8c\x8b\x9b\x31\x18\x1b\x31")); +snd($sock_b, $port_a, rtp(8, 4009, 9440, 0x6543, "\x2a" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4009, 9440, $ssrc, "\xda\x50\x2c\x2b\xc0\x97\x8e\x97\x39\x0e\x09\x13\xbf\x92\x8e\x9c\x57\x29\x31\xef\x72\x28\x19\x1b\x6d\x94\x8a\x8f\xce\x11\x0a\x11\x48\x9c\x98\xa5\xdc\x5e\xb5\xa9\xc6\x1f\x0f\x10\x31\x96\x89\x8d\xad\x19\x0e\x15\x37\xac\xaa\xc8\x57\xb7\x9c\x98\xac\x1e\x0c\x0c\x21\x9c\x8b\x8d\xa4\x25\x17\x1d\x3b\xcf\x48\x2b\x30\xae\x93\x8e" . "\xff" x 80)); +# pause +snd($sock_b, $port_a, rtp(0, 4010, 9600, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4010, 9600, $ssrc, "\xff" x 160)); +snd($sock_b, $port_a, rtp(0, 4011, 9760, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4011, 9760, $ssrc, "\xff" x 160)); +snd($sock_b, $port_a, rtp(0, 4012, 9920, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4012, 9920, $ssrc, "\xff" x 160)); +snd($sock_b, $port_a, rtp(0, 4013, 10080, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4013, 10080, $ssrc, "\xff" x 160)); +snd($sock_b, $port_a, rtp(0, 4014, 10240, 0x6543, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 4014, 10240, $ssrc, "\xff" x 80 . "\x00" x 80)); -answer('ICE SDP, no ICE option given', { ICE => 'optional' }, < 'force' }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'force' }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'default' }, < ft(), code => 'C', volume => 5, duration => 100 }); +$resp = rtpe_req('play DTMF', 'inject DTMF towards B', + { 'from-tag' => ft(), code => '4', volume => 5, duration => 100 }); + +snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1002, 3320, $ssrc, "\xff\x93\x94\xbc\x2e\x56\xbf\x2b\x13\x1b\xa7\x8e\x98\x47\x25\x41\xe2\x24\x16\x2b\x99\x8e\x9f\x28\x1e\x3d\x5b\x23\x1c\xdf\x92\x8f\xb6\x1c\x1c\x40\x5d\x26\x25\xaa\x8f\x95\x3b\x15\x1d\x5e\xde\x2c\x38\x9d\x8f\x9e\x1f\x11\x20\xc0\xc1\x37\xdd\x99\x92\xb7\x15\x10\x2c\xac\xb5\x49\xb8\x97\x99\x37\x0f\x13\x58\xa0\xae\x67\xae\x99\xa4\x1f\x0d\x1a\xae\x9b\xad\x7b\xad\x9d\xbf\x16\x0e\x27\x9d\x98\xb0\x55\xb1\xa6\x3a\x11\x11\x63\x95\x98\xbf\x3e\xbb\xb4\x26\x10\x1a\xa9\x90\x9a\x4e\x30\xce\xd4\x1e\x12\x29\x99\x8e\xa1\x2d\x29\x6d\x4b\x1c\x18\xef\x91\x8f\xb6\x1f\x24\x57\x3e\x1d\x20\xa9\x8e\x95\x3e\x19\x23\x67\x3e\x21\x31\x9c\x8e\x9e\x22\x14\x26\xcd\x4a")); +snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1003, 3480, $ssrc, "\x2a\xdf\x96\x90\xb5\x17\x13\x2f\xb6\xf5\x36\xb1\x93\x96\x39\x10\x15\x55\xaa\xc8\x4c\xa7\x95\xa0\x1f\x0e\x1b\xb4\xa1\xbd\xed\xa4\x99\xbb\x15\x0e\x27\xa0\x9d\xbd\xda\xa4\x9f\x39\x10\x11\x58\x98\x9c\xc8\xf9\xa9\xac\x23\x0e\x19\xab\x92\x9e\x59\x4c\xb0\xca\x1b\x10\x27\x9a\x90\xa5\x35\x3a\xbe\x43\x18\x15\x6c\x92\x91\xb7\x26\x30\xd6\x32\x18\x1d\xa9\x8e\x96\x44\x1d\x2d\xfc\x2e\x1b\x2d\x9a\x8d\x9e\x25\x19\x2d\xe7\x2f\x20\xea\x94\x8f\xb3\x19\x17\x36\xc8\x36\x2c\xae\x90\x95\x3b\x12\x18\x55\xb7\x43\x3e\xa1\x91\x9e\x1f\x0f\x1d\xba\xac\x64\xe8\x9d\x95\xb7\x15\x0e\x29\xa6\xa6\xda\xc3\x9d\x9b\x39\x0f\x11\x51\x9c\xa2\xd8\xbe\x9f\xa7\x21\x0e\x18\xad")); +snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1004, 3640, $ssrc, "\x96\xa3\x68\xc4\xa5\xc2\x19\x0e\x26\x9c\x93\xa9\x3f\xdb\xae\x3e\x14\x12\x5b\x93\x93\xb9\x2e\x51\xbe\x2c\x14\x1b\xa9\x8f\x97\x4c\x25\x3f\xde\x25\x16\x2a\x9a\x8e\x9e\x29\x1e\x3b\x5e\x24\x1b\x7b\x92\x8f\xb2\x1c\x1c\x3e\x61\x27\x25\xac\x8f\x94\x3e\x15\x1c\x59\xdb\x2d\x37\x9e\x8f\x9d\x20\x11\x1f\xc2\xbf\x38\xea\x99\x92\xb4\x16\x10\x2b\xad\xb4\x49\xba\x98\x98\x3a\x0f\x12\x4e\xa1\xad\x68\xaf\x99\xa3\x20\x0d\x19\xb0\x9b\xac\x7b\xae\x9d\xbc\x17\x0e\x25\x9e\x98\xaf\x55\xb2\xa6\x3d\x12\x11\x52\x96\x97\xbd\x3e\xbc\xb3\x28\x10\x19\xab\x90\x9a\x54\x2f\xd0\xcf\x1f\x12\x27\x9a\x8e\xa0\x2e\x28\x66\x4e\x1d\x18\x62\x92\x8f\xb2\x20\x23\x53\x3f\x1d\x1f")); +snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1005, 3800, $ssrc, "\xab\x8e\x94\x44\x19\x22\x61\x40\x21\x2f\x9c\x8e\x9d\x23\x14\x25\xce\x4d\x2a\xf7\x96\x8f\xb1\x18\x13\x2e\xb7\xe8\x36\xb3\x94\x96\x3c\x10\x15\x4d\xaa\xc5\x4b\xa8\x95\x9f\x20\x0e\x1a\xb6\xa0\xbc\xf5\xa4\x99\xb8\x16\x0e\x26\xa1\x9d\xbb\xdd\xa5\x9f\x3c\x10\x10\x4c\x99\x9b\xc5\x78\xaa\xac\x24\x0f\x18\xac\x93\x9d\x5f\x4a\xb1\xc7\x1c\x0f\x25\x9b\x90\xa3\x36\x39\xbf\x47\x18\x14\x56\x92\x90\xb4\x27\x2f\xd7\x34\x18\x1c\xab\x8e\x95\x4b\x1d\x2c\xfe\x2f\x1b\x2c\x9b\x8d\x9d\x27\x19\x2c\xe7\x30\x20\x6d\x94\x8f\xaf\x1a\x17\x34\xc8\x37\x2b\xaf\x91\x94\x3f\x12\x18\x4e\xb6\x45\x3d\xa3\x91\x9e\x20\x0f\x1c\xbc\xab\x6c\xf5\x9e\x95\xb3\x16\x0e\x27\xa7\xa5")); +snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1006, 3960, $ssrc, "\xd6\xc6\x9d\x9b\x3d\x0f\x11\x49\x9c\xa1\xd4\xbf\x9f\xa6\x22\x0e\x18\xaf\x96\xa2\x6e\xc6\xa5\xbe\x19\x0e\x24\x9d\x93\xa8\x40\xe1\xae\x42\x15\x12\x4e\x94\x93\xb7\x2e\x4e\xbe\x2d\x14\x1a\xab\x8f\x97\x52\x25\x3e\xdc\x26\x16\x28\x9b\x8e\x9e\x2b\x1e\x3a\x61\x25\x1b\x5d\x93\x8f\xaf\x1d\x1c\x3d\x67\x27\x24\xad\x8f\x93\x45\x15\x1c\x53\xd7\x2d\x35\x9f\x8f\x9c\x22\x11\x1f\xc5\xbe\x38\x7a\x9a\x91\xb0\x17\x10\x29\xad\xb3\x4a\xbc\x98\x98\x3e\x10\x12\x48\xa1\xad\x6a\xb1\x9a\xa1\x21\x0e\x18\xb3\x9b\xab\x7d\xaf\x9d\xb9\x18\x0e\x23\x9f\x97\xae\x55\xb4\xa5\x40\x12\x10\x49\x96\x97\xbb\x3d\xbd\xb2\x29\x10\x18\xac\x90\x99\x5d\x2f\xd4\xcd\x1f\x12\x25\x9b")); +# pause +snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1007, 4120, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1008, 4280, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1009, 4440, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1009, 4440, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1010, 4600, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1011, 4760, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1011, 4760, $ssrc, "\xff" x 160)); +# next event +snd($sock_a, $port_b, rtp(0, 1012, 4920, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1012, 4920, $ssrc, "\xff\x96\x8e\x99\xdd\x1f\x1d\x2c\x69\xe9\x39\x2d\x50\xa3\x95\x97\xbd\x1a\x0e\x12\x38\x9d\x93\x9b\xbf\x30\x2f\x4f\xdc\x39\x20\x1d\x33\xa2\x90\x91\xaa\x1f\x0f\x12\x2c\xa9\x9c\xa3\xc2\x55\xc9\xaf\xb8\x30\x18\x14\x24\xa7\x8f\x8e\xa0\x2a\x14\x16\x2a\xbc\xac\xbc\x61\xcf\xa8\x9d\xa6\x36\x15\x0f\x1b\xb4\x92\x8f\x9d\x3e\x1d\x1e\x31\xe0\xfe\x36\x30\xd3\x9e\x94\x9b\x50\x15\x0d\x17\xe3\x99\x93\x9e\xee\x2c\x30\x5b\xf0\x32\x1f\x1f\x4c\x9c\x8f\x94\xbe\x19\x0e\x15\x3d\xa2\x9b\xa7\xd2\x52\xc3\xaf\xc4\x29\x16\x16\x2f\x9e\x8e\x90\xac\x20\x13\x18\x34\xb2\xac\xc0\x61\xc2\xa5\x9d\xad\x29\x12\x10\x23\xa5\x8f\x90\xa5\x2d\x1b\x1f\x39\xd1\x65\x34\x36\xbb\x9b")); +snd($sock_a, $port_b, rtp(0, 1013, 5080, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1013, 5080, $ssrc, "\x94\x9f\x2f\x11\x0e\x1c\xb3\x95\x94\xa4\x45\x2a\x33\x69\x60\x2d\x1e\x23\xc7\x98\x8f\x98\x49\x15\x0e\x1a\xda\x9d\x9c\xab\x7d\x53\xbe\xb1\xe8\x22\x15\x19\x4d\x98\x8d\x94\xc3\x1b\x12\x1b\x48\xac\xac\xc7\x69\xba\xa2\x9f\xbb\x1f\x10\x12\x2f\x9c\x8e\x93\xb0\x25\x1a\x22\x44\xcb\x57\x34\x3d\xae\x99\x96\xa9\x23\x0f\x0f\x24\xa6\x93\x96\xac\x36\x29\x37\x7c\x4e\x29\x1e\x29\xb0\x94\x8f\x9e\x2d\x11\x0f\x1f\xb6\x9b\x9d\xb0\x55\x58\xbc\xb5\x49\x1e\x15\x1d\xbe\x94\x8e\x99\x45\x17\x12\x1f\xd9\xa9\xad\xce\xfa\xb3\xa0\xa2\xef\x1b\x0f\x16\x52\x97\x8e\x96\xcb\x1e\x1a\x26\x59\xc8\x4e\x35\x4d\xa8\x97\x98\xb8\x1c\x0e\x11\x31\x9d\x91\x98\xb9\x2d\x29\x3b\xf5")); +snd($sock_a, $port_b, rtp(0, 1014, 5240, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1014, 5240, $ssrc, "\x43\x27\x1f\x32\xa6\x92\x91\xa7\x21\x0f\x10\x28\xa9\x99\x9e\xba\x49\x60\xba\xbb\x38\x1b\x16\x23\xab\x90\x8e\x9e\x2d\x14\x13\x26\xbc\xa7\xaf\xd8\xde\xae\xa0\xa7\x3d\x17\x0f\x1a\xba\x93\x8e\x9b\x44\x1b\x1b\x2b\xe0\xc8\x48\x37\xe4\xa2\x96\x9b\x6f\x17\x0e\x15\x5d\x99\x91\x9c\xd7\x29\x29\x3f\xf8\x3c\x24\x21\x46\x9e\x90\x94\xb8\x1a\x0e\x14\x37\xa1\x99\xa1\xc8\x43\x76\xba\xc5\x2d\x19\x17\x2d\xa0\x8f\x8f\xa8\x21\x11\x16\x2e\xaf\xa6\xb2\xe5\xcf\xab\xa0\xad\x2d\x14\x10\x20\xa8\x90\x8f\xa1\x2e\x19\x1c\x31\xcb\xc9\x44\x3b\xc2\x9e\x96\x9f\x36\x13\x0e\x1a\xb8\x95\x92\xa0\x48\x26\x2a\x48\x73\x36\x23\x25\xd4\x9a\x90\x98\x5c\x15\x0e\x18\x72\x9c\x99")); +snd($sock_a, $port_b, rtp(0, 1015, 5400, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1015, 5400, $ssrc, "\xa6\xe8\x3f\xe7\xba\xdd\x27\x18\x1a\x43\x9a\x8e\x93\xbb\x1b\x10\x19\x3e\xaa\xa5\xb7\xf4\xc6\xa9\xa2\xba\x23\x12\x12\x2c\x9e\x8e\x91\xac\x25\x18\x1e\x3c\xc1\xcd\x41\x40\xb5\x9c\x97\xa8\x27\x10\x0f\x21\xa8\x92\x93\xa8\x35\x24\x2c\x50\x61\x30\x23\x2b\xb7\x97\x90\x9d\x31\x11\x0e\x1c\xb9\x9a\x9a\xab\x52\x3f\xd9\xbc\x54\x22\x18\x1d\xca\x96\x8e\x97\x52\x17\x10\x1c\xef\xa5\xa6\xbc\xff\xbe\xa7\xa5\xd8\x1d\x10\x16\x45\x98\x8e\x95\xbf\x1e\x17\x20\x4d\xbc\xd2\x3f\x4e\xad\x9a\x99\xb4\x1e\x0e\x10\x2d\x9e\x90\x96\xb2\x2c\x22\x2f\x5c\x54\x2d\x24\x32\xaa\x94\x91\xa5\x24\x0f\x0f\x24\xaa\x98\x9b\xb2\x43\x3f\xcf\xc0\x3e\x1e\x18\x23\xaf\x92\x8e\x9c\x2f")); +snd($sock_a, $port_b, rtp(0, 1016, 5560, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1016, 5560, $ssrc, "\x13\x11\x21\xbd\xa2\xa8\xc3\xfa\xb9\xa6\xa9\x45\x19\x10\x1a\xc2\x94\x8e\x99\x4e\x1a\x18\x26\xeb\xba\xdd\x40\x7d\xa7\x99\x9c\xda\x19\x0e\x14\x4a\x99\x90\x99\xc9\x26\x23\x34\x6d\x4b\x2b\x25\x41\xa1\x92\x94\xb3\x1c\x0e\x12\x30\xa0\x96\x9d\xbe\x3b\x41\xcc\xc9\x34\x1c\x19\x2c\xa3\x8f\x8f\xa5\x23\x10\x13\x2a\xaf\xa0\xaa\xcd\xeb\xb4\xa6\xae\x31\x16\x11\x1f\xab\x90\x8e\x9e\x30\x18\x19\x2c\xc8\xb9\xf0\x43\xcc\xa2\x99\x9f\x3c\x14\x0e\x19\xbe\x95\x90\x9d\x4e\x22\x24\x3a\xfa\x43\x2a\x28\xec\x9d\x91\x98\xe4\x16\x0d\x16\x51\x9c\x96\xa0\xd7\x37\x45\xca\xda\x2c\x1b\x1b\x3d\x9c\x8e\x92\xb4\x1c\x0f\x16\x38\xa8\xa0\xad\xda\xdd\xb0\xa7\xb9\x28\x14\x13")); +# pause +snd($sock_a, $port_b, rtp(0, 1017, 5720, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1017, 5720, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1018, 5880, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1018, 5880, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1019, 6040, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1019, 6040, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1020, 6200, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1020, 6200, $ssrc, "\xff" x 160)); +snd($sock_a, $port_b, rtp(0, 1021, 6360, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1021, 6360, $ssrc, "\xff" x 160)); +# resume +snd($sock_a, $port_b, rtp(0, 1022, 6520, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1022, 6520, $ssrc, "\x00" x 160)); + + + + +# RFC payload type present + +($sock_a, $sock_b) = new_call([qw(198.51.100.1 6010)], [qw(198.51.100.3 6012)]); + +($port_a) = offer('multi- no transcoding, RFC payload type present', + { ICE => 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < 'default' }, < 'remove', replace => ['origin'], flags => ['inject DTMF'] }, < ft(), code => '0', volume => 10, duration => 100 }); +$resp = rtpe_req('play DTMF', 'inject DTMF towards B', + { 'from-tag' => ft(), code => '1', volume => 6, duration => 100 }); + +snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96 | 0x80, 1002, 3320, $ssrc, "\x00\x0a\x00\xa0")); +snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1003, 3320, $ssrc, "\x00\x0a\x01\x40")); +snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1004, 3320, $ssrc, "\x00\x0a\x01\xe0")); +snd($sock_a, $port_b, rtp(0, 1005, 3800, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1005, 3320, $ssrc, "\x00\x0a\x02\x80")); +snd($sock_a, $port_b, rtp(0, 1006, 3960, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1006, 3320, $ssrc, "\x00\x0a\x03\x20")); +snd($sock_a, $port_b, rtp(0, 1007, 4120, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1007, 3320, $ssrc, "\x00\x8a\x03\xc0")); +rcv($sock_b, $port_a, rtpm(96, 1008, 3320, $ssrc, "\x00\x8a\x03\xc0")); +rcv($sock_b, $port_a, rtpm(96, 1009, 3320, $ssrc, "\x00\x8a\x03\xc0")); +snd($sock_a, $port_b, rtp(0, 1008, 4280, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1010, 4280, $ssrc, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1009, 4440, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1011, 4440, $ssrc, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1012, 4600, $ssrc, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1011, 4760, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1013, 4760, $ssrc, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1012, 4920, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96 | 0x80, 1014, 4920, $ssrc, "\x01\x06\x00\xa0")); +snd($sock_a, $port_b, rtp(0, 1013, 5080, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1015, 4920, $ssrc, "\x01\x06\x01\x40")); +snd($sock_a, $port_b, rtp(0, 1014, 5240, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1016, 4920, $ssrc, "\x01\x06\x01\xe0")); +snd($sock_a, $port_b, rtp(0, 1015, 5400, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1017, 4920, $ssrc, "\x01\x06\x02\x80")); +snd($sock_a, $port_b, rtp(0, 1016, 5560, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1018, 4920, $ssrc, "\x01\x06\x03\x20")); +snd($sock_a, $port_b, rtp(0, 1017, 5720, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(96, 1019, 4920, $ssrc, "\x01\x86\x03\xc0")); +rcv($sock_b, $port_a, rtpm(96, 1020, 4920, $ssrc, "\x01\x86\x03\xc0")); +rcv($sock_b, $port_a, rtpm(96, 1021, 4920, $ssrc, "\x01\x86\x03\xc0")); +snd($sock_a, $port_b, rtp(0, 1018, 5880, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1022, 5880, $ssrc, "\x00" x 160)); + + + + + +# SDP in/out tests, various ICE options new_call; -offer('plain SDP, ICE default', { ICE => 'default' }, < 'remove' }, < 'remove' }, < 'force' }, < 'default' }, < 'default' }, < 'force' }, < 'optional' }, < 'remove' }, < 'remove' }, < 'remove' }, < 'optional' }, < 'remove', replace => [qw(origin session-connection)], - flags => [qw(codec-mask-opus codec-mask-G722 codec-strip-G7221)] }, < '3.4.5.6', + flags => ['full-rtcp-attribute'], ICE => 'optional', }, < 'remove', replace => [qw(origin session-connection)] }, < 'remove', replace => [qw(origin session-connection)], - flags => [qw(codec-mask-opus codec-mask-G722 codec-strip-G7221 always-transcode)] }, < 'optional' }, < 'remove', replace => [qw(origin session-connection)] }, < 'optional' }, < 'remove', replace => ['origin'] }, < 'force' }, < 'remove', replace => ['origin'] }, < 'optional' }, < 'remove', replace => ['origin'], - codec => { transcode => ['PCMA'] }}, < 'force' }, < ['origin'] }, < 'optional' }, < 'remove', replace => ['origin'], - codec => { transcode => ['PCMA'] }}, < 'force' }, < ['origin'] }, < 'force' }, < 'remove', replace => ['origin'], - codec => { transcode => ['pcma'] }}, < 'default' }, < ['origin'] }, < 'default' }, < 'remove', replace => ['origin'] }, < 'default' }, < ft(), blob => $wav_file }); -is $resp->{duration}, 100, 'media duration'; - -(undef, $seq, $ts, $ssrc) = rcv($sock_a, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); -rcv($sock_a, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2)); -rcv($sock_a, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3)); -rcv($sock_a, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4)); -rcv($sock_a, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5)); - - - - -($sock_a, $sock_b) = new_call([qw(198.51.100.1 2020)], [qw(198.51.100.3 2022)]); - -offer('media playback, side A', { ICE => 'remove', replace => ['origin'] }, < ['origin'] }, < ft(), blob => $wav_file }); -is $resp->{duration}, 100, 'media duration'; - -(undef, $seq, $ts, $ssrc) = rcv($sock_a, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); -rcv($sock_a, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2)); -rcv($sock_a, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3)); -rcv($sock_a, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4)); -rcv($sock_a, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5)); - - - - -($sock_a, $sock_b) = new_call([qw(198.51.100.1 2030)], [qw(198.51.100.3 2032)]); - -offer('media playback, side B', { ICE => 'remove', replace => ['origin'] }, < 'force' }, < ['origin'] }, < tt(), blob => $wav_file }); -is $resp->{duration}, 100, 'media duration'; - -(undef, $seq, $ts, $ssrc) = rcv($sock_b, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); -rcv($sock_b, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2)); -rcv($sock_b, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3)); -rcv($sock_b, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4)); -rcv($sock_b, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5)); - -$resp = rtpe_req('play media', 'restart media playback', { 'from-tag' => tt(), blob => $wav_file }); -is $resp->{duration}, 100, 'media duration'; - -$ts += 160 * 5; -my $old_ts = $ts; -(undef, $ts) = rcv($sock_b, -1, rtpm(8 | 0x80, $seq + 5, -1, $ssrc, $pcma_1)); -print("ts $ts old $old_ts\n"); -SKIP: { - skip 'random timestamp too close to margin', 2 if $old_ts < 500 or $old_ts > 4294966795; - cmp_ok($ts, '<', $old_ts + 500, 'ts within < range'); - cmp_ok($ts, '>', $old_ts - 500, 'ts within > range'); -} -rcv($sock_b, -1, rtpm(8, $seq + 6, $ts + 160 * 1, $ssrc, $pcma_2)); -rcv($sock_b, -1, rtpm(8, $seq + 7, $ts + 160 * 2, $ssrc, $pcma_3)); -rcv($sock_b, -1, rtpm(8, $seq + 8, $ts + 160 * 3, $ssrc, $pcma_4)); -rcv($sock_b, -1, rtpm(8, $seq + 9, $ts + 160 * 4, $ssrc, $pcma_5)); - - - - -($sock_a, $sock_b) = new_call([qw(198.51.100.9 2020)], [qw(198.51.100.9 2022)]); +new_call; -offer('media playback, side A, select by label', { ICE => 'remove', replace => ['origin'], - label => 'foobar' }, < 'force' }, < ['origin'], label => 'blah' }, < 'foobar', - blob => $wav_file }); -is $resp->{duration}, 100, 'media duration'; - -(undef, $seq, $ts, $ssrc) = rcv($sock_a, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); -rcv($sock_a, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2)); -rcv($sock_a, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3)); -rcv($sock_a, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4)); -rcv($sock_a, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5)); - - - - -($sock_a, $sock_b) = new_call([qw(198.51.100.9 2030)], [qw(198.51.100.9 2032)]); - -offer('media playback, side B, select by label', { ICE => 'remove', replace => ['origin'], - label => 'quux' }, < ['origin'], label => 'meh' }, < 'remove' }, < 'meh', blob => $wav_file }); -is $resp->{duration}, 100, 'media duration'; - -(undef, $seq, $ts, $ssrc) = rcv($sock_b, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); -rcv($sock_b, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2)); -rcv($sock_b, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3)); -rcv($sock_b, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4)); -rcv($sock_b, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5)); - - - - - -# ptime tests - -($sock_a, $sock_b) = new_call([qw(198.51.100.1 3000)], [qw(198.51.100.3 3002)]); +new_call; -($port_a) = offer('default ptime in/out', { ICE => 'remove', replace => ['origin'] }, < 'remove', replace => [qw(origin session-connection)], + flags => [qw(codec-mask-opus codec-mask-G722 codec-strip-G7221)] }, < 'remove', replace => ['origin'] }, < 'remove', replace => [qw(origin session-connection)] }, < 'remove', replace => ['origin'] }, < 'remove', replace => [qw(origin session-connection)], + flags => [qw(codec-mask-opus codec-mask-G722 codec-strip-G7221 always-transcode)] }, < 'remove', replace => ['origin'] }, < 'remove', replace => [qw(origin session-connection)] }, < 'remove', replace => ['origin'], ptime => 30 }, < 'remove', replace => ['origin'] }, < 'remove', replace => ['origin'] }, < 'remove', replace => ['origin'] }, <B: 5x 20 ms packets -> 3x 30 ms snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160)); -Time::HiRes::usleep(20000); # 20 ms, needed to ensure that packet 1000 is received first -snd($sock_a, $port_b, rtp(0, 1001, 3160, 0x1234, "\x00" x 160)); -($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 240)); -snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1001, 3240, $ssrc, "\x00" x 240)); -snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); -snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1002, 3480, $ssrc, "\x00" x 240)); - -# A->B: 60 ms packet -> 2x 30 ms -# also perform TS and seq reset -snd($sock_a, $port_b, rtp(0, 8000, 500000, 0x1234, "\x00" x 480)); -rcv($sock_b, $port_a, rtpm(0, 1003, 3720, $ssrc, "\x00" x 240)); -rcv($sock_b, $port_a, rtpm(0, 1004, 3960, $ssrc, "\x00" x 240)); - -# B->A: 2x 60 ms packet -> 6x 20 ms -snd($sock_b, $port_a, rtp(0, 4000, 5000, 0x4567, "\x88" x 480)); -($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 5000, -1, "\x88" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4001, 5160, $ssrc, "\x88" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4002, 5320, $ssrc, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4001, 5480, 0x4567, "\x88" x 480)); -rcv($sock_a, $port_b, rtpm(0, 4003, 5480, $ssrc, "\x88" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4004, 5640, $ssrc, "\x88" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4005, 5800, $ssrc, "\x88" x 160)); - -# B->A: 4x 10 ms packet -> 2x 20 ms -snd($sock_b, $port_a, rtp(0, 4002, 5960, 0x4567, "\x88" x 80)); -snd($sock_b, $port_a, rtp(0, 4003, 6040, 0x4567, "\x88" x 80)); -rcv($sock_a, $port_b, rtpm(0, 4006, 5960, $ssrc, "\x88" x 160)); -# out of order packet input -snd($sock_b, $port_a, rtp(0, 4005, 6200, 0x4567, "\x88" x 80)); -Time::HiRes::usleep(10000); -snd($sock_b, $port_a, rtp(0, 4004, 6120, 0x4567, "\x88" x 80)); -rcv($sock_a, $port_b, rtpm(0, 4007, 6120, $ssrc, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4006, 6280, 0x4567, "\x88" x 80)); -snd($sock_b, $port_a, rtp(0, 4007, 6360, 0x4567, "\x88" x 80)); -rcv($sock_a, $port_b, rtpm(0, 4008, 6280, $ssrc, "\x88" x 160)); - - +rcv($sock_b, $port_a, rtpm(0, 1000, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1000, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1001, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1001, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1010, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1010, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(8, 1000, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1000, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(8, 1000, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1000, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(8, 1001, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1001, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(8, 1010, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(8, 1010, 3000, 0x1234, "\x00" x 160)); -($sock_a, $sock_b) = new_call([qw(198.51.100.1 3008)], [qw(198.51.100.3 3010)]); +($sock_a, $sock_b) = new_call([qw(198.51.100.1 2010)], [qw(198.51.100.3 2012)]); -($port_a) = offer('default ptime in, no change, ptime=30 response', { - ICE => 'remove', replace => ['origin'] }, < 'remove', replace => ['origin'], + codec => { transcode => ['PCMA'] }}, < 'remove', replace => ['origin'] }, < ['origin'] }, <B: 20 ms unchanged -snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160)); -($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 160)); -# A->B: 30 ms unchanged -snd($sock_a, $port_b, rtp(0, 1001, 3160, 0x1234, "\x00" x 240)); -rcv($sock_b, $port_a, rtpm(0, 1001, 3160, $ssrc, "\x00" x 240)); +snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1000, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1000, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1001, 3160, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1001, 3160, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1010, 4600, 0x1234, "\x00" x 160)); -# B->A: 20 ms unchanged -snd($sock_b, $port_a, rtp(0, 4000, 5000, 0x4567, "\x88" x 160)); -($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 5000, -1, "\x88" x 160)); -# B->A: 30 ms unchanged -snd($sock_b, $port_a, rtp(0, 4001, 5160, 0x4567, "\x88" x 240)); -rcv($sock_a, $port_b, rtpm(0, 4001, 5160, $ssrc, "\x88" x 240)); +snd($sock_b, $port_a, rtp(0, 2000, 4000, 0x5678, "\x00" x 160)); +($ssrc) = rcv($sock_a, $port_b, rtpm(0, 2000, 4000, -1, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 2000, 4000, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2000, 4000, $ssrc, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 2001, 4000+160, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2001, 4000+160, $ssrc, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 2010, 4000+1600, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2010, 4000+1600, $ssrc, "\x00" x 160)); + +snd($sock_b, $port_a, rtp(8, 2011, 4000+160*11, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2011, 4000+160*11, $ssrc, ")" x 160)); +# #664 seq reset +snd($sock_b, $port_a, rtp(8, 62011, 4000+160*12, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2012, 4000+160*12, $ssrc, ")" x 160)); +snd($sock_b, $port_a, rtp(8, 62012, 4000+160*13, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2013, 4000+160*13, $ssrc, ")" x 160)); +snd($sock_b, $port_a, rtp(0, 62013, 4000+160*14, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2014, 4000+160*14, $ssrc, "\x00" x 160)); -($sock_a, $sock_b) = new_call([qw(198.51.100.1 3012)], [qw(198.51.100.3 3014)]); +($sock_a, $sock_b) = new_call([qw(198.51.100.1 2210)], [qw(198.51.100.3 2212)]); -($port_a) = offer('ptime=50 in, change to 30, default response', { - ICE => 'remove', replace => ['origin'], ptime => 30 }, < 'remove', replace => ['origin'], + codec => { transcode => ['PCMA'] }}, < 'remove', replace => ['origin'] }, < ['origin'] }, <B: 2x 50 ms -> 3x 30 ms (plus 10 ms left) -snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 400)); -($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 240)); -snd($sock_a, $port_b, rtp(0, 1001, 3400, 0x1234, "\x00" x 400)); -rcv($sock_b, $port_a, rtpm(0, 1001, 3240, $ssrc, "\x00" x 240)); -rcv($sock_b, $port_a, rtpm(0, 1002, 3480, $ssrc, "\x00" x 240)); -# A->B: add another 20 ms for another full 30 ms -snd($sock_a, $port_b, rtp(0, 1002, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1003, 3720, $ssrc, "\x00" x 240)); +snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1000, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1000, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1001, 3160, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1001, 3160, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1010, 4600, 0x1234, "\x00" x 160)); -# 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)); +snd($sock_b, $port_a, rtp(0, 2000, 4000, 0x5678, "\x00" x 160)); +($ssrc) = rcv($sock_a, $port_b, rtpm(0, 2000, 4000, -1, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 2000, 4000, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2000, 4000, $ssrc, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 2001, 4000+160, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2001, 4000+160, $ssrc, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 2010, 4000+1600, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2010, 4000+1600, $ssrc, "\x00" x 160)); + +snd($sock_b, $port_a, rtp(8, 2011, 4000+160*11, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2011, 4000+160*11, $ssrc, ")" x 160)); +# #664 seq reset +snd($sock_b, $port_a, rtp(8, 62011, 4000+160*12, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2012, 4000+160*12, $ssrc, ")" x 160)); +snd($sock_b, $port_a, rtp(8, 62012, 4000+160*13, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2013, 4000+160*13, $ssrc, ")" x 160)); +snd($sock_b, $port_a, rtp(0, 62013, 4000+160*14, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2014, 4000+160*14, $ssrc, "\x00" x 160)); -($sock_a, $sock_b) = new_call([qw(198.51.100.1 3016)], [qw(198.51.100.3 3018)]); +($sock_a, $sock_b) = new_call([qw(198.51.100.1 2216)], [qw(198.51.100.3 2218)]); -($port_a) = offer('ptime=50 in, change to 30, reverse to 50, response 30', { - ICE => 'remove', replace => ['origin'], ptime => 30, 'ptime-reverse' => 50 }, < 'remove', replace => ['origin'], + codec => { transcode => ['pcma'] }}, < 'remove', replace => ['origin'] }, < ['origin'] }, <B: 2x 50 ms -> 3x 30 ms (plus 10 ms left) -snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 400)); -($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 240)); -snd($sock_a, $port_b, rtp(0, 1001, 3400, 0x1234, "\x00" x 400)); -rcv($sock_b, $port_a, rtpm(0, 1001, 3240, $ssrc, "\x00" x 240)); -rcv($sock_b, $port_a, rtpm(0, 1002, 3480, $ssrc, "\x00" x 240)); -# A->B: add another 20 ms for another full 30 ms -snd($sock_a, $port_b, rtp(0, 1002, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1003, 3720, $ssrc, "\x00" x 240)); +snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1000, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1000, 3000, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1001, 3160, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1001, 3160, 0x1234, "\x00" x 160)); +snd($sock_a, $port_b, rtp(0, 1010, 4600, 0x1234, "\x00" x 160)); +rcv($sock_b, $port_a, rtpm(0, 1010, 4600, 0x1234, "\x00" x 160)); + +snd($sock_b, $port_a, rtp(0, 2000, 4000, 0x5678, "\x00" x 160)); +($ssrc) = rcv($sock_a, $port_b, rtpm(0, 2000, 4000, -1, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 2000, 4000, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2000, 4000, $ssrc, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 2001, 4000+160, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2001, 4000+160, $ssrc, "\x00" x 160)); +snd($sock_b, $port_a, rtp(0, 2010, 4000+1600, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2010, 4000+1600, $ssrc, "\x00" x 160)); + +snd($sock_b, $port_a, rtp(8, 2011, 4000+160*11, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2011, 4000+160*11, $ssrc, ")" x 160)); +# #664 seq reset +snd($sock_b, $port_a, rtp(8, 62011, 4000+160*12, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2012, 4000+160*12, $ssrc, ")" x 160)); +snd($sock_b, $port_a, rtp(8, 62012, 4000+160*13, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2013, 4000+160*13, $ssrc, ")" x 160)); +snd($sock_b, $port_a, rtp(0, 62013, 4000+160*14, 0x5678, "\x00" x 160)); +rcv($sock_a, $port_b, rtpm(0, 2014, 4000+160*14, $ssrc, "\x00" x 160)); -# 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)); -($sock_a, $sock_b) = new_call([qw(198.51.100.1 3012)], [qw(198.51.100.3 3014)]); +# media playback + +($sock_a) = new_call([qw(198.51.100.1 2020)]); -($port_a) = offer('ptime=50 in, change to 30, response 30', { - ICE => 'remove', replace => ['origin'], ptime => 30 }, < 'remove', replace => ['origin'] }, < 'remove', replace => ['origin'] }, <B: 2x 50 ms -> 3x 30 ms (plus 10 ms left) -snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 400)); -($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 240)); -snd($sock_a, $port_b, rtp(0, 1001, 3400, 0x1234, "\x00" x 400)); -rcv($sock_b, $port_a, rtpm(0, 1001, 3240, $ssrc, "\x00" x 240)); -rcv($sock_b, $port_a, rtpm(0, 1002, 3480, $ssrc, "\x00" x 240)); -# A->B: add another 20 ms for another full 30 ms -snd($sock_a, $port_b, rtp(0, 1002, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1003, 3720, $ssrc, "\x00" x 240)); +$resp = rtpe_req('play media', 'media playback, offer only', { 'from-tag' => ft(), blob => $wav_file }); +is $resp->{duration}, 100, 'media duration'; -# 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)); +(undef, $seq, $ts, $ssrc) = rcv($sock_a, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); +rcv($sock_a, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2)); +rcv($sock_a, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3)); +rcv($sock_a, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4)); +rcv($sock_a, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5)); -($sock_a, $sock_b) = new_call([qw(198.51.100.1 3016)], [qw(198.51.100.3 3018)]); +($sock_a, $sock_b) = new_call([qw(198.51.100.1 2020)], [qw(198.51.100.3 2022)]); -($port_a) = offer('ptime=50 in, change to 30, reverse to 50, default response', { - ICE => 'remove', replace => ['origin'], ptime => 30, 'ptime-reverse' => 50 }, < 'remove', replace => ['origin'] }, < 'remove', replace => ['origin'] }, < ['origin'] }, <B: 2x 50 ms -> 3x 30 ms (plus 10 ms left) -snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 400)); -($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 240)); -snd($sock_a, $port_b, rtp(0, 1001, 3400, 0x1234, "\x00" x 400)); -rcv($sock_b, $port_a, rtpm(0, 1001, 3240, $ssrc, "\x00" x 240)); -rcv($sock_b, $port_a, rtpm(0, 1002, 3480, $ssrc, "\x00" x 240)); -# A->B: add another 20 ms for another full 30 ms -snd($sock_a, $port_b, rtp(0, 1002, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1003, 3720, $ssrc, "\x00" 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)); +$resp = rtpe_req('play media', 'media playback, side A', { 'from-tag' => ft(), blob => $wav_file }); +is $resp->{duration}, 100, 'media duration'; + +(undef, $seq, $ts, $ssrc) = rcv($sock_a, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); +rcv($sock_a, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2)); +rcv($sock_a, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3)); +rcv($sock_a, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4)); +rcv($sock_a, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5)); -($sock_a, $sock_b) = new_call([qw(198.51.100.1 3016)], [qw(198.51.100.3 3018)]); +($sock_a, $sock_b) = new_call([qw(198.51.100.1 2030)], [qw(198.51.100.3 2032)]); -($port_a) = offer('ptime=50 in, change to 30, reverse to 20, default response', { - ICE => 'remove', replace => ['origin'], ptime => 30, 'ptime-reverse' => 20 }, < 'remove', replace => ['origin'] }, < 'remove', replace => ['origin'] }, < ['origin'] }, <B: 2x 50 ms -> 3x 30 ms (plus 10 ms left) -snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 400)); -($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 240)); -snd($sock_a, $port_b, rtp(0, 1001, 3400, 0x1234, "\x00" x 400)); -rcv($sock_b, $port_a, rtpm(0, 1001, 3240, $ssrc, "\x00" x 240)); -rcv($sock_b, $port_a, rtpm(0, 1002, 3480, $ssrc, "\x00" x 240)); -# A->B: add another 20 ms for another full 30 ms -snd($sock_a, $port_b, rtp(0, 1002, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1003, 3720, $ssrc, "\x00" x 240)); -# B->A: 4x 30 ms -> 6x 20 ms -snd($sock_b, $port_a, rtp(0, 4000, 5000, 0x4567, "\x88" x 240)); -($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 5000, -1, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4001, 5240, 0x4567, "\x88" x 240)); -rcv($sock_a, $port_b, rtpm(0, 4001, 5160, $ssrc, "\x88" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4002, 5320, $ssrc, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4002, 5480, 0x4567, "\x88" x 240)); -rcv($sock_a, $port_b, rtpm(0, 4003, 5480, $ssrc, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4003, 5720, 0x4567, "\x88" x 240)); -rcv($sock_a, $port_b, rtpm(0, 4004, 5640, $ssrc, "\x88" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4005, 5800, $ssrc, "\x88" x 160)); +$resp = rtpe_req('play media', 'media playback, side B', { 'from-tag' => tt(), blob => $wav_file }); +is $resp->{duration}, 100, 'media duration'; +(undef, $seq, $ts, $ssrc) = rcv($sock_b, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); +rcv($sock_b, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2)); +rcv($sock_b, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3)); +rcv($sock_b, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4)); +rcv($sock_b, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5)); + +$resp = rtpe_req('play media', 'restart media playback', { 'from-tag' => tt(), blob => $wav_file }); +is $resp->{duration}, 100, 'media duration'; + +$ts += 160 * 5; +my $old_ts = $ts; +(undef, $ts) = rcv($sock_b, -1, rtpm(8 | 0x80, $seq + 5, -1, $ssrc, $pcma_1)); +print("ts $ts old $old_ts\n"); +SKIP: { + skip 'random timestamp too close to margin', 2 if $old_ts < 500 or $old_ts > 4294966795; + cmp_ok($ts, '<', $old_ts + 500, 'ts within < range'); + cmp_ok($ts, '>', $old_ts - 500, 'ts within > range'); +} +rcv($sock_b, -1, rtpm(8, $seq + 6, $ts + 160 * 1, $ssrc, $pcma_2)); +rcv($sock_b, -1, rtpm(8, $seq + 7, $ts + 160 * 2, $ssrc, $pcma_3)); +rcv($sock_b, -1, rtpm(8, $seq + 8, $ts + 160 * 3, $ssrc, $pcma_4)); +rcv($sock_b, -1, rtpm(8, $seq + 9, $ts + 160 * 4, $ssrc, $pcma_5)); -($sock_a, $sock_b) = new_call([qw(198.51.100.1 3016)], [qw(198.51.100.3 3018)]); -($port_a) = offer('ptime=50 in, change to 30, reverse to 20, response 40', { - ICE => 'remove', replace => ['origin'], ptime => 30, 'ptime-reverse' => 20 }, < 'remove', replace => ['origin'], + label => 'foobar' }, < 'remove', replace => ['origin'] }, < ['origin'], label => 'blah' }, <B: 2x 50 ms -> 3x 30 ms (plus 10 ms left) -snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 400)); -($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 240)); -snd($sock_a, $port_b, rtp(0, 1001, 3400, 0x1234, "\x00" x 400)); -rcv($sock_b, $port_a, rtpm(0, 1001, 3240, $ssrc, "\x00" x 240)); -rcv($sock_b, $port_a, rtpm(0, 1002, 3480, $ssrc, "\x00" x 240)); -# A->B: add another 20 ms for another full 30 ms -snd($sock_a, $port_b, rtp(0, 1002, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1003, 3720, $ssrc, "\x00" x 240)); -# B->A: 4x 30 ms -> 6x 20 ms -snd($sock_b, $port_a, rtp(0, 4000, 5000, 0x4567, "\x88" x 240)); -($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 5000, -1, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4001, 5240, 0x4567, "\x88" x 240)); -rcv($sock_a, $port_b, rtpm(0, 4001, 5160, $ssrc, "\x88" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4002, 5320, $ssrc, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4002, 5480, 0x4567, "\x88" x 240)); -rcv($sock_a, $port_b, rtpm(0, 4003, 5480, $ssrc, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4003, 5720, 0x4567, "\x88" x 240)); -rcv($sock_a, $port_b, rtpm(0, 4004, 5640, $ssrc, "\x88" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4005, 5800, $ssrc, "\x88" x 160)); +$resp = rtpe_req('play media', 'media playback, side A, select by label', { label => 'foobar', + blob => $wav_file }); +is $resp->{duration}, 100, 'media duration'; + +(undef, $seq, $ts, $ssrc) = rcv($sock_a, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); +rcv($sock_a, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2)); +rcv($sock_a, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3)); +rcv($sock_a, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4)); +rcv($sock_a, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5)); -($sock_a, $sock_b) = new_call([qw(198.51.100.1 3016)], [qw(198.51.100.3 3018)]); +($sock_a, $sock_b) = new_call([qw(198.51.100.9 2030)], [qw(198.51.100.9 2032)]); -($port_a) = offer('ptime=30 in, no change, reverse to 20, response 40', { - ICE => 'remove', replace => ['origin'], 'ptime-reverse' => 20 }, < 'remove', replace => ['origin'], + label => 'quux' }, < 'remove', replace => ['origin'] }, < ['origin'], label => 'meh' }, <B: 2x 50 ms -> 3x 30 ms (plus 10 ms left) -snd($sock_a, $port_b, rtp(0, 1000, 3000, 0x1234, "\x00" x 400)); -($ssrc) = rcv($sock_b, $port_a, rtpm(0, 1000, 3000, -1, "\x00" x 240)); -snd($sock_a, $port_b, rtp(0, 1001, 3400, 0x1234, "\x00" x 400)); -rcv($sock_b, $port_a, rtpm(0, 1001, 3240, $ssrc, "\x00" x 240)); -rcv($sock_b, $port_a, rtpm(0, 1002, 3480, $ssrc, "\x00" x 240)); -# A->B: add another 20 ms for another full 30 ms -snd($sock_a, $port_b, rtp(0, 1002, 3800, 0x1234, "\x00" x 160)); -rcv($sock_b, $port_a, rtpm(0, 1003, 3720, $ssrc, "\x00" x 240)); -# B->A: 4x 30 ms -> 6x 20 ms -snd($sock_b, $port_a, rtp(0, 4000, 5000, 0x4567, "\x88" x 240)); -($ssrc) = rcv($sock_a, $port_b, rtpm(0, 4000, 5000, -1, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4001, 5240, 0x4567, "\x88" x 240)); -rcv($sock_a, $port_b, rtpm(0, 4001, 5160, $ssrc, "\x88" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4002, 5320, $ssrc, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4002, 5480, 0x4567, "\x88" x 240)); -rcv($sock_a, $port_b, rtpm(0, 4003, 5480, $ssrc, "\x88" x 160)); -snd($sock_b, $port_a, rtp(0, 4003, 5720, 0x4567, "\x88" x 240)); -rcv($sock_a, $port_b, rtpm(0, 4004, 5640, $ssrc, "\x88" x 160)); -rcv($sock_a, $port_b, rtpm(0, 4005, 5800, $ssrc, "\x88" x 160)); +$resp = rtpe_req('play media', 'media playback, side B, select by label', { label => 'meh', blob => $wav_file }); +is $resp->{duration}, 100, 'media duration'; + +(undef, $seq, $ts, $ssrc) = rcv($sock_b, -1, rtpm(8 | 0x80, -1, -1, -1, $pcma_1)); +rcv($sock_b, -1, rtpm(8, $seq + 1, $ts + 160 * 1, $ssrc, $pcma_2)); +rcv($sock_b, -1, rtpm(8, $seq + 2, $ts + 160 * 2, $ssrc, $pcma_3)); +rcv($sock_b, -1, rtpm(8, $seq + 3, $ts + 160 * 3, $ssrc, $pcma_4)); +rcv($sock_b, -1, rtpm(8, $seq + 4, $ts + 160 * 4, $ssrc, $pcma_5)); + diff --git a/t/auto-daemon-tests.pl b/t/auto-daemon-tests.pl index 598ee63df..ad0821fa4 100755 --- a/t/auto-daemon-tests.pl +++ b/t/auto-daemon-tests.pl @@ -10523,6 +10523,7 @@ snd($sock_a, $port_b, rtp(0, 1001, 3160, 0x1234, "\x00" x 160)); snd($sock_a, $port_b, rtp(0, 1002, 3320, 0x1234, "\x00" x 160)); rcv($sock_b, $port_a, rtpm(0, 1001, 3240, $ssrc, "\x00" x 240)); snd($sock_a, $port_b, rtp(0, 1003, 3480, 0x1234, "\x00" x 160)); +Time::HiRes::usleep(1000); snd($sock_a, $port_b, rtp(0, 1004, 3640, 0x1234, "\x00" x 160)); rcv($sock_b, $port_a, rtpm(0, 1002, 3480, $ssrc, "\x00" x 240)); @@ -10544,6 +10545,7 @@ rcv($sock_a, $port_b, rtpm(0, 4005, 5800, $ssrc, "\x88" x 160)); # B->A: 4x 10 ms packet -> 2x 20 ms snd($sock_b, $port_a, rtp(0, 4002, 5960, 0x4567, "\x88" x 80)); +Time::HiRes::usleep(1000); snd($sock_b, $port_a, rtp(0, 4003, 6040, 0x4567, "\x88" x 80)); rcv($sock_a, $port_b, rtpm(0, 4006, 5960, $ssrc, "\x88" x 160)); # out of order packet input @@ -10552,6 +10554,7 @@ Time::HiRes::usleep(10000); snd($sock_b, $port_a, rtp(0, 4004, 6120, 0x4567, "\x88" x 80)); rcv($sock_a, $port_b, rtpm(0, 4007, 6120, $ssrc, "\x88" x 160)); snd($sock_b, $port_a, rtp(0, 4006, 6280, 0x4567, "\x88" x 80)); +Time::HiRes::usleep(1000); snd($sock_b, $port_a, rtp(0, 4007, 6360, 0x4567, "\x88" x 80)); rcv($sock_a, $port_b, rtpm(0, 4008, 6280, $ssrc, "\x88" x 160)); @@ -10683,6 +10686,7 @@ Time::HiRes::usleep(20000); # 20 ms, needed to ensure that packet 1000 is receiv 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)); +Time::HiRes::usleep(1000); 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 @@ -10756,6 +10760,7 @@ Time::HiRes::usleep(20000); # 20 ms, needed to ensure that packet 1000 is receiv 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)); +Time::HiRes::usleep(1000); 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 @@ -10829,6 +10834,7 @@ Time::HiRes::usleep(20000); # 20 ms, needed to ensure that packet 1000 is receiv 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)); +Time::HiRes::usleep(1000); 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 @@ -10901,6 +10907,7 @@ Time::HiRes::usleep(20000); # 20 ms, needed to ensure that packet 1000 is receiv 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)); +Time::HiRes::usleep(1000); 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 From 39a25b954dadfedc92dc1a7aa0df223fc261af3b Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 28 Jan 2021 14:07:53 -0500 Subject: [PATCH 05/13] TT#106101 mem leak fix for 554034eb7e Change-Id: I9c410211580d8513a203a29f898970a78175d08b --- daemon/udp_listener.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/daemon/udp_listener.c b/daemon/udp_listener.c index 66f3e6572..6ce3ae377 100644 --- a/daemon/udp_listener.c +++ b/daemon/udp_listener.c @@ -44,7 +44,7 @@ static void udp_listener_incoming(int fd, void *p, uintptr_t x) { continue; if (errno != EWOULDBLOCK && errno != EAGAIN) ilog(LOG_WARNING, "Error reading from UDP socket"); - return; + break; } udp_buf->str.s[len] = '\0'; @@ -61,6 +61,8 @@ static void udp_listener_incoming(int fd, void *p, uintptr_t x) { udp_buf = NULL; } } + if (udp_buf) + obj_put(udp_buf); } static void __ulc_free(void *p) { From f33877bfe3135f5dbf4340e07a9dccd7f6ee680d Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 28 Jan 2021 13:43:46 -0500 Subject: [PATCH 06/13] TT#102450 fix some timestamping issues Make sure G.722 rate multiplies is applied in the right places Don't trust encoders to return proper timestamps, but instead track them explicitly based on frame duration Change-Id: Ia9fa96cf662da97159fa170c3a3f37516889e1bd --- daemon/codec.c | 23 ++++++++++++----------- lib/codeclib.c | 6 ++++++ lib/codeclib.h | 1 + 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index fb69b2f30..17a1de118 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -1938,10 +1938,11 @@ static int packet_dtmf_fwd(struct codec_ssrc_handler *ch, struct transcode_packe struct media_packet *mp) { int payload_type = -1; // take from handler's output config - struct codec_ssrc_handler *output_ch = NULL; - struct codec_ssrc_handler *decoder_ch = NULL; if (ch->handler->dtmf_scaler) { + struct codec_ssrc_handler *output_ch = NULL; + struct codec_ssrc_handler *decoder_ch = NULL; + // this is actually a DTMF -> PCM handler // grab our underlying PCM transcoder struct codec_handler *decoder_handler = __decoder_handler(ch->handler, mp); @@ -1964,14 +1965,14 @@ static int packet_dtmf_fwd(struct codec_ssrc_handler *ch, struct transcode_packe if (ch->dtmf_ts != packet->ts) { // this is a new event ch->dtmf_ts = packet->ts; // start TS - ch->last_dtmf_event_ts = 0; // last shifted FIFO PTS + ch->last_dtmf_event_ts = 0; // last DTMF event duration } - unsigned long ts = output_ch->encoder->fifo_pts; + unsigned long ts = output_ch->encoder->next_pts / output_ch->encoder->def->clockrate_mult; // roll back TS to start of event ts -= ch->last_dtmf_event_ts; // adjust to output RTP TS - unsigned long packet_ts = ts / output_ch->encoder->def->clockrate_mult + output_ch->first_ts; + unsigned long packet_ts = ts + output_ch->first_ts; ilogs(transcoding, LOG_DEBUG, "Scaling DTMF packet timestamp and duration: TS %lu -> %lu " "(%u -> %u)", @@ -1986,18 +1987,18 @@ static int packet_dtmf_fwd(struct codec_ssrc_handler *ch, struct transcode_packe dtmf->duration = htons(duration); // shift forward our output RTP TS - output_ch->encoder->fifo_pts = ts + duration; + output_ch->encoder->next_pts = (ts + duration) * output_ch->encoder->def->clockrate_mult; output_ch->encoder->packet_pts += (duration - ch->last_dtmf_event_ts) * output_ch->encoder->def->clockrate_mult; ch->last_dtmf_event_ts = duration; } payload_type = ch->handler->dtmf_payload_type; - } skip: - if (output_ch) - obj_put(&output_ch->h); - if (decoder_ch) - obj_put(&decoder_ch->h); + if (output_ch) + obj_put(&output_ch->h); + if (decoder_ch) + obj_put(&decoder_ch->h); + } char *buf = malloc(packet->payload->len + sizeof(struct rtp_header) + RTP_BUFFER_TAIL_ROOM); memcpy(buf + sizeof(struct rtp_header), packet->payload->s, packet->payload->len); diff --git a/lib/codeclib.c b/lib/codeclib.c index 79e1e5dbc..e5c684f40 100644 --- a/lib/codeclib.c +++ b/lib/codeclib.c @@ -1285,11 +1285,17 @@ int encoder_input_data(encoder_t *enc, AVFrame *frame, return -1; if (enc->avpkt.size) { + // don't rely on the encoder producing steady timestamps, + // instead keep track of them ourselves based on the returned + // frame duration + enc->avpkt.pts = enc->next_pts; + if (enc->def->codec_type->encoder_got_packet) enc->def->codec_type->encoder_got_packet(enc); callback(enc, u1, u2); + enc->next_pts += enc->avpkt.duration; enc->mux_dts = enc->avpkt.dts + 1; // min next expected dts av_packet_unref(&enc->avpkt); diff --git a/lib/codeclib.h b/lib/codeclib.h index 7af12fdce..cda735ce9 100644 --- a/lib/codeclib.h +++ b/lib/codeclib.h @@ -240,6 +240,7 @@ struct encoder_s { AVAudioFifo *fifo; int64_t fifo_pts; // pts of first data in fifo int64_t packet_pts; // first pts of data in packetizer buffer + int64_t next_pts; // next pts expected from the encoder int ptime; int bitrate; int samples_per_frame; // for encoding From b38b49fd60c7378dde45f853f9f11f89ba7f7d50 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 28 Jan 2021 13:44:44 -0500 Subject: [PATCH 07/13] TT#102450 added tests for Ia9fa96cf Change-Id: Ic9728e12a012335c30c5640ac0b5c88e39ad24ed --- t/auto-daemon-tests-dtx.pl | 165 +++++++++++++++++++++++++++++++++++++ t/auto-daemon-tests.pl | 64 +++++++------- 2 files changed, 197 insertions(+), 32 deletions(-) diff --git a/t/auto-daemon-tests-dtx.pl b/t/auto-daemon-tests-dtx.pl index 2d8c992e5..68e103d7b 100755 --- a/t/auto-daemon-tests-dtx.pl +++ b/t/auto-daemon-tests-dtx.pl @@ -303,11 +303,67 @@ Time::HiRes::usleep(10000); # 10 ms snd($sock_a, $port_b, rtp(111, 9, 2560, 0x5678, "\xf0\x44\x0c\x00\x0a\x07\x41\x71\xa0\xf8\xc1\x54\x3c\x00\x00\x00\x00\x20")); rcv($sock_b, $port_a, rtpm(9, 9, 1600, $ssrc, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +# reverse flow +snd($sock_b, $port_a, rtp(9, 100, 7000, 0x9876, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +Time::HiRes::usleep(9000); +($ssrc) = rcv($sock_a, $port_b, rtpm(111, 100, 7000, -1, "\xf1\x54\x54\x3c\x58\x28\x92\xb6\x34\x42\x0b\x59\x8b\x52\x1c\x0d\xa0\xa6\x70\x16\xf8\x9a\x2d\x5e\xf0\x53\xb6\x78\x02\x1d\xff\x54\x12")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(9, 101, 7160, 0x9876, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(111, 101, 7320, $ssrc, "\xf1\x58\x42\x86\x17\xb7\xe1\xa2\x9c\x79\x5b\x43\x82\x64\xcc\xd1\xe0\xe4\xf8\x67\x69\x3d\x3e\x9e\xd8\x75\x34\xa9\xb2\xa5\x47\x81\x32")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(9, 102, 7320, 0x9876, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(111, 102, 7640, $ssrc, "\xf1\x50\x42\xfe\x51\x93\xf0\x66\xe8\x59\xeb\xb8\x05\x4a\x5a\x01\xa2\x3d\xf0\x29\x4d\xbd\x9c\x2e\x9f\x2d\x3f\x85\xfa\x1d\x47\x1f\xfa")); +# DTMF +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(96, 103, 7480, 0x9876, "\x01\x07\x00\xa0")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 103, 7960, $ssrc, "\x01\x07\x01\x40")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(96, 104, 7480, 0x9876, "\x01\x07\x01\x40")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 104, 7960, $ssrc, "\x01\x07\x02\x80")); +# end +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(96, 105, 7480, 0x9876, "\x01\x87\x01\xe0")); +Time::HiRes::usleep(1000); +snd($sock_b, $port_a, rtp(96, 106, 7480, 0x9876, "\x01\x87\x01\xe0")); +Time::HiRes::usleep(1000); +snd($sock_b, $port_a, rtp(96, 107, 7480, 0x9876, "\x01\x87\x01\xe0")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 105, 7960, $ssrc, "\x01\x87\x03\xc0")); +Time::HiRes::usleep(1000); +rcv($sock_a, $port_b, rtpm(101, 106, 7960, $ssrc, "\x01\x87\x03\xc0")); +Time::HiRes::usleep(1000); +rcv($sock_a, $port_b, rtpm(101, 107, 7960, $ssrc, "\x01\x87\x03\xc0")); +Time::HiRes::usleep(9000); +# more audio +snd($sock_b, $port_a, rtp(9, 108, 7960, 0x9876, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(111, 108, 8920, $ssrc, "\xf1\x50\x42\x86\xbe\xb7\x49\xe3\x7c\x53\x43\x18\x47\xe1\x6c\x71\xa2\xf6\x76\x20\xcd\x3f\x1f\x7a\x9e\x17\x06\xdc\x72\xf4\xf4\x5f\x7a")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(9, 109, 8120, 0x9876, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(111, 109, 9240, $ssrc, "\xf1\x58\x43\x82\x36\x15\x27\x26\xb5\x6a\xfb\x25\xc1\x21\x4c\x69\xe5\x76\x06\x4a\xe0\x6e\x9a\xbe\x9c\x87\x52\x8c\xf7\x67\xe5\xa7\xf6")); +# more DTMF +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(96, 110, 8280, 0x9876, "\x01\x07\x00\xa0")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 110, 9560, $ssrc, "\x01\x07\x01\x40")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(96, 111, 8280, 0x9876, "\x01\x07\x01\x40")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 111, 9560, $ssrc, "\x01\x07\x02\x80")); + + + rtpe_req('delete', 'AMR w DTMF', { 'from-tag' => ft() }); + ($sock_a, $sock_b) = new_call([qw(198.51.100.10 4042)], [qw(198.51.100.10 4044)]); ($port_a) = offer('AMR w reverse DTMF', @@ -426,6 +482,115 @@ Time::HiRes::usleep(9000); snd($sock_b, $port_a, rtp(97, 2, 1280, 0x6543, "\x01\x07\x01\x40")); Time::HiRes::usleep(9000); rcv($sock_a, $port_b, rtpm(101, 2, 1120, $ssrc, "\x01\x07\x00\xa0")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(97, 3, 1280, 0x6543, "\x01\x07\x02\x80")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 3, 1120, $ssrc, "\x01\x07\x01\x40")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(97, 4, 1280, 0x6543, "\x01\x07\x03\xc0")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 4, 1120, $ssrc, "\x01\x07\x01\xe0")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(97, 5, 1280, 0x6543, "\x01\x07\x05\x00")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 5, 1120, $ssrc, "\x01\x07\x02\x80")); +Time::HiRes::usleep(9000); +# end +snd($sock_b, $port_a, rtp(97, 6, 1280, 0x6543, "\x01\x87\x06\x40")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 6, 1120, $ssrc, "\x01\x87\x03\x20")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(97, 7, 1280, 0x6543, "\x01\x87\x06\x40")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 7, 1120, $ssrc, "\x01\x87\x03\x20")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(97, 8, 1280, 0x6543, "\x01\x87\x06\x40")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 8, 1120, $ssrc, "\x01\x87\x03\x20")); +Time::HiRes::usleep(9000); +# some audio +snd($sock_b, $port_a, rtp(96, 9, 2880, 0x6543, "\xf1\x70\xcc\x2c\xb0\xbe\x3c\x2b\x21\x51\x80\x0c\x35\xf1\xf0\xef\xf5\x4c\x56\xe1\xad\x13\x8f\x83\x6a\xad\x1f\x1a\xec\x90\x25\x17\x36")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(9, 9, 1920, $ssrc, "\xb8\xf8\xfa\x9e\xf4\xfa\xf7\xfa\xf7\xf8\xde\xf7\xb8\x7a\xba\xf7\x9b\xec\xfb\xb8\xfa\x78\xf8\xdc\x75\x9e\xb3\xf8\xde\xf8\xf5\xfa\x5e\xf3\xb8\xdf\xb8\xf5\xde\x78\xf5\xf5\xf8\xb3\xdf\xb6\xdf\xdf\xfb\x78\xbb\xfa\xba\xf8\xf8\x7a\xde\xfa\xba\xb5\x75\xf8\xf5\xdc\xfa\xf8\xb8\x78\xba\xfa\xfa\x5e\xf4\xba\x77\xfa\xfa\xba\xf7\xdb\x74\xb7\xf8\x78\xde\xb4\xf5\xf3\x5e\xba\x59\xf3\xfb\xdc\xb8\xf5\x71\xdc\xf8\xfb\xb8\xdf\xf5\xf8\xb5\x76\x9c\xdf\xf4\xdc\x3b\xb8\xf8\xd9\xfa\xf8\xf3\x5f\x7b\xb8\xfa\xfa\xdc\xb5\x78\xf5\xfa\xfa\x78\xba\xde\xfa\xb8\xf8\x77\xf8\xb8\x5e\x7a\xb7\xfa\xf7\x7a\x74\xba\xde\xf4\xdb\xb3\x73\xfb\x74\x9c\xf8\x5f\xb8\xfa\xf8\x78\xfa")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(96, 10, 3200, 0x6543, "\xf1\x70\xcc\x2c\xb0\xbe\x3c\x2b\x21\x51\x80\x0c\x35\xf1\xf0\xef\xf5\x4c\x56\xe1\xad\x13\x8f\x83\x6a\xad\x1f\x1a\xec\x90\x25\x17\x36")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(9, 10, 2080, $ssrc, "\x9c\x7a\xb5\xf5\xf5\x7a\xf5\xf8\x78\x9c\xba\xf5\x78\xf8\xfa\x7a\xba\xf4\x7a\x9b\xf1\xf3\x7b\xda\xf8\xfb\xbb\x78\xba\xf3\x5f\x9c\x78\xf5\xf4\xf8\xf6\xdc\x9c\xdc\x78\xf5\xf5\xb0\xf8\xfb\xdc\x5a\xb6\x7b\xb8\xf4\xb4\xfb\x5a\xf6\x5d\xf8\xb6\xb8\x74\x5a\xb4\xd8\x79\x74\xb9\xf4\xdd\xf9\x79\xdf\xf6\xfb\xf6\x5f\xfb\xbb\x9f\x7b\xf6\xfb\xfb\xdf\x5f\xb8\xfb\xf3\xb8\x7b\xdc\xf8\x78\x9e\xf5\xb5\x74\x9f\xf8\x7b\xfa\x7a\xde\xb3\xdc\xfa\x75\xb6\x7b\xda\xf6\xfb\xdf\x7b\x9f\xf3\xfb\xf8\x5c\xb6\xf6\xdf\xdf\xb8\xf6\xfb\xfb\xfb\x7a\x9c\xfa\xfa\xb8\xf5\x75\xb3\xfb\xdc\x1f\xb3\xfb\xdf\xf6\x7b\xbb\xdc\x75\xfb\xfb\x7a\xb8\xf8\x9e\xf5\x7a\xf5\x7a\xfa\xf8\x9c")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(96, 11, 3520, 0x6543, "\xf1\x70\xcc\x2c\xb0\xbe\x3c\x2b\x21\x51\x80\x0c\x35\xf1\xf0\xef\xf5\x4c\x56\xe1\xad\x13\x8f\x83\x6a\xad\x1f\x1a\xec\x90\x25\x17\x36")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(9, 11, 2240, $ssrc, "\xdc\xfa\xf5\x78\xf8\xba\xfa\xba\x77\x9b\xf3\xf8\xf3\x78\xfa\x9e\xfa\xf5\x5e\xb5\xf5\x71\xbb\xfb\x7b\xd6\xb2\x5f\xfb\xb9\x76\xdf\xdf\x74\xbb\xdf\xf8\x78\x9f\xf8\x76\xbb\x5f\xb8\xf8\x78\x7a\xde\xf1\x78\x9e\xf8\xfa\xb5\xde\x75\x75\xfa\xf5\xf8\x75\x9f\xb3\xda\xf4\x36\xdd\x79\x9f\xf4\xf8\xfb\xf8\x7b\x78\xfb\xbb\xde\xb5\xf8\x7a\x75\xf8\xf8\xde\xb5\xf8\xf3\xfb\x5c\x5e\xf5\xb6\xdf\xb2\xfb\xf8\xdc\xdc\x7b\xf8\xf5\xb6\x9f\xf6\xdc\x78\xf8\xb8\xf5\xfa\xf8\x9e\x5e\xfa\xb5\xf5\xf8\x3a\xba\xfa\xde\x7a\xba\x74\x78\xfa\xba\xfa\xde\xf2\x5c\xf5\x78\xf8\xb8\xba\xde\x34\xf7\xf8\xfa\xba\x5e\xb2\xde\x73\x5e\xf5\xf5\xf8\xf3\xbb\x7b\x5c\xb8\xfa\x5e\xf5\xf5")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(96, 12, 3840, 0x6543, "\xf1\x70\xcc\x2c\xb0\xbe\x3c\x2b\x21\x51\x80\x0c\x35\xf1\xf0\xef\xf5\x4c\x56\xe1\xad\x13\x8f\x83\x6a\xad\x1f\x1a\xec\x90\x25\x17\x36")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(9, 12, 2400, $ssrc, "\xf8\xf8\xf8\xf5\x7a\xdc\xb5\xb5\x71\xfb\x9f\x78\xf2\x7b\x9a\xf6\xbb\x7b\x5c\xf8\xf4\x78\xb6\xdc\xf8\xdc\xf8\x78\x9e\xf1\x76\xbb\xdc\xf8\xf8\x7a\xde\xf8\xba\xf5\x75\xb8\x78\x9e\xfa\x78\xf8\xba\xf8\x73\xdc\xb5\x7a\xde\xf5\xf8\xf3\xfa\xde\xb5\x78\xdc\xb3\xfb\x7b\xf8\x9e\xde\xfa\xf8\x35\xf3\xf8\xfa\x9c\xba\xfa\x5e\xf3\x78\x5e\xb8\xb8\xf5\x5e\xf8\x75\x75\xb8\xfa\xba\x7a\xde\x78\xb5\xf5\xf1\x7b\xde\xf8\xf8\xba\xfa\xf8\xde\x78\xf8\xb7\xf5\xf5\x5e\x9e\xb8\x5c\x75\xf3\xf3\xdc\xda\xb6\xfb\x78\xdc\xb4\xf6\x5f\xf8\x9f\xf6\xdf\x76\x7b\x9f\xf8\x9e\xf1\xf8\xdf\x36\xf6\xfb\x9a\xf8\xf8\xf6\xf6\x38\xdf\xfb\x9f\xbb\xf8\xf5\x32\xfb\xdf\xdf\x9f\xf8\xf8")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(96, 13, 4160, 0x6543, "\xf1\x70\xcc\x2c\xb0\xbe\x3c\x2b\x21\x51\x80\x0c\x35\xf1\xf0\xef\xf5\x4c\x56\xe1\xad\x13\x8f\x83\x6a\xad\x1f\x1a\xec\x90\x25\x17\x36")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(9, 13, 2560, $ssrc, "\x78\x78\x75\xf8\x9e\xde\xb3\xfa\x78\x5e\xf8\xf8\xf8\xf8\xba\xfa\x5e\x72\xde\xb8\xf8\xf5\xf8\xde\x75\x9e\xf8\x75\xb8\xf8\xf7\xba\x5e\xf7\xfa\xfa\x7a\xde\xba\xf7\xfa\x9e\x74\xb4\x74\x7a\x7a\x9b\xba\x74\xf5\xf8\x75\xf3\xdc\xf8\xf8\xde\xb5\xf8\x73\xdf\xb5\x7b\xde\xf8\xde\xf5\xba\xf8\x78\xb8\xfa\xde\xf8\x78\xb7\x7a\xb7\xfa\x5e\xba\xfa\xfa\x5b\xba\x74\xf4\xf5\xf8\xfa\xfa\x9e\x74\xba\x7a\x74\xf4\xba\xfa\xfa\xdb\x74\xf5\xf8\xf8\xf5\xb8\xde\xf8\x77\xde\xba\x7a\x9e\xba\xf2\x5e\x5e\xb4\xf5\xf5\xde\xb5\x75\xf5\xf8\xfa\x78\x9c\xf5\x5c\xf8\xb5\xf5\xf3\xfb\x7b\x5c\xba\xde\xb8\xf5\x78\xb3\xfb\x78\xdc\x9e\x78\xb8\x71\xba\x75\x5c\xf8\xde\xf8\xf3\xdf")); +Time::HiRes::usleep(9000); +snd($sock_b, $port_a, rtp(96, 14, 4480, 0x6543, "\xf1\x70\xcc\x2c\xb0\xbe\x3c\x2b\x21\x51\x80\x0c\x35\xf1\xf0\xef\xf5\x4c\x56\xe1\xad\x13\x8f\x83\x6a\xad\x1f\x1a\xec\x90\x25\x17\x36")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(9, 14, 2720, $ssrc, "\xfa\xdc\xf5\x7a\xfa\xba\xf8\xb8\x75\xdc\xf8\xf8\xf3\x7a\xf8\xfa\x9c\xb5\x7a\x9e\xf1\xf5\x75\xdf\x75\x9f\xb8\xf5\x9f\xf5\x36\xfb\xdf\xf8\xb8\xfa\xde\x78\xde\xf5\x78\xb5\xf5\xb8\xf8\x78\x7a\x5c\xb8\xf5\xfa\xf8\xfa\x7a\x7a\xde\xb2\xde\xb5\xf5\x75\x7a\xfa\x9e\xfa\x78\xfa\xfa\x9e\xf4\x77\xde\xb7\xf8\xf5\xf5\xf5\xfa\xfa\xde\x38\xb8\xfa\xf7\xde\xb7\xf8\x7a\xde\xf7\xfa\xb7\xb5\x78\xf8\xdc\x77\xf8\xb7\xf8\xfa\x77\xd9\x7a\xfa\xba\xb7\xf5\xf3\xd7\x5a\xf6\xb8\xdf\xf8\xad\xf9\x5a\x5a\xb6\xbb\x79\xf3\xf7\xdf\xdd\xdf\xfb\xfb\xb6\x76\xdd\xbb\xdd\x79\x9f\xb6\x76\x79\xb9\xf9\x7b\xd8\xfb\xf3\xb6\x5d\xfb\xf9\x5f\xbb\x74\xb4\x7b\x5d\xfb\xdf\xfb\xfb\xf8")); +Time::HiRes::usleep(9000); +# more DTMF +snd($sock_b, $port_a, rtp(97, 15, 4800, 0x6543, "\x02\x07\x01\x40")); +Time::HiRes::usleep(9000); +rcv($sock_a, $port_b, rtpm(101, 15, 2880, $ssrc, "\x02\x07\x00\xa0")); +Time::HiRes::usleep(9000); + +# reverse flow +snd($sock_a, $port_b, rtp(9, 100, 7000, 0x9876, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +Time::HiRes::usleep(9000); +($ssrc) = rcv($sock_b, $port_a, rtpm(96, 100, 7000, -1, "\xf1\x54\x54\x3c\x58\x28\x92\xb6\x34\x42\x0b\x59\x8b\x52\x1c\x0d\xa0\xa6\x70\x16\xf8\x9a\x2d\x5e\xf0\x53\xb6\x78\x02\x1d\xff\x54\x12")); +Time::HiRes::usleep(9000); +snd($sock_a, $port_b, rtp(9, 101, 7160, 0x9876, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +Time::HiRes::usleep(9000); +rcv($sock_b, $port_a, rtpm(96, 101, 7320, $ssrc, "\xf1\x58\x42\x86\x17\xb7\xe1\xa2\x9c\x79\x5b\x43\x82\x64\xcc\xd1\xe0\xe4\xf8\x67\x69\x3d\x3e\x9e\xd8\x75\x34\xa9\xb2\xa5\x47\x81\x32")); +Time::HiRes::usleep(9000); +snd($sock_a, $port_b, rtp(9, 102, 7320, 0x9876, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +Time::HiRes::usleep(9000); +rcv($sock_b, $port_a, rtpm(96, 102, 7640, $ssrc, "\xf1\x50\x42\xfe\x51\x93\xf0\x66\xe8\x59\xeb\xb8\x05\x4a\x5a\x01\xa2\x3d\xf0\x29\x4d\xbd\x9c\x2e\x9f\x2d\x3f\x85\xfa\x1d\x47\x1f\xfa")); +# DTMF +Time::HiRes::usleep(9000); +snd($sock_a, $port_b, rtp(101, 103, 7480, 0x9876, "\x01\x07\x00\xa0")); +Time::HiRes::usleep(9000); +rcv($sock_b, $port_a, rtpm(97, 103, 7960, $ssrc, "\x01\x07\x01\x40")); +Time::HiRes::usleep(9000); +snd($sock_a, $port_b, rtp(101, 104, 7480, 0x9876, "\x01\x07\x01\x40")); +Time::HiRes::usleep(9000); +rcv($sock_b, $port_a, rtpm(97, 104, 7960, $ssrc, "\x01\x07\x02\x80")); +# end +Time::HiRes::usleep(9000); +snd($sock_a, $port_b, rtp(101, 105, 7480, 0x9876, "\x01\x87\x01\xe0")); +Time::HiRes::usleep(1000); +snd($sock_a, $port_b, rtp(101, 106, 7480, 0x9876, "\x01\x87\x01\xe0")); +Time::HiRes::usleep(1000); +snd($sock_a, $port_b, rtp(101, 107, 7480, 0x9876, "\x01\x87\x01\xe0")); +Time::HiRes::usleep(9000); +rcv($sock_b, $port_a, rtpm(97, 105, 7960, $ssrc, "\x01\x87\x03\xc0")); +Time::HiRes::usleep(1000); +rcv($sock_b, $port_a, rtpm(97, 106, 7960, $ssrc, "\x01\x87\x03\xc0")); +Time::HiRes::usleep(1000); +rcv($sock_b, $port_a, rtpm(97, 107, 7960, $ssrc, "\x01\x87\x03\xc0")); +Time::HiRes::usleep(9000); +# more audio +snd($sock_a, $port_b, rtp(9, 108, 7960, 0x9876, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +Time::HiRes::usleep(9000); +rcv($sock_b, $port_a, rtpm(96, 108, 8920, $ssrc, "\xf1\x50\x42\x86\xbe\xb7\x49\xe3\x7c\x53\x43\x18\x47\xe1\x6c\x71\xa2\xf6\x76\x20\xcd\x3f\x1f\x7a\x9e\x17\x06\xdc\x72\xf4\xf4\x5f\x7a")); +Time::HiRes::usleep(9000); +snd($sock_a, $port_b, rtp(9, 109, 8120, 0x9876, "\xfb\xb8\xde\xde\x71\xb6\xfb\xdf\xf6\xf8\x9a\xfb\xf4\xf4\x78\xf6\x9f\x5f\xb8\xbb\xfb\x78\xf8\xfa\xfa\xb8\xfa\xfa\xf8\x7a\x5e\xb4\xb8\xfa\xb7\x5e\xec\x78\xf8\xba\xde\x78\xba\xde\x78\x73\xde\xb8\xf5\xb5\x7a\xde\xf1\x70\xf6\xdf\xdf\x9f\xfb\xb8\x74\xf6\x76\xdf\xdc\xb8\xdc\x9f\x70\x74\x76\xdf\xdf\x9f\xb8\xfb\x78\x74\xf6\xfb\xdc\xb2\xdc\xdc\x5f\xf4\xf2\xfb\xdd\xb9\xf8\xfb\x9f\xdc\x7b\xb6\xfb\xf8\xf8\x9e\xfa\x78\xdc\xf5\xb8\x75\xb5\xfa\x5c\xf5\xf5\x9f\xf8\xf5\xf5\x76\x9c\x70\x96\xdf\xf9\x76\xf6\xb9\x73\x9b\x7b\xdf\xfb\xf4\xf4\xf7\x9d\xdd\x59\xf7\x77\xb5\xf9\xf9\xb9\xfb\xd9\x77\xf5\xf9\xf7\xb9\xf7\xdd\xdf\xf7\xb9\xf7\x9d\x5f\xf7\xf9\xf9\xf7")); +Time::HiRes::usleep(9000); +rcv($sock_b, $port_a, rtpm(96, 109, 9240, $ssrc, "\xf1\x58\x43\x82\x36\x15\x27\x26\xb5\x6a\xfb\x25\xc1\x21\x4c\x69\xe5\x76\x06\x4a\xe0\x6e\x9a\xbe\x9c\x87\x52\x8c\xf7\x67\xe5\xa7\xf6")); +# more DTMF +Time::HiRes::usleep(9000); +snd($sock_a, $port_b, rtp(101, 110, 8280, 0x9876, "\x01\x07\x00\xa0")); +Time::HiRes::usleep(9000); +rcv($sock_b, $port_a, rtpm(97, 110, 9560, $ssrc, "\x01\x07\x01\x40")); +Time::HiRes::usleep(9000); +snd($sock_a, $port_b, rtp(101, 111, 8280, 0x9876, "\x01\x07\x01\x40")); +Time::HiRes::usleep(9000); +rcv($sock_b, $port_a, rtpm(97, 111, 9560, $ssrc, "\x01\x07\x02\x80")); diff --git a/t/auto-daemon-tests.pl b/t/auto-daemon-tests.pl index ad0821fa4..7c518e7e6 100755 --- a/t/auto-daemon-tests.pl +++ b/t/auto-daemon-tests.pl @@ -2535,7 +2535,7 @@ snd($sock_b, $port_a, rtp(8, 1001, 3160, 0x1234, "\x00" x 160)); ($ssrc) = rcv($sock_a, $port_b, rtpm(96, 1000, 3000, -1, "\xf0\x44\xd0\x46\x0d\x8d\xd6\xf3\x02\x71\x71\xf0\x00\x00\x0a\x16\x87\x77\x22\x31\xc8\x21\x00\x8b\xe8\x45\xf2\x94\x41\xd6\xf7\xd1\x68\xb1\xed\x39\x5f\x37\xbe\xbc\xd6\x47\x89\xc4\x14\xad\xff\x1b\x69\xe7\x72\x80\x44\xc4\x97\x2f\x9f\xc7\xc4\xa8\x94\xc0")); # control for CMR test below: snd($sock_b, $port_a, rtp(8, 1002, 3320, 0x1234, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(96, 1001, 3240, $ssrc, "\xf0\x44\xe0\x94\x24\x91\xd6\x45\x0d\x23\xdf\x00\x01\xad\xc9\x47\xc5\x2f\xf7\xfb\x62\x39\x06\xaf\x4d\x1c\x1e\x02\x6d\x94\xd1\x98\x28\x16\x25\x11\x1f\x56\xaa\x25\x40\x79\x19\x7e\x98\x8b\xbf\x78\x24\xe4\x37\x80\xad\x54\x59\x6d\xfd\x74\xcc\x40\x3f\x10")); +rcv($sock_a, $port_b, rtpm(96, 1001, 3320, $ssrc, "\xf0\x44\xe0\x94\x24\x91\xd6\x45\x0d\x23\xdf\x00\x01\xad\xc9\x47\xc5\x2f\xf7\xfb\x62\x39\x06\xaf\x4d\x1c\x1e\x02\x6d\x94\xd1\x98\x28\x16\x25\x11\x1f\x56\xaa\x25\x40\x79\x19\x7e\x98\x8b\xbf\x78\x24\xe4\x37\x80\xad\x54\x59\x6d\xfd\x74\xcc\x40\x3f\x10")); @@ -2655,10 +2655,10 @@ snd($sock_a, $port_b, rtp(96, 2000, 4000, 0x5678, "\x10\x04\x89\xf1\xd9\x1c\xd6\ Time::HiRes::usleep(20000); # 20 ms, wait to be processed snd($sock_b, $port_a, rtp(8, 1002, 3320, 0x1234, "\x00" x 160)); # receive one more mode 8 frame, then CMR kicks in -rcv($sock_a, $port_b, rtpm(96, 1001, 3240, $ssrc, "\xf0\x44\xe0\x94\x24\x91\xd6\x45\x0d\x23\xdf\x00\x01\xad\xc9\x47\xc5\x2f\xf7\xfb\x62\x39\x06\xaf\x4d\x1c\x1e\x02\x6d\x94\xd1\x98\x28\x16\x25\x11\x1f\x56\xaa\x25\x40\x79\x19\x7e\x98\x8b\xbf\x78\x24\xe4\x37\x80\xad\x54\x59\x6d\xfd\x74\xcc\x40\x3f\x10")); +rcv($sock_a, $port_b, rtpm(96, 1001, 3320, $ssrc, "\xf0\x44\xe0\x94\x24\x91\xd6\x45\x0d\x23\xdf\x00\x01\xad\xc9\x47\xc5\x2f\xf7\xfb\x62\x39\x06\xaf\x4d\x1c\x1e\x02\x6d\x94\xd1\x98\x28\x16\x25\x11\x1f\x56\xaa\x25\x40\x79\x19\x7e\x98\x8b\xbf\x78\x24\xe4\x37\x80\xad\x54\x59\x6d\xfd\x74\xcc\x40\x3f\x10")); snd($sock_b, $port_a, rtp(8, 1003, 3480, 0x1234, "\x00" x 160)); # now mode 1 -rcv($sock_a, $port_b, rtpm(96, 1002, 3560, $ssrc, "\xf0\x0c\x54\x01\x1e\x01\x14\x6c\xb0\x53\xa3\x87\x8d\x76\x75\xd0\x30\x76\x70\x10\x24\x6a\x10\x62\x00")); +rcv($sock_a, $port_b, rtpm(96, 1002, 3640, $ssrc, "\xf0\x0c\x54\x01\x1e\x01\x14\x6c\xb0\x53\xa3\x87\x8d\x76\x75\xd0\x30\x76\x70\x10\x24\x6a\x10\x62\x00")); @@ -2722,16 +2722,16 @@ snd($sock_a, $port_b, rtp(96, 2000, 4000, 0x5678, "\x00\x04\x89\xf1\xd9\x1c\xd6\ Time::HiRes::usleep(20000); # 20 ms, wait to be processed snd($sock_b, $port_a, rtp(8, 1002, 3320, 0x1234, "\x00" x 160)); # recv one more frame with mode 6 before CMR kicks in -rcv($sock_a, $port_b, rtpm(96, 1001, 3240, $ssrc, "\xf0\x34\xe2\x98\x10\xea\xff\xc9\x7d\x23\xdf\x6d\xd9\x47\xd5\x41\xbe\x02\xa2\xd8\xb6\x5a\x18\xfa\x62\x01\xd6\x1c\x5f\x1a\xe6\xef\x1d\x23\xd0\xf5\x3c\x05\xd1\xbd\x4e\x9b\xd5\xc3\x9b\x49\x2b\x19\x41\x0c\x60\x80")); +rcv($sock_a, $port_b, rtpm(96, 1001, 3320, $ssrc, "\xf0\x34\xe2\x98\x10\xea\xff\xc9\x7d\x23\xdf\x6d\xd9\x47\xd5\x41\xbe\x02\xa2\xd8\xb6\x5a\x18\xfa\x62\x01\xd6\x1c\x5f\x1a\xe6\xef\x1d\x23\xd0\xf5\x3c\x05\xd1\xbd\x4e\x9b\xd5\xc3\x9b\x49\x2b\x19\x41\x0c\x60\x80")); snd($sock_b, $port_a, rtp(8, 1003, 3480, 0x1234, "\x00" x 160)); # recv mode 4 -rcv($sock_a, $port_b, rtpm(96, 1002, 3560, $ssrc, "\xf0\x24\x41\x44\x30\x11\x12\x46\x3c\xb0\x53\x25\x8f\x8d\x46\x5c\x7d\xc7\xc2\x7b\x06\xb4\xd9\x48\x41\x74\xa1\x06\x04\x1c\xd2\x94\x09\x4e\x6c\x1c\x20\xbc\x98\x47\x47\x28")); +rcv($sock_a, $port_b, rtpm(96, 1002, 3640, $ssrc, "\xf0\x24\x41\x44\x30\x11\x12\x46\x3c\xb0\x53\x25\x8f\x8d\x46\x5c\x7d\xc7\xc2\x7b\x06\xb4\xd9\x48\x41\x74\xa1\x06\x04\x1c\xd2\x94\x09\x4e\x6c\x1c\x20\xbc\x98\x47\x47\x28")); snd($sock_b, $port_a, rtp(8, 1004, 3640, 0x1234, "\x00" x 160)); # recv mode 2 -rcv($sock_a, $port_b, rtpm(96, 1003, 3880, $ssrc, "\xf0\x14\x41\x46\x30\x77\x75\xde\x11\x15\x55\x79\x8a\x06\x44\xc0\x70\x7f\x07\x85\x81\x87\x86\xb7\xa5\xa5\x18\x33\x35\x39\x98\xa0\x4c\x20")); +rcv($sock_a, $port_b, rtpm(96, 1003, 3960, $ssrc, "\xf0\x14\x41\x46\x30\x77\x75\xde\x11\x15\x55\x79\x8a\x06\x44\xc0\x70\x7f\x07\x85\x81\x87\x86\xb7\xa5\xa5\x18\x33\x35\x39\x98\xa0\x4c\x20")); snd($sock_b, $port_a, rtp(8, 1005, 3800, 0x1234, "\x00" x 160)); # recv mode 0 -rcv($sock_a, $port_b, rtpm(96, 1004, 4200, $ssrc, "\xf0\x04\x30\x01\x00\x28\x1c\x10\x30\x0b\x02\x07\x8b\x00\x84\x00\xc4\x80\x00")); +rcv($sock_a, $port_b, rtpm(96, 1004, 4280, $ssrc, "\xf0\x04\x30\x01\x00\x28\x1c\x10\x30\x0b\x02\x07\x8b\x00\x84\x00\xc4\x80\x00")); @@ -2798,34 +2798,34 @@ snd($sock_a, $port_b, rtp(96, 2000, 4000, 0x5678, "\x70\x04\x89\xf1\xd9\x1c\xd6\ Time::HiRes::usleep(20000); # 20 ms, wait to be processed snd($sock_b, $port_a, rtp(8, 1002, 3320, 0x1234, "\x00" x 160)); # recv one more frame with mode 0 before CMR kicks in -rcv($sock_a, $port_b, rtpm(96, 1001, 3240, $ssrc, "\xf0\x04\xe0\x34\x00\x39\x83\x38\x90\x82\xd2\xc2\xca\x8c\x8c\x03\x18\x8b\x90")); +rcv($sock_a, $port_b, rtpm(96, 1001, 3320, $ssrc, "\xf0\x04\xe0\x34\x00\x39\x83\x38\x90\x82\xd2\xc2\xca\x8c\x8c\x03\x18\x8b\x90")); snd($sock_b, $port_a, rtp(8, 1003, 3480, 0x1234, "\x00" x 160)); # mode change suppressed due to period=2, so one more mode 0 -rcv($sock_a, $port_b, rtpm(96, 1002, 3560, $ssrc, "\xf0\x04\x10\x31\x00\x38\x9c\x7c\xb6\x01\x72\x05\x1b\xd2\xd6\x84\x34\x76\x00")); +rcv($sock_a, $port_b, rtpm(96, 1002, 3640, $ssrc, "\xf0\x04\x10\x31\x00\x38\x9c\x7c\xb6\x01\x72\x05\x1b\xd2\xd6\x84\x34\x76\x00")); snd($sock_b, $port_a, rtp(8, 1004, 3640, 0x1234, "\x00" x 160)); # recv mode 1 -rcv($sock_a, $port_b, rtpm(96, 1003, 3880, $ssrc, "\xf0\x0c\x54\x00\x0f\x00\x0e\x31\x15\x77\xf7\x8a\x96\x3a\x97\x07\x80\x42\x02\x72\x0a\x24\xa4\x4c\x00")); +rcv($sock_a, $port_b, rtpm(96, 1003, 3960, $ssrc, "\xf0\x0c\x54\x00\x0f\x00\x0e\x31\x15\x77\xf7\x8a\x96\x3a\x97\x07\x80\x42\x02\x72\x0a\x24\xa4\x4c\x00")); snd($sock_b, $port_a, rtp(8, 1005, 3800, 0x1234, "\x00" x 160)); # recv mode 1 -rcv($sock_a, $port_b, rtpm(96, 1004, 4200, $ssrc, "\xf0\x0c\x14\x00\x0f\x00\x0e\x08\x44\x91\x16\x79\xf6\xde\x12\xcd\x81\x28\x02\x64\x3b\x64\x29\x5e\x80")); +rcv($sock_a, $port_b, rtpm(96, 1004, 4280, $ssrc, "\xf0\x0c\x14\x00\x0f\x00\x0e\x08\x44\x91\x16\x79\xf6\xde\x12\xcd\x81\x28\x02\x64\x3b\x64\x29\x5e\x80")); snd($sock_b, $port_a, rtp(8, 1006, 3960, 0x1234, "\x00" x 160)); # recv mode 3 -rcv($sock_a, $port_b, rtpm(96, 1005, 4520, $ssrc, "\xf0\x1c\x01\x44\x00\x22\x2c\x88\xe8\x41\x94\xa0\x09\x82\xb2\xc5\x23\xfa\x5d\x5e\x33\xb1\x41\xfd\x04\x52\x55\x51\x4b\x15\x31\x38\x55\x00\x59\xd5\x98\x80")); +rcv($sock_a, $port_b, rtpm(96, 1005, 4600, $ssrc, "\xf0\x1c\x01\x44\x00\x22\x2c\x88\xe8\x41\x94\xa0\x09\x82\xb2\xc5\x23\xfa\x5d\x5e\x33\xb1\x41\xfd\x04\x52\x55\x51\x4b\x15\x31\x38\x55\x00\x59\xd5\x98\x80")); snd($sock_b, $port_a, rtp(8, 1007, 4120, 0x1234, "\x00" x 160)); # recv mode 3 -rcv($sock_a, $port_b, rtpm(96, 1006, 4840, $ssrc, "\xf0\x1c\x41\x06\x00\xee\xe3\xb8\x4d\x80\x61\xa6\x48\xc2\x92\x80\x33\x37\xdf\x3e\x81\x76\xf2\x60\x4f\x4a\x24\x45\x01\x34\xc3\x32\x20\x67\x3b\x30\x67\x48")); +rcv($sock_a, $port_b, rtpm(96, 1006, 4920, $ssrc, "\xf0\x1c\x41\x06\x00\xee\xe3\xb8\x4d\x80\x61\xa6\x48\xc2\x92\x80\x33\x37\xdf\x3e\x81\x76\xf2\x60\x4f\x4a\x24\x45\x01\x34\xc3\x32\x20\x67\x3b\x30\x67\x48")); snd($sock_b, $port_a, rtp(8, 1008, 4280, 0x1234, "\x00" x 160)); # recv mode 6 -rcv($sock_a, $port_b, rtpm(96, 1007, 5160, $ssrc, "\xf0\x34\x01\x46\x00\xee\xeb\xb8\x29\xc0\xd7\xe6\x69\xfa\xb2\xdf\xc3\x3a\xfa\xa1\xa3\x10\x81\xd9\x7b\xd5\x60\x11\x82\x03\x18\x87\x41\x49\xb6\x62\x3b\x79\x44\x50\x46\x3a\xfb\x1c\x00\x07\x16\x92\x8c\x95\x81\x00")); +rcv($sock_a, $port_b, rtpm(96, 1007, 5240, $ssrc, "\xf0\x34\x01\x46\x00\xee\xeb\xb8\x29\xc0\xd7\xe6\x69\xfa\xb2\xdf\xc3\x3a\xfa\xa1\xa3\x10\x81\xd9\x7b\xd5\x60\x11\x82\x03\x18\x87\x41\x49\xb6\x62\x3b\x79\x44\x50\x46\x3a\xfb\x1c\x00\x07\x16\x92\x8c\x95\x81\x00")); snd($sock_b, $port_a, rtp(8, 1009, 4440, 0x1234, "\x00" x 160)); # recv mode 6 -rcv($sock_a, $port_b, rtpm(96, 1008, 5480, $ssrc, "\xf0\x34\x41\x44\x10\xff\xff\xfc\x40\xc1\x24\xa2\x0c\xca\xb2\xbf\x43\x02\xbc\x90\x01\x2a\xe1\xcd\x71\x1d\x02\x41\xa6\x37\xbd\xc5\x95\xd7\x98\x44\x12\x61\xcc\x62\x41\xd6\x22\x36\x4c\x82\x14\x66\x08\x8d\x0b\x70")); +rcv($sock_a, $port_b, rtpm(96, 1008, 5560, $ssrc, "\xf0\x34\x41\x44\x10\xff\xff\xfc\x40\xc1\x24\xa2\x0c\xca\xb2\xbf\x43\x02\xbc\x90\x01\x2a\xe1\xcd\x71\x1d\x02\x41\xa6\x37\xbd\xc5\x95\xd7\x98\x44\x12\x61\xcc\x62\x41\xd6\x22\x36\x4c\x82\x14\x66\x08\x8d\x0b\x70")); snd($sock_b, $port_a, rtp(8, 1010, 4600, 0x1234, "\x00" x 160)); # recv mode 7 -rcv($sock_a, $port_b, rtpm(96, 1009, 5800, $ssrc, "\xf0\x3c\x01\x46\x30\xee\xeb\xb8\x19\xc0\xd5\xe6\xf9\xea\x92\xda\xd6\x5b\x4b\x2f\x83\x13\x60\x2e\x1a\xdc\xae\x8c\x44\x31\x81\x95\x6b\x19\x21\x54\xc6\x2c\x41\x9f\x90\xf1\x46\xc9\x8d\x10\xaa\xdf\x70\x0d\x71\x07\x09\x1b\x32\x0d\x3c\x2a\x01\x10")); +rcv($sock_a, $port_b, rtpm(96, 1009, 5880, $ssrc, "\xf0\x3c\x01\x46\x30\xee\xeb\xb8\x19\xc0\xd5\xe6\xf9\xea\x92\xda\xd6\x5b\x4b\x2f\x83\x13\x60\x2e\x1a\xdc\xae\x8c\x44\x31\x81\x95\x6b\x19\x21\x54\xc6\x2c\x41\x9f\x90\xf1\x46\xc9\x8d\x10\xaa\xdf\x70\x0d\x71\x07\x09\x1b\x32\x0d\x3c\x2a\x01\x10")); snd($sock_b, $port_a, rtp(8, 1011, 4760, 0x1234, "\x00" x 160)); # recv mode 7 -rcv($sock_a, $port_b, rtpm(96, 1010, 6120, $ssrc, "\xf0\x3c\x41\x46\x00\xee\xef\xb8\x60\xc1\x22\xe5\x14\xc2\xa2\xe8\xb4\xc1\x42\x09\x12\x0a\x08\xb6\x86\xd4\x78\xaf\x57\xc1\xa0\x94\x6d\x5c\x29\xd8\xf6\x88\x90\xba\xaf\x7d\xd2\x60\x94\x0e\xd0\x20\x4e\x2f\xcf\x02\x0b\x9b\x10\xe8\x10\xec\x05\xd8")); +rcv($sock_a, $port_b, rtpm(96, 1010, 6200, $ssrc, "\xf0\x3c\x41\x46\x00\xee\xef\xb8\x60\xc1\x22\xe5\x14\xc2\xa2\xe8\xb4\xc1\x42\x09\x12\x0a\x08\xb6\x86\xd4\x78\xaf\x57\xc1\xa0\x94\x6d\x5c\x29\xd8\xf6\x88\x90\xba\xaf\x7d\xd2\x60\x94\x0e\xd0\x20\x4e\x2f\xcf\x02\x0b\x9b\x10\xe8\x10\xec\x05\xd8")); @@ -2900,12 +2900,12 @@ snd($sock_b, $port_a, rtp(8, 1001, 3160, 0x1234, "\x00" x 160)); # receive 3 packets with CMRs ($ssrc) = rcv($sock_a, $port_b, rtpm(96, 1000, 3000, -1, "\x40\x1c\xd0\x46\x09\xa1\xf1\x73\x02\x71\x71\x00\x0a\x16\x87\x74\xea\x6a\x8c\x06\x67\x66\xec\xf5\x67\x6c\x54\x6d\x45\x4c\x7c\x59\x8d\x7c\x55\xc4\x6c\x50")); snd($sock_b, $port_a, rtp(8, 1002, 3320, 0x1234, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(96, 1001, 3240, $ssrc, "\x40\x1c\xe0\x92\x30\xf3\xf4\xff\x3d\x23\xdb\x6b\x59\x4f\xd5\x12\xad\xff\x5b\xf8\x88\x53\x85\x74\x19\x6d\x65\x63\x6e\x94\xbb\x5b\x9f\x7d\x97\x3c\x28\xe8")); +rcv($sock_a, $port_b, rtpm(96, 1001, 3320, $ssrc, "\x40\x1c\xe0\x92\x30\xf3\xf4\xff\x3d\x23\xdb\x6b\x59\x4f\xd5\x12\xad\xff\x5b\xf8\x88\x53\x85\x74\x19\x6d\x65\x63\x6e\x94\xbb\x5b\x9f\x7d\x97\x3c\x28\xe8")); snd($sock_b, $port_a, rtp(8, 1003, 3480, 0x1234, "\x00" x 160)); -rcv($sock_a, $port_b, rtpm(96, 1002, 3560, $ssrc, "\x40\x1c\x41\x42\x00\xd9\xd7\x64\x3c\xb0\x51\xe7\x1f\x95\x56\x3b\x34\x76\x35\x73\x46\x32\x16\x72\x67\xc4\x54\x16\x02\x64\x30\x36\x34\x18\xba\x14\xce\xd8")); +rcv($sock_a, $port_b, rtpm(96, 1002, 3640, $ssrc, "\x40\x1c\x41\x42\x00\xd9\xd7\x64\x3c\xb0\x51\xe7\x1f\x95\x56\x3b\x34\x76\x35\x73\x46\x32\x16\x72\x67\xc4\x54\x16\x02\x64\x30\x36\x34\x18\xba\x14\xce\xd8")); snd($sock_b, $port_a, rtp(8, 1004, 3640, 0x1234, "\x00" x 160)); # back to no CMR -rcv($sock_a, $port_b, rtpm(96, 1003, 3880, $ssrc, "\xf0\x1c\x41\x46\x30\xff\xf7\xfc\x31\x15\x57\x3b\x0a\x1e\x44\xcd\x5e\x0e\xa7\xe4\x3a\x1b\xb5\x7b\x38\x2a\x90\x13\x08\xf3\x5f\xaa\xba\x57\xb0\x30\xd3\xe8")); +rcv($sock_a, $port_b, rtpm(96, 1003, 3960, $ssrc, "\xf0\x1c\x41\x46\x30\xff\xf7\xfc\x31\x15\x57\x3b\x0a\x1e\x44\xcd\x5e\x0e\xa7\xe4\x3a\x1b\xb5\x7b\x38\x2a\x90\x13\x08\xf3\x5f\xaa\xba\x57\xb0\x30\xd3\xe8")); @@ -2969,10 +2969,10 @@ snd($sock_a, $port_b, rtp(96, 2000, 4000, 0x5678, "\x10\x1c\xd0\x46\x09\xa1\xf1\ Time::HiRes::usleep(20000); # 20 ms, wait to be processed snd($sock_b, $port_a, rtp(8, 1002, 3320, 0x1234, "\x00" x 160)); # receive one more mode 8 frame, then CMR kicks in -rcv($sock_a, $port_b, rtpm(96, 1001, 3240, $ssrc, "\xf0\x44\xe0\x94\x24\x91\xd6\x45\x0d\x23\xdf\x00\x01\xad\xc9\x47\xc5\x2f\xf7\xfb\x62\x39\x06\xaf\x4d\x1c\x1e\x02\x6d\x94\xd1\x98\x28\x16\x25\x11\x1f\x56\xaa\x25\x40\x79\x19\x7e\x98\x8b\xbf\x78\x24\xe4\x37\x80\xad\x54\x59\x6d\xfd\x74\xcc\x40\x3f\x10")); +rcv($sock_a, $port_b, rtpm(96, 1001, 3320, $ssrc, "\xf0\x44\xe0\x94\x24\x91\xd6\x45\x0d\x23\xdf\x00\x01\xad\xc9\x47\xc5\x2f\xf7\xfb\x62\x39\x06\xaf\x4d\x1c\x1e\x02\x6d\x94\xd1\x98\x28\x16\x25\x11\x1f\x56\xaa\x25\x40\x79\x19\x7e\x98\x8b\xbf\x78\x24\xe4\x37\x80\xad\x54\x59\x6d\xfd\x74\xcc\x40\x3f\x10")); snd($sock_b, $port_a, rtp(8, 1003, 3480, 0x1234, "\x00" x 160)); # now mode 1 -rcv($sock_a, $port_b, rtpm(96, 1002, 3560, $ssrc, "\xf0\x0c\x54\x01\x1e\x01\x14\x6c\xb0\x53\xa3\x87\x8d\x76\x75\xd0\x30\x76\x70\x10\x24\x6a\x10\x62\x00")); +rcv($sock_a, $port_b, rtpm(96, 1002, 3640, $ssrc, "\xf0\x0c\x54\x01\x1e\x01\x14\x6c\xb0\x53\xa3\x87\x8d\x76\x75\xd0\x30\x76\x70\x10\x24\x6a\x10\x62\x00")); # wait for mode-change-interval Time::HiRes::usleep(220000); # 220 ms @@ -2983,10 +2983,10 @@ Time::HiRes::usleep(20000); # 20 ms, wait to be processed snd($sock_b, $port_a, rtp(8, 1004, 3640, 0x1234, "\x00" x 160)); # one more mode 1 -rcv($sock_a, $port_b, rtpm(96, 1003, 3880, $ssrc, "\xf0\x0c\x54\x10\x0f\x00\x0a\x21\x15\x55\x79\x82\x16\x54\xb8\x7c\x48\x00\xc8\x20\x40\x11\x88\x68\x00")); +rcv($sock_a, $port_b, rtpm(96, 1003, 3960, $ssrc, "\xf0\x0c\x54\x10\x0f\x00\x0a\x21\x15\x55\x79\x82\x16\x54\xb8\x7c\x48\x00\xc8\x20\x40\x11\x88\x68\x00")); snd($sock_b, $port_a, rtp(8, 1005, 3800, 0x1234, "\x00" x 160)); # now mode 2 -rcv($sock_a, $port_b, rtpm(96, 1004, 4200, $ssrc, "\xf0\x14\x41\x00\x30\x44\x41\x10\x09\x50\x63\x20\x92\x8a\x82\xf5\x85\xf8\x20\x25\x84\x92\x02\x01\xa1\xb2\x24\x06\x0f\x60\x03\x0f\xd1\x10")); +rcv($sock_a, $port_b, rtpm(96, 1004, 4280, $ssrc, "\xf0\x14\x41\x00\x30\x44\x41\x10\x09\x50\x63\x20\x92\x8a\x82\xf5\x85\xf8\x20\x25\x84\x92\x02\x01\xa1\xb2\x24\x06\x0f\x60\x03\x0f\xd1\x10")); @@ -3049,10 +3049,10 @@ snd($sock_a, $port_b, rtp(96, 2000, 4000, 0x5678, "\x10\x1c\xd0\x46\x09\xa1\xf1\ Time::HiRes::usleep(20000); # 20 ms, wait to be processed snd($sock_b, $port_a, rtp(8, 1002, 3320, 0x1234, "\x00" x 160)); # receive one more mode 8 frame, then CMR kicks in -rcv($sock_a, $port_b, rtpm(96, 1001, 3240, $ssrc, "\xf0\x44\xe0\x94\x24\x91\xd6\x45\x0d\x23\xdf\x00\x01\xad\xc9\x47\xc5\x2f\xf7\xfb\x62\x39\x06\xaf\x4d\x1c\x1e\x02\x6d\x94\xd1\x98\x28\x16\x25\x11\x1f\x56\xaa\x25\x40\x79\x19\x7e\x98\x8b\xbf\x78\x24\xe4\x37\x80\xad\x54\x59\x6d\xfd\x74\xcc\x40\x3f\x10")); +rcv($sock_a, $port_b, rtpm(96, 1001, 3320, $ssrc, "\xf0\x44\xe0\x94\x24\x91\xd6\x45\x0d\x23\xdf\x00\x01\xad\xc9\x47\xc5\x2f\xf7\xfb\x62\x39\x06\xaf\x4d\x1c\x1e\x02\x6d\x94\xd1\x98\x28\x16\x25\x11\x1f\x56\xaa\x25\x40\x79\x19\x7e\x98\x8b\xbf\x78\x24\xe4\x37\x80\xad\x54\x59\x6d\xfd\x74\xcc\x40\x3f\x10")); snd($sock_b, $port_a, rtp(8, 1003, 3480, 0x1234, "\x00" x 160)); # now mode 1 -rcv($sock_a, $port_b, rtpm(96, 1002, 3560, $ssrc, "\xf0\x0c\x54\x01\x1e\x01\x14\x6c\xb0\x53\xa3\x87\x8d\x76\x75\xd0\x30\x76\x70\x10\x24\x6a\x10\x62\x00")); +rcv($sock_a, $port_b, rtpm(96, 1002, 3640, $ssrc, "\xf0\x0c\x54\x01\x1e\x01\x14\x6c\xb0\x53\xa3\x87\x8d\x76\x75\xd0\x30\x76\x70\x10\x24\x6a\x10\x62\x00")); # wait for mode-change-interval Time::HiRes::usleep(220000); # 220 ms @@ -3063,10 +3063,10 @@ Time::HiRes::usleep(20000); # 20 ms, wait to be processed snd($sock_b, $port_a, rtp(8, 1004, 3640, 0x1234, "\x00" x 160)); # one more mode 1 -rcv($sock_a, $port_b, rtpm(96, 1003, 3880, $ssrc, "\xf0\x0c\x54\x10\x0f\x00\x0a\x21\x15\x55\x79\x82\x16\x54\xb8\x7c\x48\x00\xc8\x20\x40\x11\x88\x68\x00")); +rcv($sock_a, $port_b, rtpm(96, 1003, 3960, $ssrc, "\xf0\x0c\x54\x10\x0f\x00\x0a\x21\x15\x55\x79\x82\x16\x54\xb8\x7c\x48\x00\xc8\x20\x40\x11\x88\x68\x00")); snd($sock_b, $port_a, rtp(8, 1005, 3800, 0x1234, "\x00" x 160)); # now mode 2 -rcv($sock_a, $port_b, rtpm(96, 1004, 4200, $ssrc, "\xf0\x14\x41\x00\x30\x44\x41\x10\x09\x50\x63\x20\x92\x8a\x82\xf5\x85\xf8\x20\x25\x84\x92\x02\x01\xa1\xb2\x24\x06\x0f\x60\x03\x0f\xd1\x10")); +rcv($sock_a, $port_b, rtpm(96, 1004, 4280, $ssrc, "\xf0\x14\x41\x00\x30\x44\x41\x10\x09\x50\x63\x20\x92\x8a\x82\xf5\x85\xf8\x20\x25\x84\x92\x02\x01\xa1\xb2\x24\x06\x0f\x60\x03\x0f\xd1\x10")); @@ -3128,10 +3128,10 @@ snd($sock_a, $port_b, rtp(96, 2000, 4000, 0x5678, "\x10\x1c\xd0\x46\x09\xa1\xf1\ Time::HiRes::usleep(20000); # 20 ms, wait to be processed snd($sock_b, $port_a, rtp(8, 1002, 3320, 0x1234, "\x00" x 160)); # receive one more mode 8 frame, then CMR kicks in -rcv($sock_a, $port_b, rtpm(96, 1001, 3240, $ssrc, "\xf0\x44\xe0\x94\x24\x91\xd6\x45\x0d\x23\xdf\x00\x01\xad\xc9\x47\xc5\x2f\xf7\xfb\x62\x39\x06\xaf\x4d\x1c\x1e\x02\x6d\x94\xd1\x98\x28\x16\x25\x11\x1f\x56\xaa\x25\x40\x79\x19\x7e\x98\x8b\xbf\x78\x24\xe4\x37\x80\xad\x54\x59\x6d\xfd\x74\xcc\x40\x3f\x10")); +rcv($sock_a, $port_b, rtpm(96, 1001, 3320, $ssrc, "\xf0\x44\xe0\x94\x24\x91\xd6\x45\x0d\x23\xdf\x00\x01\xad\xc9\x47\xc5\x2f\xf7\xfb\x62\x39\x06\xaf\x4d\x1c\x1e\x02\x6d\x94\xd1\x98\x28\x16\x25\x11\x1f\x56\xaa\x25\x40\x79\x19\x7e\x98\x8b\xbf\x78\x24\xe4\x37\x80\xad\x54\x59\x6d\xfd\x74\xcc\x40\x3f\x10")); snd($sock_b, $port_a, rtp(8, 1003, 3480, 0x1234, "\x00" x 160)); # now mode 1 -rcv($sock_a, $port_b, rtpm(96, 1002, 3560, $ssrc, "\xf0\x0c\x54\x01\x1e\x01\x14\x6c\xb0\x53\xa3\x87\x8d\x76\x75\xd0\x30\x76\x70\x10\x24\x6a\x10\x62\x00")); +rcv($sock_a, $port_b, rtpm(96, 1002, 3640, $ssrc, "\xf0\x0c\x54\x01\x1e\x01\x14\x6c\xb0\x53\xa3\x87\x8d\x76\x75\xd0\x30\x76\x70\x10\x24\x6a\x10\x62\x00")); # wait for mode-change-interval Time::HiRes::usleep(220000); # 220 ms @@ -3142,10 +3142,10 @@ Time::HiRes::usleep(20000); # 20 ms, wait to be processed snd($sock_b, $port_a, rtp(8, 1004, 3640, 0x1234, "\x00" x 160)); # one more mode 1 -rcv($sock_a, $port_b, rtpm(96, 1003, 3880, $ssrc, "\xf0\x0c\x54\x10\x0f\x00\x0a\x21\x15\x55\x79\x82\x16\x54\xb8\x7c\x48\x00\xc8\x20\x40\x11\x88\x68\x00")); +rcv($sock_a, $port_b, rtpm(96, 1003, 3960, $ssrc, "\xf0\x0c\x54\x10\x0f\x00\x0a\x21\x15\x55\x79\x82\x16\x54\xb8\x7c\x48\x00\xc8\x20\x40\x11\x88\x68\x00")); snd($sock_b, $port_a, rtp(8, 1005, 3800, 0x1234, "\x00" x 160)); # now mode 2 -rcv($sock_a, $port_b, rtpm(96, 1004, 4200, $ssrc, "\xf0\x14\x41\x00\x30\x44\x41\x10\x09\x50\x63\x20\x92\x8a\x82\xf5\x85\xf8\x20\x25\x84\x92\x02\x01\xa1\xb2\x24\x06\x0f\x60\x03\x0f\xd1\x10")); +rcv($sock_a, $port_b, rtpm(96, 1004, 4280, $ssrc, "\xf0\x14\x41\x00\x30\x44\x41\x10\x09\x50\x63\x20\x92\x8a\x82\xf5\x85\xf8\x20\x25\x84\x92\x02\x01\xa1\xb2\x24\x06\x0f\x60\x03\x0f\xd1\x10")); From 1a5bcc09052594a36237936df2c20e756f307d0c Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Thu, 28 Jan 2021 14:49:43 -0500 Subject: [PATCH 08/13] TT#109251 fix redis restore segfault Change-Id: I501a47b065e7b8ff28a3ac157c0ce567f228557f --- daemon/codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/daemon/codec.c b/daemon/codec.c index 17a1de118..9fdcb4198 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -1065,7 +1065,7 @@ static void __generator_stop(struct call_media *media) { } static void __t38_options_from_flags(struct t38_options *t_opts, const struct sdp_ng_flags *flags) { -#define t38_opt(name) t_opts->name = flags->t38_ ## name +#define t38_opt(name) t_opts->name = flags ? flags->t38_ ## name : 0 t38_opt(no_ecm); t38_opt(no_v17); t38_opt(no_v27ter); @@ -1083,7 +1083,7 @@ static void __check_t38_gateway(struct call_media *pcm_media, struct call_media t_opts = sp->t38_options; else { // create our own options - if (flags->t38_fec) + if (flags && flags->t38_fec) t_opts.fec_span = 3; t_opts.max_ec_entries = 3; } From fbf74bfe2d584323ecaf8aadd13b1cfdd8b59e02 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Wed, 27 Jan 2021 10:18:14 -0500 Subject: [PATCH 09/13] TT#14008 fix possible segfault closes #1172 Change-Id: I94bb52c290c2032073e54528283660f03e694033 --- daemon/jitter_buffer.c | 8 +++----- daemon/media_socket.c | 9 ++++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/daemon/jitter_buffer.c b/daemon/jitter_buffer.c index ac25a4f16..26593ecb6 100644 --- a/daemon/jitter_buffer.c +++ b/daemon/jitter_buffer.c @@ -99,6 +99,9 @@ static int get_clock_rate(struct media_packet *mp, int payload_type) { } static struct jb_packet* get_jb_packet(struct media_packet *mp, const str *s) { + if (rtp_payload(&mp->rtp, &mp->payload, &mp->raw)) + return NULL; + char *buf = malloc(s->len + RTP_BUFFER_HEAD_ROOM + RTP_BUFFER_TAIL_ROOM); if (!buf) { ilog(LOG_ERROR, "Failed to allocate memory: %s", strerror(errno)); @@ -113,11 +116,6 @@ static struct jb_packet* get_jb_packet(struct media_packet *mp, const str *s) { str_init_len(&p->mp.raw, buf + RTP_BUFFER_HEAD_ROOM, s->len); memcpy(p->mp.raw.s, s->s, s->len); - if(rtp_payload(&p->mp.rtp, &p->mp.payload, &p->mp.raw)) { - jb_packet_free(&p); - return NULL; - } - return p; } diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 9ea26974a..8c32a0215 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -1939,9 +1939,12 @@ void media_packet_copy(struct media_packet *dst, const struct media_packet *src) dst->raw = STR_NULL; } void media_packet_release(struct media_packet *mp) { - obj_put(mp->sfd); - obj_put(&mp->ssrc_in->parent->h); - obj_put(&mp->ssrc_out->parent->h); + if (mp->sfd) + obj_put(mp->sfd); + if (mp->ssrc_in) + obj_put(&mp->ssrc_in->parent->h); + if (mp->ssrc_out) + obj_put(&mp->ssrc_out->parent->h); g_queue_clear_full(&mp->packets_out, codec_packet_free); g_free(mp->rtp); g_free(mp->rtcp); From 0c87a19c557efc3cc2fce59c5431a2a717d3a505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Ned=C5=BEibovi=C4=87?= Date: Thu, 28 Jan 2021 18:05:44 +0100 Subject: [PATCH 10/13] Implementation of control-ng via TCP. --- daemon/bencode.c | 109 ++++++++++++++++++++++++++++++++ daemon/control_ng.c | 145 +++++++++++++++++++++++++++++++++++++++++-- daemon/main.c | 17 ++++- include/bencode.h | 4 +- include/control_ng.h | 5 +- include/main.h | 1 + t/Makefile | 4 +- 7 files changed, 273 insertions(+), 12 deletions(-) diff --git a/daemon/bencode.c b/daemon/bencode.c index 4b4eb12e5..934b59cfa 100644 --- a/daemon/bencode.c +++ b/daemon/bencode.c @@ -703,3 +703,112 @@ void bencode_buffer_destroy_add(bencode_buffer_t *buf, free_func_t func, void *p li->next = buf->free_list; buf->free_list = li; } + +static int __bencode_string(const char *s, int offset, int len) { + int pos; + unsigned long long sl; + char *end; + + for (pos = offset + 1; s[pos] != 0x3a && isdigit(s[pos]) && pos < len; ++pos); + if (pos == len) + return -1; + + sl = strtoul(s + offset + 1, &end, 10); + if (s + offset + 1 == end || end != s + pos) + return -2; + + if (pos + sl > len) + return -1; + + return pos + sl + 1; +} + +static int __bencode_integer(const char *s, int offset, int len) { + int pos; + + if (s[offset + 1] == 0x2d) { + if (offset + 3 < len && s[offset + 2] == 0x30 && s[offset + 3] == 0x65) { + return -2; + } + ++offset; + } + + if (s[offset + 1] == 0x65) + return -2; + + if (s[offset + 1] == 0x30) { + if (offset + 2 < len && s[offset + 2] == 0x65) + return offset + 3; + return -2; + } + + for (pos = offset + 1; s[pos] != 0x65 && pos < len; ++pos) { + if (s[pos] < 0x30 || s[pos] > 0x39) + return -2; + } + + if (pos == len) + return -1; + + return pos + 1; +} + +static int __bencode_next(const char *s, int offset, int len); + +static int __bencode_list(const char *s, int offset, int len) { + for (++offset; s[offset] != 0x65 && offset < len;) { + offset = __bencode_next(s, offset, len); + if (offset < 0) + return offset; + } + + if (offset == len) + return -1; + + return offset + 1; +} + +static int __bencode_dictionary(const char *s, int offset, int len) { + for (++offset; s[offset] != 0x65 && offset < len;) { + offset = __bencode_string(s, offset - 1, len); + if (offset < 0) + return offset; + offset = __bencode_next(s, offset, len); + if (offset < 0) + return offset; + } + + if (offset == len) + return -1; + + return offset + 1; +} + +static int __bencode_next(const char *s, int offset, int len) { + if (offset >= len) + return -1; + switch(s[offset]) { + case 0x69: + return __bencode_integer(s, offset, len); + case 0x6c: + return __bencode_list(s, offset, len); + case 0x64: + return __bencode_dictionary(s, offset, len); + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + return __bencode_string(s, offset - 1, len); + } + return -2; +} + +int bencode_valid(const char *s, int len) { + return __bencode_next(s, 0, len); +} diff --git a/daemon/control_ng.c b/daemon/control_ng.c index 91a7cbfa2..b6807bf39 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -1,5 +1,6 @@ #include "control_ng.h" +#include #include #include #include @@ -16,10 +17,14 @@ #include "log_funcs.h" #include "main.h" #include "statistics.h" - +#include "streambuf.h" +#include "str.h" +#include "tcp_listener.h" mutex_t rtpe_cngs_lock; +mutex_t tcp_connections_lock; GHashTable *rtpe_cngs_hash; +GHashTable *tcp_connections_hash; struct control_ng *rtpe_control_ng; static struct cookie_cache ng_cookie_cache; @@ -42,7 +47,6 @@ const char *ng_command_strings_short[NGC_COUNT] = { "PlayDTMF", "Stats", }; - static void timeval_update_request_time(struct request_time *request, const struct timeval *offer_diff) { // lock offers mutex_lock(&request->lock); @@ -390,7 +394,6 @@ out: return funcret; } - static void control_ng_send(str *cookie, str *body, const endpoint_t *sin, void *p1) { socket_t *ul = p1; struct iovec iov[3]; @@ -408,13 +411,88 @@ static void control_ng_send(str *cookie, str *body, const endpoint_t *sin, void socket_sendiov(ul, iov, iovlen, sin); } - static void control_ng_incoming(struct obj *obj, struct udp_buffer *udp_buf) { control_ng_process(&udp_buf->str, &udp_buf->sin, udp_buf->addr, control_ng_send, udp_buf->listener, &udp_buf->obj); } +static void control_incoming(struct streambuf_stream *s) { + ilog(LOG_INFO, "New TCP control ng connection from %s", s->addr); + mutex_lock(&tcp_connections_lock); + g_hash_table_insert(tcp_connections_hash, s->addr, s); + mutex_unlock(&tcp_connections_lock); + ilog(LOG_DEBUG, "TCP connections map size: %d", g_hash_table_size(tcp_connections_hash)); +} + +static void control_closed(struct streambuf_stream *s) { + ilog(LOG_INFO, "TCP control ng connection from %s is closing", s->addr); + mutex_lock(&tcp_connections_lock); + g_hash_table_remove(tcp_connections_hash, s->addr); + mutex_unlock(&tcp_connections_lock); + ilog(LOG_DEBUG, "TCP connections map size: %d", g_hash_table_size(tcp_connections_hash)); +} + +static str *chunk_message(struct streambuf *b) { + char *p = NULL; + int len, to_del, bsize; + str *ret = NULL; + + mutex_lock(&b->lock); + + for (;;) { + if (b->eof) + break; + + p = memchr(b->buf->str, ' ', b->buf->len); + if (!p) + break; + + len = p - b->buf->str; + if (len == b->buf->len) + break; + + ++p; /* bencode dictionary here */ + bsize = bencode_valid(p, b->buf->str + b->buf->len - p); + if (bsize < 0) + break; /* not enough data to parse bencoded dictionary */ + + p += bsize; + len = p - b->buf->str; + to_del = len; + + ret = str_alloc(len); + memcpy(ret->s, b->buf->str, len); + ret->len = len; + g_string_erase(b->buf, 0, to_del); + + break; + } + + mutex_unlock(&b->lock); + return ret; +} + +static void control_stream_readable(struct streambuf_stream *s) { + str *data; + + ilog(LOG_DEBUG, "Got %ld bytes from %s", s->inbuf->buf->len, s->addr); + while ((data = chunk_message(s->inbuf))) { + ilog(LOG_DEBUG, "Got control ng message from %s", s->addr); + control_ng_process(data, &s->sock.remote, s->addr, control_ng_send, &s->sock, s->parent); + free(data); + } + + if (streambuf_bufsize(s->inbuf) > 1024) { + ilog(LOG_WARNING, "Buffer length exceeded in control connection from %s", s->addr); + goto close; + } + + return; + + close: + streambuf_stream_close(s); +} void control_ng_free(void *p) { struct control_ng *c = p; @@ -433,9 +511,12 @@ void control_ng_free(void *p) { poller_del_item(c->poller, c->udp_listeners[1].fd); close_socket(&c->udp_listeners[0]); close_socket(&c->udp_listeners[1]); + streambuf_listener_shutdown(&c->tcp_listeners[0]); + streambuf_listener_shutdown(&c->tcp_listeners[1]); + if (tcp_connections_hash) + g_hash_table_destroy(tcp_connections_hash); } - struct control_ng *control_ng_new(struct poller *p, endpoint_t *ep, unsigned char tos) { struct control_ng *c; @@ -463,9 +544,63 @@ struct control_ng *control_ng_new(struct poller *p, endpoint_t *ep, unsigned cha fail2: obj_put(c); return NULL; +} + +struct control_ng *control_ng_tcp_new(struct poller *p, endpoint_t *ep, struct control_ng *ctrl_ng) { + if (!p) + return NULL; + + if (!ctrl_ng) { + ctrl_ng = obj_alloc0("control_ng", sizeof(*ctrl_ng), NULL); + ctrl_ng->udp_listeners[0].fd = -1; + ctrl_ng->udp_listeners[1].fd = -1; + } + + ctrl_ng->poller = p; + + if (streambuf_listener_init(&ctrl_ng->tcp_listeners[0], p, ep, + control_incoming, control_stream_readable, + control_closed, + NULL, + &ctrl_ng->obj)) { + ilog(LOG_ERR, "Failed to open TCP control port: %s", strerror(errno)); + goto fail; + } + if (ipv46_any_convert(ep)) { + if (streambuf_listener_init(&ctrl_ng->tcp_listeners[1], p, ep, + control_incoming, control_stream_readable, + control_closed, + NULL, + &ctrl_ng->obj)) { + ilog(LOG_ERR, "Failed to open TCP control port: %s", strerror(errno)); + goto fail; + } + } + + tcp_connections_hash = g_hash_table_new(g_str_hash, g_str_equal); + mutex_init(&tcp_connections_lock); + return ctrl_ng; + +fail: + obj_put(ctrl_ng); + return NULL; +} + +static void notify_tcp_client(gpointer key, gpointer value, gpointer user_data) { + struct streambuf_stream *s = (struct streambuf_stream *)value; + str *to_send = (str *)user_data; + char cookie_buf[16]; + str cookie = STR_CONST_INIT_LEN(cookie_buf, sizeof(cookie_buf)); + rand_hex_str(cookie_buf, sizeof(cookie_buf) / 2); + control_ng_send(&cookie, to_send, &s->sock.remote, &s->sock); } +void notify_ng_tcp_clients(str *data) { + mutex_lock(&tcp_connections_lock); + g_hash_table_foreach(tcp_connections_hash, notify_tcp_client, data); + mutex_unlock(&tcp_connections_lock); +} void control_ng_init() { mutex_init(&rtpe_cngs_lock); diff --git a/daemon/main.c b/daemon/main.c index db3ba905f..bec3d985f 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -368,6 +368,7 @@ static void options(int *argc, char ***argv) { AUTO_CLEANUP_GBUF(listenps); AUTO_CLEANUP_GBUF(listenudps); AUTO_CLEANUP_GBUF(listenngs); + AUTO_CLEANUP_GBUF(listenngtcps); AUTO_CLEANUP_GBUF(listencli); AUTO_CLEANUP_GBUF(graphitep); AUTO_CLEANUP_GBUF(graphite_prefix_s); @@ -400,6 +401,7 @@ static void options(int *argc, char ***argv) { { "listen-tcp", 'l', 0, G_OPTION_ARG_STRING, &listenps, "TCP port to listen on", "[IP:]PORT" }, { "listen-udp", 'u', 0, G_OPTION_ARG_STRING, &listenudps, "UDP port to listen on", "[IP46|HOSTNAME:]PORT" }, { "listen-ng", 'n', 0, G_OPTION_ARG_STRING, &listenngs, "UDP port to listen on, NG protocol", "[IP46|HOSTNAME:]PORT" }, + { "listen-tcp-ng", 'N', 0, G_OPTION_ARG_STRING, &listenngtcps, "TCP port to listen on, NG protocol", "[IP46|HOSTNAME:]PORT" }, { "listen-cli", 'c', 0, G_OPTION_ARG_STRING, &listencli, "UDP port to listen on, CLI", "[IP46|HOSTNAME:]PORT" }, { "graphite", 'g', 0, G_OPTION_ARG_STRING, &graphitep, "Address of the graphite server", "IP46|HOSTNAME:PORT" }, { "graphite-interval", 'G', 0, G_OPTION_ARG_INT, &rtpe_config.graphite_interval, "Graphite send interval in seconds", "INT" }, @@ -504,8 +506,8 @@ static void options(int *argc, char ***argv) { if (!if_a) die("Missing option --interface"); - if (!listenps && !listenudps && !listenngs) - die("Missing option --listen-tcp, --listen-udp or --listen-ng"); + if (!listenps && !listenudps && !listenngs && !listenngtcps) + die("Missing option --listen-tcp, --listen-udp or --listen-ng or --listen-tcp-ng"); struct ifaddrs *ifas; if (getifaddrs(&ifas)) { @@ -552,6 +554,10 @@ static void options(int *argc, char ***argv) { if (endpoint_parse_any_getaddrinfo(&rtpe_config.ng_listen_ep, listenngs)) die("Invalid IP or port '%s' (--listen-ng)", listenngs); } + if (listenngtcps) { + if (endpoint_parse_any_getaddrinfo(&rtpe_config.ng_tcp_listen_ep, listenngtcps)) + die("Invalid IP or port '%s' (--listen-tcp-ng)", listenngtcps); + } if (listencli) {if (endpoint_parse_any_getaddrinfo(&rtpe_config.cli_listen_ep, listencli)) die("Invalid IP or port '%s' (--listen-cli)", listencli); @@ -787,6 +793,7 @@ void fill_initial_rtpe_cfg(struct rtpengine_config* ini_rtpe_cfg) { ini_rtpe_cfg->tcp_listen_ep = rtpe_config.tcp_listen_ep; ini_rtpe_cfg->udp_listen_ep = rtpe_config.udp_listen_ep; ini_rtpe_cfg->ng_listen_ep = rtpe_config.ng_listen_ep; + ini_rtpe_cfg->ng_tcp_listen_ep = rtpe_config.ng_tcp_listen_ep; ini_rtpe_cfg->cli_listen_ep = rtpe_config.cli_listen_ep; ini_rtpe_cfg->redis_ep = rtpe_config.redis_ep; ini_rtpe_cfg->redis_write_ep = rtpe_config.redis_write_ep; @@ -957,6 +964,12 @@ no_kernel: die("Failed to open UDP control connection port"); } + if (rtpe_config.ng_tcp_listen_ep.port) { + rtpe_control_ng = control_ng_tcp_new(rtpe_poller, &rtpe_config.ng_tcp_listen_ep, rtpe_control_ng); + if (!rtpe_control_ng) + die("Failed to open TCP control connection port"); + } + rtpe_cli = NULL; if (rtpe_config.cli_listen_ep.port) { interfaces_exclude_port(rtpe_config.cli_listen_ep.port); diff --git a/include/bencode.h b/include/bencode.h index fb7a1efc5..e729c9b70 100644 --- a/include/bencode.h +++ b/include/bencode.h @@ -301,8 +301,8 @@ INLINE bencode_item_t *bencode_decode_expect(bencode_buffer_t *buf, const char * /* Identical to bencode_decode_expect() but takes a "str" argument. */ INLINE bencode_item_t *bencode_decode_expect_str(bencode_buffer_t *buf, const str *s, bencode_type_t expect); - - +/* Returns the number of bytes that could successfully be decoded from 's', -1 if more bytes are needed or -2 on error */ +int bencode_valid(const char *s, int len); /*** DICTIONARY LOOKUP & EXTRACTION ***/ diff --git a/include/control_ng.h b/include/control_ng.h index c5d61f39b..c275ae45a 100644 --- a/include/control_ng.h +++ b/include/control_ng.h @@ -5,9 +5,9 @@ #include "udp_listener.h" #include "socket.h" #include "str.h" +#include "tcp_listener.h" #include "bencode.h" - struct poller; enum ng_command { @@ -48,6 +48,7 @@ struct control_ng_stats { struct control_ng { struct obj obj; socket_t udp_listeners[2]; + struct streambuf_listener tcp_listeners[2]; struct poller *poller; }; @@ -62,6 +63,8 @@ extern const char *ng_command_strings[NGC_COUNT]; extern const char *ng_command_strings_short[NGC_COUNT]; struct control_ng *control_ng_new(struct poller *, endpoint_t *, unsigned char); +struct control_ng *control_ng_tcp_new(struct poller *, endpoint_t *, struct control_ng *); +void notify_ng_tcp_clients(str *); void control_ng_init(void); void control_ng_cleanup(void); int control_ng_process(str *buf, const endpoint_t *sin, char *addr, diff --git a/include/main.h b/include/main.h index cf715df82..067e1e190 100644 --- a/include/main.h +++ b/include/main.h @@ -54,6 +54,7 @@ struct rtpengine_config { endpoint_t tcp_listen_ep; endpoint_t udp_listen_ep; endpoint_t ng_listen_ep; + endpoint_t ng_tcp_listen_ep; endpoint_t cli_listen_ep; endpoint_t redis_ep; endpoint_t redis_write_ep; diff --git a/t/Makefile b/t/Makefile index f184159d5..6b4bf4126 100644 --- a/t/Makefile +++ b/t/Makefile @@ -72,7 +72,7 @@ LIBSRCS+= codeclib.c resample.c socket.c streambuf.c dtmflib.c DAEMONSRCS+= codec.c call.c ice.c kernel.c media_socket.c stun.c bencode.c poller.c \ dtls.c recording.c statistics.c rtcp.c redis.c iptables.c graphite.c \ cookie_cache.c udp_listener.c homer.c load.c cdr.c dtmf.c timerthread.c \ - media_player.c jitter_buffer.c t38.c + media_player.c jitter_buffer.c t38.c tcp_listener.c HASHSRCS+= call_interfaces.c control_ng.c sdp.c endif @@ -164,7 +164,7 @@ transcode-test: transcode-test.o $(COMMONOBJS) codeclib.o resample.o codec.o ssr rtcp.o redis.o iptables.o graphite.o call_interfaces.strhash.o sdp.strhash.o rtp.o crypto.o \ control_ng.strhash.o \ streambuf.o cookie_cache.o udp_listener.o homer.o load.o cdr.o dtmf.o timerthread.o \ - media_player.o jitter_buffer.o dtmflib.o t38.o + media_player.o jitter_buffer.o dtmflib.o t38.o tcp_listener.o payload-tracker-test: payload-tracker-test.o $(COMMONOBJS) ssrc.o aux.o auxlib.o rtp.o crypto.o codeclib.o \ resample.o dtmflib.o From 813a4f1caa3f0859401b2aedcd047283a0f0ca8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Ned=C5=BEibovi=C4=87?= Date: Thu, 28 Jan 2021 18:09:10 +0100 Subject: [PATCH 11/13] Add missing include. --- daemon/bencode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/bencode.c b/daemon/bencode.c index 934b59cfa..bd019913e 100644 --- a/daemon/bencode.c +++ b/daemon/bencode.c @@ -5,7 +5,7 @@ #include #include #include - +#include /* set to 0 for alloc debugging, e.g. through valgrind */ #define BENCODE_MIN_BUFFER_PIECE_LEN 512 From 71a222d7a8e39630621f46fbb7e8c28e40eca4f0 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 29 Jan 2021 13:07:25 -0500 Subject: [PATCH 12/13] TT#14008 improve log output for stray packets Change-Id: Ic4b03928b279aade761de3ba1646b5c27318e6a3 --- daemon/media_socket.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 8c32a0215..24fffdf8e 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -1538,8 +1538,10 @@ static int media_loop_detect(struct packet_handler_ctx *phc) { __C_DBG("packet dupe"); if (phc->mp.stream->lp_count >= RTP_LOOP_MAX_COUNT) { - ilog(LOG_WARNING, "More than %d duplicate packets detected, dropping packet " - "to avoid potential loop", RTP_LOOP_MAX_COUNT); + ilog(LOG_WARNING, "More than %d duplicate packets detected, dropping packet from %s%s%s" + "to avoid potential loop", + RTP_LOOP_MAX_COUNT, + FMT_M(endpoint_print_buf(&phc->mp.fsin))); mutex_unlock(&phc->mp.stream->in_lock); return -1; } @@ -1614,7 +1616,9 @@ static void media_packet_rtp(struct packet_handler_ctx *phc) rtp_s = g_hash_table_lookup(phc->mp.stream->rtp_stats, &phc->payload_type); if (!rtp_s) { ilog(LOG_WARNING | LOG_FLAG_LIMIT, - "RTP packet with unknown payload type %u received", phc->payload_type); + "RTP packet with unknown payload type %u received from %s%s%s", + phc->payload_type, + FMT_M(endpoint_print_buf(&phc->mp.fsin))); atomic64_inc(&phc->mp.stream->stats.errors); atomic64_inc(&rtpe_statsps.errors); } @@ -1722,8 +1726,9 @@ static int media_packet_address_check(struct packet_handler_ctx *phc) // is enabled or not. if (!PS_ISSET(phc->mp.stream, CONFIRMED) && PS_ISSET(phc->mp.stream, RTP)) { if (rtcp_demux_is_rtcp(&phc->s)) { - ilog(LOG_DEBUG | LOG_FLAG_LIMIT, "Ignoring stray RTCP packet for " - "peer address confirmation purposes"); + ilog(LOG_DEBUG | LOG_FLAG_LIMIT, "Ignoring stray RTCP packet from %s%s%s for " + "peer address confirmation purposes", + FMT_M(endpoint_print_buf(&phc->mp.fsin))); goto out; } } @@ -2045,7 +2050,8 @@ static int stream_packet(struct packet_handler_ctx *phc) { if (G_UNLIKELY(!phc->sink || !phc->sink->selected_sfd || !phc->out_srtp || !phc->out_srtp->selected_sfd || !phc->in_srtp->selected_sfd)) { - ilog(LOG_WARNING, "Media packet from %s%s%s discarded", FMT_M(endpoint_print_buf(&phc->mp.fsin))); + ilog(LOG_WARNING | LOG_FLAG_LIMIT, "Media packet from %s%s%s discarded due to lack of sink", + FMT_M(endpoint_print_buf(&phc->mp.fsin))); atomic64_inc(&phc->mp.stream->stats.errors); atomic64_inc(&rtpe_statsps.errors); goto out; From 1bd3a8fc6dd2a0549208df0e9329c6a3ec322c5b Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 29 Jan 2021 10:20:02 -0500 Subject: [PATCH 13/13] TT#14008 fix AEAD kernel API for < 4.2 Untested whether it actually works closes #1176 Change-Id: If6398632ac62525a673b844cfb4ce842a8aa0346 --- kernel-module/xt_RTPENGINE.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/kernel-module/xt_RTPENGINE.c b/kernel-module/xt_RTPENGINE.c index 75d26b46e..7e0621fa8 100644 --- a/kernel-module/xt_RTPENGINE.c +++ b/kernel-module/xt_RTPENGINE.c @@ -3950,8 +3950,13 @@ static int srtp_encrypt_aes_gcm(struct re_crypto_context *c, sg_set_buf(&sg[1], r->payload, r->payload_len + 16); // guaranteed to have space after skb_copy_expand aead_request_set_callback(req, 0, NULL, NULL); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) aead_request_set_ad(req, r->header_len); aead_request_set_crypt(req, sg, sg, r->payload_len, iv); +#else + aead_request_set_assoc(req, &sg[0], r->header_len); + aead_request_set_crypt(req, &sg[1], &sg[1], r->payload_len, iv); +#endif ret = crypto_aead_encrypt(req); aead_request_free(req); @@ -3996,8 +4001,13 @@ static int srtp_decrypt_aes_gcm(struct re_crypto_context *c, sg_set_buf(&sg[1], r->payload, r->payload_len); aead_request_set_callback(req, 0, NULL, NULL); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) aead_request_set_ad(req, r->header_len); aead_request_set_crypt(req, sg, sg, r->payload_len, iv); +#else + aead_request_set_assoc(req, &sg[0], r->header_len); + aead_request_set_crypt(req, &sg[1], &sg[1], r->payload_len, iv); +#endif ret = crypto_aead_decrypt(req); aead_request_free(req);