Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions test/cmocka/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ endif
if BUILD_XTENSA
AM_CFLAGS += -I../../src/arch/xtensa/include
AM_CFLAGS += -I../../src/platform/apollolake/include
AM_CFLAGS += -I../../src/audio
endif

if BUILD_HOST
Expand All @@ -30,6 +31,14 @@ LDFLAGS := $(filter-out -nostdlib,$(LDFLAGS))

LDADD = -lcmocka

# volume tests

check_PROGRAMS += volume_process
volume_process_SOURCES = src/audio/volume/volume_process.c
volume_process_LDADD = ../../src/audio/libaudio.a $(LDADD)

# buffer tests

check_PROGRAMS += buffer_new
buffer_new_SOURCES = src/audio/buffer/buffer_new.c src/audio/buffer/mock.c
buffer_new_LDADD = ../../src/audio/libaudio.a $(LDADD)
Expand Down
352 changes: 352 additions & 0 deletions test/cmocka/src/audio/volume/volume_process.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,352 @@
/*
* Copyright (c) 2018, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Intel Corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Author: Tomasz Lauda <tomasz.lauda@linux.intel.com>
*/

#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include <sof/audio/component.h>
#include "volume.h"

#define VOL_SCALE (uint32_t)((double)INT32_MAX / VOL_MAX)

struct vol_test_state {
struct comp_dev *dev;
struct comp_buffer *sink;
struct comp_buffer *source;
void (*verify)(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source);
};

struct vol_test_parameters {
uint32_t volume;
uint32_t channels;
uint32_t frames;
uint32_t buffer_size_ms;
uint32_t source_format;
uint32_t sink_format;
void (*verify)(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source);
};

static void set_volume(uint32_t *vol, uint32_t value, uint32_t channels)
{
int i;

for (i = 0; i < channels; i++)
vol[i] = value;
}

static int setup(void **state)
{
struct vol_test_parameters *parameters = *state;
struct vol_test_state *vol_state;
struct comp_data *cd;
uint32_t size = 0;

/* allocate new state */
vol_state = test_malloc(sizeof(*vol_state));

/* allocate and set new device */
vol_state->dev = test_malloc(COMP_SIZE(struct sof_ipc_comp_volume));
vol_state->dev->params.channels = parameters->channels;

/* allocate and set new data */
cd = test_malloc(sizeof(*cd));
comp_set_drvdata(vol_state->dev, cd);
cd->source_format = parameters->source_format;
cd->sink_format = parameters->sink_format;
cd->scale_vol = vol_get_processing_function(vol_state->dev);
set_volume(cd->volume, parameters->volume, parameters->channels);

/* allocate new sink buffer */
vol_state->sink = test_malloc(sizeof(*vol_state->sink));
vol_state->dev->params.frame_fmt = parameters->sink_format;
size = parameters->frames * comp_frame_bytes(vol_state->dev);
vol_state->sink->w_ptr = test_calloc(parameters->buffer_size_ms,
size);
vol_state->sink->size = parameters->buffer_size_ms * size;

/* allocate new source buffer */
vol_state->source = test_malloc(sizeof(*vol_state->source));
vol_state->dev->params.frame_fmt = parameters->source_format;
size = parameters->frames * comp_frame_bytes(vol_state->dev);
vol_state->source->r_ptr = test_calloc(parameters->buffer_size_ms,
size);
vol_state->source->size = parameters->buffer_size_ms * size;

/* assigns verification function */
vol_state->verify = parameters->verify;

/* assign test state */
*state = vol_state;

return 0;
}

static int teardown(void **state)
{
struct vol_test_state *vol_state = *state;
struct comp_data *cd = comp_get_drvdata(vol_state->dev);

/* free everything */
test_free(cd);
test_free(vol_state->dev);
test_free(vol_state->sink->w_ptr);
test_free(vol_state->sink);
test_free(vol_state->source->r_ptr);
test_free(vol_state->source);
test_free(vol_state);

return 0;
}

