Home | History | Annotate | Download | only in audio
      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 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 */
    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