test: mux_copy

Unit tests for mux copy with 4 sources, 1 sink and 8 channels.

Signed-off-by: Janusz Jankowski <janusz.jankowski@linux.intel.com>
This commit is contained in:
Janusz Jankowski 2019-07-22 11:53:02 +02:00
parent d5a10013aa
commit a4dcabcfc6
7 changed files with 486 additions and 1 deletions

View File

@ -20,6 +20,7 @@
#include <sof/string.h>
#include <sof/trace/preproc.h>
#include <sof/trace/trace.h>
#include <sof/ut.h>
#include <ipc/control.h>
#include <ipc/topology.h>
#include <user/trace.h>
@ -446,7 +447,7 @@ struct comp_driver comp_demux = {
},
};
static void sys_comp_mux_init(void)
UT_STATIC void sys_comp_mux_init(void)
{
comp_register(&comp_mux);
comp_register(&comp_demux);

View File

@ -21,6 +21,7 @@
#include <sof/common.h>
#include <sof/platform.h>
#include <sof/trace/trace.h>
#include <sof/ut.h>
#include <user/trace.h>
#include <stdint.h>
@ -86,6 +87,10 @@ extern const struct comp_func_map mux_func_map[];
mux_func mux_get_processing_function(struct comp_dev *dev);
demux_func demux_get_processing_function(struct comp_dev *dev);
#ifdef UNIT_TEST
void sys_comp_mux_init(void);
#endif /* UNIT_TEST */
#endif /* CONFIG_COMP_MUX */
#endif /* __SOF_AUDIO_MUX_H__ */

View File

@ -12,6 +12,10 @@ endif()
if(CONFIG_COMP_KPB)
add_subdirectory(kpb)
endif()
if(CONFIG_COMP_MUX)
add_subdirectory(mux)
endif()
if(CONFIG_COMP_SEL)
add_subdirectory(selector)
endif()

View File

@ -0,0 +1,25 @@
# SPDX-License-Identifier: BSD-3-Clause
# make small lib for stripping so we don't have to care
# about unused missing references
add_compile_options(-fdata-sections -ffunction-sections -DUNIT_TEST)
link_libraries(-Wl,--gc-sections)
add_library(
audio_mux
STATIC
${PROJECT_SOURCE_DIR}/src/audio/mux/mux.c
${PROJECT_SOURCE_DIR}/src/audio/mux/mux_generic.c
${PROJECT_SOURCE_DIR}/src/audio/component.c
)
target_link_libraries(audio_mux PRIVATE sof_options)
link_libraries(audio_mux)
cmocka_test(
mux_copy
mux_copy.c
mock.c
)

View File

@ -0,0 +1,52 @@
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2019 Intel Corporation. All rights reserved.
//
// Author: Daniel Bogdzia <danielx.bogdzia@linux.intel.com>
#include <mock_trace.h>
#include <sof/audio/component.h>
#include <sof/lib/alloc.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <stdint.h>
#include <stdlib.h>
#include <cmocka.h>
TRACE_IMPL()
void rfree(void *ptr)
{
free(ptr);
}
void *_zalloc(int zone, uint32_t caps, size_t bytes)
{
(void)zone;
(void)caps;
return calloc(bytes, 1);
}
void pipeline_xrun(struct pipeline *p, struct comp_dev *dev, int32_t bytes)
{
}
void comp_update_buffer_produce(struct comp_buffer *buffer, uint32_t bytes)
{
}
void comp_update_buffer_consume(struct comp_buffer *buffer, uint32_t bytes)
{
}
void __panic(uint32_t p, char *filename, uint32_t linenum)
{
(void)p;
(void)filename;
(void)linenum;
abort();
}

View File

@ -0,0 +1,329 @@
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2019 Intel Corporation. All rights reserved.
//
// Author: Daniel Bogdzia <danielx.bogdzia@linux.intel.com>
// Janusz Jankowski <janusz.jankowski@linux.intel.com>
#include "util.h"
#include <sof/audio/component.h>
#include <sof/audio/format.h>
#include <sof/audio/mux.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
#include <cmocka.h>
struct test_data {
uint32_t format;
uint8_t mask[MUX_MAX_STREAMS][PLATFORM_MAX_CHANNELS];
void *output;
struct comp_dev *dev;
struct comp_buffer *sources[MUX_MAX_STREAMS];
struct comp_buffer *sink;
};
static int16_t input_16b[MUX_MAX_STREAMS][PLATFORM_MAX_CHANNELS] = {
{ 0x101, 0x102, 0x104, 0x108,
0x111, 0x112, 0x114, 0x118, },
{ 0x201, 0x202, 0x204, 0x208,
0x211, 0x212, 0x214, 0x218, },
{ 0x301, 0x302, 0x304, 0x308,
0x311, 0x312, 0x314, 0x318, },
{ 0x401, 0x402, 0x404, 0x408,
0x411, 0x412, 0x414, 0x418, },
};
static int32_t input_32b[MUX_MAX_STREAMS][PLATFORM_MAX_CHANNELS] = {
{ 0xd1a1001, 0xd2a2002, 0xd4a4004, 0xd8a8008,
0xe1b1011, 0xe2b2012, 0xe4b4014, 0xe8b8018, },
{ 0xd1a1101, 0xd2a2102, 0xd4a4104, 0xd8a8108,
0xe1b1111, 0xe2b2112, 0xe4b4114, 0xe8b8118, },
{ 0xd1a1201, 0xd2a2202, 0xd4a4204, 0xd8a8208,
0xe1b1211, 0xe2b2212, 0xe4b4214, 0xe8b8218, },
{ 0xd1a1401, 0xd2a2402, 0xd4a4404, 0xd8a8408,
0xe1b1411, 0xe2b2412, 0xe4b4414, 0xe8b8418, },
};
static uint16_t valid_formats[] = {
SOF_IPC_FRAME_S16_LE,
SOF_IPC_FRAME_S24_4LE,
SOF_IPC_FRAME_S32_LE,
};
static uint8_t masks[][MUX_MAX_STREAMS][PLATFORM_MAX_CHANNELS] = {
{ { 0x01, }, },
{ { 0x01, },
{ 0x01, },
{ 0x01, },
{ 0x01, }, },
{ { 0x00, 0x00, 0x00, 0x01, },
{ 0x00, 0x00, 0x01, },
{ 0x00, 0x01, },
{ 0x01, }, },
{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, },
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, },
{ 0x00, 0x00, 0x00, 0x00, 0x01, }, },
{ { 0x02, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, },
{ 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, },
{ 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x3f, },
{ 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0xff, }, },
{ { 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0xf0, 0x00, },
{ 0x00, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0xf0, },
{ 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0xf0, 0x00, },
{ 0x00, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x00, 0xf0, }, },
{ { 0xf0, 0x00, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x00, },
{ 0x00, 0xf0, 0x00, 0x0f, 0x00, 0xf0, 0x00, 0x0f, },
{ 0xf0, 0x00, 0x0f, 0x00, 0xf0, 0x00, 0x0f, 0x00, },
{ 0x00, 0xf0, 0x00, 0x0f, 0x00, 0xf0, 0x00, 0x0f, }, },
{ { 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, },
{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, },
{ 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, },
{ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, }, },
{ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, },
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, },
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, },
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }, },
};
static int setup_group(void **state)
{
sys_comp_init();
sys_comp_mux_init();
return 0;
}
static struct sof_ipc_comp_process *create_mux_comp_ipc(struct test_data *td)
{
size_t ipc_size = sizeof(struct sof_ipc_comp_process);
size_t mux_size = sizeof(struct sof_mux_config)
+ MUX_MAX_STREAMS * sizeof(struct mux_stream_data);
struct sof_ipc_comp_process *ipc = calloc(1, ipc_size + mux_size);
struct sof_mux_config *mux = (struct sof_mux_config *)&ipc->data;
int i, j;
ipc->comp.hdr.size = sizeof(struct sof_ipc_comp_process);
ipc->comp.type = SOF_COMP_MUX;
ipc->config.hdr.size = sizeof(struct sof_ipc_comp_config);
ipc->size = mux_size;
mux->frame_format = td->format;
mux->num_channels = PLATFORM_MAX_CHANNELS;
mux->num_streams = MUX_MAX_STREAMS;
for (i = 0; i < MUX_MAX_STREAMS; ++i) {
mux->streams[i].pipeline_id = i;
mux->streams[i].num_channels = PLATFORM_MAX_CHANNELS;
for (j = 0; j < PLATFORM_MAX_CHANNELS; ++j)
mux->streams[i].mask[j] = td->mask[i][j];
}
return ipc;
}
static void prepare_sink(struct test_data *td, size_t sample_size)
{
td->sink = create_test_sink(td->dev,
MUX_MAX_STREAMS + 1,
td->format,
PLATFORM_MAX_CHANNELS);
td->sink->free = sample_size * PLATFORM_MAX_CHANNELS;
td->output = malloc(sample_size * PLATFORM_MAX_CHANNELS);
td->sink->w_ptr = td->output;
}
static void prepare_sources(struct test_data *td, size_t sample_size)
{
int i;
for (i = 0; i < MUX_MAX_STREAMS; ++i) {
td->sources[i] = create_test_source(td->dev,
i,
td->format,
PLATFORM_MAX_CHANNELS);
td->sources[i]->avail = sample_size * PLATFORM_MAX_CHANNELS;
if (td->format == SOF_IPC_FRAME_S16_LE)
td->sources[i]->r_ptr = input_16b[i];
else
td->sources[i]->r_ptr = input_32b[i];
}
}
static int setup_test_case(void **state)
{
struct test_data *td = *((struct test_data **)state);
struct sof_ipc_comp_process *ipc = create_mux_comp_ipc(td);
size_t sample_size = td->format == SOF_IPC_FRAME_S16_LE ?
sizeof(int16_t) : sizeof(int32_t);
int ret = 0;
td->dev = comp_new((struct sof_ipc_comp *)ipc);
free(ipc);
if (!td->dev)
return -EINVAL;
prepare_sink(td, sample_size);
prepare_sources(td, sample_size);
ret = comp_prepare(td->dev);
if (ret)
return ret;
return 0;
}
static int teardown_test_case(void **state)
{
struct test_data *td = *((struct test_data **)state);
int i;
for (i = 0; i < MUX_MAX_STREAMS; ++i)
free_test_source(td->sources[i]);
free(td->output);
free_test_sink(td->sink);
comp_free(td->dev);
return 0;
}
static void test_mux_copy_proc_16(void **state)
{
struct test_data *td = *((struct test_data **)state);
int16_t expected_result[PLATFORM_MAX_CHANNELS];
int i, j, k;
assert_int_equal(comp_copy(td->dev), 0);
for (i = 0; i < PLATFORM_MAX_CHANNELS; ++i) {
int32_t sample = 0;
for (j = 0; j < MUX_MAX_STREAMS; ++j) {
for (k = 0; k < PLATFORM_MAX_CHANNELS; ++k) {
if (td->mask[j][i] & BIT(k))
sample += input_16b[j][k];
}
}
expected_result[i] = sat_int16(sample);
}
assert_memory_equal(td->output, expected_result,
sizeof(expected_result));
}
static void test_mux_copy_proc_24(void **state)
{
struct test_data *td = *((struct test_data **)state);
int32_t expected_result[PLATFORM_MAX_CHANNELS];
int i, j, k;
int32_t val;
assert_int_equal(comp_copy(td->dev), 0);
for (i = 0; i < PLATFORM_MAX_CHANNELS; ++i) {
int64_t sample = 0;
for (j = 0; j < MUX_MAX_STREAMS; ++j) {
for (k = 0; k < PLATFORM_MAX_CHANNELS; ++k) {
if (td->mask[j][i] & BIT(k)) {
val = input_32b[j][k];
sample += sign_extend_s24(val);
}
}
}
expected_result[i] = sat_int24(sample);
}
assert_memory_equal(td->output, expected_result,
sizeof(expected_result));
}
static void test_mux_copy_proc_32(void **state)
{
struct test_data *td = *((struct test_data **)state);
int32_t expected_result[PLATFORM_MAX_CHANNELS];
int i, j, k;
assert_int_equal(comp_copy(td->dev), 0);
for (i = 0; i < PLATFORM_MAX_CHANNELS; ++i) {
int64_t sample = 0;
for (j = 0; j < MUX_MAX_STREAMS; ++j) {
for (k = 0; k < PLATFORM_MAX_CHANNELS; ++k) {
if (td->mask[j][i] & BIT(k))
sample += input_32b[j][k];
}
}
expected_result[i] = sat_int32(sample);
}
assert_memory_equal(td->output, expected_result,
sizeof(expected_result));
}
static char *get_test_name(int mask_index, const char *format_name)
{
int length = snprintf(NULL, 0, "test_mux_copy_%s_mask_%d",
format_name, mask_index) + 1;
char *buffer = malloc(length);
snprintf(buffer, length, "test_mux_copy_%s_mask_%d",
format_name, mask_index);
return buffer;
}
int main(void)
{
int i, j;
struct CMUnitTest tests[ARRAY_SIZE(valid_formats) * ARRAY_SIZE(masks)];
for (i = 0; i < ARRAY_SIZE(valid_formats); ++i) {
for (j = 0; j < ARRAY_SIZE(masks); ++j) {
int ti = i * ARRAY_SIZE(masks) + j;
struct test_data *td = malloc(sizeof(struct test_data));
td->format = valid_formats[i];
memcpy_s(td->mask, sizeof(td->mask),
masks[j], sizeof(masks[0]));
switch (td->format) {
case SOF_IPC_FRAME_S16_LE:
tests[ti].name = get_test_name(j, "s16le");
tests[ti].test_func = test_mux_copy_proc_16;
break;
case SOF_IPC_FRAME_S24_4LE:
tests[ti].name = get_test_name(j, "s24_4le");
tests[ti].test_func = test_mux_copy_proc_24;
break;
case SOF_IPC_FRAME_S32_LE:
tests[ti].name = get_test_name(j, "s32le");
tests[ti].test_func = test_mux_copy_proc_32;
break;
default:
return -EINVAL;
}
tests[ti].initial_state = td;
tests[ti].setup_func = setup_test_case;
tests[ti].teardown_func = teardown_test_case;
}
}
cmocka_set_message_output(CM_OUTPUT_TAP);
return cmocka_run_group_tests(tests, setup_group, NULL);
}

