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-mixer.c
25  *
26  * Generic mixer component class
27  *
28  ******************************************************************************/
29 
30 #define MODULE_TAG                      MIXER
31 
32 /*******************************************************************************
33  * Includes
34  ******************************************************************************/
35 
36 #include "xf.h"
37 #include "xa-class-base.h"
38 #include "audio/xa-mixer-api.h"
39 
40 /*******************************************************************************
41  * Tracing tags
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 
50 /*******************************************************************************
51  * Data structures
52  ******************************************************************************/
53 
54 /* ...mixed source - input data */
55 typedef struct XATrack
56 {
57     /* ...input port data */
58     xf_input_port_t     input;
59 
60     /* ...current presentation timestamp (in samples; local to a mixer state) */
61     u32                 pts;
62 
63     /* ...total amount of decoded frames since last synchronization point */
64     u32                 decoded;
65 
66     /* ...total amount of rendered frames (consumed) since last synchronization point */
67     u32                 rendered;
68 
69 }   XATrack;
70 
71 /*******************************************************************************
72  * Helpers
73  ******************************************************************************/
74 
xa_track_test_flags(XATrack * track,u32 flags)75 static inline u32 xa_track_test_flags(XATrack *track, u32 flags)
76 {
77     return (track->input.flags & flags);
78 }
79 
xa_track_set_flags(XATrack * track,u32 flags)80 static inline u32 xa_track_set_flags(XATrack *track, u32 flags)
81 {
82     return (track->input.flags |= flags);
83 }
84 
xa_track_clear_flags(XATrack * track,u32 flags)85 static inline u32 xa_track_clear_flags(XATrack *track, u32 flags)
86 {
87     return (track->input.flags &= ~flags);
88 }
89 
xa_track_toggle_flags(XATrack * track,u32 flags)90 static inline u32 xa_track_toggle_flags(XATrack *track, u32 flags)
91 {
92     return (track->input.flags ^= flags);
93 }
94 
95 /*******************************************************************************
96  * Mixer data definitions
97  ******************************************************************************/
98 
99 /* ...mixer data */
100 typedef struct XAMixer
101 {
102     /***************************************************************************
103      * Control data
104      **************************************************************************/
105 
106     /* ...generic audio codec data */
107     XACodecBase         base;
108 
109     /* ...input tracks */
110     XATrack             track[XA_MIXER_MAX_TRACK_NUMBER];
111 
112     /* ...output port */
113     xf_output_port_t    output;
114 
115     /***************************************************************************
116      * Run-time configuration parameters
117      **************************************************************************/
118 
119     /* ...audio frame size in samples */
120     u32                 frame_size;
121 
122     /* ...audio frame duration */
123     u32                 frame_duration;
124 
125     /* ...presentation timestamp (in samples; local mixer scope) */
126     u32                 pts;
127 
128 }   XAMixer;
129 
130 /*******************************************************************************
131  * Mixer flags
132  ******************************************************************************/
133 
134 /* ...output port setup completed */
135 #define XA_MIXER_FLAG_OUTPUT_SETUP      __XA_BASE_FLAG(1 << 0)
136 
137 /*******************************************************************************
138  * Track state flags
139  ******************************************************************************/
140 
141 /* ...track is idle (will autostart as soon as input data received) */
142 #define XA_TRACK_FLAG_IDLE              __XF_INPUT_FLAG(1 << 0)
143 
144 /* ...track is rendered */
145 #define XA_TRACK_FLAG_ACTIVE            __XF_INPUT_FLAG(1 << 1)
146 
147 /* ...track is paused */
148 #define XA_TRACK_FLAG_PAUSED            __XF_INPUT_FLAG(1 << 2)
149 
150 /* ...track input port is setup */
151 #define XA_TRACK_FLAG_INPUT_SETUP       __XF_INPUT_FLAG(1 << 3)
152 
153 /* ...track has received data */
154 #define XA_TRACK_FLAG_RECVD_DATA        __XF_INPUT_FLAG(1 << 4)
155 
156 /*******************************************************************************
157  * Helper functions
158  ******************************************************************************/
159 /* ...Count the tracks that have received data or are active*/
xa_mixer_check_active(XAMixer * mixer)160 static inline UWORD32 xa_mixer_check_active(XAMixer *mixer)
161 {
162     XATrack        *track;
163     UWORD32            i;
164     UWORD32            cnt = 0;
165 
166     for (track = &mixer->track[i = 0]; i < XA_MIXER_MAX_TRACK_NUMBER; i++, track++)
167     {
168         if (xa_track_test_flags(track, XA_TRACK_FLAG_RECVD_DATA | XA_TRACK_FLAG_ACTIVE))
169             cnt++;
170     }
171     return cnt;
172 }
173 
174 /* ...prepare mixer for steady operation */
xa_mixer_prepare_runtime(XAMixer * mixer)175 static inline XA_ERRORCODE xa_mixer_prepare_runtime(XAMixer *mixer)
176 {
177     XACodecBase    *base = (XACodecBase *) mixer;
178     xf_message_t   *m = xf_msg_dequeue(&mixer->output.queue);
179     xf_start_msg_t *msg = m->buffer;
180     u32             frame_size;
181     u32             factor;
182 
183     /* ...query mixer parameters */
184     XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_MIXER_CONFIG_PARAM_SAMPLE_RATE, &msg->sample_rate);
185     XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_MIXER_CONFIG_PARAM_CHANNELS, &msg->channels);
186     XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_MIXER_CONFIG_PARAM_PCM_WIDTH, &msg->pcm_width);
187     XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, 0, &msg->input_length);
188     XA_API(base, XA_API_CMD_GET_MEM_INFO_SIZE, XA_MIXER_MAX_TRACK_NUMBER, &msg->output_length);
189     XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_MIXER_CONFIG_PARAM_FRAME_SIZE, &frame_size);
190 
191     /* ...calculate mixer frame duration; get upsample factor */
192     XF_CHK_ERR(factor = xf_timebase_factor(msg->sample_rate), XA_MIXER_CONFIG_FATAL_RANGE);
193 
194     /* ...set mixer frame duration */
195     mixer->frame_duration = frame_size * factor;
196 
197     /* ...pass response to caller */
198     xf_response_data(m, sizeof(*msg));
199 
200     return XA_NO_ERROR;
201 }
202 
203 /*******************************************************************************
204  * Commands handlers
205  ******************************************************************************/
206 
207 /* ...EMPTY-THIS-BUFFER command processing */
xa_mixer_empty_this_buffer(XACodecBase * base,xf_message_t * m)208 static XA_ERRORCODE xa_mixer_empty_this_buffer(XACodecBase *base, xf_message_t *m)
209 {
210     XAMixer    *mixer = (XAMixer *) base;
211     u32         i = XF_MSG_DST_PORT(m->id);
212     XATrack    *track = &mixer->track[i];
213 
214     /* ...make sure the port is valid */
215     XF_CHK_ERR(i < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
216 
217     /* ...command is allowed only in "postinit" state */
218     XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
219 
220     TRACE(INPUT, _b("track-%u: received buffer [%p]:%u"), i, m->buffer, m->length);
221 
222     /* ...update received data for the track */
223     if (m->length)
224         xa_track_set_flags(track, XA_TRACK_FLAG_RECVD_DATA);
225     else
226         xa_track_clear_flags(track, XA_TRACK_FLAG_RECVD_DATA);
227 
228     /* ...place received message into track input port */
229     if (xf_input_port_put(&track->input, m))
230     {
231         /* ...process track autostart if needed */
232         if (xa_track_test_flags(track, XA_TRACK_FLAG_IDLE))
233         {
234             /* ...put track into active state */
235             xa_track_toggle_flags(track, XA_TRACK_FLAG_IDLE | XA_TRACK_FLAG_ACTIVE);
236 
237             /* ...save track presentation timestamp */
238             track->pts = mixer->pts;
239 
240             TRACE(INFO, _b("track-%u started (pts=%x)"), i, track->pts);
241         }
242 
243         /* ...schedule data processing if there is output port available */
244         if (xf_output_port_ready(&mixer->output))
245         {
246             /* ...force data processing */
247             xa_base_schedule(base, 0);
248         }
249     }
250 
251     return XA_NO_ERROR;
252 }
253 
254 /* ...FILL-THIS-BUFFER command processing */
xa_mixer_fill_this_buffer(XACodecBase * base,xf_message_t * m)255 static XA_ERRORCODE xa_mixer_fill_this_buffer(XACodecBase *base, xf_message_t *m)
256 {
257     XAMixer    *mixer = (XAMixer *) base;
258     u32         i = XF_MSG_DST_PORT(m->id);
259 
260     /* ...make sure the port is valid */
261     XF_CHK_ERR(i == XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
262 
263     /* ...command is allowed only in "postinit" state */
264     XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
265 
266     /* ...process runtime initialization explicitly */
267     if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
268     {
269         /* ...message must be zero-length */
270         XF_CHK_ERR(m->length == 0, XA_MIXER_EXEC_FATAL_STATE);
271     }
272     else if (m->length != 0) /* ...EOS response */
273     {
274         /* ...message must have exactly expected size (there is no ordered abortion) */
275         XF_CHK_ERR(m->length == mixer->output.length, XA_MIXER_EXEC_FATAL_STATE);
276     }
277 
278     TRACE(OUTPUT, _b("received output buffer [%p]:%u"), m->buffer, m->length);
279 
280     /* ...put message into output port */
281     if (xf_output_port_put(&mixer->output, m))
282     {
283         /* ...force data processing */
284         xa_base_schedule(base, 0);
285     }
286 
287     return XA_NO_ERROR;
288 }
289 
290 /* ...output port routing */
xa_mixer_port_route(XACodecBase * base,xf_message_t * m)291 static XA_ERRORCODE xa_mixer_port_route(XACodecBase *base, xf_message_t *m)
292 {
293     XAMixer                *mixer = (XAMixer *) base;
294     xf_route_port_msg_t    *cmd = m->buffer;
295     xf_output_port_t       *port = &mixer->output;
296     u32                     src = XF_MSG_DST(m->id);
297     u32                     dst = cmd->dst;
298 
299     /* ...command is allowed only in "postinit" state */
300     XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
301 
302     /* ...make sure output port is addressed */
303     XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
304 
305     /* ...make sure port is not routed yet */
306     XF_CHK_ERR(!xf_output_port_routed(port), XA_API_FATAL_INVALID_CMD_TYPE);
307 
308     /* ...route output port - allocate queue */
309     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);
310 
311     /* ...schedule processing instantly - tbd - check if we have anything pending on input */
312     xa_base_schedule(base, 0);
313 
314     /* ...pass success result to caller */
315     xf_response_ok(m);
316 
317     return XA_NO_ERROR;
318 }
319 
320 /* ...port unroute command */
xa_mixer_port_unroute(XACodecBase * base,xf_message_t * m)321 static XA_ERRORCODE xa_mixer_port_unroute(XACodecBase *base, xf_message_t *m)
322 {
323     XAMixer            *mixer = (XAMixer *) base;
324     xf_output_port_t   *port = &mixer->output;
325 
326     /* ...command is allowed only in "postinit" state */
327     XF_CHK_ERR(base->state & XA_BASE_FLAG_POSTINIT, XA_API_FATAL_INVALID_CMD);
328 
329     /* ...make sure output port is addressed */
330     XF_CHK_ERR(XF_MSG_DST_PORT(m->id) == XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
331 
332     /* ...cancel any pending processing */
333     xa_base_cancel(base);
334 
335     /* ...clear output-port-setup condition */
336     base->state &= ~XA_MIXER_FLAG_OUTPUT_SETUP;
337 
338     /* ...pass flush command down the graph */
339     if (xf_output_port_flush(port, XF_FLUSH))
340     {
341         TRACE(INFO, _b("port is idle; instantly unroute"));
342 
343         /* ...flushing sequence is not needed; command may be satisfied instantly */
344         xf_output_port_unroute(port);
345 
346         /* ...pass response to the proxy */
347         xf_response_ok(m);
348     }
349     else
350     {
351         TRACE(INFO, _b("port is busy; propagate unroute command"));
352 
353         /* ...flushing sequence is started; save flow-control message */
354         xf_output_port_unroute_start(port, m);
355     }
356 
357     return XA_NO_ERROR;
358 }
359 
360 /* ...PAUSE message processing */
xa_mixer_pause(XACodecBase * base,xf_message_t * m)361 static XA_ERRORCODE xa_mixer_pause(XACodecBase *base, xf_message_t *m)
362 {
363     XAMixer    *mixer = (XAMixer *) base;
364     u32         i = XF_MSG_DST_PORT(m->id);
365     XATrack    *track = &mixer->track[i];
366 
367     /* ...make sure the buffer is empty */
368     XF_CHK_ERR(m->length == 0, XA_API_FATAL_INVALID_CMD_TYPE);
369 
370     /* ...check destination port is valid */
371     XF_CHK_ERR(i < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
372 
373     /* ...check for actual track flags */
374     if (xa_track_test_flags(track, XA_TRACK_FLAG_ACTIVE))
375     {
376         /* ...switch to paused state */
377         xa_track_toggle_flags(track, XA_TRACK_FLAG_ACTIVE | XA_TRACK_FLAG_PAUSED);
378 
379         /* ...other tracks may be waiting for this one, so force data processing */
380         if (xf_output_port_ready(&mixer->output))
381         {
382             xa_base_schedule(base, 0);
383         }
384 
385         TRACE(INFO, _b("mixer[%p]::track[%u] paused"), mixer, i);
386     }
387     else
388     {
389         /* ...track is in idle state and pausing here means suspending */
390         TRACE(INFO, _b("mixer[%p]::track[%u] is not active"), mixer, i);
391     }
392 
393     /* ...complete message immediately */
394     xf_response(m);
395 
396     return XA_NO_ERROR;
397 }
398 
399 /* ...RESUME command processing */
xa_mixer_resume(XACodecBase * base,xf_message_t * m)400 static XA_ERRORCODE xa_mixer_resume(XACodecBase *base, xf_message_t *m)
401 {
402     XAMixer    *mixer = (XAMixer *) base;
403     u32         i = XF_MSG_DST_PORT(m->id);
404     XATrack    *track = &mixer->track[i];
405 
406     /* ...make sure the buffer is empty */
407     XF_CHK_ERR(m->length == 0, XA_API_FATAL_INVALID_CMD_TYPE);
408 
409     /* ...check destination port is valid */
410     XF_CHK_ERR(i < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
411 
412     /* ...check for actual track state */
413     if (xa_track_test_flags(track, XA_TRACK_FLAG_PAUSED))
414     {
415         /* ...switch track to active state */
416         xa_track_toggle_flags(track, XA_TRACK_FLAG_ACTIVE | XA_TRACK_FLAG_PAUSED);
417 
418         /* ...reset track presentation timestamp - tbd */
419         track->pts = mixer->pts;
420 
421         /* ...force data processing if there is an output buffer */
422         if (xf_output_port_ready(&mixer->output))
423         {
424             xa_base_schedule(base, 0);
425         }
426 
427         TRACE(INFO, _b("mixer[%p]::track[%u] resumed"), mixer, i);
428     }
429     else
430     {
431         /* ...track is in idle state; do nothing */
432         TRACE(INFO, _b("mixer[%p]::track[%u] is not paused"), mixer, i);
433     }
434 
435     /* ...complete message */
436     xf_response(m);
437 
438     return XA_NO_ERROR;
439 }
440 
441 /* ...FLUSH command processing */
xa_mixer_flush(XACodecBase * base,xf_message_t * m)442 static XA_ERRORCODE xa_mixer_flush(XACodecBase *base, xf_message_t *m)
443 {
444     XAMixer    *mixer = (XAMixer *) base;
445     u32         i = XF_MSG_DST_PORT(m->id);
446     XATrack    *track = &mixer->track[i];
447 
448     /* ...make sure the buffer is empty */
449     XF_CHK_ERR(m->length == 0, XA_API_FATAL_INVALID_CMD_TYPE);
450 
451     /* ...check destination port index */
452     if (i == XA_MIXER_MAX_TRACK_NUMBER)
453     {
454         /* ...flushing response received; that is a port unrouting sequence */
455         XF_CHK_ERR(xf_output_port_unrouting(&mixer->output), XA_API_FATAL_INVALID_CMD_TYPE);
456 
457         /* ...complete unroute sequence */
458         xf_output_port_unroute_done(&mixer->output);
459 
460         TRACE(INFO, _b("port is unrouted"));
461 
462         return XA_NO_ERROR;
463     }
464 
465     /* ...check destination port index is valid */
466     XF_CHK_ERR(i < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
467 
468     /* ...input port flushing; check the track state is valid */
469     if (xa_track_test_flags(track, XA_TRACK_FLAG_ACTIVE | XA_TRACK_FLAG_PAUSED))
470     {
471         /* ...purge input port */
472         xf_input_port_purge(&track->input);
473 
474         /* ...force clearing of ACTIVE and INPUT_SETUP condition */
475         xa_track_clear_flags(track, XA_TRACK_FLAG_ACTIVE | XA_TRACK_FLAG_PAUSED | XA_TRACK_FLAG_INPUT_SETUP);
476 
477         /* ...and enter into idle state */
478         xa_track_set_flags(track, XA_TRACK_FLAG_IDLE);
479 
480         /* ...other tracks may be waiting for this track, so force data processing */
481         if (xf_output_port_ready(&mixer->output))
482         {
483             xa_base_schedule(base, 0);
484         }
485 
486         TRACE(INFO, _b("mixer[%p]::track[%u] flushed"), mixer, i);
487     }
488 
489     /* ...complete message instantly (no propagation to output port) */
490     xf_response(m);
491 
492     return XA_NO_ERROR;
493 }
494 
495 /*******************************************************************************
496  * Codec API implementation
497  ******************************************************************************/
498 
499 /* ...buffers handling */
xa_mixer_memtab(XACodecBase * base,WORD32 idx,WORD32 type,WORD32 size,WORD32 align,u32 core)500 static XA_ERRORCODE xa_mixer_memtab(XACodecBase *base, WORD32 idx, WORD32 type, WORD32 size, WORD32 align, u32 core)
501 {
502     XAMixer    *mixer = (XAMixer *)base;
503 
504     if (type == XA_MEMTYPE_INPUT)
505     {
506         XATrack    *track = &mixer->track[idx];
507 
508         /* ...input buffer allocation; check track number is valid */
509         XF_CHK_ERR(idx < XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
510 
511         /* ...create input port for a track */
512         XF_CHK_ERR(xf_input_port_init(&track->input, size, align, core) == 0, XA_API_FATAL_MEM_ALLOC);
513 
514         /* ...set input port buffer */
515         XA_API(base, XA_API_CMD_SET_MEM_PTR, idx, track->input.buffer);
516 
517         /* ...put track into idle state (will start as soon as we receive data) */
518         xa_track_set_flags(track, XA_TRACK_FLAG_IDLE);
519 
520         TRACE(INIT, _b("mixer[%p]::track[%u] input port created - size=%u"), mixer, idx, size);
521     }
522     else
523     {
524         /* ...output buffer allocation */
525         XF_CHK_ERR(type == XA_MEMTYPE_OUTPUT, XA_API_FATAL_INVALID_CMD_TYPE);
526 
527         /* ...check port number is what we expect */
528         XF_CHK_ERR(idx == XA_MIXER_MAX_TRACK_NUMBER, XA_API_FATAL_INVALID_CMD_TYPE);
529 
530         /* ...set mixer frame-size (in samples - for timestamp tracking) */
531         XA_API(base, XA_API_CMD_GET_CONFIG_PARAM, XA_MIXER_CONFIG_PARAM_FRAME_SIZE, &mixer->frame_size);
532 
533         /* ...create output port for a track */
534         XF_CHK_ERR(xf_output_port_init(&mixer->output, size) == 0, XA_API_FATAL_MEM_ALLOC);
535 
536         TRACE(INIT, _b("mixer[%p] output port created; size=%u"), mixer, size);
537     }
538 
539     return XA_NO_ERROR;
540 }
541 
542 /* ...preprocessing function */
xa_mixer_preprocess(XACodecBase * base)543 static XA_ERRORCODE xa_mixer_preprocess(XACodecBase *base)
544 {
545     XAMixer        *mixer = (XAMixer *) base;
546     XATrack        *track;
547     u8              i;
548     XA_ERRORCODE    e = XA_MIXER_EXEC_NONFATAL_NO_DATA;
549 
550     /* ...prepare output buffer */
551     if (!(base->state & XA_MIXER_FLAG_OUTPUT_SETUP))
552     {
553         void   *output;
554 
555         /* ...set output buffer pointer */
556         if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
557         {
558             /* ...no actual data processing during initialization */
559             return XA_NO_ERROR;
560         }
561         else if ((output = xf_output_port_data(&mixer->output)) == NULL)
562         {
563             /* ...no output buffer available */
564             return e;
565         }
566 
567         /* ...set output buffer pointer */
568         XA_API(base, XA_API_CMD_SET_MEM_PTR, XA_MIXER_MAX_TRACK_NUMBER, output);
569 
570         /* ...mark output port is setup */
571         base->state ^= XA_MIXER_FLAG_OUTPUT_SETUP;
572     }
573 
574     /* ...check EOS */
575     if (!xa_mixer_check_active(mixer))
576     {
577         /* ...push EOS to output port */
578         xf_output_port_produce(&mixer->output, 0);
579         TRACE(INFO, _b("mixer[%p]::EOS generated"), mixer);
580     }
581 
582     /* ...setup input buffer pointers and length */
583     for (track = &mixer->track[i = 0]; i < XA_MIXER_MAX_TRACK_NUMBER; i++, track++)
584     {
585         /* ...skip tracks that are not played */
586         if (!xa_track_test_flags(track, XA_TRACK_FLAG_ACTIVE))  continue;
587 
588         /* ...set temporary mixing request */
589         e = XA_NO_ERROR;
590 
591         /* ...skip the tracks that has been setup already */
592         if (xa_track_test_flags(track, XA_TRACK_FLAG_INPUT_SETUP))  continue;
593 
594         /* ...found active track that hasn't been setup yet */
595         TRACE(INPUT, _b("track-%u: ts=%x vs mts=%x"), i, track->pts, mixer->pts);
596 
597         /* ...if track presentation timestamp is in the future, do nothing yet really */
598         if (!xf_time_after(track->pts, mixer->pts))
599         {
600             u32     filled;
601 
602             /* ...take actual data from input port (mixer is always using internal buffer) */
603             if (!xf_input_port_fill(&track->input))
604             {
605                 /* ...failed to prefill input buffer - no sufficient data yet */
606                 return XA_MIXER_EXEC_NONFATAL_NO_DATA;
607             }
608             else
609             {
610                 /* ...retrieve number of bytes available */
611                 filled = xf_input_port_level(&track->input);
612             }
613 
614             /* ...set total number of bytes we have in buffer */
615             XA_API(base, XA_API_CMD_SET_INPUT_BYTES, i, &filled);
616 
617             /* ...actual data is to be played */
618             TRACE(INPUT, _b("track-%u: filled %u bytes"), i, filled);
619         }
620 
621         /* ...mark the track input is setup (emit silence or actual data) */
622         xa_track_set_flags(track, XA_TRACK_FLAG_INPUT_SETUP);
623     }
624 
625     /* ...do mixing operation only when all active tracks are setup */
626     return e;
627 }
628 
629 /* ...postprocessing function */
xa_mixer_postprocess(XACodecBase * base,int done)630 static XA_ERRORCODE xa_mixer_postprocess(XACodecBase *base, int done)
631 {
632     XAMixer        *mixer = (XAMixer *) base;
633     XATrack        *track;
634     u32             produced;
635     u32             consumed;
636     u8              i;
637 
638     /* ...process execution stage transitions */
639     if (done)
640     {
641         if (base->state & XA_BASE_FLAG_RUNTIME_INIT)
642         {
643             /* ...failed to initialize runtime (can't be? - tbd)*/
644             BUG(1, _x("breakpoint"));
645         }
646         else if (base->state & XA_BASE_FLAG_EXECUTION)
647         {
648             /* ...enter into execution state; initialize runtime */
649             return XA_CHK(xa_mixer_prepare_runtime(mixer));
650         }
651         else
652         {
653             /* ...mixer operation is over (can't be? - tbd) */
654             BUG(1, _x("breakpoint"));
655         }
656     }
657 
658     /* ...input ports maintenance; process all tracks */
659     for (track = &mixer->track[i = 0]; i < XA_MIXER_MAX_TRACK_NUMBER; i++, track++)
660     {
661         /* ...skip the tracks that are not runing */
662         if (!xa_track_test_flags(track, XA_TRACK_FLAG_ACTIVE))  continue;
663 
664         /* ...clear input setup flag */
665         xa_track_clear_flags(track, XA_TRACK_FLAG_INPUT_SETUP);
666 
667         /* ...advance track presentation timestamp */
668         track->pts += mixer->frame_size;
669 
670         /* ...get total amount of consumed bytes */
671         XA_API(base, XA_API_CMD_GET_CURIDX_INPUT_BUF, i, &consumed);
672 
673         TRACE(INPUT, _b("track-%u::postprocess(c=%u, ts=%x)"), i, consumed, track->pts);
674 
675         /* ...consume that amount from input port (may be zero) */
676         xf_input_port_consume(&track->input, consumed);
677 
678         /* ...check if input port is done */
679         if (xf_input_port_done(&track->input))
680         {
681             /* ...input stream is over; return zero-length input back to caller */
682             xf_input_port_purge(&track->input);
683 
684             /* ...switch to idle state */
685             xa_track_toggle_flags(track, XA_TRACK_FLAG_ACTIVE | XA_TRACK_FLAG_IDLE);
686 
687             TRACE(INFO, _b("mixer[%p]::track[%u] completed"), mixer, i);
688         }
689     }
690 
691     /* ...check if we have produced anything */
692     XA_API(base, XA_API_CMD_GET_OUTPUT_BYTES, XA_MIXER_MAX_TRACK_NUMBER, &produced);
693 
694     TRACE(OUTPUT, _b("mixer[%p]::postprocess(p=%u, ts=%x, done=%u)"), mixer, produced, mixer->pts, done);
695 
696     /* ...output port maintenance */
697     if (produced)
698     {
699         /* ...make sure we have produced exactly single frame */
700         BUG(produced != mixer->output.length, _x("Invalid length: %u != %u"), produced, mixer->output.length);
701 
702         /* ...steady mixing process; advance mixer presentation timestamp */
703         mixer->pts += mixer->frame_size;
704 
705         /* ...push data from output port */
706         xf_output_port_produce(&mixer->output, produced);
707 
708         /* ...clear output-setup condition */
709         base->state &= ~XA_MIXER_FLAG_OUTPUT_SETUP;
710     }
711 
712     /* ...reschedule data processing if there is a pending output message */
713     if (xf_output_port_ready(&mixer->output))
714     {
715         /* ...schedule execution with respect to urgency */
716         xa_base_schedule(base, (produced ? mixer->frame_duration : 0));
717     }
718 
719     return XA_NO_ERROR;
720 }
721 
722 /*******************************************************************************
723  * Command-processing function
724  ******************************************************************************/
725 
726 /* ...command hooks */
727 static XA_ERRORCODE (* const xa_mixer_cmd[])(XACodecBase *, xf_message_t *) =
728 {
729     /* ...set-parameter - actually, same as in generic case */
730     [XF_OPCODE_TYPE(XF_SET_PARAM)] = xa_base_set_param,
731     [XF_OPCODE_TYPE(XF_GET_PARAM)] = xa_base_get_param,
732 
733     /* ...output port routing/unrouting */
734     [XF_OPCODE_TYPE(XF_ROUTE)] = xa_mixer_port_route,
735     [XF_OPCODE_TYPE(XF_UNROUTE)] = xa_mixer_port_unroute,
736 
737     /* ...input/output buffers processing */
738     [XF_OPCODE_TYPE(XF_EMPTY_THIS_BUFFER)] = xa_mixer_empty_this_buffer,
739     [XF_OPCODE_TYPE(XF_FILL_THIS_BUFFER)] = xa_mixer_fill_this_buffer,
740     [XF_OPCODE_TYPE(XF_FLUSH)] = xa_mixer_flush,
741 
742     /* ...track control */
743     [XF_OPCODE_TYPE(XF_PAUSE)] = xa_mixer_pause,
744     [XF_OPCODE_TYPE(XF_RESUME)] = xa_mixer_resume,
745 };
746 
747 /* ...total number of commands supported */
748 #define XA_MIXER_CMD_NUM        (sizeof(xa_mixer_cmd) / sizeof(xa_mixer_cmd[0]))
749 
750 /*******************************************************************************
751  * Entry points
752  ******************************************************************************/
753 
754 /* ...mixer termination-state command processor */
xa_mixer_terminate(xf_component_t * component,xf_message_t * m)755 static int xa_mixer_terminate(xf_component_t *component, xf_message_t *m)
756 {
757     XAMixer    *mixer = (XAMixer *) component;
758     u32         opcode = m->opcode;
759 
760     if (m == xf_output_port_control_msg(&mixer->output))
761     {
762         /* ...output port flushing complete; mark port is idle and terminate */
763         xf_output_port_flush_done(&mixer->output);
764         return -1;
765     }
766     else if (opcode == XF_FILL_THIS_BUFFER && xf_output_port_routed(&mixer->output))
767     {
768         /* ...output buffer returned by the sink component; ignore and keep waiting */
769         TRACE(OUTPUT, _b("collect output buffer"));
770         return 0;
771     }
772     else if (opcode == XF_UNREGISTER)
773     {
774         /* ...ignore subsequent unregister command/response */
775         return 0;
776     }
777     else
778     {
779         /* ...everything else is responded with generic failure */
780         xf_response_err(m);
781         return 0;
782     }
783 }
784 
785 /* ...mixer class destructor */
xa_mixer_destroy(xf_component_t * component,xf_message_t * m)786 static int xa_mixer_destroy(xf_component_t *component, xf_message_t *m)
787 {
788     XAMixer    *mixer = (XAMixer *) component;
789     u32         core = xf_component_core(component);
790     u32         i;
791 
792     /* ...destroy all inputs */
793     for (i = 0; i < XA_MIXER_MAX_TRACK_NUMBER; i++)
794     {
795         xf_input_port_destroy(&mixer->track[i].input, core);
796     }
797 
798     /* ...destroy output port */
799     xf_output_port_destroy(&mixer->output, core);
800 
801     /* ...destroy base object */
802     xa_base_destroy(&mixer->base, XF_MM(sizeof(*mixer)), core);
803 
804     TRACE(INIT, _b("mixer[%p] destroyed"), mixer);
805 
806     return 0;
807 }
808 
809 /* ...mixer class first-stage destructor */
xa_mixer_cleanup(xf_component_t * component,xf_message_t * m)810 static int xa_mixer_cleanup(xf_component_t *component, xf_message_t *m)
811 {
812     XAMixer    *mixer = (XAMixer *) component;
813     u32         i;
814 
815     /* ...complete message with error result code */
816     xf_response_err(m);
817 
818     /* ...cancel internal scheduling message if needed */
819     xa_base_cancel(&mixer->base);
820 
821     /* ...purge all input ports (specify "unregister"? - don't know yet - tbd) */
822     for (i = 0; i < XA_MIXER_MAX_TRACK_NUMBER; i++)
823     {
824         xf_input_port_purge(&mixer->track[i].input);
825     }
826 
827     /* ...flush output port */
828     if (xf_output_port_flush(&mixer->output, XF_FLUSH))
829     {
830         /* ...flushing sequence is not needed; destroy mixer */
831         return xa_mixer_destroy(component, NULL);
832     }
833     else
834     {
835         /* ...wait until output port is cleaned; adjust component hooks */
836         component->entry = xa_mixer_terminate;
837         component->exit = xa_mixer_destroy;
838 
839         TRACE(INIT, _b("mixer[%p] cleanup sequence started"), mixer);
840 
841         /* ...indicate that second stage is required */
842         return 1;
843     }
844 }
845 
846 /* ...mixer class factory */
xa_mixer_factory(u32 core,xa_codec_func_t process)847 xf_component_t * xa_mixer_factory(u32 core, xa_codec_func_t process)
848 {
849     XAMixer    *mixer;
850 
851     /* ...construct generic audio component */
852     XF_CHK_ERR(mixer = (XAMixer *)xa_base_factory(core, XF_MM(sizeof(*mixer)), process), NULL);
853 
854     /* ...set generic codec API */
855     mixer->base.memtab = xa_mixer_memtab;
856     mixer->base.preprocess = xa_mixer_preprocess;
857     mixer->base.postprocess = xa_mixer_postprocess;
858 
859     /* ...set message-processing table */
860     mixer->base.command = xa_mixer_cmd;
861     mixer->base.command_num = XA_MIXER_CMD_NUM;
862 
863     /* ...set component destructor hook */
864     mixer->base.component.exit = xa_mixer_cleanup;
865 
866     TRACE(INIT, _b("Mixer[%p] created"), mixer);
867 
868     /* ...return handle to component */
869     return (xf_component_t *) mixer;
870 }
871