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 sane */
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