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-pcm.c
25  *
26  * PCM format converter plugin
27  *
28  ******************************************************************************/
29 
30 #define MODULE_TAG                      PCM
31 
32 /*******************************************************************************
33  * Includes
34  ******************************************************************************/
35 
36 #include "xf-plugin.h"
37 #include "xa-audio-decoder-api.h"
38 #include "xa-pcm-api.h"
39 
40 #include <fcntl.h>
41 
42 /*******************************************************************************
43  * Tracing configuration
44  ******************************************************************************/
45 
46 TRACE_TAG(INIT, 1);
47 TRACE_TAG(PROCESS, 0);
48 
49 /*******************************************************************************
50  * Local typedefs
51  ******************************************************************************/
52 
53 /* ...API structure */
54 typedef struct XAPcmCodec
55 {
56     /* ...codec state */
57     u32                 state;
58 
59     /* ...sampling rate of input/output signal (informative only) */
60     u32                 sample_rate;
61 
62     /* ...number of input/output channels */
63     u8                  in_channels, out_channels;
64 
65     /* ...PCM sample width of input/output streams */
66     u8                  in_pcm_width, out_pcm_width;
67 
68     /* ...input/output stride size */
69     u8                  in_stride, out_stride;
70 
71     /* ...channel routing map between input and output */
72     u32                 chan_routing;
73 
74     /* ...data processing hook */
75     XA_ERRORCODE      (*process)(struct XAPcmCodec *);
76 
77     /* ...number of samples in input/output buffers */
78     u32                 insize, outsize;
79 
80     /* ...input/output memory indices */
81     u32                 input_idx, output_idx;
82 
83     /* ...input/output buffers passed from/to caller */
84     void               *input, *output;
85 
86     /* ...number of input bytes consumed/produced */
87     u32                 consumed, produced;
88 
89     /* ...debug - file handles */
90     int                 f_input, f_output;
91 
92 }   XAPcmCodec;
93 
94 /*******************************************************************************
95  * Local execution flags
96  ******************************************************************************/
97 
98 #define XA_PCM_FLAG_PREINIT_DONE        (1 << 0)
99 #define XA_PCM_FLAG_POSTINIT_DONE       (1 << 1)
100 #define XA_PCM_FLAG_RUNNING             (1 << 2)
101 #define XA_PCM_FLAG_EOS                 (1 << 3)
102 #define XA_PCM_FLAG_COMPLETE            (1 << 4)
103 
104 /*******************************************************************************
105  * Local constants definitions
106  ******************************************************************************/
107 
108 /* ...process at most 1024 samples per call */
109 #define XA_PCM_MAX_SAMPLES              1024
110 
111 /*******************************************************************************
112  * Internal processing functions
113  ******************************************************************************/
114 
115 /* ...identity translation of PCM16/24 */
xa_pcm_do_execute_copy(XAPcmCodec * d)116 static XA_ERRORCODE xa_pcm_do_execute_copy(XAPcmCodec *d)
117 {
118     u32     n = d->insize;
119     u8      k = d->in_channels;
120     u32     length = n * k * (d->in_pcm_width == 16 ? 2 : 4);
121     s16    *input = d->input, *output = d->output;
122 
123     TRACE(PROCESS, _b("Copy PCM%d %p to %p (%u samples)"), d->in_pcm_width, input, output, n);
124 
125     /* ...check if we have all data setup */
126     XF_CHK_ERR(input && n && output, XA_PCM_EXEC_FATAL_STATE);
127 
128     /* ...copy the samples without any processing */
129     memcpy(output, input, length);
130 
131     /* ...set number of consumed/produced bytes */
132     d->consumed = length;
133     d->produced = length;
134 
135     /* ...reset input buffer length */
136     d->insize = 0;
137 
138     /* ...copy input to output */
139     return XA_NO_ERROR;
140 }
141 
142 /* ...data processing for PCM16, channel mapping case */
xa_pcm_do_execute_pcm16_chmap(XAPcmCodec * d)143 static XA_ERRORCODE xa_pcm_do_execute_pcm16_chmap(XAPcmCodec *d)
144 {
145     u32     n = d->insize, i;
146     u8      k = d->in_channels, j;
147     u32     chmap = d->chan_routing, map;
148     s16    *input = d->input, *output = d->output;
149     u32     length = n * k * (d->in_pcm_width == 16 ? 2 : 4);
150 
151     TRACE(PROCESS, _b("Map PCM16 %p to %p (%u samples, map: %X)"), input, output, n, chmap);
152 
153     /* ...check if we have all data setup */
154     XF_CHK_ERR(input && n && output, XA_PCM_EXEC_FATAL_STATE);
155 
156 #if 0
157     /* ...convert individual samples (that function could be CPU-optimized - tbd) */
158     for (i = 0; i < n; i++, input += k)
159     {
160         /* ...process individual channels in a sample */
161         for (j = 0, map = chmap; j < k; j++, map >>= 4)
162         {
163             u8      m = map & 0xF;
164 
165             /* ...fill output channel (zero unused channel) */
166             *output++ = (m < 8 ? input[m] : 0);
167         }
168     }
169 
170     /* ...set number of consumed/produced bytes */
171     d->consumed = (u32)((u8 *)input - (u8 *)d->input);
172     d->produced = (u32)((u8 *)output - (u8 *)d->output);
173 #else
174     memcpy(output, input, length);
175     /* ...set number of consumed/produced bytes */
176     d->consumed = length;
177     d->produced = length;
178 #endif
179     /* ...reset input buffer length */
180     d->insize = 0;
181 
182     /* ...copy input to output */
183     return XA_NO_ERROR;
184 }
185 
186 /* ...data processing for PCM24/PCM32, channel mapping case */
xa_pcm_do_execute_pcm24_chmap(XAPcmCodec * d)187 static XA_ERRORCODE xa_pcm_do_execute_pcm24_chmap(XAPcmCodec *d)
188 {
189     u32     n = d->insize, i;
190     u8      k = d->in_channels, j;
191     u32     chmap = d->chan_routing, map;
192     s32    *input = d->input, *output = d->output;
193 
194     TRACE(PROCESS, _b("Map PCM24 %p to %p (%u samples, map: %X)"), input, output, n, chmap);
195 
196     /* ...check if we have all data setup */
197     XF_CHK_ERR(input && n && output, XA_PCM_EXEC_FATAL_STATE);
198 
199     /* ...convert individual samples (that function could be CPU-optimized - tbd) */
200     for (i = 0; i < n; i++, input += k)
201     {
202         /* ...process individual channels in a sample */
203         for (j = 0, map = chmap; j < k; j++, map >>= 4)
204         {
205             u8      m = map & 0xF;
206 
207             /* ...fill output channel (zero unused channel) */
208             *output++ = (m < 8 ? input[m] : 0);
209         }
210     }
211 
212     /* ...set number of consumed/produced bytes */
213     d->consumed = (u32)((u8 *)input - (u8 *)d->input);
214     d->produced = (u32)((u8 *)output - (u8 *)d->output);
215 
216     /* ...reset input buffer length */
217     d->insize = 0;
218 
219     /* ...copy input to output */
220     return XA_NO_ERROR;
221 }
222 
223 /* ...convert multichannel 24-bit PCM to 16-bit PCM with channel mapping */
xa_pcm_do_execute_pcm24_to_pcm16(XAPcmCodec * d)224 static XA_ERRORCODE xa_pcm_do_execute_pcm24_to_pcm16(XAPcmCodec *d)
225 {
226     u32     n = d->insize, i;
227     u8      k = d->in_channels, j;
228     u32     chmap = d->chan_routing, map;
229     s32    *input = d->input;
230     s16    *output = d->output;
231 
232     TRACE(PROCESS, _b("Convert PCM24 %p to PCM16 %p (%u samples, map: %X)"), input, output, n, chmap);
233 
234     /* ...check if we have all data setup */
235     XF_CHK_ERR(input && n && output, XA_PCM_EXEC_FATAL_STATE);
236 
237     /* ...convert individual samples (that function could be CPU-optimized - tbd) */
238     for (i = 0; i < n; i++, input += k)
239     {
240         /* ...process individual channels in a sample */
241         for (j = 0, map = chmap; j < k; j++, map >>= 4)
242         {
243             u8      m = map & 0xF;
244 
245             /* ...convert and zero out unused channels */
246             *output++ = (m < 8 ? input[m] >> 16 : 0);
247         }
248     }
249 
250     /* ...set number of consumed/produced bytes */
251     d->consumed = (u32)((u8 *)input - (u8 *)d->input);
252     d->produced = (u32)((u8 *)output - (u8 *)d->output);
253 
254     /* ...dump output data */
255     //BUG(write(d->f_input, d->input, d->consumed) != d->consumed, _x("%m"));
256     //BUG(write(d->f_output, d->output, d->produced) != d->produced, _x("%m"));
257 
258     /* ...reset input buffer length (tbd - need that?) */
259     d->insize = 0;
260 
261     /* ...copy input to output */
262     return XA_NO_ERROR;
263 }
264 
265 /* ...convert multichannel 16-bit PCM to 24-bit PCM with channel mapping */
xa_pcm_do_execute_pcm16_to_pcm24(XAPcmCodec * d)266 static XA_ERRORCODE xa_pcm_do_execute_pcm16_to_pcm24(XAPcmCodec *d)
267 {
268     u32     n = d->insize, i;
269     u8      k = d->in_channels, j;
270     u32     chmap = d->chan_routing, map;
271     s16    *input = d->input;
272     s32    *output = d->output;
273 
274     TRACE(PROCESS, _b("Convert PCM16 %p to PCM24 %p (%u samples, map: %X)"), input, output, n, chmap);
275 
276     /* ...check if we have all data setup */
277     XF_CHK_ERR(input && n && output, XA_PCM_EXEC_FATAL_STATE);
278 
279     /* ...convert individual samples (that function could be CPU-optimized - tbd) */
280     for (i = 0; i < n; i++, input += k)
281     {
282         /* ...process individual channels in a sample */
283         for (j = 0, map = chmap; j < k; j++, map >>= 4)
284         {
285             u8      m = map & 0xF;
286 
287             /* ...convert and zero out unused channels */
288             *output++ = (m < 8 ? input[m] << 16 : 0);
289         }
290     }
291 
292     /* ...set number of consumed/produced bytes */
293     d->consumed = (u32)((u8 *)input - (u8 *)d->input);
294     d->produced = (u32)((u8 *)output - (u8 *)d->output);
295 
296     /* ...reset input buffer length (tbd - need that?) */
297     d->insize = 0;
298 
299     /* ...copy input to output */
300     return XA_NO_ERROR;
301 }
302 
303 /* ...determine if we need to do a channel routing */
xa_pcm_is_identity_mapping(u32 chmap,u8 k)304 static inline int xa_pcm_is_identity_mapping(u32 chmap, u8 k)
305 {
306     u8      j;
307 
308     for (j = 0; j < k; j++, chmap >>= 4)
309         if ((chmap & 0xF) != j)
310             return 0;
311 
312     return 1;
313 }
314 
315 /* ...runtime initialization */
xa_pcm_do_runtime_init(XAPcmCodec * d)316 static inline XA_ERRORCODE xa_pcm_do_runtime_init(XAPcmCodec *d)
317 {
318     u8      in_width = d->in_pcm_width, out_width = d->out_pcm_width;
319     u8      in_ch = d->in_channels, out_ch = d->out_channels;
320     u32     chmap = d->chan_routing;
321 
322     /* ...check for supported processing schemes */
323     if (in_width == out_width)
324     {
325         /* ...check if we need to do a channel mapping */
326         if (in_ch != out_ch || !xa_pcm_is_identity_mapping(chmap, in_ch))
327         {
328             /* ...mapping is needed */
329             d->process = (in_width == 16 ? xa_pcm_do_execute_pcm16_chmap : xa_pcm_do_execute_pcm24_chmap);
330         }
331         else
332         {
333             /* ...setup identity translation */
334             d->process = xa_pcm_do_execute_copy;
335         }
336     }
337     else
338     {
339         /* ...samples converion is required */
340         d->process = (in_width == 16 ? xa_pcm_do_execute_pcm16_to_pcm24 : xa_pcm_do_execute_pcm24_to_pcm16);
341     }
342 
343     /* ...mark the runtime initialization is completed */
344     d->state = XA_PCM_FLAG_PREINIT_DONE | XA_PCM_FLAG_POSTINIT_DONE | XA_PCM_FLAG_RUNNING;
345 
346     TRACE(INIT, _b("PCM format converter initialized: PCM%u -> PCM%u, ich=%u, och=%u, map=%X"), in_width, out_width, in_ch, out_ch, chmap);
347 
348     return XA_NO_ERROR;
349 }
350 
351 /*******************************************************************************
352  * Commands processing
353  ******************************************************************************/
354 
355 /* ...standard codec initialization routine */
xa_pcm_get_api_size(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)356 static XA_ERRORCODE xa_pcm_get_api_size(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
357 {
358     /* ...return API structure size */
359     *(WORD32 *)pv_value = sizeof(*d);
360 
361     return XA_NO_ERROR;
362 }
363 
364 /* ...standard codec initialization routine */
xa_pcm_init(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)365 static XA_ERRORCODE xa_pcm_init(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
366 {
367     /* ...validity check */
368     XF_CHK_ERR(d, XA_API_FATAL_INVALID_CMD_TYPE);
369 
370     /* ...process particular initialization type */
371     switch (i_idx)
372     {
373     case XA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS:
374     {
375         /* ...pre-configuration initialization; reset internal data */
376         memset(d, 0, sizeof(*d));
377 
378         /* ...set default parameters */
379         d->in_pcm_width = d->out_pcm_width = 16;
380         d->in_channels = d->out_channels = 2;
381         d->chan_routing = (0 << 0) | (1 << 1);
382         d->sample_rate = 48000;
383 
384         /* ...open debug files */
385         //BUG((d->f_input = open("pcm-in.dat", O_WRONLY | O_CREAT, 0664)) < 0, _x("%m"));
386         //BUG((d->f_output = open("pcm-out.dat", O_WRONLY | O_CREAT, 0664)) < 0, _x("%m"));
387 
388         /* ...mark pre-initialization is done */
389         d->state = XA_PCM_FLAG_PREINIT_DONE;
390 
391         return XA_NO_ERROR;
392     }
393 
394     case XA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS:
395     {
396         /* ...post-configuration initialization (all parameters are set) */
397         XF_CHK_ERR(d->state & XA_PCM_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
398 
399         /* ...calculate input sample stride size */
400         d->in_stride = d->in_channels * (d->in_pcm_width == 16 ? 2 : 4);
401         d->out_stride = d->out_channels * (d->out_pcm_width == 16 ? 2 : 4);
402 
403         /* ...mark post-initialization is complete */
404         d->state |= XA_PCM_FLAG_POSTINIT_DONE;
405 
406         return XA_NO_ERROR;
407     }
408 
409     case XA_CMD_TYPE_INIT_PROCESS:
410     {
411         /* ...run-time initialization process; make sure post-init is complete */
412         XF_CHK_ERR(d->state & XA_PCM_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
413 
414         /* ...initialize runtime for specified transformation function */
415         return xa_pcm_do_runtime_init(d);
416     }
417 
418     case XA_CMD_TYPE_INIT_DONE_QUERY:
419     {
420         /* ...check for runtime initialization completion; maske usre post-init is complete */
421         XF_CHK_ERR(d->state & XA_PCM_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
422 
423         /* ...put current status */
424         *(WORD32 *)pv_value = (d->state & XA_PCM_FLAG_RUNNING ? 1 : 0);
425 
426         return XA_NO_ERROR;
427     }
428 
429     default:
430         /* ...unrecognized command */
431         return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
432     }
433 }
434 
435 /* ...set configuration parameter */
xa_pcm_set_config_param(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)436 static XA_ERRORCODE xa_pcm_set_config_param(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
437 {
438     WORD32      i_value;
439 
440     /* ...validity check */
441     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
442 
443     /* ...configuration is allowed only in PRE-CONFIG state */
444     XF_CHK_ERR(d->state == XA_PCM_FLAG_PREINIT_DONE, XA_PCM_CONFIG_NONFATAL_STATE);
445 
446     /* ...get integer parameter value */
447     i_value = *(WORD32 *)pv_value;
448 
449     /* ...process individual configuration parameter */
450     switch (i_idx)
451     {
452     case XA_CODEC_CONFIG_PARAM_SAMPLE_RATE:
453     case XA_PCM_CONFIG_PARAM_SAMPLE_RATE:
454         /* ...accept any sampling rate */
455         d->sample_rate = (u32)i_value;
456         return XA_NO_ERROR;
457 
458     case XA_PCM_CONFIG_PARAM_IN_PCM_WIDTH:
459         /* ...return input sample bit-width */
460         XF_CHK_ERR(i_value == 16 || i_value == 24, XA_PCM_CONFIG_NONFATAL_RANGE);
461         d->in_pcm_width = (u8)i_value;
462         return XA_NO_ERROR;
463 
464     case XA_PCM_CONFIG_PARAM_IN_CHANNELS:
465         /* ...support at most 8-channels stream */
466         XF_CHK_ERR(i_value > 0 && i_value <= 8, XA_PCM_CONFIG_NONFATAL_RANGE);
467         d->in_channels = (u8)i_value;
468         return XA_NO_ERROR;
469 
470     case XA_CODEC_CONFIG_PARAM_PCM_WIDTH:
471     case XA_PCM_CONFIG_PARAM_OUT_PCM_WIDTH:
472         /* ...we only support PCM16 and PCM24 */
473         XF_CHK_ERR(i_value == 16 || i_value == 24, XA_PCM_CONFIG_NONFATAL_RANGE);
474         d->out_pcm_width = (u8)i_value;
475         return XA_NO_ERROR;
476 
477     case XA_CODEC_CONFIG_PARAM_CHANNELS:
478     case XA_PCM_CONFIG_PARAM_OUT_CHANNELS:
479         /* ...support at most 8-channels stream */
480         XF_CHK_ERR(i_value > 0 && i_value <= 8, XA_API_FATAL_INVALID_CMD_TYPE);
481         d->out_channels = (u8)i_value;
482         return XA_NO_ERROR;
483 
484     case XA_PCM_CONFIG_PARAM_CHANROUTING:
485         /* ...accept any channel routing mask */
486         d->chan_routing = (u32)i_value;
487         return XA_NO_ERROR;
488 
489     default:
490         /* ...unrecognized parameter */
491         return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
492     }
493 }
494 
495 /* ...retrieve configuration parameter */
xa_pcm_get_config_param(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)496 static XA_ERRORCODE xa_pcm_get_config_param(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
497 {
498     /* ...validity check */
499     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
500 
501     /* ...make sure pre-configuration is completed */
502     XF_CHK_ERR(d->state & XA_PCM_FLAG_PREINIT_DONE, XA_PCM_CONFIG_NONFATAL_STATE);
503 
504     /* ...process individual parameter */
505     switch (i_idx)
506     {
507     case XA_CODEC_CONFIG_PARAM_SAMPLE_RATE:
508     case XA_PCM_CONFIG_PARAM_SAMPLE_RATE:
509         /* ...return output sampling frequency */
510         *(WORD32 *)pv_value = d->sample_rate;
511         return XA_NO_ERROR;
512 
513     case XA_PCM_CONFIG_PARAM_IN_PCM_WIDTH:
514         /* ...return input sample bit-width */
515         *(WORD32 *)pv_value = d->in_pcm_width;
516         return XA_NO_ERROR;
517 
518     case XA_PCM_CONFIG_PARAM_IN_CHANNELS:
519         /* ...return number of input channels */
520         *(WORD32 *)pv_value = d->in_channels;
521         return XA_NO_ERROR;
522 
523     case XA_CODEC_CONFIG_PARAM_PCM_WIDTH:
524     case XA_PCM_CONFIG_PARAM_OUT_PCM_WIDTH:
525         /* ...return output sample bit-width */
526         *(WORD32 *)pv_value = d->out_pcm_width;
527         return XA_NO_ERROR;
528 
529     case XA_CODEC_CONFIG_PARAM_CHANNELS:
530     case XA_PCM_CONFIG_PARAM_OUT_CHANNELS:
531         /* ...return number of output channels */
532         *(WORD32 *)pv_value = d->out_channels;
533         return XA_NO_ERROR;
534 
535     case XA_PCM_CONFIG_PARAM_CHANROUTING:
536         /* ...return current channel routing mask */
537         *(WORD32 *)pv_value = d->chan_routing;
538         return XA_NO_ERROR;
539 
540     default:
541         /* ...unrecognized parameter */
542         return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
543     }
544 }
545 
546 /* ...execution command */
xa_pcm_execute(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)547 static XA_ERRORCODE xa_pcm_execute(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
548 {
549     /* ...basic validity check */
550     XF_CHK_ERR(d, XA_API_FATAL_INVALID_CMD_TYPE);
551 
552    /* ...codec must be in running state */
553     XF_CHK_ERR(d->state & XA_PCM_FLAG_RUNNING, XA_API_FATAL_INVALID_CMD_TYPE);
554 
555     /* ...process individual command type */
556     switch (i_idx)
557     {
558     case XA_CMD_TYPE_DO_EXECUTE:
559         /* ...do data processing (tbd - result code is bad) */
560         if (d->insize != 0)
561         {
562             XF_CHK_ERR(!XA_ERROR_SEVERITY(d->process(d)), XA_PCM_EXEC_FATAL_STATE);
563         }
564 
565         /* ...process end-of-stream condition */
566         (d->state & XA_PCM_FLAG_EOS ? d->state ^= XA_PCM_FLAG_EOS | XA_PCM_FLAG_COMPLETE : 0);
567 
568         return XA_NO_ERROR;
569 
570     case XA_CMD_TYPE_DONE_QUERY:
571         /* ...check if processing is complete */
572         XF_CHK_ERR(pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
573 
574         /* ...return completion status */
575         *(WORD32 *)pv_value = (d->state & XA_PCM_FLAG_COMPLETE ? 1 : 0);
576 
577         return XA_NO_ERROR;
578 
579     case XA_CMD_TYPE_DO_RUNTIME_INIT:
580         /* ...reset codec operation */
581         return xa_pcm_do_runtime_init(d);
582 
583     default:
584         /* ...unrecognized command */
585         return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
586     }
587 }
588 
589 /* ...set number of input bytes */
xa_pcm_set_input_bytes(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)590 static XA_ERRORCODE xa_pcm_set_input_bytes(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
591 {
592     u32     in_stride = d->in_stride;
593     u32     insize;
594 
595     /* ...validity check */
596     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
597 
598     /* ...track index must be valid */
599     XF_CHK_ERR(i_idx == 0, XA_API_FATAL_INVALID_CMD_TYPE);
600 
601     /* ...component must be initialized */
602     XF_CHK_ERR(d->state & XA_PCM_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
603 
604     /* ...input buffer must exist */
605     XF_CHK_ERR(d->input, XA_API_FATAL_INVALID_CMD_TYPE);
606 
607     /* ...convert bytes into samples (don't like division, but still...) */
608     insize = *(WORD32 *)pv_value / in_stride;
609 
610     /* ...make sure we have integral amount of samples */
611     XF_CHK_ERR(*(WORD32 *)pv_value == insize * in_stride, XA_API_FATAL_INVALID_CMD_TYPE);
612 
613     /* ...limit input buffer size to maximal value*/
614     d->insize = (insize > XA_PCM_MAX_SAMPLES ? XA_PCM_MAX_SAMPLES : insize);
615 
616     return XA_NO_ERROR;
617 }
618 
619 /* ...get number of output bytes produced */
xa_pcm_get_output_bytes(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)620 static XA_ERRORCODE xa_pcm_get_output_bytes(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
621 {
622     /* ...validity check */
623     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
624 
625     /* ...buffer index must be valid */
626     XF_CHK_ERR(i_idx == 1, XA_API_FATAL_INVALID_CMD_TYPE);
627 
628     /* ...component must be initialized */
629     XF_CHK_ERR(d->state & XA_PCM_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
630 
631     /* ...output buffer must exist */
632     XF_CHK_ERR(d->output, XA_API_FATAL_INVALID_CMD_TYPE);
633 
634     /* ...return number of produced bytes (and reset instantly? - tbd) */
635     *(WORD32 *)pv_value = d->produced;
636 
637     return XA_NO_ERROR;
638 }
639 
640 /* ...get number of consumed bytes */
xa_pcm_get_curidx_input_buf(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)641 static XA_ERRORCODE xa_pcm_get_curidx_input_buf(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
642 {
643     /* ...validity check */
644     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
645 
646     /* ...index must be valid */
647     XF_CHK_ERR(i_idx == 0, XA_API_FATAL_INVALID_CMD_TYPE);
648 
649     /* ...input buffer must exist */
650     XF_CHK_ERR(d->input, XA_PCM_EXEC_NONFATAL_INPUT);
651 
652     /* ...return number of bytes consumed */
653     *(WORD32 *)pv_value = d->consumed;
654 
655     return XA_NO_ERROR;
656 }
657 
658 /* ...end-of-stream processing */
xa_pcm_input_over(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)659 static XA_ERRORCODE xa_pcm_input_over(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
660 {
661     /* ...validity check */
662     XF_CHK_ERR(d, XA_API_FATAL_INVALID_CMD_TYPE);
663 
664     /* ...put end-of-stream flag */
665     d->state |= XA_PCM_FLAG_EOS;
666 
667     TRACE(PROCESS, _b("Input-over-condition signalled"));
668 
669     return XA_NO_ERROR;
670 }
671 
672 /* ..get total amount of data for memory tables */
xa_pcm_get_memtabs_size(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)673 static XA_ERRORCODE xa_pcm_get_memtabs_size(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
674 {
675     /* ...basic validity checks */
676     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
677 
678     /* ...check mixer is pre-initialized */
679     XF_CHK_ERR(d->state & XA_PCM_FLAG_PREINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
680 
681     /* ...we have all our tables inside API structure */
682     *(WORD32 *)pv_value = 0;
683 
684     return XA_NO_ERROR;
685 }
686 
687 /* ...return total amount of memory buffers */
xa_pcm_get_n_memtabs(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)688 static XA_ERRORCODE xa_pcm_get_n_memtabs(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
689 {
690     /* ...basic validity checks */
691     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
692 
693     /* ...we have 1 input buffer and 1 output buffer */
694     *(WORD32 *)pv_value = 1 + 1;
695 
696     return XA_NO_ERROR;
697 }
698 
699 /* ...return memory type data */
xa_pcm_get_mem_info_type(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)700 static XA_ERRORCODE xa_pcm_get_mem_info_type(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
701 {
702     /* ...basic validity check */
703     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
704 
705     /* ...codec must be in post-init state */
706     XF_CHK_ERR(d->state & XA_PCM_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
707 
708     /* ...check buffer type */
709     switch (i_idx)
710     {
711     case 0:
712         *(WORD32 *)pv_value = XA_MEMTYPE_INPUT;
713         return XA_NO_ERROR;
714 
715     case 1:
716         *(WORD32 *)pv_value = XA_MEMTYPE_OUTPUT;
717         return XA_NO_ERROR;
718 
719     default:
720         return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
721     }
722 }
723 
724 /* ...return memory buffer size */
xa_pcm_get_mem_info_size(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)725 static XA_ERRORCODE xa_pcm_get_mem_info_size(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
726 {
727     /* ...basic validity check */
728     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
729 
730     /* ...codec must be in post-init state */
731     XF_CHK_ERR(d->state & XA_PCM_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
732 
733     /* ...determine particular buffer */
734     switch (i_idx)
735     {
736     case 0:
737         /* ...input buffer size can be any */
738         *(WORD32 *)pv_value = 0;
739         return XA_NO_ERROR;
740 
741     case 1:
742         /* ...output buffer size is dependent on stride */
743         *(WORD32 *)pv_value = XA_PCM_MAX_SAMPLES * d->out_stride;
744         return XA_NO_ERROR;
745 
746     default:
747         /* ...invalid buffer index */
748         return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
749     }
750 }
751 
752 /* ...return memory alignment data */
xa_pcm_get_mem_info_alignment(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)753 static XA_ERRORCODE xa_pcm_get_mem_info_alignment(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
754 {
755     /* ...basic validity check */
756     XF_CHK_ERR(d && pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
757 
758     /* ...codec must be in post-initialization state */
759     XF_CHK_ERR(d->state & XA_PCM_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
760 
761     /* ...all buffers are 4-bytes aligned */
762     *(WORD32 *)pv_value = 4;
763 
764     return XA_NO_ERROR;
765 }
766 
767 /* ...set memory pointer */
xa_pcm_set_mem_ptr(XAPcmCodec * d,WORD32 i_idx,pVOID pv_value)768 static XA_ERRORCODE xa_pcm_set_mem_ptr(XAPcmCodec *d, WORD32 i_idx, pVOID pv_value)
769 {
770     /* ...basic validity check */
771     XF_CHK_ERR(d, XA_API_FATAL_INVALID_CMD_TYPE);
772     XF_CHK_ERR(pv_value, XA_API_FATAL_INVALID_CMD_TYPE);
773 
774     /* ...codec must be in post-initialized state */
775     XF_CHK_ERR(d->state & XA_PCM_FLAG_POSTINIT_DONE, XA_API_FATAL_INVALID_CMD_TYPE);
776 
777     /* ...select memory buffer */
778     switch (i_idx)
779     {
780     case 0:
781         /* ...input buffer */
782         d->input = pv_value;
783         return XA_NO_ERROR;
784 
785     case 1:
786         /* ...output buffer */
787         d->output = pv_value;
788         return XA_NO_ERROR;
789 
790     default:
791         /* ...invalid index */
792         return XF_CHK_ERR(0, XA_API_FATAL_INVALID_CMD_TYPE);
793     }
794 }
795 
796 /*******************************************************************************
797  * API command hooks
798  ******************************************************************************/
799 
800 static XA_ERRORCODE (* const xa_pcm_api[])(XAPcmCodec *, WORD32, pVOID) =
801 {
802     [XA_API_CMD_GET_API_SIZE]           = xa_pcm_get_api_size,
803 
804     [XA_API_CMD_INIT]                   = xa_pcm_init,
805     [XA_API_CMD_SET_CONFIG_PARAM]       = xa_pcm_set_config_param,
806     [XA_API_CMD_GET_CONFIG_PARAM]       = xa_pcm_get_config_param,
807 
808     [XA_API_CMD_EXECUTE]                = xa_pcm_execute,
809     [XA_API_CMD_SET_INPUT_BYTES]        = xa_pcm_set_input_bytes,
810     [XA_API_CMD_GET_OUTPUT_BYTES]       = xa_pcm_get_output_bytes,
811     [XA_API_CMD_GET_CURIDX_INPUT_BUF]   = xa_pcm_get_curidx_input_buf,
812     [XA_API_CMD_INPUT_OVER]             = xa_pcm_input_over,
813 
814     [XA_API_CMD_GET_MEMTABS_SIZE]       = xa_pcm_get_memtabs_size,
815     [XA_API_CMD_GET_N_MEMTABS]          = xa_pcm_get_n_memtabs,
816     [XA_API_CMD_GET_MEM_INFO_TYPE]      = xa_pcm_get_mem_info_type,
817     [XA_API_CMD_GET_MEM_INFO_SIZE]      = xa_pcm_get_mem_info_size,
818     [XA_API_CMD_GET_MEM_INFO_ALIGNMENT] = xa_pcm_get_mem_info_alignment,
819     [XA_API_CMD_SET_MEM_PTR]            = xa_pcm_set_mem_ptr,
820 };
821 
822 /* ...total numer of commands supported */
823 #define XA_PCM_API_COMMANDS_NUM     (sizeof(xa_pcm_api) / sizeof(xa_pcm_api[0]))
824 
825 /*******************************************************************************
826  * API entry point
827  ******************************************************************************/
828 
xa_pcm_codec(xa_codec_handle_t p_xa_module_obj,WORD32 i_cmd,WORD32 i_idx,pVOID pv_value)829 XA_ERRORCODE xa_pcm_codec(xa_codec_handle_t p_xa_module_obj, WORD32 i_cmd, WORD32 i_idx, pVOID pv_value)
830 {
831     XAPcmCodec *d = (XAPcmCodec *) p_xa_module_obj;
832 
833     /* ...check if command index is valid */
834     XF_CHK_ERR(i_cmd < XA_PCM_API_COMMANDS_NUM, XA_API_FATAL_INVALID_CMD);
835 
836     /* ...see if command is defined */
837     XF_CHK_ERR(xa_pcm_api[i_cmd], XA_API_FATAL_INVALID_CMD);
838 
839     /* ...execute requested command */
840     return xa_pcm_api[i_cmd](d, i_idx, pv_value);
841 }
842