From d64c888a0ebc3ceb3387251b9e3eb887e6243c84 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 14 May 2018 13:57:05 -0400 Subject: [PATCH] TT#36301 transcoding unit tests Change-Id: If48e5afe5a343b557183b6e87441f52424dd2c6a --- daemon/log_funcs.h | 1 + {daemon => include}/call_interfaces.h | 0 {daemon => include}/cdr.h | 0 {daemon => include}/cli.h | 0 {daemon => include}/codec.h | 0 {daemon => include}/control_ng.h | 0 {daemon => include}/control_tcp.h | 0 {daemon => include}/control_udp.h | 0 {daemon => include}/cookie_cache.h | 0 {daemon => include}/graphite.h | 0 {daemon => include}/homer.h | 0 {daemon => include}/ice.h | 0 {daemon => include}/iptables.h | 0 {daemon => include}/kernel.h | 0 {daemon => include}/load.h | 0 {daemon => include}/main.h | 0 {daemon => include}/poller.h | 0 {daemon => include}/redis.h | 0 {daemon => include}/sdp.h | 0 {daemon => include}/ssrc.h | 0 {daemon => include}/streambuf.h | 0 {daemon => include}/stun.h | 0 {daemon => include}/tcp_listener.h | 0 {daemon => include}/udp_listener.h | 0 t/.gitignore | 29 +++ t/.ycm_extra_conf.py | 1 + t/Makefile | 33 ++- t/log.h | 7 + t/log_funcs.h | 24 ++ t/transcode-test.c | 356 ++++++++++++++++++++++++++ 30 files changed, 448 insertions(+), 3 deletions(-) rename {daemon => include}/call_interfaces.h (100%) rename {daemon => include}/cdr.h (100%) rename {daemon => include}/cli.h (100%) rename {daemon => include}/codec.h (100%) rename {daemon => include}/control_ng.h (100%) rename {daemon => include}/control_tcp.h (100%) rename {daemon => include}/control_udp.h (100%) rename {daemon => include}/cookie_cache.h (100%) rename {daemon => include}/graphite.h (100%) rename {daemon => include}/homer.h (100%) rename {daemon => include}/ice.h (100%) rename {daemon => include}/iptables.h (100%) rename {daemon => include}/kernel.h (100%) rename {daemon => include}/load.h (100%) rename {daemon => include}/main.h (100%) rename {daemon => include}/poller.h (100%) rename {daemon => include}/redis.h (100%) rename {daemon => include}/sdp.h (100%) rename {daemon => include}/ssrc.h (100%) rename {daemon => include}/streambuf.h (100%) rename {daemon => include}/stun.h (100%) rename {daemon => include}/tcp_listener.h (100%) rename {daemon => include}/udp_listener.h (100%) create mode 100644 t/log_funcs.h create mode 100644 t/transcode-test.c diff --git a/daemon/log_funcs.h b/daemon/log_funcs.h index 87f62481e..4c6229a31 100644 --- a/daemon/log_funcs.h +++ b/daemon/log_funcs.h @@ -6,6 +6,7 @@ #include "call.h" #include "media_socket.h" #include "ice.h" +#include "log.h" INLINE void log_info_clear() { switch (log_info.e) { diff --git a/daemon/call_interfaces.h b/include/call_interfaces.h similarity index 100% rename from daemon/call_interfaces.h rename to include/call_interfaces.h diff --git a/daemon/cdr.h b/include/cdr.h similarity index 100% rename from daemon/cdr.h rename to include/cdr.h diff --git a/daemon/cli.h b/include/cli.h similarity index 100% rename from daemon/cli.h rename to include/cli.h diff --git a/daemon/codec.h b/include/codec.h similarity index 100% rename from daemon/codec.h rename to include/codec.h diff --git a/daemon/control_ng.h b/include/control_ng.h similarity index 100% rename from daemon/control_ng.h rename to include/control_ng.h diff --git a/daemon/control_tcp.h b/include/control_tcp.h similarity index 100% rename from daemon/control_tcp.h rename to include/control_tcp.h diff --git a/daemon/control_udp.h b/include/control_udp.h similarity index 100% rename from daemon/control_udp.h rename to include/control_udp.h diff --git a/daemon/cookie_cache.h b/include/cookie_cache.h similarity index 100% rename from daemon/cookie_cache.h rename to include/cookie_cache.h diff --git a/daemon/graphite.h b/include/graphite.h similarity index 100% rename from daemon/graphite.h rename to include/graphite.h diff --git a/daemon/homer.h b/include/homer.h similarity index 100% rename from daemon/homer.h rename to include/homer.h diff --git a/daemon/ice.h b/include/ice.h similarity index 100% rename from daemon/ice.h rename to include/ice.h diff --git a/daemon/iptables.h b/include/iptables.h similarity index 100% rename from daemon/iptables.h rename to include/iptables.h diff --git a/daemon/kernel.h b/include/kernel.h similarity index 100% rename from daemon/kernel.h rename to include/kernel.h diff --git a/daemon/load.h b/include/load.h similarity index 100% rename from daemon/load.h rename to include/load.h diff --git a/daemon/main.h b/include/main.h similarity index 100% rename from daemon/main.h rename to include/main.h diff --git a/daemon/poller.h b/include/poller.h similarity index 100% rename from daemon/poller.h rename to include/poller.h diff --git a/daemon/redis.h b/include/redis.h similarity index 100% rename from daemon/redis.h rename to include/redis.h diff --git a/daemon/sdp.h b/include/sdp.h similarity index 100% rename from daemon/sdp.h rename to include/sdp.h diff --git a/daemon/ssrc.h b/include/ssrc.h similarity index 100% rename from daemon/ssrc.h rename to include/ssrc.h diff --git a/daemon/streambuf.h b/include/streambuf.h similarity index 100% rename from daemon/streambuf.h rename to include/streambuf.h diff --git a/daemon/stun.h b/include/stun.h similarity index 100% rename from daemon/stun.h rename to include/stun.h diff --git a/daemon/tcp_listener.h b/include/tcp_listener.h similarity index 100% rename from daemon/tcp_listener.h rename to include/tcp_listener.h diff --git a/daemon/udp_listener.h b/include/udp_listener.h similarity index 100% rename from daemon/udp_listener.h rename to include/udp_listener.h diff --git a/t/.gitignore b/t/.gitignore index 676e1606f..a8d692760 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -13,3 +13,32 @@ rtplib.c str.c crypto.c aes-crypt +aux.c +bencode.c +call.c +call_interfaces.c +cdr.c +codec.c +control_ng.c +cookie_cache.c +dtls.c +graphite.c +homer.c +ice.c +iptables.c +kernel.c +load.c +media_socket.c +poller.c +recording.c +redis.c +rtcp.c +rtp.c +sdp.c +socket.c +ssrc.c +statistics.c +streambuf.c +stun.c +transcode-test +udp_listener.c diff --git a/t/.ycm_extra_conf.py b/t/.ycm_extra_conf.py index 85c659d13..ae7a3870c 100644 --- a/t/.ycm_extra_conf.py +++ b/t/.ycm_extra_conf.py @@ -23,6 +23,7 @@ flags = [ '-I../kernel-module/', '-I../lib/', '-I../daemon/', + '-I../include/', '-D_GNU_SOURCE', '-D__DEBUG=1', '-D__YCM=1', diff --git a/t/Makefile b/t/Makefile index 756221d4a..d9e08194f 100644 --- a/t/Makefile +++ b/t/Makefile @@ -16,10 +16,18 @@ CFLAGS+= $(shell pkg-config --cflags libavutil) CFLAGS+= $(shell pkg-config --cflags libswresample) CFLAGS+= $(shell pkg-config --cflags libavfilter) CFLAGS+= -DWITH_TRANSCODING +CFLAGS+= $(shell pkg-config --cflags libpcre) +CFLAGS+= $(shell pkg-config --cflags zlib) +CFLAGS+= $(shell pkg-config --cflags json-glib-1.0) +CFLAGS+= $(shell pkg-config --cflags libevent_pthreads) +CFLAGS+= $(shell pkg-config xmlrpc_client --cflags 2> /dev/null || xmlrpc-c-config client --cflags) +CFLAGS+= $(shell pkg-config xmlrpc --cflags 2> /dev/null) +CFLAGS+= $(shell pkg-config xmlrpc_util --cflags 2> /dev/null) else CFLAGS+= -DWITHOUT_CODECLIB endif +LDLIBS= -lm LDLIBS+= $(shell pkg-config --libs glib-2.0) LDLIBS+= $(shell pkg-config --libs gthread-2.0) LDLIBS+= $(shell pkg-config --libs libcrypto) @@ -30,17 +38,31 @@ LDLIBS+= $(shell pkg-config --libs libavformat) LDLIBS+= $(shell pkg-config --libs libavutil) LDLIBS+= $(shell pkg-config --libs libswresample) LDLIBS+= $(shell pkg-config --libs libavfilter) +LDLIBS+= $(shell pkg-config --libs libpcre) +LDLIBS+= $(shell pkg-config --libs zlib) +LDLIBS+= $(shell pkg-config --libs json-glib-1.0) +LDLIBS+= -lpcap +LDLIBS+= $(shell pkg-config --libs libevent_pthreads) +LDLIBS+= $(shell pkg-config xmlrpc_client --libs 2> /dev/null || xmlrpc-c-config client --libs) +LDLIBS+= $(shell pkg-config xmlrpc --libs 2> /dev/null) +LDLIBS+= $(shell pkg-config xmlrpc_util --libs 2> /dev/null) +LDLIBS+= -lhiredis endif SRCS= bitstr-test.c aes-crypt.c ifeq ($(with_transcoding),yes) -SRCS+= amr-decode-test.c amr-encode-test.c +SRCS+= amr-decode-test.c amr-encode-test.c transcode-test.c endif LIBSRCS= loglib.c auxlib.c str.c rtplib.c ifeq ($(with_transcoding),yes) LIBSRCS+= codeclib.c resample.c endif DAEMONSRCS= crypto.c +ifeq ($(with_transcoding),yes) +DAEMONSRCS+= codec.c ssrc.c call.c ice.c aux.c kernel.c media_socket.c stun.c bencode.c socket.c poller.c \ + dtls.c recording.c statistics.c rtcp.c redis.c iptables.c graphite.c call_interfaces.c sdp.c \ + rtp.c control_ng.c streambuf.c cookie_cache.c udp_listener.c homer.c load.c cdr.c +endif OBJS= $(SRCS:.c=.o) $(LIBSRCS:.c=.o) $(DAEMONSRCS:.c=.o) COMMONOBJS= str.o auxlib.o rtplib.o loglib.o @@ -53,13 +75,13 @@ include .depend TESTS= bitstr-test aes-crypt ifeq ($(with_transcoding),yes) -TESTS+= amr-decode-test amr-encode-test +TESTS+= amr-decode-test amr-encode-test transcode-test endif ADD_CLEAN= $(TESTS) unit-tests: $(TESTS) - for x in $(TESTS); do echo testing: $$x; ./$$x || exit 1; done + for x in $(TESTS); do echo testing: $$x; G_DEBUG=fatal-warnings ./$$x || exit 1; done bitstr-test: bitstr-test.o @@ -68,3 +90,8 @@ amr-decode-test: amr-decode-test.o $(COMMONOBJS) codeclib.o resample.o amr-encode-test: amr-encode-test.o $(COMMONOBJS) codeclib.o resample.o aes-crypt: aes-crypt.o $(COMMONOBJS) crypto.o + +transcode-test: transcode-test.o $(COMMONOBJS) codeclib.o resample.o codec.o ssrc.o call.o ice.o aux.o \ + kernel.o media_socket.o stun.o bencode.o socket.o poller.o dtls.o recording.o statistics.o \ + rtcp.o redis.o iptables.o graphite.o call_interfaces.o sdp.o rtp.o crypto.o control_ng.o \ + streambuf.o cookie_cache.o udp_listener.o homer.o load.o cdr.o diff --git a/t/log.h b/t/log.h index 38b8d34c8..8ef7a2482 100644 --- a/t/log.h +++ b/t/log.h @@ -4,4 +4,11 @@ #include "loglib.h" #define __ilog(prio, fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__) +INLINE void rtcplog(const char *x) { +} +INLINE void cdrlog(const char *x) { +} +extern int _log_facility_rtcp; +extern int _log_facility_cdr; + #endif diff --git a/t/log_funcs.h b/t/log_funcs.h new file mode 100644 index 000000000..ffba6d974 --- /dev/null +++ b/t/log_funcs.h @@ -0,0 +1,24 @@ +#ifndef _LOG_FUNCS_H_ +#define _LOG_FUNCS_H_ + +#include "aux.h" +#include "str.h" + +struct call; +struct stream_fd; +struct ice_agent; + +INLINE void log_info_clear() { +} +INLINE void log_info_call(struct call *c) { +} +INLINE void log_info_stream_fd(struct stream_fd *sfd) { +} +INLINE void log_info_str(const str *s) { +} +INLINE void log_info_c_string(const char *s) { +} +INLINE void log_info_ice_agent(struct ice_agent *ag) { +} + +#endif diff --git a/t/transcode-test.c b/t/transcode-test.c new file mode 100644 index 000000000..716b52ade --- /dev/null +++ b/t/transcode-test.c @@ -0,0 +1,356 @@ +#include "codec.h" +#include "call.h" +#include "call_interfaces.h" +#include "log.h" +#include "main.h" +#include "ssrc.h" + +int _log_facility_rtcp; +int _log_facility_cdr; +struct rtpengine_config rtpe_config; +struct poller *rtpe_poller; + +static str *sdup(char *s) { + str *r = g_slice_alloc(sizeof(*r)); + str_init(r, s); + return r; +} +static void queue_dump(GString *s, GQueue *q) { + for (GList *l = q->head; l; l = l->next) { + if (s->len) + g_string_append(s, " "); + struct rtp_payload_type *pt = l->data; + g_string_append_printf(s, "%i/%s", pt->payload_type, pt->encoding_with_params.s); + if (pt->format_parameters.len) + g_string_append_printf(s, "/%s", pt->format_parameters.s); + } +} + +#define start() { \ + printf("running test %s:%i\n", __FILE__, __LINE__); \ + struct call call = {{0,},}; \ + call.ssrc_hash = create_ssrc_hash_call(); \ + struct sdp_ng_flags flags = {0,}; \ + bencode_buffer_init(&call.buffer); \ + struct call_media *media_A = call_media_new(&call); /* originator */ \ + struct call_media *media_B = call_media_new(&call); /* output destination */ \ + GQueue rtp_types = G_QUEUE_INIT; /* parsed from received SDP */ \ + flags.codec_strip = g_hash_table_new_full(str_hash, str_equal, str_slice_free, NULL); \ + flags.codec_mask = g_hash_table_new_full(str_hash, str_equal, str_slice_free, NULL) + +#define transcode(codec) g_queue_push_tail(&flags.codec_transcode, sdup(#codec)) + +#define sdp_pt_fmt(num, codec, clockrate, fmt) { \ + struct rtp_payload_type *pt = g_slice_alloc(sizeof(*pt)); \ + *pt = (struct rtp_payload_type) { num, STR_CONST_INIT(#codec "/" #clockrate), STR_CONST_INIT(#codec), \ + clockrate, STR_CONST_INIT(""), 1, STR_CONST_INIT(fmt), 0, 0, NULL }; \ + g_queue_push_tail(&rtp_types, pt); \ + } + +#define sdp_pt(num, codec, clockrate) sdp_pt_fmt(num, codec, clockrate, "") + +#define offer() \ + codec_rtp_payload_types(media_B, media_A, &rtp_types, \ + flags.codec_strip, &flags.codec_offer, &flags.codec_transcode, \ + flags.codec_mask); \ + codec_handlers_update(media_B, media_A, &flags); \ + g_queue_clear(&rtp_types); \ + memset(&flags, 0, sizeof(flags)) + +#define answer() \ + codec_rtp_payload_types(media_A, media_B, &rtp_types, \ + flags.codec_strip, &flags.codec_offer, &flags.codec_transcode, \ + flags.codec_mask); \ + codec_handlers_update(media_A, media_B, &flags); \ + +#define expect(side, dir, codecs) { \ + printf("running test %s:%i\n", __FILE__, __LINE__); \ + GString *s = g_string_new(""); \ + queue_dump(s, &media_ ## side->codecs_prefs_ ## dir); \ + if (strcmp(s->str, codecs) != 0) { \ + printf("test failed: %s:%i\n", __FILE__, __LINE__); \ + printf("expected: %s\n", codecs); \ + printf("received: %s\n", s->str); \ + abort(); \ + } \ + printf("test ok: %s:%i\n", __FILE__, __LINE__); \ + g_string_free(s, TRUE); \ + } + +#define packet_seq(side, pt_in, pload, pt_out, pload_exp, rtp_ts, rtp_seq) { \ + printf("running test %s:%i\n", __FILE__, __LINE__); \ + struct codec_handler *h = codec_handler_get(media_ ## side, pt_in); \ + str pl = STR_CONST_INIT(pload); \ + str pl_exp = STR_CONST_INIT(pload_exp); \ + struct media_packet mp = { \ + .media = media_ ## side, \ + .ssrc_in = get_ssrc_ctx(1234, call.ssrc_hash, SSRC_DIR_INPUT), \ + .ssrc_out = get_ssrc_ctx(1234, call.ssrc_hash, SSRC_DIR_OUTPUT), \ + }; \ + int packet_len = sizeof(struct rtp_header) + pl.len; \ + char *packet = malloc(packet_len); \ + struct rtp_header *rtp = (void *) packet; \ + *rtp = (struct rtp_header) { \ + .m_pt = pt_in, \ + .ssrc = 1234, \ + .seq_num = htons(rtp_seq), \ + .timestamp = htonl(rtp_ts), \ + }; \ + mp.rtp = rtp; \ + mp.payload = pl; \ + mp.payload.s = (packet + sizeof(struct rtp_header)); \ + memcpy(mp.payload.s, pl.s, pl.len); \ + mp.raw.s = packet; \ + mp.raw.len = packet_len; \ + h->func(h, media_A, &mp); \ + if (pt_out == -1) { \ + if (mp.packets_out.length != 0) { \ + printf("test failed: %s:%i\n", __FILE__, __LINE__); \ + printf("unexpected packet\n"); \ + abort(); \ + } \ + } \ + else { \ + if (mp.packets_out.length != 1) { \ + printf("test failed: %s:%i\n", __FILE__, __LINE__); \ + printf("no packet\n"); \ + abort(); \ + } \ + struct codec_packet *cp = g_queue_pop_head(&mp.packets_out); \ + rtp = (void *) cp->s.s; \ + if (rtp->m_pt != pt_out) { \ + printf("test failed: %s:%i\n", __FILE__, __LINE__); \ + printf("expected: %i\n", pt_out); \ + printf("received: %i\n", rtp->m_pt); \ + abort(); \ + } \ + printf("packet contents: "); \ + for (int i = sizeof(struct rtp_header); i < cp->s.len; i++) { \ + unsigned char cc = cp->s.s[i]; \ + printf("\\x%02x", cc); \ + } \ + printf("\n"); \ + if (str_shift(&cp->s, sizeof(struct rtp_header))) \ + abort(); \ + if (pl_exp.len != cp->s.len) \ + abort(); \ + if (memcmp(pl_exp.s, cp->s.s, pl_exp.len)) \ + abort(); \ + } \ + printf("test ok: %s:%i\n", __FILE__, __LINE__); \ + free(packet); \ +} + +#define packet(side, pt_in, pload, pt_out, pload_exp) \ + packet_seq(side, pt_in, pload, pt_out, pload_exp, 0, 0) + +#define end() } /* free/cleanup should go here */ + +#define PCMU_payload "\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00" +#define PCMU_payload_AMR "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x7e\xff\x7e\xf6\xf3\xf5\xf5\xf5\xf6\xf7\xf7\xf8\xf9\xf9\xfa\xfb\xfb\xfc\xfc\xfd\xfd\xfe\xfe\xff\xff\x7e\xff\x7d\xff\x7b\xfc\xf6\xf5\xf6\xe3\x6e\x42\x3d\x3d\x3e\x3f\x41\x3f\x3d\x3f\x41\x44\x46\x49\x4b\x4d\x50\x54\x58\x5b\x60\x67\x6f\x74\xec\x6c\x46\x41\x42\x45\x48\x4a\x4d\x4f\x60\xff\xdb\xd2\xce\xc6\xc6\xc5\xc4\xc6\xbf\xbe\xba\xba\xba\xb8\xb6\xb4\xb3\xb2\xb0\xb0\xaf\xaf\xae\xae\xaf\xae\xae\xae\xaf\xb1\xb1\xb2\xb2\xb4\xb6\xb6\xb7\xb7\xb8\xb8\xb8\xb9\xb9\xba\xb8\xb9\xb9\xba\xba\xbb\xbb\xbd\xbc\xbd\xbf\xbf\xc0\xc2\xc5\xc8\xca\xcd\xce\xd0\xdc\xdc\xe5\xe7\xf0\xf8\x7c\x6f\x70\x65\x6e\x62\x60" // after AMR decode +#define PCMA_payload "\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a\x2b\x2a" +#define AMR_WB_payload "\xf0\x1c\xf3\x06\x08\x10\x77\x32\x23\x20\xd3\x50\x62\x12\xc7\x7c\xe2\xea\x84\x0e\x6e\xf4\x4d\xe4\x7f\xc9\x4c\xcc\x58\x5d\xed\xcc\x5d\x7c\x6c\x14\x7d\xc0" // octet aligned +#define AMR_WB_payload_noe "\xf1\xfc\xc1\x82\x04\x1d\xcc\x88\xc8\x34\xd4\x18\x84\xb1\xdf\x38\xba\xa1\x03\x9b\xbd\x13\x79\x1f\xf2\x53\x33\x16\x17\x7b\x73\x17\x5f\x1b\x05\x1f\x70" // bandwidth efficient + +int main() { + codeclib_init(0); + + // plain + start(); + sdp_pt(0, PCMU, 8000); + offer(); + expect(A, recv, ""); + expect(A, send, "0/PCMU/8000"); + expect(B, recv, "0/PCMU/8000"); + expect(B, send, ""); + sdp_pt(0, PCMU, 8000); + answer(); + expect(A, recv, "0/PCMU/8000"); + expect(A, send, "0/PCMU/8000"); + expect(B, recv, "0/PCMU/8000"); + expect(B, send, "0/PCMU/8000"); + packet(A, 0, PCMU_payload, 0, PCMU_payload); + packet(B, 0, PCMU_payload, 0, PCMU_payload); + end(); + + // plain with two offered and two answered + start(); + sdp_pt(0, PCMU, 8000); + sdp_pt(8, PCMA, 8000); + offer(); + expect(A, recv, ""); + expect(A, send, "0/PCMU/8000 8/PCMA/8000"); + expect(B, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(B, send, ""); + sdp_pt(0, PCMU, 8000); + sdp_pt(8, PCMA, 8000); + answer(); + expect(A, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(A, send, "0/PCMU/8000 8/PCMA/8000"); + expect(B, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(B, send, "0/PCMU/8000 8/PCMA/8000"); + packet(A, 0, PCMU_payload, 0, PCMU_payload); + packet(B, 0, PCMU_payload, 0, PCMU_payload); + packet(A, 8, PCMA_payload, 8, PCMA_payload); + packet(B, 8, PCMA_payload, 8, PCMA_payload); + end(); + + // plain with two offered and two answered + always-transcode one way + start(); + flags.always_transcode = 1; + sdp_pt(0, PCMU, 8000); + sdp_pt(8, PCMA, 8000); + offer(); + expect(A, recv, ""); + expect(A, send, "0/PCMU/8000 8/PCMA/8000"); + expect(B, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(B, send, ""); + sdp_pt(0, PCMU, 8000); + sdp_pt(8, PCMA, 8000); + answer(); + expect(A, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(A, send, "0/PCMU/8000 8/PCMA/8000"); + expect(B, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(B, send, "0/PCMU/8000 8/PCMA/8000"); + packet(A, 0, PCMU_payload, 0, PCMU_payload); + packet(B, 0, PCMU_payload, 0, PCMU_payload); + packet(A, 8, PCMA_payload, 8, PCMA_payload); + packet(B, 8, PCMA_payload, 0, PCMU_payload); + end(); + + // plain with two offered and two answered + always-transcode both ways + start(); + flags.always_transcode = 1; + sdp_pt(0, PCMU, 8000); + sdp_pt(8, PCMA, 8000); + offer(); + expect(A, recv, ""); + expect(A, send, "0/PCMU/8000 8/PCMA/8000"); + expect(B, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(B, send, ""); + flags.always_transcode = 1; + sdp_pt(0, PCMU, 8000); + sdp_pt(8, PCMA, 8000); + answer(); + expect(A, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(A, send, "0/PCMU/8000 8/PCMA/8000"); + expect(B, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(B, send, "0/PCMU/8000 8/PCMA/8000"); + packet(A, 0, PCMU_payload, 0, PCMU_payload); + packet(B, 0, PCMU_payload, 0, PCMU_payload); + packet(A, 8, PCMA_payload, 0, PCMU_payload); + packet(B, 8, PCMA_payload, 0, PCMU_payload); + end(); + + // add one codec to transcode + start(); + sdp_pt(0, PCMU, 8000); + transcode(PCMA); + offer(); + expect(A, recv, ""); + expect(A, send, "0/PCMU/8000"); + expect(B, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(B, send, ""); + sdp_pt(0, PCMU, 8000); + sdp_pt(8, PCMA, 8000); + answer(); + expect(A, recv, "0/PCMU/8000"); + expect(A, send, "0/PCMU/8000"); + expect(B, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(B, send, "0/PCMU/8000 8/PCMA/8000"); + packet(A, 0, PCMU_payload, 0, PCMU_payload); + packet(B, 0, PCMU_payload, 0, PCMU_payload); + packet(B, 8, PCMA_payload, 0, PCMU_payload); + end(); + + // add one codec to transcode, don't accept original offered codec + start(); + sdp_pt(0, PCMU, 8000); + transcode(PCMA); + offer(); + expect(A, recv, ""); + expect(A, send, "0/PCMU/8000"); + expect(B, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(B, send, ""); + sdp_pt(8, PCMA, 8000); + answer(); + expect(A, recv, "0/PCMU/8000"); + expect(A, send, "0/PCMU/8000"); + expect(B, recv, "0/PCMU/8000 8/PCMA/8000"); + expect(B, send, "8/PCMA/8000"); + packet(A, 0, PCMU_payload, 8, PCMA_payload); + packet(B, 8, PCMA_payload, 0, PCMU_payload); + end(); + + { + str codec_name = STR_CONST_INIT("AMR-WB"); + const codec_def_t *def = codec_find(&codec_name, MT_AUDIO); + assert(def); + if (def->support_encoding && def->support_decoding) { + // forward AMR-WB + start(); + sdp_pt(0, PCMU, 8000); + transcode(AMR-WB); + offer(); + expect(A, recv, ""); + expect(A, send, "0/PCMU/8000"); + expect(B, recv, "0/PCMU/8000 96/AMR-WB/16000/octet-align=1"); + expect(B, send, ""); + sdp_pt_fmt(96, AMR-WB, 16000, "octet-align=1"); + answer(); + expect(A, recv, "0/PCMU/8000"); + expect(A, send, "0/PCMU/8000"); + expect(B, recv, "0/PCMU/8000 96/AMR-WB/16000/octet-align=1"); + expect(B, send, "96/AMR-WB/16000/octet-align=1"); + packet_seq(A, 0, PCMU_payload, -1, "", 0, 0); // nothing due to resampling buffer + packet_seq(A, 0, PCMU_payload, 96, AMR_WB_payload, 160, 1); + packet_seq(B, 96, AMR_WB_payload, -1, "", 0, 0); // nothing due to resampling/decoding buffer + packet_seq(B, 96, AMR_WB_payload, 0, PCMU_payload_AMR, 320, 1); + end(); + + // reverse AMR-WB (octet aligned) + start(); + sdp_pt_fmt(96, AMR-WB, 16000, "octet-align=1"); + transcode(PCMU); + offer(); + expect(A, recv, ""); + expect(A, send, "96/AMR-WB/16000/octet-align=1"); + expect(B, recv, "96/AMR-WB/16000/octet-align=1 0/PCMU/8000"); + expect(B, send, ""); + sdp_pt(0, PCMU, 8000); + answer(); + expect(A, recv, "96/AMR-WB/16000/octet-align=1"); + expect(A, send, "96/AMR-WB/16000/octet-align=1"); + expect(B, recv, "96/AMR-WB/16000/octet-align=1 0/PCMU/8000"); + expect(B, send, "0/PCMU/8000"); + packet_seq(B, 0, PCMU_payload, -1, "", 0, 0); // nothing due to resampling buffer + packet_seq(B, 0, PCMU_payload, 96, AMR_WB_payload, 160, 1); + packet_seq(A, 96, AMR_WB_payload, -1, "", 0, 0); // nothing due to resampling/decoding buffer + packet_seq(A, 96, AMR_WB_payload, 0, PCMU_payload_AMR, 320, 1); + end(); + + // reverse AMR-WB (bandwidth efficient) + start(); + sdp_pt(96, AMR-WB, 16000); + transcode(PCMU); + offer(); + expect(A, recv, ""); + expect(A, send, "96/AMR-WB/16000"); + expect(B, recv, "96/AMR-WB/16000 0/PCMU/8000"); + expect(B, send, ""); + sdp_pt(0, PCMU, 8000); + answer(); + expect(A, recv, "96/AMR-WB/16000"); + expect(A, send, "96/AMR-WB/16000"); + expect(B, recv, "96/AMR-WB/16000 0/PCMU/8000"); + expect(B, send, "0/PCMU/8000"); + packet_seq(B, 0, PCMU_payload, -1, "", 0, 0); // nothing due to resampling buffer + packet_seq(B, 0, PCMU_payload, 96, AMR_WB_payload_noe, 160, 1); + packet_seq(A, 96, AMR_WB_payload_noe, -1, "", 0, 0); // nothing due to resampling/decoding buffer + packet_seq(A, 96, AMR_WB_payload_noe, 0, PCMU_payload_AMR, 320, 1); + end(); + } + } + + return 0; +}