blob: 0909d446316918316262afeeb4e69bcf81622c89 [file] [log] [blame]
/*******************************************************************************
* 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-mixer.c
*
* Sample mixer plugin
*
******************************************************************************/
#define MODULE_TAG MIXER
/*******************************************************************************
* Includes
******************************************************************************/
#include "xf-plugin.h"
#include "audio/xa-mixer-api.h"
/*******************************************************************************
* Tracing configuration
******************************************************************************/
TRACE_TAG(INIT, 1);
TRACE_TAG(PROCESS, 1);
/*******************************************************************************
* Internal functions definitions
******************************************************************************/
/* ...API structure */
typedef struct XAPcmMixer
{
/* ...mixer state */
u32 state;
/* ...number of samples in a frame */
u32 frame_size;
/* ...number of channels (channel mask?) */
u32 channels;
/* ...PCM sample width */
u32 pcm_width;
/* ...sampling rate */
u32 sample_rate;
/* ...number of bytes in input/output buffer */
u32 buffer_size;
/* ...master volume and individual track volumes*/
u32 volume[XA_MIXER_MAX_TRACK_NUMBER + 1];
/* ...input buffers */
void *input[XA_MIXER_MAX_TRACK_NUMBER];
/* ...number of samples in individual buffers */
u32 input_length[XA_MIXER_MAX_TRACK_NUMBER];
/* ...output buffer */
void *output;
/* ...number of produced bytes - do I need that? have buffer-size already - tbd */
u32 produced;
/* ...scratch buffer pointer */
void *scratch;
} XAPcmMixer;
/*******************************************************************************
* Mixer state flags
******************************************************************************/
#define XA_MIXER_FLAG_PREINIT_DONE (1 << 0)
#define XA_MIXER_FLAG_POSTINIT_DONE (1 << 1)
#define XA_MIXER_FLAG_RUNNING (1 << 2)
#define XA_MIXER_FLAG_OUTPUT (1 << 3)
#define XA_MIXER_FLAG_COMPLETE (1 << 4)
/*******************************************************************************
* DSP functions
******************************************************************************/
#define DSP_SATURATE_S16(s32) \
(s16)((s32) > 0x7fff ? 0x7fff : ((s32) < -0x8000 ? -0x8000 : (s32)))
/* ...mixer preinitialization (default parameters) */
static inline void xa_mixer_preinit(XAPcmMixer *d)
{
u32 i;
/* ...pre-configuration initialization; reset internal data */
memset(d, 0, sizeof(*d));
/* ...set default parameters */
d->pcm_width = 16, d->channels = 2, d->frame_size = 512;
/* ...set default volumes (last index is a master volume)*/
for (i = 0; i <= XA_MIXER_MAX_TRACK_NUMBER; i++)
{
d->volume[i] = ((1 << 12) << 16) | (1 << 12);
}
}
/* ...do mixing of stereo PCM-16 streams */
static XA_ERRORCODE xa_mixer_do_execute_stereo_16bit(XAPcmMixer *d)
{
s16 *output = d->output;
s16 *b[XA_MIXER_MAX_TRACK_NUMBER];
u16 v_l[XA_MIXER_MAX_TRACK_NUMBER];
u16 v_r[XA_MIXER_MAX_TRACK_NUMBER];
u16 w_l, w_r;
u32 t32;
u32 i, j;
/* ...retrieve master volume - assume up to 24dB amplifying (4 bits) */
t32 = d->volume[XA_MIXER_MAX_TRACK_NUMBER];
w_l = (u16)(t32 & 0xFFFF), w_r = (u16)(t32 >> 16);
/* ...prepare individual tracks */
for (j = 0; j < XA_MIXER_MAX_TRACK_NUMBER; j++)
{
u32 n = d->input_length[j];
/* ...check if we have input buffer available */
if (n == 0)
{
/* ...output silence (multiply garbage in the scratch buffer by 0) */
b[j] = d->scratch;
v_l[j] = v_r[j] = 0;
}
else
{
s32 k = (s32)(d->buffer_size - n);
/* ...put input buffer */
XF_CHK_ERR(b[j] = d->input[j], XA_MIXER_EXEC_FATAL_INPUT);
/* ...if length is not sufficient, pad buffer remainder */
(k > 0 ? memset((void *)b[j] + n, 0x00, k) : 0);
/* ...set individual track volume/balance */
t32 = d->volume[j];
v_l[j] = (u16)(t32 & 0xFFFF), v_r[j] = (u16)(t32 >> 16);
}
TRACE(PROCESS, _b("b[%u] = %p%s"), j, b[j], (n == 0 ? " - scratch" : ""));
}
/* ...process all tracks */
for (i = 0; i < d->frame_size; i++)
{
s32 l32 = 0, r32 = 0;
/* ...fill-in every channel in our map (unrolls loop here) */
for (j = 0; j < XA_MIXER_MAX_TRACK_NUMBER; j++)
{
/* ...left channel processing (no saturation here yet) */
l32 += *b[j]++ * v_l[j];
/* ...right channel processing */
r32 += *b[j]++ * v_r[j];
}
/* ...normalize (truncate towards -inf) and multiply by master volume */
l32 = ((l32 >> 12) * w_l) >> 12;
r32 = ((r32 >> 12) * w_r) >> 12;
/* ...saturate and store in buffer */
*output++ = DSP_SATURATE_S16(l32);
*output++ = DSP_SATURATE_S16(r32);
}
/* ...save total number of produced bytes */
d->produced = (u32)((void *)output - d->output);
/* ...put flag saying we have output buffer */
d->state |= XA_MIXER_FLAG_OUTPUT;
TRACE(PROCESS, _b("produced: %u bytes (%u samples)"), d->produced, d->frame_size);
/* ...reset input buffer length? */
//memset(d->input_length, 0, sizeof(d->input_length));
/* ...return success result code */
return XA_NO_ERROR;
}
/* ...runtime reset */
static XA_ERRORCODE xa_mixer_do_runtime_init(XAPcmMixer *d)
{
/* ...no special processing is needed here */
return XA_NO_ERROR;
}
/*******************************************************************************
* Commands processing
******************************************************************************/
/* ...codec API size query */
static XA_ERRORCODE xa_mixer_get_api_size(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...check parameters are sane */
XF_CHK_ERR(pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...retrieve API structure size */
*(WORD32 *)pv_value = sizeof(*d);
return XA_NO_ERROR;
}
/* ...standard codec initialization routine */
static XA_ERRORCODE xa_mixer_init(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...sanity check - mixer must be valid */
XF_CHK_ERR(d, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...process particular initialization type */
switch (i_idx)
{
case XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS:
{
/* ...pre-configuration initialization; reset internal data */
xa_mixer_preinit(d);
/* ...and mark mixer has been created */
d->state = XA_MIXER_FLAG_PREINIT_DONE;
return XA_NO_ERROR;
}
case XA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS:
{
/* ...post-configuration initialization (all parameters are set) */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...calculate input/output buffer size in bytes */
d->buffer_size = d->channels * d->frame_size * (d->pcm_width == 16 ? sizeof(s16) : sizeof(s32));
/* ...mark post-initialization is complete */
d->state |= XA_MIXER_FLAG_POSTINIT_DONE;
return XA_NO_ERROR;
}
case XA_CMD_TYPE_INIT_PROCESS:
{
/* ...kick run-time initialization process; make sure mixer is setup */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...enter into execution stage */
d->state |= XA_MIXER_FLAG_RUNNING;
return XA_NO_ERROR;
}
case XA_CMD_TYPE_INIT_DONE_QUERY:
{
/* ...check if initialization is done; make sure pointer is sane */
XF_CHK_ERR(pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...put current status */
*(WORD32 *)pv_value = (d->state & XA_MIXER_FLAG_RUNNING ? 1 : 0);
return XA_NO_ERROR;
}
default:
/* ...unrecognized command type */
TRACE(ERROR, _x("Unrecognized command type: %X"), i_idx);
return XA_API_FATAL_INVALID_CMD_TYPE;
}
}
/* ...set mixer configuration parameter */
static XA_ERRORCODE xa_mixer_set_config_param(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
u32 i_value;
/* ...sanity check - mixer pointer must be sane */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...pre-initialization must be completed, mixer must be idle */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...get parameter value */
i_value = (u32) *(WORD32 *)pv_value;
/* ...process individual configuration parameter */
switch (i_idx)
{
case XA_MIXER_CONFIG_PARAM_PCM_WIDTH:
/* ...check value is permitted (16 bits only) */
XF_CHK_ERR(i_value == 16, XA_MIXER_CONFIG_NONFATAL_RANGE);
d->pcm_width = (u32)i_value;
return XA_NO_ERROR;
case XA_MIXER_CONFIG_PARAM_CHANNELS:
/* ...allow stereo only */
XF_CHK_ERR(i_value == 2, XA_MIXER_CONFIG_NONFATAL_RANGE);
d->channels = (u32)i_value;
return XA_NO_ERROR;
case XA_MIXER_CONFIG_PARAM_SAMPLE_RATE:
/* ...set mixer sample rate */
d->sample_rate = (u32)i_value;
return XA_NO_ERROR;
default:
TRACE(ERROR, _x("Invalid parameter: %X"), i_idx);
return XA_API_FATAL_INVALID_CMD_TYPE;
}
}
/* ...retrieve configuration parameter */
static XA_ERRORCODE xa_mixer_get_config_param(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...sanity check - mixer must be initialized */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...make sure pre-initialization is completed */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...process individual configuration parameter */
switch (i_idx)
{
case XA_MIXER_CONFIG_PARAM_INPUT_TRACKS:
/* ...return maximal number of input tracks supported */
*(WORD32 *)pv_value = XA_MIXER_MAX_TRACK_NUMBER;
return XA_NO_ERROR;
case XA_MIXER_CONFIG_PARAM_SAMPLE_RATE:
/* ...return mixer sample rate */
*(WORD32 *)pv_value = d->sample_rate;
return XA_NO_ERROR;
case XA_MIXER_CONFIG_PARAM_PCM_WIDTH:
/* ...return current PCM width */
*(WORD32 *)pv_value = d->pcm_width;
return XA_NO_ERROR;
case XA_MIXER_CONFIG_PARAM_CHANNELS:
/* ...return current channel number */
*(WORD32 *)pv_value = d->channels;
return XA_NO_ERROR;
case XA_MIXER_CONFIG_PARAM_FRAME_SIZE:
/* ...return current in/out frame length (in samples) */
*(WORD32 *)pv_value = d->frame_size;
return XA_NO_ERROR;
case XA_MIXER_CONFIG_PARAM_BUFFER_SIZE:
/* ...return current in/out frame length (in bytes) */
*(WORD32 *)pv_value = d->buffer_size;
return XA_NO_ERROR;
default:
TRACE(ERROR, _x("Invalid parameter: %X"), i_idx);
return XA_API_FATAL_INVALID_CMD_TYPE;
}
}
/* ...execution command */
static XA_ERRORCODE xa_mixer_execute(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...sanity check - mixer must be valid */
XF_CHK_ERR(d, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...mixer must be in running state */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_RUNNING, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...process individual command type */
switch (i_idx)
{
case XA_CMD_TYPE_DO_EXECUTE:
/* ...perform mixing of the channels */
return xa_mixer_do_execute_stereo_16bit(d);
case XA_CMD_TYPE_DONE_QUERY:
/* ...check if processing is complete */
XF_CHK_ERR(pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
*(WORD32 *)pv_value = (d->state & XA_MIXER_FLAG_COMPLETE ? 1 : 0);
return XA_NO_ERROR;
case XA_CMD_TYPE_DO_RUNTIME_INIT:
/* ...reset mixer operation */
return xa_mixer_do_runtime_init(d);
default:
/* ...unrecognized command */
TRACE(ERROR, _x("Invalid index: %X"), i_idx);
return XA_API_FATAL_INVALID_CMD_TYPE;
}
}
/* ...set number of input bytes */
static XA_ERRORCODE xa_mixer_set_input_bytes(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
u32 size;
/* ...sanity check - check parameters */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...track index must be valid */
XF_CHK_ERR(i_idx >= 0 && i_idx < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...mixer must be initialized */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...input buffer must exist */
XF_CHK_ERR(d->input[i_idx], XA_API_FATAL_INVALID_CMD_TYPE);
/* ...input frame length should not be zero (in bytes) */
XF_CHK_ERR((size = (u32)*(WORD32 *)pv_value) > 0, XA_MIXER_EXEC_NONFATAL_INPUT);
/* ...all is correct; set input buffer length in bytes */
d->input_length[i_idx] = size;
return XA_NO_ERROR;
}
/* ...get number of output bytes */
static XA_ERRORCODE xa_mixer_get_output_bytes(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...sanity check - check parameters */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...track index must be zero */
XF_CHK_ERR(i_idx == XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...mixer must be running */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_RUNNING, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...output buffer must exist */
XF_CHK_ERR(d->output, XA_MIXER_EXEC_NONFATAL_OUTPUT);
/* ...return number of produced bytes */
*(WORD32 *)pv_value = (d->state & XA_MIXER_FLAG_OUTPUT ? d->buffer_size : 0);
return XA_NO_ERROR;
}
/* ...get number of consumed bytes */
static XA_ERRORCODE xa_mixer_get_curidx_input_buf(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...sanity check - check parameters */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...track index must be valid */
XF_CHK_ERR(i_idx >= 0 && i_idx < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...mixer must be running */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_RUNNING, XA_MIXER_EXEC_FATAL_STATE);
/* ...input buffer must exist */
XF_CHK_ERR(d->input[i_idx], XA_MIXER_EXEC_FATAL_INPUT);
/* ...return number of bytes consumed (always consume fixed-length chunk) */
*(WORD32 *)pv_value = d->input_length[i_idx], d->input_length[i_idx] = 0;
return XA_NO_ERROR;
}
/*******************************************************************************
* Memory information API
******************************************************************************/
/* ..get total amount of data for memory tables */
static XA_ERRORCODE xa_mixer_get_memtabs_size(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...basic sanity checks */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...check mixer is pre-initialized */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...we have all our tables inside API structure - good? tbd */
*(WORD32 *)pv_value = 0;
return XA_NO_ERROR;
}
/* ..set memory tables pointer */
static XA_ERRORCODE xa_mixer_set_memtabs_ptr(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...basic sanity checks */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...check mixer is pre-initialized */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...do not do anything; just return success - tbd */
return XA_NO_ERROR;
}
/* ...return total amount of memory buffers */
static XA_ERRORCODE xa_mixer_get_n_memtabs(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...basic sanity checks */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...we have N input buffers, 1 output buffer and 1 scratch buffer */
*(WORD32 *)pv_value = XA_MIXER_MAX_TRACK_NUMBER + 1 + 1;
return XA_NO_ERROR;
}
/* ...return memory buffer data */
static XA_ERRORCODE xa_mixer_get_mem_info_size(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...basic sanity check */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...return frame buffer minimal size only after post-initialization is done */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...all buffers are of the same length */
*(WORD32 *)pv_value = (WORD32) d->buffer_size;
return XA_NO_ERROR;
}
/* ...return memory alignment data */
static XA_ERRORCODE xa_mixer_get_mem_info_alignment(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...basic sanity check */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...return frame buffer minimal size only after post-initialization is done */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...all buffers are 4-bytes aligned */
*(WORD32 *)pv_value = 4;
return XA_NO_ERROR;
}
/* ...return memory type data */
static XA_ERRORCODE xa_mixer_get_mem_info_type(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...basic sanity check */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...return frame buffer minimal size only after post-initialization is done */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
switch (i_idx)
{
case 0 ... XA_MIXER_MAX_TRACK_NUMBER - 1:
/* ...input buffers */
*(WORD32 *)pv_value = XA_MEMTYPE_INPUT;
return XA_NO_ERROR;
case XA_MIXER_MAX_TRACK_NUMBER:
/* ...output buffer */
*(WORD32 *)pv_value = XA_MEMTYPE_OUTPUT;
return XA_NO_ERROR;
case XA_MIXER_MAX_TRACK_NUMBER + 1:
/* ...scratch buffer */
*(WORD32 *)pv_value = XA_MEMTYPE_SCRATCH;
return XA_NO_ERROR;
default:
/* ...invalid index */
return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
}
}
/* ...set memory pointer */
static XA_ERRORCODE xa_mixer_set_mem_ptr(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
{
/* ...basic sanity check */
XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...codec must be initialized */
XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
/* ...select memory buffer */
switch (i_idx)
{
case 0 ... XA_MIXER_MAX_TRACK_NUMBER - 1:
/* ...input buffers */
d->input[i_idx] = pv_value;
return XA_NO_ERROR;
case XA_MIXER_MAX_TRACK_NUMBER:
/* ...output buffer */
d->output = pv_value;
return XA_NO_ERROR;
case XA_MIXER_MAX_TRACK_NUMBER + 1:
/* ...scratch buffer */
d->scratch = pv_value;
return XA_NO_ERROR;
default:
/* ...invalid index */
return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
}
}
/*******************************************************************************
* API command hooks
******************************************************************************/
static XA_ERRORCODE (* const xa_mixer_api[])(XAPcmMixer *, WORD32, pVOID) =
{
[XA_API_CMD_GET_API_SIZE] = xa_mixer_get_api_size,
[XA_API_CMD_INIT] = xa_mixer_init,
[XA_API_CMD_SET_CONFIG_PARAM] = xa_mixer_set_config_param,
[XA_API_CMD_GET_CONFIG_PARAM] = xa_mixer_get_config_param,
[XA_API_CMD_EXECUTE] = xa_mixer_execute,
[XA_API_CMD_SET_INPUT_BYTES] = xa_mixer_set_input_bytes,
[XA_API_CMD_GET_OUTPUT_BYTES] = xa_mixer_get_output_bytes,
[XA_API_CMD_GET_CURIDX_INPUT_BUF] = xa_mixer_get_curidx_input_buf,
[XA_API_CMD_GET_MEMTABS_SIZE] = xa_mixer_get_memtabs_size,
[XA_API_CMD_SET_MEMTABS_PTR] = xa_mixer_set_memtabs_ptr,
[XA_API_CMD_GET_N_MEMTABS] = xa_mixer_get_n_memtabs,
[XA_API_CMD_GET_MEM_INFO_SIZE] = xa_mixer_get_mem_info_size,
[XA_API_CMD_GET_MEM_INFO_ALIGNMENT] = xa_mixer_get_mem_info_alignment,
[XA_API_CMD_GET_MEM_INFO_TYPE] = xa_mixer_get_mem_info_type,
[XA_API_CMD_SET_MEM_PTR] = xa_mixer_set_mem_ptr,
};
/* ...total numer of commands supported */
#define XA_MIXER_API_COMMANDS_NUM (sizeof(xa_mixer_api) / sizeof(xa_mixer_api[0]))
/*******************************************************************************
* API entry point
******************************************************************************/
XA_ERRORCODE xa_mixer(xa_codec_handle_t p_xa_module_obj, WORD32 i_cmd, WORD32 i_idx, pVOID pv_value)
{
XAPcmMixer *d = (XAPcmMixer *) p_xa_module_obj;
/* ...check if command index is sane */
XF_CHK_ERR(i_cmd < XA_MIXER_API_COMMANDS_NUM, XA_API_FATAL_INVALID_CMD);
/* ...see if command is defined */
XF_CHK_ERR(xa_mixer_api[i_cmd], XA_API_FATAL_INVALID_CMD);
/* ...execute requested command */
return xa_mixer_api[i_cmd](d, i_idx, pv_value);
}