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@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@linux.intel.com + * Ranjani Sridharan ranjani.sridharan@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;