[Sound-open-firmware] [RFC PATCH 0/6] Host testbench
This set of patches introduces the testbench for audio processing components in SOF. The testbench enables functional/quality testing of SOF components. The testbench reads in audio samples from a file and write out the processed samples to the output file.
The host directory includes common code with routines for topology parsing and setting up sof ipc, scheduler and processing pipelines. It also includes simpler implementations for SOF features such as tracing. It also includes a new file component that allows reading in or writing out samples from/to a file.
The host directory also includes the testbench for setting up pipelines based on a test topology. It reads in input samples from a file , schedules pipeline copy and copies the processed sample to the output file. The output file can be used to perform audio quality tests using matlab/octave. Currently it supports only volume pipelines. Support for other components such as src/eq will be added soon.
Ranjani Sridharan (6): host: add host testbench common source and header files host: add new component for file IO host: add testbench program host: include host testbench directory for compilation scripts: add scritps for building host library and invoking the testbench doc: add README for host testbench
configure.ac | 1 + doc/README-HOST | 23 + doc/README.host | 23 + scripts/host-testbench.sh | 25 + src/Makefile.am | 2 +- src/host/Makefile.am | 29 + src/host/alloc.c | 63 +++ src/host/common_test.c | 206 +++++++ src/host/file.c | 720 +++++++++++++++++++++++++ src/host/ipc.c | 81 +++ src/host/schedule.c | 98 ++++ src/host/testbench.c | 298 ++++++++++ src/host/topology.c | 954 +++++++++++++++++++++++++++++++++ src/host/trace.c | 181 +++++++ src/include/host/common_test.h | 65 +++ src/include/host/file.h | 77 +++ src/include/host/topology.h | 202 +++++++ src/include/host/trace.h | 49 ++ 18 files changed, 3096 insertions(+), 1 deletion(-) create mode 100644 doc/README-HOST create mode 100644 doc/README.host create mode 100755 scripts/host-testbench.sh create mode 100644 src/host/Makefile.am create mode 100644 src/host/alloc.c create mode 100644 src/host/common_test.c create mode 100644 src/host/file.c create mode 100644 src/host/ipc.c create mode 100644 src/host/schedule.c create mode 100644 src/host/testbench.c create mode 100644 src/host/topology.c create mode 100644 src/host/trace.c create mode 100644 src/include/host/common_test.h create mode 100644 src/include/host/file.h create mode 100644 src/include/host/topology.h create mode 100644 src/include/host/trace.h
This patch adds the common header and source files required for all component testbench. These files include routines for parsing topology files, initializing sof ipc, scheduler, memory allocation and pipeline structures. It also provides simpler implementations for some of the SOF features such as tracing.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- src/host/Makefile.am | 19 + src/host/alloc.c | 63 +++ src/host/common_test.c | 206 +++++++ src/host/ipc.c | 81 +++ src/host/schedule.c | 98 ++++ src/host/topology.c | 954 +++++++++++++++++++++++++++++++++ src/host/trace.c | 181 +++++++ src/include/host/common_test.h | 65 +++ src/include/host/topology.h | 202 +++++++ src/include/host/trace.h | 49 ++ 10 files changed, 1918 insertions(+) create mode 100644 src/host/Makefile.am create mode 100644 src/host/alloc.c create mode 100644 src/host/common_test.c create mode 100644 src/host/ipc.c create mode 100644 src/host/schedule.c create mode 100644 src/host/topology.c create mode 100644 src/host/trace.c create mode 100644 src/include/host/common_test.h create mode 100644 src/include/host/topology.h create mode 100644 src/include/host/trace.h
diff --git a/src/host/Makefile.am b/src/host/Makefile.am new file mode 100644 index 0000000..a1044a5 --- /dev/null +++ b/src/host/Makefile.am @@ -0,0 +1,19 @@ +AUTOMAKE_OPTIONS = subdir-objects + +SOF_INC = $(prefix)/include/sof +DEFINE = -DSOF_INC="$(SOF_INC)" + +AM_CPPFLAGS = -I $(SOF_INC) $(SOF_INCDIR) $(DEFINE) +AM_CFLAGS = -g -Wall +AM_LDFLAGS = -L$(prefix)/lib + +noinst_LIBRARIES = libtb_common.a + +libtb_common_a_SOURCES = \ + common_test.c \ + topology.c \ + file.c \ + trace.c \ + ipc.c \ + schedule.c \ + alloc.c diff --git a/src/host/alloc.c b/src/host/alloc.c new file mode 100644 index 0000000..beda37c --- /dev/null +++ b/src/host/alloc.c @@ -0,0 +1,63 @@ +/* + * 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + + */ +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <sof/alloc.h> +#include "host/common_test.h" + +/* testbench mem alloc definition */ + +void *rmalloc(int zone, uint32_t caps, size_t bytes) +{ + return malloc(bytes); +} + +void *rzalloc(int zone, uint32_t caps, size_t bytes) +{ + void *x; + + x = calloc(1, bytes); + return x; +} + +void rfree(void *ptr) +{ + free(ptr); +} + +void *rballoc(int zone, uint32_t caps, size_t bytes) +{ + return malloc(bytes); +} diff --git a/src/host/common_test.c b/src/host/common_test.c new file mode 100644 index 0000000..e286883 --- /dev/null +++ b/src/host/common_test.c @@ -0,0 +1,206 @@ +/* + * 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(s): Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ + +#include <stdint.h> +#include <stddef.h> +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <sof/task.h> +#include <sof/alloc.h> +#include <sof/ipc.h> +#include <sof/dai.h> +#include <sof/dma.h> +#include <sof/work.h> +#include <sof/wait.h> +#include <sof/intel-ipc.h> +#include <sof/audio/pipeline.h> +#include "host/common_test.h" +#include "host/topology.h" + +/* print debug messages */ +void debug_print(char *message) +{ + if (debug) + printf("debug: %s", message); +} + +/* testbench helper functions for pipeline setup and trigger */ + +int tb_pipeline_setup(struct sof *sof) +{ + /* init components */ + sys_comp_init(); + + /* init IPC */ + if (ipc_init(sof) < 0) { + fprintf(stderr, "error: IPC init\n"); + return -EINVAL; + } + + /* init scheduler */ + if (scheduler_init(sof) < 0) { + fprintf(stderr, "error: scheduler init\n"); + return -EINVAL; + } + + debug_print("ipc and scheduler initialized\n"); + + return 0; +} + +/* set up pcm params, prepare and trigger pipeline */ +int tb_pipeline_start(struct ipc *ipc, int nch, char *bits_in, + struct sof_ipc_pipe_new *ipc_pipe) +{ + struct ipc_comp_dev *pcm_dev; + struct pipeline *p; + struct comp_dev *cd; + int ret; + + /* set up pipeline params */ + ret = tb_pipeline_params(ipc, nch, bits_in, ipc_pipe); + if (ret < 0) { + fprintf(stderr, "error: pipeline params\n"); + return -EINVAL; + } + + /* Get IPC component device for pipeline */ + pcm_dev = ipc_get_comp(ipc, ipc_pipe->sched_id); + if (!pcm_dev) { + fprintf(stderr, "error: ipc get comp\n"); + return -EINVAL; + } + + /* Point to pipeline */ + cd = pcm_dev->cd; + p = pcm_dev->cd->pipeline; + + /* Component prepare */ + ret = pipeline_prepare(p, cd); + + /* Start the pipeline */ + ret = pipeline_trigger(p, cd, COMP_TRIGGER_START); + if (ret < 0) + printf("Warning: Failed start pipeline command.\n"); + + return ret; +} + +/* pipeline pcm params */ +int tb_pipeline_params(struct ipc *ipc, int nch, char *bits_in, + struct sof_ipc_pipe_new *ipc_pipe) +{ + int fs_period, ret = 0; + struct ipc_comp_dev *pcm_dev; + struct pipeline *p; + struct comp_dev *cd; + struct sof_ipc_pcm_params params; + int fs, deadline; + char message[DEBUG_MSG_LEN]; + + deadline = ipc_pipe->deadline; + fs = deadline * ipc_pipe->frames_per_sched; + + /* Compute period from sample rates */ + fs_period = (int)(0.9999 + fs * deadline / 1e6); + sprintf(message, "period sample count %d\n", fs_period); + debug_print(message); + + /* set pcm params */ + params.comp_id = ipc_pipe->comp_id; + params.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED; + params.params.frame_fmt = find_format(bits_in); + params.params.direction = SOF_IPC_STREAM_PLAYBACK; + params.params.rate = fs; + params.params.channels = nch; + switch (params.params.frame_fmt) { + case(SOF_IPC_FRAME_S16_LE): + params.params.sample_container_bytes = 2; + params.params.sample_valid_bytes = 2; + params.params.host_period_bytes = fs_period * nch * + params.params.sample_container_bytes; + break; + case(SOF_IPC_FRAME_S24_4LE): + params.params.sample_container_bytes = 4; + params.params.sample_valid_bytes = 3; + params.params.host_period_bytes = fs_period * nch * + params.params.sample_container_bytes; + break; + case(SOF_IPC_FRAME_S32_LE): + params.params.sample_container_bytes = 4; + params.params.sample_valid_bytes = 4; + params.params.host_period_bytes = fs_period * nch * + params.params.sample_container_bytes; + break; + default: + fprintf(stderr, "error: invalid frame format\n"); + return -EINVAL; + } + + /* get scheduling component device for pipeline*/ + pcm_dev = ipc_get_comp(ipc, ipc_pipe->sched_id); + if (!pcm_dev) { + fprintf(stderr, "error: ipc get comp\n"); + return -EINVAL; + } + + /* point to pipeline */ + cd = pcm_dev->cd; + p = pcm_dev->cd->pipeline; + if (!p) { + fprintf(stderr, "error: pipeline NULL\n"); + return -EINVAL; + } + + /* pipeline params */ + ret = pipeline_params(p, cd, ¶ms); + if (ret < 0) + fprintf(stderr, "error: pipeline_params\n"); + + return ret; +} + +/* The following definitions are to satisfy libsof linker errors */ + +struct dai *dai_get(uint32_t type, uint32_t index) +{ + return NULL; +} + +struct dma *dma_get(int dmac_id) +{ + return NULL; +} diff --git a/src/host/ipc.c b/src/host/ipc.c new file mode 100644 index 0000000..0cbb61a --- /dev/null +++ b/src/host/ipc.c @@ -0,0 +1,81 @@ +/* + * 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ + +#include <sof/ipc.h> +#include <sof/intel-ipc.h> + +/* testbench ipc */ +struct ipc *_ipc; + +int platform_ipc_init(struct ipc *ipc) +{ + struct intel_ipc_data *iipc; + int i; + + _ipc = ipc; + + /* init ipc data */ + iipc = malloc(sizeof(struct intel_ipc_data)); + ipc_set_drvdata(_ipc, iipc); + _ipc->dsp_msg = NULL; + list_init(&ipc->empty_list); + list_init(&ipc->msg_list); + spinlock_init(&ipc->lock); + + for (i = 0; i < MSG_QUEUE_SIZE; i++) + list_item_prepend(&ipc->message[i].list, &ipc->empty_list); + + /* allocate page table buffer */ + iipc->page_table = malloc(HOST_PAGE_SIZE); + if (iipc->page_table) + bzero(iipc->page_table, HOST_PAGE_SIZE); + + /* PM */ + iipc->pm_prepare_D3 = 0; + + return 0; +} + +/* The following definitions are to satisfy libsof linker errors */ + +int ipc_stream_send_position(struct comp_dev *cdev, + struct sof_ipc_stream_posn *posn) +{ + return 0; +} + +int ipc_stream_send_xrun(struct comp_dev *cdev, + struct sof_ipc_stream_posn *posn) +{ + return 0; +} diff --git a/src/host/schedule.c b/src/host/schedule.c new file mode 100644 index 0000000..614a2b6 --- /dev/null +++ b/src/host/schedule.c @@ -0,0 +1,98 @@ +/* + * 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ + +#include <sof/audio/component.h> +#include <sof/task.h> +#include <stdint.h> +#include <sof/wait.h> + +/* scheduler testbench definition */ + +struct schedule_data { + spinlock_t lock; + struct list_item list; /* list of tasks in priority queue */ + uint32_t clock; +}; + +static struct schedule_data *sch; + +void schedule_task_complete(struct task *task) +{ + list_item_del(&task->list); + task->state = TASK_STATE_COMPLETED; +} + +/* schedule task */ +void schedule_task(struct task *task, uint64_t start, uint64_t deadline) +{ + task->deadline = deadline; + list_item_prepend(&task->list, &sch->list); + task->state = TASK_STATE_QUEUED; + + if (task->func) + task->func(task->data); + + schedule_task_complete(task); +} + +/* initialize scheduler */ +int scheduler_init(struct sof *sof) +{ + trace_pipe("ScI"); + + sch = malloc(sizeof(*sch)); + list_init(&sch->list); + spinlock_init(&sch->lock); + + return 0; +} + +/* The following definitions are to satisfy libsof linker errors */ + +void schedule(void) +{ +} + +void schedule_task_idle(struct task *task, uint64_t deadline) +{ +} + +/* testbench work definition */ + +void work_schedule_default(struct work *w, uint64_t timeout) +{ +} + +void work_cancel_default(struct work *work) +{ +} diff --git a/src/host/topology.c b/src/host/topology.c new file mode 100644 index 0000000..46f7e66 --- /dev/null +++ b/src/host/topology.c @@ -0,0 +1,954 @@ +/* + * 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: Ranjani Sridharan ranjani.sridharan@linux.intel.com + * Liam Girdwood liam.r.girdwood@linux.intel.com + */ + +/* + * Topology parser to parse topology bin file + * and set up components and pipeline + */ + +#include <sof/ipc.h> +#include <stdio.h> +#include <string.h> +#include <dlfcn.h> +#include <sof/audio/component.h> +#include "host/topology.h" +#include "host/file.h" + +char *input_file; +char *output_file; +void *volume_lib; +FILE *file; +char pipeline_string[DEBUG_MSG_LEN]; + +/* + * Register component driver + * Only needed once per component type + */ +static void register_comp(int comp_type) +{ + static int pga_reg; + static int file_reg; + + switch (comp_type) { + case SND_SOC_TPLG_DAPM_PGA: + /* register comp driver if not already registered */ + if (!pga_reg) { + debug_print("register pga comp driver\n"); + + /* register volume driver */ + void (*sys_comp_volume_init)() = + (void (*)(void))dlsym(volume_lib, + "sys_comp_volume_init"); + sys_comp_volume_init(); + pga_reg = 1; + } + break; + case SND_SOC_TPLG_DAPM_DAI_IN: + case SND_SOC_TPLG_DAPM_AIF_IN: + /* register comp driver if not already registered */ + if (!file_reg) { + debug_print("register file comp driver\n"); + + /* register file driver */ + sys_comp_file_init(); + file_reg = 1; + } + break; + default: + break; + } +} + +/* read vendor tuples array from topology */ +static int read_array(struct snd_soc_tplg_vendor_array *array) +{ + struct snd_soc_tplg_vendor_uuid_elem uuid; + struct snd_soc_tplg_vendor_string_elem string; + struct snd_soc_tplg_vendor_value_elem value; + int j, ret = 0; + size_t size; + + switch (array->type) { + case SND_SOC_TPLG_TUPLE_TYPE_UUID: + + /* copy uuid elems into array */ + for (j = 0; j < array->num_elems; j++) { + size = sizeof(struct snd_soc_tplg_vendor_uuid_elem); + ret = fread(&uuid, size, 1, file); + if (ret != 1) + return -EINVAL; + memcpy(&array->uuid[j], &uuid, size); + } + break; + case SND_SOC_TPLG_TUPLE_TYPE_STRING: + + /* copy string elems into array */ + for (j = 0; j < array->num_elems; j++) { + size = sizeof(struct snd_soc_tplg_vendor_string_elem); + ret = fread(&string, size, 1, file); + if (ret != 1) + return -EINVAL; + memcpy(&array->string[j], &string, size); + } + break; + case SND_SOC_TPLG_TUPLE_TYPE_BOOL: + case SND_SOC_TPLG_TUPLE_TYPE_BYTE: + case SND_SOC_TPLG_TUPLE_TYPE_WORD: + case SND_SOC_TPLG_TUPLE_TYPE_SHORT: + /* copy value elems into array */ + for (j = 0; j < array->num_elems; j++) { + size = sizeof(struct snd_soc_tplg_vendor_value_elem); + ret = fread(&value, size, 1, file); + if (ret != 1) + return -EINVAL; + memcpy(&array->value[j], &value, size); + } + break; + default: + printf("error: unknown token type %d\n", array->type); + return -EINVAL; + } + return 0; +} + +/* load pipeline graph DAPM widget*/ +static int load_graph(struct sof *sof, struct comp_info *temp_comp_list, + int count, int num_comps, int pipeline_id) +{ + struct sof_ipc_pipe_comp_connect connection; + struct snd_soc_tplg_dapm_graph_elem *graph_elem; + size_t size; + int i, j, ret = 0; + + /* allocate memory for graph elem */ + size = sizeof(struct snd_soc_tplg_dapm_graph_elem); + graph_elem = (struct snd_soc_tplg_dapm_graph_elem *)malloc(size); + if (!graph_elem) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + /* set up component connections */ + connection.source_id = -1; + connection.sink_id = -1; + for (i = 0; i < count; i++) { + size = sizeof(struct snd_soc_tplg_dapm_graph_elem); + ret = fread(graph_elem, size, 1, file); + if (ret != 1) + return -EINVAL; + + /* look up component id from the component list */ + for (j = 0; j < num_comps; j++) { + if (strcmp(temp_comp_list[j].name, + graph_elem->source) == 0) + connection.source_id = temp_comp_list[j].id; + + if (strcmp(temp_comp_list[j].name, + graph_elem->sink) == 0) + connection.sink_id = temp_comp_list[j].id; + } + + strcat(pipeline_string, graph_elem->source); + strcat(pipeline_string, "->"); + + if (i == (count - 1)) + strcat(pipeline_string, graph_elem->sink); + + /* connect source and sink */ + if (connection.source_id != -1 && connection.sink_id != -1) + if (ipc_comp_connect(sof->ipc, &connection) < 0) { + fprintf(stderr, "error: comp connect\n"); + return -EINVAL; + } + } + + /* pipeline complete after pipeline connections are established */ + for (i = 0; i < num_comps; i++) { + if (temp_comp_list[i].pipeline_id == pipeline_id && + temp_comp_list[i].type == SND_SOC_TPLG_DAPM_SCHEDULER) + ipc_pipeline_complete(sof->ipc, temp_comp_list[i].id); + } + + free(graph_elem); + return 0; +} + +/* load buffer DAPM widget */ +static int load_buffer(struct sof *sof, int comp_id, int pipeline_id, int size) +{ + struct sof_ipc_buffer buffer; + struct snd_soc_tplg_vendor_array *array = NULL; + int ret = 0; + + /* configure buffer */ + buffer.comp.id = comp_id; + buffer.comp.pipeline_id = pipeline_id; + + /* allocate memory for vendor tuple array */ + array = (struct snd_soc_tplg_vendor_array *)malloc(size); + ret = fread(array, sizeof(struct snd_soc_tplg_vendor_array), 1, file); + if (ret != 1) + return -EINVAL; + + read_array(array); + /* parse buffer tokens */ + ret = sof_parse_tokens(&buffer, buffer_tokens, + ARRAY_SIZE(buffer_tokens), array, + size); + + /* create buffer component */ + if (ipc_buffer_new(sof->ipc, &buffer) < 0) { + fprintf(stderr, "error: buffer new\n"); + return -EINVAL; + } + free(array); + return 0; +} + +/* load fileread component */ +static int load_fileread(struct sof *sof, int comp_id, int pipeline_id, + int size, char *bits_in, int *fr_id, int *sched_id) +{ + struct sof_ipc_comp_file fileread; + struct snd_soc_tplg_vendor_array *array = NULL; + size_t total_array_size = 0, read_size; + int ret = 0; + + fileread.config.frame_fmt = find_format(bits_in); + + /* allocate memory for vendor tuple array */ + array = (struct snd_soc_tplg_vendor_array *)malloc(size); + if (!array) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + /* read vendor tokens */ + while (total_array_size < size) { + read_size = sizeof(struct snd_soc_tplg_vendor_array); + ret = fread(array, read_size, 1, file); + if (ret != 1) + return -EINVAL; + read_array(array); + + /* parse comp tokens */ + ret = sof_parse_tokens(&fileread.config, comp_tokens, + ARRAY_SIZE(comp_tokens), array, + array->size); + if (ret != 0) { + printf("error: parse fileread tokens %d\n", size); + return -EINVAL; + } + total_array_size += array->size; + } + + /* configure fileread */ + fileread.fn = strdup(input_file); + fileread.mode = FILE_READ; + fileread.comp.id = comp_id; + + /* use fileread comp as scheduling comp */ + *fr_id = *sched_id = comp_id; + fileread.comp.hdr.size = sizeof(struct sof_ipc_comp_file); + fileread.comp.type = SOF_COMP_FILEREAD; + fileread.comp.pipeline_id = pipeline_id; + + /* create fileread component */ + if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&fileread) < 0) { + fprintf(stderr, "error: comp register\n"); + return -EINVAL; + } + + free(array); + free(fileread.fn); + return 0; +} + +/* load filewrite component */ +static int load_filewrite(struct sof *sof, int comp_id, int pipeline_id, + int size, int *fw_id) +{ + struct sof_ipc_comp_file filewrite; + struct snd_soc_tplg_vendor_array *array = NULL; + size_t total_array_size = 0, read_size; + int ret = 0; + + /* allocate memory for vendor tuple array */ + array = (struct snd_soc_tplg_vendor_array *)malloc(size); + if (!array) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + /* read vendor tokens */ + while (total_array_size < size) { + read_size = sizeof(struct snd_soc_tplg_vendor_array); + ret = fread(array, read_size, 1, file); + if (ret != 1) + return -EINVAL; + + read_array(array); + + /* parse comp tokens */ + ret = sof_parse_tokens(&filewrite.config, comp_tokens, + ARRAY_SIZE(comp_tokens), array, + array->size); + if (ret != 0) { + printf("error: parse filewrite tokens %d\n", size); + return -EINVAL; + } + total_array_size += array->size; + } + + /* configure filewrite */ + filewrite.fn = strdup(output_file); + filewrite.comp.id = comp_id; + filewrite.mode = FILE_WRITE; + *fw_id = comp_id; + filewrite.comp.hdr.size = sizeof(struct sof_ipc_comp_file); + filewrite.comp.type = SOF_COMP_FILEREAD; + filewrite.comp.pipeline_id = pipeline_id; + + /* create filewrite component */ + if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&filewrite) < 0) { + fprintf(stderr, "error: comp register\n"); + return -EINVAL; + } + + free(array); + free(filewrite.fn); + return 0; +} + +/* load pda dapm widget */ +static int load_pga(struct sof *sof, int comp_id, int pipeline_id, + int size) +{ + struct sof_ipc_comp_volume volume; + struct snd_soc_tplg_vendor_array *array = NULL; + size_t total_array_size = 0, read_size; + int ret = 0; + + /* allocate memory for vendor tuple array */ + array = (struct snd_soc_tplg_vendor_array *)malloc(size); + if (!array) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + /* read vendor tokens */ + while (total_array_size < size) { + read_size = sizeof(struct snd_soc_tplg_vendor_array); + ret = fread(array, read_size, 1, file); + if (ret != 1) + return -EINVAL; + read_array(array); + + /* parse volume tokens */ + ret = sof_parse_tokens(&volume.config, comp_tokens, + ARRAY_SIZE(comp_tokens), array, + array->size); + if (ret != 0) { + printf("error: parse pga tokens %d\n", size); + return -EINVAL; + } + total_array_size += array->size; + } + + /* configure volume */ + volume.comp.id = comp_id; + volume.comp.hdr.size = sizeof(struct sof_ipc_comp_volume); + volume.comp.type = SOF_COMP_VOLUME; + volume.comp.pipeline_id = pipeline_id; + + /* load volume component */ + if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&volume) < 0) { + fprintf(stderr, "error: comp register\n"); + return -EINVAL; + } + + free(array); + return 0; +} + +/* load scheduler dapm widget */ +static int load_pipeline(struct sof *sof, struct sof_ipc_pipe_new *pipeline, + int comp_id, int pipeline_id, int size, int *sched_id) +{ + struct snd_soc_tplg_vendor_array *array = NULL; + size_t total_array_size = 0, read_size; + int ret = 0; + + /* configure pipeline */ + pipeline->sched_id = *sched_id; + pipeline->comp_id = comp_id; + pipeline->pipeline_id = pipeline_id; + + /* allocate memory for vendor tuple array */ + array = (struct snd_soc_tplg_vendor_array *)malloc(size); + if (!array) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + /* read vendor arrays */ + while (total_array_size < size) { + read_size = sizeof(struct snd_soc_tplg_vendor_array); + ret = fread(array, read_size, 1, file); + if (ret != 1) + return -EINVAL; + + ret = read_array(array); + if (ret < 0) + return -EINVAL; + + /* parse scheduler tokens */ + ret = sof_parse_tokens(pipeline, sched_tokens, + ARRAY_SIZE(sched_tokens), array, + array->size); + if (ret != 0) { + printf("error: parse pipeline tokens %d\n", size); + return -EINVAL; + } + total_array_size += array->size; + } + + /* Create pipeline */ + if (ipc_pipeline_new(sof->ipc, pipeline) < 0) { + fprintf(stderr, "error: pipeline new\n"); + return -EINVAL; + } + + free(array); + return 0; +} + +/* load dapm widget kcontrols + * we dont use controls in the testbench atm. + * so just skip to the next dapm widget + */ +static int load_controls(struct sof *sof, int num_kcontrols) +{ + struct snd_soc_tplg_ctl_hdr *ctl_hdr; + struct snd_soc_tplg_mixer_control *mixer_ctl; + struct snd_soc_tplg_enum_control *enum_ctl; + struct snd_soc_tplg_bytes_control *bytes_ctl; + size_t read_size, size; + int j, ret = 0; + + /* allocate memory */ + size = sizeof(struct snd_soc_tplg_ctl_hdr); + ctl_hdr = (struct snd_soc_tplg_ctl_hdr *)malloc(size); + if (!ctl_hdr) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + size = sizeof(struct snd_soc_tplg_mixer_control); + mixer_ctl = (struct snd_soc_tplg_mixer_control *)malloc(size); + if (!mixer_ctl) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + size = sizeof(struct snd_soc_tplg_enum_control); + enum_ctl = (struct snd_soc_tplg_enum_control *)malloc(size); + if (!enum_ctl) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + size = sizeof(struct snd_soc_tplg_bytes_control); + bytes_ctl = (struct snd_soc_tplg_bytes_control *)malloc(size); + if (!bytes_ctl) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + for (j = 0; j < num_kcontrols; j++) { + /* read control header */ + read_size = sizeof(struct snd_soc_tplg_ctl_hdr); + ret = fread(ctl_hdr, read_size, 1, file); + if (ret != 1) + return -EINVAL; + + /* load control based on type */ + switch (ctl_hdr->ops.info) { + case SND_SOC_TPLG_CTL_VOLSW: + case SND_SOC_TPLG_CTL_STROBE: + case SND_SOC_TPLG_CTL_VOLSW_SX: + case SND_SOC_TPLG_CTL_VOLSW_XR_SX: + case SND_SOC_TPLG_CTL_RANGE: + case SND_SOC_TPLG_DAPM_CTL_VOLSW: + + /* load mixer type control */ + read_size = sizeof(struct snd_soc_tplg_ctl_hdr); + fseek(file, read_size * -1, SEEK_CUR); + read_size = sizeof(struct snd_soc_tplg_mixer_control); + ret = fread(mixer_ctl, read_size, 1, file); + if (ret != 1) + return -EINVAL; + + /* skip mixer private data */ + fseek(file, mixer_ctl->priv.size, SEEK_CUR); + break; + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_CTL_ENUM_VALUE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + + /* load enum type control */ + read_size = sizeof(struct snd_soc_tplg_ctl_hdr); + fseek(file, read_size * -1, SEEK_CUR); + read_size = sizeof(struct snd_soc_tplg_enum_control); + ret = fread(enum_ctl, read_size, 1, file); + if (ret != 1) + return -EINVAL; + + /* skip enum private data */ + fseek(file, enum_ctl->priv.size, SEEK_CUR); + break; + case SND_SOC_TPLG_CTL_BYTES: + + /* load bytes type controls */ + read_size = sizeof(struct snd_soc_tplg_ctl_hdr); + fseek(file, read_size * -1, SEEK_CUR); + read_size = sizeof(struct snd_soc_tplg_bytes_control); + ret = fread(bytes_ctl, read_size, 1, file); + if (ret != 1) + return -EINVAL; + + /* skip bytes private data */ + fseek(file, bytes_ctl->priv.size, SEEK_CUR); + break; + default: + printf("control type not supported\n"); + return -EINVAL; + } + } + + /* free all data */ + free(mixer_ctl); + free(enum_ctl); + free(bytes_ctl); + free(ctl_hdr); + return 0; +} + +/* load dapm widget */ +static int load_widget(struct sof *sof, int *fr_id, int *fw_id, + int *sched_id, char *bits_in, + struct comp_info *temp_comp_list, + struct sof_ipc_pipe_new *pipeline, int comp_id, + int comp_index, int pipeline_id) +{ + struct snd_soc_tplg_dapm_widget *widget; + char message[DEBUG_MSG_LEN]; + size_t read_size, size; + int ret = 0; + + /* allocate memory for widget */ + size = sizeof(struct snd_soc_tplg_dapm_widget); + widget = (struct snd_soc_tplg_dapm_widget *)malloc(size); + if (!widget) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + /* read widget data */ + read_size = sizeof(struct snd_soc_tplg_dapm_widget); + ret = fread(widget, read_size, 1, file); + if (ret != 1) + return -EINVAL; + + /* + * create a list with all widget info + * containing mapping between component names and ids + * which will be used for setting up component connections + */ + temp_comp_list[comp_index].id = comp_id; + temp_comp_list[comp_index].name = strdup(widget->name); + temp_comp_list[comp_index].type = widget->id; + temp_comp_list[comp_index].pipeline_id = pipeline_id; + + sprintf(message, "loading widget %s id %d\n", + temp_comp_list[comp_index].name, + temp_comp_list[comp_index].id); + debug_print(message); + + /* register comp driver */ + register_comp(temp_comp_list[comp_index].type); + + /* load widget based on type */ + switch (temp_comp_list[comp_index].type) { + /* load pga widget */ + case(SND_SOC_TPLG_DAPM_PGA): + if (load_pga(sof, temp_comp_list[comp_index].id, + pipeline_id, widget->priv.size) < 0) { + printf("error: load pga\n"); + return -EINVAL; + } + break; + + /* replace pcm playback component with fileread in testbench */ + case(SND_SOC_TPLG_DAPM_AIF_IN): + if (load_fileread(sof, temp_comp_list[comp_index].id, + pipeline_id, widget->priv.size, bits_in, + fr_id, sched_id) < 0) { + printf("error: load fileread\n"); + return -EINVAL; + } + break; + + /* replace dai in component with filewrite in testbench */ + case(SND_SOC_TPLG_DAPM_DAI_IN): + if (load_filewrite(sof, temp_comp_list[comp_index].id, + pipeline_id, widget->priv.size, + fw_id) < 0) { + printf("error: load filewrite\n"); + return -EINVAL; + } + break; + + /* load buffer */ + case(SND_SOC_TPLG_DAPM_BUFFER): + if (load_buffer(sof, temp_comp_list[comp_index].id, + pipeline_id, widget->priv.size) < 0) { + printf("error: load buffer\n"); + return -EINVAL; + } + break; + + /* load pipeline */ + case(SND_SOC_TPLG_DAPM_SCHEDULER): + if (load_pipeline(sof, pipeline, + temp_comp_list[comp_index].id, + pipeline_id, + widget->priv.size, + sched_id) < 0) { + printf("error: load buffer\n"); + return -EINVAL; + } + break; + + /* unsupported widgets */ + default: + printf("Widget type not supported %d\n", + widget->id); + break; + } + + /* load widget kcontrols */ + if (widget->num_kcontrols > 0) + if (load_controls(sof, widget->num_kcontrols) < 0) { + printf("error: load buffer\n"); + return -EINVAL; + } + + free(widget); + return 0; +} + +/* parse topology file and set up pipeline */ +int parse_topology(char *filename, struct sof *sof, int *fr_id, int *fw_id, + int *sched_id, char *bits_in, char *in_file, + char *out_file, void *volume_library, char *pipeline_msg) +{ + struct snd_soc_tplg_hdr *hdr; + + struct comp_info *temp_comp_list = NULL; + struct sof_ipc_pipe_new pipeline; + char message[DEBUG_MSG_LEN]; + int next_comp_id = 0, num_comps = 0; + int i, ret = 0; + size_t file_size, size; + + /* set volume library */ + volume_lib = volume_library; + + /* open topology file */ + file = fopen(filename, "rb"); + if (!file) { + fprintf(stderr, "error: opening file %s\n", filename); + return -EINVAL; + } + + /* set up fileread and filewrite file names */ + input_file = strdup(in_file); + output_file = strdup(out_file); + + /* file size */ + fseek(file, 0, SEEK_END); + file_size = ftell(file); + fseek(file, 0, SEEK_SET); + + /* allocate memory */ + size = sizeof(struct snd_soc_tplg_hdr); + hdr = (struct snd_soc_tplg_hdr *)malloc(size); + if (!hdr) { + printf("error: mem alloc\n"); + return -EINVAL; + } + + debug_print("topology parsing start\n"); + while (1) { + /* read topology header */ + ret = fread(hdr, sizeof(struct snd_soc_tplg_hdr), 1, file); + if (ret != 1) + return -EINVAL; + + sprintf(message, "type: %x, size: 0x%x count: %d index: %d\n", + hdr->type, hdr->payload_size, hdr->count, hdr->index); + debug_print(message); + + /* parse header and load the next block based on type */ + switch (hdr->type) { + /* load dapm widget */ + case SND_SOC_TPLG_TYPE_DAPM_WIDGET: + sprintf(message, "number of DAPM widgets %d\n", + hdr->count); + debug_print(message); + size = sizeof(struct comp_info) * hdr->count; + temp_comp_list = (struct comp_info *)malloc(size); + num_comps = hdr->count; + + for (i = 0; i < hdr->count; i++) + load_widget(sof, fr_id, fw_id, sched_id, + bits_in, temp_comp_list, + &pipeline, next_comp_id++, + i, hdr->index); + break; + + /* set up component connections from pipeline graph */ + case SND_SOC_TPLG_TYPE_DAPM_GRAPH: + if (load_graph(sof, temp_comp_list, hdr->count, + num_comps, hdr->index) < 0) { + printf("error: pipeline graph\n"); + return -EINVAL; + } + + if (ftell(file) == file_size) + goto finish; + break; + default: + fseek(file, hdr->payload_size, SEEK_CUR); + if (ftell(file) == file_size) + goto finish; + break; + } + } +finish: + debug_print("topology parsing end\n"); + strcpy(pipeline_msg, pipeline_string); + + /* free all data */ + free(hdr); + + for (i = 0; i < num_comps; i++) + free(temp_comp_list[i].name); + + free(temp_comp_list); + fclose(file); + return 0; +} + +/* parse vendor tokens in topology */ +int sof_parse_tokens(void *object, const struct sof_topology_token *tokens, + int count, struct snd_soc_tplg_vendor_array *array, + int priv_size) +{ + int asize; + + while (priv_size > 0) { + asize = array->size; + + /* validate asize */ + if (asize < 0) { /* FIXME: A zero-size array makes no sense */ + printf("error: invalid array size 0x%x\n", asize); + return -EINVAL; + } + + /* make sure there is enough data before parsing */ + priv_size -= asize; + + if (priv_size < 0) { + printf("error: invalid array size 0x%x\n", asize); + return -EINVAL; + } + + /* call correct parser depending on type */ + switch (array->type) { + case SND_SOC_TPLG_TUPLE_TYPE_UUID: + sof_parse_uuid_tokens(object, tokens, count, + array); + break; + case SND_SOC_TPLG_TUPLE_TYPE_STRING: + sof_parse_string_tokens(object, tokens, count, + array); + break; + case SND_SOC_TPLG_TUPLE_TYPE_BOOL: + case SND_SOC_TPLG_TUPLE_TYPE_BYTE: + case SND_SOC_TPLG_TUPLE_TYPE_WORD: + case SND_SOC_TPLG_TUPLE_TYPE_SHORT: + sof_parse_word_tokens(object, tokens, count, + array); + break; + default: + printf("error: unknown token type %d\n", array->type); + return -EINVAL; + } + + /* next array */ + array = (void *)array + asize; + } + return 0; +} + +void sof_parse_word_tokens(void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array) +{ + struct snd_soc_tplg_vendor_value_elem *elem; + int i, j; + + /* parse element by element */ + for (i = 0; i < array->num_elems; i++) { + elem = &array->value[i]; + + /* search for token */ + for (j = 0; j < count; j++) { + /* match token type */ + if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_WORD) + continue; + + /* match token id */ + if (tokens[j].token != elem->token) + continue; + + /* matched - now load token */ + tokens[j].get_token(elem, object, tokens[j].offset, + tokens[j].size); + } + } +} + +void sof_parse_uuid_tokens(void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array) +{ + struct snd_soc_tplg_vendor_uuid_elem *elem; + int i, j; + + /* parse element by element */ + for (i = 0; i < array->num_elems; i++) { + elem = &array->uuid[i]; + + /* search for token */ + for (j = 0; j < count; j++) { + /* match token type */ + if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_UUID) + continue; + + /* match token id */ + if (tokens[j].token != elem->token) + continue; + + /* matched - now load token */ + tokens[j].get_token(elem, object, tokens[j].offset, + tokens[j].size); + } + } +} + +void sof_parse_string_tokens(void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array) +{ + struct snd_soc_tplg_vendor_string_elem *elem; + int i, j; + + /* parse element by element */ + for (i = 0; i < array->num_elems; i++) { + elem = &array->string[i]; + + /* search for token */ + for (j = 0; j < count; j++) { + /* match token type */ + if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_STRING) + continue; + + /* match token id */ + if (tokens[j].token != elem->token) + continue; + + /* matched - now load token */ + tokens[j].get_token(elem, object, tokens[j].offset, + tokens[j].size); + } + } +} + +enum sof_ipc_frame find_format(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sof_frames); i++) { + if (strcmp(name, sof_frames[i].name) == 0) + return sof_frames[i].frame; + } + + /* use s32le if nothing is specified */ + return SOF_IPC_FRAME_S32_LE; +} + +int get_token_uint32_t(void *elem, void *object, uint32_t offset, + uint32_t size) +{ + struct snd_soc_tplg_vendor_value_elem *velem = elem; + uint32_t *val = object + offset; + + *val = velem->value; + return 0; +} + +int get_token_comp_format(void *elem, void *object, uint32_t offset, + uint32_t size) +{ + struct snd_soc_tplg_vendor_string_elem *velem = elem; + uint32_t *val = object + offset; + + *val = find_format(velem->string); + return 0; +} diff --git a/src/host/trace.c b/src/host/trace.c new file mode 100644 index 0000000..a98648b --- /dev/null +++ b/src/host/trace.c @@ -0,0 +1,181 @@ +/* + * 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ + +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include "host/common_test.h" +#include "host/trace.h" + +#define MAX_TRACE_CLASSES 255 +/* testbench trace definition */ + +/* enable trace by default in testbench */ +static int test_bench_trace = 1; +int num_trace_classes; + +/* set up trace class identifier table based on SOF trace header file */ +void setup_trace_table(void) +{ + char buffer[2048]; + char *trace = "sof/trace.h"; + char *trace_filename = malloc(strlen(SOF_INC) + strlen(trace) + 2); + char *token; + int ret, i = 0; + size_t size; + FILE *fp; + + /* set up trace file name using include directory prefix */ + sprintf(trace_filename, "%s/%s", SOF_INC, trace); + + fp = fopen(trace_filename, "r"); + if (!fp) { + fprintf(stderr, "error: opening trace include file %s\n", + trace_filename); + } + + /* find number of trace classes defined */ + while (fgets(buffer, sizeof(buffer), fp)) { + char identifier[1024]; + int value = 0, shift = 0; + + ret = sscanf(buffer, "#define %s (%d << %d)", identifier, + &value, &shift); + if (ret == 3) { + /* if TRACE_CLASS definition */ + if (strstr(identifier, "TRACE_CLASS")) + i++; + } + } + + num_trace_classes = i; + + /* allocate memory for trace table */ + size = sizeof(struct trace_class_table); + trace_table = (struct trace_class_table *)malloc(size * + num_trace_classes); + + /* rewind file pointer */ + fseek(fp, 0, SEEK_SET); + + i = 0; + + /* read lines from header */ + while (fgets(buffer, sizeof(buffer), fp)) { + char identifier[1024]; + int value = 0, shift = 0; + + ret = sscanf(buffer, "#define %s (%d << %d)", identifier, + &value, &shift); + if (ret == 3) { + /* if TRACE_CLASS definition */ + if (strstr(identifier, "TRACE_CLASS")) { + /* extract subsystem name */ + token = strtok(identifier, "_"); + token = strtok(NULL, "_"); + token = strtok(NULL, "_"); + + /* add trace class entry */ + trace_table[i].trace_class = value; + trace_table[i].class_name = strdup(token); + i++; + } + } + } + fclose(fp); + free(trace_filename); +} + +void free_trace_table(void) +{ + int i; + + for (i = 0; i < num_trace_classes; i++) + free(trace_table[i].class_name); + + free(trace_table); +} + +/* look up subsystem class name from table */ +static char *get_trace_class(uint32_t trace_class) +{ + int i; + + /* look up trace class table and return subsystem name */ + for (i = 0; i < num_trace_classes; i++) { + if (trace_table[i].trace_class == trace_class) + return trace_table[i].class_name; + } + + return "value"; +} + +/* print trace event */ +void _trace_event(uint32_t event) +{ + char a, b, c; + char *trace_class = NULL; + + if (test_bench_trace > 0) { + a = event & 0xff; + b = (event >> 8) & 0xff; + c = (event >> 16) & 0xff; + + /* look up subsystem from trace class table */ + trace_class = strdup(get_trace_class(event >> 24)); + + /* print trace event stderr*/ + if (strcmp(trace_class, "value") == 0) + fprintf(stderr, "Trace value %d\n", event); + else + fprintf(stderr, "Trace %s %c%c%c\n", trace_class, + c, b, a); + } + + free(trace_class); +} + +void _trace_event_mbox_atomic(uint32_t event) +{ + _trace_event(event); +} + +/* enable trace in testbench */ +void tb_enable_trace(bool enable) +{ + test_bench_trace = enable; + if (enable) + debug_print("trace print enabled\n"); + else + debug_print("trace print disabled\n"); +} diff --git a/src/include/host/common_test.h b/src/include/host/common_test.h new file mode 100644 index 0000000..96193e5 --- /dev/null +++ b/src/include/host/common_test.h @@ -0,0 +1,65 @@ +/* + * 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(s): Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ +#ifndef _COMMON_TEST_H +#define _COMMON_TEST_H + +#include <stdint.h> +#include <stddef.h> +#include <time.h> +#include <stdio.h> +#include <uapi/ipc.h> +#include <sof/sof.h> +#include <sof/audio/component.h> +#include <sof/audio/format.h> + +#define DEBUG_MSG_LEN 256 + +extern int debug; + +int scheduler_init(struct sof *sof); + +void sys_comp_file_init(void); + +void sys_comp_filewrite_init(void); + +int tb_pipeline_setup(struct sof *sof); + +int tb_pipeline_start(struct ipc *ipc, int nch, char *bits_in, + struct sof_ipc_pipe_new *ipc_pipe); + +int tb_pipeline_params(struct ipc *ipc, int nch, char *bits_in, + struct sof_ipc_pipe_new *ipc_pipe); + +void debug_print(char *message); + +#endif diff --git a/src/include/host/topology.h b/src/include/host/topology.h new file mode 100644 index 0000000..b3421c8 --- /dev/null +++ b/src/include/host/topology.h @@ -0,0 +1,202 @@ +/* + * 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: Liam Girdwood liam.r.girdwood@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ +#ifndef _COMMON_TPLG_H +#define _COMMON_TPLG_H + +#include <sound/asoc.h> +#include "common_test.h" + +/* + * TODO: include these token from kernel uapi header + * Tokens - must match values in topology configurations + */ + +/* buffers */ +#define SOF_TKN_BUF_SIZE 100 +#define SOF_TKN_BUF_CAPS 101 + +/* scheduling */ +#define SOF_TKN_SCHED_DEADLINE 200 +#define SOF_TKN_SCHED_PRIORITY 201 +#define SOF_TKN_SCHED_MIPS 202 +#define SOF_TKN_SCHED_CORE 203 +#define SOF_TKN_SCHED_FRAMES 204 +#define SOF_TKN_SCHED_TIMER 205 + +/* volume */ +#define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250 +#define SOF_TKN_VOLUME_RAMP_STEP_MS 251 + +/* SRC */ +#define SOF_TKN_SRC_RATE_IN 300 +#define SOF_TKN_SRC_RATE_OUT 301 + +/* Generic components */ +#define SOF_TKN_COMP_PERIOD_SINK_COUNT 400 +#define SOF_TKN_COMP_PERIOD_SOURCE_COUNT 401 +#define SOF_TKN_COMP_FORMAT 402 +#define SOF_TKN_COMP_PRELOAD_COUNT 403 + +struct comp_info { + char *name; + int id; + int type; + int pipeline_id; +}; + +struct frame_types { + char *name; + enum sof_ipc_frame frame; +}; + +static const struct frame_types sof_frames[] = { + /* TODO: fix topology to use ALSA formats */ + {"s16le", SOF_IPC_FRAME_S16_LE}, + {"s24le", SOF_IPC_FRAME_S24_4LE}, + {"s32le", SOF_IPC_FRAME_S32_LE}, + {"float", SOF_IPC_FRAME_FLOAT}, + /* ALSA formats */ + {"S16_LE", SOF_IPC_FRAME_S16_LE}, + {"S24_LE", SOF_IPC_FRAME_S24_4LE}, + {"S32_LE", SOF_IPC_FRAME_S32_LE}, + {"FLOAT_LE", SOF_IPC_FRAME_FLOAT}, +}; + +struct sof_topology_token { + uint32_t token; + uint32_t type; + int (*get_token)(void *elem, void *object, uint32_t offset, + uint32_t size); + uint32_t offset; + uint32_t size; +}; + +enum sof_ipc_frame find_format(const char *name); + +int get_token_uint32_t(void *elem, void *object, uint32_t offset, + uint32_t size); + +int get_token_comp_format(void *elem, void *object, uint32_t offset, + uint32_t size); + +/* Buffers */ +static const struct sof_topology_token buffer_tokens[] = { + {SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t, + offsetof(struct sof_ipc_buffer, size), 0}, + {SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t, + offsetof(struct sof_ipc_buffer, caps), 0}, +}; + +/* scheduling */ +static const struct sof_topology_token sched_tokens[] = { + {SOF_TKN_SCHED_DEADLINE, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_uint32_t, + offsetof(struct sof_ipc_pipe_new, deadline), 0}, + {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_uint32_t, + offsetof(struct sof_ipc_pipe_new, priority), 0}, + {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_uint32_t, + offsetof(struct sof_ipc_pipe_new, mips), 0}, + {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_uint32_t, + offsetof(struct sof_ipc_pipe_new, core), 0}, + {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_uint32_t, + offsetof(struct sof_ipc_pipe_new, frames_per_sched), 0}, + {SOF_TKN_SCHED_TIMER, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_uint32_t, + offsetof(struct sof_ipc_pipe_new, timer), 0}, +}; + +/* volume */ +static const struct sof_topology_token volume_tokens[] = { + {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_uint32_t, + offsetof(struct sof_ipc_comp_volume, ramp), 0}, + {SOF_TKN_VOLUME_RAMP_STEP_MS, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t, + offsetof(struct sof_ipc_comp_volume, initial_ramp), 0}, +}; + +/* SRC */ +static const struct sof_topology_token src_tokens[] = { + {SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_uint32_t, + offsetof(struct sof_ipc_comp_src, source_rate), 0}, + {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, + get_token_uint32_t, + offsetof(struct sof_ipc_comp_src, sink_rate), 0}, +}; + +/* Tone */ +static const struct sof_topology_token tone_tokens[] = { +}; + +/* Generic components */ +static const struct sof_topology_token comp_tokens[] = { + {SOF_TKN_COMP_PERIOD_SINK_COUNT, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t, + offsetof(struct sof_ipc_comp_config, periods_sink), 0}, + {SOF_TKN_COMP_PERIOD_SOURCE_COUNT, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t, + offsetof(struct sof_ipc_comp_config, periods_source), 0}, + {SOF_TKN_COMP_FORMAT, + SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format, + offsetof(struct sof_ipc_comp_config, frame_fmt), 0}, + {SOF_TKN_COMP_PRELOAD_COUNT, + SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t, + offsetof(struct sof_ipc_comp_config, preload_count), 0}, +}; + +int sof_parse_tokens(void *object, + const struct sof_topology_token *tokens, + int count, struct snd_soc_tplg_vendor_array *array, + int priv_size); +void sof_parse_string_tokens(void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array); +void sof_parse_uuid_tokens(void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array); +void sof_parse_word_tokens(void *object, + const struct sof_topology_token *tokens, + int count, + struct snd_soc_tplg_vendor_array *array); + +int parse_topology(char *filename, struct sof *sof, int *fr_id, int *fw_id, + int *sched_id, char *bits_in, + char *in_file, char *out_file, void *volume_library, + char *pipeline); + +#endif diff --git a/src/include/host/trace.h b/src/include/host/trace.h new file mode 100644 index 0000000..8c45fb4 --- /dev/null +++ b/src/include/host/trace.h @@ -0,0 +1,49 @@ +/* + * 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ +#include <stdbool.h> + +#ifndef _TRACE_H +#define _TRACE_H + +struct trace_class_table { + int trace_class; + char *class_name; +}; + +struct trace_class_table *trace_table; + +void tb_enable_trace(bool enable); + +void setup_trace_table(void); + +void free_trace_table(void); + +#endif
On Thu, 2018-05-31 at 19:29 -0700, Ranjani Sridharan wrote:
This patch adds the common header and source files required for all component testbench. These files include routines for parsing topology files, initializing sof ipc, scheduler, memory allocation and pipeline structures. It also provides simpler implementations for some of the SOF features such as tracing.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com
src/host/Makefile.am | 19 + src/host/alloc.c | 63 +++ src/host/common_test.c | 206 +++++++ src/host/ipc.c | 81 +++ src/host/schedule.c | 98 ++++ src/host/topology.c | 954 +++++++++++++++++++++++++++++++++ src/host/trace.c | 181 +++++++ src/include/host/common_test.h | 65 +++ src/include/host/topology.h | 202 +++++++ src/include/host/trace.h | 49 ++ 10 files changed, 1918 insertions(+) create mode 100644 src/host/Makefile.am create mode 100644 src/host/alloc.c create mode 100644 src/host/common_test.c create mode 100644 src/host/ipc.c create mode 100644 src/host/schedule.c create mode 100644 src/host/topology.c create mode 100644 src/host/trace.c create mode 100644 src/include/host/common_test.h create mode 100644 src/include/host/topology.h create mode 100644 src/include/host/trace.h
diff --git a/src/host/Makefile.am b/src/host/Makefile.am new file mode 100644 index 0000000..a1044a5 --- /dev/null +++ b/src/host/Makefile.am @@ -0,0 +1,19 @@ +AUTOMAKE_OPTIONS = subdir-objects
+SOF_INC = $(prefix)/include/sof +DEFINE = -DSOF_INC="$(SOF_INC)"
+AM_CPPFLAGS = -I $(SOF_INC) $(SOF_INCDIR) $(DEFINE) +AM_CFLAGS = -g -Wall +AM_LDFLAGS = -L$(prefix)/lib
+noinst_LIBRARIES = libtb_common.a
+libtb_common_a_SOURCES = \
- common_test.c \
- topology.c \
- file.c \
- trace.c \
- ipc.c \
- schedule.c \
- alloc.c
diff --git a/src/host/alloc.c b/src/host/alloc.c new file mode 100644 index 0000000..beda37c --- /dev/null +++ b/src/host/alloc.c @@ -0,0 +1,63 @@ +/*
- 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
Liam Girdwood <liam.r.girdwood@linux.intel.com>
Keyon Jie <yang.jie@linux.intel.com>
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <sof/alloc.h> +#include "host/common_test.h"
+/* testbench mem alloc definition */
+void *rmalloc(int zone, uint32_t caps, size_t bytes) +{
- return malloc(bytes);
+}
+void *rzalloc(int zone, uint32_t caps, size_t bytes) +{
- void *x;
- x = calloc(1, bytes);
- return x;
+}
Can't we just
return calloc(1, bytes); ?
+void rfree(void *ptr) +{
- free(ptr);
+}
+void *rballoc(int zone, uint32_t caps, size_t bytes) +{
- return malloc(bytes);
+} diff --git a/src/host/common_test.c b/src/host/common_test.c new file mode 100644 index 0000000..e286883 --- /dev/null +++ b/src/host/common_test.c @@ -0,0 +1,206 @@ +/*
- 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(s): Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
Liam Girdwood <liam.r.girdwood@linux.intel.com>
Keyon Jie <yang.jie@linux.intel.com>
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+#include <stdint.h> +#include <stddef.h> +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <sof/task.h> +#include <sof/alloc.h> +#include <sof/ipc.h> +#include <sof/dai.h> +#include <sof/dma.h> +#include <sof/work.h> +#include <sof/wait.h> +#include <sof/intel-ipc.h> +#include <sof/audio/pipeline.h> +#include "host/common_test.h" +#include "host/topology.h"
+/* print debug messages */ +void debug_print(char *message) +{
- if (debug)
printf("debug: %s", message);
+}
+/* testbench helper functions for pipeline setup and trigger */
+int tb_pipeline_setup(struct sof *sof) +{
- /* init components */
- sys_comp_init();
- /* init IPC */
- if (ipc_init(sof) < 0) {
fprintf(stderr, "error: IPC init\n");
return -EINVAL;
- }
errors should be handled like :-
err = func(val); if (err < 0) { fprintf(stderr, "error: blah %d\n", err); return err; }
This will need to be changed for all similar code like the above, otherwise we lose the error value and re-write it.
- /* init scheduler */
- if (scheduler_init(sof) < 0) {
fprintf(stderr, "error: scheduler init\n");
return -EINVAL;
- }
- debug_print("ipc and scheduler initialized\n");
- return 0;
+}
+/* set up pcm params, prepare and trigger pipeline */ +int tb_pipeline_start(struct ipc *ipc, int nch, char *bits_in,
struct sof_ipc_pipe_new *ipc_pipe)
+{
- struct ipc_comp_dev *pcm_dev;
- struct pipeline *p;
- struct comp_dev *cd;
- int ret;
- /* set up pipeline params */
- ret = tb_pipeline_params(ipc, nch, bits_in, ipc_pipe);
- if (ret < 0) {
fprintf(stderr, "error: pipeline params\n");
return -EINVAL;
- }
- /* Get IPC component device for pipeline */
- pcm_dev = ipc_get_comp(ipc, ipc_pipe->sched_id);
- if (!pcm_dev) {
fprintf(stderr, "error: ipc get comp\n");
return -EINVAL;
- }
- /* Point to pipeline */
- cd = pcm_dev->cd;
- p = pcm_dev->cd->pipeline;
- /* Component prepare */
- ret = pipeline_prepare(p, cd);
- /* Start the pipeline */
- ret = pipeline_trigger(p, cd, COMP_TRIGGER_START);
- if (ret < 0)
printf("Warning: Failed start pipeline command.\n");
- return ret;
+}
+/* pipeline pcm params */ +int tb_pipeline_params(struct ipc *ipc, int nch, char *bits_in,
struct sof_ipc_pipe_new *ipc_pipe)
+{
- int fs_period, ret = 0;
- struct ipc_comp_dev *pcm_dev;
- struct pipeline *p;
- struct comp_dev *cd;
- struct sof_ipc_pcm_params params;
- int fs, deadline;
- char message[DEBUG_MSG_LEN];
- deadline = ipc_pipe->deadline;
- fs = deadline * ipc_pipe->frames_per_sched;
- /* Compute period from sample rates */
- fs_period = (int)(0.9999 + fs * deadline / 1e6);
- sprintf(message, "period sample count %d\n", fs_period);
- debug_print(message);
- /* set pcm params */
- params.comp_id = ipc_pipe->comp_id;
- params.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
- params.params.frame_fmt = find_format(bits_in);
- params.params.direction = SOF_IPC_STREAM_PLAYBACK;
- params.params.rate = fs;
- params.params.channels = nch;
- switch (params.params.frame_fmt) {
- case(SOF_IPC_FRAME_S16_LE):
params.params.sample_container_bytes = 2;
best to use sizeof(uint16_t) here and below.
params.params.sample_valid_bytes = 2;
params.params.host_period_bytes = fs_period * nch *
params.params.sample_container_bytes;
break;
- case(SOF_IPC_FRAME_S24_4LE):
params.params.sample_container_bytes = 4;
params.params.sample_valid_bytes = 3;
params.params.host_period_bytes = fs_period * nch *
params.params.sample_container_bytes;
break;
- case(SOF_IPC_FRAME_S32_LE):
params.params.sample_container_bytes = 4;
params.params.sample_valid_bytes = 4;
params.params.host_period_bytes = fs_period * nch *
params.params.sample_container_bytes;
break;
- default:
fprintf(stderr, "error: invalid frame format\n");
return -EINVAL;
- }
- /* get scheduling component device for pipeline*/
- pcm_dev = ipc_get_comp(ipc, ipc_pipe->sched_id);
- if (!pcm_dev) {
fprintf(stderr, "error: ipc get comp\n");
return -EINVAL;
- }
- /* point to pipeline */
- cd = pcm_dev->cd;
- p = pcm_dev->cd->pipeline;
- if (!p) {
fprintf(stderr, "error: pipeline NULL\n");
return -EINVAL;
- }
- /* pipeline params */
- ret = pipeline_params(p, cd, ¶ms);
- if (ret < 0)
fprintf(stderr, "error: pipeline_params\n");
- return ret;
+}
+/* The following definitions are to satisfy libsof linker errors */
+struct dai *dai_get(uint32_t type, uint32_t index) +{
- return NULL;
+}
+struct dma *dma_get(int dmac_id) +{
- return NULL;
+} diff --git a/src/host/ipc.c b/src/host/ipc.c new file mode 100644 index 0000000..0cbb61a --- /dev/null +++ b/src/host/ipc.c @@ -0,0 +1,81 @@ +/*
- 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
Liam Girdwood <liam.r.girdwood@linux.intel.com>
Keyon Jie <yang.jie@linux.intel.com>
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+#include <sof/ipc.h> +#include <sof/intel-ipc.h>
+/* testbench ipc */ +struct ipc *_ipc;
+int platform_ipc_init(struct ipc *ipc) +{
- struct intel_ipc_data *iipc;
- int i;
- _ipc = ipc;
- /* init ipc data */
- iipc = malloc(sizeof(struct intel_ipc_data));
- ipc_set_drvdata(_ipc, iipc);
- _ipc->dsp_msg = NULL;
- list_init(&ipc->empty_list);
- list_init(&ipc->msg_list);
- spinlock_init(&ipc->lock);
- for (i = 0; i < MSG_QUEUE_SIZE; i++)
list_item_prepend(&ipc->message[i].list, &ipc->empty_list);
- /* allocate page table buffer */
- iipc->page_table = malloc(HOST_PAGE_SIZE);
- if (iipc->page_table)
bzero(iipc->page_table, HOST_PAGE_SIZE);
- /* PM */
- iipc->pm_prepare_D3 = 0;
- return 0;
+}
+/* The following definitions are to satisfy libsof linker errors */
+int ipc_stream_send_position(struct comp_dev *cdev,
struct sof_ipc_stream_posn *posn)
+{
- return 0;
+}
+int ipc_stream_send_xrun(struct comp_dev *cdev,
struct sof_ipc_stream_posn *posn)
+{
Should we have some printf logging here ?
- return 0;
+} diff --git a/src/host/schedule.c b/src/host/schedule.c new file mode 100644 index 0000000..614a2b6 --- /dev/null +++ b/src/host/schedule.c @@ -0,0 +1,98 @@ +/*
- 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
Liam Girdwood <liam.r.girdwood@linux.intel.com>
Keyon Jie <yang.jie@linux.intel.com>
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+#include <sof/audio/component.h> +#include <sof/task.h> +#include <stdint.h> +#include <sof/wait.h>
+/* scheduler testbench definition */
+struct schedule_data {
- spinlock_t lock;
- struct list_item list; /* list of tasks in priority queue */
- uint32_t clock;
+};
+static struct schedule_data *sch;
+void schedule_task_complete(struct task *task) +{
- list_item_del(&task->list);
- task->state = TASK_STATE_COMPLETED;
+}
+/* schedule task */ +void schedule_task(struct task *task, uint64_t start, uint64_t deadline) +{
- task->deadline = deadline;
- list_item_prepend(&task->list, &sch->list);
- task->state = TASK_STATE_QUEUED;
- if (task->func)
task->func(task->data);
- schedule_task_complete(task);
+}
+/* initialize scheduler */ +int scheduler_init(struct sof *sof) +{
- trace_pipe("ScI");
- sch = malloc(sizeof(*sch));
- list_init(&sch->list);
- spinlock_init(&sch->lock);
- return 0;
+}
+/* The following definitions are to satisfy libsof linker errors */
+void schedule(void) +{ +}
+void schedule_task_idle(struct task *task, uint64_t deadline) +{ +}
+/* testbench work definition */
+void work_schedule_default(struct work *w, uint64_t timeout) +{ +}
+void work_cancel_default(struct work *work) +{ +} diff --git a/src/host/topology.c b/src/host/topology.c new file mode 100644 index 0000000..46f7e66 --- /dev/null +++ b/src/host/topology.c @@ -0,0 +1,954 @@ +/*
- 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: Ranjani Sridharan ranjani.sridharan@linux.intel.com
Liam Girdwood <liam.r.girdwood@linux.intel.com>
- */
+/*
- Topology parser to parse topology bin file
- and set up components and pipeline
- */
+#include <sof/ipc.h> +#include <stdio.h> +#include <string.h> +#include <dlfcn.h> +#include <sof/audio/component.h> +#include "host/topology.h" +#include "host/file.h"
+char *input_file; +char *output_file; +void *volume_lib; +FILE *file; +char pipeline_string[DEBUG_MSG_LEN];
+/*
- Register component driver
- Only needed once per component type
- */
+static void register_comp(int comp_type) +{
- static int pga_reg;
- static int file_reg;
You should use a structure here and pass it in to your function.
- switch (comp_type) {
- case SND_SOC_TPLG_DAPM_PGA:
/* register comp driver if not already registered */
if (!pga_reg) {
debug_print("register pga comp driver\n");
/* register volume driver */
void (*sys_comp_volume_init)() =
(void (*)(void))dlsym(volume_lib,
"sys_comp_volume_init")
;
This string could be constructed "sys_comp_" + type + "_init", where type could be passed in from cmd line.
sys_comp_volume_init();
pga_reg = 1;
}
break;
- case SND_SOC_TPLG_DAPM_DAI_IN:
- case SND_SOC_TPLG_DAPM_AIF_IN:
/* register comp driver if not already registered */
if (!file_reg) {
debug_print("register file comp driver\n");
/* register file driver */
sys_comp_file_init();
file_reg = 1;
}
break;
- default:
break;
- }
+}
+/* read vendor tuples array from topology */ +static int read_array(struct snd_soc_tplg_vendor_array *array) +{
- struct snd_soc_tplg_vendor_uuid_elem uuid;
- struct snd_soc_tplg_vendor_string_elem string;
- struct snd_soc_tplg_vendor_value_elem value;
- int j, ret = 0;
- size_t size;
- switch (array->type) {
- case SND_SOC_TPLG_TUPLE_TYPE_UUID:
/* copy uuid elems into array */
for (j = 0; j < array->num_elems; j++) {
size = sizeof(struct snd_soc_tplg_vendor_uuid_elem);
ret = fread(&uuid, size, 1, file);
if (ret != 1)
return -EINVAL;
memcpy(&array->uuid[j], &uuid, size);
}
break;
- case SND_SOC_TPLG_TUPLE_TYPE_STRING:
/* copy string elems into array */
for (j = 0; j < array->num_elems; j++) {
size = sizeof(struct
snd_soc_tplg_vendor_string_elem);
ret = fread(&string, size, 1, file);
if (ret != 1)
return -EINVAL;
memcpy(&array->string[j], &string, size);
}
break;
- case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
- case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
- case SND_SOC_TPLG_TUPLE_TYPE_WORD:
- case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
/* copy value elems into array */
for (j = 0; j < array->num_elems; j++) {
size = sizeof(struct snd_soc_tplg_vendor_value_elem);
ret = fread(&value, size, 1, file);
if (ret != 1)
return -EINVAL;
memcpy(&array->value[j], &value, size);
}
break;
- default:
printf("error: unknown token type %d\n", array->type);
return -EINVAL;
- }
- return 0;
+}
+/* load pipeline graph DAPM widget*/ +static int load_graph(struct sof *sof, struct comp_info *temp_comp_list,
int count, int num_comps, int pipeline_id)
+{
- struct sof_ipc_pipe_comp_connect connection;
- struct snd_soc_tplg_dapm_graph_elem *graph_elem;
- size_t size;
- int i, j, ret = 0;
- /* allocate memory for graph elem */
- size = sizeof(struct snd_soc_tplg_dapm_graph_elem);
- graph_elem = (struct snd_soc_tplg_dapm_graph_elem *)malloc(size);
- if (!graph_elem) {
printf("error: mem alloc\n");
return -EINVAL;
- }
- /* set up component connections */
- connection.source_id = -1;
- connection.sink_id = -1;
- for (i = 0; i < count; i++) {
size = sizeof(struct snd_soc_tplg_dapm_graph_elem);
ret = fread(graph_elem, size, 1, file);
if (ret != 1)
return -EINVAL;
Always best to get and print errno for any failed file IO ops. Will need to be done in multiple places.
/* look up component id from the component list */
for (j = 0; j < num_comps; j++) {
if (strcmp(temp_comp_list[j].name,
graph_elem->source) == 0)
connection.source_id = temp_comp_list[j].id;
if (strcmp(temp_comp_list[j].name,
graph_elem->sink) == 0)
connection.sink_id = temp_comp_list[j].id;
}
strcat(pipeline_string, graph_elem->source);
strcat(pipeline_string, "->");
if (i == (count - 1))
strcat(pipeline_string, graph_elem->sink);
/* connect source and sink */
if (connection.source_id != -1 && connection.sink_id != -1)
if (ipc_comp_connect(sof->ipc, &connection) < 0) {
fprintf(stderr, "error: comp connect\n");
return -EINVAL;
}
- }
- /* pipeline complete after pipeline connections are established */
- for (i = 0; i < num_comps; i++) {
if (temp_comp_list[i].pipeline_id == pipeline_id &&
temp_comp_list[i].type == SND_SOC_TPLG_DAPM_SCHEDULER)
ipc_pipeline_complete(sof->ipc,
temp_comp_list[i].id);
- }
- free(graph_elem);
- return 0;
+}
+/* load buffer DAPM widget */ +static int load_buffer(struct sof *sof, int comp_id, int pipeline_id, int size) +{
- struct sof_ipc_buffer buffer;
- struct snd_soc_tplg_vendor_array *array = NULL;
- int ret = 0;
- /* configure buffer */
- buffer.comp.id = comp_id;
- buffer.comp.pipeline_id = pipeline_id;
- /* allocate memory for vendor tuple array */
- array = (struct snd_soc_tplg_vendor_array *)malloc(size);
- ret = fread(array, sizeof(struct snd_soc_tplg_vendor_array), 1,
file);
- if (ret != 1)
return -EINVAL;
- read_array(array);
- /* parse buffer tokens */
- ret = sof_parse_tokens(&buffer, buffer_tokens,
ARRAY_SIZE(buffer_tokens), array,
size);
- /* create buffer component */
- if (ipc_buffer_new(sof->ipc, &buffer) < 0) {
fprintf(stderr, "error: buffer new\n");
return -EINVAL;
- }
- free(array);
- return 0;
+}
+/* load fileread component */ +static int load_fileread(struct sof *sof, int comp_id, int pipeline_id,
int size, char *bits_in, int *fr_id, int *sched_id)
+{
- struct sof_ipc_comp_file fileread;
- struct snd_soc_tplg_vendor_array *array = NULL;
- size_t total_array_size = 0, read_size;
- int ret = 0;
- fileread.config.frame_fmt = find_format(bits_in);
- /* allocate memory for vendor tuple array */
- array = (struct snd_soc_tplg_vendor_array *)malloc(size);
- if (!array) {
printf("error: mem alloc\n");
return -EINVAL;
- }
- /* read vendor tokens */
- while (total_array_size < size) {
read_size = sizeof(struct snd_soc_tplg_vendor_array);
ret = fread(array, read_size, 1, file);
if (ret != 1)
return -EINVAL;
read_array(array);
/* parse comp tokens */
ret = sof_parse_tokens(&fileread.config, comp_tokens,
ARRAY_SIZE(comp_tokens), array,
array->size);
if (ret != 0) {
printf("error: parse fileread tokens %d\n", size);
return -EINVAL;
}
total_array_size += array->size;
- }
- /* configure fileread */
- fileread.fn = strdup(input_file);
- fileread.mode = FILE_READ;
- fileread.comp.id = comp_id;
- /* use fileread comp as scheduling comp */
- *fr_id = *sched_id = comp_id;
- fileread.comp.hdr.size = sizeof(struct sof_ipc_comp_file);
- fileread.comp.type = SOF_COMP_FILEREAD;
- fileread.comp.pipeline_id = pipeline_id;
- /* create fileread component */
- if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&fileread) < 0) {
fprintf(stderr, "error: comp register\n");
return -EINVAL;
- }
- free(array);
- free(fileread.fn);
- return 0;
+}
+/* load filewrite component */ +static int load_filewrite(struct sof *sof, int comp_id, int pipeline_id,
int size, int *fw_id)
+{
- struct sof_ipc_comp_file filewrite;
- struct snd_soc_tplg_vendor_array *array = NULL;
- size_t total_array_size = 0, read_size;
- int ret = 0;
- /* allocate memory for vendor tuple array */
- array = (struct snd_soc_tplg_vendor_array *)malloc(size);
- if (!array) {
printf("error: mem alloc\n");
return -EINVAL;
- }
- /* read vendor tokens */
- while (total_array_size < size) {
read_size = sizeof(struct snd_soc_tplg_vendor_array);
ret = fread(array, read_size, 1, file);
if (ret != 1)
return -EINVAL;
read_array(array);
/* parse comp tokens */
ret = sof_parse_tokens(&filewrite.config, comp_tokens,
ARRAY_SIZE(comp_tokens), array,
array->size);
if (ret != 0) {
printf("error: parse filewrite tokens %d\n", size);
return -EINVAL;
}
total_array_size += array->size;
- }
- /* configure filewrite */
- filewrite.fn = strdup(output_file);
- filewrite.comp.id = comp_id;
- filewrite.mode = FILE_WRITE;
- *fw_id = comp_id;
- filewrite.comp.hdr.size = sizeof(struct sof_ipc_comp_file);
- filewrite.comp.type = SOF_COMP_FILEREAD;
- filewrite.comp.pipeline_id = pipeline_id;
- /* create filewrite component */
- if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&filewrite) < 0) {
fprintf(stderr, "error: comp register\n");
return -EINVAL;
free resources here ? and above, likewise for fileread.
- }
- free(array);
- free(filewrite.fn);
- return 0;
+}
+/* load pda dapm widget */ +static int load_pga(struct sof *sof, int comp_id, int pipeline_id,
int size)
+{
- struct sof_ipc_comp_volume volume;
- struct snd_soc_tplg_vendor_array *array = NULL;
- size_t total_array_size = 0, read_size;
- int ret = 0;
- /* allocate memory for vendor tuple array */
- array = (struct snd_soc_tplg_vendor_array *)malloc(size);
- if (!array) {
printf("error: mem alloc\n");
return -EINVAL;
- }
- /* read vendor tokens */
- while (total_array_size < size) {
read_size = sizeof(struct snd_soc_tplg_vendor_array);
ret = fread(array, read_size, 1, file);
if (ret != 1)
return -EINVAL;
read_array(array);
/* parse volume tokens */
ret = sof_parse_tokens(&volume.config, comp_tokens,
ARRAY_SIZE(comp_tokens), array,
array->size);
if (ret != 0) {
printf("error: parse pga tokens %d\n", size);
stderr
return -EINVAL;
please dont re-write the error value.
}
total_array_size += array->size;
- }
- /* configure volume */
- volume.comp.id = comp_id;
- volume.comp.hdr.size = sizeof(struct sof_ipc_comp_volume);
- volume.comp.type = SOF_COMP_VOLUME;
- volume.comp.pipeline_id = pipeline_id;
- /* load volume component */
- if (ipc_comp_new(sof->ipc, (struct sof_ipc_comp *)&volume) < 0) {
fprintf(stderr, "error: comp register\n");
return -EINVAL;
free array
- }
- free(array);
- return 0;
+}
+/* load scheduler dapm widget */ +static int load_pipeline(struct sof *sof, struct sof_ipc_pipe_new *pipeline,
int comp_id, int pipeline_id, int size, int
*sched_id) +{
- struct snd_soc_tplg_vendor_array *array = NULL;
- size_t total_array_size = 0, read_size;
- int ret = 0;
- /* configure pipeline */
- pipeline->sched_id = *sched_id;
- pipeline->comp_id = comp_id;
- pipeline->pipeline_id = pipeline_id;
- /* allocate memory for vendor tuple array */
- array = (struct snd_soc_tplg_vendor_array *)malloc(size);
- if (!array) {
printf("error: mem alloc\n");
return -EINVAL;
- }
- /* read vendor arrays */
- while (total_array_size < size) {
read_size = sizeof(struct snd_soc_tplg_vendor_array);
ret = fread(array, read_size, 1, file);
if (ret != 1)
return -EINVAL;
ret = read_array(array);
if (ret < 0)
return -EINVAL;
/* parse scheduler tokens */
ret = sof_parse_tokens(pipeline, sched_tokens,
ARRAY_SIZE(sched_tokens), array,
array->size);
if (ret != 0) {
printf("error: parse pipeline tokens %d\n", size);
return -EINVAL;
}
total_array_size += array->size;
- }
- /* Create pipeline */
- if (ipc_pipeline_new(sof->ipc, pipeline) < 0) {
fprintf(stderr, "error: pipeline new\n");
return -EINVAL;
- }
- free(array);
- return 0;
+}
+/* load dapm widget kcontrols
- we dont use controls in the testbench atm.
- so just skip to the next dapm widget
- */
+static int load_controls(struct sof *sof, int num_kcontrols) +{
- struct snd_soc_tplg_ctl_hdr *ctl_hdr;
- struct snd_soc_tplg_mixer_control *mixer_ctl;
- struct snd_soc_tplg_enum_control *enum_ctl;
- struct snd_soc_tplg_bytes_control *bytes_ctl;
- size_t read_size, size;
- int j, ret = 0;
- /* allocate memory */
- size = sizeof(struct snd_soc_tplg_ctl_hdr);
- ctl_hdr = (struct snd_soc_tplg_ctl_hdr *)malloc(size);
- if (!ctl_hdr) {
printf("error: mem alloc\n");
return -EINVAL;
-ENOMEM for all memory allocation failures.
- }
- size = sizeof(struct snd_soc_tplg_mixer_control);
- mixer_ctl = (struct snd_soc_tplg_mixer_control *)malloc(size);
- if (!mixer_ctl) {
printf("error: mem alloc\n");
return -EINVAL;
- }
- size = sizeof(struct snd_soc_tplg_enum_control);
- enum_ctl = (struct snd_soc_tplg_enum_control *)malloc(size);
- if (!enum_ctl) {
printf("error: mem alloc\n");
return -EINVAL;
- }
- size = sizeof(struct snd_soc_tplg_bytes_control);
- bytes_ctl = (struct snd_soc_tplg_bytes_control *)malloc(size);
- if (!bytes_ctl) {
printf("error: mem alloc\n");
return -EINVAL;
- }
- for (j = 0; j < num_kcontrols; j++) {
/* read control header */
read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
ret = fread(ctl_hdr, read_size, 1, file);
if (ret != 1)
return -EINVAL;
/* load control based on type */
switch (ctl_hdr->ops.info) {
case SND_SOC_TPLG_CTL_VOLSW:
case SND_SOC_TPLG_CTL_STROBE:
case SND_SOC_TPLG_CTL_VOLSW_SX:
case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
case SND_SOC_TPLG_CTL_RANGE:
case SND_SOC_TPLG_DAPM_CTL_VOLSW:
/* load mixer type control */
read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
fseek(file, read_size * -1, SEEK_CUR);
read_size = sizeof(struct
snd_soc_tplg_mixer_control);
ret = fread(mixer_ctl, read_size, 1, file);
if (ret != 1)
return -EINVAL;
/* skip mixer private data */
fseek(file, mixer_ctl->priv.size, SEEK_CUR);
break;
case SND_SOC_TPLG_CTL_ENUM:
case SND_SOC_TPLG_CTL_ENUM_VALUE:
case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE:
case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT:
case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE:
/* load enum type control */
read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
fseek(file, read_size * -1, SEEK_CUR);
read_size = sizeof(struct snd_soc_tplg_enum_control);
ret = fread(enum_ctl, read_size, 1, file);
if (ret != 1)
return -EINVAL;
/* skip enum private data */
fseek(file, enum_ctl->priv.size, SEEK_CUR);
break;
case SND_SOC_TPLG_CTL_BYTES:
/* load bytes type controls */
read_size = sizeof(struct snd_soc_tplg_ctl_hdr);
fseek(file, read_size * -1, SEEK_CUR);
read_size = sizeof(struct
snd_soc_tplg_bytes_control);
ret = fread(bytes_ctl, read_size, 1, file);
if (ret != 1)
return -EINVAL;
/* skip bytes private data */
fseek(file, bytes_ctl->priv.size, SEEK_CUR);
break;
default:
printf("control type not supported\n");
return -EINVAL;
}
- }
- /* free all data */
- free(mixer_ctl);
- free(enum_ctl);
- free(bytes_ctl);
- free(ctl_hdr);
- return 0;
+}
+/* load dapm widget */ +static int load_widget(struct sof *sof, int *fr_id, int *fw_id,
int *sched_id, char *bits_in,
struct comp_info *temp_comp_list,
struct sof_ipc_pipe_new *pipeline, int comp_id,
int comp_index, int pipeline_id)
+{
- struct snd_soc_tplg_dapm_widget *widget;
- char message[DEBUG_MSG_LEN];
- size_t read_size, size;
- int ret = 0;
- /* allocate memory for widget */
- size = sizeof(struct snd_soc_tplg_dapm_widget);
- widget = (struct snd_soc_tplg_dapm_widget *)malloc(size);
- if (!widget) {
printf("error: mem alloc\n");
return -EINVAL;
- }
- /* read widget data */
- read_size = sizeof(struct snd_soc_tplg_dapm_widget);
- ret = fread(widget, read_size, 1, file);
- if (ret != 1)
return -EINVAL;
- /*
* create a list with all widget info
* containing mapping between component names and ids
* which will be used for setting up component connections
*/
- temp_comp_list[comp_index].id = comp_id;
- temp_comp_list[comp_index].name = strdup(widget->name);
- temp_comp_list[comp_index].type = widget->id;
- temp_comp_list[comp_index].pipeline_id = pipeline_id;
- sprintf(message, "loading widget %s id %d\n",
temp_comp_list[comp_index].name,
temp_comp_list[comp_index].id);
- debug_print(message);
- /* register comp driver */
- register_comp(temp_comp_list[comp_index].type);
- /* load widget based on type */
- switch (temp_comp_list[comp_index].type) {
- /* load pga widget */
- case(SND_SOC_TPLG_DAPM_PGA):
if (load_pga(sof, temp_comp_list[comp_index].id,
pipeline_id, widget->priv.size) < 0) {
printf("error: load pga\n");
return -EINVAL;
}
break;
- /* replace pcm playback component with fileread in testbench */
- case(SND_SOC_TPLG_DAPM_AIF_IN):
if (load_fileread(sof, temp_comp_list[comp_index].id,
pipeline_id, widget->priv.size, bits_in,
fr_id, sched_id) < 0) {
printf("error: load fileread\n");
return -EINVAL;
}
break;
- /* replace dai in component with filewrite in testbench */
- case(SND_SOC_TPLG_DAPM_DAI_IN):
if (load_filewrite(sof, temp_comp_list[comp_index].id,
pipeline_id, widget->priv.size,
fw_id) < 0) {
printf("error: load filewrite\n");
return -EINVAL;
}
break;
- /* load buffer */
- case(SND_SOC_TPLG_DAPM_BUFFER):
if (load_buffer(sof, temp_comp_list[comp_index].id,
pipeline_id, widget->priv.size) < 0) {
printf("error: load buffer\n");
return -EINVAL;
}
break;
- /* load pipeline */
- case(SND_SOC_TPLG_DAPM_SCHEDULER):
if (load_pipeline(sof, pipeline,
temp_comp_list[comp_index].id,
pipeline_id,
widget->priv.size,
sched_id) < 0) {
printf("error: load buffer\n");
return -EINVAL;
}
break;
- /* unsupported widgets */
- default:
printf("Widget type not supported %d\n",
widget->id);
break;
- }
- /* load widget kcontrols */
- if (widget->num_kcontrols > 0)
if (load_controls(sof, widget->num_kcontrols) < 0) {
printf("error: load buffer\n");
return -EINVAL;
}
- free(widget);
- return 0;
+}
+/* parse topology file and set up pipeline */ +int parse_topology(char *filename, struct sof *sof, int *fr_id, int *fw_id,
int *sched_id, char *bits_in, char *in_file,
char *out_file, void *volume_library, char *pipeline_msg)
+{
- struct snd_soc_tplg_hdr *hdr;
- struct comp_info *temp_comp_list = NULL;
- struct sof_ipc_pipe_new pipeline;
- char message[DEBUG_MSG_LEN];
- int next_comp_id = 0, num_comps = 0;
- int i, ret = 0;
- size_t file_size, size;
- /* set volume library */
- volume_lib = volume_library;
- /* open topology file */
- file = fopen(filename, "rb");
- if (!file) {
fprintf(stderr, "error: opening file %s\n", filename);
return -EINVAL;
- }
- /* set up fileread and filewrite file names */
- input_file = strdup(in_file);
- output_file = strdup(out_file);
- /* file size */
- fseek(file, 0, SEEK_END);
- file_size = ftell(file);
- fseek(file, 0, SEEK_SET);
- /* allocate memory */
- size = sizeof(struct snd_soc_tplg_hdr);
- hdr = (struct snd_soc_tplg_hdr *)malloc(size);
- if (!hdr) {
printf("error: mem alloc\n");
return -EINVAL;
- }
- debug_print("topology parsing start\n");
- while (1) {
/* read topology header */
ret = fread(hdr, sizeof(struct snd_soc_tplg_hdr), 1, file);
if (ret != 1)
return -EINVAL;
sprintf(message, "type: %x, size: 0x%x count: %d index:
%d\n",
hdr->type, hdr->payload_size, hdr->count, hdr-
index);
debug_print(message);
/* parse header and load the next block based on type */
switch (hdr->type) {
/* load dapm widget */
case SND_SOC_TPLG_TYPE_DAPM_WIDGET:
sprintf(message, "number of DAPM widgets %d\n",
hdr->count);
debug_print(message);
size = sizeof(struct comp_info) * hdr->count;
temp_comp_list = (struct comp_info *)malloc(size);
num_comps = hdr->count;
for (i = 0; i < hdr->count; i++)
load_widget(sof, fr_id, fw_id, sched_id,
bits_in, temp_comp_list,
&pipeline, next_comp_id++,
i, hdr->index);
break;
/* set up component connections from pipeline graph */
case SND_SOC_TPLG_TYPE_DAPM_GRAPH:
if (load_graph(sof, temp_comp_list, hdr->count,
num_comps, hdr->index) < 0) {
printf("error: pipeline graph\n");
return -EINVAL;
}
if (ftell(file) == file_size)
goto finish;
break;
default:
fseek(file, hdr->payload_size, SEEK_CUR);
if (ftell(file) == file_size)
goto finish;
break;
}
- }
+finish:
- debug_print("topology parsing end\n");
- strcpy(pipeline_msg, pipeline_string);
- /* free all data */
- free(hdr);
- for (i = 0; i < num_comps; i++)
free(temp_comp_list[i].name);
- free(temp_comp_list);
- fclose(file);
- return 0;
+}
+/* parse vendor tokens in topology */ +int sof_parse_tokens(void *object, const struct sof_topology_token *tokens,
int count, struct snd_soc_tplg_vendor_array *array,
int priv_size)
+{
- int asize;
- while (priv_size > 0) {
asize = array->size;
/* validate asize */
if (asize < 0) { /* FIXME: A zero-size array makes no sense
*/
printf("error: invalid array size 0x%x\n", asize);
return -EINVAL;
}
/* make sure there is enough data before parsing */
priv_size -= asize;
if (priv_size < 0) {
printf("error: invalid array size 0x%x\n", asize);
return -EINVAL;
}
/* call correct parser depending on type */
switch (array->type) {
case SND_SOC_TPLG_TUPLE_TYPE_UUID:
sof_parse_uuid_tokens(object, tokens, count,
array);
break;
case SND_SOC_TPLG_TUPLE_TYPE_STRING:
sof_parse_string_tokens(object, tokens, count,
array);
break;
case SND_SOC_TPLG_TUPLE_TYPE_BOOL:
case SND_SOC_TPLG_TUPLE_TYPE_BYTE:
case SND_SOC_TPLG_TUPLE_TYPE_WORD:
case SND_SOC_TPLG_TUPLE_TYPE_SHORT:
sof_parse_word_tokens(object, tokens, count,
array);
break;
default:
printf("error: unknown token type %d\n", array-
type);
return -EINVAL;
}
/* next array */
array = (void *)array + asize;
- }
- return 0;
+}
+void sof_parse_word_tokens(void *object,
const struct sof_topology_token *tokens,
int count,
struct snd_soc_tplg_vendor_array *array)
+{
- struct snd_soc_tplg_vendor_value_elem *elem;
- int i, j;
- /* parse element by element */
- for (i = 0; i < array->num_elems; i++) {
elem = &array->value[i];
/* search for token */
for (j = 0; j < count; j++) {
/* match token type */
if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_WORD)
continue;
/* match token id */
if (tokens[j].token != elem->token)
continue;
/* matched - now load token */
tokens[j].get_token(elem, object, tokens[j].offset,
tokens[j].size);
}
- }
+}
+void sof_parse_uuid_tokens(void *object,
const struct sof_topology_token *tokens,
int count,
struct snd_soc_tplg_vendor_array *array)
+{
- struct snd_soc_tplg_vendor_uuid_elem *elem;
- int i, j;
- /* parse element by element */
- for (i = 0; i < array->num_elems; i++) {
elem = &array->uuid[i];
/* search for token */
for (j = 0; j < count; j++) {
/* match token type */
if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_UUID)
continue;
/* match token id */
if (tokens[j].token != elem->token)
continue;
/* matched - now load token */
tokens[j].get_token(elem, object, tokens[j].offset,
tokens[j].size);
}
- }
+}
+void sof_parse_string_tokens(void *object,
const struct sof_topology_token *tokens,
int count,
struct snd_soc_tplg_vendor_array *array)
+{
- struct snd_soc_tplg_vendor_string_elem *elem;
- int i, j;
- /* parse element by element */
- for (i = 0; i < array->num_elems; i++) {
elem = &array->string[i];
/* search for token */
for (j = 0; j < count; j++) {
/* match token type */
if (tokens[j].type != SND_SOC_TPLG_TUPLE_TYPE_STRING)
continue;
/* match token id */
if (tokens[j].token != elem->token)
continue;
/* matched - now load token */
tokens[j].get_token(elem, object, tokens[j].offset,
tokens[j].size);
}
- }
+}
+enum sof_ipc_frame find_format(const char *name) +{
- int i;
- for (i = 0; i < ARRAY_SIZE(sof_frames); i++) {
if (strcmp(name, sof_frames[i].name) == 0)
return sof_frames[i].frame;
- }
- /* use s32le if nothing is specified */
- return SOF_IPC_FRAME_S32_LE;
+}
+int get_token_uint32_t(void *elem, void *object, uint32_t offset,
uint32_t size)
+{
- struct snd_soc_tplg_vendor_value_elem *velem = elem;
- uint32_t *val = object + offset;
- *val = velem->value;
- return 0;
+}
+int get_token_comp_format(void *elem, void *object, uint32_t offset,
uint32_t size)
+{
- struct snd_soc_tplg_vendor_string_elem *velem = elem;
- uint32_t *val = object + offset;
- *val = find_format(velem->string);
- return 0;
+} diff --git a/src/host/trace.c b/src/host/trace.c new file mode 100644 index 0000000..a98648b --- /dev/null +++ b/src/host/trace.c @@ -0,0 +1,181 @@ +/*
- 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
Liam Girdwood <liam.r.girdwood@linux.intel.com>
Keyon Jie <yang.jie@linux.intel.com>
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include "host/common_test.h" +#include "host/trace.h"
+#define MAX_TRACE_CLASSES 255 +/* testbench trace definition */
+/* enable trace by default in testbench */ +static int test_bench_trace = 1; +int num_trace_classes;
+/* set up trace class identifier table based on SOF trace header file */ +void setup_trace_table(void) +{
- char buffer[2048];
- char *trace = "sof/trace.h";
- char *trace_filename = malloc(strlen(SOF_INC) + strlen(trace) + 2);
- char *token;
- int ret, i = 0;
- size_t size;
- FILE *fp;
- /* set up trace file name using include directory prefix */
- sprintf(trace_filename, "%s/%s", SOF_INC, trace);
- fp = fopen(trace_filename, "r");
- if (!fp) {
fprintf(stderr, "error: opening trace include file %s\n",
trace_filename);
include errno here.
- }
- /* find number of trace classes defined */
- while (fgets(buffer, sizeof(buffer), fp)) {
char identifier[1024];
int value = 0, shift = 0;
ret = sscanf(buffer, "#define %s (%d << %d)", identifier,
&value, &shift);
if (ret == 3) {
/* if TRACE_CLASS definition */
if (strstr(identifier, "TRACE_CLASS"))
i++;
}
- }
- num_trace_classes = i;
- /* allocate memory for trace table */
- size = sizeof(struct trace_class_table);
- trace_table = (struct trace_class_table *)malloc(size *
num_trace_classes);
- /* rewind file pointer */
- fseek(fp, 0, SEEK_SET);
- i = 0;
- /* read lines from header */
Can you explain what this does in more detail.
- while (fgets(buffer, sizeof(buffer), fp)) {
char identifier[1024];
int value = 0, shift = 0;
should be declared at top of func.
ret = sscanf(buffer, "#define %s (%d << %d)", identifier,
&value, &shift);
if (ret == 3) {
/* if TRACE_CLASS definition */
if (strstr(identifier, "TRACE_CLASS")) {
/* extract subsystem name */
token = strtok(identifier, "_");
token = strtok(NULL, "_");
token = strtok(NULL, "_");
/* add trace class entry */
trace_table[i].trace_class = value;
trace_table[i].class_name = strdup(token);
i++;
}
}
- }
- fclose(fp);
- free(trace_filename);
+}
+void free_trace_table(void) +{
- int i;
- for (i = 0; i < num_trace_classes; i++)
free(trace_table[i].class_name);
- free(trace_table);
+}
+/* look up subsystem class name from table */ +static char *get_trace_class(uint32_t trace_class) +{
- int i;
- /* look up trace class table and return subsystem name */
- for (i = 0; i < num_trace_classes; i++) {
if (trace_table[i].trace_class == trace_class)
return trace_table[i].class_name;
- }
- return "value";
+}
+/* print trace event */ +void _trace_event(uint32_t event) +{
- char a, b, c;
- char *trace_class = NULL;
- if (test_bench_trace > 0) {
a = event & 0xff;
b = (event >> 8) & 0xff;
c = (event >> 16) & 0xff;
/* look up subsystem from trace class table */
trace_class = strdup(get_trace_class(event >> 24));
/* print trace event stderr*/
if (strcmp(trace_class, "value") == 0)
fprintf(stderr, "Trace value %d\n", event);
else
fprintf(stderr, "Trace %s %c%c%c\n", trace_class,
c, b, a);
- }
- free(trace_class);
+}
+void _trace_event_mbox_atomic(uint32_t event) +{
- _trace_event(event);
+}
+/* enable trace in testbench */ +void tb_enable_trace(bool enable) +{
- test_bench_trace = enable;
- if (enable)
debug_print("trace print enabled\n");
- else
debug_print("trace print disabled\n");
+} diff --git a/src/include/host/common_test.h b/src/include/host/common_test.h new file mode 100644 index 0000000..96193e5 --- /dev/null +++ b/src/include/host/common_test.h @@ -0,0 +1,65 @@ +/*
- 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(s): Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
Liam Girdwood <liam.r.girdwood@linux.intel.com>
Keyon Jie <yang.jie@linux.intel.com>
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+#ifndef _COMMON_TEST_H +#define _COMMON_TEST_H
+#include <stdint.h> +#include <stddef.h> +#include <time.h> +#include <stdio.h> +#include <uapi/ipc.h> +#include <sof/sof.h> +#include <sof/audio/component.h> +#include <sof/audio/format.h>
+#define DEBUG_MSG_LEN 256
+extern int debug;
+int scheduler_init(struct sof *sof);
+void sys_comp_file_init(void);
+void sys_comp_filewrite_init(void);
+int tb_pipeline_setup(struct sof *sof);
+int tb_pipeline_start(struct ipc *ipc, int nch, char *bits_in,
struct sof_ipc_pipe_new *ipc_pipe);
+int tb_pipeline_params(struct ipc *ipc, int nch, char *bits_in,
struct sof_ipc_pipe_new *ipc_pipe);
+void debug_print(char *message);
+#endif diff --git a/src/include/host/topology.h b/src/include/host/topology.h new file mode 100644 index 0000000..b3421c8 --- /dev/null +++ b/src/include/host/topology.h @@ -0,0 +1,202 @@ +/*
- 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: Liam Girdwood liam.r.girdwood@linux.intel.com
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+#ifndef _COMMON_TPLG_H +#define _COMMON_TPLG_H
+#include <sound/asoc.h> +#include "common_test.h"
+/*
- TODO: include these token from kernel uapi header
- Tokens - must match values in topology configurations
- */
+/* buffers */ +#define SOF_TKN_BUF_SIZE 100 +#define SOF_TKN_BUF_CAPS 101
+/* scheduling */ +#define SOF_TKN_SCHED_DEADLINE 200 +#define SOF_TKN_SCHED_PRIORITY 201 +#define SOF_TKN_SCHED_MIPS 202 +#define SOF_TKN_SCHED_CORE 203 +#define SOF_TKN_SCHED_FRAMES 204 +#define SOF_TKN_SCHED_TIMER 205
+/* volume */ +#define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250 +#define SOF_TKN_VOLUME_RAMP_STEP_MS 251
+/* SRC */ +#define SOF_TKN_SRC_RATE_IN 300 +#define SOF_TKN_SRC_RATE_OUT 301
+/* Generic components */ +#define SOF_TKN_COMP_PERIOD_SINK_COUNT 400 +#define SOF_TKN_COMP_PERIOD_SOURCE_COUNT 401 +#define SOF_TKN_COMP_FORMAT 402 +#define SOF_TKN_COMP_PRELOAD_COUNT 403
+struct comp_info {
- char *name;
- int id;
- int type;
- int pipeline_id;
+};
+struct frame_types {
- char *name;
- enum sof_ipc_frame frame;
+};
+static const struct frame_types sof_frames[] = {
- /* TODO: fix topology to use ALSA formats */
- {"s16le", SOF_IPC_FRAME_S16_LE},
- {"s24le", SOF_IPC_FRAME_S24_4LE},
- {"s32le", SOF_IPC_FRAME_S32_LE},
- {"float", SOF_IPC_FRAME_FLOAT},
- /* ALSA formats */
- {"S16_LE", SOF_IPC_FRAME_S16_LE},
- {"S24_LE", SOF_IPC_FRAME_S24_4LE},
- {"S32_LE", SOF_IPC_FRAME_S32_LE},
- {"FLOAT_LE", SOF_IPC_FRAME_FLOAT},
+};
+struct sof_topology_token {
- uint32_t token;
- uint32_t type;
- int (*get_token)(void *elem, void *object, uint32_t offset,
uint32_t size);
- uint32_t offset;
- uint32_t size;
+};
+enum sof_ipc_frame find_format(const char *name);
+int get_token_uint32_t(void *elem, void *object, uint32_t offset,
uint32_t size);
+int get_token_comp_format(void *elem, void *object, uint32_t offset,
uint32_t size);
+/* Buffers */ +static const struct sof_topology_token buffer_tokens[] = {
- {SOF_TKN_BUF_SIZE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
offsetof(struct sof_ipc_buffer, size), 0},
- {SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
offsetof(struct sof_ipc_buffer, caps), 0},
+};
+/* scheduling */ +static const struct sof_topology_token sched_tokens[] = {
- {SOF_TKN_SCHED_DEADLINE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_uint32_t,
offsetof(struct sof_ipc_pipe_new, deadline), 0},
- {SOF_TKN_SCHED_PRIORITY, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_uint32_t,
offsetof(struct sof_ipc_pipe_new, priority), 0},
- {SOF_TKN_SCHED_MIPS, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_uint32_t,
offsetof(struct sof_ipc_pipe_new, mips), 0},
- {SOF_TKN_SCHED_CORE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_uint32_t,
offsetof(struct sof_ipc_pipe_new, core), 0},
- {SOF_TKN_SCHED_FRAMES, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_uint32_t,
offsetof(struct sof_ipc_pipe_new, frames_per_sched), 0},
- {SOF_TKN_SCHED_TIMER, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_uint32_t,
offsetof(struct sof_ipc_pipe_new, timer), 0},
+};
+/* volume */ +static const struct sof_topology_token volume_tokens[] = {
- {SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_uint32_t,
offsetof(struct sof_ipc_comp_volume, ramp), 0},
- {SOF_TKN_VOLUME_RAMP_STEP_MS,
SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
offsetof(struct sof_ipc_comp_volume, initial_ramp), 0},
+};
+/* SRC */ +static const struct sof_topology_token src_tokens[] = {
- {SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_uint32_t,
offsetof(struct sof_ipc_comp_src, source_rate), 0},
- {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD,
get_token_uint32_t,
offsetof(struct sof_ipc_comp_src, sink_rate), 0},
+};
+/* Tone */ +static const struct sof_topology_token tone_tokens[] = { +};
+/* Generic components */ +static const struct sof_topology_token comp_tokens[] = {
- {SOF_TKN_COMP_PERIOD_SINK_COUNT,
SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
offsetof(struct sof_ipc_comp_config, periods_sink), 0},
- {SOF_TKN_COMP_PERIOD_SOURCE_COUNT,
SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
offsetof(struct sof_ipc_comp_config, periods_source), 0},
- {SOF_TKN_COMP_FORMAT,
SND_SOC_TPLG_TUPLE_TYPE_STRING, get_token_comp_format,
offsetof(struct sof_ipc_comp_config, frame_fmt), 0},
- {SOF_TKN_COMP_PRELOAD_COUNT,
SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_uint32_t,
offsetof(struct sof_ipc_comp_config, preload_count), 0},
+};
+int sof_parse_tokens(void *object,
const struct sof_topology_token *tokens,
int count, struct snd_soc_tplg_vendor_array *array,
int priv_size);
+void sof_parse_string_tokens(void *object,
const struct sof_topology_token *tokens,
int count,
struct snd_soc_tplg_vendor_array *array);
+void sof_parse_uuid_tokens(void *object,
const struct sof_topology_token *tokens,
int count,
struct snd_soc_tplg_vendor_array *array);
+void sof_parse_word_tokens(void *object,
const struct sof_topology_token *tokens,
int count,
struct snd_soc_tplg_vendor_array *array);
+int parse_topology(char *filename, struct sof *sof, int *fr_id, int *fw_id,
int *sched_id, char *bits_in,
char *in_file, char *out_file, void *volume_library,
char *pipeline);
+#endif diff --git a/src/include/host/trace.h b/src/include/host/trace.h new file mode 100644 index 0000000..8c45fb4 --- /dev/null +++ b/src/include/host/trace.h @@ -0,0 +1,49 @@ +/*
- 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+#include <stdbool.h>
+#ifndef _TRACE_H +#define _TRACE_H
+struct trace_class_table {
- int trace_class;
- char *class_name;
+};
+struct trace_class_table *trace_table;
+void tb_enable_trace(bool enable);
+void setup_trace_table(void);
+void free_trace_table(void);
+#endif
--------------------------------------------------------------------- Intel Corporation (UK) Limited Registered No. 1134945 (England) Registered Office: Pipers Way, Swindon SN3 1RJ VAT No: 860 2173 47
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.
This patch adds a new file component that testbench can use to read in samples and write out processed samples. Both text and raw pcm input formats are supported.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- src/host/file.c | 720 ++++++++++++++++++++++++++++++++++++++++ src/include/host/file.h | 77 +++++ 2 files changed, 797 insertions(+) create mode 100644 src/host/file.c create mode 100644 src/include/host/file.h
diff --git a/src/host/file.c b/src/host/file.c new file mode 100644 index 0000000..f0d420f --- /dev/null +++ b/src/host/file.c @@ -0,0 +1,720 @@ +/* + * 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(s): Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ + +/* file component for reading/writing pcm samples to/from a file */ + +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> +#include <errno.h> +#include <inttypes.h> +#include <sof/sof.h> +#include <sof/lock.h> +#include <sof/list.h> +#include <sof/stream.h> +#include <sof/work.h> +#include <sof/clock.h> +#include <sof/audio/component.h> +#include <sof/audio/format.h> +#include <sof/audio/pipeline.h> +#include <uapi/ipc.h> +#include "host/common_test.h" +#include "host/file.h" + +static inline void buffer_check_wrap_32(int32_t **ptr, int32_t *end, + size_t size) +{ + if (*ptr >= end) + *ptr = (int32_t *)((size_t)*ptr - size); +} + +static inline void buffer_check_wrap_16(int16_t **ptr, int16_t *end, + size_t size) +{ + if (*ptr >= end) + *ptr = (int16_t *)((size_t)*ptr - size); +} + +/* + * Read 32-bit samples from file + * currently only supports txt files + */ +static int read_samples_32(struct comp_dev *dev, struct comp_buffer *sink, + int n, int fmt, int nch) +{ + struct file_comp_data *cd = comp_get_drvdata(dev); + int32_t *dest = (int32_t *)sink->w_ptr; + int32_t sample; + int n_samples = 0; + int i, n_wrap, n_min, ret; + + while (n > 0) { + n_wrap = (int32_t *)sink->end_addr - dest; + + /* check for buffer wrap and copy to the end of the buffer */ + n_min = (n < n_wrap) ? n : n_wrap; + while (n_min > 0) { + n -= nch; + n_min -= nch; + + /* copy sample per channel */ + for (i = 0; i < nch; i++) { + /* read sample from file */ + switch (cd->fs.f_format) { + /* text input file */ + case FILE_TEXT: + if (fmt == SOF_IPC_FRAME_S32_LE) + ret = fscanf(cd->fs.rfh, "%d", + dest); + + /* mask bits if 24-bit samples */ + if (fmt == SOF_IPC_FRAME_S24_4LE) { + ret = fscanf(cd->fs.rfh, "%d", + &sample); + *dest = sample & 0x00ffffff; + } + /* quit if eof is reached */ + if (ret == EOF) { + cd->fs.reached_eof = 1; + goto quit; + } + break; + + /* raw input file */ + default: + if (fmt == SOF_IPC_FRAME_S32_LE) + ret = fread(dest, + sizeof(int32_t), + 1, cd->fs.rfh); + + /* mask bits if 24-bit samples */ + if (fmt == SOF_IPC_FRAME_S24_4LE) { + ret = fread(&sample, + sizeof(int32_t), + 1, cd->fs.rfh); + *dest = sample & 0x00ffffff; + } + /* quit if eof is reached */ + if (ret != 1) { + cd->fs.reached_eof = 1; + goto quit; + } + break; + } + dest++; + n_samples++; + } + } + /* check for buffer wrap and update pointer */ + buffer_check_wrap_32(&dest, sink->end_addr, + sink->size); + } +quit: + return n_samples; +} + +/* + * Read 16-bit samples from file + * currently only supports txt files + */ +static int read_samples_16(struct comp_dev *dev, struct comp_buffer *sink, + int n, int nch) +{ + struct file_comp_data *cd = comp_get_drvdata(dev); + int16_t *dest = (int16_t *)sink->w_ptr; + int i, n_wrap, n_min, ret; + int n_samples = 0; + + /* copy samples */ + while (n > 0) { + n_wrap = (int16_t *)sink->end_addr - dest; + + /* check for buffer wrap and copy to the end of the buffer */ + n_min = (n < n_wrap) ? n : n_wrap; + while (n_min > 0) { + n -= nch; + n_min -= nch; + + /* copy sample per channel */ + for (i = 0; i < nch; i++) { + /* read sample from file */ + ret = fscanf(cd->fs.rfh, "%hd", dest); + switch (cd->fs.f_format) { + /* text input file */ + case FILE_TEXT: + ret = fscanf(cd->fs.rfh, "%hd", dest); + if (ret == EOF) { + cd->fs.reached_eof = 1; + goto quit; + } + break; + + /* rw pcm input file */ + default: + ret = fread(dest, sizeof(int16_t), 1, + cd->fs.rfh); + if (ret != 1) { + cd->fs.reached_eof = 1; + goto quit; + } + break; + } + + dest++; + n_samples++; + } + } + /* check for buffer wrap and update pointer */ + buffer_check_wrap_16(&dest, sink->end_addr, + sink->size); + } + +quit: + return n_samples; +} + +/* + * Write 16-bit samples from file + * currently only supports txt files + */ +static int write_samples_16(struct comp_dev *dev, struct comp_buffer *source, + int n, int nch) +{ + struct file_comp_data *cd = comp_get_drvdata(dev); + int16_t *src = (int16_t *)source->r_ptr; + int i, n_wrap, n_min, ret; + int n_samples = 0; + + /* copy samples */ + while (n > 0) { + n_wrap = (int16_t *)source->end_addr - src; + + /* check for buffer wrap and copy to the end of the buffer */ + n_min = (n < n_wrap) ? n : n_wrap; + while (n_min > 0) { + n -= nch; + n_min -= nch; + + /* copy sample per channel */ + for (i = 0; i < nch; i++) { + switch (cd->fs.f_format) { + /* text output file */ + case FILE_TEXT: + ret = fprintf(cd->fs.wfh, + "%d\n", *src); + if (ret < 0) + goto quit; + break; + + /* raw pcm output file */ + default: + ret = fwrite(src, + sizeof(int16_t), + 1, cd->fs.wfh); + if (ret != 1) + goto quit; + break; + } + + src++; + n_samples++; + } + } + /* check for buffer wrap and update pointer */ + buffer_check_wrap_16(&src, source->end_addr, + source->size); + } +quit: + return n_samples; +} + +/* + * Write 32-bit samples from file + * currently only supports txt files + */ +static int write_samples_32(struct comp_dev *dev, struct comp_buffer *source, + int n, int fmt, int nch) +{ + struct file_comp_data *cd = comp_get_drvdata(dev); + int32_t *src = (int32_t *)source->r_ptr; + int i, n_wrap, n_min, ret; + int n_samples = 0; + int32_t sample; + + /* copy samples */ + while (n > 0) { + n_wrap = (int32_t *)source->end_addr - src; + + /* check for buffer wrap and copy to the end of the buffer */ + n_min = (n < n_wrap) ? n : n_wrap; + while (n_min > 0) { + n -= nch; + n_min -= nch; + + /* copy sample per channel */ + for (i = 0; i < nch; i++) { + switch (cd->fs.f_format) { + /* text output file */ + case FILE_TEXT: + if (fmt == SOF_IPC_FRAME_S32_LE) + ret = fprintf(cd->fs.wfh, + "%d\n", *src); + if (fmt == SOF_IPC_FRAME_S24_4LE) { + sample = *src << 8; + ret = fprintf(cd->fs.wfh, + "%d\n", + sample >> 8); + } + if (ret < 0) + goto quit; + break; + + /* raw pcm output file */ + default: + if (fmt == SOF_IPC_FRAME_S32_LE) + ret = fwrite(src, + sizeof(int32_t), + 1, cd->fs.wfh); + if (fmt == SOF_IPC_FRAME_S24_4LE) { + sample = *src << 8; + sample >>= 8; + ret = fwrite(&sample, + sizeof(int32_t), + 1, cd->fs.wfh); + } + if (ret != 1) + goto quit; + break; + } + + /* increment read pointer */ + src++; + + /* increment number of samples written */ + n_samples++; + } + } + /* check for buffer wrap and update pointer */ + buffer_check_wrap_32(&src, source->end_addr, + source->size); + } +quit: + return n_samples; +} + +/* function for processing 32-bit samples */ +static int file_s32_default(struct comp_dev *dev, struct comp_buffer *sink, + struct comp_buffer *source, uint32_t frames) +{ + struct file_comp_data *cd = comp_get_drvdata(dev); + int nch = dev->params.channels; + int n_samples = 0; + + switch (cd->fs.mode) { + case FILE_READ: + /* read samples */ + n_samples = read_samples_32(dev, sink, frames * nch, + SOF_IPC_FRAME_S32_LE, nch); + break; + case FILE_WRITE: + /* write samples */ + n_samples = write_samples_32(dev, source, frames * nch, + SOF_IPC_FRAME_S32_LE, nch); + break; + default: + /* TODO: duplex mode */ + break; + } + + cd->fs.n += n_samples; + return n_samples; +} + +/* function for processing 16-bit samples */ +static int file_s16(struct comp_dev *dev, struct comp_buffer *sink, + struct comp_buffer *source, uint32_t frames) +{ + struct file_comp_data *cd = comp_get_drvdata(dev); + int nch = dev->params.channels; + int n_samples = 0; + + switch (cd->fs.mode) { + case FILE_READ: + /* read samples */ + n_samples = read_samples_16(dev, sink, frames * nch, nch); + break; + case FILE_WRITE: + /* write samples */ + n_samples = write_samples_16(dev, source, frames * nch, nch); + break; + default: + /* TODO: duplex mode */ + break; + } + + cd->fs.n += n_samples; + return n_samples; +} + +/* function for processing 24-bit samples */ +static int file_s24(struct comp_dev *dev, struct comp_buffer *sink, + struct comp_buffer *source, uint32_t frames) +{ + struct file_comp_data *cd = comp_get_drvdata(dev); + int nch = dev->params.channels; + int n_samples = 0; + + switch (cd->fs.mode) { + case FILE_READ: + /* read samples */ + n_samples = read_samples_32(dev, sink, frames * nch, + SOF_IPC_FRAME_S24_4LE, nch); + break; + case FILE_WRITE: + /* write samples */ + n_samples = write_samples_32(dev, source, frames * nch, + SOF_IPC_FRAME_S24_4LE, nch); + break; + default: + /* TODO: duplex mode */ + break; + } + + cd->fs.n += n_samples; + return n_samples; +} + +static enum file_format get_file_format(char *filename) +{ + char *ext = strrchr(filename, '.'); + + if (!strcmp(ext, ".txt")) + return FILE_TEXT; + + return FILE_RAW; +} + +static struct comp_dev *file_new(struct sof_ipc_comp *comp) +{ + struct comp_dev *dev; + struct sof_ipc_comp_file *file; + struct sof_ipc_comp_file *ipc_file = + (struct sof_ipc_comp_file *)comp; + struct file_comp_data *cd; + + /* allocate memory for file comp */ + dev = malloc(COMP_SIZE(struct sof_ipc_comp_file)); + if (!dev) + return NULL; + + /* copy file comp config */ + file = (struct sof_ipc_comp_file *)&dev->comp; + memcpy(file, ipc_file, sizeof(struct sof_ipc_comp_file)); + + /* allocate memory for file comp data */ + cd = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) { + free(dev); + return NULL; + } + + comp_set_drvdata(dev, cd); + + /* default function for processing samples */ + cd->file_func = file_s32_default; + + /* get filename from IPC and open file */ + cd->fs.fn = strdup(ipc_file->fn); + + /* set file format */ + cd->fs.f_format = get_file_format(cd->fs.fn); + + /* set file comp mode */ + cd->fs.mode = ipc_file->mode; + + /* open file handle(s) depending on mode */ + switch (cd->fs.mode) { + case FILE_READ: + cd->fs.rfh = fopen(cd->fs.fn, "r"); + if (!cd->fs.rfh) { + fprintf(stderr, "error: opening file %s\n", cd->fs.fn); + free(cd); + free(dev); + return NULL; + } + break; + case FILE_WRITE: + cd->fs.wfh = fopen(cd->fs.fn, "w"); + if (!cd->fs.wfh) { + fprintf(stderr, "error: opening file %s\n", cd->fs.fn); + free(cd); + free(dev); + return NULL; + } + break; + default: + /* TODO: duplex mode */ + break; + } + + cd->fs.reached_eof = 0; + cd->fs.n = 0; + + dev->state = COMP_STATE_READY; + + return dev; +} + +static void file_free(struct comp_dev *dev) +{ + struct file_comp_data *cd = comp_get_drvdata(dev); + + if (cd->fs.mode == FILE_READ) + fclose(cd->fs.rfh); + else + fclose(cd->fs.wfh); + + free(cd->fs.fn); + free(cd); + free(dev); + + debug_print("free file component\n"); +} + +/* set component audio stream parameters */ +static int file_params(struct comp_dev *dev) +{ + struct file_comp_data *cd = comp_get_drvdata(dev); + struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev); + + /* for file endpoint set the following from topology config */ + if (cd->fs.mode == FILE_WRITE) { + dev->params.frame_fmt = config->frame_fmt; + if (dev->params.frame_fmt == SOF_IPC_FRAME_S16_LE) + dev->params.sample_container_bytes = 2; + else + dev->params.sample_container_bytes = 4; + } + + /* Need to compute this in non-host endpoint */ + dev->frame_bytes = + dev->params.sample_container_bytes * dev->params.channels; + + /* calculate period size based on config */ + cd->period_bytes = dev->frames * dev->frame_bytes; + + /* File to sink supports only S32_LE/S16_LE/S24_4LE PCM formats */ + if (config->frame_fmt != SOF_IPC_FRAME_S32_LE && + config->frame_fmt != SOF_IPC_FRAME_S24_4LE && + config->frame_fmt != SOF_IPC_FRAME_S16_LE) + return -EINVAL; + + return 0; +} + +static int fr_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) +{ + return -EINVAL; +} + +static int file_trigger(struct comp_dev *dev, int cmd) +{ + return comp_set_state(dev, cmd); +} + +/* used to pass standard and bespoke commands (with data) to component */ +static int file_cmd(struct comp_dev *dev, int cmd, void *data) +{ + struct sof_ipc_ctrl_data *cdata = data; + int ret = 0; + + switch (cmd) { + case COMP_CMD_SET_DATA: + ret = fr_cmd(dev, cdata); + break; + default: + break; + } + + return ret; +} + +/* + * copy and process stream samples + * returns the number of bytes copied + */ +static int file_copy(struct comp_dev *dev) +{ + struct comp_buffer *buffer; + struct file_comp_data *cd = comp_get_drvdata(dev); + int ret = 0, bytes; + + switch (cd->fs.mode) { + case FILE_READ: + /* file component sink buffer */ + buffer = list_first_item(&dev->bsink_list, struct comp_buffer, + source_list); + + /* test sink has enough free frames */ + if (buffer->free >= cd->period_bytes && !cd->fs.reached_eof) { + /* read PCM samples from file */ + ret = cd->file_func(dev, buffer, NULL, dev->frames); + + /* update sink buffer pointers */ + bytes = dev->params.sample_container_bytes; + if (ret > 0) + comp_update_buffer_produce(buffer, + ret * bytes); + } + break; + case FILE_WRITE: + /* file component source buffer */ + buffer = list_first_item(&dev->bsource_list, + struct comp_buffer, sink_list); + + /* test source has enough free frames */ + if (buffer->avail >= cd->period_bytes) { + /* write PCM samples into file */ + ret = cd->file_func(dev, NULL, buffer, dev->frames); + + /* update source buffer pointers */ + bytes = dev->params.sample_container_bytes; + if (ret > 0) + comp_update_buffer_consume(buffer, + ret * bytes); + } + break; + default: + /* TODO: duplex mode */ + break; + } + + return ret; +} + +static int file_prepare(struct comp_dev *dev) +{ + struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev); + struct comp_buffer *buffer = NULL; + struct file_comp_data *cd = comp_get_drvdata(dev); + int ret = 0, periods; + + /* file component sink/source buffer period count */ + switch (cd->fs.mode) { + case FILE_READ: + buffer = list_first_item(&dev->bsink_list, struct comp_buffer, + source_list); + periods = config->periods_sink; + break; + case FILE_WRITE: + buffer = list_first_item(&dev->bsource_list, + struct comp_buffer, sink_list); + periods = config->periods_source; + break; + default: + /* TODO: duplex mode */ + break; + } + + if (!buffer) { + printf("error: no sink/source buffer\n"); + return -EINVAL; + } + + /* set downstream buffer size */ + switch (config->frame_fmt) { + case(SOF_IPC_FRAME_S16_LE): + ret = buffer_set_size(buffer, dev->frames * 2 * + periods * dev->params.channels); + if (ret < 0) { + printf("error: file buffer size set\n"); + return ret; + } + buffer_reset_pos(buffer); + + /* set file function */ + cd->file_func = file_s16; + break; + case(SOF_IPC_FRAME_S24_4LE): + ret = buffer_set_size(buffer, dev->frames * 4 * + periods * dev->params.channels); + if (ret < 0) { + fprintf(stderr, "error: file buffer size set\n"); + return ret; + } + buffer_reset_pos(buffer); + + /* set file function */ + cd->file_func = file_s24; + break; + case(SOF_IPC_FRAME_S32_LE): + ret = buffer_set_size(buffer, dev->frames * 4 * + periods * dev->params.channels); + if (ret < 0) { + fprintf(stderr, "error: file buffer size set\n"); + return ret; + } + buffer_reset_pos(buffer); + break; + default: + return -EINVAL; + } + + dev->state = COMP_STATE_PREPARE; + + return ret; +} + +static int file_reset(struct comp_dev *dev) +{ + dev->state = COMP_STATE_INIT; + + return 0; +} + +struct comp_driver comp_file = { + .type = SOF_COMP_FILEREAD, + .ops = { + .new = file_new, + .free = file_free, + .params = file_params, + .cmd = file_cmd, + .trigger = file_trigger, + .copy = file_copy, + .prepare = file_prepare, + .reset = file_reset, + }, +}; + +void sys_comp_file_init(void) +{ + comp_register(&comp_file); +} diff --git a/src/include/host/file.h b/src/include/host/file.h new file mode 100644 index 0000000..777b26d --- /dev/null +++ b/src/include/host/file.h @@ -0,0 +1,77 @@ +/* + * 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * Liam Girdwood liam.r.girdwood@linux.intel.com + * Keyon Jie yang.jie@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ +#ifndef _FILE_H +#define _FILE_H + +/* file component modes */ +enum file_mode { + FILE_READ = 0, + FILE_WRITE, + FILE_DUPLEX, +}; + +enum file_format { + FILE_TEXT = 0, + FILE_RAW, +}; + +/* file component state */ +struct file_state { + char *fn; + FILE *rfh, *wfh; /* read/write file handle */ + int reached_eof; + int n; + enum file_mode mode; + enum file_format f_format; +}; + +/* file comp data */ +struct file_comp_data { + uint32_t period_bytes; + uint32_t channels; + uint32_t frame_bytes; + uint32_t rate; + struct file_state fs; + int (*file_func)(struct comp_dev *dev, struct comp_buffer *sink, + struct comp_buffer *source, uint32_t frames); + +}; + +/* file IO ipc comp */ +struct sof_ipc_comp_file { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; + char *fn; + enum file_mode mode; +}; +#endif
On Thu, 2018-05-31 at 19:29 -0700, Ranjani Sridharan wrote:
This patch adds a new file component that testbench can use to read in samples and write out processed samples. Both text and raw pcm input formats are supported.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com
src/host/file.c | 720 ++++++++++++++++++++++++++++++++++++++++ src/include/host/file.h | 77 +++++ 2 files changed, 797 insertions(+) create mode 100644 src/host/file.c create mode 100644 src/include/host/file.h
diff --git a/src/host/file.c b/src/host/file.c new file mode 100644 index 0000000..f0d420f --- /dev/null +++ b/src/host/file.c @@ -0,0 +1,720 @@ +/*
- 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(s): Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+/* file component for reading/writing pcm samples to/from a file */
+#include <stdio.h> +#include <stdint.h> +#include <stddef.h> +#include <errno.h> +#include <inttypes.h> +#include <sof/sof.h> +#include <sof/lock.h> +#include <sof/list.h> +#include <sof/stream.h> +#include <sof/work.h> +#include <sof/clock.h> +#include <sof/audio/component.h> +#include <sof/audio/format.h> +#include <sof/audio/pipeline.h> +#include <uapi/ipc.h> +#include "host/common_test.h" +#include "host/file.h"
+static inline void buffer_check_wrap_32(int32_t **ptr, int32_t *end,
size_t size)
+{
- if (*ptr >= end)
*ptr = (int32_t *)((size_t)*ptr - size);
+}
+static inline void buffer_check_wrap_16(int16_t **ptr, int16_t *end,
size_t size)
+{
- if (*ptr >= end)
*ptr = (int16_t *)((size_t)*ptr - size);
+}
+/*
- Read 32-bit samples from file
- currently only supports txt files
- */
+static int read_samples_32(struct comp_dev *dev, struct comp_buffer *sink,
int n, int fmt, int nch)
+{
- struct file_comp_data *cd = comp_get_drvdata(dev);
- int32_t *dest = (int32_t *)sink->w_ptr;
- int32_t sample;
- int n_samples = 0;
- int i, n_wrap, n_min, ret;
- while (n > 0) {
n_wrap = (int32_t *)sink->end_addr - dest;
/* check for buffer wrap and copy to the end of the buffer */
n_min = (n < n_wrap) ? n : n_wrap;
while (n_min > 0) {
n -= nch;
n_min -= nch;
/* copy sample per channel */
for (i = 0; i < nch; i++) {
/* read sample from file */
switch (cd->fs.f_format) {
We should really have a reader/write for each type to be optimal.
/* text input file */
case FILE_TEXT:
if (fmt == SOF_IPC_FRAME_S32_LE)
ret = fscanf(cd->fs.rfh,
"%d",
dest);
/* mask bits if 24-bit samples */
if (fmt == SOF_IPC_FRAME_S24_4LE) {
ret = fscanf(cd->fs.rfh,
"%d",
&sample);
*dest = sample & 0x00ffffff;
}
/* quit if eof is reached */
if (ret == EOF) {
cd->fs.reached_eof = 1;
goto quit;
}
break;
/* raw input file */
default:
if (fmt == SOF_IPC_FRAME_S32_LE)
ret = fread(dest,
sizeof(int32_t),
1, cd->fs.rfh);
and freading period at a time is optimal rather than sample by sample.
/* mask bits if 24-bit samples */
if (fmt == SOF_IPC_FRAME_S24_4LE) {
ret = fread(&sample,
sizeof(int32_t),
1, cd->fs.rfh);
*dest = sample & 0x00ffffff;
}
/* quit if eof is reached */
if (ret != 1) {
cd->fs.reached_eof = 1;
goto quit;
}
break;
}
dest++;
n_samples++;
}
}
/* check for buffer wrap and update pointer */
buffer_check_wrap_32(&dest, sink->end_addr,
sink->size);
- }
+quit:
- return n_samples;
+}
+/*
- Read 16-bit samples from file
- currently only supports txt files
- */
+static int read_samples_16(struct comp_dev *dev, struct comp_buffer *sink,
int n, int nch)
+{
- struct file_comp_data *cd = comp_get_drvdata(dev);
- int16_t *dest = (int16_t *)sink->w_ptr;
- int i, n_wrap, n_min, ret;
- int n_samples = 0;
- /* copy samples */
- while (n > 0) {
n_wrap = (int16_t *)sink->end_addr - dest;
/* check for buffer wrap and copy to the end of the buffer */
n_min = (n < n_wrap) ? n : n_wrap;
while (n_min > 0) {
n -= nch;
n_min -= nch;
/* copy sample per channel */
for (i = 0; i < nch; i++) {
/* read sample from file */
ret = fscanf(cd->fs.rfh, "%hd", dest);
switch (cd->fs.f_format) {
/* text input file */
case FILE_TEXT:
ret = fscanf(cd->fs.rfh, "%hd",
dest);
if (ret == EOF) {
cd->fs.reached_eof = 1;
goto quit;
}
break;
/* rw pcm input file */
default:
ret = fread(dest, sizeof(int16_t), 1,
cd->fs.rfh);
if (ret != 1) {
cd->fs.reached_eof = 1;
goto quit;
}
break;
}
dest++;
n_samples++;
}
}
/* check for buffer wrap and update pointer */
buffer_check_wrap_16(&dest, sink->end_addr,
sink->size);
- }
+quit:
- return n_samples;
+}
+/*
- Write 16-bit samples from file
- currently only supports txt files
- */
+static int write_samples_16(struct comp_dev *dev, struct comp_buffer *source,
int n, int nch)
+{
- struct file_comp_data *cd = comp_get_drvdata(dev);
- int16_t *src = (int16_t *)source->r_ptr;
- int i, n_wrap, n_min, ret;
- int n_samples = 0;
- /* copy samples */
- while (n > 0) {
n_wrap = (int16_t *)source->end_addr - src;
/* check for buffer wrap and copy to the end of the buffer */
n_min = (n < n_wrap) ? n : n_wrap;
while (n_min > 0) {
n -= nch;
n_min -= nch;
/* copy sample per channel */
for (i = 0; i < nch; i++) {
switch (cd->fs.f_format) {
/* text output file */
case FILE_TEXT:
ret = fprintf(cd->fs.wfh,
"%d\n", *src);
if (ret < 0)
goto quit;
break;
/* raw pcm output file */
default:
ret = fwrite(src,
sizeof(int16_t),
1, cd->fs.wfh);
if (ret != 1)
goto quit;
break;
}
src++;
n_samples++;
}
}
/* check for buffer wrap and update pointer */
buffer_check_wrap_16(&src, source->end_addr,
source->size);
- }
+quit:
- return n_samples;
+}
+/*
- Write 32-bit samples from file
- currently only supports txt files
- */
+static int write_samples_32(struct comp_dev *dev, struct comp_buffer *source,
int n, int fmt, int nch)
+{
- struct file_comp_data *cd = comp_get_drvdata(dev);
- int32_t *src = (int32_t *)source->r_ptr;
- int i, n_wrap, n_min, ret;
- int n_samples = 0;
- int32_t sample;
- /* copy samples */
- while (n > 0) {
n_wrap = (int32_t *)source->end_addr - src;
/* check for buffer wrap and copy to the end of the buffer */
n_min = (n < n_wrap) ? n : n_wrap;
while (n_min > 0) {
n -= nch;
n_min -= nch;
/* copy sample per channel */
for (i = 0; i < nch; i++) {
switch (cd->fs.f_format) {
/* text output file */
case FILE_TEXT:
if (fmt == SOF_IPC_FRAME_S32_LE)
ret = fprintf(cd->fs.wfh,
"%d\n", *src);
if (fmt == SOF_IPC_FRAME_S24_4LE) {
sample = *src << 8;
ret = fprintf(cd->fs.wfh,
"%d\n",
sample >> 8);
}
if (ret < 0)
goto quit;
break;
/* raw pcm output file */
default:
if (fmt == SOF_IPC_FRAME_S32_LE)
ret = fwrite(src,
sizeof(int32_t),
1, cd->fs.wfh);
if (fmt == SOF_IPC_FRAME_S24_4LE) {
sample = *src << 8;
sample >>= 8;
ret = fwrite(&sample,
sizeof(int32_t),
1, cd->fs.wfh);
}
if (ret != 1)
goto quit;
break;
}
/* increment read pointer */
src++;
/* increment number of samples written */
n_samples++;
}
}
/* check for buffer wrap and update pointer */
buffer_check_wrap_32(&src, source->end_addr,
source->size);
- }
+quit:
- return n_samples;
+}
+/* function for processing 32-bit samples */ +static int file_s32_default(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source, uint32_t frames)
+{
- struct file_comp_data *cd = comp_get_drvdata(dev);
- int nch = dev->params.channels;
- int n_samples = 0;
- switch (cd->fs.mode) {
- case FILE_READ:
/* read samples */
n_samples = read_samples_32(dev, sink, frames * nch,
SOF_IPC_FRAME_S32_LE, nch);
break;
- case FILE_WRITE:
/* write samples */
n_samples = write_samples_32(dev, source, frames * nch,
SOF_IPC_FRAME_S32_LE, nch);
break;
- default:
/* TODO: duplex mode */
break;
- }
- cd->fs.n += n_samples;
- return n_samples;
+}
+/* function for processing 16-bit samples */ +static int file_s16(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source, uint32_t frames)
+{
- struct file_comp_data *cd = comp_get_drvdata(dev);
- int nch = dev->params.channels;
- int n_samples = 0;
- switch (cd->fs.mode) {
- case FILE_READ:
/* read samples */
n_samples = read_samples_16(dev, sink, frames * nch, nch);
break;
- case FILE_WRITE:
/* write samples */
n_samples = write_samples_16(dev, source, frames * nch, nch);
break;
- default:
/* TODO: duplex mode */
break;
- }
- cd->fs.n += n_samples;
- return n_samples;
+}
+/* function for processing 24-bit samples */ +static int file_s24(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source, uint32_t frames)
+{
- struct file_comp_data *cd = comp_get_drvdata(dev);
- int nch = dev->params.channels;
- int n_samples = 0;
- switch (cd->fs.mode) {
- case FILE_READ:
/* read samples */
n_samples = read_samples_32(dev, sink, frames * nch,
SOF_IPC_FRAME_S24_4LE, nch);
break;
- case FILE_WRITE:
/* write samples */
n_samples = write_samples_32(dev, source, frames * nch,
SOF_IPC_FRAME_S24_4LE, nch);
break;
- default:
/* TODO: duplex mode */
break;
- }
- cd->fs.n += n_samples;
- return n_samples;
+}
+static enum file_format get_file_format(char *filename) +{
- char *ext = strrchr(filename, '.');
- if (!strcmp(ext, ".txt"))
return FILE_TEXT;
- return FILE_RAW;
+}
+static struct comp_dev *file_new(struct sof_ipc_comp *comp) +{
- struct comp_dev *dev;
- struct sof_ipc_comp_file *file;
- struct sof_ipc_comp_file *ipc_file =
(struct sof_ipc_comp_file *)comp;
- struct file_comp_data *cd;
- /* allocate memory for file comp */
- dev = malloc(COMP_SIZE(struct sof_ipc_comp_file));
- if (!dev)
return NULL;
- /* copy file comp config */
- file = (struct sof_ipc_comp_file *)&dev->comp;
- memcpy(file, ipc_file, sizeof(struct sof_ipc_comp_file));
- /* allocate memory for file comp data */
- cd = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, sizeof(*cd));
- if (!cd) {
free(dev);
return NULL;
- }
- comp_set_drvdata(dev, cd);
- /* default function for processing samples */
- cd->file_func = file_s32_default;
- /* get filename from IPC and open file */
- cd->fs.fn = strdup(ipc_file->fn);
- /* set file format */
- cd->fs.f_format = get_file_format(cd->fs.fn);
- /* set file comp mode */
- cd->fs.mode = ipc_file->mode;
- /* open file handle(s) depending on mode */
- switch (cd->fs.mode) {
- case FILE_READ:
cd->fs.rfh = fopen(cd->fs.fn, "r");
if (!cd->fs.rfh) {
fprintf(stderr, "error: opening file %s\n", cd-
fs.fn);
free(cd);
free(dev);
return NULL;
}
break;
- case FILE_WRITE:
cd->fs.wfh = fopen(cd->fs.fn, "w");
if (!cd->fs.wfh) {
fprintf(stderr, "error: opening file %s\n", cd-
fs.fn);
free(cd);
free(dev);
return NULL;
}
break;
- default:
/* TODO: duplex mode */
break;
- }
- cd->fs.reached_eof = 0;
- cd->fs.n = 0;
- dev->state = COMP_STATE_READY;
- return dev;
+}
+static void file_free(struct comp_dev *dev) +{
- struct file_comp_data *cd = comp_get_drvdata(dev);
- if (cd->fs.mode == FILE_READ)
fclose(cd->fs.rfh);
- else
fclose(cd->fs.wfh);
- free(cd->fs.fn);
- free(cd);
- free(dev);
- debug_print("free file component\n");
+}
+/* set component audio stream parameters */ +static int file_params(struct comp_dev *dev) +{
- struct file_comp_data *cd = comp_get_drvdata(dev);
- struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
- /* for file endpoint set the following from topology config */
- if (cd->fs.mode == FILE_WRITE) {
dev->params.frame_fmt = config->frame_fmt;
if (dev->params.frame_fmt == SOF_IPC_FRAME_S16_LE)
dev->params.sample_container_bytes = 2;
else
dev->params.sample_container_bytes = 4;
- }
- /* Need to compute this in non-host endpoint */
- dev->frame_bytes =
dev->params.sample_container_bytes * dev->params.channels;
- /* calculate period size based on config */
- cd->period_bytes = dev->frames * dev->frame_bytes;
- /* File to sink supports only S32_LE/S16_LE/S24_4LE PCM formats */
- if (config->frame_fmt != SOF_IPC_FRAME_S32_LE &&
config->frame_fmt != SOF_IPC_FRAME_S24_4LE &&
config->frame_fmt != SOF_IPC_FRAME_S16_LE)
return -EINVAL;
- return 0;
+}
+static int fr_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata) +{
- return -EINVAL;
+}
+static int file_trigger(struct comp_dev *dev, int cmd) +{
- return comp_set_state(dev, cmd);
+}
+/* used to pass standard and bespoke commands (with data) to component */ +static int file_cmd(struct comp_dev *dev, int cmd, void *data) +{
- struct sof_ipc_ctrl_data *cdata = data;
- int ret = 0;
- switch (cmd) {
- case COMP_CMD_SET_DATA:
ret = fr_cmd(dev, cdata);
break;
- default:
break;
- }
- return ret;
+}
+/*
- copy and process stream samples
- returns the number of bytes copied
- */
+static int file_copy(struct comp_dev *dev) +{
- struct comp_buffer *buffer;
- struct file_comp_data *cd = comp_get_drvdata(dev);
- int ret = 0, bytes;
- switch (cd->fs.mode) {
- case FILE_READ:
/* file component sink buffer */
buffer = list_first_item(&dev->bsink_list, struct
comp_buffer,
source_list);
/* test sink has enough free frames */
if (buffer->free >= cd->period_bytes && !cd->fs.reached_eof)
{
/* read PCM samples from file */
ret = cd->file_func(dev, buffer, NULL, dev->frames);
/* update sink buffer pointers */
bytes = dev->params.sample_container_bytes;
if (ret > 0)
comp_update_buffer_produce(buffer,
ret * bytes);
}
break;
- case FILE_WRITE:
/* file component source buffer */
buffer = list_first_item(&dev->bsource_list,
struct comp_buffer, sink_list);
/* test source has enough free frames */
if (buffer->avail >= cd->period_bytes) {
/* write PCM samples into file */
ret = cd->file_func(dev, NULL, buffer, dev->frames);
/* update source buffer pointers */
bytes = dev->params.sample_container_bytes;
if (ret > 0)
comp_update_buffer_consume(buffer,
ret * bytes);
}
break;
- default:
/* TODO: duplex mode */
break;
- }
- return ret;
+}
+static int file_prepare(struct comp_dev *dev) +{
- struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
- struct comp_buffer *buffer = NULL;
- struct file_comp_data *cd = comp_get_drvdata(dev);
- int ret = 0, periods;
- /* file component sink/source buffer period count */
- switch (cd->fs.mode) {
- case FILE_READ:
buffer = list_first_item(&dev->bsink_list, struct
comp_buffer,
source_list);
periods = config->periods_sink;
break;
- case FILE_WRITE:
buffer = list_first_item(&dev->bsource_list,
struct comp_buffer, sink_list);
periods = config->periods_source;
break;
- default:
/* TODO: duplex mode */
break;
- }
- if (!buffer) {
printf("error: no sink/source buffer\n");
return -EINVAL;
- }
- /* set downstream buffer size */
- switch (config->frame_fmt) {
- case(SOF_IPC_FRAME_S16_LE):
ret = buffer_set_size(buffer, dev->frames * 2 *
periods * dev->params.channels);
if (ret < 0) {
printf("error: file buffer size set\n");
return ret;
}
buffer_reset_pos(buffer);
/* set file function */
cd->file_func = file_s16;
break;
- case(SOF_IPC_FRAME_S24_4LE):
ret = buffer_set_size(buffer, dev->frames * 4 *
periods * dev->params.channels);
if (ret < 0) {
fprintf(stderr, "error: file buffer size set\n");
return ret;
}
buffer_reset_pos(buffer);
/* set file function */
cd->file_func = file_s24;
break;
- case(SOF_IPC_FRAME_S32_LE):
ret = buffer_set_size(buffer, dev->frames * 4 *
periods * dev->params.channels);
if (ret < 0) {
fprintf(stderr, "error: file buffer size set\n");
return ret;
}
buffer_reset_pos(buffer);
break;
- default:
return -EINVAL;
- }
- dev->state = COMP_STATE_PREPARE;
- return ret;
+}
+static int file_reset(struct comp_dev *dev) +{
- dev->state = COMP_STATE_INIT;
- return 0;
+}
+struct comp_driver comp_file = {
- .type = SOF_COMP_FILEREAD,
- .ops = {
.new = file_new,
.free = file_free,
.params = file_params,
.cmd = file_cmd,
.trigger = file_trigger,
.copy = file_copy,
.prepare = file_prepare,
.reset = file_reset,
- },
+};
+void sys_comp_file_init(void) +{
- comp_register(&comp_file);
+} diff --git a/src/include/host/file.h b/src/include/host/file.h new file mode 100644 index 0000000..777b26d --- /dev/null +++ b/src/include/host/file.h @@ -0,0 +1,77 @@ +/*
- 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
Liam Girdwood <liam.r.girdwood@linux.intel.com>
Keyon Jie <yang.jie@linux.intel.com>
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+#ifndef _FILE_H +#define _FILE_H
+/* file component modes */ +enum file_mode {
- FILE_READ = 0,
- FILE_WRITE,
- FILE_DUPLEX,
+};
+enum file_format {
- FILE_TEXT = 0,
- FILE_RAW,
+};
+/* file component state */ +struct file_state {
- char *fn;
- FILE *rfh, *wfh; /* read/write file handle */
- int reached_eof;
- int n;
- enum file_mode mode;
- enum file_format f_format;
+};
+/* file comp data */ +struct file_comp_data {
- uint32_t period_bytes;
- uint32_t channels;
- uint32_t frame_bytes;
- uint32_t rate;
- struct file_state fs;
- int (*file_func)(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source, uint32_t frames);
+};
+/* file IO ipc comp */ +struct sof_ipc_comp_file {
- struct sof_ipc_comp comp;
- struct sof_ipc_comp_config config;
- char *fn;
- enum file_mode mode;
+}; +#endif
This patch adds the testbench that parses a test topology file, and sets up the pipeline for processing. It schedules pipeline_copy() for reading samples from an input file, processing them through a pipeline and writing the processed samples to the output file.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- src/host/Makefile.am | 10 ++ src/host/testbench.c | 298 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 src/host/testbench.c
diff --git a/src/host/Makefile.am b/src/host/Makefile.am index a1044a5..f3a3343 100644 --- a/src/host/Makefile.am +++ b/src/host/Makefile.am @@ -7,6 +7,16 @@ AM_CPPFLAGS = -I $(SOF_INC) $(SOF_INCDIR) $(DEFINE) AM_CFLAGS = -g -Wall AM_LDFLAGS = -L$(prefix)/lib
+bin_PROGRAMS = testbench + +testbench_SOURCES = \ + testbench.c + +testbench_LDADD = \ + -ldl -lm -lsof_ipc \ + libtb_common.a \ + -lsof + noinst_LIBRARIES = libtb_common.a
libtb_common_a_SOURCES = \ diff --git a/src/host/testbench.c b/src/host/testbench.c new file mode 100644 index 0000000..86ed7fc --- /dev/null +++ b/src/host/testbench.c @@ -0,0 +1,298 @@ +/* + * 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ + +#include <sof/ipc.h> +#include <sof/list.h> +#include <getopt.h> +#include <dlfcn.h> +#include "host/common_test.h" +#include "host/topology.h" +#include "host/trace.h" +#include "host/file.h" + +#define TESTBENCH_NCH 2 /* Stereo */ + +/* main firmware context */ +static struct sof sof; +static int fr_id; /* comp id for fileread */ +static int fw_id; /* comp id for filewrite */ +static int sched_id; /* comp id for scheduling comp */ + +int debug; + +/* + * Parse shared library from user input + * Currently only handles volume comp + */ +static void parse_libraries(char *libs, void *handle) +{ + char *lib_token, *comp_token; + char *token = strtok_r(libs, ",", &lib_token); + char message[DEBUG_MSG_LEN]; + + while (token) { + char *token1 = strtok_r(token, "=", &comp_token); + + /* parse shared library for volume component */ + if (strcmp(token1, "vol") == 0) { + while (token1) { + token1 = strtok_r(NULL, "=", &comp_token); + if (!token1) + return; + + /* close shared library object */ + if (handle) + dlclose(handle); + + /* open volume shared library object */ + handle = dlopen(token1, RTLD_LAZY); + if (!handle) { + fprintf(stderr, "error: %s\n", + dlerror()); + exit(EXIT_FAILURE); + } + + sprintf(message, "opening vol shared lib %s\n", + token1); + debug_print(message); + } + } + token = strtok_r(NULL, ",", &lib_token); + } +} + +/* print usage for testbench */ +static void print_usage(char *executable) +{ + printf("Usage: %s -i <input_file> -o <output_file> ", executable); + printf("-t <tplg_file> -b <input_format> "); + printf("-a <comp1=comp1_library,comp2=comp2_library>\n"); + printf("input_format should be S16_LE, S32_LE, S24_LE or FLOAT_LE\n"); + printf("Example Usage:\n"); + printf("%s -i in.txt -o out.txt -t test.tplg ", executable); + printf("-b S16_LE -a vol=libsof_volume.so\n"); +} + +/* free components */ +static void free_comps(void) +{ + struct list_item *clist; + struct list_item *temp; + struct ipc_comp_dev *icd = NULL; + + list_for_item_safe(clist, temp, &sof.ipc->comp_list) { + icd = container_of(clist, struct ipc_comp_dev, list); + switch (icd->type) { + case COMP_TYPE_COMPONENT: + comp_free(icd->cd); + list_item_del(&icd->list); + rfree(icd); + break; + case COMP_TYPE_BUFFER: + rfree(icd->cb->addr); + rfree(icd->cb); + list_item_del(&icd->list); + rfree(icd); + break; + default: + rfree(icd->pipeline); + list_item_del(&icd->list); + rfree(icd); + break; + } + } +} + +int main(int argc, char **argv) +{ + struct ipc_comp_dev *pcm_dev; + struct pipeline *p; + struct sof_ipc_pipe_new *ipc_pipe; + struct comp_dev *cd; + struct file_comp_data *frcd, *fwcd; + char *tplg_file = NULL, *input_file = NULL; + char *output_file = NULL, *bits_in = "S32_LE"; + char pipeline[DEBUG_MSG_LEN]; + clock_t tic, toc; + double c_realtime, t_exec; + int fs, n_in, n_out, ret; + int option = 0; + + /* volume component share library handle */ + void *vol_handle = NULL; + + /* TODO: create a shared library table for all components */ + /*set up default volume shared library */ + if (!vol_handle) { + vol_handle = dlopen("libsof_volume.so", RTLD_LAZY); + if (!vol_handle) { + fprintf(stderr, "error: %s\n", dlerror()); + exit(EXIT_FAILURE); + } + } + + /* set up trace class definition table from trace header */ + setup_trace_table(); + + /* command line arguments*/ + while ((option = getopt(argc, argv, "hdi:o:t:b:a:")) != -1) { + switch (option) { + /* input sample file */ + case 'i': + input_file = strdup(optarg); + break; + + /* output sample file */ + case 'o': + output_file = strdup(optarg); + break; + + /* topology file */ + case 't': + tplg_file = strdup(optarg); + break; + + /* input samples bit format */ + case 'b': + bits_in = strdup(optarg); + break; + + /* override default libraries */ + case 'a': + parse_libraries(optarg, vol_handle); + break; + + /* enable debug prints */ + case 'd': + debug = 1; + break; + + /* print usage */ + case 'h': + default: + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + } + + /* check args */ + if (!tplg_file || !input_file || !output_file) { + print_usage(argv[0]); + exit(EXIT_FAILURE); + } + + /* initialize ipc and scheduler */ + if (tb_pipeline_setup(&sof) < 0) { + fprintf(stderr, "error: pipeline init\n"); + exit(EXIT_FAILURE); + } + + /* parse topology file and create pipeline */ + if (parse_topology(tplg_file, &sof, &fr_id, &fw_id, &sched_id, bits_in, + input_file, output_file, vol_handle, pipeline) < 0) { + fprintf(stderr, "error: parsing topology\n"); + exit(EXIT_FAILURE); + } + + /* Get pointers to fileread and filewrite */ + pcm_dev = ipc_get_comp(sof.ipc, fw_id); + fwcd = comp_get_drvdata(pcm_dev->cd); + pcm_dev = ipc_get_comp(sof.ipc, fr_id); + frcd = comp_get_drvdata(pcm_dev->cd); + + /* Run pipeline until EOF from fileread */ + pcm_dev = ipc_get_comp(sof.ipc, sched_id); + p = pcm_dev->cd->pipeline; + ipc_pipe = &p->ipc_pipe; + + fs = ipc_pipe->deadline * ipc_pipe->frames_per_sched; + + /* set pipeline params and trigger start */ + if (tb_pipeline_start(sof.ipc, TESTBENCH_NCH, bits_in, ipc_pipe) < 0) { + fprintf(stderr, "error: pipeline params\n"); + exit(EXIT_FAILURE); + } + + cd = pcm_dev->cd; + tb_enable_trace(false); /* reduce trace output */ + tic = clock(); + + while (frcd->fs.reached_eof == 0) + pipeline_schedule_copy(p, 0); + + if (!frcd->fs.reached_eof) + printf("warning: possible pipeline xrun\n"); + + /* reset and free pipeline */ + toc = clock(); + tb_enable_trace(true); + ret = pipeline_reset(p, cd); + if (ret < 0) { + fprintf(stderr, "error: pipeline reset\n"); + exit(EXIT_FAILURE); + } + + n_in = frcd->fs.n; + n_out = fwcd->fs.n; + t_exec = (double)(toc - tic) / CLOCKS_PER_SEC; + c_realtime = (double)n_out / TESTBENCH_NCH / fs / t_exec; + + /* free all components/buffers in pipeline */ + free_comps(); + + /* free trace class defs */ + free_trace_table(); + + /* print test summary */ + printf("==========================================================\n"); + printf(" Test Summary\n"); + printf("==========================================================\n"); + printf("Test Pipeline:\n"); + printf("%s\n", pipeline); + printf("Input bit format: %s\n", bits_in); + printf("Output written to file: "%s"\n", output_file); + printf("Input sample count: %d\n", n_in); + printf("Output sample count: %d\n", n_out); + printf("Total execution time: %.2f us, %.2f x realtime\n", + 1e3 * t_exec, c_realtime); + + /* free all other data */ + free(bits_in); + free(input_file); + free(tplg_file); + free(output_file); + + /* close shared library object */ + if (vol_handle) + dlclose(vol_handle); + + return EXIT_SUCCESS; +}
On Thu, 2018-05-31 at 19:29 -0700, Ranjani Sridharan wrote:
This patch adds the testbench that parses a test topology file, and sets up the pipeline for processing. It schedules pipeline_copy() for reading samples from an input file, processing them through a pipeline and writing the processed samples to the output file.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com
src/host/Makefile.am | 10 ++ src/host/testbench.c | 298 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 308 insertions(+) create mode 100644 src/host/testbench.c
diff --git a/src/host/Makefile.am b/src/host/Makefile.am index a1044a5..f3a3343 100644 --- a/src/host/Makefile.am +++ b/src/host/Makefile.am @@ -7,6 +7,16 @@ AM_CPPFLAGS = -I $(SOF_INC) $(SOF_INCDIR) $(DEFINE) AM_CFLAGS = -g -Wall AM_LDFLAGS = -L$(prefix)/lib
+bin_PROGRAMS = testbench
+testbench_SOURCES = \
- testbench.c
+testbench_LDADD = \
- -ldl -lm -lsof_ipc \
- libtb_common.a \
- -lsof
noinst_LIBRARIES = libtb_common.a
libtb_common_a_SOURCES = \ diff --git a/src/host/testbench.c b/src/host/testbench.c new file mode 100644 index 0000000..86ed7fc --- /dev/null +++ b/src/host/testbench.c @@ -0,0 +1,298 @@ +/*
- 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: Seppo Ingalsuo seppo.ingalsuo@linux.intel.com
Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
- */
+#include <sof/ipc.h> +#include <sof/list.h> +#include <getopt.h> +#include <dlfcn.h> +#include "host/common_test.h" +#include "host/topology.h" +#include "host/trace.h" +#include "host/file.h"
+#define TESTBENCH_NCH 2 /* Stereo */
+/* main firmware context */ +static struct sof sof; +static int fr_id; /* comp id for fileread */ +static int fw_id; /* comp id for filewrite */ +static int sched_id; /* comp id for scheduling comp */
+int debug;
+/*
- Parse shared library from user input
- Currently only handles volume comp
- */
Can you explain in more detail what this does, i.e. assumptions about libraries and how we parse them.
+static void parse_libraries(char *libs, void *handle) +{
- char *lib_token, *comp_token;
- char *token = strtok_r(libs, ",", &lib_token);
- char message[DEBUG_MSG_LEN];
- while (token) {
char *token1 = strtok_r(token, "=", &comp_token);
/* parse shared library for volume component */
if (strcmp(token1, "vol") == 0) {
while (token1) {
token1 = strtok_r(NULL, "=", &comp_token);
if (!token1)
return;
/* close shared library object */
if (handle)
dlclose(handle);
/* open volume shared library object */
handle = dlopen(token1, RTLD_LAZY);
if (!handle) {
fprintf(stderr, "error: %s\n",
dlerror());
exit(EXIT_FAILURE);
}
sprintf(message, "opening vol shared lib
%s\n",
token1);
debug_print(message);
}
}
token = strtok_r(NULL, ",", &lib_token);
- }
+}
+/* print usage for testbench */ +static void print_usage(char *executable) +{
- printf("Usage: %s -i <input_file> -o <output_file> ", executable);
- printf("-t <tplg_file> -b <input_format> ");
- printf("-a <comp1=comp1_library,comp2=comp2_library>\n");
We should be able to do "-a comp1_lib,comp2_lib,comp3_lib -t etc), the optarg will be a comma separated string.
- printf("input_format should be S16_LE, S32_LE, S24_LE or
FLOAT_LE\n");
- printf("Example Usage:\n");
- printf("%s -i in.txt -o out.txt -t test.tplg ", executable);
- printf("-b S16_LE -a vol=libsof_volume.so\n");
+}
+/* free components */ +static void free_comps(void) +{
- struct list_item *clist;
- struct list_item *temp;
- struct ipc_comp_dev *icd = NULL;
- list_for_item_safe(clist, temp, &sof.ipc->comp_list) {
icd = container_of(clist, struct ipc_comp_dev, list);
switch (icd->type) {
case COMP_TYPE_COMPONENT:
comp_free(icd->cd);
list_item_del(&icd->list);
rfree(icd);
break;
case COMP_TYPE_BUFFER:
rfree(icd->cb->addr);
rfree(icd->cb);
list_item_del(&icd->list);
rfree(icd);
break;
default:
rfree(icd->pipeline);
list_item_del(&icd->list);
rfree(icd);
break;
}
- }
+}
+int main(int argc, char **argv) +{
- struct ipc_comp_dev *pcm_dev;
- struct pipeline *p;
- struct sof_ipc_pipe_new *ipc_pipe;
- struct comp_dev *cd;
- struct file_comp_data *frcd, *fwcd;
- char *tplg_file = NULL, *input_file = NULL;
- char *output_file = NULL, *bits_in = "S32_LE";
- char pipeline[DEBUG_MSG_LEN];
- clock_t tic, toc;
- double c_realtime, t_exec;
- int fs, n_in, n_out, ret;
- int option = 0;
- /* volume component share library handle */
- void *vol_handle = NULL;
- /* TODO: create a shared library table for all components */
- /*set up default volume shared library */
- if (!vol_handle) {
vol_handle = dlopen("libsof_volume.so", RTLD_LAZY);
if (!vol_handle) {
fprintf(stderr, "error: %s\n", dlerror());
exit(EXIT_FAILURE);
}
- }
- /* set up trace class definition table from trace header */
- setup_trace_table();
- /* command line arguments*/
- while ((option = getopt(argc, argv, "hdi:o:t:b:a:")) != -1) {
switch (option) {
/* input sample file */
case 'i':
input_file = strdup(optarg);
break;
/* output sample file */
case 'o':
output_file = strdup(optarg);
break;
/* topology file */
case 't':
tplg_file = strdup(optarg);
break;
/* input samples bit format */
case 'b':
bits_in = strdup(optarg);
break;
/* override default libraries */
case 'a':
parse_libraries(optarg, vol_handle);
break;
/* enable debug prints */
case 'd':
debug = 1;
break;
/* print usage */
case 'h':
default:
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
- }
- /* check args */
- if (!tplg_file || !input_file || !output_file) {
print_usage(argv[0]);
exit(EXIT_FAILURE);
- }
- /* initialize ipc and scheduler */
- if (tb_pipeline_setup(&sof) < 0) {
fprintf(stderr, "error: pipeline init\n");
exit(EXIT_FAILURE);
- }
- /* parse topology file and create pipeline */
- if (parse_topology(tplg_file, &sof, &fr_id, &fw_id, &sched_id,
bits_in,
input_file, output_file, vol_handle, pipeline) <
- {
fprintf(stderr, "error: parsing topology\n");
exit(EXIT_FAILURE);
- }
- /* Get pointers to fileread and filewrite */
- pcm_dev = ipc_get_comp(sof.ipc, fw_id);
- fwcd = comp_get_drvdata(pcm_dev->cd);
- pcm_dev = ipc_get_comp(sof.ipc, fr_id);
- frcd = comp_get_drvdata(pcm_dev->cd);
- /* Run pipeline until EOF from fileread */
- pcm_dev = ipc_get_comp(sof.ipc, sched_id);
- p = pcm_dev->cd->pipeline;
- ipc_pipe = &p->ipc_pipe;
- fs = ipc_pipe->deadline * ipc_pipe->frames_per_sched;
- /* set pipeline params and trigger start */
- if (tb_pipeline_start(sof.ipc, TESTBENCH_NCH, bits_in, ipc_pipe) < 0)
{
fprintf(stderr, "error: pipeline params\n");
exit(EXIT_FAILURE);
- }
- cd = pcm_dev->cd;
- tb_enable_trace(false); /* reduce trace output */
- tic = clock();
- while (frcd->fs.reached_eof == 0)
pipeline_schedule_copy(p, 0);
- if (!frcd->fs.reached_eof)
printf("warning: possible pipeline xrun\n");
- /* reset and free pipeline */
- toc = clock();
- tb_enable_trace(true);
- ret = pipeline_reset(p, cd);
- if (ret < 0) {
fprintf(stderr, "error: pipeline reset\n");
exit(EXIT_FAILURE);
- }
- n_in = frcd->fs.n;
- n_out = fwcd->fs.n;
- t_exec = (double)(toc - tic) / CLOCKS_PER_SEC;
- c_realtime = (double)n_out / TESTBENCH_NCH / fs / t_exec;
- /* free all components/buffers in pipeline */
- free_comps();
- /* free trace class defs */
- free_trace_table();
- /* print test summary */
- printf("==========================================================\n"
);
- printf(" Test Summary\n");
- printf("==========================================================\n"
);
- printf("Test Pipeline:\n");
- printf("%s\n", pipeline);
- printf("Input bit format: %s\n", bits_in);
- printf("Output written to file: "%s"\n", output_file);
- printf("Input sample count: %d\n", n_in);
- printf("Output sample count: %d\n", n_out);
- printf("Total execution time: %.2f us, %.2f x realtime\n",
1e3 * t_exec, c_realtime);
- /* free all other data */
- free(bits_in);
- free(input_file);
- free(tplg_file);
- free(output_file);
- /* close shared library object */
- if (vol_handle)
dlclose(vol_handle);
- return EXIT_SUCCESS;
+}
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- configure.ac | 1 + src/Makefile.am | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac index 49e58a5..3c914a9 100644 --- a/configure.ac +++ b/configure.ac @@ -381,6 +381,7 @@ AC_CONFIG_FILES([ src/library/include/Makefile src/library/include/platform/Makefile src/lib/Makefile + src/host/Makefile src/platform/Makefile src/platform/baytrail/Makefile src/platform/baytrail/include/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 331dd0d..697b32d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,7 @@ export COMMON_INCDIR = \ $(PLATFORM_INCDIR)
if BUILD_LIB -SUBDIRS = ipc math audio arch include library +SUBDIRS = ipc math audio arch include library host endif
if BUILD_XTENSA
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- doc/README.host | 23 +++++++++++++++++++++++ scripts/host-testbench.sh | 25 +++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 doc/README.host create mode 100755 scripts/host-testbench.sh
diff --git a/doc/README.host b/doc/README.host new file mode 100644 index 0000000..30ad583 --- /dev/null +++ b/doc/README.host @@ -0,0 +1,23 @@ +The host testbench is meant to serve as a vehicle to test components for functionality +and quality of processed samples. + +Compilation steps: + +Run the host-build-all.sh to build the required libraries for the testbench. +It should also build the testbench executable. + +Running the Testbench: + +The test can be invoked by running the "testbench" bin in the src/host directory. + +Compile and run using script provided (Recommended): + +Set up the input arguments for the test in +"host-testbench.sh" and invoke it to compile the host libraries +and execute the testbench. + +Known Limitations: + +1. Currently, testbench code supports simple volume topologies only. + +2. When setting up arguments, please keep the same file format for input and output files diff --git a/scripts/host-testbench.sh b/scripts/host-testbench.sh new file mode 100755 index 0000000..fe84af9 --- /dev/null +++ b/scripts/host-testbench.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +#build host library +sudo ./scripts/host-build-all.sh + +#input file +input_file="48000Hz_stereo_16bit.raw" + +#output_file +output_file="out.raw" + +#input bit format +bits_in="S16_LE" + +# topology file +# please use only simple volume topologies for now +topology_file="../sound-open-firmware-tools/topology/test/test-playback-ssp2-I2S-volume-s16le-s32le-48k-24576k-codec.tplg" + +#optional libraries to override +libraries="vol=libsof_volume.so" + +# Use -d to enable debug prints + +# run testbench +./src/host/testbench -i $input_file -o $output_file -b $bits_in -t $topology_file -a $libraries -d
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- doc/README-HOST | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 doc/README-HOST
diff --git a/doc/README-HOST b/doc/README-HOST new file mode 100644 index 0000000..30ad583 --- /dev/null +++ b/doc/README-HOST @@ -0,0 +1,23 @@ +The host testbench is meant to serve as a vehicle to test components for functionality +and quality of processed samples. + +Compilation steps: + +Run the host-build-all.sh to build the required libraries for the testbench. +It should also build the testbench executable. + +Running the Testbench: + +The test can be invoked by running the "testbench" bin in the src/host directory. + +Compile and run using script provided (Recommended): + +Set up the input arguments for the test in +"host-testbench.sh" and invoke it to compile the host libraries +and execute the testbench. + +Known Limitations: + +1. Currently, testbench code supports simple volume topologies only. + +2. When setting up arguments, please keep the same file format for input and output files
On Thu, 2018-05-31 at 19:29 -0700, Ranjani Sridharan wrote:
This set of patches introduces the testbench for audio processing components in SOF. The testbench enables functional/quality testing of SOF components. The testbench reads in audio samples from a file and write out the processed samples to the output file.
The host directory includes common code with routines for topology parsing and setting up sof ipc, scheduler and processing pipelines. It also includes simpler implementations for SOF features such as tracing. It also includes a new file component that allows reading in or writing out samples from/to a file.
The host directory also includes the testbench for setting up pipelines based on a test topology. It reads in input samples from a file , schedules pipeline copy and copies the processed sample to the output file. The output file can be used to perform audio quality tests using matlab/octave. Currently it supports only volume pipelines. Support for other components such as src/eq will be added soon.
Hi All,
These set of patches are RFC again as I have moved the testbench code to be part of the SOF repo instead of the SOFT repo.
Thanks, Ranjani
Ranjani Sridharan (6): host: add host testbench common source and header files host: add new component for file IO host: add testbench program host: include host testbench directory for compilation scripts: add scritps for building host library and invoking the testbench doc: add README for host testbench
configure.ac | 1 + doc/README-HOST | 23 + doc/README.host | 23 + scripts/host-testbench.sh | 25 + src/Makefile.am | 2 +- src/host/Makefile.am | 29 + src/host/alloc.c | 63 +++ src/host/common_test.c | 206 +++++++ src/host/file.c | 720 +++++++++++++++++++++++++ src/host/ipc.c | 81 +++ src/host/schedule.c | 98 ++++ src/host/testbench.c | 298 ++++++++++ src/host/topology.c | 954 +++++++++++++++++++++++++++++++++ src/host/trace.c | 181 +++++++ src/include/host/common_test.h | 65 +++ src/include/host/file.h | 77 +++ src/include/host/topology.h | 202 +++++++ src/include/host/trace.h | 49 ++ 18 files changed, 3096 insertions(+), 1 deletion(-) create mode 100644 doc/README-HOST create mode 100644 doc/README.host create mode 100755 scripts/host-testbench.sh create mode 100644 src/host/Makefile.am create mode 100644 src/host/alloc.c create mode 100644 src/host/common_test.c create mode 100644 src/host/file.c create mode 100644 src/host/ipc.c create mode 100644 src/host/schedule.c create mode 100644 src/host/testbench.c create mode 100644 src/host/topology.c create mode 100644 src/host/trace.c create mode 100644 src/include/host/common_test.h create mode 100644 src/include/host/file.h create mode 100644 src/include/host/topology.h create mode 100644 src/include/host/trace.h
On Thu, 2018-05-31 at 19:29 -0700, Ranjani Sridharan wrote:
This set of patches introduces the testbench for audio processing components in SOF. The testbench enables functional/quality testing of SOF components. The testbench reads in audio samples from a file and write out the processed samples to the output file.
The host directory includes common code with routines for topology parsing and setting up sof ipc, scheduler and processing pipelines. It also includes simpler implementations for SOF features such as tracing. It also includes a new file component that allows reading in or writing out samples from/to a file.
The host directory also includes the testbench for setting up pipelines based on a test topology. It reads in input samples from a file , schedules pipeline copy and copies the processed sample to the output file. The output file can be used to perform audio quality tests using matlab/octave. Currently it supports only volume pipelines. Support for other components such as src/eq will be added soon.
Ranjani Sridharan (6): host: add host testbench common source and header files host: add new component for file IO host: add testbench program host: include host testbench directory for compilation scripts: add scritps for building host library and invoking the testbench doc: add README for host testbench
I've applied so testers can start testing, but have some minor comments that can be fixed incrementally.
Thanks
Liam
On 01.06.2018 10:45, Liam Girdwood wrote:
On Thu, 2018-05-31 at 19:29 -0700, Ranjani Sridharan wrote:
This set of patches introduces the testbench for audio processing components in SOF. The testbench enables functional/quality testing of SOF components. The testbench reads in audio samples from a file and write out the processed samples to the output file.
The host directory includes common code with routines for topology parsing and setting up sof ipc, scheduler and processing pipelines. It also includes simpler implementations for SOF features such as tracing. It also includes a new file component that allows reading in or writing out samples from/to a file.
The host directory also includes the testbench for setting up pipelines based on a test topology. It reads in input samples from a file , schedules pipeline copy and copies the processed sample to the output file. The output file can be used to perform audio quality tests using matlab/octave. Currently it supports only volume pipelines. Support for other components such as src/eq will be added soon.
Ranjani Sridharan (6): host: add host testbench common source and header files host: add new component for file IO host: add testbench program host: include host testbench directory for compilation scripts: add scritps for building host library and invoking the testbench doc: add README for host testbench
I've applied so testers can start testing, but have some minor comments that can be fixed incrementally.
This is good news, thanks Ranjani and Liam!
We will start to prepare patches for audio processing component tests. Should the objective quality checks scripts go to SOFT? The output of those scripts is performance metric that's compared to some default criteria.
We don't have bit exact test vectors for most things so I feel SOFT could be better location for objective quality tests. Simpler bit exact test cases could be kept in SOF since we might in future use those also for optional run-time tests in platform.
Thanks, Seppo
Thanks
Liam _______________________________________________ Sound-open-firmware mailing list Sound-open-firmware@alsa-project.org http://mailman.alsa-project.org/mailman/listinfo/sound-open-firmware
On Fri, 2018-06-01 at 11:39 +0300, Seppo Ingalsuo wrote:
Ranjani Sridharan (6): host: add host testbench common source and header files host: add new component for file IO host: add testbench program host: include host testbench directory for compilation scripts: add scritps for building host library and invoking the testbench doc: add README for host testbench
I've applied so testers can start testing, but have some minor comments that can be fixed incrementally.
This is good news, thanks Ranjani and Liam!
We will start to prepare patches for audio processing component tests. Should the objective quality checks scripts go to SOFT? The output of those scripts is performance metric that's compared to some default criteria.
Yes.
We don't have bit exact test vectors for most things so I feel SOFT could be better location for objective quality tests. Simpler bit exact test cases could be kept in SOF since we might in future use those also for optional run-time tests in platform.
ok.
Liam
On Fri, 2018-06-01 at 08:45 +0100, Liam Girdwood wrote:
On Thu, 2018-05-31 at 19:29 -0700, Ranjani Sridharan wrote:
This set of patches introduces the testbench for audio processing components in SOF. The testbench enables functional/quality testing of SOF components. The testbench reads in audio samples from a file and write out the processed samples to the output file.
The host directory includes common code with routines for topology parsing and setting up sof ipc, scheduler and processing pipelines. It also includes simpler implementations for SOF features such as tracing. It also includes a new file component that allows reading in or writing out samples from/to a file.
The host directory also includes the testbench for setting up pipelines based on a test topology. It reads in input samples from a file , schedules pipeline copy and copies the processed sample to the output file. The output file can be used to perform audio quality tests using matlab/octave. Currently it supports only volume pipelines. Support for other components such as src/eq will be added soon.
Ranjani Sridharan (6): host: add host testbench common source and header files host: add new component for file IO host: add testbench program host: include host testbench directory for compilation scripts: add scritps for building host library and invoking the testbench doc: add README for host testbench
I've applied so testers can start testing, but have some minor comments that can be fixed incrementally.
Thanks, Liam. I will work on the comments and send out the fixes addressing them.
Thanks
Liam
participants (4)
-
Liam Girdwood
-
Liam Girdwood
-
Ranjani Sridharan
-
Seppo Ingalsuo