summaryrefslogtreecommitdiff
path: root/hifi/xaf/hifi-dpf/audio
diff options
context:
space:
mode:
Diffstat (limited to 'hifi/xaf/hifi-dpf/audio')
-rw-r--r--hifi/xaf/hifi-dpf/audio/xa-class-audio-codec.c785
-rw-r--r--hifi/xaf/hifi-dpf/audio/xa-class-base.c537
-rw-r--r--hifi/xaf/hifi-dpf/audio/xa-class-base.h263
-rw-r--r--hifi/xaf/hifi-dpf/audio/xa-class-mixer.c870
4 files changed, 2455 insertions, 0 deletions
diff --git a/hifi/xaf/hifi-dpf/audio/xa-class-audio-codec.c b/hifi/xaf/hifi-dpf/audio/xa-class-audio-codec.c
new file mode 100644
index 00000000..3806548f
--- /dev/null
+++ b/hifi/xaf/hifi-dpf/audio/xa-class-audio-codec.c
@@ -0,0 +1,785 @@
+/*******************************************************************************
+* Copyright (C) 2018 Cadence Design Systems, Inc.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to use this Software with Cadence processor cores only and
+* not with any other processors and platforms, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************************/
+
+/*******************************************************************************
+ * xa-class-audio-codec.c
+ *
+ * Generic audio codec task implementation
+ *
+ ******************************************************************************/
+
+#define MODULE_TAG CODEC
+
+/*******************************************************************************
+ * Includes
+ ******************************************************************************/
+
+#include "xf.h"
+#include "xa-class-base.h"
+#include "audio/xa-audio-decoder-api.h"
+
+/*******************************************************************************
+ * Tracing configuration
+ ******************************************************************************/
+
+TRACE_TAG(INIT, 1);
+TRACE_TAG(WARNING, 1);
+TRACE_TAG(INFO, 1);
+TRACE_TAG(INPUT, 1);
+TRACE_TAG(OUTPUT, 1);
+TRACE_TAG(DECODE, 1);
+
+/*******************************************************************************
+ * Internal functions definitions
+ ******************************************************************************/
+
+typedef struct XAAudioCodec
+{
+ /***************************************************************************
+ * Control data
+ **************************************************************************/
+
+ /* ...generic audio codec data */
+ XACodecBase base;
+
+ /* ...input port data */
+ xf_input_port_t input;
+
+ /* ...output port data */
+ xf_output_port_t output;
+
+ /* ...input port index */
+ WORD32 in_idx;
+
+ /* ...output port index */
+ WORD32 out_idx;
+
+ /***************************************************************************
+ * Run-time configuration parameters
+ **************************************************************************/
+
+ /* ...sample size in bytes */
+ u32 sample_size;
+
+ /* ...audio sample duration */
+ u32 factor;
+
+ /* ...total number of produced audio frames since last reset */
+ u32 produced;
+
+} XAAudioCodec;
+
+/*******************************************************************************
+ * Auxiliary codec execution flags
+ ******************************************************************************/
+
+/* ...input port setup condition */
+#define XA_CODEC_FLAG_INPUT_SETUP __XA_BASE_FLAG(1 << 0)
+
+/* ...output port setup condition */
+#define XA_CODEC_FLAG_OUTPUT_SETUP __XA_BASE_FLAG(1 << 1)
+
+/*******************************************************************************
+ * Data processing scheduling
+ ******************************************************************************/
+
+/* ...prepare codec for steady operation (tbd - don't absolutely like it) */
+static inline XA_ERRORCODE xa_codec_prepare_runtime(XAAudioCodec *codec)
+{
+ XACodecBase *base = (XACodecBase *)codec;
+ xf_message_t *m = xf_msg_queue_head(&codec->output.queue);
+ xf_start_msg_t *msg = m->buffer;
+ u32 frame_size;
+ u32 factor;
+
+ /* ...fill-in buffer parameters */
+ XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_CODEC_CONFIG_PARAM_SAMPLE_RATE, &msg->sample_rate);
+ XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_CODEC_CONFIG_PARAM_CHANNELS, &msg->channels);
+ XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_CODEC_CONFIG_PARAM_PCM_WIDTH, &msg->pcm_width);
+ XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, codec->in_idx, &msg->input_length);
+ XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, codec->out_idx, &msg->output_length);
+
+ TRACE(INIT, _b("codec[%p]::runtime init: f=%u, c=%u, w=%u, i=%u, o=%u"), codec, msg->sample_rate, msg->channels, msg->pcm_width, msg->input_length, msg->output_length);
+
+ /* ...reallocate input port buffer as needed - tbd */
+ BUG(msg->input_length > codec->input.length, _x("Input buffer reallocation required: %u to %u"), codec->input.length, msg->input_length);
+
+ /* ...save sample size in bytes */
+ codec->sample_size = msg->channels * (msg->pcm_width == 16 ? 2 : 4);
+
+ /* ...calculate frame duration; get number of samples in the frame (don't like division here - tbd) */
+ frame_size = msg->output_length / codec->sample_size;
+
+ /* ...it must be a multiple */
+ XF_CHK_ERR(frame_size * codec->sample_size == msg->output_length, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...retrieve upsampling factor for given sample rate */
+ XF_CHK_ERR(factor = xf_timebase_factor(msg->sample_rate), XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...set frame duration factor (converts number of bytes into timebase units) */
+ codec->factor = factor / codec->sample_size;
+
+ TRACE(INIT, _b("ts-factor: %u (%u)"), codec->factor, factor);
+
+ BUG(codec->factor * codec->sample_size != factor, _x("Freq mismatch: %u vs %u"), codec->factor * codec->sample_size, factor);
+
+ /* ...pass response to caller (push out of output port) */
+ xf_output_port_produce(&codec->output, sizeof(*msg));
+
+ /* ...codec runtime initialization is completed */
+ TRACE(INIT, _b("codec[%p] runtime initialized: i=%u, o=%u"), codec, msg->input_length, msg->output_length);
+
+ return XA_NO_ERROR;
+}
+
+/*******************************************************************************
+ * Commands processing
+ ******************************************************************************/
+
+/* ...EMPTY-THIS-BUFFER command processing */
+static XA_ERRORCODE xa_codec_empty_this_buffer(XACodecBase *base, xf_message_t *m)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) base;
+
+ /* ...make sure the port is sane */
+ XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == 0, XA_API_FATAL_INVALID_CMD);
+
+ /* ...command is allowed only in post-init state */
+ XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
+
+ /* ...put message into input queue */
+ if (xf_input_port_put(&codec->input, m))
+ {
+ /* ...restart stream if it is in completed state */
+ if (base->state & XA_BASE_FLAG_COMPLETED)
+ {
+ /* ...reset execution stage */
+ base->state = XA_BASE_FLAG_POSTINIT | XA_BASE_FLAG_EXECUTION;
+
+ /* ...reset execution runtime */
+ XA_API(base, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DO_RUNTIME_INIT, NULL);
+
+ /* ...reset produced samples counter */
+ codec->produced = 0;
+ }
+
+ /* ...codec must be in one of these states */
+ XF_CHK_ERR(base->state & (XA_BASE_FLAG_RUNTIME_INIT | XA_BASE_FLAG_EXECUTION), XA_API_FATAL_INVALID_CMD);
+
+ /* ...schedule data processing if output is ready */
+ if (xf_output_port_ready(&codec->output))
+ {
+ xa_base_schedule(base, 0);
+ }
+ }
+
+ TRACE(INPUT, _b("Received buffer [%p]:%u"), m->buffer, m->length);
+
+ return XA_NO_ERROR;
+}
+
+/* ...FILL-THIS-BUFFER command processing */
+static XA_ERRORCODE xa_codec_fill_this_buffer(XACodecBase *base, xf_message_t *m)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) base;
+
+ /* ...make sure the port is sane */
+ XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == 1, XA_API_FATAL_INVALID_CMD);
+
+ /* ...command is allowed only in postinit state */
+ XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
+
+ /* ...special handling of zero-length buffer */
+ if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
+ {
+ /* ...message must be zero-length */
+ BUG(m->length != 0, _x("Invalid message length: %u"), m->length);
+ }
+ else if (m == xf_output_port_control_msg(&codec->output))
+ {
+ /* ...end-of-stream processing indication received; check the state */
+ BUG((base->state & XA_BASE_FLAG_COMPLETED) == 0, _x("invalid state: %x"), base->state);
+
+ /* ... mark flushing sequence is done */
+ xf_output_port_flush_done(&codec->output);
+
+ /* ...complete pending zero-length input buffer */
+ xf_input_port_purge(&codec->input);
+
+ TRACE(INFO, _b("codec[%p] playback completed"), codec);
+
+ /* ...playback is over */
+ return XA_NO_ERROR;
+ }
+ else if ((base->state & XA_BASE_FLAG_COMPLETED) && !xf_output_port_routed(&codec->output))
+ {
+ /* ...return message arrived from application immediately */
+ xf_response_ok(m);
+
+ return XA_NO_ERROR;
+ }
+ else
+ {
+ TRACE(OUTPUT, _b("Received output buffer [%p]:%u"), m->buffer, m->length);
+
+ /* ...adjust message length (may be shorter than original) */
+ m->length = codec->output.length;
+ }
+
+ /* ...place message into output port */
+ if (xf_output_port_put(&codec->output, m) && xf_input_port_ready(&codec->input))
+ {
+ /* ...schedule data processing instantly */
+ if (base->state & (XA_BASE_FLAG_RUNTIME_INIT | XA_BASE_FLAG_EXECUTION))
+ {
+ xa_base_schedule(base, 0);
+ }
+ }
+
+ return XA_NO_ERROR;
+}
+
+/* ...output port routing */
+static XA_ERRORCODE xa_codec_port_route(XACodecBase *base, xf_message_t *m)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) base;
+ xf_route_port_msg_t *cmd = m->buffer;
+ xf_output_port_t *port = &codec->output;
+ u32 src = XF_MSG_DST(m->id);
+ u32 dst = cmd->dst;
+
+ /* ...command is allowed only in "postinit" state */
+ XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
+
+ /* ...make sure output port is addressed */
+ XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == 1, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...make sure port is not routed yet */
+ XF_CHK_ERR(!xf_output_port_routed(port), XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...route output port - allocate queue */
+ XF_CHK_ERR(xf_output_port_route(port, __XF_MSG_ID(dst, src), cmd->alloc_number, cmd->alloc_size, cmd->alloc_align) == 0, XA_API_FATAL_MEM_ALLOC);
+
+ /* ...schedule processing instantly */
+ xa_base_schedule(base, 0);
+
+ /* ...pass success result to caller */
+ xf_response_ok(m);
+
+ return XA_NO_ERROR;
+}
+
+/* ...port unroute command */
+static XA_ERRORCODE xa_codec_port_unroute(XACodecBase *base, xf_message_t *m)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) base;
+
+ /* ...command is allowed only in "postinit" state */
+ XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
+
+ /* ...make sure output port is addressed */
+ XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == 1, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...cancel any pending processing */
+ xa_base_cancel(base);
+
+ /* ...clear output-port-setup condition */
+ base->state &= ~XA_CODEC_FLAG_OUTPUT_SETUP;
+
+ /* ...pass flush command down the graph */
+ if (xf_output_port_flush(&codec->output, XF_FLUSH))
+ {
+ TRACE(INFO, _b("port is idle; instantly unroute"));
+
+ /* ...flushing sequence is not needed; command may be satisfied instantly */
+ xf_output_port_unroute(&codec->output);
+
+ /* ...pass response to the proxy */
+ xf_response_ok(m);
+ }
+ else
+ {
+ TRACE(INFO, _b("port is busy; propagate unroute command"));
+
+ /* ...flushing sequence is started; save flow-control message */
+ xf_output_port_unroute_start(&codec->output, m);
+ }
+
+ return XA_NO_ERROR;
+}
+
+/* ...FLUSH command processing */
+static XA_ERRORCODE xa_codec_flush(XACodecBase *base, xf_message_t *m)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) base;
+
+ /* ...command is allowed only in "postinit" state */
+ XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
+
+ /* ...ensure input parameter length is zero */
+ XF_CHK_ERR(m->length == 0, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ TRACE(1, _b("flush command received"));
+
+ /* ...flush command must be addressed to input port */
+ if (XF_MSG_DST_PORT(m->id) == 0)
+ {
+ /* ...cancel data processing message if needed */
+ xa_base_cancel(base);
+
+ /* ...input port flushing; purge content of input buffer */
+ xf_input_port_purge(&codec->input);
+
+ /* ...clear input-ready condition */
+ base->state &= ~XA_CODEC_FLAG_INPUT_SETUP;
+
+ /* ...reset execution runtime */
+ XA_API(base, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DO_RUNTIME_INIT, NULL);
+
+ /* ...reset produced samples counter */
+ codec->produced = 0;
+
+ /* ...propagate flushing command to output port */
+ if (xf_output_port_flush(&codec->output, XF_FLUSH))
+ {
+ /* ...flushing sequence is not needed; satisfy command instantly */
+ xf_response(m);
+ }
+ else
+ {
+ /* ...flushing sequence is started; save flow-control message at input port */
+ xf_input_port_control_save(&codec->input, m);
+ }
+ }
+ else if (xf_output_port_unrouting(&codec->output))
+ {
+ /* ...flushing during port unrouting; complete unroute sequence */
+ xf_output_port_unroute_done(&codec->output);
+
+ TRACE(INFO, _b("port is unrouted"));
+ }
+ else
+ {
+ /* ...output port flush command/response; check if the port is routed */
+ if (!xf_output_port_routed(&codec->output))
+ {
+ /* ...complete all queued messages */
+ xf_output_port_flush(&codec->output, XF_FLUSH);
+
+ /* ...and pass response to flushing command */
+ xf_response(m);
+ }
+ else
+ {
+ /* ...response to flushing command received */
+ BUG(m != xf_output_port_control_msg(&codec->output), _x("invalid message: %p"), m);
+
+ /* ...mark flushing sequence is completed */
+ xf_output_port_flush_done(&codec->output);
+
+ /* ...complete original flow-control command */
+ xf_input_port_purge_done(&codec->input);
+ }
+
+ /* ...clear output-setup condition */
+ base->state &= ~XA_CODEC_FLAG_OUTPUT_SETUP;
+ }
+
+ return XA_NO_ERROR;
+}
+
+/*******************************************************************************
+ * Generic codec API
+ ******************************************************************************/
+
+/* ...memory buffer handling */
+static XA_ERRORCODE xa_codec_memtab(XACodecBase *base, WORD32 idx, WORD32 type, WORD32 size, WORD32 align, u32 core)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) base;
+
+ if (type == XA_MEMTYPE_INPUT)
+ {
+ /* ...input port specification; allocate internal buffer */
+ XF_CHK_ERR(xf_input_port_init(&codec->input, size, align, core) == 0, XA_API_FATAL_MEM_ALLOC);
+
+ /* ...save input port index */
+ codec->in_idx = idx;
+
+ /* ...set input buffer pointer as needed */
+ (size ? XA_API(base, XA_API_CMD_SET_MEM_PTR, idx, codec->input.buffer) : 0);
+
+ (size ? TRACE(1, _x("set input ptr: %p"), codec->input.buffer) : 0);
+ }
+ else
+ {
+ /* ...output buffer specification */
+ XF_CHK_ERR(type == XA_MEMTYPE_OUTPUT, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...initialize output port queue (no allocation here yet) */
+ XF_CHK_ERR(xf_output_port_init(&codec->output, size) == 0, XA_API_FATAL_MEM_ALLOC);
+
+ /* ...save output port index */
+ codec->out_idx = idx;
+ }
+
+ return XA_NO_ERROR;
+}
+
+/* ...prepare input/output buffers */
+static XA_ERRORCODE xa_codec_preprocess(XACodecBase *base)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) base;
+
+ /* ...prepare output buffer if needed */
+ if (!(base->state & XA_CODEC_FLAG_OUTPUT_SETUP))
+ {
+ void *output;
+
+ /* ...get output buffer from port, if possible */
+ if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
+ {
+ /* ...run-time is not initialized yet; use scratch buffer */
+ output = base->scratch;
+ }
+ else if ((output = xf_output_port_data(&codec->output)) == NULL)
+ {
+ /* ...no output buffer available */
+ return XA_CODEC_EXEC_NO_DATA;
+ }
+
+ /* ...set the output buffer pointer */
+ XA_API(base, XA_API_CMD_SET_MEM_PTR, codec->out_idx, output);
+
+ TRACE(1, _x("set output ptr: %p"), output);
+
+ /* ...mark output port is setup */
+ base->state ^= XA_CODEC_FLAG_OUTPUT_SETUP;
+ }
+
+ /* ...prepare input data if needed */
+ if (!(base->state & XA_CODEC_FLAG_INPUT_SETUP))
+ {
+ void *input;
+ u32 filled;
+
+ /* ...fill input buffer */
+ if (xf_input_port_bypass(&codec->input))
+ {
+ /* ...use input buffer directly; check if there is data available */
+ if ((input = xf_input_port_data(&codec->input)) != NULL)
+ {
+ /* ...set input data buffer pointer */
+ XA_API(base, XA_API_CMD_SET_MEM_PTR, codec->in_idx, input);
+
+ /* ...retrieve number of input bytes */
+ filled = xf_input_port_length(&codec->input);
+ }
+ else if (!xf_input_port_done(&codec->input))
+ {
+ /* ...return non-fatal indication to prevent further processing */
+ return XA_CODEC_EXEC_NO_DATA;
+ }
+ else
+ {
+ /* ...mark we have no data in current buffer */
+ filled = 0;
+ }
+ }
+ else
+ {
+ /* ...port is in non-bypass mode; try to fill internal buffer */
+ if (xf_input_port_done(&codec->input) || xf_input_port_fill(&codec->input))
+ {
+ /* ...retrieve number of bytes in input buffer (not really - tbd) */
+ filled = xf_input_port_level(&codec->input);
+ }
+ else
+ {
+ /* ...return non-fatal indication to prevent further processing */
+ return XA_CODEC_EXEC_NO_DATA;
+ }
+ }
+
+ /* ...check if input stream is over */
+ if (xf_input_port_done(&codec->input))
+ {
+ /* ...pass input-over command to the codec to indicate the final buffer */
+ XA_API(base, XA_API_CMD_INPUT_OVER, codec->in_idx, NULL);
+
+ TRACE(INFO, _b("codec[%p]: signal input-over (filled: %u)"), codec, filled);
+ }
+
+ TRACE(INPUT, _b("input-buffer fill-level: %u bytes"), filled);
+
+ /* ...specify number of bytes available in the input buffer */
+ XA_API(base, XA_API_CMD_SET_INPUT_BYTES, codec->in_idx, &filled);
+
+ /* ...mark input port is setup */
+ base->state ^= XA_CODEC_FLAG_INPUT_SETUP;
+ }
+
+ return XA_NO_ERROR;
+}
+
+/* ...post-processing operation; input/output ports maintenance */
+static XA_ERRORCODE xa_codec_postprocess(XACodecBase *base, int done)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) base;
+ WORD32 consumed = 0;
+ WORD32 produced = 0;
+
+ /* ...get number of consumed / produced bytes */
+ XA_API(base, XA_API_CMD_GET_CURIDX_INPUT_BUF, codec->in_idx, &consumed);
+
+ /* ...get number of produced bytes only if runtime is initialized (sample size is known) */
+ (codec->sample_size ? XA_API(base, XA_API_CMD_GET_OUTPUT_BYTES, codec->out_idx, &produced) : 0);
+
+ TRACE(DECODE, _b("codec[%p]::postprocess(c=%u, p=%u, d=%u)"), codec, consumed, produced, done);
+
+ /* ...input buffer maintenance; check if we consumed anything */
+ if (consumed)
+ {
+ /* ...consume specified number of bytes from input port */
+ xf_input_port_consume(&codec->input, consumed);
+
+ /* ...clear input-setup flag */
+ base->state ^= XA_CODEC_FLAG_INPUT_SETUP;
+ }
+
+ /* ...output buffer maintenance; check if we have produced anything */
+ if (produced)
+ {
+ /* ...increment total number of produced samples (really don't like division here - tbd) */
+ codec->produced += produced / codec->sample_size;
+
+ /* ...immediately complete output buffer (don't wait until it gets filled) */
+ xf_output_port_produce(&codec->output, produced);
+
+ /* ...clear output port setup flag */
+ base->state ^= XA_CODEC_FLAG_OUTPUT_SETUP;
+ }
+
+ /* ...process execution stage transition */
+ if (done)
+ {
+ if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
+ {
+ /* ...stream is completed while codec is in runtime initialization stage */
+ BUG(1, _x("breakpoint"));
+ }
+ else if (base->state & XA_BASE_FLAG_EXECUTION)
+ {
+ /* ...runtime initialization done */
+ XA_CHK(xa_codec_prepare_runtime(codec));
+
+ /* ...clear output port setup flag as we were using scratch buffer;
+ * technically, no need to repeat setup of input buffer, but some codecs require
+ * it as well
+ */
+ base->state &= ~(XA_CODEC_FLAG_INPUT_SETUP | XA_CODEC_FLAG_OUTPUT_SETUP);
+ }
+ else
+ {
+ /* ...output stream is over; propagate condition to sink port */
+ if (xf_output_port_flush(&codec->output, XF_FILL_THIS_BUFFER))
+ {
+ /* ...flushing sequence is not needed; complete pending zero-length input */
+ xf_input_port_purge(&codec->input);
+
+ /* ...no propagation to output port */
+ TRACE(INFO, _b("codec[%p] playback completed"), codec);
+ }
+ else
+ {
+ /* ...flushing sequence is started; wait until flow-control message returns */
+ TRACE(INFO, _b("propagate end-of-stream condition"));
+ }
+ }
+
+ /* ...return early to prevent task rescheduling */
+ return XA_NO_ERROR;
+ }
+
+ /* ...reschedule processing if needed */
+ if (xf_input_port_ready(&codec->input) && xf_output_port_ready(&codec->output))
+ {
+ /* ...schedule data processing with respect to its urgency */
+ xa_base_schedule(base, produced * codec->factor);
+ }
+
+ return XA_NO_ERROR;
+}
+
+/* ...configuration parameter retrieval */
+static XA_ERRORCODE xa_codec_getparam(XACodecBase *base, WORD32 id, pVOID value)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) base;
+
+ if (id == XA_CODEC_CONFIG_PARAM_PRODUCED)
+ {
+ /* ...retrieve number of produced samples since last reset */
+ *(u32 *)value = codec->produced;
+
+ return XA_NO_ERROR;
+ }
+ else
+ {
+ /* ...pass command to underlying codec plugin */
+ return XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, id, value);
+ }
+}
+
+/*******************************************************************************
+ * Component entry point
+ ******************************************************************************/
+
+/* ...command hooks */
+static XA_ERRORCODE (* const xa_codec_cmd[])(XACodecBase *, xf_message_t *) =
+{
+ [XF_OPCODE_TYPE(XF_SET_PARAM)] = xa_base_set_param,
+ [XF_OPCODE_TYPE(XF_GET_PARAM)] = xa_base_get_param,
+ [XF_OPCODE_TYPE(XF_ROUTE)] = xa_codec_port_route,
+ [XF_OPCODE_TYPE(XF_UNROUTE)] = xa_codec_port_unroute,
+ [XF_OPCODE_TYPE(XF_EMPTY_THIS_BUFFER)] = xa_codec_empty_this_buffer,
+ [XF_OPCODE_TYPE(XF_FILL_THIS_BUFFER)] = xa_codec_fill_this_buffer,
+ [XF_OPCODE_TYPE(XF_FLUSH)] = xa_codec_flush,
+ [XF_OPCODE_TYPE(XF_SET_PARAM_EXT)] = xa_base_set_param_ext,
+ [XF_OPCODE_TYPE(XF_GET_PARAM_EXT)] = xa_base_get_param_ext,
+};
+
+/* ...total number of commands supported */
+#define XA_CODEC_CMD_NUM (sizeof(xa_codec_cmd) / sizeof(xa_codec_cmd[0]))
+
+/* ...command processor for termination state (only for routed port case) */
+static int xa_audio_codec_terminate(xf_component_t *component, xf_message_t *m)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) component;
+ u32 opcode = m->opcode;
+
+ /* ...check if we received output port control message */
+ if (m == xf_output_port_control_msg(&codec->output))
+ {
+ /* ...output port flushing complete; mark port is idle and terminate */
+ xf_output_port_flush_done(&codec->output);
+ return -1;
+ }
+ else if (opcode == XF_FILL_THIS_BUFFER)
+ {
+ /* ...output buffer returned by the sink component; ignore and keep waiting */
+ TRACE(OUTPUT, _b("collect output buffer"));
+ return 0;
+ }
+ else if (opcode == XF_UNREGISTER)
+ {
+ /* ...ignore subsequent unregister command/response - tbd */
+ return 0;
+ }
+ else
+ {
+ /* ...everything else is responded with generic failure */
+ xf_response_err(m);
+ return 0;
+ }
+}
+
+/* ...audio codec destructor */
+static int xa_audio_codec_destroy(xf_component_t *component, xf_message_t *m)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) component;
+ u32 core = xf_component_core(component);
+
+ /* ...destroy input port */
+ xf_input_port_destroy(&codec->input, core);
+
+ /* ...destroy output port */
+ xf_output_port_destroy(&codec->output, core);
+
+ /* ...deallocate all resources */
+ xa_base_destroy(&codec->base, XF_MM(sizeof(*codec)), core);
+
+ TRACE(INIT, _b("audio-codec[%p@%u] destroyed"), codec, core);
+
+ /* ...indicate the client has been destroyed */
+ return 0;
+}
+
+/* ...audio codec destructor - first stage (ports unrouting) */
+static int xa_audio_codec_cleanup(xf_component_t *component, xf_message_t *m)
+{
+ XAAudioCodec *codec = (XAAudioCodec *) component;
+
+ /* ...complete message with error response */
+ xf_response_err(m);
+
+ /* ...cancel internal scheduling message if needed */
+ xa_base_cancel(&codec->base);
+
+ /* ...purge input port (returns OK? pretty strange at this point - tbd) */
+ xf_input_port_purge(&codec->input);
+
+ /* ...propagate unregister command to connected component */
+ if (xf_output_port_flush(&codec->output, XF_FLUSH))
+ {
+ /* ...flushing sequence is not needed; destroy audio codec */
+ return xa_audio_codec_destroy(component, NULL);
+ }
+ else
+ {
+ /* ...wait until output port is cleaned; adjust component hooks */
+ component->entry = xa_audio_codec_terminate;
+ component->exit = xa_audio_codec_destroy;
+
+ TRACE(INIT, _b("codec[%p] cleanup sequence started"), codec);
+
+ /* ...indicate that second stage is required */
+ return 1;
+ }
+}
+
+/*******************************************************************************
+ * Audio codec component factory
+ ******************************************************************************/
+
+xf_component_t * xa_audio_codec_factory(u32 core, xa_codec_func_t process)
+{
+ XAAudioCodec *codec;
+
+ /* ...allocate local memory for codec structure */
+ XF_CHK_ERR(codec = (XAAudioCodec *) xa_base_factory(core, XF_MM(sizeof(*codec)), process), NULL);
+
+ /* ...set base codec API methods */
+ codec->base.memtab = xa_codec_memtab;
+ codec->base.preprocess = xa_codec_preprocess;
+ codec->base.postprocess = xa_codec_postprocess;
+ codec->base.getparam = xa_codec_getparam;
+
+ /* ...set message commands processing table */
+ codec->base.command = xa_codec_cmd;
+ codec->base.command_num = XA_CODEC_CMD_NUM;
+
+ /* ...set component destructor hook */
+ codec->base.component.exit = xa_audio_codec_cleanup;
+
+ TRACE(INIT, _b("Codec[%p] initialized"), codec);
+
+ return (xf_component_t *) codec;
+}
diff --git a/hifi/xaf/hifi-dpf/audio/xa-class-base.c b/hifi/xaf/hifi-dpf/audio/xa-class-base.c
new file mode 100644
index 00000000..0b672553
--- /dev/null
+++ b/hifi/xaf/hifi-dpf/audio/xa-class-base.c
@@ -0,0 +1,537 @@
+/*******************************************************************************
+* Copyright (C) 2018 Cadence Design Systems, Inc.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to use this Software with Cadence processor cores only and
+* not with any other processors and platforms, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************************/
+
+/*******************************************************************************
+ * xa-class-base.c
+ *
+ * Generic audio codec task implementation
+ *
+ ******************************************************************************/
+
+#define MODULE_TAG BASE
+
+/*******************************************************************************
+ * Includes
+ ******************************************************************************/
+
+#include "xf.h"
+#include "xa-class-base.h"
+
+/*******************************************************************************
+ * Tracing configuration
+ ******************************************************************************/
+
+TRACE_TAG(INIT, 1);
+TRACE_TAG(WARNING, 1);
+TRACE_TAG(SETUP, 1);
+TRACE_TAG(EXEC, 1);
+
+/*******************************************************************************
+ * Internal functions definitions
+ ******************************************************************************/
+
+/* ...codec pre-initialization */
+static XA_ERRORCODE xa_base_preinit(XACodecBase *base, u32 core)
+{
+ WORD32 n;
+
+ /* ...codec must be empty */
+ XF_CHK_ERR(base->state == 0, XA_API_FATAL_INVALID_CMD);
+
+ /* ...get API structure size */
+ XA_API(base, XA_API_CMD_GET_API_SIZE, 0, &n);
+
+ /* ...allocate memory for codec API structure (4-bytes aligned) */
+ XMALLOC(&base->api, n, 4, core);
+
+ /* ...set default config parameters */
+ XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL);
+
+ /* ...get memory info tables size */
+ if (XA_API(base, XA_API_CMD_GET_MEMTABS_SIZE, 0, &n), n != 0)
+ {
+ /* ...allocate memory for tables (4-bytes aligned) */
+ XMALLOC(&base->mem_tabs, n, 4, core);
+
+ /* ...set pointer for process memory tables */
+ XA_API(base, XA_API_CMD_SET_MEMTABS_PTR, 0, base->mem_tabs.addr);
+ }
+
+ TRACE(INIT, _b("Codec[%p] pre-initialization completed"), base);
+
+ return XA_NO_ERROR;
+}
+
+/* ...post-initialization setup */
+static XA_ERRORCODE xa_base_postinit(XACodecBase *base, u32 core)
+{
+ WORD32 n, i;
+
+ /* ...issue post-config command and determine the buffer requirements */
+ XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, NULL);
+
+ /* ...get number of memory tables required */
+ XA_API(base, XA_API_CMD_GET_N_MEMTABS, 0, &n);
+
+ /* ...set scratch buffer in advance (as codec not necessarily exposes it) */
+ base->scratch = XF_CORE_DATA(core)->scratch;
+
+ /* ...allocate memory buffers */
+ for (i = 0; i < n; i++)
+ {
+ WORD32 size, align, type;
+
+ TRACE(1, _b("i = %u (of %u)"), (u32)i, (u32)n);
+
+ /* ...get memory type */
+ XA_API(base, XA_API_CMD_GET_MEM_INFO_TYPE, i, &type);
+
+ /* ...get memory size of i-th buffer */
+ XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, i, &size);
+
+ /* ...get alignment */
+ XA_API(base, XA_API_CMD_GET_MEM_INFO_ALIGNMENT, i, &align);
+
+ /* ...process individual buffer */
+ switch (type)
+ {
+ case XA_MEMTYPE_SCRATCH:
+ /* ...scratch memory is shared among all codecs; check its validity */
+ XF_CHK_ERR(size <= XF_CFG_CODEC_SCRATCHMEM_SIZE, XA_API_FATAL_MEM_ALLOC);
+
+ /* ...make sure alignment is sane */
+ XF_CHK_ERR((XF_CFG_CODEC_SCRATCHMEM_ALIGN & (align - 1)) == 0, XA_API_FATAL_MEM_ALIGN);
+
+ /* ...set the scratch memory pointer */
+ XA_API(base, XA_API_CMD_SET_MEM_PTR, i, base->scratch);
+
+ TRACE(INIT, _b("Mem tab %d: sz=%d al=%d ty=%d Scratch memory (%p)"), i, size, align, type, base->scratch);
+
+ break;
+
+ case XA_MEMTYPE_PERSIST:
+ /* ...allocate persistent memory */
+ XMALLOC(&base->persist, size, align, core);
+
+ /* ...and set the pointer instantly */
+ XA_API(base, XA_API_CMD_SET_MEM_PTR, i, base->persist.addr);
+
+ TRACE(INIT, _b("Mem tab %d: sz=%d al=%d ty=%d Persistent memory (%p)"), i, size, align, type, base->persist.addr);
+
+ break;
+
+ case XA_MEMTYPE_INPUT:
+ case XA_MEMTYPE_OUTPUT:
+ /* ...input/output buffer specification; pass to codec function */
+ CODEC_API(base, memtab, i, type, size, align, core);
+
+ break;
+
+ default:
+ /* ...unrecognized memory type */
+ TRACE(ERROR, _x("Invalid memory type: [%d]=(%u, %u, %u)"), i, type, size, align);
+ return XA_API_FATAL_INVALID_CMD_TYPE;
+ }
+ }
+
+ TRACE(INIT, _b("Codec[%p] post-initialization completed (api:%p[%u])"), base, base->api.addr, base->api.size);
+
+ return XA_NO_ERROR;
+}
+
+/*******************************************************************************
+ * Commands processing
+ ******************************************************************************/
+
+/* ...SET-PARAM processing (enabled in all states) */
+XA_ERRORCODE xa_base_set_param(XACodecBase *base, xf_message_t *m)
+{
+ xf_set_param_msg_t *cmd = m->buffer;
+ xf_set_param_item_t *param = &cmd->item[0];
+ WORD32 n, i;
+
+ /* ...calculate total amount of parameters */
+ n = m->length / sizeof(*param);
+
+ /* ...check the message length is sane */
+ XF_CHK_ERR(m->length == XF_SET_PARAM_CMD_LEN(n), XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...apply all parameters; pass to codec-specific function */
+ for (i = 0; i < n; i++)
+ {
+ TRACE(SETUP, _b("set-param[%p]: [%u]=%u"), base, param[i].id, param[i].value);
+
+ if (base->setparam)
+ {
+ CODEC_API(base, setparam, param[i].id, &param[i].value);
+ }
+ else
+ {
+ XA_API(base, XA_API_CMD_SET_CONFIG_PARAM, param[i].id, &param[i].value);
+ }
+ }
+
+ /* ...check if we need to do post-initialization */
+ if ((base->state & XA_BASE_FLAG_POSTINIT) == 0)
+ {
+ /* ...do post-initialization step */
+ XA_CHK(xa_base_postinit(base, XF_MSG_DST_CORE(m->id)));
+
+ /* ...mark the codec static configuration is set */
+ base->state ^= XA_BASE_FLAG_POSTINIT | XA_BASE_FLAG_RUNTIME_INIT;
+ }
+
+ /* ...complete message processing; output buffer is empty */
+ xf_response_ok(m);
+
+ return XA_NO_ERROR;
+}
+
+/* ...GET-PARAM message processing (enabled in all states) */
+XA_ERRORCODE xa_base_get_param(XACodecBase *base, xf_message_t *m)
+{
+ xf_get_param_msg_t *cmd = m->buffer;
+ u32 *id = &cmd->c.id[0];
+ u32 *value = &cmd->r.value[0];
+ u32 n, i;
+
+ /* ...calculate amount of parameters */
+ n = m->length / sizeof(*id);
+
+ /* ...check input parameter length */
+ XF_CHK_ERR(XF_GET_PARAM_CMD_LEN(n) == m->length, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...retrieve the collection of codec parameters */
+ for (i = 0; i < n; i++)
+ {
+ /* ...place the result into same location */
+ if (base->getparam)
+ {
+ CODEC_API(base, getparam, id[i], &value[i]);
+ }
+ else
+ {
+ XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, id[i], &value[i]);
+ }
+ }
+
+ /* ...complete message specifying output buffer size */
+ xf_response_data(m, XF_GET_PARAM_RSP_LEN(n));
+
+ return XA_NO_ERROR;
+}
+
+/* ...SET-PARAM-EXT processing (enabled in all states) */
+XA_ERRORCODE xa_base_set_param_ext(XACodecBase *base, xf_message_t *m)
+{
+ xf_ext_param_msg_t *cmd = m->buffer;
+ u16 length = m->length;
+ u16 remaining = (length + 3) & ~3;
+ u16 i;
+
+ for (i = 0; TRACE_CFG(SETUP) && i < remaining; i += 16)
+ {
+ TRACE(SETUP, _b("[%03x]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X"),
+ i,
+ ((u8 *)m->buffer)[i + 0], ((u8 *)m->buffer)[i + 1],
+ ((u8 *)m->buffer)[i + 2], ((u8 *)m->buffer)[i + 3],
+ ((u8 *)m->buffer)[i + 4], ((u8 *)m->buffer)[i + 5],
+ ((u8 *)m->buffer)[i + 6], ((u8 *)m->buffer)[i + 7],
+ ((u8 *)m->buffer)[i + 8], ((u8 *)m->buffer)[i + 9],
+ ((u8 *)m->buffer)[i + 10], ((u8 *)m->buffer)[i + 11],
+ ((u8 *)m->buffer)[i + 12], ((u8 *)m->buffer)[i + 13],
+ ((u8 *)m->buffer)[i + 14], ((u8 *)m->buffer)[i + 15]);
+ }
+
+ /* ...process all parameters encapsulated in buffer */
+ while (remaining >= sizeof(*cmd))
+ {
+ u16 id = cmd->desc.id;
+ u16 dlen = cmd->desc.length;
+ u16 dsize = (dlen + 3) & ~3;
+ u16 pad = dlen & 3;
+
+ /* ...cut-off descriptor header */
+ remaining -= sizeof(*cmd);
+
+ TRACE(SETUP, _b("remaining:%u, desc_size:%u"), (u32)remaining, (u32)dsize);
+
+ /* ...make sure length is sufficient */
+ XF_CHK_ERR(remaining >= dsize, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...pad remaining bytes with zeroes */
+ (pad ? memset(cmd->data + dlen, 0, 4 - pad) : 0);
+
+ TRACE(SETUP, _b("set-ext-param[%p]: [%u]:%u - [%02X:%02X:%02X:%02X:...]"), base, id, dsize, cmd->data[0], cmd->data[1], cmd->data[2], cmd->data[3]);
+
+ /* ...apply parameter */
+ XA_API(base, XA_API_CMD_SET_CONFIG_PARAM, id, cmd->data);
+
+ /* ...move to next item (keep 4-bytes alignment for descriptor) */
+ cmd = (xf_ext_param_msg_t *)(&cmd->data[0] + dsize), remaining -= dsize;
+ }
+
+ /* ...check the message is fully processed */
+ XF_CHK_ERR(remaining == 0, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...complete message processing; output buffer is empty */
+ //xf_response_ok(m);
+
+ /* ...unfortunately, it looks like a bug of the library that updates the memory
+ * and leaves it in a dirty state causing subsequent cache inconsistency - tbd
+ */
+ xf_response_data(m, length);
+
+ return XA_NO_ERROR;
+}
+
+/* ...GET-PARAM-EXT message processing (enabled in all states) */
+XA_ERRORCODE xa_base_get_param_ext(XACodecBase *base, xf_message_t *m)
+{
+ xf_ext_param_msg_t *cmd = m->buffer;
+ u32 length = m->length;
+ u32 remaining = (length + 3) & ~3;
+ int i;
+
+ for (i = 0; TRACE_CFG(SETUP) && i < remaining; i += 16)
+ {
+ TRACE(SETUP, _b("[%03x]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X"),
+ i,
+ ((u8 *)m->buffer)[i + 0], ((u8 *)m->buffer)[i + 1],
+ ((u8 *)m->buffer)[i + 2], ((u8 *)m->buffer)[i + 3],
+ ((u8 *)m->buffer)[i + 4], ((u8 *)m->buffer)[i + 5],
+ ((u8 *)m->buffer)[i + 6], ((u8 *)m->buffer)[i + 7],
+ ((u8 *)m->buffer)[i + 8], ((u8 *)m->buffer)[i + 9],
+ ((u8 *)m->buffer)[i + 10], ((u8 *)m->buffer)[i + 11],
+ ((u8 *)m->buffer)[i + 12], ((u8 *)m->buffer)[i + 13],
+ ((u8 *)m->buffer)[i + 14], ((u8 *)m->buffer)[i + 15]);
+ }
+
+ /* ...process all parameters encapsulated in buffer */
+ while (remaining >= sizeof(*cmd))
+ {
+ u16 id = cmd->desc.id;
+ u16 len = cmd->desc.length;
+ u16 size = (len + 3) & ~3;
+ u8 pad = len & 3;
+
+ /* ...cut-off command header */
+ remaining -= sizeof(*cmd);
+
+ /* ...make sure data buffer has sufficient length */
+ XF_CHK_ERR(remaining >= size, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...retrieve parameter from buffer (care about alignment? - tbd) */
+ XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, id, cmd->data);
+
+ /* ...pad remaininig bytes with zeroes */
+ (pad ? memset(cmd->data + len, 0, 4 - pad) : 0);
+
+ TRACE(SETUP, _b("get-ext-param[%p]: [%u]:%u - [%02X:%02X:%02X:%02X:...]"), base, id, size, cmd->data[0], cmd->data[1], cmd->data[2], cmd->data[3]);
+
+ /* ...move to next item (alignment issues? - tbd) */
+ cmd = (xf_ext_param_msg_t *)(&cmd->data[0] + size), remaining -= size;
+ }
+
+ /* ...check the message is fully processed */
+ XF_CHK_ERR(remaining == 0, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...complete message processing; output buffer has the same length */
+ xf_response_data(m, length);
+
+ return XA_NO_ERROR;
+}
+
+/*******************************************************************************
+ * Command/data processing functions
+ ******************************************************************************/
+
+/* ...generic codec data processing */
+static XA_ERRORCODE xa_base_process(XACodecBase *base)
+{
+ XA_ERRORCODE error;
+ WORD32 done;
+
+ /* ...clear internal scheduling flag */
+ base->state &= ~XA_BASE_FLAG_SCHEDULE;
+
+ /* ...codec-specific preprocessing (buffer maintenance) */
+ if ((error = CODEC_API(base, preprocess)) != XA_NO_ERROR)
+ {
+ /* ...return non-fatal codec error */
+ return error;
+ }
+
+ /* ...execution step */
+ if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
+ {
+ /* ...kick initialization process */
+ XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_PROCESS, NULL);
+
+ /* ...check if initialization is completed */
+ XA_API(base, XA_API_CMD_INIT, XA_CMD_TYPE_INIT_DONE_QUERY, &done);
+
+ TRACE(EXEC, _b("Initialization result: %d"), done);
+
+ /* ...switch to execution state if required */
+ (done ? base->state ^= XA_BASE_FLAG_RUNTIME_INIT | XA_BASE_FLAG_EXECUTION : 0);
+ }
+ else if (base->state & XA_BASE_FLAG_EXECUTION)
+ {
+ TRACE(1, _b("do exec"));
+
+ /* ...execute decoding process */
+ XA_API(base, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DO_EXECUTE, NULL);
+
+ /* ...check for end-of-stream condition */
+ XA_API(base, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DONE_QUERY, &done);
+
+ TRACE(EXEC, _b("Execution result: %d"), done);
+
+ /* ...mark the output path is done to release all queued buffers */
+ (done ? base->state ^= XA_BASE_FLAG_EXECUTION | XA_BASE_FLAG_COMPLETED : 0);
+ }
+
+ /* ...codec-specific buffer post-processing */
+ return CODEC_API(base, postprocess, done);
+}
+
+/* ...message-processing function (component entry point) */
+static int xa_base_command(xf_component_t *component, xf_message_t *m)
+{
+ XACodecBase *base = (XACodecBase *) component;
+ u32 cmd;
+
+ /* ...invoke data-processing function if message is null */
+ if (m == NULL)
+ {
+ XF_CHK_ERR(!XA_ERROR_SEVERITY(xa_base_process(base)), -EPIPE);
+ return 0;
+ }
+
+ /* ...process the command */
+ TRACE(EXEC, _b("[%p]:state[%X]:(%X, %d, %p)"), base, base->state, m->opcode, m->length, m->buffer);
+
+ /* ...bail out if this is forced termination command (I do have a map; maybe I'd better have a hook? - tbd) */
+ if ((cmd = XF_OPCODE_TYPE(m->opcode)) == XF_OPCODE_TYPE(XF_UNREGISTER))
+ {
+ TRACE(INIT, _b("force component[%p] termination"), base);
+ return -1;
+ }
+
+ /* ...check opcode is valid */
+ XF_CHK_ERR(cmd < base->command_num, -EINVAL);
+
+ /* ...and has a hook */
+ XF_CHK_ERR(base->command[cmd] != NULL, -EINVAL);
+
+ /* ...pass control to specific command */
+ XF_CHK_ERR(!XA_ERROR_SEVERITY(base->command[cmd](base, m)), -EPIPE);
+
+ /* ...execution completed successfully */
+ return 0;
+}
+
+/*******************************************************************************
+ * Base codec API
+ ******************************************************************************/
+
+/* ...data processing scheduling */
+void xa_base_schedule(XACodecBase *base, u32 dts)
+{
+ if ((base->state & XA_BASE_FLAG_SCHEDULE) == 0)
+ {
+ /* ...schedule component task execution */
+ xf_component_schedule(&base->component, dts);
+
+ /* ...and put scheduling flag */
+ base->state ^= XA_BASE_FLAG_SCHEDULE;
+ }
+ else
+ {
+ TRACE(EXEC, _b("codec[%p] processing pending"), base);
+ }
+}
+
+/* ...cancel data processing */
+void xa_base_cancel(XACodecBase *base)
+{
+ if (base->state & XA_BASE_FLAG_SCHEDULE)
+ {
+ /* ...cancel scheduled codec task */
+ xf_component_cancel(&base->component);
+
+ /* ...and clear scheduling flag */
+ base->state ^= XA_BASE_FLAG_SCHEDULE;
+
+ TRACE(EXEC, _b("codec[%p] processing cancelled"), base);
+ }
+}
+
+/* ...base codec destructor */
+void xa_base_destroy(XACodecBase *base, u32 size, u32 core)
+{
+ /* ...deallocate all resources */
+ xf_mm_free_buffer(&base->persist, core);
+ xf_mm_free_buffer(&base->mem_tabs, core);
+ xf_mm_free_buffer(&base->api, core);
+
+ /* ...destroy codec structure (and task) itself */
+ xf_mem_free(base, size, core, 0);
+
+ TRACE(INIT, _b("codec[%p]:%u destroyed"), base, core);
+}
+
+/* ...generic codec initialization routine */
+XACodecBase * xa_base_factory(u32 core, u32 size, xa_codec_func_t process)
+{
+ XACodecBase *base;
+
+ /* ...make sure the size is sane */
+ XF_CHK_ERR(size >= sizeof(XACodecBase), NULL);
+
+ /* ...allocate local memory for codec structure */
+ XF_CHK_ERR(base = xf_mem_alloc(size, 0, core, 0), NULL);
+
+ /* ...reset codec memory */
+ memset(base, 0, size);
+
+ /* ...set low-level codec API function */
+ base->process = process;
+
+ /* ...set message processing function */
+ base->component.entry = xa_base_command;
+
+ /* ...do basic initialization */
+ if (xa_base_preinit(base, core) != XA_NO_ERROR)
+ {
+ /* ...initialization failed for some reason; do cleanup */
+ xa_base_destroy(base, size, core);
+
+ return NULL;
+ }
+
+ /* ...initialization completed successfully */
+ TRACE(INIT, _b("Codec[%p]:%u initialized"), base, core);
+
+ return base;
+}
diff --git a/hifi/xaf/hifi-dpf/audio/xa-class-base.h b/hifi/xaf/hifi-dpf/audio/xa-class-base.h
new file mode 100644
index 00000000..252044d4
--- /dev/null
+++ b/hifi/xaf/hifi-dpf/audio/xa-class-base.h
@@ -0,0 +1,263 @@
+/*******************************************************************************
+* Copyright (C) 2018 Cadence Design Systems, Inc.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to use this Software with Cadence processor cores only and
+* not with any other processors and platforms, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************************/
+
+/*******************************************************************************
+ * xa-class-base.h
+ *
+ * Generic Xtensa Audio codecs interfaces
+ *
+ ******************************************************************************/
+
+#ifndef __XA_CLASS_BASE_H
+#define __XA_CLASS_BASE_H
+
+/*******************************************************************************
+ * Includes
+ ******************************************************************************/
+
+/* ...audio-specific API */
+#include "audio/xa_type_def.h"
+#include "audio/xa_error_standards.h"
+#include "audio/xa_apicmd_standards.h"
+#include "audio/xa_memory_standards.h"
+
+/*******************************************************************************
+ * Generic codec structure
+ ******************************************************************************/
+
+typedef struct XACodecBase XACodecBase;
+
+/* ...memory buffer initialization */
+typedef XA_ERRORCODE (*xa_codec_memtab_f)(XACodecBase *codec, WORD32 i, WORD32 type, WORD32 size, WORD32 align, u32 core);
+
+/* ...preprocessing operation */
+typedef XA_ERRORCODE (*xa_codec_preprocess_f)(XACodecBase *);
+
+/* ...postprocessing operation */
+typedef XA_ERRORCODE (*xa_codec_postprocess_f)(XACodecBase *, int);
+
+/* ...parameter setting function */
+typedef XA_ERRORCODE (*xa_codec_setparam_f)(XACodecBase *, WORD32, pVOID p);
+
+/* ...parameter retrival function */
+typedef XA_ERRORCODE (*xa_codec_getparam_f)(XACodecBase *, WORD32, pVOID p);
+
+/*******************************************************************************
+ * Codec instance structure
+ ******************************************************************************/
+
+struct XACodecBase
+{
+ /***************************************************************************
+ * Control data
+ **************************************************************************/
+
+ /* ...generic component handle */
+ xf_component_t component;
+
+ /* ...codec API entry point (function) */
+ xa_codec_func_t *process;
+
+ /* ...codec API handle, passed to *process */
+ xf_mm_buffer_t api;
+
+ /* ...memory table buffer */
+ xf_mm_buffer_t mem_tabs;
+
+ /* ...persistent memory buffer */
+ xf_mm_buffer_t persist;
+
+ /* ...scratch memory pointer */
+ void *scratch;
+
+ /* ...codec control state */
+ u32 state;
+
+ /***************************************************************************
+ * Codec-specific methods
+ **************************************************************************/
+
+ /* ...memory buffer initialization */
+ xa_codec_memtab_f memtab;
+
+ /* ...preprocessing function */
+ xa_codec_preprocess_f preprocess;
+
+ /* ...postprocessing function */
+ xa_codec_postprocess_f postprocess;
+
+ /* ...configuration parameter setting function */
+ xa_codec_setparam_f setparam;
+
+ /* ...configuration parameter retrieval function */
+ xa_codec_getparam_f getparam;
+
+ /* ...command-processing table */
+ XA_ERRORCODE (* const * command)(XACodecBase *, xf_message_t *);
+
+ /* ...command-processing table size */
+ u32 command_num;
+};
+
+/*******************************************************************************
+ * Base codec execution flags
+ ******************************************************************************/
+
+/* ...codec static initialization completed */
+#define XA_BASE_FLAG_POSTINIT (1 << 0)
+
+/* ...codec runtime initialization sequence */
+#define XA_BASE_FLAG_RUNTIME_INIT (1 << 1)
+
+/* ...codec steady execution state */
+#define XA_BASE_FLAG_EXECUTION (1 << 2)
+
+/* ...execution stage completed */
+#define XA_BASE_FLAG_COMPLETED (1 << 3)
+
+/* ...data processing scheduling flag */
+#define XA_BASE_FLAG_SCHEDULE (1 << 4)
+
+/* ...base codec flags accessor */
+#define __XA_BASE_FLAGS(flags) ((flags) & ((1 << 5) - 1))
+
+/* ...custom execution flag */
+#define __XA_BASE_FLAG(f) ((f) << 5)
+
+/*******************************************************************************
+ * Local macros definitions
+ ******************************************************************************/
+
+/* ...audio-framework API function execution */
+#define XA_CHK(cond) \
+({ \
+ XA_ERRORCODE __e = (cond); \
+ if (__e != XA_NO_ERROR) \
+ { \
+ if (XA_ERROR_SEVERITY(__e)) \
+ { \
+ TRACE(ERROR, _x("error: %X"), __e); \
+ return __e; \
+ } \
+ TRACE(WARNING, _x("warning: %X"), __e); \
+ } \
+ __e; \
+})
+
+/* ...low-level codec API function execution */
+#define XA_API(codec, cmd, idx, pv) \
+({ \
+ XA_ERRORCODE __e; \
+ __e = (codec)->process((xa_codec_handle_t)(codec)->api.addr, (cmd), (idx), (pv)); \
+ if (__e != XA_NO_ERROR) \
+ { \
+ if (XA_ERROR_SEVERITY(__e)) \
+ { \
+ TRACE(ERROR, _x("[%p]:(%d, %d, %p): %X"), (codec), (cmd), (idx), (pv), __e); \
+ return __e; \
+ } \
+ TRACE(WARNING, _x("%X"), __e); \
+ } \
+ __e; \
+})
+
+#define XA_API_NORET(codec, cmd, idx, pv) \
+({ \
+ XA_ERRORCODE __e; \
+ __e = (codec)->process((xa_codec_handle_t)(codec)->api.addr, (cmd), (idx), (pv)); \
+ if (__e != XA_NO_ERROR) \
+ { \
+ if (XA_ERROR_SEVERITY(__e)) \
+ { \
+ TRACE(ERROR, _x("[%p]:(%d, %d, %p): %X"), (codec), (cmd), (idx), (pv), __e); \
+ } \
+ TRACE(WARNING, _x("%X"), __e); \
+ } \
+ __e; \
+})
+
+/* ...codec hook invocation */
+#define CODEC_API(codec, func, ...) \
+({ \
+ XA_ERRORCODE __e = (codec)->func((codec), ##__VA_ARGS__); \
+ \
+ if (__e != XA_NO_ERROR) \
+ { \
+ if (XA_ERROR_SEVERITY(__e)) \
+ { \
+ /* ...actual error is reported by the codec */ \
+ TRACE(ERROR, _x("[%p]: " #func ": %X"), (codec), __e); \
+ return __e; \
+ } \
+ \
+ TRACE(WARNING, _x("warning: %X"), __e); \
+ } \
+ __e; \
+})
+
+/* ...allocate local memory on specific core */
+#define XMALLOC(p, size, align, core) \
+do \
+{ \
+ if (xf_mm_alloc_buffer((size), (align), (core), (p)) != 0) \
+ { \
+ TRACE(ERROR, _x("Failed to allocate %d bytes of memory"), (size)); \
+ return XA_API_FATAL_MEM_ALLOC; \
+ } \
+ \
+ if (((u32)((p)->addr) & ((align) - 1)) != 0) \
+ { \
+ TRACE(ERROR, _x("Invalid %d-algnment: %p"), (align), (p)->addr); \
+ return XA_API_FATAL_MEM_ALIGN; \
+ } \
+} \
+while (0)
+
+/*******************************************************************************
+ * Public API
+ ******************************************************************************/
+
+/* ...SET-PARAM processing */
+extern XA_ERRORCODE xa_base_set_param(XACodecBase *base, xf_message_t *m);
+
+/* ...GET-PARAM-EXT message processing */
+extern XA_ERRORCODE xa_base_set_param_ext(XACodecBase *base, xf_message_t *m);
+
+/* ...GET-PARAM message processing */
+extern XA_ERRORCODE xa_base_get_param(XACodecBase *base, xf_message_t *m);
+
+/* ...GET-PARAM-EXT message processing */
+extern XA_ERRORCODE xa_base_get_param_ext(XACodecBase *base, xf_message_t *m);
+
+/* ...data processing scheduling */
+extern void xa_base_schedule(XACodecBase *base, u32 dts);
+
+/* ...cancel internal scheduling message */
+extern void xa_base_cancel(XACodecBase *base);
+
+/* ...base codec factory */
+extern XACodecBase * xa_base_factory(u32 core, u32 size, xa_codec_func_t process);
+
+/* ...base codec destructor */
+extern void xa_base_destroy(XACodecBase *base, u32 size, u32 core);
+
+#endif /* __XA_CLASS_BASE_H */
diff --git a/hifi/xaf/hifi-dpf/audio/xa-class-mixer.c b/hifi/xaf/hifi-dpf/audio/xa-class-mixer.c
new file mode 100644
index 00000000..ac2ff9ad
--- /dev/null
+++ b/hifi/xaf/hifi-dpf/audio/xa-class-mixer.c
@@ -0,0 +1,870 @@
+/*******************************************************************************
+* Copyright (C) 2018 Cadence Design Systems, Inc.
+*
+* Permission is hereby granted, free of charge, to any person obtaining
+* a copy of this software and associated documentation files (the
+* "Software"), to use this Software with Cadence processor cores only and
+* not with any other processors and platforms, subject to
+* the following conditions:
+*
+* The above copyright notice and this permission notice shall be included
+* in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************************/
+
+/*******************************************************************************
+ * xa-class-mixer.c
+ *
+ * Generic mixer component class
+ *
+ ******************************************************************************/
+
+#define MODULE_TAG MIXER
+
+/*******************************************************************************
+ * Includes
+ ******************************************************************************/
+
+#include "xf.h"
+#include "xa-class-base.h"
+#include "audio/xa-mixer-api.h"
+
+/*******************************************************************************
+ * Tracing tags
+ ******************************************************************************/
+
+TRACE_TAG(INIT, 1);
+TRACE_TAG(WARNING, 1);
+TRACE_TAG(INFO, 1);
+TRACE_TAG(INPUT, 1);
+TRACE_TAG(OUTPUT, 1);
+
+/*******************************************************************************
+ * Data structures
+ ******************************************************************************/
+
+/* ...mixed source - input data */
+typedef struct XATrack
+{
+ /* ...input port data */
+ xf_input_port_t input;
+
+ /* ...current presentation timestamp (in samples; local to a mixer state) */
+ u32 pts;
+
+ /* ...total amount of decoded frames since last synchronization point */
+ u32 decoded;
+
+ /* ...total amount of rendered frames (consumed) since last synchronization point */
+ u32 rendered;
+
+} XATrack;
+
+/*******************************************************************************
+ * Helpers
+ ******************************************************************************/
+
+static inline u32 xa_track_test_flags(XATrack *track, u32 flags)
+{
+ return (track->input.flags & flags);
+}
+
+static inline u32 xa_track_set_flags(XATrack *track, u32 flags)
+{
+ return (track->input.flags |= flags);
+}
+
+static inline u32 xa_track_clear_flags(XATrack *track, u32 flags)
+{
+ return (track->input.flags &= ~flags);
+}
+
+static inline u32 xa_track_toggle_flags(XATrack *track, u32 flags)
+{
+ return (track->input.flags ^= flags);
+}
+
+/*******************************************************************************
+ * Mixer data definitions
+ ******************************************************************************/
+
+/* ...mixer data */
+typedef struct XAMixer
+{
+ /***************************************************************************
+ * Control data
+ **************************************************************************/
+
+ /* ...generic audio codec data */
+ XACodecBase base;
+
+ /* ...input tracks */
+ XATrack track[XA_MIXER_MAX_TRACK_NUMBER];
+
+ /* ...output port */
+ xf_output_port_t output;
+
+ /***************************************************************************
+ * Run-time configuration parameters
+ **************************************************************************/
+
+ /* ...audio frame size in samples */
+ u32 frame_size;
+
+ /* ...audio frame duration */
+ u32 frame_duration;
+
+ /* ...presentation timestamp (in samples; local mixer scope) */
+ u32 pts;
+
+} XAMixer;
+
+/*******************************************************************************
+ * Mixer flags
+ ******************************************************************************/
+
+/* ...output port setup completed */
+#define XA_MIXER_FLAG_OUTPUT_SETUP __XA_BASE_FLAG(1 << 0)
+
+/*******************************************************************************
+ * Track state flags
+ ******************************************************************************/
+
+/* ...track is idle (will autostart as soon as input data received) */
+#define XA_TRACK_FLAG_IDLE __XF_INPUT_FLAG(1 << 0)
+
+/* ...track is rendered */
+#define XA_TRACK_FLAG_ACTIVE __XF_INPUT_FLAG(1 << 1)
+
+/* ...track is paused */
+#define XA_TRACK_FLAG_PAUSED __XF_INPUT_FLAG(1 << 2)
+
+/* ...track input port is setup */
+#define XA_TRACK_FLAG_INPUT_SETUP __XF_INPUT_FLAG(1 << 3)
+
+/* ...track has received data */
+#define XA_TRACK_FLAG_RECVD_DATA __XF_INPUT_FLAG(1 << 4)
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+/* ...Count the tracks that have received data or are active*/
+static inline UWORD32 xa_mixer_check_active(XAMixer *mixer)
+{
+ XATrack *track;
+ UWORD32 i;
+ UWORD32 cnt = 0;
+
+ for (track = &mixer->track[i = 0]; i < XA_MIXER_MAX_TRACK_NUMBER; i++, track++)
+ {
+ if (xa_track_test_flags(track, XA_TRACK_FLAG_RECVD_DATA | XA_TRACK_FLAG_ACTIVE))
+ cnt++;
+ }
+ return cnt;
+}
+
+/* ...prepare mixer for steady operation */
+static inline XA_ERRORCODE xa_mixer_prepare_runtime(XAMixer *mixer)
+{
+ XACodecBase *base = (XACodecBase *) mixer;
+ xf_message_t *m = xf_msg_dequeue(&mixer->output.queue);
+ xf_start_msg_t *msg = m->buffer;
+ u32 frame_size;
+ u32 factor;
+
+ /* ...query mixer parameters */
+ XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_MIXER_CONFIG_PARAM_SAMPLE_RATE, &msg->sample_rate);
+ XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_MIXER_CONFIG_PARAM_CHANNELS, &msg->channels);
+ XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_MIXER_CONFIG_PARAM_PCM_WIDTH, &msg->pcm_width);
+ XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, 0, &msg->input_length);
+ XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, XA_MIXER_MAX_TRACK_NUMBER, &msg->output_length);
+ XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_MIXER_CONFIG_PARAM_FRAME_SIZE, &frame_size);
+
+ /* ...calculate mixer frame duration; get upsample factor */
+ XF_CHK_ERR(factor = xf_timebase_factor(msg->sample_rate), XA_MIXER_CONFIG_FATAL_RANGE);
+
+ /* ...set mixer frame duration */
+ mixer->frame_duration = frame_size * factor;
+
+ /* ...pass response to caller */
+ xf_response_data(m, sizeof(*msg));
+
+ return XA_NO_ERROR;
+}
+
+/*******************************************************************************
+ * Commands handlers
+ ******************************************************************************/
+
+/* ...EMPTY-THIS-BUFFER command processing */
+static XA_ERRORCODE xa_mixer_empty_this_buffer(XACodecBase *base, xf_message_t *m)
+{
+ XAMixer *mixer = (XAMixer *) base;
+ u32 i = XF_MSG_DST_PORT(m->id);
+ XATrack *track = &mixer->track[i];
+
+ /* ...make sure the port is valid */
+ XF_CHK_ERR(i < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...command is allowed only in "postinit" state */
+ XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
+
+ TRACE(INPUT, _b("track-%u: received buffer [%p]:%u"), i, m->buffer, m->length);
+
+ /* ...update received data for the track */
+ if (m->length)
+ xa_track_set_flags(track, XA_TRACK_FLAG_RECVD_DATA);
+ else
+ xa_track_clear_flags(track, XA_TRACK_FLAG_RECVD_DATA);
+
+ /* ...place received message into track input port */
+ if (xf_input_port_put(&track->input, m))
+ {
+ /* ...process track autostart if needed */
+ if (xa_track_test_flags(track, XA_TRACK_FLAG_IDLE))
+ {
+ /* ...put track into active state */
+ xa_track_toggle_flags(track, XA_TRACK_FLAG_IDLE | XA_TRACK_FLAG_ACTIVE);
+
+ /* ...save track presentation timestamp */
+ track->pts = mixer->pts;
+
+ TRACE(INFO, _b("track-%u started (pts=%x)"), i, track->pts);
+ }
+
+ /* ...schedule data processing if there is output port available */
+ if (xf_output_port_ready(&mixer->output))
+ {
+ /* ...force data processing */
+ xa_base_schedule(base, 0);
+ }
+ }
+
+ return XA_NO_ERROR;
+}
+
+/* ...FILL-THIS-BUFFER command processing */
+static XA_ERRORCODE xa_mixer_fill_this_buffer(XACodecBase *base, xf_message_t *m)
+{
+ XAMixer *mixer = (XAMixer *) base;
+ u32 i = XF_MSG_DST_PORT(m->id);
+
+ /* ...make sure the port is valid */
+ XF_CHK_ERR(i == XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...command is allowed only in "postinit" state */
+ XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
+
+ /* ...process runtime initialization explicitly */
+ if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
+ {
+ /* ...message must be zero-length */
+ XF_CHK_ERR(m->length == 0, XA_MIXER_EXEC_FATAL_STATE);
+ }
+ else if (m->length != 0) /* ...EOS response */
+ {
+ /* ...message must have exactly expected size (there is no ordered abortion) */
+ XF_CHK_ERR(m->length == mixer->output.length, XA_MIXER_EXEC_FATAL_STATE);
+ }
+
+ TRACE(OUTPUT, _b("received output buffer [%p]:%u"), m->buffer, m->length);
+
+ /* ...put message into output port */
+ if (xf_output_port_put(&mixer->output, m))
+ {
+ /* ...force data processing */
+ xa_base_schedule(base, 0);
+ }
+
+ return XA_NO_ERROR;
+}
+
+/* ...output port routing */
+static XA_ERRORCODE xa_mixer_port_route(XACodecBase *base, xf_message_t *m)
+{
+ XAMixer *mixer = (XAMixer *) base;
+ xf_route_port_msg_t *cmd = m->buffer;
+ xf_output_port_t *port = &mixer->output;
+ u32 src = XF_MSG_DST(m->id);
+ u32 dst = cmd->dst;
+
+ /* ...command is allowed only in "postinit" state */
+ XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
+
+ /* ...make sure output port is addressed */
+ XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...make sure port is not routed yet */
+ XF_CHK_ERR(!xf_output_port_routed(port), XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...route output port - allocate queue */
+ XF_CHK_ERR(xf_output_port_route(port, __XF_MSG_ID(dst, src), cmd->alloc_number, cmd->alloc_size, cmd->alloc_align) == 0, XA_API_FATAL_MEM_ALLOC);
+
+ /* ...schedule processing instantly - tbd - check if we have anything pending on input */
+ xa_base_schedule(base, 0);
+
+ /* ...pass success result to caller */
+ xf_response_ok(m);
+
+ return XA_NO_ERROR;
+}
+
+/* ...port unroute command */
+static XA_ERRORCODE xa_mixer_port_unroute(XACodecBase *base, xf_message_t *m)
+{
+ XAMixer *mixer = (XAMixer *) base;
+ xf_output_port_t *port = &mixer->output;
+
+ /* ...command is allowed only in "postinit" state */
+ XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
+
+ /* ...make sure output port is addressed */
+ XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...cancel any pending processing */
+ xa_base_cancel(base);
+
+ /* ...clear output-port-setup condition */
+ base->state &= ~XA_MIXER_FLAG_OUTPUT_SETUP;
+
+ /* ...pass flush command down the graph */
+ if (xf_output_port_flush(port, XF_FLUSH))
+ {
+ TRACE(INFO, _b("port is idle; instantly unroute"));
+
+ /* ...flushing sequence is not needed; command may be satisfied instantly */
+ xf_output_port_unroute(port);
+
+ /* ...pass response to the proxy */
+ xf_response_ok(m);
+ }
+ else
+ {
+ TRACE(INFO, _b("port is busy; propagate unroute command"));
+
+ /* ...flushing sequence is started; save flow-control message */
+ xf_output_port_unroute_start(port, m);
+ }
+
+ return XA_NO_ERROR;
+}
+
+/* ...PAUSE message processing */
+static XA_ERRORCODE xa_mixer_pause(XACodecBase *base, xf_message_t *m)
+{
+ XAMixer *mixer = (XAMixer *) base;
+ u32 i = XF_MSG_DST_PORT(m->id);
+ XATrack *track = &mixer->track[i];
+
+ /* ...make sure the buffer is empty */
+ XF_CHK_ERR(m->length == 0, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...check destination port is valid */
+ XF_CHK_ERR(i < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...check for actual track flags */
+ if (xa_track_test_flags(track, XA_TRACK_FLAG_ACTIVE))
+ {
+ /* ...switch to paused state */
+ xa_track_toggle_flags(track, XA_TRACK_FLAG_ACTIVE | XA_TRACK_FLAG_PAUSED);
+
+ /* ...other tracks may be waiting for this one, so force data processing */
+ if (xf_output_port_ready(&mixer->output))
+ {
+ xa_base_schedule(base, 0);
+ }
+
+ TRACE(INFO, _b("mixer[%p]::track[%u] paused"), mixer, i);
+ }
+ else
+ {
+ /* ...track is in idle state and pausing here means suspending */
+ TRACE(INFO, _b("mixer[%p]::track[%u] is not active"), mixer, i);
+ }
+
+ /* ...complete message immediately */
+ xf_response(m);
+
+ return XA_NO_ERROR;
+}
+
+/* ...RESUME command processing */
+static XA_ERRORCODE xa_mixer_resume(XACodecBase *base, xf_message_t *m)
+{
+ XAMixer *mixer = (XAMixer *) base;
+ u32 i = XF_MSG_DST_PORT(m->id);
+ XATrack *track = &mixer->track[i];
+
+ /* ...make sure the buffer is empty */
+ XF_CHK_ERR(m->length == 0, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...check destination port is valid */
+ XF_CHK_ERR(i < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...check for actual track state */
+ if (xa_track_test_flags(track, XA_TRACK_FLAG_PAUSED))
+ {
+ /* ...switch track to active state */
+ xa_track_toggle_flags(track, XA_TRACK_FLAG_ACTIVE | XA_TRACK_FLAG_PAUSED);
+
+ /* ...reset track presentation timestamp - tbd */
+ track->pts = mixer->pts;
+
+ /* ...force data processing if there is an output buffer */
+ if (xf_output_port_ready(&mixer->output))
+ {
+ xa_base_schedule(base, 0);
+ }
+
+ TRACE(INFO, _b("mixer[%p]::track[%u] resumed"), mixer, i);
+ }
+ else
+ {
+ /* ...track is in idle state; do nothing */
+ TRACE(INFO, _b("mixer[%p]::track[%u] is not paused"), mixer, i);
+ }
+
+ /* ...complete message */
+ xf_response(m);
+
+ return XA_NO_ERROR;
+}
+
+/* ...FLUSH command processing */
+static XA_ERRORCODE xa_mixer_flush(XACodecBase *base, xf_message_t *m)
+{
+ XAMixer *mixer = (XAMixer *) base;
+ u32 i = XF_MSG_DST_PORT(m->id);
+ XATrack *track = &mixer->track[i];
+
+ /* ...make sure the buffer is empty */
+ XF_CHK_ERR(m->length == 0, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...check destination port index */
+ if (i == XA_MIXER_MAX_TRACK_NUMBER)
+ {
+ /* ...flushing response received; that is a port unrouting sequence */
+ XF_CHK_ERR(xf_output_port_unrouting(&mixer->output), XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...complete unroute sequence */
+ xf_output_port_unroute_done(&mixer->output);
+
+ TRACE(INFO, _b("port is unrouted"));
+
+ return XA_NO_ERROR;
+ }
+
+ /* ...check destination port index is valid */
+ XF_CHK_ERR(i < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...input port flushing; check the track state is valid */
+ if (xa_track_test_flags(track, XA_TRACK_FLAG_ACTIVE | XA_TRACK_FLAG_PAUSED))
+ {
+ /* ...purge input port */
+ xf_input_port_purge(&track->input);
+
+ /* ...force clearing of ACTIVE and INPUT_SETUP condition */
+ xa_track_clear_flags(track, XA_TRACK_FLAG_ACTIVE | XA_TRACK_FLAG_PAUSED | XA_TRACK_FLAG_INPUT_SETUP);
+
+ /* ...and enter into idle state */
+ xa_track_set_flags(track, XA_TRACK_FLAG_IDLE);
+
+ /* ...other tracks may be waiting for this track, so force data processing */
+ if (xf_output_port_ready(&mixer->output))
+ {
+ xa_base_schedule(base, 0);
+ }
+
+ TRACE(INFO, _b("mixer[%p]::track[%u] flushed"), mixer, i);
+ }
+
+ /* ...complete message instantly (no propagation to output port) */
+ xf_response(m);
+
+ return XA_NO_ERROR;
+}
+
+/*******************************************************************************
+ * Codec API implementation
+ ******************************************************************************/
+
+/* ...buffers handling */
+static XA_ERRORCODE xa_mixer_memtab(XACodecBase *base, WORD32 idx, WORD32 type, WORD32 size, WORD32 align, u32 core)
+{
+ XAMixer *mixer = (XAMixer *)base;
+
+ if (type == XA_MEMTYPE_INPUT)
+ {
+ XATrack *track = &mixer->track[idx];
+
+ /* ...input buffer allocation; check track number is sane */
+ XF_CHK_ERR(idx < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...create input port for a track */
+ XF_CHK_ERR(xf_input_port_init(&track->input, size, align, core) == 0, XA_API_FATAL_MEM_ALLOC);
+
+ /* ...set input port buffer */
+ XA_API(base, XA_API_CMD_SET_MEM_PTR, idx, track->input.buffer);
+
+ /* ...put track into idle state (will start as soon as we receive data) */
+ xa_track_set_flags(track, XA_TRACK_FLAG_IDLE);
+
+ TRACE(INIT, _b("mixer[%p]::track[%u] input port created - size=%u"), mixer, idx, size);
+ }
+ else
+ {
+ /* ...output buffer allocation */
+ XF_CHK_ERR(type == XA_MEMTYPE_OUTPUT, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...check port number is what we expect */
+ XF_CHK_ERR(idx == XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
+
+ /* ...set mixer frame-size (in samples - for timestamp tracking) */
+ XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_MIXER_CONFIG_PARAM_FRAME_SIZE, &mixer->frame_size);
+
+ /* ...create output port for a track */
+ XF_CHK_ERR(xf_output_port_init(&mixer->output, size) == 0, XA_API_FATAL_MEM_ALLOC);
+
+ TRACE(INIT, _b("mixer[%p] output port created; size=%u"), mixer, size);
+ }
+
+ return XA_NO_ERROR;
+}
+
+/* ...preprocessing function */
+static XA_ERRORCODE xa_mixer_preprocess(XACodecBase *base)
+{
+ XAMixer *mixer = (XAMixer *) base;
+ XATrack *track;
+ u8 i;
+ XA_ERRORCODE e = XA_MIXER_EXEC_NONFATAL_NO_DATA;
+
+ /* ...prepare output buffer */
+ if (!(base->state & XA_MIXER_FLAG_OUTPUT_SETUP))
+ {
+ void *output;
+
+ /* ...set output buffer pointer */
+ if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
+ {
+ /* ...no actual data processing during initialization */
+ return XA_NO_ERROR;
+ }
+ else if ((output = xf_output_port_data(&mixer->output)) == NULL)
+ {
+ /* ...no output buffer available */
+ return e;
+ }
+
+ /* ...set output buffer pointer */
+ XA_API(base, XA_API_CMD_SET_MEM_PTR, XA_MIXER_MAX_TRACK_NUMBER, output);
+
+ /* ...mark output port is setup */
+ base->state ^= XA_MIXER_FLAG_OUTPUT_SETUP;
+ }
+
+ /* ...check EOS */
+ if (!xa_mixer_check_active(mixer))
+ {
+ /* ...push EOS to output port */
+ xf_output_port_produce(&mixer->output, 0);
+ TRACE(INFO, _b("mixer[%p]::EOS generated"), mixer);
+ }
+
+ /* ...setup input buffer pointers and length */
+ for (track = &mixer->track[i = 0]; i < XA_MIXER_MAX_TRACK_NUMBER; i++, track++)
+ {
+ /* ...skip tracks that are not played */
+ if (!xa_track_test_flags(track, XA_TRACK_FLAG_ACTIVE)) continue;
+
+ /* ...set temporary mixing request */
+ e = XA_NO_ERROR;
+
+ /* ...skip the tracks that has been setup already */
+ if (xa_track_test_flags(track, XA_TRACK_FLAG_INPUT_SETUP)) continue;
+
+ /* ...found active track that hasn't been setup yet */
+ TRACE(INPUT, _b("track-%u: ts=%x vs mts=%x"), i, track->pts, mixer->pts);
+
+ /* ...if track presentation timestamp is in the future, do nothing yet really */
+ if (!xf_time_after(track->pts, mixer->pts))
+ {
+ u32 filled;
+
+ /* ...take actual data from input port (mixer is always using internal buffer) */
+ if (!xf_input_port_fill(&track->input))
+ {
+ /* ...failed to prefill input buffer - no sufficient data yet */
+ return XA_MIXER_EXEC_NONFATAL_NO_DATA;
+ }
+ else
+ {
+ /* ...retrieve number of bytes available */
+ filled = xf_input_port_level(&track->input);
+ }
+
+ /* ...set total number of bytes we have in buffer */
+ XA_API(base, XA_API_CMD_SET_INPUT_BYTES, i, &filled);
+
+ /* ...actual data is to be played */
+ TRACE(INPUT, _b("track-%u: filled %u bytes"), i, filled);
+ }
+
+ /* ...mark the track input is setup (emit silence or actual data) */
+ xa_track_set_flags(track, XA_TRACK_FLAG_INPUT_SETUP);
+ }
+
+ /* ...do mixing operation only when all active tracks are setup */
+ return e;
+}
+
+/* ...postprocessing function */
+static XA_ERRORCODE xa_mixer_postprocess(XACodecBase *base, int done)
+{
+ XAMixer *mixer = (XAMixer *) base;
+ XATrack *track;
+ u32 produced;
+ u32 consumed;
+ u8 i;
+
+ /* ...process execution stage transitions */
+ if (done)
+ {
+ if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
+ {
+ /* ...failed to initialize runtime (can't be? - tbd)*/
+ BUG(1, _x("breakpoint"));
+ }
+ else if (base->state & XA_BASE_FLAG_EXECUTION)
+ {
+ /* ...enter into execution state; initialize runtime */
+ return XA_CHK(xa_mixer_prepare_runtime(mixer));
+ }
+ else
+ {
+ /* ...mixer operation is over (can't be? - tbd) */
+ BUG(1, _x("breakpoint"));
+ }
+ }
+
+ /* ...input ports maintenance; process all tracks */
+ for (track = &mixer->track[i = 0]; i < XA_MIXER_MAX_TRACK_NUMBER; i++, track++)
+ {
+ /* ...skip the tracks that are not runing */
+ if (!xa_track_test_flags(track, XA_TRACK_FLAG_ACTIVE)) continue;
+
+ /* ...clear input setup flag */
+ xa_track_clear_flags(track, XA_TRACK_FLAG_INPUT_SETUP);
+
+ /* ...advance track presentation timestamp */
+ track->pts += mixer->frame_size;
+
+ /* ...get total amount of consumed bytes */
+ XA_API(base, XA_API_CMD_GET_CURIDX_INPUT_BUF, i, &consumed);
+
+ TRACE(INPUT, _b("track-%u::postprocess(c=%u, ts=%x)"), i, consumed, track->pts);
+
+ /* ...consume that amount from input port (may be zero) */
+ xf_input_port_consume(&track->input, consumed);
+
+ /* ...check if input port is done */
+ if (xf_input_port_done(&track->input))
+ {
+ /* ...input stream is over; return zero-length input back to caller */
+ xf_input_port_purge(&track->input);
+
+ /* ...switch to idle state */
+ xa_track_toggle_flags(track, XA_TRACK_FLAG_ACTIVE | XA_TRACK_FLAG_IDLE);
+
+ TRACE(INFO, _b("mixer[%p]::track[%u] completed"), mixer, i);
+ }
+ }
+
+ /* ...check if we have produced anything */
+ XA_API(base, XA_API_CMD_GET_OUTPUT_BYTES, XA_MIXER_MAX_TRACK_NUMBER, &produced);
+
+ TRACE(OUTPUT, _b("mixer[%p]::postprocess(p=%u, ts=%x, done=%u)"), mixer, produced, mixer->pts, done);
+
+ /* ...output port maintenance */
+ if (produced)
+ {
+ /* ...make sure we have produced exactly single frame */
+ BUG(produced != mixer->output.length, _x("Invalid length: %u != %u"), produced, mixer->output.length);
+
+ /* ...steady mixing process; advance mixer presentation timestamp */
+ mixer->pts += mixer->frame_size;
+
+ /* ...push data from output port */
+ xf_output_port_produce(&mixer->output, produced);
+
+ /* ...clear output-setup condition */
+ base->state &= ~XA_MIXER_FLAG_OUTPUT_SETUP;
+ }
+
+ /* ...reschedule data processing if there is a pending output message */
+ if (xf_output_port_ready(&mixer->output))
+ {
+ /* ...schedule execution with respect to urgency */
+ xa_base_schedule(base, (produced ? mixer->frame_duration : 0));
+ }
+
+ return XA_NO_ERROR;
+}
+
+/*******************************************************************************
+ * Command-processing function
+ ******************************************************************************/
+
+/* ...command hooks */
+static XA_ERRORCODE (* const xa_mixer_cmd[])(XACodecBase *, xf_message_t *) =
+{
+ /* ...set-parameter - actually, same as in generic case */
+ [XF_OPCODE_TYPE(XF_SET_PARAM)] = xa_base_set_param,
+ [XF_OPCODE_TYPE(XF_GET_PARAM)] = xa_base_get_param,
+
+ /* ...output port routing/unrouting */
+ [XF_OPCODE_TYPE(XF_ROUTE)] = xa_mixer_port_route,
+ [XF_OPCODE_TYPE(XF_UNROUTE)] = xa_mixer_port_unroute,
+
+ /* ...input/output buffers processing */
+ [XF_OPCODE_TYPE(XF_EMPTY_THIS_BUFFER)] = xa_mixer_empty_this_buffer,
+ [XF_OPCODE_TYPE(XF_FILL_THIS_BUFFER)] = xa_mixer_fill_this_buffer,
+ [XF_OPCODE_TYPE(XF_FLUSH)] = xa_mixer_flush,
+
+ /* ...track control */
+ [XF_OPCODE_TYPE(XF_PAUSE)] = xa_mixer_pause,
+ [XF_OPCODE_TYPE(XF_RESUME)] = xa_mixer_resume,
+};
+
+/* ...total number of commands supported */
+#define XA_MIXER_CMD_NUM (sizeof(xa_mixer_cmd) / sizeof(xa_mixer_cmd[0]))
+
+/*******************************************************************************
+ * Entry points
+ ******************************************************************************/
+
+/* ...mixer termination-state command processor */
+static int xa_mixer_terminate(xf_component_t *component, xf_message_t *m)
+{
+ XAMixer *mixer = (XAMixer *) component;
+ u32 opcode = m->opcode;
+
+ if (m == xf_output_port_control_msg(&mixer->output))
+ {
+ /* ...output port flushing complete; mark port is idle and terminate */
+ xf_output_port_flush_done(&mixer->output);
+ return -1;
+ }
+ else if (opcode == XF_FILL_THIS_BUFFER && xf_output_port_routed(&mixer->output))
+ {
+ /* ...output buffer returned by the sink component; ignore and keep waiting */
+ TRACE(OUTPUT, _b("collect output buffer"));
+ return 0;
+ }
+ else if (opcode == XF_UNREGISTER)
+ {
+ /* ...ignore subsequent unregister command/response */
+ return 0;
+ }
+ else
+ {
+ /* ...everything else is responded with generic failure */
+ xf_response_err(m);
+ return 0;
+ }
+}
+
+/* ...mixer class destructor */
+static int xa_mixer_destroy(xf_component_t *component, xf_message_t *m)
+{
+ XAMixer *mixer = (XAMixer *) component;
+ u32 core = xf_component_core(component);
+ u32 i;
+
+ /* ...destroy all inputs */
+ for (i = 0; i < XA_MIXER_MAX_TRACK_NUMBER; i++)
+ {
+ xf_input_port_destroy(&mixer->track[i].input, core);
+ }
+
+ /* ...destroy output port */
+ xf_output_port_destroy(&mixer->output, core);
+
+ /* ...destroy base object */
+ xa_base_destroy(&mixer->base, XF_MM(sizeof(*mixer)), core);
+
+ TRACE(INIT, _b("mixer[%p] destroyed"), mixer);
+
+ return 0;
+}
+
+/* ...mixer class first-stage destructor */
+static int xa_mixer_cleanup(xf_component_t *component, xf_message_t *m)
+{
+ XAMixer *mixer = (XAMixer *) component;
+ u32 i;
+
+ /* ...complete message with error result code */
+ xf_response_err(m);
+
+ /* ...cancel internal scheduling message if needed */
+ xa_base_cancel(&mixer->base);
+
+ /* ...purge all input ports (specify "unregister"? - don't know yet - tbd) */
+ for (i = 0; i < XA_MIXER_MAX_TRACK_NUMBER; i++)
+ {
+ xf_input_port_purge(&mixer->track[i].input);
+ }
+
+ /* ...flush output port */
+ if (xf_output_port_flush(&mixer->output, XF_FLUSH))
+ {
+ /* ...flushing sequence is not needed; destroy mixer */
+ return xa_mixer_destroy(component, NULL);
+ }
+ else
+ {
+ /* ...wait until output port is cleaned; adjust component hooks */
+ component->entry = xa_mixer_terminate;
+ component->exit = xa_mixer_destroy;
+
+ TRACE(INIT, _b("mixer[%p] cleanup sequence started"), mixer);
+
+ /* ...indicate that second stage is required */
+ return 1;
+ }
+}
+
+/* ...mixer class factory */
+xf_component_t * xa_mixer_factory(u32 core, xa_codec_func_t process)
+{
+ XAMixer *mixer;
+
+ /* ...construct generic audio component */
+ XF_CHK_ERR(mixer = (XAMixer *)xa_base_factory(core, XF_MM(sizeof(*mixer)), process), NULL);
+
+ /* ...set generic codec API */
+ mixer->base.memtab = xa_mixer_memtab;
+ mixer->base.preprocess = xa_mixer_preprocess;
+ mixer->base.postprocess = xa_mixer_postprocess;
+
+ /* ...set message-processing table */
+ mixer->base.command = xa_mixer_cmd;
+ mixer->base.command_num = XA_MIXER_CMD_NUM;
+
+ /* ...set component destructor hook */
+ mixer->base.component.exit = xa_mixer_cleanup;
+
+ TRACE(INIT, _b("Mixer[%p] created"), mixer);
+
+ /* ...return handle to component */
+ return (xf_component_t *) mixer;
+}