diff options
-rw-r--r-- | test/main.c | 1 | ||||
-rw-r--r-- | test/mock/mock_auplay.c | 101 | ||||
-rw-r--r-- | test/play.c | 99 | ||||
-rw-r--r-- | test/srcs.mk | 6 | ||||
-rw-r--r-- | test/test.c | 65 | ||||
-rw-r--r-- | test/test.h | 30 |
6 files changed, 300 insertions, 2 deletions
diff --git a/test/main.c b/test/main.c index 057da2d..125f1ec 100644 --- a/test/main.c +++ b/test/main.c @@ -42,6 +42,7 @@ static const struct test tests[] = { TEST(test_message), TEST(test_mos), TEST(test_network), + TEST(test_play), TEST(test_ua_alloc), TEST(test_ua_options), TEST(test_ua_register), diff --git a/test/mock/mock_auplay.c b/test/mock/mock_auplay.c new file mode 100644 index 0000000..9857d9f --- /dev/null +++ b/test/mock/mock_auplay.c @@ -0,0 +1,101 @@ +/** + * @file mock/mock_auplay.c Mock audio player + * + * Copyright (C) 2010 - 2016 Creytiv.com + */ +#include <re.h> +#include <baresip.h> +#include "../test.h" + + +struct auplay_st { + const struct auplay *ap; /* inheritance */ + + struct tmr tmr; + struct auplay_prm prm; + int16_t *sampv; + size_t sampc; + auplay_write_h *wh; + void *arg; +}; + + +static struct { + mock_sample_h *sampleh; + void *arg; +} mock; + + +static void tmr_handler(void *arg) +{ + struct auplay_st *st = arg; + + tmr_start(&st->tmr, st->prm.ptime, tmr_handler, st); + + if (st->wh) + st->wh(st->sampv, st->sampc, st->arg); + + /* feed the audio-samples back to the test */ + if (mock.sampleh) + mock.sampleh(st->sampv, st->sampc, mock.arg); +} + + +static void auplay_destructor(void *arg) +{ + struct auplay_st *st = arg; + + tmr_cancel(&st->tmr); + mem_deref(st->sampv); +} + + +static int mock_auplay_alloc(struct auplay_st **stp, const struct auplay *ap, + struct auplay_prm *prm, const char *device, + auplay_write_h *wh, void *arg) +{ + struct auplay_st *st; + int err = 0; + (void)device; + + if (!stp || !ap || !prm) + return EINVAL; + + st = mem_zalloc(sizeof(*st), auplay_destructor); + if (!st) + return ENOMEM; + + st->ap = ap; + st->prm = *prm; + st->wh = wh; + st->arg = arg; + + st->sampc = prm->srate * prm->ch * prm->ptime / 1000; + + st->sampv = mem_zalloc(2 * st->sampc, NULL); + if (!st->sampv) { + err = ENOMEM; + goto out; + } + + tmr_start(&st->tmr, 0, tmr_handler, st); + + out: + if (err) + mem_deref(st); + else + *stp = st; + + return err; +} + + +int mock_auplay_register(struct auplay **auplayp, + mock_sample_h *sampleh, void *arg) +{ + mock.sampleh = sampleh; + mock.arg = arg; + + return auplay_register(auplayp, baresip_auplayl(), + "mock-auplay", mock_auplay_alloc); +} diff --git a/test/play.c b/test/play.c new file mode 100644 index 0000000..9e8c09c --- /dev/null +++ b/test/play.c @@ -0,0 +1,99 @@ +/** + * @file test/play.c Baresip selftest -- audio file player + * + * Copyright (C) 2010 Creytiv.com + */ +#include <string.h> +#include <re.h> +#include <baresip.h> +#include "test.h" + + +#define NUM_SAMPLES 320 /* 8000 Hz, 1 channel, 40ms */ + + +struct test { + struct mbuf *mb_samp; +}; + + +static struct mbuf *generate_tone(void) +{ + struct mbuf *mb; + unsigned i; + int err = 0; + + mb = mbuf_alloc(NUM_SAMPLES * 2); + if (!mb) + return NULL; + + for (i=0; i<NUM_SAMPLES; i++) + err |= mbuf_write_u16(mb, i); + + mb->pos = 0; + + if (err) + return mem_deref(mb); + else + return mb; +} + + +static void sample_handler(const int16_t *sampv, size_t sampc, void *arg) +{ + struct test *test = arg; + size_t bytec = sampc * 2; + int err = 0; + + if (!test->mb_samp) { + test->mb_samp = mbuf_alloc(bytec); + ASSERT_TRUE(test->mb_samp != NULL); + } + + /* save the samples that was played */ + err = mbuf_write_mem(test->mb_samp, (void *)sampv, bytec); + + out: + /* stop the test? */ + if (err || test->mb_samp->end >= (NUM_SAMPLES*2)) + re_cancel(); +} + + +int test_play(void) +{ + struct auplay *auplay = NULL; + struct player *player = NULL; + struct play *play = NULL; + struct mbuf *mb_tone = NULL; + struct test test = {0}; + int err; + + /* use a mock audio-driver to save the audio-samples */ + err = mock_auplay_register(&auplay, sample_handler, &test); + ASSERT_EQ(0, err); + + err = play_init(&player); + ASSERT_EQ(0, err); + + mb_tone = generate_tone(); + ASSERT_TRUE(mb_tone != NULL); + + err = play_tone(&play, player, mb_tone, 8000, 1, 0); + ASSERT_EQ(0, err); + + err = re_main_timeout(10000); + ASSERT_EQ(0, err); + + /* verify the audio-samples that was played */ + TEST_MEMCMP(mb_tone->buf, NUM_SAMPLES*2, + test.mb_samp->buf, test.mb_samp->end); + + out: + mem_deref(test.mb_samp); + mem_deref(mb_tone); + mem_deref(play); + mem_deref(player); + mem_deref(auplay); + return err; +} diff --git a/test/srcs.mk b/test/srcs.mk index 417742f..91d4d3d 100644 --- a/test/srcs.mk +++ b/test/srcs.mk @@ -9,14 +9,15 @@ # Test-cases: # TEST_SRCS += account.c +TEST_SRCS += call.c TEST_SRCS += cmd.c TEST_SRCS += contact.c -TEST_SRCS += ua.c TEST_SRCS += cplusplus.c -TEST_SRCS += call.c TEST_SRCS += message.c TEST_SRCS += mos.c TEST_SRCS += net.c +TEST_SRCS += play.c +TEST_SRCS += ua.c # @@ -35,6 +36,7 @@ ifneq ($(USE_TLS),) TEST_SRCS += mock/cert.c endif +TEST_SRCS += mock/mock_auplay.c TEST_SRCS += mock/mock_ausrc.c ifneq ($(USE_VIDEO),) TEST_SRCS += mock/mock_vidsrc.c diff --git a/test/test.c b/test/test.c index 8623180..d1fa3ad 100644 --- a/test/test.c +++ b/test/test.c @@ -42,3 +42,68 @@ bool test_cmp_double(double a, double b, double precision) { return fabs(a - b) < precision; } + + +void test_hexdump_dual(FILE *f, + const void *ep, size_t elen, + const void *ap, size_t alen) +{ + const uint8_t *ebuf = ep; + const uint8_t *abuf = ap; + size_t i, j, len; +#define WIDTH 8 + + if (!f || !ep || !ap) + return; + + len = max(elen, alen); + + (void)re_fprintf(f, "\nOffset: Expected (%zu bytes): " + " Actual (%zu bytes):\n", elen, alen); + + for (i=0; i < len; i += WIDTH) { + + (void)re_fprintf(f, "0x%04zx ", i); + + for (j=0; j<WIDTH; j++) { + const size_t pos = i+j; + if (pos < elen) { + bool wrong = pos >= alen; + + if (wrong) + (void)re_fprintf(f, "\x1b[35m"); + (void)re_fprintf(f, " %02x", ebuf[pos]); + if (wrong) + (void)re_fprintf(f, "\x1b[;m"); + } + else + (void)re_fprintf(f, " "); + } + + (void)re_fprintf(f, " "); + + for (j=0; j<WIDTH; j++) { + const size_t pos = i+j; + if (pos < alen) { + bool wrong; + + if (pos < elen) + wrong = ebuf[pos] != abuf[pos]; + else + wrong = true; + + if (wrong) + (void)re_fprintf(f, "\x1b[33m"); + (void)re_fprintf(f, " %02x", abuf[pos]); + if (wrong) + (void)re_fprintf(f, "\x1b[;m"); + } + else + (void)re_fprintf(f, " "); + } + + (void)re_fprintf(f, "\n"); + } + + (void)re_fprintf(f, "\n"); +} diff --git a/test/test.h b/test/test.h index d928517..b7ef3e0 100644 --- a/test/test.h +++ b/test/test.h @@ -53,6 +53,20 @@ goto out; \ } +#define TEST_MEMCMP(expected, expn, actual, actn) \ + if (expn != actn || \ + 0 != memcmp((expected), (actual), (expn))) { \ + (void)re_fprintf(stderr, "\n"); \ + warning("TEST_MEMCMP: %s:%u:" \ + " %s(): failed\n", \ + __FILE__, __LINE__, __func__); \ + test_hexdump_dual(stderr, \ + expected, expn, \ + actual, actn); \ + err = EINVAL; \ + goto out; \ + } + #define TEST_STRCMP(expected, expn, actual, actn) \ if (expn != actn || \ 0 != memcmp((expected), (actual), (expn))) { \ @@ -79,6 +93,9 @@ int re_main_timeout(uint32_t timeout_ms); bool test_cmp_double(double a, double b, double precision); +void test_hexdump_dual(FILE *f, + const void *ep, size_t elen, + const void *ap, size_t alen); #ifdef USE_TLS @@ -114,6 +131,18 @@ int mock_ausrc_register(struct ausrc **ausrcp); /* + * Mock Audio-player + */ + +struct auplay; + +typedef void (mock_sample_h)(const int16_t *sampv, size_t sampc, void *arg); + +int mock_auplay_register(struct auplay **auplayp, + mock_sample_h *sampleh, void *arg); + + +/* * Mock Video-source */ @@ -155,6 +184,7 @@ int test_ua_options(void); int test_message(void); int test_mos(void); int test_network(void); +int test_play(void); int test_call_answer(void); int test_call_reject(void); |