[Sound-open-firmware] [PATCH v1 1/3] comp: default function to set comp state
This patch adds a the comp_set_state() used for the mandatory pipeline commands, START, STOP, PAUSE and RELEASE. It also updates the cmd method in existing components to use comp_set_state().
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- src/audio/component.c | 36 ++++++++++++++++++++++++++++++++++++ src/audio/eq_fir.c | 23 ++--------------------- src/audio/host.c | 16 ++++------------ src/audio/src.c | 26 +++----------------------- src/audio/tone.c | 26 +++----------------------- src/audio/volume.c | 20 +++----------------- src/include/reef/audio/component.h | 3 +++ 7 files changed, 54 insertions(+), 96 deletions(-)
diff --git a/src/audio/component.c b/src/audio/component.c index 6369e2e..6f2e0c3 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -117,6 +117,42 @@ void comp_unregister(struct comp_driver *drv) spin_unlock(&cd->lock); }
+int comp_set_state(struct comp_dev *dev, int cmd) +{ + int ret = 0; + + switch (cmd) { + case COMP_CMD_START: + case COMP_CMD_RELEASE: + dev->state = COMP_STATE_RUNNING; + break; + case COMP_CMD_STOP: + if (dev->state == COMP_STATE_RUNNING || + dev->state == COMP_STATE_DRAINING || + dev->state == COMP_STATE_PAUSED) { + comp_buffer_reset(dev); + dev->state = COMP_STATE_SETUP; + } else { + trace_comp_error("CEs"); + ret = -EINVAL; + } + break; + case COMP_CMD_PAUSE: + /* only support pausing for running */ + if (dev->state == COMP_STATE_RUNNING) + dev->state = COMP_STATE_PAUSED; + else { + trace_comp_error("CEp"); + ret = -EINVAL; + } + break; + default: + break; + } + + return ret; +} + void sys_comp_init(void) { cd = rzalloc(RZONE_SYS, RFLAGS_NONE, sizeof(*cd)); diff --git a/src/audio/eq_fir.c b/src/audio/eq_fir.c index 534a4a1..6380340 100644 --- a/src/audio/eq_fir.c +++ b/src/audio/eq_fir.c @@ -364,31 +364,12 @@ static int eq_fir_cmd(struct comp_dev *dev, int cmd, void *data)
break; case COMP_CMD_START: - trace_src("EFs"); - dev->state = COMP_STATE_RUNNING; - break; case COMP_CMD_STOP: - trace_src("ESp"); - if (dev->state == COMP_STATE_RUNNING || - dev->state == COMP_STATE_DRAINING || - dev->state == COMP_STATE_PAUSED) { - comp_buffer_reset(dev); - dev->state = COMP_STATE_SETUP; - } - break; case COMP_CMD_PAUSE: - trace_src("EPe"); - /* only support pausing for running */ - if (dev->state == COMP_STATE_RUNNING) - dev->state = COMP_STATE_PAUSED; - - break; case COMP_CMD_RELEASE: - trace_src("ERl"); - dev->state = COMP_STATE_RUNNING; - break; default: - trace_src("EDf"); + ret = comp_set_state(dev, cmd); + break; }
return ret; diff --git a/src/audio/host.c b/src/audio/host.c index e71e95f..f81fd66 100644 --- a/src/audio/host.c +++ b/src/audio/host.c @@ -553,28 +553,20 @@ static int host_cmd(struct comp_dev *dev, int cmd, void *data)
// TODO: align cmd macros. switch (cmd) { - case COMP_CMD_PAUSE: - /* only support pausing for running, channel is paused by DAI */ - if (dev->state == COMP_STATE_RUNNING) - dev->state = COMP_STATE_PAUSED; - break; case COMP_CMD_STOP: if (dev->state == COMP_STATE_RUNNING || dev->state == COMP_STATE_DRAINING || dev->state == COMP_STATE_PAUSED) ret = host_stop(dev); break; - case COMP_CMD_RELEASE: - /* channel is released by DAI */ - dev->state = COMP_STATE_RUNNING; - break; - case COMP_CMD_START: - dev->state = COMP_STATE_RUNNING; - break; case COMP_CMD_SUSPEND: case COMP_CMD_RESUME: break; + case COMP_CMD_START: + case COMP_CMD_PAUSE: + case COMP_CMD_RELEASE: default: + ret = comp_set_state(dev, cmd); break; }
diff --git a/src/audio/src.c b/src/audio/src.c index 0279841..0ecb48c 100644 --- a/src/audio/src.c +++ b/src/audio/src.c @@ -381,7 +381,7 @@ static int src_cmd(struct comp_dev *dev, int cmd, void *data) { trace_src("SCm"); struct comp_data *cd = comp_get_drvdata(dev); - int i; + int i, ret = 0;
switch (cmd) { case COMP_CMD_SRC: @@ -400,35 +400,15 @@ static int src_cmd(struct comp_dev *dev, int cmd, void *data)
break; case COMP_CMD_START: - trace_src("SSt"); - dev->state = COMP_STATE_RUNNING; - break; case COMP_CMD_STOP: - trace_src("SSp"); - if (dev->state == COMP_STATE_RUNNING || - dev->state == COMP_STATE_DRAINING || - dev->state == COMP_STATE_PAUSED) { - comp_buffer_reset(dev); - dev->state = COMP_STATE_SETUP; - } - break; case COMP_CMD_PAUSE: - trace_src("SPe"); - /* only support pausing for running */ - if (dev->state == COMP_STATE_RUNNING) - dev->state = COMP_STATE_PAUSED; - - break; case COMP_CMD_RELEASE: - trace_src("SRl"); - dev->state = COMP_STATE_RUNNING; - break; default: - trace_src("SDf"); + ret = comp_set_state(dev, cmd); break; }
- return 0; + return ret; }
/* copy and process stream data from source to sink buffers */ diff --git a/src/audio/tone.c b/src/audio/tone.c index cbc50ac..305563e 100644 --- a/src/audio/tone.c +++ b/src/audio/tone.c @@ -433,6 +433,7 @@ static int tone_cmd(struct comp_dev *dev, int cmd, void *data) { struct comp_data *cd = comp_get_drvdata(dev); struct sof_ipc_comp_tone *ct; + int ret = 0;
trace_tone("tri");
@@ -456,36 +457,15 @@ static int tone_cmd(struct comp_dev *dev, int cmd, void *data) tonegen_unmute(&cd->sg); break; case COMP_CMD_START: - trace_tone("TSt"); - dev->state = COMP_STATE_RUNNING; - break; case COMP_CMD_STOP: - trace_tone("TSp"); - if (dev->state == COMP_STATE_RUNNING || - dev->state == COMP_STATE_DRAINING || - dev->state == COMP_STATE_PAUSED) { - comp_buffer_reset(dev); - dev->state = COMP_STATE_SETUP; - } - break; case COMP_CMD_PAUSE: - trace_tone("TPe"); - /* only support pausing for running */ - if (dev->state == COMP_STATE_RUNNING) - dev->state = COMP_STATE_PAUSED; - - break; case COMP_CMD_RELEASE: - trace_tone("TRl"); - dev->state = COMP_STATE_RUNNING; - break; default: - trace_tone("TDf"); - + ret = comp_set_state(dev, cmd); break; }
- return 0; + return ret; }
/* copy and process stream data from source to sink buffers */ diff --git a/src/audio/volume.c b/src/audio/volume.c index 93a3839..2e097d5 100644 --- a/src/audio/volume.c +++ b/src/audio/volume.c @@ -385,7 +385,7 @@ static int volume_cmd(struct comp_dev *dev, int cmd, void *data) { struct comp_data *cd = comp_get_drvdata(dev); struct sof_ipc_ctrl_values *cv; - int i, j; + int i, j, ret = 0;
trace_volume("cmd");
@@ -425,29 +425,15 @@ static int volume_cmd(struct comp_dev *dev, int cmd, void *data) work_schedule_default(&cd->volwork, VOL_RAMP_US); break; case COMP_CMD_START: - dev->state = COMP_STATE_RUNNING; - break; case COMP_CMD_STOP: - if (dev->state == COMP_STATE_RUNNING || - dev->state == COMP_STATE_DRAINING || - dev->state == COMP_STATE_PAUSED) { - comp_buffer_reset(dev); - dev->state = COMP_STATE_SETUP; - } - break; case COMP_CMD_PAUSE: - /* only support pausing for running */ - if (dev->state == COMP_STATE_RUNNING) - dev->state = COMP_STATE_PAUSED; - break; case COMP_CMD_RELEASE: - dev->state = COMP_STATE_RUNNING; - break; default: + ret = comp_set_state(dev, cmd); break; }
- return 0; + return ret; }
/* copy and process stream data from source to sink buffers */ diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h index e73a22a..cbd2356 100644 --- a/src/include/reef/audio/component.h +++ b/src/include/reef/audio/component.h @@ -215,6 +215,9 @@ static inline void comp_free(struct comp_dev *dev) dev->drv->ops.free(dev); }
+/* component state set */ +int comp_set_state(struct comp_dev *dev, int cmd); + /* component parameter init - mandatory */ static inline int comp_params(struct comp_dev *dev) {
This patch adds a 1:N or N:1 MUX/DEMUX component. Only one source and one sink buffer can be active at run-time. The MUX component is configured using the COMP_CMD_MUX_SWITCH command passed along with the chosen source and sink buffer configuration. It performs no processing on the input samples, but simply copies the input frames from the source to the sink buffer.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com --- src/audio/mux.c | 275 +++++++++++++++++++++++++++++++++++-- src/include/reef/audio/Makefile.am | 3 +- src/include/reef/audio/component.h | 2 + src/include/reef/audio/mux.h | 46 +++++++ src/include/uapi/ipc.h | 5 + 5 files changed, 322 insertions(+), 9 deletions(-) create mode 100644 src/include/reef/audio/mux.h
diff --git a/src/audio/mux.c b/src/audio/mux.c index f420bd3..ce10da8 100644 --- a/src/audio/mux.c +++ b/src/audio/mux.c @@ -26,35 +26,184 @@ * POSSIBILITY OF SUCH DAMAGE. * * Author: Liam Girdwood liam.r.girdwood@linux.intel.com + * 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/mux.h> +#include <reef/audio/pipeline.h> +#include <uapi/ipc.h>
/* tracing */ -#define trace_mux(__e) trace_event(TRACE_CLASS_MUX, __e) +#define trace_mux(__e) trace_event(TRACE_CLASS_MUX, __e) #define trace_mux_error(__e) trace_error(TRACE_CLASS_MUX, __e) #define tracev_mux(__e) tracev_event(TRACE_CLASS_MUX, __e)
+/* + * mux_comp_data structure + * num_src_buffer - number of source buffers + * num_sink_buffer - number of sink buffers + * config - current configuration of the MUX component + * mux_func - function that performs the routing of input buffer to + * the output buffer based on config + */ +struct mux_comp_data { + uint32_t num_src_buffer, num_sink_buffer; + struct mux_config *config; + int (*mux_func)(struct comp_dev *dev, struct comp_buffer *sink, + struct comp_buffer *source, uint32_t frames); + +}; + +/* mux function to copy data from source to sink buffer */ +static int mux_function(struct comp_dev *dev, struct comp_buffer *sink_buffer, + struct comp_buffer *source_buffer, uint32_t frames) +{ + int32_t *src = (int32_t *) source_buffer->r_ptr; + int32_t *dest = (int32_t *) sink_buffer->w_ptr; + int nch = dev->params.channels; + struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev); + int ret = 0; + + /* 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: + default: + memcpy(dest, src, frames * nch * sizeof(int32_t)); + break; + } + + return ret; +} + static struct comp_dev *mux_new(struct sof_ipc_comp *comp) { - trace_mux("new"); + struct comp_dev *dev; + struct mux_comp_data *cd; + + trace_mux("MUn"); + dev = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, + COMP_SIZE(struct sof_ipc_comp_mux)); + if (dev == NULL) + return NULL; + + memcpy(&dev->comp, comp, sizeof(struct sof_ipc_comp_mux)); + + cd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd)); + if (cd == NULL) { + rfree(dev); + return NULL; + } + + cd->config = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, + sizeof(struct mux_config)); + if (cd == NULL) { + rfree(dev); + rfree(cd); + return NULL; + }
- return NULL; + comp_set_drvdata(dev, cd); + cd->mux_func = mux_function; + + return dev; }
static void mux_free(struct comp_dev *dev) { + struct mux_comp_data *cd = comp_get_drvdata(dev);
+ rfree(cd->config); + rfree(cd); + rfree(dev); }
-/* set component audio stream paramters */ +/* set component audio stream parameters */ static int mux_params(struct comp_dev *dev) { + return 0; +} + +/* set new mux component configuration + * updates the connection status of sink/source buffers + */ +static int mux_switch_config(struct comp_dev *dev, + struct mux_config *new_config) +{ + struct mux_comp_data *cd = comp_get_drvdata(dev); + struct comp_buffer *source_buffer, *sink_buffer; + struct list_item *clist; + int i = 0; + + if ((new_config->in_buffer > cd->num_src_buffer) || + (new_config->out_buffer > cd->num_sink_buffer)) { + trace_mux_error("MUb"); + return -EINVAL; + } + + cd->config->in_buffer = new_config->in_buffer; + cd->config->out_buffer = new_config->out_buffer; + + /* connect new MUX source buffer and disconnect the rest */ + list_for_item_prev(clist, &dev->bsource_list) { + source_buffer = container_of(clist, struct comp_buffer, + sink_list); + if (i == cd->config->in_buffer) + source_buffer->connected = 1; + else + source_buffer->connected = 0; + i++; + } + + i = 0; + /* connect new MUX sink buffer and disconnect the rest */ + list_for_item_prev(clist, &dev->bsink_list) { + sink_buffer = container_of(clist, struct comp_buffer, + source_list); + if (i == cd->config->out_buffer) + sink_buffer->connected = 1; + else + sink_buffer->connected = 0; + i++; + } + + return 0; +} + +/* set the number of input and output buffers connected at pipeline setup */ +static int set_buffer_count(struct comp_dev *dev) +{ + struct list_item *clist; + struct mux_comp_data *cd = comp_get_drvdata(dev); + int count = 0; + + if (list_is_empty(&dev->bsource_list) || + list_is_empty(&dev->bsink_list)) { + trace_mux_error("Mbc"); + return -EINVAL; + } + + list_for_item(clist, &dev->bsource_list) + count++; + cd->num_src_buffer = count - 1; + + count = 0; + list_for_item(clist, &dev->bsink_list) + count++; + cd->num_sink_buffer = count - 1;
return 0; } @@ -62,25 +211,134 @@ static int mux_params(struct comp_dev *dev) /* used to pass standard and bespoke commands (with data) to component */ static int mux_cmd(struct comp_dev *dev, int cmd, void *data) { - /* mux will use buffer "connected" status */ - return 0; + struct sof_ipc_mux_switch *assign; + struct mux_config *new_config; + int ret = 0; + + switch (cmd) { + case COMP_CMD_MUX_SWITCH: + /* switch config only if pipeline has been stopped or paused*/ + if (dev->state == COMP_STATE_SETUP || + dev->state == COMP_STATE_PAUSED) { + assign = (struct sof_ipc_mux_switch *) data; + new_config = (struct mux_config *) assign->data; + ret = mux_switch_config(dev, new_config); + if (ret < 0) + trace_mux_error("Mec"); + } else { + trace_mux_error("Mes"); + ret = -EINVAL; + } + break; + 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; }
/* copy and process stream data from source to sink buffers */ static int mux_copy(struct comp_dev *dev) { + struct mux_comp_data *cd = comp_get_drvdata(dev); + struct comp_buffer *source_buffer = NULL, *sink_buffer = NULL; + int i = 0; + uint32_t copy_bytes; + struct list_item *clist; + + /* check if the selected source buffer is connected */ + list_for_item_prev(clist, &dev->bsource_list) { + if (i == cd->config->in_buffer) { + source_buffer = container_of(clist, struct comp_buffer, + sink_list); + if (source_buffer->connected == 1) + goto sink; + else { + trace_mux_error("Msc"); + return -EINVAL; + } + } + i++; + } + +sink: + i = 0; + /* check if the selected sink buffer is connected */ + list_for_item_prev(clist, &dev->bsink_list) { + if (i == cd->config->out_buffer) { + sink_buffer = container_of(clist, struct comp_buffer, + source_list); + if (sink_buffer->connected == 1) + goto copy; + else { + trace_mux_error("Msb"); + return -EINVAL; + } + } + i++; + } + +copy: + if (!source_buffer || !sink_buffer) { + trace_mux_error("Mbn"); + return -EINVAL; + } + + /* 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->frames * dev->frame_bytes) + return -EINVAL; + + /* Run passthrough if buffers have enough room */ + cd->mux_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 0; }
+static int mux_preload(struct comp_dev *dev) +{ + return mux_copy(dev); +} + +static int mux_default_config(struct comp_dev *dev) +{ + struct mux_config config = {0, 0}; + int ret = 0; + + ret = set_buffer_count(dev); + if (ret < 0) + return -EINVAL; + + ret = mux_switch_config(dev, &config); + + return ret; +} + static int mux_reset(struct comp_dev *dev) { - return 0; + trace_mux("MUr"); + dev->state = COMP_STATE_INIT; + return mux_default_config(dev); }
static int mux_prepare(struct comp_dev *dev) { - return 0; + trace_mux("MUp"); + dev->state = COMP_STATE_PREPARE; + return mux_default_config(dev); }
struct comp_driver comp_mux = { @@ -93,6 +351,7 @@ struct comp_driver comp_mux = { .copy = mux_copy, .prepare = mux_prepare, .reset = mux_reset, + .preload = mux_preload, }, };
diff --git a/src/include/reef/audio/Makefile.am b/src/include/reef/audio/Makefile.am index b02684c..509a34a 100644 --- a/src/include/reef/audio/Makefile.am +++ b/src/include/reef/audio/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ component.h \ pipeline.h \ - buffer.h + buffer.h \ + mux.h diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h index cbd2356..47dd7e8 100644 --- a/src/include/reef/audio/component.h +++ b/src/include/reef/audio/component.h @@ -82,6 +82,8 @@ #define COMP_CMD_EQ_IIR_CONFIG 109 /* Configuration data for IIR EQ */ #define COMP_CMD_EQ_IIR_SWITCH 110 /* Response update request for IIR EQ */
+#define COMP_CMD_MUX_SWITCH 111 /* MUX switch config */ + /* MMAP IPC status */ #define COMP_CMD_IPC_MMAP_RPOS 200 /* host read position */ #define COMP_CMD_IPC_MMAP_PPOS 201 /* DAI presentation position */ diff --git a/src/include/reef/audio/mux.h b/src/include/reef/audio/mux.h new file mode 100644 index 0000000..a765a6a --- /dev/null +++ b/src/include/reef/audio/mux.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Ranjani Sridharan ranjani.sridharan@linux.intel.com + */ + +#ifndef SOF_COMP_MUX_H +#define SOF_COMP_MUX_H + +/* + * mux_config data structure + * in_buffer - ID of input buffer connected to the MUX component + * out_buffer - ID of output buffer connected to the MUX component + */ + +struct mux_config { + uint32_t in_buffer, out_buffer; +}; + + + +#endif diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h index 053390c..e0d0303 100644 --- a/src/include/uapi/ipc.h +++ b/src/include/uapi/ipc.h @@ -622,6 +622,11 @@ struct sof_ipc_eq_iir_switch { int32_t data[]; } __attribute__((packed));
+struct sof_ipc_mux_switch { + struct sof_ipc_comp comp; + uint32_t data[]; +} __attribute__((packed)); + /* frees components, buffers and pipelines * SOF_IPC_TPLG_COMP_FREE, SOF_IPC_TPLG_PIPE_FREE, SOF_IPC_TPLG_BUFFER_FREE */
On Mon, 2017-09-04 at 14:35 +0100, Ranjani Sridharan wrote:
This patch adds a 1:N or N:1 MUX/DEMUX component. Only one source and one sink buffer can be active at run-time. The MUX component is configured using the COMP_CMD_MUX_SWITCH command passed along with the chosen source and sink buffer configuration. It performs no processing on the input samples, but simply copies the input frames from the source to the sink buffer.
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com
src/audio/mux.c | 275 +++++++++++++++++++++++++++++++++++-- src/include/reef/audio/Makefile.am | 3 +- src/include/reef/audio/component.h | 2 + src/include/reef/audio/mux.h | 46 +++++++ src/include/uapi/ipc.h | 5 + 5 files changed, 322 insertions(+), 9 deletions(-) create mode 100644 src/include/reef/audio/mux.h
diff --git a/src/audio/mux.c b/src/audio/mux.c index f420bd3..ce10da8 100644 --- a/src/audio/mux.c +++ b/src/audio/mux.c @@ -26,35 +26,184 @@
- POSSIBILITY OF SUCH DAMAGE.
- Author: Liam Girdwood liam.r.girdwood@linux.intel.com
*/
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/mux.h> +#include <reef/audio/pipeline.h> +#include <uapi/ipc.h>
/* tracing */ -#define trace_mux(__e) trace_event(TRACE_CLASS_MUX, __e) +#define trace_mux(__e) trace_event(TRACE_CLASS_MUX, __e) #define trace_mux_error(__e) trace_error(TRACE_CLASS_MUX, __e) #define tracev_mux(__e) tracev_event(TRACE_CLASS_MUX, __e)
+/*
- mux_comp_data structure
- num_src_buffer - number of source buffers
- num_sink_buffer - number of sink buffers
- config - current configuration of the MUX component
- mux_func - function that performs the routing of input buffer to
the output buffer based on config
- */
+struct mux_comp_data {
- uint32_t num_src_buffer, num_sink_buffer;
- struct mux_config *config;
- int (*mux_func)(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source, uint32_t frames);
+};
+/* mux function to copy data from source to sink buffer */ +static int mux_function(struct comp_dev *dev, struct comp_buffer *sink_buffer,
- struct comp_buffer *source_buffer, uint32_t frames)
+{
- int32_t *src = (int32_t *) source_buffer->r_ptr;
- int32_t *dest = (int32_t *) sink_buffer->w_ptr;
- int nch = dev->params.channels;
- struct sof_ipc_comp_config *config = COMP_GET_CONFIG(dev);
- int ret = 0;
- /* 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 should be here.
- default:
fail here and return error.
memcpy(dest, src, frames * nch * sizeof(int32_t));
break;
- }
- return ret;
+}
static struct comp_dev *mux_new(struct sof_ipc_comp *comp) {
- trace_mux("new");
- struct comp_dev *dev;
- struct mux_comp_data *cd;
- trace_mux("MUn");
- dev = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
COMP_SIZE(struct sof_ipc_comp_mux));
- if (dev == NULL)
return NULL;
- memcpy(&dev->comp, comp, sizeof(struct sof_ipc_comp_mux));
- cd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
- if (cd == NULL) {
rfree(dev);
return NULL;
- }
- cd->config = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
sizeof(struct mux_config));
- if (cd == NULL) {
rfree(dev);
rfree(cd);
return NULL;
- }
- return NULL;
- comp_set_drvdata(dev, cd);
- cd->mux_func = mux_function;
- return dev;
}
static void mux_free(struct comp_dev *dev) {
struct mux_comp_data *cd = comp_get_drvdata(dev);
rfree(cd->config);
rfree(cd);
rfree(dev);
}
-/* set component audio stream paramters */ +/* set component audio stream parameters */ static int mux_params(struct comp_dev *dev) {
- return 0;
+}
+/* set new mux component configuration
- updates the connection status of sink/source buffers
- */
+static int mux_switch_config(struct comp_dev *dev,
- struct mux_config *new_config)
+{
- struct mux_comp_data *cd = comp_get_drvdata(dev);
- struct comp_buffer *source_buffer, *sink_buffer;
- struct list_item *clist;
- int i = 0;
- if ((new_config->in_buffer > cd->num_src_buffer) ||
(new_config->out_buffer > cd->num_sink_buffer)) {
trace_mux_error("MUb");
return -EINVAL;
- }
- cd->config->in_buffer = new_config->in_buffer;
- cd->config->out_buffer = new_config->out_buffer;
- /* connect new MUX source buffer and disconnect the rest */
- list_for_item_prev(clist, &dev->bsource_list) {
source_buffer = container_of(clist, struct comp_buffer,
sink_list);
if (i == cd->config->in_buffer)
source_buffer->connected = 1;
else
source_buffer->connected = 0;
i++;
- }
- i = 0;
- /* connect new MUX sink buffer and disconnect the rest */
- list_for_item_prev(clist, &dev->bsink_list) {
sink_buffer = container_of(clist, struct comp_buffer,
source_list);
if (i == cd->config->out_buffer)
sink_buffer->connected = 1;
else
sink_buffer->connected = 0;
i++;
- }
- return 0;
+}
+/* set the number of input and output buffers connected at pipeline setup */ +static int set_buffer_count(struct comp_dev *dev) +{
- struct list_item *clist;
- struct mux_comp_data *cd = comp_get_drvdata(dev);
- int count = 0;
- if (list_is_empty(&dev->bsource_list) ||
list_is_empty(&dev->bsink_list)) {
trace_mux_error("Mbc");
return -EINVAL;
- }
- list_for_item(clist, &dev->bsource_list)
count++;
- cd->num_src_buffer = count - 1;
why do we subtract 1 ?
count = 0;
list_for_item(clist, &dev->bsink_list)
count++;
cd->num_sink_buffer = count - 1;
return 0;
} @@ -62,25 +211,134 @@ static int mux_params(struct comp_dev *dev) /* used to pass standard and bespoke commands (with data) to component */ static int mux_cmd(struct comp_dev *dev, int cmd, void *data) {
- /* mux will use buffer "connected" status */
- return 0;
- struct sof_ipc_mux_switch *assign;
- struct mux_config *new_config;
- int ret = 0;
- switch (cmd) {
- case COMP_CMD_MUX_SWITCH:
/* switch config only if pipeline has been stopped or paused*/
Switch can happen at any time.
if (dev->state == COMP_STATE_SETUP ||
dev->state == COMP_STATE_PAUSED) {
assign = (struct sof_ipc_mux_switch *) data;
new_config = (struct mux_config *) assign->data;
ret = mux_switch_config(dev, new_config);
if (ret < 0)
trace_mux_error("Mec");
} else {
trace_mux_error("Mes");
ret = -EINVAL;
}
break;
- 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;
}
/* copy and process stream data from source to sink buffers */ static int mux_copy(struct comp_dev *dev) {
- struct mux_comp_data *cd = comp_get_drvdata(dev);
- struct comp_buffer *source_buffer = NULL, *sink_buffer = NULL;
- int i = 0;
- uint32_t copy_bytes;
- struct list_item *clist;
- /* check if the selected source buffer is connected */
better to have a flag here that indicates a config change and we can then do the look up only when config changes instead of at every copy.
- list_for_item_prev(clist, &dev->bsource_list) {
if (i == cd->config->in_buffer) {
source_buffer = container_of(clist, struct comp_buffer,
sink_list);
if (source_buffer->connected == 1)
goto sink;
else {
trace_mux_error("Msc");
return -EINVAL;
}
}
i++;
- }
+sink:
- i = 0;
- /* check if the selected sink buffer is connected */
- list_for_item_prev(clist, &dev->bsink_list) {
if (i == cd->config->out_buffer) {
sink_buffer = container_of(clist, struct comp_buffer,
source_list);
if (sink_buffer->connected == 1)
goto copy;
else {
trace_mux_error("Msb");
return -EINVAL;
}
}
i++;
- }
+copy:
- if (!source_buffer || !sink_buffer) {
trace_mux_error("Mbn");
return -EINVAL;
- }
- /* 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->frames * dev->frame_bytes)
trace some error here
return -EINVAL;
/* Run passthrough if buffers have enough room */
cd->mux_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 0;
return frames copied.
}
+static int mux_preload(struct comp_dev *dev) +{
- return mux_copy(dev);
+}
+static int mux_default_config(struct comp_dev *dev) +{
- struct mux_config config = {0, 0};
- int ret = 0;
- ret = set_buffer_count(dev);
- if (ret < 0)
return -EINVAL;
- ret = mux_switch_config(dev, &config);
- return ret;
+}
static int mux_reset(struct comp_dev *dev) {
- return 0;
- trace_mux("MUr");
- dev->state = COMP_STATE_INIT;
- return mux_default_config(dev);
}
static int mux_prepare(struct comp_dev *dev) {
- return 0;
- trace_mux("MUp");
- dev->state = COMP_STATE_PREPARE;
- return mux_default_config(dev);
}
struct comp_driver comp_mux = { @@ -93,6 +351,7 @@ struct comp_driver comp_mux = { .copy = mux_copy, .prepare = mux_prepare, .reset = mux_reset,
},.preload = mux_preload,
};
diff --git a/src/include/reef/audio/Makefile.am b/src/include/reef/audio/Makefile.am index b02684c..509a34a 100644 --- a/src/include/reef/audio/Makefile.am +++ b/src/include/reef/audio/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ component.h \ pipeline.h \
- buffer.h
- buffer.h \
- mux.h
diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h index cbd2356..47dd7e8 100644 --- a/src/include/reef/audio/component.h +++ b/src/include/reef/audio/component.h @@ -82,6 +82,8 @@ #define COMP_CMD_EQ_IIR_CONFIG 109 /* Configuration data for IIR EQ */ #define COMP_CMD_EQ_IIR_SWITCH 110 /* Response update request for IIR EQ */
+#define COMP_CMD_MUX_SWITCH 111 /* MUX switch config */
This should be using the ROUTE cmd, and also using the new generic value data structure sof_ipc_ctrl_data using type sof_ipc_ctrl_value_comp. You will only need array size (of type sof_ipc_ctrl_value_comp) of 1 for mux (the value indicates the target component index).
/* MMAP IPC status */ #define COMP_CMD_IPC_MMAP_RPOS 200 /* host read position */ #define COMP_CMD_IPC_MMAP_PPOS 201 /* DAI presentation position */ diff --git a/src/include/reef/audio/mux.h b/src/include/reef/audio/mux.h new file mode 100644 index 0000000..a765a6a --- /dev/null +++ b/src/include/reef/audio/mux.h @@ -0,0 +1,46 @@ +/*
- Copyright (c) 2017, Intel Corporation
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Intel Corporation nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
- Author: Ranjani Sridharan ranjani.sridharan@linux.intel.com
- */
+#ifndef SOF_COMP_MUX_H +#define SOF_COMP_MUX_H
+/*
- mux_config data structure
- in_buffer - ID of input buffer connected to the MUX component
- out_buffer - ID of output buffer connected to the MUX component
- */
+struct mux_config {
- uint32_t in_buffer, out_buffer;
+};
+#endif diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h index 053390c..e0d0303 100644 --- a/src/include/uapi/ipc.h +++ b/src/include/uapi/ipc.h @@ -622,6 +622,11 @@ struct sof_ipc_eq_iir_switch { int32_t data[]; } __attribute__((packed));
+struct sof_ipc_mux_switch {
- struct sof_ipc_comp comp;
- uint32_t data[];
+} __attribute__((packed));
/* frees components, buffers and pipelines
- SOF_IPC_TPLG_COMP_FREE, SOF_IPC_TPLG_PIPE_FREE, SOF_IPC_TPLG_BUFFER_FREE
*/
--------------------------------------------------------------------- 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 passthrough component that copies the input sample 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 | 216 +++++++++++++++++++++++++++++++++++++++++++++++ src/include/reef/trace.h | 1 + src/include/uapi/ipc.h | 7 ++ 4 files changed, 226 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..1056a03 --- /dev/null +++ b/src/audio/passthrough.c @@ -0,0 +1,216 @@ +/* + * 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) + +/* + * passthrough_comp_data structure + * passthrough_func - function that performs the routing of input buffer + * to the output buffer based on config + */ +struct passthrough_comp_data { + int (*passthrough_func)(struct comp_dev *dev, struct comp_buffer *sink, + struct comp_buffer *source, uint32_t frames); + +}; + +/* passthrough function to copy data from source to sink buffer */ +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; + int ret = 0; + + /* 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"); + ret = -EINVAL; + break; + } + + return ret; +} + +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; +} + +static void passthrough_free(struct comp_dev *dev) +{ + struct passthrough_comp_data *cd = comp_get_drvdata(dev); + + rfree(cd); + rfree(dev); +} + +/* set component audio stream parameters */ +static int passthrough_params(struct comp_dev *dev) +{ + return 0; +} + +/* used to pass standard and bespoke commands (with data) to 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; +} + +/* copy and process stream data from source to sink buffers */ +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->frames * dev->frame_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 0; +} + +static int passthrough_preload(struct comp_dev *dev) +{ + return passthrough_copy(dev); +} + +static int passthrough_reset(struct comp_dev *dev) +{ + trace_pass("PTe"); + dev->state = COMP_STATE_INIT; + return 0; +} + +static int passthrough_prepare(struct comp_dev *dev) +{ + trace_pass("PTl"); + dev->state = COMP_STATE_PREPARE; + return 0; +} + +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 e0d0303..cb79e26 100644 --- a/src/include/uapi/ipc.h +++ b/src/include/uapi/ipc.h @@ -474,6 +474,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 */ @@ -573,6 +574,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;
On Mon, 2017-09-04 at 14:35 +0100, Ranjani Sridharan wrote:
This patch adds a passthrough component that copies the input sample 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 | 216 +++++++++++++++++++++++++++++++++++++++++++++++ src/include/reef/trace.h | 1 + src/include/uapi/ipc.h | 7 ++ 4 files changed, 226 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..1056a03 --- /dev/null +++ b/src/audio/passthrough.c @@ -0,0 +1,216 @@ +/*
- 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)
Probably best to write a short description of that this comp does and how it's intended as satrting point and template for other components.
+/*
- passthrough_comp_data structure
- passthrough_func - function that performs the routing of input buffer
to the output buffer based on config
- */
+struct passthrough_comp_data {
- int (*passthrough_func)(struct comp_dev *dev, struct comp_buffer *sink,
struct comp_buffer *source, uint32_t frames);
+};
+/* passthrough function to copy data from source to sink buffer */ +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;
- int ret = 0;
- /* 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");
same issues as with mux here.
ret = -EINVAL;
break;
- }
- return ret;
+}
+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;
Can you be verbose with comments throughout this file since it will be a template too.
- return dev;
+}
+static void passthrough_free(struct comp_dev *dev) +{
- struct passthrough_comp_data *cd = comp_get_drvdata(dev);
- rfree(cd);
- rfree(dev);
+}
+/* set component audio stream parameters */ +static int passthrough_params(struct comp_dev *dev) +{
- return 0;
+}
+/* used to pass standard and bespoke commands (with data) to 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;
+}
+/* copy and process stream data from source to sink buffers */ +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->frames * dev->frame_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 0;
+}
+static int passthrough_preload(struct comp_dev *dev) +{
- return passthrough_copy(dev);
+}
+static int passthrough_reset(struct comp_dev *dev) +{
- trace_pass("PTe");
- dev->state = COMP_STATE_INIT;
- return 0;
+}
+static int passthrough_prepare(struct comp_dev *dev) +{
- trace_pass("PTl");
- dev->state = COMP_STATE_PREPARE;
- return 0;
+}
+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 e0d0303..cb79e26 100644 --- a/src/include/uapi/ipc.h +++ b/src/include/uapi/ipc.h @@ -474,6 +474,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 */ @@ -573,6 +574,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;
--------------------------------------------------------------------- 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.
On Mon, 2017-09-04 at 14:35 +0100, Ranjani Sridharan wrote:
This patch adds a the comp_set_state() used for the mandatory pipeline commands, START, STOP, PAUSE and RELEASE. It also updates the cmd method in existing components to use comp_set_state().
Signed-off-by: Ranjani Sridharan ranjani.sridharan@linux.intel.com
src/audio/component.c | 36 ++++++++++++++++++++++++++++++++++++ src/audio/eq_fir.c | 23 ++--------------------- src/audio/host.c | 16 ++++------------ src/audio/src.c | 26 +++----------------------- src/audio/tone.c | 26 +++----------------------- src/audio/volume.c | 20 +++----------------- src/include/reef/audio/component.h | 3 +++ 7 files changed, 54 insertions(+), 96 deletions(-)
diff --git a/src/audio/component.c b/src/audio/component.c index 6369e2e..6f2e0c3 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -117,6 +117,42 @@ void comp_unregister(struct comp_driver *drv) spin_unlock(&cd->lock); }
+int comp_set_state(struct comp_dev *dev, int cmd) +{
- int ret = 0;
- switch (cmd) {
- case COMP_CMD_START:
- case COMP_CMD_RELEASE:
dev->state = COMP_STATE_RUNNING;
break;
- case COMP_CMD_STOP:
if (dev->state == COMP_STATE_RUNNING ||
dev->state == COMP_STATE_DRAINING ||
dev->state == COMP_STATE_PAUSED) {
comp_buffer_reset(dev);
dev->state = COMP_STATE_SETUP;
} else {
trace_comp_error("CEs");
ret = -EINVAL;
}
break;
- case COMP_CMD_PAUSE:
/* only support pausing for running */
if (dev->state == COMP_STATE_RUNNING)
dev->state = COMP_STATE_PAUSED;
else {
trace_comp_error("CEp");
ret = -EINVAL;
}
break;
- default:
we should set ret to -EINVAL here and trace.
break;
- }
- return ret;
+}
void sys_comp_init(void) { cd = rzalloc(RZONE_SYS, RFLAGS_NONE, sizeof(*cd)); diff --git a/src/audio/eq_fir.c b/src/audio/eq_fir.c index 534a4a1..6380340 100644 --- a/src/audio/eq_fir.c +++ b/src/audio/eq_fir.c @@ -364,31 +364,12 @@ static int eq_fir_cmd(struct comp_dev *dev, int cmd, void *data)
break;
case COMP_CMD_START:
trace_src("EFs");
dev->state = COMP_STATE_RUNNING;
case COMP_CMD_STOP:break;
trace_src("ESp");
if (dev->state == COMP_STATE_RUNNING ||
dev->state == COMP_STATE_DRAINING ||
dev->state == COMP_STATE_PAUSED) {
comp_buffer_reset(dev);
dev->state = COMP_STATE_SETUP;
}
case COMP_CMD_PAUSE:break;
trace_src("EPe");
/* only support pausing for running */
if (dev->state == COMP_STATE_RUNNING)
dev->state = COMP_STATE_PAUSED;
case COMP_CMD_RELEASE:break;
trace_src("ERl");
dev->state = COMP_STATE_RUNNING;
default:break;
trace_src("EDf");
ret = comp_set_state(dev, cmd);
break;
}
return ret;
diff --git a/src/audio/host.c b/src/audio/host.c index e71e95f..f81fd66 100644 --- a/src/audio/host.c +++ b/src/audio/host.c @@ -553,28 +553,20 @@ static int host_cmd(struct comp_dev *dev, int cmd, void *data)
// TODO: align cmd macros. switch (cmd) {
- case COMP_CMD_PAUSE:
/* only support pausing for running, channel is paused by DAI */
if (dev->state == COMP_STATE_RUNNING)
dev->state = COMP_STATE_PAUSED;
case COMP_CMD_STOP: if (dev->state == COMP_STATE_RUNNING || dev->state == COMP_STATE_DRAINING || dev->state == COMP_STATE_PAUSED) ret = host_stop(dev); break;break;
- case COMP_CMD_RELEASE:
/* channel is released by DAI */
dev->state = COMP_STATE_RUNNING;
break;
- case COMP_CMD_START:
dev->state = COMP_STATE_RUNNING;
case COMP_CMD_SUSPEND: case COMP_CMD_RESUME: break;break;
- case COMP_CMD_START:
- case COMP_CMD_PAUSE:
- case COMP_CMD_RELEASE: default:
break; }ret = comp_set_state(dev, cmd);
diff --git a/src/audio/src.c b/src/audio/src.c index 0279841..0ecb48c 100644 --- a/src/audio/src.c +++ b/src/audio/src.c @@ -381,7 +381,7 @@ static int src_cmd(struct comp_dev *dev, int cmd, void *data) { trace_src("SCm"); struct comp_data *cd = comp_get_drvdata(dev);
- int i;
int i, ret = 0;
switch (cmd) { case COMP_CMD_SRC:
@@ -400,35 +400,15 @@ static int src_cmd(struct comp_dev *dev, int cmd, void *data)
break;
case COMP_CMD_START:
trace_src("SSt");
dev->state = COMP_STATE_RUNNING;
case COMP_CMD_STOP:break;
trace_src("SSp");
if (dev->state == COMP_STATE_RUNNING ||
dev->state == COMP_STATE_DRAINING ||
dev->state == COMP_STATE_PAUSED) {
comp_buffer_reset(dev);
dev->state = COMP_STATE_SETUP;
}
case COMP_CMD_PAUSE:break;
trace_src("SPe");
/* only support pausing for running */
if (dev->state == COMP_STATE_RUNNING)
dev->state = COMP_STATE_PAUSED;
case COMP_CMD_RELEASE:break;
trace_src("SRl");
dev->state = COMP_STATE_RUNNING;
default:break;
trace_src("SDf");
break; }ret = comp_set_state(dev, cmd);
- return 0;
- return ret;
}
/* copy and process stream data from source to sink buffers */ diff --git a/src/audio/tone.c b/src/audio/tone.c index cbc50ac..305563e 100644 --- a/src/audio/tone.c +++ b/src/audio/tone.c @@ -433,6 +433,7 @@ static int tone_cmd(struct comp_dev *dev, int cmd, void *data) { struct comp_data *cd = comp_get_drvdata(dev); struct sof_ipc_comp_tone *ct;
int ret = 0;
trace_tone("tri");
@@ -456,36 +457,15 @@ static int tone_cmd(struct comp_dev *dev, int cmd, void *data) tonegen_unmute(&cd->sg); break; case COMP_CMD_START:
trace_tone("TSt");
dev->state = COMP_STATE_RUNNING;
case COMP_CMD_STOP:break;
trace_tone("TSp");
if (dev->state == COMP_STATE_RUNNING ||
dev->state == COMP_STATE_DRAINING ||
dev->state == COMP_STATE_PAUSED) {
comp_buffer_reset(dev);
dev->state = COMP_STATE_SETUP;
}
case COMP_CMD_PAUSE:break;
trace_tone("TPe");
/* only support pausing for running */
if (dev->state == COMP_STATE_RUNNING)
dev->state = COMP_STATE_PAUSED;
case COMP_CMD_RELEASE:break;
trace_tone("TRl");
dev->state = COMP_STATE_RUNNING;
default:break;
trace_tone("TDf");
break; }ret = comp_set_state(dev, cmd);
- return 0;
- return ret;
}
/* copy and process stream data from source to sink buffers */ diff --git a/src/audio/volume.c b/src/audio/volume.c index 93a3839..2e097d5 100644 --- a/src/audio/volume.c +++ b/src/audio/volume.c @@ -385,7 +385,7 @@ static int volume_cmd(struct comp_dev *dev, int cmd, void *data) { struct comp_data *cd = comp_get_drvdata(dev); struct sof_ipc_ctrl_values *cv;
- int i, j;
int i, j, ret = 0;
trace_volume("cmd");
@@ -425,29 +425,15 @@ static int volume_cmd(struct comp_dev *dev, int cmd, void *data) work_schedule_default(&cd->volwork, VOL_RAMP_US); break; case COMP_CMD_START:
dev->state = COMP_STATE_RUNNING;
case COMP_CMD_STOP:break;
if (dev->state == COMP_STATE_RUNNING ||
dev->state == COMP_STATE_DRAINING ||
dev->state == COMP_STATE_PAUSED) {
comp_buffer_reset(dev);
dev->state = COMP_STATE_SETUP;
}
case COMP_CMD_PAUSE:break;
/* only support pausing for running */
if (dev->state == COMP_STATE_RUNNING)
dev->state = COMP_STATE_PAUSED;
case COMP_CMD_RELEASE:break;
dev->state = COMP_STATE_RUNNING;
default:break;
break; }ret = comp_set_state(dev, cmd);
- return 0;
- return ret;
}
/* copy and process stream data from source to sink buffers */ diff --git a/src/include/reef/audio/component.h b/src/include/reef/audio/component.h index e73a22a..cbd2356 100644 --- a/src/include/reef/audio/component.h +++ b/src/include/reef/audio/component.h @@ -215,6 +215,9 @@ static inline void comp_free(struct comp_dev *dev) dev->drv->ops.free(dev); }
+/* component state set */ +int comp_set_state(struct comp_dev *dev, int cmd);
/* component parameter init - mandatory */ static inline int comp_params(struct comp_dev *dev) {
--------------------------------------------------------------------- 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.
participants (2)
-
Liam Girdwood
-
Ranjani Sridharan