View File

@ -0,0 +1,69 @@
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2019 Intel Corporation. All rights reserved.
//
// Author: Daniel Bogdzia <danielx.bogdzia@linux.intel.com>
// Janusz Jankowski <janusz.jankowski@linux.intel.com>
#include <sof/sof.h>
#include <sof/audio/component.h>
#include <sof/audio/mux.h>
#include <sof/lib/alloc.h>
#include <stdlib.h>
static inline struct comp_buffer *create_test_sink(struct comp_dev *dev,
uint32_t pipeline_id,
uint32_t frame_fmt,
uint16_t channels)
{
struct comp_buffer *buffer = calloc(1, sizeof(struct comp_buffer));
/* set bsink list */
list_item_append(&buffer->source_list, &dev->bsink_list);
/* alloc sink and set default parameters */
buffer->sink = calloc(1, sizeof(struct comp_dev));
buffer->sink->state = COMP_STATE_PREPARE;
buffer->sink->params.frame_fmt = frame_fmt;
buffer->sink->params.channels = channels;
buffer->free = 0;
buffer->avail = 0;
buffer->ipc_buffer.comp.pipeline_id = pipeline_id;
return buffer;
}
static inline void free_test_sink(struct comp_buffer *buffer)
{
free(buffer->sink);
free(buffer);
}
static inline struct comp_buffer *create_test_source(struct comp_dev *dev,
uint32_t pipeline_id,
uint32_t frame_fmt,
uint16_t channels)
{
struct comp_buffer *buffer = calloc(1, sizeof(struct comp_buffer));
/*set bsource list */
list_item_append(&buffer->sink_list, &dev->bsource_list);
/* alloc source and set default parameters */
buffer->source = calloc(1, sizeof(struct comp_dev));
buffer->source->state = COMP_STATE_PREPARE;
buffer->source->params.frame_fmt = frame_fmt;
buffer->source->params.channels = channels;
buffer->free = 0;
buffer->avail = 0;
buffer->ipc_buffer.comp.pipeline_id = pipeline_id;
return buffer;
}
static inline void free_test_source(struct comp_buffer *buffer)
{
free(buffer->source);
free(buffer);
}