mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-10 06:35:41 +01:00
5ab26fbc14
In mapper test program, two set of file descriptors open to the same files for container builder and parser contexts, however the same file descriptor is available for the case. This commit arranges to use the same file descriptor for the contexts. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
517 lines
13 KiB
C
517 lines
13 KiB
C
// 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,
|
|
int *cntr_fds, unsigned int cntr_count)
|
|
{
|
|
struct container_context *cntrs = trial->cntrs;
|
|
enum container_format cntr_format = trial->cntr_format;
|
|
unsigned int bytes_per_sample;
|
|
uint64_t total_frame_count;
|
|
int i;
|
|
int err = 0;
|
|
|
|
for (i = 0; i < cntr_count; ++i) {
|
|
snd_pcm_format_t format;
|
|
unsigned int channels;
|
|
unsigned int rate;
|
|
|
|
err = container_builder_init(cntrs + i, cntr_fds[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,
|
|
int *cntr_fds, unsigned int cntr_count)
|
|
{
|
|
struct container_context *cntrs = trial->cntrs;
|
|
unsigned int bytes_per_sample;
|
|
uint64_t total_frame_count;
|
|
int i;
|
|
int err = 0;
|
|
|
|
for (i = 0; i < cntr_count; ++i) {
|
|
snd_pcm_format_t format;
|
|
unsigned int channels;
|
|
unsigned int rate;
|
|
|
|
err = container_parser_init(cntrs + i, cntr_fds[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)
|
|
{
|
|
int *cntr_fds;
|
|
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;
|
|
|
|
cntr_fds = calloc(cntr_count, sizeof(*cntr_fds));
|
|
if (cntr_fds == NULL)
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < cntr_count; ++i) {
|
|
const char *path = trial->paths[i];
|
|
|
|
cntr_fds[i] = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);
|
|
if (cntr_fds[i] < 0) {
|
|
err = -errno;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
err = test_demux(trial, access, sample_format, samples_per_frame,
|
|
frames_per_second, frames_per_buffer, frame_buffer,
|
|
frame_count, cntr_fds, cntr_count);
|
|
if (err < 0)
|
|
goto end;
|
|
|
|
for (i = 0; i < cntr_count; ++i) {
|
|
off64_t pos = lseek64(cntr_fds[i], 0, SEEK_SET);
|
|
if (pos != 0) {
|
|
err = -EIO;
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
err = test_mux(trial, access, sample_format, samples_per_frame,
|
|
frames_per_second, frames_per_buffer, check_buffer,
|
|
frame_count, cntr_fds, cntr_count);
|
|
end:
|
|
for (i = 0; i < cntr_count; ++i) {
|
|
unlink(trial->paths[i]);
|
|
close(cntr_fds[i]);
|
|
}
|
|
|
|
free(cntr_fds);
|
|
|
|
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) {
|
|
err = -ENOMEM;
|
|
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 =
|
|
(1ull << SND_PCM_FORMAT_U8) |
|
|
(1ull << SND_PCM_FORMAT_S16_LE) |
|
|
(1ull << SND_PCM_FORMAT_S18_3LE) |
|
|
(1ull << SND_PCM_FORMAT_S20_3LE) |
|
|
(1ull << SND_PCM_FORMAT_S24_LE) |
|
|
(1ull << SND_PCM_FORMAT_S32_LE) |
|
|
(1ull << 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 = 1ull << access;
|
|
verbose = true;
|
|
} else {
|
|
access_mask = (1ull << SND_PCM_ACCESS_MMAP_INTERLEAVED) |
|
|
(1ull << SND_PCM_ACCESS_MMAP_NONINTERLEAVED) |
|
|
(1ull << SND_PCM_ACCESS_RW_INTERLEAVED) |
|
|
(1ull << 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;
|
|
}
|