static void fill_source_s16(struct vol_test_state *vol_state)
{
int16_t *src = (int16_t *)vol_state->source->r_ptr;
int i;

for (i = 0; i < vol_state->source->size / sizeof(int16_t); i++)
src[i] = i;
}

static void fill_source_s32(struct vol_test_state *vol_state)
{
int32_t *src = (int32_t *)vol_state->source->r_ptr;
int i;

for (i = 0; i < vol_state->source->size / sizeof(int32_t); i++)
src[i] = i << 16;
}

static void verify_s16_to_s16(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source)
{
struct comp_data *cd = comp_get_drvdata(dev);
const uint16_t *src = (uint16_t *)source->r_ptr;
const uint16_t *dst = (uint16_t *)sink->w_ptr;
int channels = dev->params.channels;
int channel;
int i;
double processed;

for (i = 0; i < sink->size / sizeof(uint16_t); i += channels) {
for (channel = 0; channel < channels; channel++) {
processed = src[i + channel] *
((double)cd->volume[channel] *
(double)VOL_SCALE / INT32_MAX);
assert_int_equal(dst[i + channel], processed + 0.5);
}
}
}

static void verify_s16_to_sX(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source)
{
struct comp_data *cd = comp_get_drvdata(dev);
const uint16_t *src = (uint16_t *)source->r_ptr;
const uint32_t *dst = (uint32_t *)sink->w_ptr;
int channels = dev->params.channels;
int channel;
int i;
double processed;
int shift = 0;

/* get shift value */
if (cd->sink_format == SOF_IPC_FRAME_S24_4LE)
shift = 8;
else if (cd->sink_format == SOF_IPC_FRAME_S32_LE)
shift = 16;

for (i = 0; i < sink->size / sizeof(uint32_t); i += channels) {
for (channel = 0; channel < channels; channel++) {
processed = src[i + channel] *
((double)cd->volume[channel] *
(double)VOL_SCALE / INT32_MAX);
assert_int_equal(dst[i + channel],
(uint32_t)(processed + 0.5) << shift);
}
}
}

static void verify_sX_to_s16(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source)
{
struct comp_data *cd = comp_get_drvdata(dev);
const uint32_t *src = (uint32_t *)source->r_ptr;
const uint16_t *dst = (uint16_t *)sink->w_ptr;
int channels = dev->params.channels;
int channel;
int i;
double processed;
int shift = 0;

/* get shift value */
if (cd->source_format == SOF_IPC_FRAME_S24_4LE)
shift = 8;

for (i = 0; i < sink->size / sizeof(uint16_t); i += channels) {
for (channel = 0; channel < channels; channel++) {
processed = (src[i + channel] << shift) *
((double)cd->volume[channel] *
(double)VOL_SCALE / INT32_MAX);
assert_int_equal(dst[i + channel],
(uint32_t)(processed + 0.5) >> 16);
}
}
}

static void verify_s24_to_s24_s32(struct comp_dev *dev,
struct comp_buffer *sink,
struct comp_buffer *source)
{
struct comp_data *cd = comp_get_drvdata(dev);
const uint32_t *src = (uint32_t *)source->r_ptr;
const uint32_t *dst = (uint32_t *)sink->w_ptr;
int channels = dev->params.channels;
int channel;
int i;
double processed;
int shift = 0;

/* get shift value */
if (cd->sink_format == SOF_IPC_FRAME_S32_LE)
shift = 8;

for (i = 0; i < sink->size / sizeof(uint32_t); i += channels) {
for (channel = 0; channel < channels; channel++) {
processed = (src[i + channel] << 8) *
((double)cd->volume[channel] *
(double)VOL_SCALE / INT32_MAX);
assert_int_equal(dst[i + channel],
((uint32_t)(processed + 0.5) >> 8) << shift);
}
}
}

