mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-12-22 18:06:30 +01:00
4e3843d0ed
Also replace lseek64 with lseek. _FILE_OFFSET_BITS=64 is passed to needed platforms since configure uses AC_SYS_LARGEFILE macro. Therefore off_t is already 64-bit and lseek is same as lseek64. Additionally this fixes buils with latest musl where these lfs64 functions are moved out from _GNU_SOURCE and under _LARGEFILE64_SOURCE macro alone. This makes the builds fail on 32-bit platforms even though default off_t on musl is 64-bit always. Fixes: https://github.com/alsa-project/alsa-utils/pull/183 Reviewed-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Khem Raj <raj.khem@gmail.com> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
528 lines
13 KiB
C
528 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 <aconfig.h>
|
|
#ifdef HAVE_MEMFD_CREATE
|
|
#define _GNU_SOURCE
|
|
#endif
|
|
|
|
#include "../mapper.h"
|
|
#include "../misc.h"
|
|
|
|
#include "generator.h"
|
|
|
|
#ifdef HAVE_MEMFD_CREATE
|
|
#include <sys/mman.h>
|
|
#endif
|
|
|
|
#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];
|
|
|
|
#ifdef HAVE_MEMFD_CREATE
|
|
cntr_fds[i] = memfd_create(path, 0);
|
|
#else
|
|
cntr_fds[i] = open(path, O_RDWR | O_CREAT | O_TRUNC, 0644);
|
|
#endif
|
|
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) {
|
|
off_t pos = lseek(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)
|
|
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;
|
|
}
|