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 75 static inline u32 xa_track_test_flags(XATrack *track, u32 flags) 76 { 77 return (track->input.flags & flags); 78 } 79 80 static inline u32 xa_track_set_flags(XATrack *track, u32 flags) 81 { 82 return (track->input.flags |= flags); 83 } 84 85 static inline u32 xa_track_clear_flags(XATrack *track, u32 flags) 86 { 87 return (track->input.flags &= ~flags); 88 } 89 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*/ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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