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

Ranjani Sridharan ranjani.sridharan at linux.intel.com
Mon Sep 11 23:39:02 CEST 2017


This patch adds a new switch component that mutes the pipeline when the
when the switch is OFF. Stream data flows through the pipeline normally
when it is ON.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
---
 src/audio/switch.c     | 178 +++++++++++++++++++++++++++++++++++++++++++++++--
 src/include/uapi/ipc.h |   6 ++
 2 files changed, 178 insertions(+), 6 deletions(-)

diff --git a/src/audio/switch.c b/src/audio/switch.c
index 7149b61..67f723c 100644
--- a/src/audio/switch.c
+++ b/src/audio/switch.c
@@ -26,6 +26,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  *
  * Author: Liam Girdwood <liam.r.girdwood at linux.intel.com>
+ *	   Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
  */
 
 #include <stdint.h>
@@ -40,46 +41,211 @@
 #define trace_switch_error(__e)   trace_error(TRACE_CLASS_SWITCH, __e)
 #define tracev_switch(__e)        tracev_event(TRACE_CLASS_SWITCH, __e)
 
+/* Simple switch component
+ * This component copies stream data from source buffer to the sink buffer
+ * if the switch is ON. Otherwise it discards the source buffer data and
+ * writes 0's to the sink buffer.
+ */
+
+/*
+ * switch_comp_data structure
+ *	on_switch	- indicates if the switch is ON/OFF
+ *	switch_func	- function that performs the routing of input buffer to
+ *			the output buffer based on on_switch
+ */
+struct switch_comp_data {
+	int on_switch;
+	int (*switch_func)(struct comp_dev *dev, struct comp_buffer *sink,
+		struct comp_buffer *source, uint32_t frames);
+
+};
+
+/* switch function to copy data from source to sink buffer */
+static int switch_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);
+	struct switch_comp_data *cd = comp_get_drvdata(dev);
+	int32_t *src = (int32_t *) source_buffer->r_ptr;
+	int32_t *dest = (int32_t *) sink_buffer->w_ptr;
+	int nch = dev->params.channels;
+
+	/* copy source buffer to sink buffer if switch is on */
+	if (cd->on_switch == 1) {
+		/* 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_switch_error("SWf");
+			return -EINVAL;
+		}
+
+		return frames;
+	}
+
+	/* discard source data and copy 0's if switch is off */
+	memset(dest, 0, frames * nch * sizeof(int32_t));
+
+	return frames;
+}
+
 static struct comp_dev *switch_new(struct sof_ipc_comp *comp)
 {
-	trace_switch("new");
+	struct comp_dev *dev;
+	struct switch_comp_data *cd;
+
+	trace_switch("Swn");
+	dev = rzalloc(RZONE_RUNTIME, RFLAGS_NONE,
+		COMP_SIZE(struct sof_ipc_comp_switch));
+	if (dev == NULL)
+		return NULL;
+
+	memcpy(&dev->comp, comp, sizeof(struct sof_ipc_comp_switch));
 
-	return NULL;
+	cd = rzalloc(RZONE_RUNTIME, RFLAGS_NONE, sizeof(*cd));
+	if (cd == NULL) {
+		rfree(dev);
+		return NULL;
+	}
+
+	/* switch is on by default */
+	cd->on_switch = 1;
+
+	comp_set_drvdata(dev, cd);
+	cd->switch_func = switch_function;
+
+	return dev;
 }
 
 static void switch_free(struct comp_dev *dev)
 {
+	struct switch_comp_data *cd = comp_get_drvdata(dev);
 
+	rfree(cd);
+	rfree(dev);
 }
 
 /* set component audio stream paramters */
 static int switch_params(struct comp_dev *dev)
 {
-
 	return 0;
 }
 
+static int switch_ctrl_cmd(struct comp_dev *dev,
+	struct sof_ipc_ctrl_data *cdata)
+{
+	struct switch_comp_data *cd = comp_get_drvdata(dev);
+	int ret = 0;
+
+	if (cdata == NULL) {
+		trace_switch_error("swe");
+		return -EINVAL;
+	}
+
+	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_switch_error("Swd");
+			ret = -EINVAL;
+		}
+
+		cd->on_switch = cdata->compv[0].uvalue;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
 /* used to pass standard and bespoke commands (with data) to component */
 static int switch_cmd(struct comp_dev *dev, int cmd, void *data)
 {
-	/* switch 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 = switch_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 */
 static int switch_copy(struct comp_dev *dev)
 {
+	struct switch_comp_data *cd = comp_get_drvdata(dev);
+	struct comp_buffer *source_buffer = NULL, *sink_buffer = NULL;
+	uint32_t copy_bytes;
 
-	return 0;
+	/* 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);
+
+	if (!source_buffer || !sink_buffer) {
+		trace_switch_error("Scp");
+		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_switch_error("Scb");
+		return -EINVAL;
+	}
+
+	/* Run passthrough if buffers have enough room */
+	cd->switch_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 switch_reset(struct comp_dev *dev)
 {
+	struct switch_comp_data *cd = comp_get_drvdata(dev);
+
+	/* reset switch to on status */
+	cd->on_switch = 1;
+	dev->state = COMP_STATE_INIT;
+
 	return 0;
 }
 
 static int switch_prepare(struct comp_dev *dev)
 {
+	dev->state = COMP_STATE_PREPARE;
+
 	return 0;
 }
 
diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h
index 2c2f415..cbef325 100644
--- a/src/include/uapi/ipc.h
+++ b/src/include/uapi/ipc.h
@@ -616,6 +616,12 @@ struct sof_ipc_comp_mux {
 	struct sof_ipc_comp_config config;
 } __attribute__((packed));
 
+/* generic switch component */
+struct sof_ipc_comp_switch {
+	struct sof_ipc_comp comp;
+	struct sof_ipc_comp_config config;
+} __attribute__((packed));
+
 /* generic passthrough component */
 struct sof_ipc_comp_passthrough {
 	struct sof_ipc_comp comp;
-- 
2.11.0



More information about the Sound-open-firmware mailing list