This patch adds the testbench code for the passthrough component. The testbench simulates a simple pipeline with a passthrough comp connected to 1 source buffer and 1 sink buffer and the contents of input file are copied to the output file.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- tune/c/include/common_test.h | 1 + tune/passthrough/Makefile.am | 27 ++++ tune/passthrough/passthrough_test.c | 259 ++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 tune/passthrough/Makefile.am create mode 100644 tune/passthrough/passthrough_test.c
diff --git a/tune/c/include/common_test.h b/tune/c/include/common_test.h index 01eadec..3cd6bfd 100644 --- a/tune/c/include/common_test.h +++ b/tune/c/include/common_test.h @@ -71,6 +71,7 @@ .config = SCONFIG} #define SPIPE_MIX(scomp) {.comp = scomp, .config = SCONFIG} #define SPIPE_MUX(scomp) {.comp = scomp, .config = SCONFIG} +#define SPIPE_PASS(scomp) {.comp = scomp, .config = SCONFIG} #define SPIPE_SRC(scomp) {.comp = scomp, .config = SCONFIG} #define SPIPE_EQ_FIR(scomp) {.comp = scomp, .config = SCONFIG} #define SPIPE_EQ_IIR(scomp) {.comp = scomp, .config = SCONFIG} diff --git a/tune/passthrough/Makefile.am b/tune/passthrough/Makefile.am new file mode 100644 index 0000000..1ca1b60 --- /dev/null +++ b/tune/passthrough/Makefile.am @@ -0,0 +1,27 @@ +AUTOMAKE_OPTIONS = subdir-objects + +SOF = ../../../sof.git +SRCADIR = $(SOF)/src/audio +INCDIR1 = ../c/include +INCDIR2 = $(SOF)/src/include +INCDIR3 = $(SOF)/src/arch/xtensa/include +INCDIR4 = $(SOF)/src/platform/baytrail/include +INCLUDE = -I$(INCDIR1) -I$(INCDIR2) -I$(INCDIR3) -I$(INCDIR4) -I$(SRCADIR) +DEFINE = -DCONFIG_BAYTRAIL -D__XTENSA__ -DMODULE_TEST + +AM_CPPFLAGS = $(INCLUDE) $(DEFINE) +AM_CFLAGS = -m32 -g -Wall +LDADD = -lm + +bin_PROGRAMS = passthrough_test + +passthrough_test_SOURCES = passthrough_test.c \ + ../../../sof.git/src/audio/passthrough.c \ + ../../../sof.git/src/audio/component.c \ + ../../../sof.git/src/audio/pipeline.c \ + ../../../sof.git/src/audio/buffer.c \ + ../../../sof.git/src/ipc/ipc.c \ + ../c/src/fileread.c \ + ../c/src/filewrite.c \ + ../c/src/common_test.h \ + ../c/src/common_test.c diff --git a/tune/passthrough/passthrough_test.c b/tune/passthrough/passthrough_test.c new file mode 100644 index 0000000..a6f9099 --- /dev/null +++ b/tune/passthrough/passthrough_test.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2017, 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: Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ + +#include "common_test.h" + +/* Internal buffer */ +#define TEST_BENCH_DEADLINE 5000 /* 5 ms */ +#define TEST_BENCH_NCH 2 /* Stereo */ +#define TEST_BENCH_RATE_MAX 192000 /* Hz */ +#define TEST_BENCH_FRAME_SIZE (4 * TEST_BENCH_NCH) /* 4bytes x NCH */ +#define TEST_BENCH_PERIOD_FRAMES (TEST_BENCH_RATE_MAX*TEST_BENCH_DEADLINE/1e6) +#define INT_PERIOD_SIZE (TEST_BENCH_PERIOD_FRAMES * TEST_BENCH_FRAME_SIZE) + +/* main firmware context */ +static struct reef reef; + +/* + * Test Pipeline (ID=0) + * + * Fileread(0) ---> B(3)---> Passthrough(1) ---> B(4) ---> Filewrite(2) + * + */ + +#define FR_ID 0 +#define PASSTHROUGH_ID 1 /* scheduling component */ +#define FW_ID1 2 +#define FW_ID2 3 +#define PIPE_ID 0 +#define PIPE_COMP_ID 7 +#define SCHED_ID PASSTHROUGH_ID + + +/* components used in static pipeline */ +static struct sof_ipc_comp_fileread fileread_p0[] = { + SPIPE_FILEREAD(SPIPE_COMP(0, SOF_COMP_FILEREAD, sof_ipc_comp_fileread), + "in.txt"), /* ID = 0 */ +}; + +static struct sof_ipc_comp_filewrite filewrite_p0[] = { + SPIPE_FILEWRITE(SPIPE_COMP(2, SOF_COMP_FILEWRITE, + sof_ipc_comp_filewrite), "out_1.txt"), /* ID = 2 */ +}; + +static struct sof_ipc_comp_passthrough passthrough_p0[] = { + SPIPE_PASS(SPIPE_COMP(1, SOF_COMP_PASSTHROUGH, + sof_ipc_comp_passthrough)), /* ID = 1 */ +}; + +static struct scomps scomps_p0[] = { + SCOMP(fileread_p0), + SCOMP(passthrough_p0), + SCOMP(filewrite_p0), +}; + +/* + * Buffers used in static pipeline 2. + */ +static struct sof_ipc_buffer buffers_p0[] = { + SPIPE_BUFFER(3, INT_PERIOD_SIZE * 2), /* B(3) */ + SPIPE_BUFFER(4, INT_PERIOD_SIZE * 2), /* B(4) */ + +}; + +/* pipeline 0 component/buffer connections */ +static struct sof_ipc_pipe_comp_connect connect_p0[] = { + SPIPE_COMP_CONNECT(0, 3), /* p(0): Fileread(0) -> B(3) */ + SPIPE_COMP_CONNECT(3, 1), /* p(0): B(3) -> Passthrough(1) */ + SPIPE_COMP_CONNECT(1, 4), /* p(0): Passthrough(1) -> B(4) */ + SPIPE_COMP_CONNECT(4, 2), /* p(0): B(4)-> Filewrite(2) */ +}; + +/* the static pipelines */ +static struct spipe spipe[] = { + SPIPE(scomps_p0, buffers_p0, connect_p0), +}; + +/* pipelines */ +struct sof_ipc_pipe_new pipeline[] = { + SPIPE_PIPE(PIPE_ID, 0, PIPE_COMP_ID, SCHED_ID, TEST_BENCH_DEADLINE, + TASK_PRI_LOW, TEST_BENCH_PERIOD_FRAMES), +}; + +/* pipeline setup, params and start */ +static int pipeline_calls(int i) +{ + int ret = 0; + struct pipeline *p; + struct ipc_comp_dev *pcm_dev; + + /* construct pipeline */ + ret = test_bench_pipeline_setup(&reef, &pipeline[i], &spipe[i]); + if (ret < 0) { + printf("error: pipeline setup\n"); + ret = -EINVAL; + goto out; + } + + /* set up pipeline params */ + ret = test_bench_pipeline_params(reef.ipc, TEST_BENCH_RATE_MAX, + TEST_BENCH_NCH, FR_ID, TEST_BENCH_DEADLINE, + pipeline[i].pipeline_id); + if (ret < 0) { + printf("error: pipeline params\n"); + ret = -EINVAL; + goto out; + } + + /* prepare pipeline */ + pcm_dev = ipc_get_comp(reef.ipc, FR_ID); + p = pcm_dev->cd->pipeline; + ret = pipeline_prepare(p, pcm_dev->cd); + if (ret < 0) { + printf("error: pipeline prepare\n"); + ret = -EINVAL; + goto out; + } + + /* start pipeline */ + ret = pipeline_cmd(p, pcm_dev->cd, COMP_CMD_START, NULL); + if (ret < 0) { + printf("error: start pipeline cmd\n"); + ret = -EINVAL; + } + +out: + return ret; +} + +/* copy frames from input file until EOF */ +static int schedule_pipeline(struct ipc_comp_dev *pcm_dev, + struct pipeline *p, struct fileread_comp_data *frcd) +{ + /* copy period frames from input file to output files */ + while (frcd->frs.reached_eof == 0) + pipeline_schedule_copy(p, pcm_dev->cd); + + return 0; +} + +void usage(char *executable) +{ + fprintf(stderr, "Usage: %s <input.txt> <output.txt>\n", + executable); +} + +int main(int argc, char **argv) +{ + struct ipc_comp_dev *pcm_dev; + struct pipeline *p; + struct comp_dev *cd; + int ret = 0, samples_in, samples_out, i = 0; + struct fileread_comp_data *frcd; + struct filewrite_comp_data *fwcd1; + clock_t tic, toc; + double c_realtime, t_exec; + + /* handle command line arguments*/ + if (argc > 2) { + switch (argc) { + case 3: + fileread_p0[0].fn = argv[1]; + filewrite_p0[0].fn = argv[2]; + break; + default: + usage(argv[0]); + return EXIT_SUCCESS; + } + } else { + usage(argv[0]); + return EXIT_SUCCESS; + } + + /* init components */ + sys_comp_init(); + sys_comp_fileread_init(); + sys_comp_filewrite_init(); + sys_comp_passthrough_init(); + + for (i = 0; i < ARRAY_SIZE(pipeline); i++) { + /* perform pipeline set up and start*/ + ret = pipeline_calls(i); + if (ret < 0) + exit(EXIT_FAILURE); + + /* Reduce print output */ + test_bench_disable_trace(); + + /* fileread and filewrite component data */ + pcm_dev = ipc_get_comp(reef.ipc, FW_ID1); + fwcd1 = comp_get_drvdata(pcm_dev->cd); + pcm_dev = ipc_get_comp(reef.ipc, FR_ID); + frcd = comp_get_drvdata(pcm_dev->cd); + p = pcm_dev->cd->pipeline; + cd = pcm_dev->cd; + + tic = clock(); + + /* + * Run copy until EOF from fileread + */ + ret = schedule_pipeline(pcm_dev, p, frcd); + if (ret < 0) + exit(EXIT_FAILURE); + + toc = clock(); + + /* samples read in and written out */ + samples_in = frcd->frs.n; + samples_out = fwcd1->fws.n; + + test_bench_enable_trace(); + + /* reset and free pipeline */ + ret = pipeline_reset(p, cd); + if (ret < 0) { + printf("error: pipeline reset\n"); + exit(EXIT_FAILURE); + } + pipeline_free(p); + + /* report test results */ + t_exec = (double) (toc - tic) / CLOCKS_PER_SEC; + c_realtime = (double) samples_out / TEST_BENCH_NCH / + TEST_BENCH_RATE_MAX / t_exec; + printf("Read %d input samples,\n", samples_in); + printf("wrote %d output samples,\n", samples_out); + printf("test execution time was %.2f us, %.2fx realtime.\n", + 1e3 * t_exec, c_realtime); + } + + return EXIT_SUCCESS; +}