diff --git a/src/audio/codec_adapter/codec/generic.c b/src/audio/codec_adapter/codec/generic.c index 8c1259f8805b..4442f1e02199 100644 --- a/src/audio/codec_adapter/codec/generic.c +++ b/src/audio/codec_adapter/codec/generic.c @@ -245,6 +245,22 @@ int codec_prepare(struct comp_dev *dev) return ret; } +static int process_passthrough(struct comp_dev *dev) +{ + int ret; + struct codec_data *codec = comp_get_codec(dev); + + ret = memcpy_s(codec->cpd.out_buff, codec->cpd.avail, codec->cpd.in_buff, codec->cpd.avail); + if (ret) { + comp_err(dev, "process_through() error %d: failed to copy data from in to out", + ret); + codec->cpd.produced = 0; + return ret; + } + codec->cpd.produced = codec->cpd.avail; + return 0; +} + int codec_process(struct comp_dev *dev) { int ret; @@ -260,7 +276,12 @@ int codec_process(struct comp_dev *dev) return -EPERM; } - ret = codec->ops->process(dev); + // TODO: how to set cd->passthrough flag? + if (cd->passthrough) { + ret = process_passthrough(dev); + } else { + ret = codec->ops->process(dev); + } if (ret) { comp_err(dev, "codec_prepare() error %d: codec process failed for codec_id %x", ret, codec_id); diff --git a/src/audio/codec_adapter/codec_adapter.c b/src/audio/codec_adapter/codec_adapter.c index 5ce1a18bd57b..df7996475f41 100644 --- a/src/audio/codec_adapter/codec_adapter.c +++ b/src/audio/codec_adapter/codec_adapter.c @@ -30,6 +30,8 @@ DECLARE_SOF_RT_UUID("codec_adapter", ca_uuid, 0xd8218443, 0x5ff3, 0x4a4c, DECLARE_TR_CTX(ca_tr, SOF_UUID(ca_uuid), LOG_LEVEL_INFO); +#define ENUM_CTRL_PASSTHROUGH 0 + /** * \brief Create a codec adapter component. * \param[in] drv - component driver pointer. @@ -91,6 +93,7 @@ static struct comp_dev *codec_adapter_new(const struct comp_driver *drv, dev->state = COMP_STATE_READY; cd->state = PP_STATE_CREATED; + cd->passthrough = 0; comp_cl_info(&comp_codec_adapter, "codec_adapter_new() done"); return dev; @@ -620,6 +623,89 @@ static int codec_adapter_ctrl_set_data(struct comp_dev *dev, return ret; } +static int codec_adapter_ctrl_enum_set(struct sof_ipc_ctrl_data *cdata, struct comp_data *cd) +{ + int ret; + + switch (cdata->index) { + case ENUM_CTRL_PASSTHROUGH: + if (cdata->num_elems) + cd->passthrough = cdata->chanv[0].value; + break; + default: + comp_cl_err(&comp_codec_adapter, + "codec_adapter_ctrl_enum_set() error: invalid index=%d", + cdata->index); + ret = -EINVAL; + break; + } + + return ret; +} + +static int codec_adapter_set_value(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + int ret; + struct comp_data *cd = comp_get_drvdata(dev); + + switch (cdata->cmd) { + case SOF_CTRL_CMD_ENUM: + comp_dbg(dev, "codec_adapter_set_value(): SOF_CTRL_CMD_ENUM index=%d", + cdata->index); + ret = codec_adapter_ctrl_enum_set(cdata, cd); + break; + default: + comp_err(dev, "codec_adapter_set_value() error: invalid cdata->cmd"); + ret = -EINVAL; + break; + } + + return ret; +} + +static int codec_adapter_ctrl_enum_get(struct sof_ipc_ctrl_data *cdata, struct comp_data *cd) +{ + int ret; + int j; + + switch (cdata->index) { + case ENUM_CTRL_PASSTHROUGH: + for (j = 0; j < cdata->num_elems; j++) + cdata->chanv[j].value = cd->passthrough; + break; + default: + comp_cl_err(&comp_codec_adapter, + "codec_adapter_ctrl_enum_get() error: invalid index=%d", + cdata->index); + ret = -EINVAL; + break; + } + + return ret; +} + +static int codec_adapter_get_value(struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + int ret; + struct comp_data *cd = comp_get_drvdata(dev); + + switch (cdata->cmd) { + case SOF_CTRL_CMD_ENUM: + comp_dbg(dev, "codec_adapter_get_value(): SOF_CTRL_CMD_ENUM index=%d", + cdata->index); + ret = codec_adapter_ctrl_enum_get(cdata, cd); + break; + default: + comp_err(dev, "codec_adapter_get_value() error: invalid cdata->cmd"); + ret = -EINVAL; + break; + } + + return ret; +} + /* Used to pass standard and bespoke commands (with data) to component */ static int codec_adapter_cmd(struct comp_dev *dev, int cmd, void *data, int max_data_size) @@ -637,6 +723,12 @@ static int codec_adapter_cmd(struct comp_dev *dev, int cmd, void *data, comp_err(dev, "codec_adapter_cmd() get_data not implemented yet."); ret = -ENODATA; break; + case COMP_CMD_SET_VALUE: + ret = codec_adapter_set_value(dev, cdata); + break; + case COMP_CMD_GET_VALUE: + ret = codec_adapter_get_value(dev, cdata); + break; default: comp_err(dev, "codec_adapter_cmd() error: unknown command"); ret = -EINVAL; diff --git a/src/include/sof/audio/codec_adapter/codec/generic.h b/src/include/sof/audio/codec_adapter/codec/generic.h index 32b7f38346ad..da2d78ab230a 100644 --- a/src/include/sof/audio/codec_adapter/codec/generic.h +++ b/src/include/sof/audio/codec_adapter/codec/generic.h @@ -188,6 +188,7 @@ struct comp_data { struct sof_ipc_stream_params stream_params; uint32_t period_bytes; /** pipeline period bytes */ uint32_t deep_buff_bytes; /**< copy start threshold */ + int passthrough:1; /**< data passthrough mode */ }; /*****************************************************************************/ diff --git a/tools/topology/m4/codec_adapter.m4 b/tools/topology/m4/codec_adapter.m4 index c5e932433731..65f52589a957 100644 --- a/tools/topology/m4/codec_adapter.m4 +++ b/tools/topology/m4/codec_adapter.m4 @@ -50,6 +50,9 @@ define(`W_CODEC_ADAPTER', ` bytes [' $6 ` ]' +` enum [' + $7 +` ]' `}') diff --git a/tools/topology/sof/pipe-codec-adapter-playback.m4 b/tools/topology/sof/pipe-codec-adapter-playback.m4 index af3c5e4c1b98..69547b56bd2a 100644 --- a/tools/topology/sof/pipe-codec-adapter-playback.m4 +++ b/tools/topology/sof/pipe-codec-adapter-playback.m4 @@ -12,6 +12,7 @@ include(`dai.m4') include(`pipeline.m4') include(`codec_adapter.m4') include(`bytecontrol.m4') +include(`enumcontrol.m4') # # Controls @@ -99,6 +100,20 @@ C_CONTROLBYTES(CA_RUNTIME_CONTROLBYTES_NAME_PIPE, PIPELINE_ID, , CA_RUNTIME_PARAMS) +define(CA_PASSTHRU_ENUM, concat(`ca_passthru_enum_', PIPELINE_ID)) +define(CA_PASSTHRU_CONTROL, concat(`CA PassThrough', PIPELINE_ID)) + +# Codec adapter passthrough enum list +CONTROLENUM_LIST(CA_PASSTHRU_ENUM, LIST(` ', `"passthru off"', `"passthru on"')) + +# Codec adapter passthrough enum control +C_CONTROLENUM(CA_PASSTHRU_CONTROL, PIPELINE_ID, + CA_PASSTHRU_ENUM, + LIST(` ', ENUM_CHANNEL(FC, 3, 0)), + CONTROLENUM_OPS(enum, + 257 binds the mixer control to enum get/put handlers, + 257, 257)) + # # Components and Buffers # @@ -112,7 +127,8 @@ ifdef(`CA_SCHEDULE_CORE',`', `define(`CA_SCHEDULE_CORE', `SCHEDULE_CORE')') W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, DAI_PERIODS, 0, SCHEDULE_CORE) W_CODEC_ADAPTER(0, PIPELINE_FORMAT, DAI_PERIODS, DAI_PERIODS, CA_SCHEDULE_CORE, - LIST(` ', "CA_SETUP_CONTROLBYTES_NAME_PIPE", "CA_RUNTIME_CONTROLBYTES_NAME_PIPE")) + LIST(` ', "CA_SETUP_CONTROLBYTES_NAME_PIPE", "CA_RUNTIME_CONTROLBYTES_NAME_PIPE"), + LIST(` ', "CA_PASSTHRU_CONTROL")) # Playback Buffers W_BUFFER(0, COMP_BUFFER_SIZE(DAI_PERIODS, @@ -145,6 +161,8 @@ indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Playback PCM_I PCM_CAPABILITIES(Passthrough Playback PCM_ID, CAPABILITY_FORMAT_NAME(PIPELINE_FORMAT), PCM_MIN_RATE, PCM_MAX_RATE, 2, PIPELINE_CHANNELS, 2, 16, 192, 16384, 65536, 65536) +undefine(`CA_PASSTHRU_CONTROL') +undefine(`CA_PASSTHRU_ENUM') undefine(`CA_RUNTIME_CONTROLBYTES_NAME_PIPE') undefine(`CA_RUNTIME_PARAMS') undefine(`CA_SETUP_CONTROLBYTES_NAME_PIPE')