mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-12-22 16:46:31 +01:00
axfer: add a unit test for mapper interface
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>
This commit is contained in:
parent
25c8e3bebb
commit
39d1ab8a0c
2 changed files with 509 additions and 2 deletions
|
@ -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
|
||||
|
|
491
axfer/test/mapper-test.c
Normal file
491
axfer/test/mapper-test.c
Normal file
|
@ -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;
|
||||
}
|
Loading…
Reference in a new issue