[Sound-open-firmware] [PATCH v2 1/2] MUX component added

Ranjani Sridharan ranjani.sridharan at linux.intel.com
Tue Sep 5 13:58:20 CEST 2017


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 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
  */
-- 
2.9.3



More information about the Sound-open-firmware mailing list