[alsa-devel] [RFCv2][PATCH 12/38] axfer: add a unit test for mapper interface
Takashi Sakamoto
o-takashi at sakamocchi.jp
Tue Sep 19 02:43:52 CEST 2017
In former commits, mapper module gets supports of muxer/demuxer for
several cases for playback source or capture destination. This commit adds
a unit test for them. This includes positive test cases only. The test
cases actually generate I/O to file systems for many test cases. It takes a
bit long time to finish.
Signed-off-by: Takashi Sakamoto <o-takashi at sakamocchi.jp>
---
axfer/test/Makefile.am | 20 +-
axfer/test/mapper-test.c | 491 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 509 insertions(+), 2 deletions(-)
create mode 100644 axfer/test/mapper-test.c
diff --git a/axfer/test/Makefile.am b/axfer/test/Makefile.am
index 66b30ef8..76a93bfc 100644
--- a/axfer/test/Makefile.am
+++ b/axfer/test/Makefile.am
@@ -1,8 +1,10 @@
TESTS = \
- container-test
+ container-test \
+ mapper-test
check_PROGRAMS = \
- container-test
+ container-test \
+ mapper-test
container_test_SOURCES = \
../container.h \
@@ -13,3 +15,17 @@ container_test_SOURCES = \
../container-raw.c \
generator.c \
container-test.c
+
+mapper_test_SOURCES = \
+ ../container.h \
+ ../container.c \
+ ../container-riff-wave.c \
+ ../container-au.c \
+ ../container-voc.c \
+ ../container-raw.c \
+ ../mapper.h \
+ ../mapper.c \
+ ../mapper-single.c \
+ ../mapper-multiple.c \
+ generator.c \
+ mapper-test.c
diff --git a/axfer/test/mapper-test.c b/axfer/test/mapper-test.c
new file mode 100644
index 00000000..554e638e
--- /dev/null
+++ b/axfer/test/mapper-test.c
@@ -0,0 +1,491 @@
+/*
+ * mapper-io.c - a unit test for muxer/demuxer for PCM frames on buffer.
+ *
+ * Copyright (c) 2017 Takashi Sakamoto <o-takashi at sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "../mapper.h"
+#include "../misc.h"
+
+#include "generator.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include <assert.h>
+
+struct mapper_trial {
+ enum container_format cntr_format;
+ struct container_context *cntrs;
+
+ char **paths;
+
+ struct mapper_context mapper;
+ bool verbose;
+};
+
+static void test_demuxer(struct mapper_context *mapper, snd_pcm_access_t access,
+ unsigned int bytes_per_sample,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_buffer,
+ void *frame_buffer, unsigned int frame_count,
+ struct container_context *cntrs,
+ unsigned int cntr_count, bool verbose)
+{
+ unsigned int total_frame_count;
+ int err;
+
+ err = mapper_context_init(mapper, MAPPER_TYPE_DEMUXER, cntr_count,
+ verbose);
+ assert(err == 0);
+
+ err = mapper_context_pre_process(mapper, access, bytes_per_sample,
+ samples_per_frame, frames_per_buffer,
+ cntrs);
+ assert(err == 0);
+
+ total_frame_count = frame_count;
+ err = mapper_context_process_frames(mapper, frame_buffer,
+ &total_frame_count, cntrs);
+ assert(err == 0);
+ assert(total_frame_count == frame_count);
+
+ mapper_context_post_process(mapper);
+ mapper_context_destroy(mapper);
+}
+
+static int test_demux(struct mapper_trial *trial, snd_pcm_access_t access,
+ snd_pcm_format_t sample_format,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_second,
+ unsigned int frames_per_buffer,
+ void *frame_buffer, unsigned int frame_count,
+ unsigned int cntr_count)
+{
+ struct container_context *cntrs = trial->cntrs;
+ char **paths = trial->paths;
+ enum container_format cntr_format = trial->cntr_format;
+ unsigned int bytes_per_sample;
+ uint64_t total_frame_count;
+ int i;
+ int err;
+
+ for (i = 0; i < cntr_count; ++i) {
+ snd_pcm_format_t format;
+ unsigned int channels;
+ unsigned int rate;
+
+ err = container_builder_init(cntrs + i, paths[i], cntr_format,
+ 0);
+ if (err < 0)
+ goto end;
+
+ format = sample_format;
+ rate = frames_per_second;
+ total_frame_count = frame_count;
+ if (cntr_count > 1)
+ channels = 1;
+ else
+ channels = samples_per_frame;
+ err = container_context_pre_process(cntrs + i, &format,
+ &channels, &rate,
+ &total_frame_count);
+ if (err < 0)
+ goto end;
+ assert(format == sample_format);
+ assert(rate == frames_per_second);
+ assert(total_frame_count >= 0);
+ if (cntr_count > 1)
+ assert(channels == 1);
+ else
+ assert(channels == samples_per_frame);
+ }
+
+ bytes_per_sample = snd_pcm_format_physical_width(sample_format) / 8;
+ test_demuxer(&trial->mapper, access, bytes_per_sample,
+ samples_per_frame, frames_per_buffer, frame_buffer,
+ frame_count, cntrs, cntr_count, trial->verbose);
+
+ for (i = 0; i < cntr_count; ++i) {
+ container_context_post_process(cntrs + i, &total_frame_count);
+ assert(total_frame_count == frame_count);
+ }
+end:
+ for (i = 0; i < cntr_count; ++i)
+ container_context_destroy(cntrs + i);
+
+ return err;
+}
+
+static void test_muxer(struct mapper_context *mapper, snd_pcm_access_t access,
+ unsigned int bytes_per_sample,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_buffer,
+ void *frame_buffer, unsigned int frame_count,
+ struct container_context *cntrs,
+ unsigned int cntr_count, bool verbose)
+{
+ unsigned int total_frame_count;
+ int err;
+
+ err = mapper_context_init(mapper, MAPPER_TYPE_MUXER, cntr_count,
+ verbose);
+ assert(err == 0);
+
+ err = mapper_context_pre_process(mapper, access, bytes_per_sample,
+ samples_per_frame, frames_per_buffer,
+ cntrs);
+ assert(err == 0);
+
+ total_frame_count = frame_count;
+ err = mapper_context_process_frames(mapper, frame_buffer,
+ &total_frame_count, cntrs);
+ assert(err == 0);
+ assert(total_frame_count == frame_count);
+
+ mapper_context_post_process(mapper);
+ mapper_context_destroy(mapper);
+}
+
+static int test_mux(struct mapper_trial *trial, snd_pcm_access_t access,
+ snd_pcm_format_t sample_format,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_second,
+ unsigned int frames_per_buffer,
+ void *frame_buffer, unsigned int frame_count,
+ unsigned int cntr_count)
+{
+ struct container_context *cntrs = trial->cntrs;
+ char **paths = trial->paths;
+ unsigned int bytes_per_sample;
+ uint64_t total_frame_count;
+ int i;
+ int err;
+
+ for (i = 0; i < cntr_count; ++i) {
+ snd_pcm_format_t format;
+ unsigned int channels;
+ unsigned int rate;
+
+ err = container_parser_init(cntrs + i, paths[i], 0);
+ if (err < 0)
+ goto end;
+
+ format = sample_format;
+ rate = frames_per_second;
+ if (cntr_count > 1)
+ channels = 1;
+ else
+ channels = samples_per_frame;
+ err = container_context_pre_process(cntrs + i, &format,
+ &channels, &rate,
+ &total_frame_count);
+ if (err < 0)
+ goto end;
+
+ assert(format == sample_format);
+ assert(rate == frames_per_second);
+ assert(total_frame_count == frame_count);
+ if (cntr_count > 1)
+ assert(channels == 1);
+ else
+ assert(channels == samples_per_frame);
+ }
+
+ bytes_per_sample = snd_pcm_format_physical_width(sample_format) / 8;
+ test_muxer(&trial->mapper, access, bytes_per_sample, samples_per_frame,
+ frames_per_buffer, frame_buffer, frame_count, cntrs,
+ cntr_count, trial->verbose);
+
+ for (i = 0; i < cntr_count; ++i) {
+ container_context_post_process(cntrs + i, &total_frame_count);
+ assert(total_frame_count == frame_count);
+ }
+end:
+ for (i = 0; i < cntr_count; ++i)
+ container_context_destroy(cntrs + i);
+
+ return err;
+}
+
+static int test_mapper(struct mapper_trial *trial, snd_pcm_access_t access,
+ snd_pcm_format_t sample_format,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_second, void *frame_buffer,
+ void *check_buffer, unsigned int frame_count,
+ unsigned int cntr_count)
+{
+ unsigned int frames_per_buffer;
+ int i;
+ int err;
+
+ /* Use a buffer aligned by typical size of page frame. */
+ frames_per_buffer = ((frame_count + 4096) / 4096) * 4096;
+
+ err = test_demux(trial, access, sample_format, samples_per_frame,
+ frames_per_second, frames_per_buffer, frame_buffer,
+ frame_count, cntr_count);
+ if (err < 0)
+ goto end;
+
+ err = test_mux(trial, access, sample_format, samples_per_frame,
+ frames_per_second, frames_per_buffer, check_buffer,
+ frame_count, cntr_count);
+end:
+ for (i = 0; i < cntr_count; ++i)
+ unlink(trial->paths[i]);
+
+ return err;
+}
+
+static int test_i_buf(struct mapper_trial *trial, snd_pcm_access_t access,
+ snd_pcm_format_t sample_format,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_second, void *frame_buffer,
+ unsigned int frame_count, unsigned int cntr_count)
+{
+ unsigned int size;
+ char *buf;
+ int err;
+
+ size = frame_count * samples_per_frame *
+ snd_pcm_format_physical_width(sample_format) / 8;
+ buf = malloc(size);
+ if (buf == 0)
+ return -ENOMEM;
+ memset(buf, 0, size);
+
+ /* Test multiple target. */
+ err = test_mapper(trial, access, sample_format, samples_per_frame,
+ frames_per_second, frame_buffer, buf,
+ frame_count, cntr_count);
+ if (err < 0)
+ goto end;
+ err = memcmp(frame_buffer, buf, size);
+ assert(err == 0);
+
+ /* Test single target. */
+ err = test_mapper(trial, access, sample_format, samples_per_frame,
+ frames_per_second, frame_buffer, buf,
+ frame_count, 1);
+ if (err < 0)
+ goto end;
+ err = memcmp(frame_buffer, buf, size);
+ assert(err == 0);
+end:
+ free(buf);
+
+ return err;
+}
+
+static int test_vector(struct mapper_trial *trial, snd_pcm_access_t access,
+ snd_pcm_format_t sample_format,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_second, void *frame_buffer,
+ unsigned int frame_count, unsigned int cntr_count)
+{
+ unsigned int size;
+ char **bufs;
+ int i;
+ int err;
+
+ bufs = calloc(cntr_count, sizeof(*bufs));
+ if (bufs == NULL)
+ return -ENOMEM;
+
+ size = frame_count * snd_pcm_format_physical_width(sample_format) / 8;
+
+ for (i = 0; i < cntr_count; ++i) {
+ bufs[i] = malloc(size);
+ if (bufs[i] == NULL)
+ goto end;
+ memset(bufs[i], 0, size);
+ }
+
+ /* Test multiple target. */
+ err = test_mapper(trial, access, sample_format, samples_per_frame,
+ frames_per_second, frame_buffer, bufs,
+ frame_count, cntr_count);
+ if (err < 0)
+ goto end;
+ for (i = 0; i < cntr_count; ++i) {
+ char **target = frame_buffer;
+ err = memcmp(target[i], bufs[i], size);
+ assert(err == 0);
+ }
+
+ /* Test single target. */
+ err = test_mapper(trial, access, sample_format, samples_per_frame,
+ frames_per_second, frame_buffer, bufs,
+ frame_count, 1);
+ if (err < 0)
+ goto end;
+ for (i = 0; i < cntr_count; ++i) {
+ char **target = frame_buffer;
+ err = memcmp(target[i], bufs[i], size);
+ assert(err == 0);
+ }
+end:
+ for (i = 0; i < cntr_count; ++i) {
+ if (bufs[i])
+ free(bufs[i]);
+ }
+ free(bufs);
+
+ return err;
+}
+
+static int test_n_buf(struct mapper_trial *trial, snd_pcm_access_t access,
+ snd_pcm_format_t sample_format,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_second, void *frame_buffer,
+ unsigned int frame_count, unsigned int cntr_count)
+{
+ char *test_buf = frame_buffer;
+ unsigned int size;
+ char **test_vec;
+ int i;
+ int err;
+
+ size = frame_count * snd_pcm_format_physical_width(sample_format) / 8;
+
+ test_vec = calloc(cntr_count * 2, sizeof(*test_vec));
+ if (test_vec == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < cntr_count; ++i)
+ test_vec[i] = test_buf + size * i;
+
+ err = test_vector(trial, access, sample_format, samples_per_frame,
+ frames_per_second, test_vec, frame_count, cntr_count);
+ free(test_vec);
+
+ return err;
+}
+
+static int callback(struct test_generator *gen, snd_pcm_access_t access,
+ snd_pcm_format_t sample_format,
+ unsigned int samples_per_frame, void *frame_buffer,
+ unsigned int frame_count)
+{
+
+ int (*handler)(struct mapper_trial *trial, snd_pcm_access_t access,
+ snd_pcm_format_t sample_format,
+ unsigned int samples_per_frame,
+ unsigned int frames_per_second, void *frame_buffer,
+ unsigned int frame_count, unsigned int cntr_count);
+ struct mapper_trial *trial = gen->private_data;
+
+ if (access == SND_PCM_ACCESS_RW_NONINTERLEAVED)
+ handler = test_vector;
+ else if (access == SND_PCM_ACCESS_MMAP_NONINTERLEAVED)
+ handler = test_n_buf;
+ else
+ handler = test_i_buf;
+
+ return handler(trial, access, sample_format, samples_per_frame, 48000,
+ frame_buffer, frame_count, samples_per_frame);
+};
+
+int main(int argc, const char *argv[])
+{
+ /* Test 8/16/18/20/24/32/64 bytes per sample. */
+ static const uint64_t sample_format_mask =
+ (1ul << SND_PCM_FORMAT_U8) |
+ (1ul << SND_PCM_FORMAT_S16_LE) |
+ (1ul << SND_PCM_FORMAT_S18_3LE) |
+ (1ul << SND_PCM_FORMAT_S20_3LE) |
+ (1ul << SND_PCM_FORMAT_S24_LE) |
+ (1ul << SND_PCM_FORMAT_S32_LE) |
+ (1ul << SND_PCM_FORMAT_FLOAT64_LE);
+ uint64_t access_mask;
+ struct test_generator gen = {0};
+ struct mapper_trial *trial;
+ struct container_context *cntrs;
+ unsigned int samples_per_frame;
+ char **paths = NULL;
+ snd_pcm_access_t access;
+ bool verbose;
+ int i;
+ int err;
+
+ /* Test up to 32 channels. */
+ samples_per_frame = 32;
+ cntrs = calloc(samples_per_frame, sizeof(*cntrs));
+ if (cntrs == NULL)
+ return -ENOMEM;
+
+ paths = calloc(samples_per_frame, sizeof(*paths));
+ if (paths == NULL) {
+ err = -ENOMEM;
+ goto end;
+ }
+ for (i = 0; i < samples_per_frame; ++i) {
+ paths[i] = malloc(8);
+ if (paths[i] == NULL) {
+ err = -ENOMEM;
+ goto end;
+ }
+ snprintf(paths[i], 8, "hoge%d", i);
+ }
+
+ if (argc > 1) {
+ char *term;
+ access = strtol(argv[1], &term, 10);
+ if (errno != 0 || *term != '\0') {
+ err = -EINVAL;;
+ goto end;
+ }
+ if (access < SND_PCM_ACCESS_MMAP_INTERLEAVED &&
+ access > SND_PCM_ACCESS_RW_NONINTERLEAVED) {
+ err = -EINVAL;
+ goto end;
+ }
+ if (access == SND_PCM_ACCESS_MMAP_COMPLEX) {
+ err = -EINVAL;
+ goto end;
+ }
+
+ access_mask = 1ul << access;
+ verbose = true;
+ } else {
+ access_mask = (1ul << SND_PCM_ACCESS_MMAP_INTERLEAVED) |
+ (1ul << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) |
+ (1ul << SND_PCM_ACCESS_RW_INTERLEAVED) |
+ (1ul << SND_PCM_ACCESS_RW_NONINTERLEAVED);
+ verbose = false;
+ }
+
+ err = generator_context_init(&gen, access_mask, sample_format_mask,
+ 1, samples_per_frame,
+ 23, 4500, 1024,
+ sizeof(struct mapper_trial));
+ if (err < 0)
+ goto end;
+
+ trial = gen.private_data;
+ trial->cntrs = cntrs;
+ trial->cntr_format = CONTAINER_FORMAT_RIFF_WAVE;
+ trial->paths = paths;
+ trial->verbose = verbose;
+ err = generator_context_run(&gen, callback);
+
+ generator_context_destroy(&gen);
+end:
+ if (paths) {
+ for (i = 0; i < samples_per_frame; ++i)
+ free(paths[i]);
+ free(paths);
+ }
+ free(cntrs);
+
+ if (err < 0) {
+ printf("%s\n", strerror(-err));
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
--
2.11.0
More information about the Alsa-devel
mailing list