static void verify_s32_to_s24_s32(struct comp_dev *dev,
struct comp_buffer *sink,
struct comp_buffer *source)
{
struct comp_data *cd = comp_get_drvdata(dev);
const uint32_t *src = (uint32_t *)source->r_ptr;
const uint32_t *dst = (uint32_t *)sink->w_ptr;
int channels = dev->params.channels;
int channel;
int i;
double processed;
int shift = 0;

/* get shift value */
if (cd->sink_format == SOF_IPC_FRAME_S24_4LE)
shift = 8;

for (i = 0; i < sink->size / sizeof(uint32_t); i += channels) {
for (channel = 0; channel < channels; channel++) {
processed = src[i + channel] *
((double)cd->volume[channel] *
(double)VOL_SCALE / INT32_MAX);
assert_int_equal(dst[i + channel],
(uint32_t)(processed + 0.5) >> shift);
}
}
}

static void test_vol(void **state)
{
struct vol_test_state *vol_state = *state;
struct comp_data *cd = comp_get_drvdata(vol_state->dev);

switch (cd->source_format) {
case SOF_IPC_FRAME_S16_LE:
fill_source_s16(vol_state);
break;
case SOF_IPC_FRAME_S24_4LE:
case SOF_IPC_FRAME_S32_LE:
case SOF_IPC_FRAME_FLOAT:
fill_source_s32(vol_state);
break;
}

cd->scale_vol(vol_state->dev, vol_state->sink, vol_state->source);

vol_state->verify(vol_state->dev, vol_state->sink, vol_state->source);
}

static struct vol_test_parameters parameters[] = {
{ VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, verify_s16_to_s16 },
{ VOL_MAX / 2, 2, 48, 1, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, verify_s16_to_s16 },
{ VOL_MAX / 3, 2, 48, 1, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, verify_s16_to_s16 },
{ VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, verify_s16_to_sX },
{ VOL_MAX / 2, 2, 48, 1, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, verify_s16_to_sX },
{ VOL_MAX / 3, 2, 48, 1, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, verify_s16_to_sX },
{ VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, verify_s16_to_sX },
{ VOL_MAX / 2, 2, 48, 1, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, verify_s16_to_sX },
{ VOL_MAX / 3, 2, 48, 1, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, verify_s16_to_sX },

{ VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 },
{ VOL_MAX / 2, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 },
{ VOL_MAX / 3, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 },
{ VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, verify_s24_to_s24_s32 },
{ VOL_MAX / 2, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, verify_s24_to_s24_s32 },
{ VOL_MAX / 3, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, verify_s24_to_s24_s32 },
{ VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, verify_s24_to_s24_s32 },
{ VOL_MAX / 2, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, verify_s24_to_s24_s32 },
{ VOL_MAX / 3, 2, 48, 1, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, verify_s24_to_s24_s32 },

{ VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 },
{ VOL_MAX / 2, 2, 48, 1, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 },
{ VOL_MAX / 3, 2, 48, 1, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, verify_sX_to_s16 },
{ VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, verify_s32_to_s24_s32 },
{ VOL_MAX / 2, 2, 48, 1, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, verify_s32_to_s24_s32 },
{ VOL_MAX / 3, 2, 48, 1, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, verify_s32_to_s24_s32 },
{ VOL_MAX, 2, 48, 1, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, verify_s32_to_s24_s32 },
{ VOL_MAX / 2, 2, 48, 1, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, verify_s32_to_s24_s32 },
{ VOL_MAX / 3, 2, 48, 1, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, verify_s32_to_s24_s32 },
};

int main(void)
{
int i;

struct CMUnitTest tests[ARRAY_SIZE(parameters)];

for (i = 0; i < ARRAY_SIZE(parameters); i++) {
tests[i].name = "test_vol";
tests[i].test_func = test_vol;
tests[i].setup_func = setup;
tests[i].teardown_func = teardown;
tests[i].initial_state = &parameters[i];
}

cmocka_set_message_output(CM_OUTPUT_TAP);

return cmocka_run_group_tests(tests, NULL, NULL);
}