[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