diff --git a/daemon/call.c b/daemon/call.c index dd5385ec1..bbe7cdd31 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -5391,3 +5391,56 @@ int call_delete_branch_by_id(const str *callid, const str *branch, } return call_delete_branch(c, branch, fromtag, totag, ctx, delete_delay); } + +struct call_media *call_make_transform_media(struct call_monologue *ml, const str *type, enum media_type type_id, + const str *media_id, const endpoint_t *remote, const str *interface) +{ + struct call_media *ret = call_get_media(ml, type, type_id, media_id, false, ml->medias->len + 1); + + if (!media_id->len) + generate_mid(ret, ret->unique_id); + + ret->protocol = &transport_protocols[PROTO_RTP_AVP]; + bf_set(&ret->media_flags, MEDIA_FLAG_SEND | MEDIA_FLAG_RECV); + + ret->desired_family = remote->address.family; + __init_interface(ret, interface, 1); + + struct endpoint_map *em = __get_endpoint_map(ret, 1, remote, NULL, true); + if (!em) + return false; + + __num_media_streams(ret, 1); + __assign_stream_fds(ret, &em->intf_sfds); + + return ret; +} + +bool monologue_transform(struct call_monologue *ml, sdp_ng_flags *flags, medias_q *out_q) { + __auto_type q = &flags->medias; + + for (__auto_type l = q->head; l; l = l->next) { + __auto_type media = l->data; + + if (!media->destination.address.family) + return false; + + __auto_type m = call_make_transform_media(ml, &media->type, codec_get_type(&media->type), + &media->id, &media->destination, &flags->interface); + + media->id = m->media_id; + t_queue_push_tail(out_q, m); + + // subscribe to itself + __add_media_subscription(m, m, NULL); + + __auto_type ps = m->streams.head->data; + ps->advertised_endpoint = ps->endpoint = media->destination; + __add_sink_handler(&ps->rtp_sinks, ps, NULL); + + if (!codec_handler_transform(m, &media->codecs)) + return false; + } + + return true; +} diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 90a5b398f..415838a37 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -1585,6 +1585,115 @@ static void call_ng_received_from_iter(str *key, unsigned int i, helper_arg arg) } } +static void call_ng_payload_type(const ng_parser_t *parser, str *key, parser_arg value, + struct rtp_payload_type *pt) +{ + str s = STR_NULL; + parser->get_str(value, &s); + switch (__csh_lookup(key)) { + case CSH_LOOKUP("codec"): + pt->encoding = s; + break; + case CSH_LOOKUP("payload type"): + pt->payload_type = parser->get_int_str(value, -1); + break; + case CSH_LOOKUP("clock rate"): + pt->clock_rate = parser->get_int_str(value, 0); + break; + case CSH_LOOKUP("channels"): + pt->channels = parser->get_int_str(value, 0); + break; + case CSH_LOOKUP("format"): + pt->format_parameters = s; + break; + case CSH_LOOKUP("options"): + pt->codec_opts = s; + break; + default: + ilog(LOG_WARN, "Unknown payload type key '" STR_FORMAT "'", STR_FMT(key)); + } +} + +static void call_ng_codec(const ng_parser_t *parser, str *key, parser_arg value, struct ng_codec *codec) { + switch (__csh_lookup(key)) { + case CSH_LOOKUP("input"): + parser->dict_iter(parser, value, call_ng_payload_type, &codec->input); + break; + case CSH_LOOKUP("output"): + parser->dict_iter(parser, value, call_ng_payload_type, &codec->output); + break; + default: + ilog(LOG_WARN, "Unknown codec key '" STR_FORMAT "'", STR_FMT(key)); + } +} + +static void call_ng_codec_iter(const ng_parser_t *parser, parser_arg item, struct ng_media *media) { + __auto_type codec = g_new0(struct ng_codec, 1); + t_queue_push_tail(&media->codecs, codec); + + codec->input.payload_type = -1; + codec->output.payload_type = -1; + + parser->dict_iter(parser, item, call_ng_codec, codec); + + if (codec->input.payload_type == -1 || codec->output.payload_type == -1) + ilog(LOG_WARN, "Incomplete codec definition"); +} + +static void call_ng_endpoint(const ng_parser_t *parser, str *key, parser_arg value, struct ng_media *media) { + str s = STR_NULL; + parser->get_str(value, &s); + switch (__csh_lookup(key)) { + case CSH_LOOKUP("address"): + media->destination_address = s; + break; + case CSH_LOOKUP("family"): + case CSH_LOOKUP("address-family"): + case CSH_LOOKUP("address family"): + media->destination.address.family = get_socket_family_rfc(&s); + break; + case CSH_LOOKUP("port"): + media->destination.port = parser->get_int_str(value, 0); + break; + default: + ilog(LOG_WARN, "Unknown endpoint key '" STR_FORMAT "'", STR_FMT(key)); + } +} + +static void call_ng_media(const ng_parser_t *parser, str *key, parser_arg value, struct ng_media *media) { + str s = STR_NULL; + parser->get_str(value, &s); + switch (__csh_lookup(key)) { + case CSH_LOOKUP("codec"): + parser->list_iter(parser, value, NULL, call_ng_codec_iter, media); + break; + case CSH_LOOKUP("destination"): + parser->dict_iter(parser, value, call_ng_endpoint, media); + if (!media->destination.address.family) + ilog(LOG_ERR, "Destination address without family specified"); + else + if (!sockaddr_parse_str(&media->destination.address, media->destination.address.family, + &media->destination_address)) + ilog(LOG_ERR, "Failed to parse destination address '" STR_FORMAT "'", + STR_FMT(&media->destination_address)); + break; + case CSH_LOOKUP("id"): + media->id = s; + break; + case CSH_LOOKUP("type"): + media->type = s; + break; + default: + ilog(LOG_WARN, "Unknown media key '" STR_FORMAT "'", STR_FMT(key)); + } +} + +static void call_ng_media_iter(const ng_parser_t *parser, parser_arg item, sdp_ng_flags *out) { + __auto_type media = g_new0(struct ng_media, 1); + t_queue_push_tail(&out->medias, media); + parser->dict_iter(parser, item, call_ng_media, media); +} + void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, helper_arg arg) { str s = STR_NULL; sdp_ng_flags *out = arg.flags; @@ -1883,11 +1992,17 @@ void call_ng_main_flags(const ng_parser_t *parser, str *key, parser_arg value, h case CSH_LOOKUP("interface"): out->interface = s; break; + case CSH_LOOKUP("instance"): + out->instance = s; + break; case CSH_LOOKUP("media address"): case CSH_LOOKUP("media-address"): if (!sockaddr_parse_any_str(&out->media_address, &s)) ilog(LOG_WARN, "Could not parse 'media-address'"); break; + case CSH_LOOKUP("media"): + parser->list_iter(parser, value, NULL, call_ng_media_iter, out); + break; case CSH_LOOKUP("media echo"): case CSH_LOOKUP("media-echo"): switch (__csh_lookup_n(1, &s)) { @@ -2268,6 +2383,15 @@ static void ng_sdp_attr_manipulations_free(struct sdp_manipulations * array[__MT } } +static void ng_codecs_free(struct ng_codec *c) { + g_free(c); +} + +static void ng_media_free(struct ng_media *m) { + t_queue_clear_full(&m->codecs, ng_codecs_free); + g_free(m); +} + void call_ng_free_flags(sdp_ng_flags *flags) { str_case_value_ht_destroy_ptr(&flags->codec_set); if (flags->frequencies) @@ -2286,6 +2410,8 @@ RTPE_NG_FLAGS_STR_CASE_HT_PARAMS #undef X ng_sdp_attr_manipulations_free(flags->sdp_manipulations); + + t_queue_clear_full(&flags->medias, ng_media_free); } static enum load_limit_reasons call_offer_session_limit(void) { @@ -4195,6 +4321,88 @@ const char *call_connect_ng(ng_command_ctx_t *ctx) { return NULL; } +const char *call_transform_ng(ng_command_ctx_t *ctx) { + g_auto(sdp_ng_flags) flags; + g_autoptr(call_t) call = NULL; + + /* + * { + * command: transform + * [ call-id: ... ] + * [ from-tag: ... ] + * [ instance: ... ] + * [ interface: ... ] + * media: [ + * { + * [ id: ... ] + * type: audio/video/... + * codec: [ + * { + * input: { + * codec: G729 + * payload type: 18 + * clock rate: 8000 + * channels: 1 + * [ format: annexb=no ] + * [ options: bitrate=xxx ] + * }, + * output: { + * ... + * }, + * }, ... + * ], + * destination: { + * family: IP4 + * address: 127.0.0.1 + * port: 4444 + * }, + * }, + * ... + * ] + * } + */ + + call_ng_process_flags(&flags, ctx); + + if (flags.instance.len && !str_cmp_str(&rtpe_instance_id, &flags.instance)) + return "Transform loop detected"; + + char rand_call_id[65]; + if (!flags.call_id.len) + flags.call_id = STR_LEN(rand_hex_str(rand_call_id, 32), 64); + + char rand_from_tag[65]; + if (!flags.from_tag.len) + flags.from_tag = STR_LEN(rand_hex_str(rand_from_tag, 32), 64); + + call = call_get_or_create(&flags.call_id, false); + struct call_monologue *ml = call_get_or_create_monologue(call, &flags.from_tag); + + g_auto(medias_q) mq = TYPED_GQUEUE_INIT; + if (!monologue_transform(ml, &flags, &mq)) + return "Failed to set up transform"; + + const ng_parser_t *parser = ctx->parser_ctx.parser; + parser->dict_add_str_dup(ctx->resp, "call-id", &call->callid); + parser->dict_add_str_dup(ctx->resp, "from-tag", &ml->tag); + + parser_arg list = parser->dict_add_list(ctx->resp, "media"); + + for (__auto_type l = mq.head; l; l = l->next) { + __auto_type m = l->data; + parser_arg dict = parser->list_add_dict(list); + parser->dict_add_str_dup(dict, "id", &m->media_id); + __auto_type ps = m->streams.head->data; + __auto_type sfd = ps->selected_sfd; + parser->dict_add_str(dict, "family", STR_PTR(sfd->socket.local.address.family->rfc_name)); + parser->dict_add_str_dup(dict, "address", STR_PTR(sockaddr_print_buf(&sfd->socket.local.address))); + parser->dict_add_int(dict, "port", sfd->socket.local.port); + } + + call_unlock_release_update(&call); + return NULL; +} + void call_interfaces_free(void) { if (info_re) { diff --git a/daemon/codec.c b/daemon/codec.c index 6c7b82efa..e9fcef38c 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -1609,6 +1609,44 @@ static struct codec_handler *codec_handler_get_udptl(struct call_media *m) { #endif + +bool codec_handler_transform(struct call_media *receiver, ng_codecs_q *q) { +#ifdef WITH_TRANSCODING + if (!t_hash_table_is_set(receiver->codec_handlers)) + receiver->codec_handlers = codec_handlers_ht_new(); +#endif + + for (__auto_type j = q->head; j; j = j->next) { + __auto_type codec = j->data; + __auto_type input = &codec->input; + __auto_type output = &codec->output; + +#ifdef WITH_TRANSCODING + ensure_codec_def(input, receiver); + ensure_codec_def(output, receiver); + + __auto_type handler = __get_pt_handler(receiver, input, receiver); +#endif + + if (!rtp_payload_type_eq_nf(input, output)) { +#ifdef WITH_TRANSCODING + if (!codec_def_supported(input->codec_def) || !codec_def_supported(output->codec_def)) + return false; + __make_transcoder(handler, output, NULL, -1, false, -1); +#else + return false; +#endif + } +#ifdef WITH_TRANSCODING + else + __make_passthrough(handler, -1, -1); +#endif + } + + return true; +} + + static void __mqtt_timer_free(struct mqtt_timer *mqt) { obj_release(mqt->call); } diff --git a/daemon/control_ng.c b/daemon/control_ng.c index 8178a377e..1dedf706c 100644 --- a/daemon/control_ng.c +++ b/daemon/control_ng.c @@ -47,7 +47,7 @@ const char *ng_command_strings[OP_COUNT] = { "block silence media", "unblock silence media", "publish", "subscribe request", "subscribe answer", "unsubscribe", - "connect", "cli" + "connect", "cli", "transform" }; const char *ng_command_strings_esc[OP_COUNT] = { "ping", "offer", "answer", "delete", "query", "list", @@ -58,7 +58,7 @@ const char *ng_command_strings_esc[OP_COUNT] = { "block_silence_media", "unblock_silence_media", "publish", "subscribe_request", "subscribe_answer", "unsubscribe", - "connect", "cli" + "connect", "cli", "transform" }; const char *ng_command_strings_short[OP_COUNT] = { "Ping", "Offer", "Answer", "Delete", "Query", "List", @@ -68,7 +68,7 @@ const char *ng_command_strings_short[OP_COUNT] = { "PlayDTMF", "Stats", "SlnMedia", "UnslnMedia", "BlkSlnMedia", "UnblkSlnMedia", "Pub", "SubReq", "SubAns", "Unsub", - "Conn", "CLI" + "Conn", "CLI", "Trnsfm" }; typedef struct ng_ctx { @@ -853,6 +853,10 @@ static void control_ng_process_payload(ng_ctx *hctx, str *reply, str *data, cons command_ctx.opmode = OP_CLI; errstr = cli_ng(&command_ctx); break; + case CSH_LOOKUP("transform"): + command_ctx.opmode = OP_TRANSFORM; + errstr = call_transform_ng(&command_ctx); + break; default: errstr = "Unrecognized command"; } diff --git a/include/call.h b/include/call.h index 8b7f6efe3..db4e2befe 100644 --- a/include/call.h +++ b/include/call.h @@ -871,6 +871,7 @@ int monologue_subscribe_answer(struct call_monologue *dst, sdp_ng_flags *flags, sdp_streams_q *streams); int monologue_unsubscribe(struct call_monologue *dst, sdp_ng_flags *); void dialogue_connect(struct call_monologue *, struct call_monologue *, sdp_ng_flags *); +bool monologue_transform(struct call_monologue *, sdp_ng_flags *, medias_q *); void monologue_destroy(struct call_monologue *ml); int call_delete_branch_by_id(const str *callid, const str *branch, const str *fromtag, const str *totag, ng_command_ctx_t *, int delete_delay); diff --git a/include/call_interfaces.h b/include/call_interfaces.h index 4860ed648..d8a4d480b 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -13,6 +13,21 @@ struct call_stats; struct streambuf_stream; struct sockaddr_in6; +struct ng_codec { + struct rtp_payload_type input; + struct rtp_payload_type output; +}; + +struct ng_media { + str id; + str type; + ng_codecs_q codecs; + str destination_address; + endpoint_t destination; + +}; + + #define RTPE_NG_FLAGS_STR_Q_PARAMS \ X(from_tags) \ X(codec_strip) \ @@ -52,6 +67,7 @@ struct sdp_ng_flags { sockaddr_t media_address; str direction[2]; str interface; + str instance; sockfamily_t *address_family; int tos; str record_call_str; @@ -87,6 +103,8 @@ struct sdp_ng_flags { /* types of medias to be removed by media lvl manipulations */ bool sdp_media_remove[__MT_MAX]; + ng_medias_q medias; + enum { ICE_DEFAULT = 0, ICE_REMOVE, @@ -319,6 +337,7 @@ const char *call_subscribe_request_ng(ng_command_ctx_t *); const char *call_subscribe_answer_ng(ng_command_ctx_t *); const char *call_unsubscribe_ng(ng_command_ctx_t *); const char *call_connect_ng(ng_command_ctx_t *); +const char *call_transform_ng(ng_command_ctx_t *); void add_media_to_sub_list(subscription_q *q, struct call_media *media, struct call_monologue *ml); diff --git a/include/codec.h b/include/codec.h index a82a61014..c1db494e0 100644 --- a/include/codec.h +++ b/include/codec.h @@ -190,6 +190,8 @@ struct chu_args { #define codec_handlers_update(r, s, ...) \ __codec_handlers_update(r, s, (struct chu_args) {__VA_ARGS__}) +bool codec_handler_transform(struct call_media *r, ng_codecs_q *); + #ifdef WITH_TRANSCODING void ensure_codec_def(rtp_payload_type *pt, struct call_media *media); diff --git a/include/control_ng.h b/include/control_ng.h index bb07b641e..0bbfb5e9d 100644 --- a/include/control_ng.h +++ b/include/control_ng.h @@ -31,6 +31,7 @@ enum ng_opmode { OP_UNSUBSCRIBE, OP_CONNECT, OP_CLI, + OP_TRANSFORM, OP_COUNT, // last, number of elements OP_OTHER = OP_COUNT // alias to above @@ -85,6 +86,9 @@ typedef union { void (**call_fn)(call_t *); GHashTable *ht; struct call_monologue *ml; + struct ng_media *media; + struct ng_codec *codec; + struct rtp_payload_type *pt; void *generic; } helper_arg __attribute__ ((__transparent_union__)); diff --git a/include/types.h b/include/types.h index 51172c136..1dd2cf746 100644 --- a/include/types.h +++ b/include/types.h @@ -97,4 +97,11 @@ TYPED_GQUEUE(sdp_attr, struct sdp_attr) struct intf_config; TYPED_GQUEUE(intf_config, struct intf_config) +struct ng_codec; +TYPED_GQUEUE(ng_codecs, struct ng_codec) + +struct ng_media; +TYPED_GQUEUE(ng_medias, struct ng_media) + + #endif diff --git a/t/Makefile b/t/Makefile index 460e3ce99..3586dd726 100644 --- a/t/Makefile +++ b/t/Makefile @@ -106,7 +106,8 @@ include ../lib/common.Makefile daemon-tests-intfs daemon-tests-stats daemon-tests-delay-buffer daemon-tests-delay-timing \ daemon-tests-evs daemon-tests-player-cache daemon-tests-redis daemon-tests-redis-json \ daemon-tests-measure-rtp daemon-tests-mos-legacy daemon-tests-mos-fullband daemon-tests-config-file \ - daemon-tests-templ-def daemon-tests-templ-def-offer daemon-tests-t38 daemon-tests-evs-dtx + daemon-tests-templ-def daemon-tests-templ-def-offer daemon-tests-t38 daemon-tests-evs-dtx \ + daemon-tests-transform TESTS= test-bitstr aes-crypt aead-aes-crypt test-const_str_hash.strhash ifeq ($(with_transcoding),yes) @@ -148,7 +149,7 @@ daemon-tests: daemon-tests-main daemon-tests-jb daemon-tests-pubsub daemon-tests daemon-tests-mos-fullband daemon-tests-config-file \ daemon-tests-templ-def daemon-tests-templ-def-offer \ daemon-tests-sdp-manipulations daemon-tests-sdes-manipulations \ - daemon-tests-sdp-orig-replacements daemon-tests-moh daemon-tests-evs-dtx + daemon-tests-sdp-orig-replacements daemon-tests-moh daemon-tests-evs-dtx daemon-tests-transform daemon-test-deps: tests-preload.so $(MAKE) -C ../daemon @@ -168,6 +169,9 @@ daemon-tests-dtx-cn: daemon-test-deps daemon-tests-pubsub: daemon-test-deps ./auto-test-helper "$@" perl -I../perl auto-daemon-tests-pubsub.pl +daemon-tests-transform: daemon-test-deps + ./auto-test-helper "$@" perl -I../perl auto-daemon-tests-transform.pl + daemon-tests-stats: daemon-test-deps ./auto-test-helper "$@" perl -I../perl auto-daemon-tests-stats.pl diff --git a/t/auto-daemon-tests-transform.pl b/t/auto-daemon-tests-transform.pl new file mode 100755 index 000000000..027a46333 --- /dev/null +++ b/t/auto-daemon-tests-transform.pl @@ -0,0 +1,190 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use NGCP::Rtpengine::Test; +use NGCP::Rtpclient::SRTP; +use NGCP::Rtpengine::AutoTest; +use Test::More; +use POSIX; +use Data::Dumper; + + +autotest_start(qw(--config-file=none -t -1 -i 203.0.113.1 -i 2001:db8:4321::1 + -n 2223 -f -L 7 -E --log-level-internals=7)) + or die; + + + +my ($resp, $sock_a, $sock_b, $port_a, $seq, $ts, $ssrc); + + +($sock_a) = new_call([qw(198.51.100.14 6150)]); + +$resp = rtpe_req('transform', 'simple transform', + { + media => [ + { + type => 'audio', + codec => [ + { + input => { + codec => 'PCMA', + 'payload type' => 8, + 'clock rate' => 8000, + channels => 1, + }, + output => { + codec => 'PCMU', + 'payload type' => 0, + 'clock rate' => 8000, + channels => 1, + }, + }, + ], + destination => { + family => 'IP4', + address => '198.51.100.14', + port => 6150, + }, + }, + ], + } +); + +is($resp->{media}[0]{address}, '203.0.113.1', 'address ok'); +$port_a = $resp->{media}[0]{port}; +snd($sock_a, $port_a, rtp(8, 2000, 4000, 0x3456, "\x00" x 160)); +($seq, $ts, $ssrc) = rcv($sock_a, $port_a, rtpm(0, -1, -1, -1, "\x29" x 160)); +snd($sock_a, $port_a, rtp(8, 2001, 4160, 0x3456, "\x00" x 160)); +rcv($sock_a, $port_a, rtpm(0, $seq + 1, $ts + 160, $ssrc, "\x29" x 160)); + +rtpe_req('delete', 'delete call'); + + +($sock_a) = new_call([qw(198.51.100.14 6152)]); + +$resp = rtpe_req('transform', 'no-op transform', + { + media => [ + { + type => 'audio', + codec => [ + { + input => { + codec => 'G722', + 'payload type' => 9, + 'clock rate' => 8000, + channels => 1, + }, + output => { + codec => 'G722', + 'payload type' => 9, + 'clock rate' => 8000, + channels => 1, + }, + }, + ], + destination => { + family => 'IP4', + address => '198.51.100.14', + port => 6152, + }, + }, + ], + } +); + +is($resp->{media}[0]{address}, '203.0.113.1', 'address ok'); +$port_a = $resp->{media}[0]{port}; +snd($sock_a, $port_a, rtp(9, 2000, 4000, 0x3456, "\x00" x 160)); +rcv($sock_a, $port_a, rtpm(9, 2000, 4000, 0x3456, "\x00" x 160)); +snd($sock_a, $port_a, rtp(9, 2001, 4160, 0x3456, "\x00" x 160)); +rcv($sock_a, $port_a, rtpm(9, 2001, 4160, 0x3456, "\x00" x 160)); + +rtpe_req('delete', 'delete call'); + + +($sock_a) = new_call([qw(198.51.100.14 6154)]); + +$resp = rtpe_req('transform', 'multiple transforms', + { + media => [ + { + type => 'audio', + codec => [ + { + input => { + codec => 'G722', + 'payload type' => 9, + 'clock rate' => 8000, + channels => 1, + }, + output => { + codec => 'G722', + 'payload type' => 9, + 'clock rate' => 8000, + channels => 1, + }, + }, + { + input => { + codec => 'PCMA', + 'payload type' => 8, + 'clock rate' => 8000, + channels => 1, + }, + output => { + codec => 'PCMU', + 'payload type' => 0, + 'clock rate' => 8000, + channels => 1, + }, + }, + { + input => { + codec => 'PCMU', + 'payload type' => 0, + 'clock rate' => 8000, + channels => 1, + }, + output => { + codec => 'PCMA', + 'payload type' => 8, + 'clock rate' => 8000, + channels => 1, + }, + }, + ], + destination => { + family => 'IP4', + address => '198.51.100.14', + port => 6154, + }, + }, + ], + } +); + +is($resp->{media}[0]{address}, '203.0.113.1', 'address ok'); +$port_a = $resp->{media}[0]{port}; +snd($sock_a, $port_a, rtp(9, 2000, 4000, 0x3456, "\x00" x 160)); +($seq, $ts, $ssrc) = rcv($sock_a, $port_a, rtpm(9, -1, -1, -1, "\x00" x 160)); +snd($sock_a, $port_a, rtp(9, 2001, 4160, 0x3456, "\x00" x 160)); +($seq, $ts, $ssrc) = rcv($sock_a, $port_a, rtpm(9, $seq + 1, $ts + 160, $ssrc, "\x00" x 160)); + +snd($sock_a, $port_a, rtp(8, 2000, 4000, 0x346a, "\x00" x 160)); +($seq, $ts, $ssrc) = rcv($sock_a, $port_a, rtpm(0, -1, -1, -1, "\x29" x 160)); +snd($sock_a, $port_a, rtp(8, 2001, 4160, 0x346a, "\x00" x 160)); +($seq, $ts, $ssrc) = rcv($sock_a, $port_a, rtpm(0, $seq + 1, $ts + 160, $ssrc, "\x29" x 160)); + +snd($sock_a, $port_a, rtp(0, 2000, 4000, 0x347e, "\x00" x 160)); +($seq, $ts, $ssrc) = rcv($sock_a, $port_a, rtpm(8, -1, -1, -1, "\x2a" x 160)); +snd($sock_a, $port_a, rtp(0, 2001, 4160, 0x347e, "\x00" x 160)); +($seq, $ts, $ssrc) = rcv($sock_a, $port_a, rtpm(8, $seq + 1, $ts + 160, $ssrc, "\x2a" x 160)); + +rtpe_req('delete', 'delete call'); + + +done_testing(); +#done_testing;NGCP::Rtpengine::AutoTest::terminate('f00');exit; diff --git a/t/test-stats.c b/t/test-stats.c index 3537ae9d8..1db29e253 100644 --- a/t/test-stats.c +++ b/t/test-stats.c @@ -290,6 +290,13 @@ int main(void) { "clis_ps_max 0 150\n" "clis_ps_avg 0 150\n" "cli_count 0 150\n" + "transform_time_min 0.000000 150\n" + "transform_time_max 0.000000 150\n" + "transform_time_avg 0.000000 150\n" + "transforms_ps_min 0 150\n" + "transforms_ps_max 0 150\n" + "transforms_ps_avg 0 150\n" + "transform_count 0 150\n" "call_dur 0.000000 150\n" "average_call_dur 0.000000 150\n" "forced_term_sess 0 150\n" @@ -772,6 +779,14 @@ int main(void) { "0.000000\n" "avgclidelay\n" "0.000000\n" + "Min/Max/Avg transform processing delay\n" + "0.000000/0.000000/0.000000 sec\n" + "mintransformdelay\n" + "0.000000\n" + "maxtransformdelay\n" + "0.000000\n" + "avgtransformdelay\n" + "0.000000\n" "Min/Max/Avg ping requests per second\n" "0/0/0 per sec\n" "minpingrequestrate\n" @@ -1004,6 +1019,14 @@ int main(void) { "0\n" "avgclirequestrate\n" "0\n" + "Min/Max/Avg transform requests per second\n" + "0/0/0 per sec\n" + "mintransformrequestrate\n" + "0\n" + "maxtransformrequestrate\n" + "0\n" + "avgtransformrequestrate\n" + "0\n" "\n" "\n" "}\n" @@ -1167,7 +1190,7 @@ int main(void) { "{\n" "proxies\n" "[\n" - " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI \n" + " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI | Trnsfm \n" "\n" "]\n" "totalpingcount\n" @@ -1228,6 +1251,8 @@ int main(void) { "0\n" "totalclicount\n" "0\n" + "totaltrnsfmcount\n" + "0\n" "\n" "}\n" "interfaces\n" @@ -1451,6 +1476,13 @@ int main(void) { "clis_ps_max 0 150\n" "clis_ps_avg 0 150\n" "cli_count 0 150\n" + "transform_time_min 0.000000 150\n" + "transform_time_max 0.000000 150\n" + "transform_time_avg 0.000000 150\n" + "transforms_ps_min 0 150\n" + "transforms_ps_max 0 150\n" + "transforms_ps_avg 0 150\n" + "transform_count 0 150\n" "call_dur 0.000000 150\n" "average_call_dur 0.000000 150\n" "forced_term_sess 0 150\n" @@ -1933,6 +1965,14 @@ int main(void) { "0.000000\n" "avgclidelay\n" "0.000000\n" + "Min/Max/Avg transform processing delay\n" + "0.000000/0.000000/0.000000 sec\n" + "mintransformdelay\n" + "0.000000\n" + "maxtransformdelay\n" + "0.000000\n" + "avgtransformdelay\n" + "0.000000\n" "Min/Max/Avg ping requests per second\n" "0/0/0 per sec\n" "minpingrequestrate\n" @@ -2165,6 +2205,14 @@ int main(void) { "0\n" "avgclirequestrate\n" "0\n" + "Min/Max/Avg transform requests per second\n" + "0/0/0 per sec\n" + "mintransformrequestrate\n" + "0\n" + "maxtransformrequestrate\n" + "0\n" + "avgtransformrequestrate\n" + "0\n" "\n" "\n" "}\n" @@ -2328,7 +2376,7 @@ int main(void) { "{\n" "proxies\n" "[\n" - " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI \n" + " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI | Trnsfm \n" "\n" "]\n" "totalpingcount\n" @@ -2389,6 +2437,8 @@ int main(void) { "0\n" "totalclicount\n" "0\n" + "totaltrnsfmcount\n" + "0\n" "\n" "}\n" "interfaces\n" @@ -2609,6 +2659,13 @@ int main(void) { "clis_ps_max 0 150\n" "clis_ps_avg 0 150\n" "cli_count 0 150\n" + "transform_time_min 0.000000 150\n" + "transform_time_max 0.000000 150\n" + "transform_time_avg 0.000000 150\n" + "transforms_ps_min 0 150\n" + "transforms_ps_max 0 150\n" + "transforms_ps_avg 0 150\n" + "transform_count 0 150\n" "call_dur 0.000000 150\n" "average_call_dur 0.000000 150\n" "forced_term_sess 0 150\n" @@ -3091,6 +3148,14 @@ int main(void) { "0.000000\n" "avgclidelay\n" "0.000000\n" + "Min/Max/Avg transform processing delay\n" + "0.000000/0.000000/0.000000 sec\n" + "mintransformdelay\n" + "0.000000\n" + "maxtransformdelay\n" + "0.000000\n" + "avgtransformdelay\n" + "0.000000\n" "Min/Max/Avg ping requests per second\n" "0/0/0 per sec\n" "minpingrequestrate\n" @@ -3323,6 +3388,14 @@ int main(void) { "0\n" "avgclirequestrate\n" "0\n" + "Min/Max/Avg transform requests per second\n" + "0/0/0 per sec\n" + "mintransformrequestrate\n" + "0\n" + "maxtransformrequestrate\n" + "0\n" + "avgtransformrequestrate\n" + "0\n" "\n" "\n" "}\n" @@ -3486,7 +3559,7 @@ int main(void) { "{\n" "proxies\n" "[\n" - " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI \n" + " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI | Trnsfm \n" "\n" "]\n" "totalpingcount\n" @@ -3547,6 +3620,8 @@ int main(void) { "0\n" "totalclicount\n" "0\n" + "totaltrnsfmcount\n" + "0\n" "\n" "}\n" "interfaces\n" @@ -3786,6 +3861,13 @@ int main(void) { "clis_ps_max 0 157\n" "clis_ps_avg 0 157\n" "cli_count 0 157\n" + "transform_time_min 0.000000 157\n" + "transform_time_max 0.000000 157\n" + "transform_time_avg 0.000000 157\n" + "transforms_ps_min 0 157\n" + "transforms_ps_max 0 157\n" + "transforms_ps_avg 0 157\n" + "transform_count 0 157\n" "call_dur 0.000000 157\n" "average_call_dur 0.000000 157\n" "forced_term_sess 0 157\n" @@ -4268,6 +4350,14 @@ int main(void) { "0.000000\n" "avgclidelay\n" "0.000000\n" + "Min/Max/Avg transform processing delay\n" + "0.000000/0.000000/0.000000 sec\n" + "mintransformdelay\n" + "0.000000\n" + "maxtransformdelay\n" + "0.000000\n" + "avgtransformdelay\n" + "0.000000\n" "Min/Max/Avg ping requests per second\n" "0/0/0 per sec\n" "minpingrequestrate\n" @@ -4500,6 +4590,14 @@ int main(void) { "0\n" "avgclirequestrate\n" "0\n" + "Min/Max/Avg transform requests per second\n" + "0/0/0 per sec\n" + "mintransformrequestrate\n" + "0\n" + "maxtransformrequestrate\n" + "0\n" + "avgtransformrequestrate\n" + "0\n" "\n" "\n" "}\n" @@ -4663,7 +4761,7 @@ int main(void) { "{\n" "proxies\n" "[\n" - " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI \n" + " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI | Trnsfm \n" "\n" "]\n" "totalpingcount\n" @@ -4724,6 +4822,8 @@ int main(void) { "0\n" "totalclicount\n" "0\n" + "totaltrnsfmcount\n" + "0\n" "\n" "}\n" "interfaces\n" @@ -4952,6 +5052,13 @@ int main(void) { "clis_ps_max 0 157\n" "clis_ps_avg 0 157\n" "cli_count 0 157\n" + "transform_time_min 0.000000 157\n" + "transform_time_max 0.000000 157\n" + "transform_time_avg 0.000000 157\n" + "transforms_ps_min 0 157\n" + "transforms_ps_max 0 157\n" + "transforms_ps_avg 0 157\n" + "transform_count 0 157\n" "call_dur 0.000000 157\n" "average_call_dur 0.000000 157\n" "forced_term_sess 0 157\n" @@ -5434,6 +5541,14 @@ int main(void) { "0.000000\n" "avgclidelay\n" "0.000000\n" + "Min/Max/Avg transform processing delay\n" + "0.000000/0.000000/0.000000 sec\n" + "mintransformdelay\n" + "0.000000\n" + "maxtransformdelay\n" + "0.000000\n" + "avgtransformdelay\n" + "0.000000\n" "Min/Max/Avg ping requests per second\n" "0/0/0 per sec\n" "minpingrequestrate\n" @@ -5666,6 +5781,14 @@ int main(void) { "0\n" "avgclirequestrate\n" "0\n" + "Min/Max/Avg transform requests per second\n" + "0/0/0 per sec\n" + "mintransformrequestrate\n" + "0\n" + "maxtransformrequestrate\n" + "0\n" + "avgtransformrequestrate\n" + "0\n" "\n" "\n" "}\n" @@ -5829,7 +5952,7 @@ int main(void) { "{\n" "proxies\n" "[\n" - " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI \n" + " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI | Trnsfm \n" "\n" "]\n" "totalpingcount\n" @@ -5890,6 +6013,8 @@ int main(void) { "0\n" "totalclicount\n" "0\n" + "totaltrnsfmcount\n" + "0\n" "\n" "}\n" "interfaces\n" @@ -6113,6 +6238,13 @@ int main(void) { "clis_ps_max 0 200\n" "clis_ps_avg 0 200\n" "cli_count 0 200\n" + "transform_time_min 0.000000 200\n" + "transform_time_max 0.000000 200\n" + "transform_time_avg 0.000000 200\n" + "transforms_ps_min 0 200\n" + "transforms_ps_max 0 200\n" + "transforms_ps_avg 0 200\n" + "transform_count 0 200\n" "call_dur 143.000000 200\n" "average_call_dur 0.000000 200\n" "forced_term_sess 0 200\n" @@ -6595,6 +6727,14 @@ int main(void) { "0.000000\n" "avgclidelay\n" "0.000000\n" + "Min/Max/Avg transform processing delay\n" + "0.000000/0.000000/0.000000 sec\n" + "mintransformdelay\n" + "0.000000\n" + "maxtransformdelay\n" + "0.000000\n" + "avgtransformdelay\n" + "0.000000\n" "Min/Max/Avg ping requests per second\n" "0/0/0 per sec\n" "minpingrequestrate\n" @@ -6827,6 +6967,14 @@ int main(void) { "0\n" "avgclirequestrate\n" "0\n" + "Min/Max/Avg transform requests per second\n" + "0/0/0 per sec\n" + "mintransformrequestrate\n" + "0\n" + "maxtransformrequestrate\n" + "0\n" + "avgtransformrequestrate\n" + "0\n" "\n" "\n" "}\n" @@ -6990,7 +7138,7 @@ int main(void) { "{\n" "proxies\n" "[\n" - " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI \n" + " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI | Trnsfm \n" "\n" "]\n" "totalpingcount\n" @@ -7051,6 +7199,8 @@ int main(void) { "0\n" "totalclicount\n" "0\n" + "totaltrnsfmcount\n" + "0\n" "\n" "}\n" "interfaces\n" @@ -7276,6 +7426,13 @@ int main(void) { "clis_ps_max 0 200\n" "clis_ps_avg 0 200\n" "cli_count 0 200\n" + "transform_time_min 0.000000 200\n" + "transform_time_max 0.000000 200\n" + "transform_time_avg 0.000000 200\n" + "transforms_ps_min 0 200\n" + "transforms_ps_max 0 200\n" + "transforms_ps_avg 0 200\n" + "transform_count 0 200\n" "call_dur 0.000000 200\n" "average_call_dur 93.000000 200\n" "forced_term_sess 0 200\n" @@ -7758,6 +7915,14 @@ int main(void) { "0.000000\n" "avgclidelay\n" "0.000000\n" + "Min/Max/Avg transform processing delay\n" + "0.000000/0.000000/0.000000 sec\n" + "mintransformdelay\n" + "0.000000\n" + "maxtransformdelay\n" + "0.000000\n" + "avgtransformdelay\n" + "0.000000\n" "Min/Max/Avg ping requests per second\n" "0/0/0 per sec\n" "minpingrequestrate\n" @@ -7990,6 +8155,14 @@ int main(void) { "0\n" "avgclirequestrate\n" "0\n" + "Min/Max/Avg transform requests per second\n" + "0/0/0 per sec\n" + "mintransformrequestrate\n" + "0\n" + "maxtransformrequestrate\n" + "0\n" + "avgtransformrequestrate\n" + "0\n" "\n" "\n" "}\n" @@ -8153,7 +8326,7 @@ int main(void) { "{\n" "proxies\n" "[\n" - " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI \n" + " Proxy | Ping | Offer | Answer | Delete | Query | List | StartRec | StopRec | PauseRec | StartFwd | StopFwd | BlkDTMF | UnblkDTMF | BlkMedia | UnblkMedia | PlayMedia | StopMedia | PlayDTMF | Stats | SlnMedia | UnslnMedia | BlkSlnMedia | UnblkSlnMedia | Pub | SubReq | SubAns | Unsub | Conn | CLI | Trnsfm \n" "\n" "]\n" "totalpingcount\n" @@ -8214,6 +8387,8 @@ int main(void) { "0\n" "totalclicount\n" "0\n" + "totaltrnsfmcount\n" + "0\n" "\n" "}\n" "interfaces\n"