[Sound-open-firmware] [PATCH v3] Passthrough component added
This patch adds a passthrough component that copies the input stream from the source buffer to the sink buffer. It is meant to serve as a template for creating new components.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- src/audio/Makefile.am | 3 +- src/audio/passthrough.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++ src/include/reef/trace.h | 1 + src/include/uapi/ipc.h | 7 ++ 4 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 src/audio/passthrough.c
diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am index 285422e..c71430c 100644 --- a/src/audio/Makefile.am +++ b/src/audio/Makefile.am @@ -17,7 +17,8 @@ libaudio_a_SOURCES = \ pipeline.c \ pipeline_static.c \ component.c \ - buffer.c + buffer.c \ + passthrough.c
libaudio_a_CFLAGS = \ $(ARCH_CFLAGS) \ diff --git a/src/audio/passthrough.c b/src/audio/passthrough.c new file mode 100644 index 0000000..420d502 --- /dev/null +++ b/src/audio/passthrough.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ + +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> +#include <reef/lock.h> +#include <reef/alloc.h> +#include <reef/list.h> +#include <reef/stream.h> +#include <reef/trace.h> +#include <reef/audio/component.h> +#include <reef/audio/pipeline.h> +#include <uapi/ipc.h> + +/* tracing */ +#define trace_pass(__e) trace_event(TRACE_CLASS_PASS, __e) +#define trace_pass_error(__e) trace_error(TRACE_CLASS_PASS, __e) +#define tracev_pass(__e) tracev_event(TRACE_CLASS_PASS, __e) + +/* The passthrough component, as the name inplies, allows the source buffer + * to pass through the component, without any processing, to the sink buffer. + * It supports 16-bits and 32-bits data formats. + * This code is intended to be used as a template for creating new components. + */ + +/* + * passthrough_comp_data structure: This is private data that cannot be touched + * outside the component. It contains: + * passthrough_func - function that performs the buffer copy + */ +struct passthrough_comp_data { + int (*passthrough_func)(struct comp_dev *dev, struct comp_buffer *sink, + struct comp_buffer *source, uint32_t frames); + +}; + +/* This function performs memcpy of the stream data from the source buffer to + * the sink buffer. It returns the number of frames that were copied. + */ +static int passthrough_function(struct comp_dev *dev, + struct comp_buffer *sink_buffer, + struct comp_buffer *source_buffer, uint32_t frames) +{ + struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev); + int32_t *src = (int32_t *) source_buffer->r_ptr; + int32_t *dest = (int32_t *) sink_buffer->w_ptr; + int nch = dev->params.channels; + + /* copy frames from source to destination */ + switch (config->frame_fmt) { + case SOF_IPC_FRAME_S16_LE: + memcpy(dest, src, frames * nch * sizeof(int16_t)); + break; + case SOF_IPC_FRAME_S32_LE: + case SOF_IPC_FRAME_S24_4LE: + case SOF_IPC_FRAME_FLOAT: + memcpy(dest, src, frames * nch * sizeof(int32_t)); + break; + default: + trace_pass_error("PTp"); + return -EINVAL; + } + + return frames; +} + +/* passthrough_new create the new passthrough component and allocates + * memory for the component and its private data. + * It returns a pointer to struct comp_dev that was created. + */ +static struct comp_dev *passthrough_new(struct sof_ipc_comp *comp) +{ + struct comp_dev *dev; + struct passthrough_comp_data *cd; + + trace_pass("PTn"); + dev = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, + COMP_SIZE(struct sof_ipc_comp_passthrough)); + if (dev == NULL) + return NULL; + + memcpy(&dev->comp, comp, sizeof(struct sof_ipc_comp_passthrough)); + + cd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd)); + if (cd == NULL) { + rfree(dev); + return NULL; + } + + comp_set_drvdata(dev, cd); + cd->passthrough_func = passthrough_function; + + return dev; +} + +/* passthrough_free performs the clean-up */ +static void passthrough_free(struct comp_dev *dev) +{ + struct passthrough_comp_data *cd = comp_get_drvdata(dev); + + rfree(cd); + rfree(dev); +} + +/* passthrough_params sets the component audio stream parameters */ +static int passthrough_params(struct comp_dev *dev) +{ + return 0; +} + +/* passthrough_cmd is used to pass standard and bespoke commands (with data) + * to the component + */ +static int passthrough_cmd(struct comp_dev *dev, int cmd, void *data) +{ + int ret = 0; + + switch (cmd) { + case COMP_CMD_START: + case COMP_CMD_STOP: + case COMP_CMD_PAUSE: + case COMP_CMD_RELEASE: + default: + ret = comp_set_state(dev, cmd); + break; + } + + return ret; +} + +/* passthrough_copy is called when stream data flows through the pipeline + * It calls passthrough_function to copy the source buffer to the sink buffer. + * It returns the number of frames that were copied. + */ +static int passthrough_copy(struct comp_dev *dev) +{ + struct passthrough_comp_data *cd = comp_get_drvdata(dev); + struct comp_buffer *source_buffer = NULL, *sink_buffer = NULL; + uint32_t copy_bytes; + + /* get source and sink buffers */ + source_buffer = list_first_item(&dev->bsource_list, struct comp_buffer, + sink_list); + sink_buffer = list_first_item(&dev->bsink_list, struct comp_buffer, + source_list); + + /* check that source has enough frames available and sink enough + * frames free + */ + copy_bytes = comp_buffer_get_copy_bytes(dev, source_buffer, + sink_buffer); + + if (copy_bytes < dev->params.host_period_bytes) { + trace_pass_error("PTc"); + return -EINVAL; + } + + /* Run passthrough if buffers have enough room */ + cd->passthrough_func(dev, sink_buffer, source_buffer, dev->frames); + + comp_update_buffer_consume(source_buffer, + dev->params.host_period_bytes); + comp_update_buffer_produce(sink_buffer, dev->params.host_period_bytes); + + return dev->frames; +} + +/* passthrough_preload is used for preloading the component buffers before + * pipeline start + */ +static int passthrough_preload(struct comp_dev *dev) +{ + return passthrough_copy(dev); +} + +/* passthrough_reset rests the component state */ +static int passthrough_reset(struct comp_dev *dev) +{ + trace_pass("PTe"); + dev->state = COMP_STATE_INIT; + return 0; +} + +/* passthrough_prepare prepares the component for receiving stream data */ +static int passthrough_prepare(struct comp_dev *dev) +{ + trace_pass("PTl"); + dev->state = COMP_STATE_PREPARE; + return 0; +} + +/* passthrough component driver ops */ +struct comp_driver comp_passthrough = { + .type = SOF_COMP_PASSTHROUGH, + .ops = { + .new = passthrough_new, + .free = passthrough_free, + .params = passthrough_params, + .cmd = passthrough_cmd, + .copy = passthrough_copy, + .prepare = passthrough_prepare, + .reset = passthrough_reset, + .preload = passthrough_preload, + }, +}; + +void sys_comp_passthrough_init(void) +{ + comp_register(&comp_passthrough); +} diff --git a/src/include/reef/trace.h b/src/include/reef/trace.h index 300e8d8..b7ec31a 100644 --- a/src/include/reef/trace.h +++ b/src/include/reef/trace.h @@ -87,6 +87,7 @@ #define TRACE_CLASS_TONE (18 << 24) #define TRACE_CLASS_EQ_FIR (19 << 24) #define TRACE_CLASS_EQ_IIR (20 << 24) +#define TRACE_CLASS_PASS (21 << 24)
/* move to config.h */ #define TRACE 1 diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h index be4c9f2..127ecf1 100644 --- a/src/include/uapi/ipc.h +++ b/src/include/uapi/ipc.h @@ -516,6 +516,7 @@ enum sof_comp_type { SOF_COMP_EQ_FIR, SOF_COMP_FILEREAD, /* host test based file IO */ SOF_COMP_FILEWRITE, /* host test based file IO */ + SOF_COMP_PASSTHROUGH, };
/* XRUN action for component */ @@ -615,6 +616,12 @@ struct sof_ipc_comp_mux { struct sof_ipc_comp_config config; } __attribute__((packed));
+/* generic passthrough component */ +struct sof_ipc_comp_passthrough { + struct sof_ipc_comp comp; + struct sof_ipc_comp_config config; +} __attribute__((packed)); + /* generic tone generator component */ struct sof_ipc_comp_tone { struct sof_ipc_comp comp;
participants (1)
-
Ranjani Sridharan