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-class-audio-codec.c
25  *
26  * Generic audio codec task implementation
27  *
28  ******************************************************************************/
29 
30 #define MODULE_TAG                      CODEC
31 
32 /*******************************************************************************
33  * Includes
34  ******************************************************************************/
35 
36 #include "xf.h"
37 #include "xa-class-base.h"
38 #include "audio/xa-audio-decoder-api.h"
39 
40 /*******************************************************************************
41  * Tracing configuration
42  ******************************************************************************/
43 
44 TRACE_TAG(INIT, 1);
45 TRACE_TAG(WARNING, 1);
46 TRACE_TAG(INFO, 1);
47 TRACE_TAG(INPUT, 1);
48 TRACE_TAG(OUTPUT, 1);
49 TRACE_TAG(DECODE, 1);
50 
51 /*******************************************************************************
52  * Internal functions definitions
53  ******************************************************************************/
54 
55 typedef struct XAAudioCodec
56 {
57     /***************************************************************************
58      * Control data
59      **************************************************************************/
60 
61     /* ...generic audio codec data */
62     XACodecBase             base;
63 
64     /* ...input port data */
65     xf_input_port_t         input;
66 
67     /* ...output port data */
68     xf_output_port_t        output;
69 
70     /* ...input port index */
71     WORD32                  in_idx;
72 
73     /* ...output port index */
74     WORD32                  out_idx;
75 
76     /***************************************************************************
77      * Run-time configuration parameters
78      **************************************************************************/
79 
80     /* ...sample size in bytes */
81     u32                     sample_size;
82 
83     /* ...audio sample duration */
84     u32                     factor;
85 
86     /* ...total number of produced audio frames since last reset */
87     u32                     produced;
88 
89 }   XAAudioCodec;
90 
91 /*******************************************************************************
92  * Auxiliary codec execution flags
93  ******************************************************************************/
94 
95 /* ...input port setup condition */
96 #define XA_CODEC_FLAG_INPUT_SETUP       __XA_BASE_FLAG(1 << 0)
97 
98 /* ...output port setup condition */
99 #define XA_CODEC_FLAG_OUTPUT_SETUP      __XA_BASE_FLAG(1 << 1)
100 
101 /*******************************************************************************
102  * Data processing scheduling
103  ******************************************************************************/
104 
105 /* ...prepare codec for steady operation (tbd - don't absolutely like it) */
xa_codec_prepare_runtime(XAAudioCodec * codec)106 static inline XA_ERRORCODE xa_codec_prepare_runtime(XAAudioCodec *codec)
107 {
108     XACodecBase    *base = (XACodecBase *)codec;
109     xf_message_t   *m = xf_msg_queue_head(&codec->output.queue);
110     xf_start_msg_t *msg = m->buffer;
111     u32             frame_size;
112     u32             factor;
113 
114     /* ...fill-in buffer parameters */
115     XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_CODEC_CONFIG_PARAM_SAMPLE_RATE, &msg->sample_rate);
116     XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_CODEC_CONFIG_PARAM_CHANNELS, &msg->channels);
117     XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_CODEC_CONFIG_PARAM_PCM_WIDTH, &msg->pcm_width);
118     XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, codec->in_idx, &msg->input_length);
119     XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, codec->out_idx, &msg->output_length);
120 
121     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);
122 
123     /* ...reallocate input port buffer as needed - tbd */
124     BUG(msg->input_length > codec->input.length, _x("Input buffer reallocation required: %u to %u"), codec->input.length, msg->input_length);
125 
126     /* ...save sample size in bytes */
127     codec->sample_size = msg->channels * (msg->pcm_width == 16 ? 2 : 4);
128 
129     /* ...calculate frame duration; get number of samples in the frame (don't like division here - tbd) */
130     frame_size = msg->output_length / codec->sample_size;
131 
132     /* ...it must be a multiple */
133     XF_CHK_ERR(frame_size * codec->sample_size == msg->output_length, XA_API_FATAL_INVALID_CMD_TYPE);
134 
135     /* ...retrieve upsampling factor for given sample rate */
136     XF_CHK_ERR(factor = xf_timebase_factor(msg->sample_rate), XA_API_FATAL_INVALID_CMD_TYPE);
137 
138     /* ...set frame duration factor (converts number of bytes into timebase units) */
139     codec->factor = factor / codec->sample_size;
140 
141     TRACE(INIT, _b("ts-factor: %u (%u)"), codec->factor, factor);
142 
143     BUG(codec->factor * codec->sample_size != factor, _x("Freq mismatch: %u vs %u"), codec->factor * codec->sample_size, factor);
144 
145     /* ...pass response to caller (push out of output port) */
146     xf_output_port_produce(&codec->output, sizeof(*msg));
147 
148     /* ...codec runtime initialization is completed */
149     TRACE(INIT, _b("codec[%p] runtime initialized: i=%u, o=%u"), codec, msg->input_length, msg->output_length);
150 
151     return XA_NO_ERROR;
152 }
153 
154 /*******************************************************************************
155  * Commands processing
156  ******************************************************************************/
157 
158 /* ...EMPTY-THIS-BUFFER command processing */
xa_codec_empty_this_buffer(XACodecBase * base,xf_message_t * m)159 static XA_ERRORCODE xa_codec_empty_this_buffer(XACodecBase *base, xf_message_t *m)
160 {
161     XAAudioCodec   *codec = (XAAudioCodec *) base;
162 
163     /* ...make sure the port is valid */
164     XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == 0, XA_API_FATAL_INVALID_CMD);
165 
166     /* ...command is allowed only in post-init state */
167     XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
168 
169     /* ...put message into input queue */
170     if (xf_input_port_put(&codec->input, m))
171     {
172         /* ...restart stream if it is in completed state */
173         if (base->state & XA_BASE_FLAG_COMPLETED)
174         {
175             /* ...reset execution stage */
176             base->state = XA_BASE_FLAG_POSTINIT | XA_BASE_FLAG_EXECUTION;
177 
178             /* ...reset execution runtime */
179             XA_API(base, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DO_RUNTIME_INIT, NULL);
180 
181             /* ...reset produced samples counter */
182             codec->produced = 0;
183         }
184 
185         /* ...codec must be in one of these states */
186         XF_CHK_ERR(base->state & (XA_BASE_FLAG_RUNTIME_INIT | XA_BASE_FLAG_EXECUTION), XA_API_FATAL_INVALID_CMD);
187 
188         /* ...schedule data processing if output is ready */
189         if (xf_output_port_ready(&codec->output))
190         {
191             xa_base_schedule(base, 0);
192         }
193     }
194 
195     TRACE(INPUT, _b("Received buffer [%p]:%u"), m->buffer, m->length);
196 
197     return XA_NO_ERROR;
198 }
199 
200 /* ...FILL-THIS-BUFFER command processing */
xa_codec_fill_this_buffer(XACodecBase * base,xf_message_t * m)201 static XA_ERRORCODE xa_codec_fill_this_buffer(XACodecBase *base, xf_message_t *m)
202 {
203     XAAudioCodec   *codec = (XAAudioCodec *) base;
204 
205     /* ...make sure the port is valid */
206     XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == 1, XA_API_FATAL_INVALID_CMD);
207 
208     /* ...command is allowed only in postinit state */
209     XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
210 
211     /* ...special handling of zero-length buffer */
212     if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
213     {
214         /* ...message must be zero-length */
215         BUG(m->length != 0, _x("Invalid message length: %u"), m->length);
216     }
217     else if (m == xf_output_port_control_msg(&codec->output))
218     {
219         /* ...end-of-stream processing indication received; check the state */
220         BUG((base->state & XA_BASE_FLAG_COMPLETED) == 0, _x("invalid state: %x"), base->state);
221 
222         /* ... mark flushing sequence is done */
223         xf_output_port_flush_done(&codec->output);
224 
225         /* ...complete pending zero-length input buffer */
226         xf_input_port_purge(&codec->input);
227 
228         TRACE(INFO, _b("codec[%p] playback completed"), codec);
229 
230         /* ...playback is over */
231         return XA_NO_ERROR;
232     }
233     else if ((base->state & XA_BASE_FLAG_COMPLETED) && !xf_output_port_routed(&codec->output))
234     {
235         /* ...return message arrived from application immediately */
236         xf_response_ok(m);
237 
238         return XA_NO_ERROR;
239     }
240     else
241     {
242         TRACE(OUTPUT, _b("Received output buffer [%p]:%u"), m->buffer, m->length);
243 
244         /* ...adjust message length (may be shorter than original) */
245         m->length = codec->output.length;
246     }
247 
248     /* ...place message into output port */
249     if (xf_output_port_put(&codec->output, m) && xf_input_port_ready(&codec->input))
250     {
251         /* ...schedule data processing instantly */
252         if (base->state & (XA_BASE_FLAG_RUNTIME_INIT | XA_BASE_FLAG_EXECUTION))
253         {
254             xa_base_schedule(base, 0);
255         }
256     }
257 
258     return XA_NO_ERROR;
259 }
260 
261 /* ...output port routing */
xa_codec_port_route(XACodecBase * base,xf_message_t * m)262 static XA_ERRORCODE xa_codec_port_route(XACodecBase *base, xf_message_t *m)
263 {
264     XAAudioCodec           *codec = (XAAudioCodec *) base;
265     xf_route_port_msg_t    *cmd = m->buffer;
266     xf_output_port_t       *port = &codec->output;
267     u32                     src = XF_MSG_DST(m->id);
268     u32                     dst = cmd->dst;
269 
270     /* ...command is allowed only in "postinit" state */
271     XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
272 
273     /* ...make sure output port is addressed */
274     XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == 1, XA_API_FATAL_INVALID_CMD_TYPE);
275 
276     /* ...make sure port is not routed yet */
277     XF_CHK_ERR(!xf_output_port_routed(port), XA_API_FATAL_INVALID_CMD_TYPE);
278 
279     /* ...route output port - allocate queue */
280     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);
281 
282     /* ...schedule processing instantly */
283     xa_base_schedule(base, 0);
284 
285     /* ...pass success result to caller */
286     xf_response_ok(m);
287 
288     return XA_NO_ERROR;
289 }
290 
291 /* ...port unroute command */
xa_codec_port_unroute(XACodecBase * base,xf_message_t * m)292 static XA_ERRORCODE xa_codec_port_unroute(XACodecBase *base, xf_message_t *m)
293 {
294     XAAudioCodec           *codec = (XAAudioCodec *) base;
295 
296     /* ...command is allowed only in "postinit" state */
297     XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
298 
299     /* ...make sure output port is addressed */
300     XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == 1, XA_API_FATAL_INVALID_CMD_TYPE);
301 
302     /* ...cancel any pending processing */
303     xa_base_cancel(base);
304 
305     /* ...clear output-port-setup condition */
306     base->state &= ~XA_CODEC_FLAG_OUTPUT_SETUP;
307 
308     /* ...pass flush command down the graph */
309     if (xf_output_port_flush(&codec->output, XF_FLUSH))
310     {
311         TRACE(INFO, _b("port is idle; instantly unroute"));
312 
313         /* ...flushing sequence is not needed; command may be satisfied instantly */
314         xf_output_port_unroute(&codec->output);
315 
316         /* ...pass response to the proxy */
317         xf_response_ok(m);
318     }
319     else
320     {
321         TRACE(INFO, _b("port is busy; propagate unroute command"));
322 
323         /* ...flushing sequence is started; save flow-control message */
324         xf_output_port_unroute_start(&codec->output, m);
325     }
326 
327     return XA_NO_ERROR;
328 }
329 
330 /* ...FLUSH command processing */
xa_codec_flush(XACodecBase * base,xf_message_t * m)331 static XA_ERRORCODE xa_codec_flush(XACodecBase *base, xf_message_t *m)
332 {
333     XAAudioCodec   *codec = (XAAudioCodec *) base;
334 
335     /* ...command is allowed only in "postinit" state */
336     XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
337 
338     /* ...ensure input parameter length is zero */
339     XF_CHK_ERR(m->length == 0, XA_API_FATAL_INVALID_CMD_TYPE);
340 
341     TRACE(1, _b("flush command received"));
342 
343     /* ...flush command must be addressed to input port */
344     if (XF_MSG_DST_PORT(m->id) == 0)
345     {
346         /* ...cancel data processing message if needed */
347         xa_base_cancel(base);
348 
349         /* ...input port flushing; purge content of input buffer */
350         xf_input_port_purge(&codec->input);
351 
352         /* ...clear input-ready condition */
353         base->state &= ~XA_CODEC_FLAG_INPUT_SETUP;
354 
355         /* ...reset execution runtime */
356         XA_API(base, XA_API_CMD_EXECUTE, XA_CMD_TYPE_DO_RUNTIME_INIT, NULL);
357 
358         /* ...reset produced samples counter */
359         codec->produced = 0;
360 
361         /* ...propagate flushing command to output port */
362         if (xf_output_port_flush(&codec->output, XF_FLUSH))
363         {
364             /* ...flushing sequence is not needed; satisfy command instantly */
365             xf_response(m);
366         }
367         else
368         {
369             /* ...flushing sequence is started; save flow-control message at input port */
370             xf_input_port_control_save(&codec->input, m);
371         }
372     }
373     else if (xf_output_port_unrouting(&codec->output))
374     {
375         /* ...flushing during port unrouting; complete unroute sequence */
376         xf_output_port_unroute_done(&codec->output);
377 
378         TRACE(INFO, _b("port is unrouted"));
379     }
380     else
381     {
382         /* ...output port flush command/response; check if the port is routed */
383         if (!xf_output_port_routed(&codec->output))
384         {
385             /* ...complete all queued messages */
386             xf_output_port_flush(&codec->output, XF_FLUSH);
387 
388             /* ...and pass response to flushing command */
389             xf_response(m);
390         }
391         else
392         {
393             /* ...response to flushing command received */
394             BUG(m != xf_output_port_control_msg(&codec->output), _x("invalid message: %p"), m);
395 
396             /* ...mark flushing sequence is completed */
397             xf_output_port_flush_done(&codec->output);
398 
399             /* ...complete original flow-control command */
400             xf_input_port_purge_done(&codec->input);
401         }
402 
403         /* ...clear output-setup condition */
404         base->state &= ~XA_CODEC_FLAG_OUTPUT_SETUP;
405     }
406 
407     return XA_NO_ERROR;
408 }
409 
410 /*******************************************************************************
411  * Generic codec API
412  ******************************************************************************/
413 
414 /* ...memory buffer handling */
xa_codec_memtab(XACodecBase * base,WORD32 idx,WORD32 type,WORD32 size,WORD32 align,u32 core)415 static XA_ERRORCODE xa_codec_memtab(XACodecBase *base, WORD32 idx, WORD32 type, WORD32 size, WORD32 align, u32 core)
416 {
417     XAAudioCodec   *codec = (XAAudioCodec *) base;
418 
419     if (type == XA_MEMTYPE_INPUT)
420     {
421         /* ...input port specification; allocate internal buffer */
422         XF_CHK_ERR(xf_input_port_init(&codec->input, size, align, core) == 0, XA_API_FATAL_MEM_ALLOC);
423 
424         /* ...save input port index */
425         codec->in_idx = idx;
426 
427         /* ...set input buffer pointer as needed */
428         (size ? XA_API(base, XA_API_CMD_SET_MEM_PTR, idx, codec->input.buffer) : 0);
429 
430         (size ? TRACE(1, _x("set input ptr: %p"), codec->input.buffer) : 0);
431     }
432     else
433     {
434         /* ...output buffer specification */
435         XF_CHK_ERR(type == XA_MEMTYPE_OUTPUT, XA_API_FATAL_INVALID_CMD_TYPE);
436 
437         /* ...initialize output port queue (no allocation here yet) */
438         XF_CHK_ERR(xf_output_port_init(&codec->output, size) == 0, XA_API_FATAL_MEM_ALLOC);
439 
440         /* ...save output port index */
441         codec->out_idx = idx;
442     }
443 
444     return XA_NO_ERROR;
445 }
446 
447 /* ...prepare input/output buffers */
xa_codec_preprocess(XACodecBase * base)448 static XA_ERRORCODE xa_codec_preprocess(XACodecBase *base)
449 {
450     XAAudioCodec   *codec = (XAAudioCodec *) base;
451 
452     /* ...prepare output buffer if needed */
453     if (!(base->state & XA_CODEC_FLAG_OUTPUT_SETUP))
454     {
455         void   *output;
456 
457         /* ...get output buffer from port, if possible */
458         if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
459         {
460             /* ...run-time is not initialized yet; use scratch buffer */
461             output = base->scratch;
462         }
463         else if ((output = xf_output_port_data(&codec->output)) == NULL)
464         {
465             /* ...no output buffer available */
466             return XA_CODEC_EXEC_NO_DATA;
467         }
468 
469         /* ...set the output buffer pointer */
470         XA_API(base, XA_API_CMD_SET_MEM_PTR, codec->out_idx, output);
471 
472         TRACE(1, _x("set output ptr: %p"), output);
473 
474         /* ...mark output port is setup */
475         base->state ^= XA_CODEC_FLAG_OUTPUT_SETUP;
476     }
477 
478     /* ...prepare input data if needed */
479     if (!(base->state & XA_CODEC_FLAG_INPUT_SETUP))
480     {
481         void   *input;
482         u32     filled;
483 
484         /* ...fill input buffer */
485         if (xf_input_port_bypass(&codec->input))
486         {
487             /* ...use input buffer directly; check if there is data available */
488             if ((input = xf_input_port_data(&codec->input)) != NULL)
489             {
490                 /* ...set input data buffer pointer */
491                 XA_API(base, XA_API_CMD_SET_MEM_PTR, codec->in_idx, input);
492 
493                 /* ...retrieve number of input bytes */
494                 filled = xf_input_port_length(&codec->input);
495             }
496             else if (!xf_input_port_done(&codec->input))
497             {
498                 /* ...return non-fatal indication to prevent further processing */
499                 return XA_CODEC_EXEC_NO_DATA;
500             }
501             else
502             {
503                 /* ...mark we have no data in current buffer */
504                 filled = 0;
505             }
506         }
507         else
508         {
509             /* ...port is in non-bypass mode; try to fill internal buffer */
510             if (xf_input_port_done(&codec->input) || xf_input_port_fill(&codec->input))
511             {
512                 /* ...retrieve number of bytes in input buffer (not really - tbd) */
513                 filled = xf_input_port_level(&codec->input);
514             }
515             else
516             {
517                 /* ...return non-fatal indication to prevent further processing */
518                 return XA_CODEC_EXEC_NO_DATA;
519             }
520         }
521 
522         /* ...check if input stream is over */
523         if (xf_input_port_done(&codec->input))
524         {
525             /* ...pass input-over command to the codec to indicate the final buffer */
526             XA_API(base, XA_API_CMD_INPUT_OVER, codec->in_idx, NULL);
527 
528             TRACE(INFO, _b("codec[%p]: signal input-over (filled: %u)"), codec, filled);
529         }
530 
531         TRACE(INPUT, _b("input-buffer fill-level: %u bytes"), filled);
532 
533         /* ...specify number of bytes available in the input buffer */
534         XA_API(base, XA_API_CMD_SET_INPUT_BYTES, codec->in_idx, &filled);
535 
536         /* ...mark input port is setup */
537         base->state ^= XA_CODEC_FLAG_INPUT_SETUP;
538     }
539 
540     return XA_NO_ERROR;
541 }
542 
543 /* ...post-processing operation; input/output ports maintenance */
xa_codec_postprocess(XACodecBase * base,int done)544 static XA_ERRORCODE xa_codec_postprocess(XACodecBase *base, int done)
545 {
546     XAAudioCodec   *codec = (XAAudioCodec *) base;
547     WORD32          consumed = 0;
548     WORD32          produced = 0;
549 
550     /* ...get number of consumed / produced bytes */
551     XA_API(base, XA_API_CMD_GET_CURIDX_INPUT_BUF, codec->in_idx, &consumed);
552 
553     /* ...get number of produced bytes only if runtime is initialized (sample size is known) */
554     (codec->sample_size ? XA_API(base, XA_API_CMD_GET_OUTPUT_BYTES, codec->out_idx, &produced) : 0);
555 
556     TRACE(DECODE, _b("codec[%p]::postprocess(c=%u, p=%u, d=%u)"), codec, consumed, produced, done);
557 
558     /* ...input buffer maintenance; check if we consumed anything */
559     if (consumed)
560     {
561         /* ...consume specified number of bytes from input port */
562         xf_input_port_consume(&codec->input, consumed);
563 
564         /* ...clear input-setup flag */
565         base->state ^= XA_CODEC_FLAG_INPUT_SETUP;
566     }
567 
568     /* ...output buffer maintenance; check if we have produced anything */
569     if (produced)
570     {
571         /* ...increment total number of produced samples (really don't like division here - tbd) */
572         codec->produced += produced / codec->sample_size;
573 
574         /* ...immediately complete output buffer (don't wait until it gets filled) */
575         xf_output_port_produce(&codec->output, produced);
576 
577         /* ...clear output port setup flag */
578         base->state ^= XA_CODEC_FLAG_OUTPUT_SETUP;
579     }
580 
581     /* ...process execution stage transition */
582     if (done)
583     {
584         if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
585         {
586             /* ...stream is completed while codec is in runtime initialization stage */
587             BUG(1, _x("breakpoint"));
588         }
589         else if (base->state & XA_BASE_FLAG_EXECUTION)
590         {
591             /* ...runtime initialization done */
592             XA_CHK(xa_codec_prepare_runtime(codec));
593 
594             /* ...clear output port setup flag as we were using scratch buffer;
595              * technically, no need to repeat setup of input buffer, but some codecs require
596              * it as well
597              */
598             base->state &= ~(XA_CODEC_FLAG_INPUT_SETUP | XA_CODEC_FLAG_OUTPUT_SETUP);
599         }
600         else
601         {
602             /* ...output stream is over; propagate condition to sink port */
603             if (xf_output_port_flush(&codec->output, XF_FILL_THIS_BUFFER))
604             {
605                 /* ...flushing sequence is not needed; complete pending zero-length input */
606                 xf_input_port_purge(&codec->input);
607 
608                 /* ...no propagation to output port */
609                 TRACE(INFO, _b("codec[%p] playback completed"), codec);
610             }
611             else
612             {
613                 /* ...flushing sequence is started; wait until flow-control message returns */
614                 TRACE(INFO, _b("propagate end-of-stream condition"));
615             }
616         }
617 
618         /* ...return early to prevent task rescheduling */
619         return XA_NO_ERROR;
620     }
621 
622     /* ...reschedule processing if needed */
623     if (xf_input_port_ready(&codec->input) && xf_output_port_ready(&codec->output))
624     {
625         /* ...schedule data processing with respect to its urgency */
626         xa_base_schedule(base, produced * codec->factor);
627     }
628 
629     return XA_NO_ERROR;
630 }
631 
632 /* ...configuration parameter retrieval */
xa_codec_getparam(XACodecBase * base,WORD32 id,pVOID value)633 static XA_ERRORCODE xa_codec_getparam(XACodecBase *base, WORD32 id, pVOID value)
634 {
635     XAAudioCodec   *codec = (XAAudioCodec *) base;
636 
637     if (id == XA_CODEC_CONFIG_PARAM_PRODUCED)
638     {
639         /* ...retrieve number of produced samples since last reset */
640         *(u32 *)value = codec->produced;
641 
642         return XA_NO_ERROR;
643     }
644     else
645     {
646         /* ...pass command to underlying codec plugin */
647         return XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, id, value);
648     }
649 }
650 
651 /*******************************************************************************
652  * Component entry point
653  ******************************************************************************/
654 
655 /* ...command hooks */
656 static XA_ERRORCODE (* const xa_codec_cmd[])(XACodecBase *, xf_message_t *) =
657 {
658     [XF_OPCODE_TYPE(XF_SET_PARAM)] = xa_base_set_param,
659     [XF_OPCODE_TYPE(XF_GET_PARAM)] = xa_base_get_param,
660     [XF_OPCODE_TYPE(XF_ROUTE)] = xa_codec_port_route,
661     [XF_OPCODE_TYPE(XF_UNROUTE)] = xa_codec_port_unroute,
662     [XF_OPCODE_TYPE(XF_EMPTY_THIS_BUFFER)] = xa_codec_empty_this_buffer,
663     [XF_OPCODE_TYPE(XF_FILL_THIS_BUFFER)] = xa_codec_fill_this_buffer,
664     [XF_OPCODE_TYPE(XF_FLUSH)] = xa_codec_flush,
665     [XF_OPCODE_TYPE(XF_SET_PARAM_EXT)] = xa_base_set_param_ext,
666     [XF_OPCODE_TYPE(XF_GET_PARAM_EXT)] = xa_base_get_param_ext,
667 };
668 
669 /* ...total number of commands supported */
670 #define XA_CODEC_CMD_NUM        (sizeof(xa_codec_cmd) / sizeof(xa_codec_cmd[0]))
671 
672 /* ...command processor for termination state (only for routed port case) */
xa_audio_codec_terminate(xf_component_t * component,xf_message_t * m)673 static int xa_audio_codec_terminate(xf_component_t *component, xf_message_t *m)
674 {
675     XAAudioCodec   *codec = (XAAudioCodec *) component;
676     u32             opcode = m->opcode;
677 
678     /* ...check if we received output port control message */
679     if (m == xf_output_port_control_msg(&codec->output))
680     {
681         /* ...output port flushing complete; mark port is idle and terminate */
682         xf_output_port_flush_done(&codec->output);
683         return -1;
684     }
685     else if (opcode == XF_FILL_THIS_BUFFER)
686     {
687         /* ...output buffer returned by the sink component; ignore and keep waiting */
688         TRACE(OUTPUT, _b("collect output buffer"));
689         return 0;
690     }
691     else if (opcode == XF_UNREGISTER)
692     {
693         /* ...ignore subsequent unregister command/response - tbd */
694         return 0;
695     }
696     else
697     {
698         /* ...everything else is responded with generic failure */
699         xf_response_err(m);
700         return 0;
701     }
702 }
703 
704 /* ...audio codec destructor */
xa_audio_codec_destroy(xf_component_t * component,xf_message_t * m)705 static int xa_audio_codec_destroy(xf_component_t *component, xf_message_t *m)
706 {
707     XAAudioCodec   *codec = (XAAudioCodec *) component;
708     u32             core = xf_component_core(component);
709 
710     /* ...destroy input port */
711     xf_input_port_destroy(&codec->input, core);
712 
713     /* ...destroy output port */
714     xf_output_port_destroy(&codec->output, core);
715 
716     /* ...deallocate all resources */
717     xa_base_destroy(&codec->base, XF_MM(sizeof(*codec)), core);
718 
719     TRACE(INIT, _b("audio-codec[%p@%u] destroyed"), codec, core);
720 
721     /* ...indicate the client has been destroyed */
722     return 0;
723 }
724 
725 /* ...audio codec destructor - first stage (ports unrouting) */
xa_audio_codec_cleanup(xf_component_t * component,xf_message_t * m)726 static int xa_audio_codec_cleanup(xf_component_t *component, xf_message_t *m)
727 {
728     XAAudioCodec *codec = (XAAudioCodec *) component;
729 
730     /* ...complete message with error response */
731     xf_response_err(m);
732 
733     /* ...cancel internal scheduling message if needed */
734     xa_base_cancel(&codec->base);
735 
736     /* ...purge input port (returns OK? pretty strange at this point - tbd) */
737     xf_input_port_purge(&codec->input);
738 
739     /* ...propagate unregister command to connected component */
740     if (xf_output_port_flush(&codec->output, XF_FLUSH))
741     {
742         /* ...flushing sequence is not needed; destroy audio codec */
743         return xa_audio_codec_destroy(component, NULL);
744     }
745     else
746     {
747         /* ...wait until output port is cleaned; adjust component hooks */
748         component->entry = xa_audio_codec_terminate;
749         component->exit = xa_audio_codec_destroy;
750 
751         TRACE(INIT, _b("codec[%p] cleanup sequence started"), codec);
752 
753         /* ...indicate that second stage is required */
754         return 1;
755     }
756 }
757 
758 /*******************************************************************************
759  * Audio codec component factory
760  ******************************************************************************/
761 
xa_audio_codec_factory(u32 core,xa_codec_func_t process)762 xf_component_t * xa_audio_codec_factory(u32 core, xa_codec_func_t process)
763 {
764     XAAudioCodec   *codec;
765 
766     /* ...allocate local memory for codec structure */
767     XF_CHK_ERR(codec = (XAAudioCodec *) xa_base_factory(core, XF_MM(sizeof(*codec)), process), NULL);
768 
769     /* ...set base codec API methods */
770     codec->base.memtab = xa_codec_memtab;
771     codec->base.preprocess = xa_codec_preprocess;
772     codec->base.postprocess = xa_codec_postprocess;
773     codec->base.getparam = xa_codec_getparam;
774 
775     /* ...set message commands processing table */
776     codec->base.command = xa_codec_cmd;
777     codec->base.command_num = XA_CODEC_CMD_NUM;
778 
779     /* ...set component destructor hook */
780     codec->base.component.exit = xa_audio_codec_cleanup;
781 
782     TRACE(INIT, _b("Codec[%p] initialized"), codec);
783 
784     return (xf_component_t *) codec;
785 }
786