]> git.alsa-project.org Git - alsa-utils.git/commitdiff
axfer: add a unit test for mapper interface
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Tue, 13 Nov 2018 06:41:24 +0000 (15:41 +0900)
committerTakashi Iwai <tiwai@suse.de>
Tue, 13 Nov 2018 11:04:28 +0000 (12:04 +0100)
In former commits, mapper module gets supports of muxer/demuxer for
single/multiple targets 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@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
axfer/test/Makefile.am
axfer/test/mapper-test.c [new file with mode: 0644]

index 66b30ef87f40c1e213437da868028aa386632e1d..76a93bfcb1a508bc72499731afbd236352a376ed 100644 (file)
@@ -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 (file)
index 0000000..9f005aa
--- /dev/null
@@ -0,0 +1,491 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mapper-io.c - a unit test for muxer/demuxer for PCM frames on buffer.
+//
+// Copyright (c) 2018 Takashi Sakamoto <o-takashi@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;
+}