1 /*******************************************************************************
2 * Copyright (C) 2018 Cadence Design Systems, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to use this Software with Cadence processor cores only and
7 * not with any other processors and platforms, subject to
8 * the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included
11 * in all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
18 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 ******************************************************************************/
22 
23 /*******************************************************************************
24  * xa-mixer.c
25  *
26  * Sample mixer plugin
27  *
28  ******************************************************************************/
29 
30 #define MODULE_TAG                      MIXER
31 
32 /*******************************************************************************
33  * Includes
34  ******************************************************************************/
35 
36 #include "xf-plugin.h"
37 #include "audio/xa-mixer-api.h"
38 
39 /*******************************************************************************
40  * Tracing configuration
41  ******************************************************************************/
42 
43 TRACE_TAG(INIT, 1);
44 TRACE_TAG(PROCESS, 1);
45 
46 /*******************************************************************************
47  * Internal functions definitions
48  ******************************************************************************/
49 
50 /* ...API structure */
51 typedef struct XAPcmMixer
52 {
53     /* ...mixer state */
54     u32                 state;
55 
56     /* ...number of samples in a frame */
57     u32                 frame_size;
58 
59     /* ...number of channels (channel mask?) */
60     u32                 channels;
61 
62     /* ...PCM sample width */
63     u32                 pcm_width;
64 
65     /* ...sampling rate */
66     u32                 sample_rate;
67 
68     /* ...number of bytes in input/output buffer */
69     u32                 buffer_size;
70 
71     /* ...master volume and individual track volumes*/
72     u32                 volume[XA_MIXER_MAX_TRACK_NUMBER + 1];
73 
74     /* ...input buffers */
75     void               *input[XA_MIXER_MAX_TRACK_NUMBER];
76 
77     /* ...number of samples in individual buffers */
78     u32                 input_length[XA_MIXER_MAX_TRACK_NUMBER];
79 
80     /* ...output buffer */
81     void               *output;
82 
83     /* ...number of produced bytes - do I need that? have buffer-size already - tbd */
84     u32                 produced;
85 
86     /* ...scratch buffer pointer */
87     void               *scratch;
88 
89 }   XAPcmMixer;
90 
91 /*******************************************************************************
92  * Mixer state flags
93  ******************************************************************************/
94 
95 #define XA_MIXER_FLAG_PREINIT_DONE      (1 << 0)
96 #define XA_MIXER_FLAG_POSTINIT_DONE     (1 << 1)
97 #define XA_MIXER_FLAG_RUNNING           (1 << 2)
98 #define XA_MIXER_FLAG_OUTPUT            (1 << 3)
99 #define XA_MIXER_FLAG_COMPLETE          (1 << 4)
100 
101 /*******************************************************************************
102  * DSP functions
103  ******************************************************************************/
104 
105 #define DSP_SATURATE_S16(s32)   \
106     (s16)((s32) > 0x7fff ? 0x7fff : ((s32) < -0x8000 ? -0x8000 : (s32)))
107 
108 /* ...mixer preinitialization (default parameters) */
xa_mixer_preinit(XAPcmMixer * d)109 static inline void xa_mixer_preinit(XAPcmMixer *d)
110 {
111     u32     i;
112 
113     /* ...pre-configuration initialization; reset internal data */
114     memset(d, 0, sizeof(*d));
115 
116     /* ...set default parameters */
117     d->pcm_width = 16, d->channels = 2, d->frame_size = 512;
118 
119     /* ...set default volumes (last index is a master volume)*/
120     for (i = 0; i <= XA_MIXER_MAX_TRACK_NUMBER; i++)
121     {
122         d->volume[i] = ((1 << 12) << 16) | (1 << 12);
123     }
124 }
125 
126 /* ...do mixing of stereo PCM-16 streams */
xa_mixer_do_execute_stereo_16bit(XAPcmMixer * d)127 static XA_ERRORCODE xa_mixer_do_execute_stereo_16bit(XAPcmMixer *d)
128 {
129     s16    *output = d->output;
130     s16    *b[XA_MIXER_MAX_TRACK_NUMBER];
131     u16     v_l[XA_MIXER_MAX_TRACK_NUMBER];
132     u16     v_r[XA_MIXER_MAX_TRACK_NUMBER];
133     u16     w_l, w_r;
134     u32     t32;
135     u32     i, j;
136 
137     /* ...retrieve master volume - assume up to 24dB amplifying (4 bits) */
138     t32 = d->volume[XA_MIXER_MAX_TRACK_NUMBER];
139     w_l = (u16)(t32 & 0xFFFF), w_r = (u16)(t32 >> 16);
140 
141     /* ...prepare individual tracks */
142     for (j = 0; j < XA_MIXER_MAX_TRACK_NUMBER; j++)
143     {
144         u32     n = d->input_length[j];
145 
146         /* ...check if we have input buffer available */
147         if (n == 0)
148         {
149             /* ...output silence (multiply garbage in the scratch buffer by 0) */
150             b[j] = d->scratch;
151             v_l[j] = v_r[j] = 0;
152         }
153         else
154         {
155             s32     k = (s32)(d->buffer_size - n);
156 
157             /* ...put input buffer */
158             XF_CHK_ERR(b[j] = d->input[j], XA_MIXER_EXEC_FATAL_INPUT);
159 
160             /* ...if length is not sufficient, pad buffer remainder */
161             (k > 0 ? memset((void *)b[j] + n, 0x00, k) : 0);
162 
163             /* ...set individual track volume/balance */
164             t32 = d->volume[j];
165             v_l[j] = (u16)(t32 & 0xFFFF), v_r[j] = (u16)(t32 >> 16);
166         }
167 
168         TRACE(PROCESS, _b("b[%u] = %p%s"), j, b[j], (n == 0 ? " - scratch" : ""));
169     }
170 
171     /* ...process all tracks */
172     for (i = 0; i < d->frame_size; i++)
173     {
174         s32     l32 = 0, r32 = 0;
175 
176         /* ...fill-in every channel in our map (unrolls loop here) */
177         for (j = 0; j < XA_MIXER_MAX_TRACK_NUMBER; j++)
178         {
179             /* ...left channel processing (no saturation here yet) */
180             l32 += *b[j]++ * v_l[j];
181 
182             /* ...right channel processing */
183             r32 += *b[j]++ * v_r[j];
184         }
185 
186         /* ...normalize (truncate towards -inf) and multiply by master volume */
187         l32 = ((l32 >> 12) * w_l) >> 12;
188         r32 = ((r32 >> 12) * w_r) >> 12;
189 
190         /* ...saturate and store in buffer */
191         *output++ = DSP_SATURATE_S16(l32);
192         *output++ = DSP_SATURATE_S16(r32);
193     }
194 
195     /* ...save total number of produced bytes */
196     d->produced = (u32)((void *)output - d->output);
197 
198     /* ...put flag saying we have output buffer */
199     d->state |= XA_MIXER_FLAG_OUTPUT;
200 
201     TRACE(PROCESS, _b("produced: %u bytes (%u samples)"), d->produced, d->frame_size);
202 
203     /* ...reset input buffer length? */
204     //memset(d->input_length, 0, sizeof(d->input_length));
205 
206     /* ...return success result code */
207     return XA_NO_ERROR;
208 }
209 
210 /* ...runtime reset */
xa_mixer_do_runtime_init(XAPcmMixer * d)211 static XA_ERRORCODE xa_mixer_do_runtime_init(XAPcmMixer *d)
212 {
213     /* ...no special processing is needed here */
214     return XA_NO_ERROR;
215 }
216 
217 /*******************************************************************************
218  * Commands processing
219  ******************************************************************************/
220 
221 /* ...codec API size query */
xa_mixer_get_api_size(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)222 static XA_ERRORCODE xa_mixer_get_api_size(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
223 {
224     /* ...check parameters are sane */
225     XF_CHK_ERR(pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
226 
227     /* ...retrieve API structure size */
228     *(WORD32 *)pv_value = sizeof(*d);
229 
230     return XA_NO_ERROR;
231 }
232 
233 /* ...standard codec initialization routine */
xa_mixer_init(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)234 static XA_ERRORCODE xa_mixer_init(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
235 {
236     /* ...sanity check - mixer must be valid */
237     XF_CHK_ERR(d, XA_API_FATAL_INVALID_CMD_TYPE);
238 
239     /* ...process particular initialization type */
240     switch (i_idx)
241     {
242     case XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS:
243     {
244         /* ...pre-configuration initialization; reset internal data */
245         xa_mixer_preinit(d);
246 
247         /* ...and mark mixer has been created */
248         d->state = XA_MIXER_FLAG_PREINIT_DONE;
249 
250         return XA_NO_ERROR;
251     }
252 
253     case XA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS:
254     {
255         /* ...post-configuration initialization (all parameters are set) */
256         XF_CHK_ERR(d->state & XA_MIXER_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
257 
258         /* ...calculate input/output buffer size in bytes */
259         d->buffer_size = d->channels * d->frame_size * (d->pcm_width == 16 ? sizeof(s16) : sizeof(s32));
260 
261         /* ...mark post-initialization is complete */
262         d->state |= XA_MIXER_FLAG_POSTINIT_DONE;
263 
264         return XA_NO_ERROR;
265     }
266 
267     case XA_CMD_TYPE_INIT_PROCESS:
268     {
269         /* ...kick run-time initialization process; make sure mixer is setup */
270         XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
271 
272         /* ...enter into execution stage */
273         d->state |= XA_MIXER_FLAG_RUNNING;
274 
275         return XA_NO_ERROR;
276     }
277 
278     case XA_CMD_TYPE_INIT_DONE_QUERY:
279     {
280         /* ...check if initialization is done; make sure pointer is sane */
281         XF_CHK_ERR(pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
282 
283         /* ...put current status */
284         *(WORD32 *)pv_value = (d->state & XA_MIXER_FLAG_RUNNING ? 1 : 0);
285 
286         return XA_NO_ERROR;
287     }
288 
289     default:
290         /* ...unrecognized command type */
291         TRACE(ERROR, _x("Unrecognized command type: %X"), i_idx);
292         return XA_API_FATAL_INVALID_CMD_TYPE;
293     }
294 }
295 
296 /* ...set mixer configuration parameter */
xa_mixer_set_config_param(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)297 static XA_ERRORCODE xa_mixer_set_config_param(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
298 {
299     u32     i_value;
300 
301     /* ...sanity check - mixer pointer must be sane */
302     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
303 
304     /* ...pre-initialization must be completed, mixer must be idle */
305     XF_CHK_ERR(d->state & XA_MIXER_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
306 
307     /* ...get parameter value  */
308     i_value = (u32) *(WORD32 *)pv_value;
309 
310     /* ...process individual configuration parameter */
311     switch (i_idx)
312     {
313     case XA_MIXER_CONFIG_PARAM_PCM_WIDTH:
314         /* ...check value is permitted (16 bits only) */
315         XF_CHK_ERR(i_value == 16, XA_MIXER_CONFIG_NONFATAL_RANGE);
316         d->pcm_width = (u32)i_value;
317         return XA_NO_ERROR;
318 
319     case XA_MIXER_CONFIG_PARAM_CHANNELS:
320         /* ...allow stereo only */
321         XF_CHK_ERR(i_value == 2, XA_MIXER_CONFIG_NONFATAL_RANGE);
322         d->channels = (u32)i_value;
323         return XA_NO_ERROR;
324 
325     case XA_MIXER_CONFIG_PARAM_SAMPLE_RATE:
326         /* ...set mixer sample rate */
327         d->sample_rate = (u32)i_value;
328         return XA_NO_ERROR;
329 
330     default:
331         TRACE(ERROR, _x("Invalid parameter: %X"), i_idx);
332         return XA_API_FATAL_INVALID_CMD_TYPE;
333     }
334 }
335 
336 /* ...retrieve configuration parameter */
xa_mixer_get_config_param(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)337 static XA_ERRORCODE xa_mixer_get_config_param(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
338 {
339     /* ...sanity check - mixer must be initialized */
340     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
341 
342     /* ...make sure pre-initialization is completed */
343     XF_CHK_ERR(d->state & XA_MIXER_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
344 
345     /* ...process individual configuration parameter */
346     switch (i_idx)
347     {
348     case XA_MIXER_CONFIG_PARAM_INPUT_TRACKS:
349         /* ...return maximal number of input tracks supported */
350         *(WORD32 *)pv_value = XA_MIXER_MAX_TRACK_NUMBER;
351         return XA_NO_ERROR;
352 
353     case XA_MIXER_CONFIG_PARAM_SAMPLE_RATE:
354         /* ...return mixer sample rate */
355         *(WORD32 *)pv_value = d->sample_rate;
356         return XA_NO_ERROR;
357 
358     case XA_MIXER_CONFIG_PARAM_PCM_WIDTH:
359         /* ...return current PCM width */
360         *(WORD32 *)pv_value = d->pcm_width;
361         return XA_NO_ERROR;
362 
363     case XA_MIXER_CONFIG_PARAM_CHANNELS:
364         /* ...return current channel number */
365         *(WORD32 *)pv_value = d->channels;
366         return XA_NO_ERROR;
367 
368     case XA_MIXER_CONFIG_PARAM_FRAME_SIZE:
369         /* ...return current in/out frame length (in samples) */
370         *(WORD32 *)pv_value = d->frame_size;
371         return XA_NO_ERROR;
372 
373     case XA_MIXER_CONFIG_PARAM_BUFFER_SIZE:
374         /* ...return current in/out frame length (in bytes) */
375         *(WORD32 *)pv_value = d->buffer_size;
376         return XA_NO_ERROR;
377 
378     default:
379         TRACE(ERROR, _x("Invalid parameter: %X"), i_idx);
380         return XA_API_FATAL_INVALID_CMD_TYPE;
381     }
382 }
383 
384 /* ...execution command */
xa_mixer_execute(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)385 static XA_ERRORCODE xa_mixer_execute(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
386 {
387     /* ...sanity check - mixer must be valid */
388     XF_CHK_ERR(d, XA_API_FATAL_INVALID_CMD_TYPE);
389 
390     /* ...mixer must be in running state */
391     XF_CHK_ERR(d->state & XA_MIXER_FLAG_RUNNING, XA_API_FATAL_INVALID_CMD_TYPE);
392 
393     /* ...process individual command type */
394     switch (i_idx)
395     {
396     case XA_CMD_TYPE_DO_EXECUTE:
397         /* ...perform mixing of the channels */
398         return xa_mixer_do_execute_stereo_16bit(d);
399 
400     case XA_CMD_TYPE_DONE_QUERY:
401         /* ...check if processing is complete */
402         XF_CHK_ERR(pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
403         *(WORD32 *)pv_value = (d->state & XA_MIXER_FLAG_COMPLETE ? 1 : 0);
404         return XA_NO_ERROR;
405 
406     case XA_CMD_TYPE_DO_RUNTIME_INIT:
407         /* ...reset mixer operation */
408         return xa_mixer_do_runtime_init(d);
409 
410     default:
411         /* ...unrecognized command */
412         TRACE(ERROR, _x("Invalid index: %X"), i_idx);
413         return XA_API_FATAL_INVALID_CMD_TYPE;
414     }
415 }
416 
417 /* ...set number of input bytes */
xa_mixer_set_input_bytes(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)418 static XA_ERRORCODE xa_mixer_set_input_bytes(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
419 {
420     u32     size;
421 
422     /* ...sanity check - check parameters */
423     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
424 
425     /* ...track index must be valid */
426     XF_CHK_ERR(i_idx >= 0 && i_idx < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
427 
428     /* ...mixer must be initialized */
429     XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
430 
431     /* ...input buffer must exist */
432     XF_CHK_ERR(d->input[i_idx], XA_API_FATAL_INVALID_CMD_TYPE);
433 
434     /* ...input frame length should not be zero (in bytes) */
435     XF_CHK_ERR((size = (u32)*(WORD32 *)pv_value) > 0, XA_MIXER_EXEC_NONFATAL_INPUT);
436 
437     /* ...all is correct; set input buffer length in bytes */
438     d->input_length[i_idx] = size;
439 
440     return XA_NO_ERROR;
441 }
442 
443 /* ...get number of output bytes */
xa_mixer_get_output_bytes(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)444 static XA_ERRORCODE xa_mixer_get_output_bytes(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
445 {
446     /* ...sanity check - check parameters */
447     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
448 
449     /* ...track index must be zero */
450     XF_CHK_ERR(i_idx == XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
451 
452     /* ...mixer must be running */
453     XF_CHK_ERR(d->state & XA_MIXER_FLAG_RUNNING, XA_API_FATAL_INVALID_CMD_TYPE);
454 
455     /* ...output buffer must exist */
456     XF_CHK_ERR(d->output, XA_MIXER_EXEC_NONFATAL_OUTPUT);
457 
458     /* ...return number of produced bytes */
459     *(WORD32 *)pv_value = (d->state & XA_MIXER_FLAG_OUTPUT ? d->buffer_size : 0);
460 
461     return XA_NO_ERROR;
462 }
463 
464 /* ...get number of consumed bytes */
xa_mixer_get_curidx_input_buf(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)465 static XA_ERRORCODE xa_mixer_get_curidx_input_buf(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
466 {
467     /* ...sanity check - check parameters */
468     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
469 
470     /* ...track index must be valid */
471     XF_CHK_ERR(i_idx >= 0 && i_idx < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
472 
473     /* ...mixer must be running */
474     XF_CHK_ERR(d->state & XA_MIXER_FLAG_RUNNING, XA_MIXER_EXEC_FATAL_STATE);
475 
476     /* ...input buffer must exist */
477     XF_CHK_ERR(d->input[i_idx], XA_MIXER_EXEC_FATAL_INPUT);
478 
479     /* ...return number of bytes consumed (always consume fixed-length chunk) */
480     *(WORD32 *)pv_value = d->input_length[i_idx], d->input_length[i_idx] = 0;
481 
482     return XA_NO_ERROR;
483 }
484 
485 /*******************************************************************************
486  * Memory information API
487  ******************************************************************************/
488 
489 /* ..get total amount of data for memory tables */
xa_mixer_get_memtabs_size(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)490 static XA_ERRORCODE xa_mixer_get_memtabs_size(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
491 {
492     /* ...basic sanity checks */
493     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
494 
495     /* ...check mixer is pre-initialized */
496     XF_CHK_ERR(d->state & XA_MIXER_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
497 
498     /* ...we have all our tables inside API structure - good? tbd */
499     *(WORD32 *)pv_value = 0;
500 
501     return XA_NO_ERROR;
502 }
503 
504 /* ..set memory tables pointer */
xa_mixer_set_memtabs_ptr(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)505 static XA_ERRORCODE xa_mixer_set_memtabs_ptr(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
506 {
507     /* ...basic sanity checks */
508     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
509 
510     /* ...check mixer is pre-initialized */
511     XF_CHK_ERR(d->state & XA_MIXER_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
512 
513     /* ...do not do anything; just return success - tbd */
514     return XA_NO_ERROR;
515 }
516 
517 /* ...return total amount of memory buffers */
xa_mixer_get_n_memtabs(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)518 static XA_ERRORCODE xa_mixer_get_n_memtabs(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
519 {
520     /* ...basic sanity checks */
521     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
522 
523     /* ...we have N input buffers, 1 output buffer and 1 scratch buffer */
524     *(WORD32 *)pv_value = XA_MIXER_MAX_TRACK_NUMBER + 1 + 1;
525 
526     return XA_NO_ERROR;
527 }
528 
529 /* ...return memory buffer data */
xa_mixer_get_mem_info_size(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)530 static XA_ERRORCODE xa_mixer_get_mem_info_size(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
531 {
532     /* ...basic sanity check */
533     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
534 
535     /* ...return frame buffer minimal size only after post-initialization is done */
536     XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
537 
538     /* ...all buffers are of the same length */
539     *(WORD32 *)pv_value = (WORD32) d->buffer_size;
540 
541     return XA_NO_ERROR;
542 }
543 
544 /* ...return memory alignment data */
xa_mixer_get_mem_info_alignment(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)545 static XA_ERRORCODE xa_mixer_get_mem_info_alignment(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
546 {
547     /* ...basic sanity check */
548     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
549 
550     /* ...return frame buffer minimal size only after post-initialization is done */
551     XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
552 
553     /* ...all buffers are 4-bytes aligned */
554     *(WORD32 *)pv_value = 4;
555 
556     return XA_NO_ERROR;
557 }
558 
559 /* ...return memory type data */
xa_mixer_get_mem_info_type(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)560 static XA_ERRORCODE xa_mixer_get_mem_info_type(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
561 {
562     /* ...basic sanity check */
563     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
564 
565     /* ...return frame buffer minimal size only after post-initialization is done */
566     XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
567 
568     switch (i_idx)
569     {
570     case 0 ... XA_MIXER_MAX_TRACK_NUMBER - 1:
571         /* ...input buffers */
572         *(WORD32 *)pv_value = XA_MEMTYPE_INPUT;
573         return XA_NO_ERROR;
574 
575     case XA_MIXER_MAX_TRACK_NUMBER:
576         /* ...output buffer */
577         *(WORD32 *)pv_value = XA_MEMTYPE_OUTPUT;
578         return XA_NO_ERROR;
579 
580     case XA_MIXER_MAX_TRACK_NUMBER + 1:
581         /* ...scratch buffer */
582         *(WORD32 *)pv_value = XA_MEMTYPE_SCRATCH;
583         return XA_NO_ERROR;
584 
585     default:
586         /* ...invalid index */
587         return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
588     }
589 }
590 
591 /* ...set memory pointer */
xa_mixer_set_mem_ptr(XAPcmMixer * d,WORD32 i_idx,pVOID pv_value)592 static XA_ERRORCODE xa_mixer_set_mem_ptr(XAPcmMixer *d, WORD32 i_idx, pVOID pv_value)
593 {
594     /* ...basic sanity check */
595     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
596 
597     /* ...codec must be initialized */
598     XF_CHK_ERR(d->state & XA_MIXER_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
599 
600     /* ...select memory buffer */
601     switch (i_idx)
602     {
603     case 0 ... XA_MIXER_MAX_TRACK_NUMBER - 1:
604         /* ...input buffers */
605         d->input[i_idx] = pv_value;
606         return XA_NO_ERROR;
607 
608     case XA_MIXER_MAX_TRACK_NUMBER:
609         /* ...output buffer */
610         d->output = pv_value;
611         return XA_NO_ERROR;
612 
613     case XA_MIXER_MAX_TRACK_NUMBER + 1:
614         /* ...scratch buffer */
615         d->scratch = pv_value;
616         return XA_NO_ERROR;
617 
618     default:
619         /* ...invalid index */
620         return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
621     }
622 }
623 
624 /*******************************************************************************
625  * API command hooks
626  ******************************************************************************/
627 
628 static XA_ERRORCODE (* const xa_mixer_api[])(XAPcmMixer *, WORD32, pVOID) =
629 {
630     [XA_API_CMD_GET_API_SIZE]           = xa_mixer_get_api_size,
631 
632     [XA_API_CMD_INIT]                   = xa_mixer_init,
633     [XA_API_CMD_SET_CONFIG_PARAM]       = xa_mixer_set_config_param,
634     [XA_API_CMD_GET_CONFIG_PARAM]       = xa_mixer_get_config_param,
635 
636     [XA_API_CMD_EXECUTE]                = xa_mixer_execute,
637     [XA_API_CMD_SET_INPUT_BYTES]        = xa_mixer_set_input_bytes,
638     [XA_API_CMD_GET_OUTPUT_BYTES]       = xa_mixer_get_output_bytes,
639     [XA_API_CMD_GET_CURIDX_INPUT_BUF]   = xa_mixer_get_curidx_input_buf,
640 
641     [XA_API_CMD_GET_MEMTABS_SIZE]       = xa_mixer_get_memtabs_size,
642     [XA_API_CMD_SET_MEMTABS_PTR]        = xa_mixer_set_memtabs_ptr,
643     [XA_API_CMD_GET_N_MEMTABS]          = xa_mixer_get_n_memtabs,
644     [XA_API_CMD_GET_MEM_INFO_SIZE]      = xa_mixer_get_mem_info_size,
645     [XA_API_CMD_GET_MEM_INFO_ALIGNMENT] = xa_mixer_get_mem_info_alignment,
646     [XA_API_CMD_GET_MEM_INFO_TYPE]      = xa_mixer_get_mem_info_type,
647     [XA_API_CMD_SET_MEM_PTR]            = xa_mixer_set_mem_ptr,
648 };
649 
650 /* ...total numer of commands supported */
651 #define XA_MIXER_API_COMMANDS_NUM   (sizeof(xa_mixer_api) / sizeof(xa_mixer_api[0]))
652 
653 /*******************************************************************************
654  * API entry point
655  ******************************************************************************/
656 
xa_mixer(xa_codec_handle_t p_xa_module_obj,WORD32 i_cmd,WORD32 i_idx,pVOID pv_value)657 XA_ERRORCODE xa_mixer(xa_codec_handle_t p_xa_module_obj, WORD32 i_cmd, WORD32 i_idx, pVOID pv_value)
658 {
659     XAPcmMixer    *d = (XAPcmMixer *) p_xa_module_obj;
660 
661     /* ...check if command index is sane */
662     XF_CHK_ERR(i_cmd < XA_MIXER_API_COMMANDS_NUM, XA_API_FATAL_INVALID_CMD);
663 
664     /* ...see if command is defined */
665     XF_CHK_ERR(xa_mixer_api[i_cmd], XA_API_FATAL_INVALID_CMD);
666 
667     /* ...execute requested command */
668     return xa_mixer_api[i_cmd](d, i_idx, pv_value);
669 }
670