[Sound-open-firmware] [PATCH v2 1/2] MUX component added
Pierre-Louis Bossart
pierre-louis.bossart at linux.intel.com
Tue Sep 5 21:32:20 CEST 2017
On 9/5/17 6:58 AM, 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.
Sorry for the late feedback, but re-looking at the code, I am still not
sure how the 1:N case is handled and how I would use it.
Let's take the simplifying case of my 1:2 case for byt-cr support, where
I need to send data to both SSP0/SSP2 but only one is activated by a
DAPM route. I don't currently have any controls to know in userspace
which of the two is activated, so how would I send a switch command?
Even if I did send an IPC command 'manually' (with a kcontrol?), what
happens if the switch command is invoked to go from one to the other
pipeline while audio is flowing, could this lead to the main pipeline
stalling?
What am I missing?
>
> Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> ---
> src/audio/mux.c | 293 +++++++++++++++++++++++++++++++++++--
> src/include/reef/audio/Makefile.am | 3 +-
> src/include/reef/audio/component.h | 1 -
> src/include/reef/audio/mux.h | 50 +++++++
> src/include/uapi/ipc.h | 1 -
> 5 files changed, 335 insertions(+), 13 deletions(-)
> create mode 100644 src/include/reef/audio/mux.h
>
> diff --git a/src/audio/mux.c b/src/audio/mux.c
> index f420bd3..e010104 100644
> --- a/src/audio/mux.c
> +++ b/src/audio/mux.c
> @@ -26,61 +26,333 @@
> * POSSIBILITY OF SUCH DAMAGE.
> *
> * Author: Liam Girdwood <liam.r.girdwood at linux.intel.com>
> + * Ranjani Sridharan <ranjani.sridharan at 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(dest, src, frames * nch * sizeof(int32_t));
> + break;
> + default:
> + trace_mux_error("MUf");
> + ret = -EINVAL;
> + 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;
> + }
> +
> + cd->config->source_buffer_id = -1;
> + cd->config->sink_buffer_id = -1;
> +
> + comp_set_drvdata(dev, cd);
> + cd->mux_func = mux_function;
>
> - return NULL;
> + 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_route(struct comp_dev *dev,
> + int32_t source_buffer_index, int sink_buffer_index)
> +{
> + struct mux_comp_data *cd = comp_get_drvdata(dev);
> + struct comp_buffer *source_buffer, *sink_buffer;
> + struct list_item *clist;
> + int i = 0;
> +
> + if ((source_buffer_index > (cd->num_src_buffer - 1)) ||
> + (sink_buffer_index > (cd->num_sink_buffer - 1))) {
> + trace_mux_error("MUb");
> + return -EINVAL;
> + }
> +
> + /* switch source buffer if needed */
> + if (source_buffer_index != cd->config->source_buffer_id) {
> + cd->config->source_buffer_id = source_buffer_index;
> + /* 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->source_buffer_id) {
> + source_buffer->connected = 1;
> + cd->config->source_buffer = source_buffer;
> + } else
> + source_buffer->connected = 0;
> + i++;
> + }
> + }
> +
> + /* switch sink buffer if needed */
> + i = 0;
> + if (sink_buffer_index != cd->config->sink_buffer_id) {
> + cd->config->sink_buffer_id = sink_buffer_index;
> + /* 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->sink_buffer_id) {
> + sink_buffer->connected = 1;
> + cd->config->sink_buffer = sink_buffer;
> + } 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;
> +
> + count = 0;
> + list_for_item(clist, &dev->bsink_list)
> + count++;
> + cd->num_sink_buffer = count;
>
> return 0;
> }
>
> +static int mux_ctrl_cmd(struct comp_dev *dev, struct sof_ipc_ctrl_data *cdata)
> +{
> + struct mux_comp_data *cd = comp_get_drvdata(dev);
> + int source_buffer_index = -1, sink_buffer_index = -1, ret = 0;
> +
> + switch (cdata->cmd) {
> + case SOF_CTRL_CMD_ROUTE:
> + /* check if the ctrl cmd is for this component */
> + if (cdata->comp_id != dev->comp.id)
> + break;
> +
> + if (cdata->num_elems < 1) {
> + trace_mux_error("Mcd");
> + ret = -EINVAL;
> + }
> +
> + if (cdata->compv[0].index == 0) {
> + /* new source buffer index */
> + source_buffer_index = cdata->compv[0].uvalue;
> + /* sink buffer index is unchanged */
> + sink_buffer_index = cd->config->sink_buffer_id;
> + } else {
> + /* new sink buffer index */
> + sink_buffer_index = cdata->compv[0].uvalue;
> + /* source buffer index is unchanged */
> + source_buffer_index = cd->config->source_buffer_id;
> + }
> + /* switch to the new source/sink buffer(s)*/
> + ret = mux_route(dev, source_buffer_index,
> + sink_buffer_index);
> + break;
> + default:
> + break;
> + }
> +
> + if (ret < 0)
> + trace_mux_error("Mct");
> + return ret;
> +
> +}
> +
> /* 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_ctrl_data *cdata = data;
> + int ret = 0;
> +
> + switch (cmd) {
> + case COMP_CMD_SET_VALUE:
> + ret = mux_ctrl_cmd(dev, cdata);
> + 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 */
> +/* copy and process stream data from source to sink buffers
> + * returns the number of frames copied
> + */
> 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;
> + uint32_t copy_bytes;
>
> - return 0;
> + /* get the connected source and sink buffers */
> + source_buffer = cd->config->source_buffer;
> + sink_buffer = cd->config->sink_buffer;
> +
> + 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->params.host_period_bytes) {
> + trace_mux_error("Mcb");
> + 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 dev->frames;
> +}
> +
> +static int mux_preload(struct comp_dev *dev)
> +{
> + return mux_copy(dev);
> +}
> +
> +static int mux_default_config(struct comp_dev *dev)
> +{
> + int ret = 0;
> +
> + ret = set_buffer_count(dev);
> + if (ret < 0)
> + return -EINVAL;
> +
> + ret = mux_route(dev, 0, 0);
> +
> + 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 +365,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 e20ffed..ed29da4 100644
> --- a/src/include/reef/audio/component.h
> +++ b/src/include/reef/audio/component.h
> @@ -80,7 +80,6 @@
> #define COMP_CMD_SET_DATA 102
> #define COMP_CMD_GET_DATA 103
>
> -
> /* 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..6c6b6af
> --- /dev/null
> +++ b/src/include/reef/audio/mux.h
> @@ -0,0 +1,50 @@
> +/*
> + * 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 at linux.intel.com>
> + */
> +
> +#ifndef SOF_COMP_MUX_H
> +#define SOF_COMP_MUX_H
> +
> +#include <reef/audio/component.h>
> +/*
> + * mux_config data structure
> + * in_buffer_id - ID of input buffer connected to the MUX component
> + * out_buffer_id - ID of output buffer connected to the MUX component
> + * in_buffer - pointer to the connected source buffer
> + * out_buffer - pointer to the connected sink buffer
> + */
> +
> +struct mux_config {
> + uint32_t source_buffer_id, sink_buffer_id;
> + struct comp_buffer *source_buffer, *sink_buffer;
> +};
> +
> +
> +
> +#endif
> diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
> index c8cdedb..be4c9f2 100644
> --- a/src/include/uapi/ipc.h
> +++ b/src/include/uapi/ipc.h
> @@ -641,7 +641,6 @@ struct sof_ipc_comp_eq_iir {
> struct sof_ipc_comp_config config;
> } __attribute__((packed));
>
> -
> /* frees components, buffers and pipelines
> * SOF_IPC_TPLG_COMP_FREE, SOF_IPC_TPLG_PIPE_FREE, SOF_IPC_TPLG_BUFFER_FREE
> */
>
More information about the Sound-open-firmware
mailing list