Home | History | Annotate | Download | only in libopensles
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /* OutputMixExt implementation */
     18 
     19 #include "sles_allinclusive.h"
     20 #include <math.h>
     21 
     22 
     23 // OutputMixExt is used by SDL, but is not specific to or dependent on SDL
     24 
     25 
     26 // stereo is a frame consisting of a pair of 16-bit PCM samples
     27 
     28 typedef struct {
     29     short left;
     30     short right;
     31 } stereo;
     32 
     33 
     34 /** \brief Summary of the gain, as an optimization for the mixer */
     35 
     36 typedef enum {
     37     GAIN_MUTE  = 0,  // mValue == 0.0f within epsilon
     38     GAIN_UNITY = 1,  // mValue == 1.0f within epsilon
     39     GAIN_OTHER = 2   // 0.0f < mValue < 1.0f
     40 } Summary;
     41 
     42 
     43 /** \brief Check whether a track has any data for us to read */
     44 
     45 static SLboolean track_check(Track *track)
     46 {
     47     assert(NULL != track);
     48     SLboolean trackHasData = SL_BOOLEAN_FALSE;
     49 
     50     CAudioPlayer *audioPlayer = track->mAudioPlayer;
     51     if (NULL != audioPlayer) {
     52 
     53         // track is initialized
     54 
     55         // FIXME This lock could block and result in stuttering;
     56         // a trylock with retry or lockless solution would be ideal
     57         object_lock_exclusive(&audioPlayer->mObject);
     58         assert(audioPlayer->mTrack == track);
     59 
     60         SLuint32 framesMixed = track->mFramesMixed;
     61         if (0 != framesMixed) {
     62             track->mFramesMixed = 0;
     63             audioPlayer->mPlay.mFramesSinceLastSeek += framesMixed;
     64             audioPlayer->mPlay.mFramesSincePositionUpdate += framesMixed;
     65         }
     66 
     67         SLboolean doBroadcast = SL_BOOLEAN_FALSE;
     68         const BufferHeader *oldFront;
     69 
     70         if (audioPlayer->mBufferQueue.mClearRequested) {
     71             // application thread(s) that call BufferQueue::Clear while mixer is active
     72             // will block synchronously until mixer acknowledges the Clear request
     73             audioPlayer->mBufferQueue.mFront = &audioPlayer->mBufferQueue.mArray[0];
     74             audioPlayer->mBufferQueue.mRear = &audioPlayer->mBufferQueue.mArray[0];
     75             audioPlayer->mBufferQueue.mState.count = 0;
     76             audioPlayer->mBufferQueue.mState.playIndex = 0;
     77             audioPlayer->mBufferQueue.mClearRequested = SL_BOOLEAN_FALSE;
     78             track->mReader = NULL;
     79             track->mAvail = 0;
     80             doBroadcast = SL_BOOLEAN_TRUE;
     81         }
     82 
     83         if (audioPlayer->mDestroyRequested) {
     84             // an application thread that calls Object::Destroy while mixer is active will block
     85             // synchronously in the PreDestroy hook until mixer acknowledges the Destroy request
     86             COutputMix *outputMix = CAudioPlayer_GetOutputMix(audioPlayer);
     87             unsigned i = track - outputMix->mOutputMixExt.mTracks;
     88             assert( /* 0 <= i && */ i < MAX_TRACK);
     89             unsigned mask = 1 << i;
     90             track->mAudioPlayer = NULL;
     91             assert(outputMix->mOutputMixExt.mActiveMask & mask);
     92             outputMix->mOutputMixExt.mActiveMask &= ~mask;
     93             audioPlayer->mTrack = NULL;
     94             audioPlayer->mDestroyRequested = SL_BOOLEAN_FALSE;
     95             doBroadcast = SL_BOOLEAN_TRUE;
     96             goto broadcast;
     97         }
     98 
     99         switch (audioPlayer->mPlay.mState) {
    100 
    101         case SL_PLAYSTATE_PLAYING:  // continue playing current track data
    102             if (0 < track->mAvail) {
    103                 trackHasData = SL_BOOLEAN_TRUE;
    104                 break;
    105             }
    106 
    107             // try to get another buffer from queue
    108             oldFront = audioPlayer->mBufferQueue.mFront;
    109             if (oldFront != audioPlayer->mBufferQueue.mRear) {
    110                 assert(0 < audioPlayer->mBufferQueue.mState.count);
    111                 track->mReader = oldFront->mBuffer;
    112                 track->mAvail = oldFront->mSize;
    113                 // note that the buffer stays on the queue while we are reading
    114                 audioPlayer->mPlay.mState = SL_PLAYSTATE_PLAYING;
    115                 trackHasData = SL_BOOLEAN_TRUE;
    116             } else {
    117                 // no buffers on queue, so playable but not playing
    118                 // NTH should be able to call a desperation callback when completely starved,
    119                 // or call less often than every buffer based on high/low water-marks
    120             }
    121 
    122             // copy gains from audio player to track
    123             track->mGains[0] = audioPlayer->mGains[0];
    124             track->mGains[1] = audioPlayer->mGains[1];
    125             break;
    126 
    127         case SL_PLAYSTATE_STOPPING: // application thread(s) called Play::SetPlayState(STOPPED)
    128             audioPlayer->mPlay.mPosition = (SLmillisecond) 0;
    129             audioPlayer->mPlay.mFramesSinceLastSeek = 0;
    130             audioPlayer->mPlay.mFramesSincePositionUpdate = 0;
    131             audioPlayer->mPlay.mLastSeekPosition = 0;
    132             audioPlayer->mPlay.mState = SL_PLAYSTATE_STOPPED;
    133             // stop cancels a pending seek
    134             audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN;
    135             oldFront = audioPlayer->mBufferQueue.mFront;
    136             if (oldFront != audioPlayer->mBufferQueue.mRear) {
    137                 assert(0 < audioPlayer->mBufferQueue.mState.count);
    138                 track->mReader = oldFront->mBuffer;
    139                 track->mAvail = oldFront->mSize;
    140             }
    141             doBroadcast = SL_BOOLEAN_TRUE;
    142             break;
    143 
    144         case SL_PLAYSTATE_STOPPED:  // idle
    145         case SL_PLAYSTATE_PAUSED:   // idle
    146             break;
    147 
    148         default:
    149             assert(SL_BOOLEAN_FALSE);
    150             break;
    151         }
    152 
    153 broadcast:
    154         if (doBroadcast) {
    155             object_cond_broadcast(&audioPlayer->mObject);
    156         }
    157 
    158         object_unlock_exclusive(&audioPlayer->mObject);
    159 
    160     }
    161 
    162     return trackHasData;
    163 
    164 }
    165 
    166 
    167 /** \brief This is the track mixer: fill the specified 16-bit stereo PCM buffer */
    168 
    169 void IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size)
    170 {
    171     SL_ENTER_INTERFACE_VOID
    172 
    173     // Force to be a multiple of a frame, assumes stereo 16-bit PCM
    174     size &= ~3;
    175     SLboolean mixBufferHasData = SL_BOOLEAN_FALSE;
    176     IOutputMixExt *this = (IOutputMixExt *) self;
    177     IObject *thisObject = this->mThis;
    178     // This lock should never block, except when the application destroys the output mix object
    179     object_lock_exclusive(thisObject);
    180     unsigned activeMask;
    181     // If the output mix is marked for destruction, then acknowledge the request
    182     if (this->mDestroyRequested) {
    183         IEngine *thisEngine = thisObject->mEngine;
    184         interface_lock_exclusive(thisEngine);
    185         assert(&thisEngine->mOutputMix->mObject == thisObject);
    186         thisEngine->mOutputMix = NULL;
    187         // Note we don't attempt to connect another output mix, even if there is one
    188         interface_unlock_exclusive(thisEngine);
    189         // Acknowledge the destroy request, and notify the pre-destroy hook
    190         this->mDestroyRequested = SL_BOOLEAN_FALSE;
    191         object_cond_broadcast(thisObject);
    192         activeMask = 0;
    193     } else {
    194         activeMask = this->mActiveMask;
    195     }
    196     while (activeMask) {
    197         unsigned i = ctz(activeMask);
    198         assert(MAX_TRACK > i);
    199         activeMask &= ~(1 << i);
    200         Track *track = &this->mTracks[i];
    201 
    202         // track is allocated
    203 
    204         if (!track_check(track)) {
    205             continue;
    206         }
    207 
    208         // track is playing
    209         void *dstWriter = pBuffer;
    210         unsigned desired = size;
    211         SLboolean trackContributedToMix = SL_BOOLEAN_FALSE;
    212         float gains[STEREO_CHANNELS];
    213         Summary summaries[STEREO_CHANNELS];
    214         unsigned channel;
    215         for (channel = 0; channel < STEREO_CHANNELS; ++channel) {
    216             float gain = track->mGains[channel];
    217             gains[channel] = gain;
    218             Summary summary;
    219             if (gain <= 0.001) {
    220                 summary = GAIN_MUTE;
    221             } else if (gain >= 0.999) {
    222                 summary = GAIN_UNITY;
    223             } else {
    224                 summary = GAIN_OTHER;
    225             }
    226             summaries[channel] = summary;
    227         }
    228         while (desired > 0) {
    229             unsigned actual = desired;
    230             if (track->mAvail < actual) {
    231                 actual = track->mAvail;
    232             }
    233             // force actual to be a frame multiple
    234             if (actual > 0) {
    235                 assert(NULL != track->mReader);
    236                 stereo *mixBuffer = (stereo *) dstWriter;
    237                 const stereo *source = (const stereo *) track->mReader;
    238                 unsigned j;
    239                 if (GAIN_MUTE != summaries[0] || GAIN_MUTE != summaries[1]) {
    240                     if (mixBufferHasData) {
    241                         // apply gain during add
    242                         if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) {
    243                             for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
    244                                 mixBuffer->left += (short) (source->left * track->mGains[0]);
    245                                 mixBuffer->right += (short) (source->right * track->mGains[1]);
    246                             }
    247                         // no gain adjustment needed, so do a simple add
    248                         } else {
    249                             for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
    250                                 mixBuffer->left += source->left;
    251                                 mixBuffer->right += source->right;
    252                             }
    253                         }
    254                     } else {
    255                         // apply gain during copy
    256                         if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) {
    257                             for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
    258                                 mixBuffer->left = (short) (source->left * track->mGains[0]);
    259                                 mixBuffer->right = (short) (source->right * track->mGains[1]);
    260                             }
    261                         // no gain adjustment needed, so do a simple copy
    262                         } else {
    263                             memcpy(dstWriter, track->mReader, actual);
    264                         }
    265                     }
    266                     trackContributedToMix = SL_BOOLEAN_TRUE;
    267                 }
    268                 dstWriter = (char *) dstWriter + actual;
    269                 desired -= actual;
    270                 track->mReader = (char *) track->mReader + actual;
    271                 track->mAvail -= actual;
    272                 if (track->mAvail == 0) {
    273                     IBufferQueue *bufferQueue = &track->mAudioPlayer->mBufferQueue;
    274                     interface_lock_exclusive(bufferQueue);
    275                     const BufferHeader *oldFront, *newFront, *rear;
    276                     oldFront = bufferQueue->mFront;
    277                     rear = bufferQueue->mRear;
    278                     // a buffer stays on queue while playing, so it better still be there
    279                     assert(oldFront != rear);
    280                     newFront = oldFront;
    281                     if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1]) {
    282                         newFront = bufferQueue->mArray;
    283                     }
    284                     bufferQueue->mFront = (BufferHeader *) newFront;
    285                     assert(0 < bufferQueue->mState.count);
    286                     --bufferQueue->mState.count;
    287                     if (newFront != rear) {
    288                         // we don't acknowledge application requests between buffers
    289                         // within the same mixer frame
    290                         assert(0 < bufferQueue->mState.count);
    291                         track->mReader = newFront->mBuffer;
    292                         track->mAvail = newFront->mSize;
    293                     }
    294                     // else we would set play state to playable but not playing during next mixer
    295                     // frame if the queue is still empty at that time
    296                     ++bufferQueue->mState.playIndex;
    297                     slBufferQueueCallback callback = bufferQueue->mCallback;
    298                     void *context = bufferQueue->mContext;
    299                     interface_unlock_exclusive(bufferQueue);
    300                     // The callback function is called on each buffer completion
    301                     if (NULL != callback) {
    302                         (*callback)((SLBufferQueueItf) bufferQueue, context);
    303                         // Maybe it enqueued another buffer, or maybe it didn't.
    304                         // We will find out later during the next mixer frame.
    305                     }
    306                 }
    307                 // no lock, but safe because noone else updates this field
    308                 track->mFramesMixed += actual >> 2;    // sizeof(short) * STEREO_CHANNELS
    309                 continue;
    310             }
    311             // we need more data: desired > 0 but actual == 0
    312             if (track_check(track)) {
    313                 continue;
    314             }
    315             // underflow: clear out rest of partial buffer (NTH synthesize comfort noise)
    316             if (!mixBufferHasData && trackContributedToMix) {
    317                 memset(dstWriter, 0, actual);
    318             }
    319             break;
    320         }
    321         if (trackContributedToMix) {
    322             mixBufferHasData = SL_BOOLEAN_TRUE;
    323         }
    324     }
    325     object_unlock_exclusive(thisObject);
    326     // No active tracks, so output silence
    327     if (!mixBufferHasData) {
    328         memset(pBuffer, 0, size);
    329     }
    330 
    331     SL_LEAVE_INTERFACE_VOID
    332 }
    333 
    334 
    335 static const struct SLOutputMixExtItf_ IOutputMixExt_Itf = {
    336     IOutputMixExt_FillBuffer
    337 };
    338 
    339 void IOutputMixExt_init(void *self)
    340 {
    341     IOutputMixExt *this = (IOutputMixExt *) self;
    342     this->mItf = &IOutputMixExt_Itf;
    343     this->mActiveMask = 0;
    344     Track *track = &this->mTracks[0];
    345     unsigned i;
    346     for (i = 0; i < MAX_TRACK; ++i, ++track) {
    347         track->mAudioPlayer = NULL;
    348     }
    349     this->mDestroyRequested = SL_BOOLEAN_FALSE;
    350 }
    351 
    352 
    353 /** \brief Called by Engine::CreateAudioPlayer to allocate a track */
    354 
    355 SLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *this)
    356 {
    357     this->mTrack = NULL;
    358 
    359     // check the source for compatibility
    360     switch (this->mDataSource.mLocator.mLocatorType) {
    361     case SL_DATALOCATOR_BUFFERQUEUE:
    362 #ifdef ANDROID
    363     case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
    364 #endif
    365         switch (this->mDataSource.mFormat.mFormatType) {
    366         case SL_DATAFORMAT_PCM:
    367 #ifdef USE_SDL
    368             // SDL is hard-coded to 44.1 kHz, and there is no sample rate converter
    369             if (SL_SAMPLINGRATE_44_1 != this->mDataSource.mFormat.mPCM.samplesPerSec)
    370                 return SL_RESULT_CONTENT_UNSUPPORTED;
    371 #endif
    372             break;
    373         default:
    374             break;
    375         }
    376         break;
    377     default:
    378         break;
    379     }
    380 
    381     // check the sink for compatibility
    382     const SLDataSink *pAudioSnk = &this->mDataSink.u.mSink;
    383     Track *track = NULL;
    384     switch (*(SLuint32 *)pAudioSnk->pLocator) {
    385     case SL_DATALOCATOR_OUTPUTMIX:
    386         {
    387         // pAudioSnk->pFormat is ignored
    388         IOutputMixExt *omExt = &((COutputMix *) ((SLDataLocator_OutputMix *)
    389             pAudioSnk->pLocator)->outputMix)->mOutputMixExt;
    390         // allocate an entry within OutputMix for this track
    391         interface_lock_exclusive(omExt);
    392         unsigned availMask = ~omExt->mActiveMask;
    393         if (!availMask) {
    394             interface_unlock_exclusive(omExt);
    395             // All track slots full in output mix
    396             return SL_RESULT_MEMORY_FAILURE;
    397         }
    398         unsigned i = ctz(availMask);
    399         assert(MAX_TRACK > i);
    400         omExt->mActiveMask |= 1 << i;
    401         track = &omExt->mTracks[i];
    402         track->mAudioPlayer = NULL;    // only field that is accessed before full initialization
    403         interface_unlock_exclusive(omExt);
    404         this->mTrack = track;
    405         this->mGains[0] = 1.0f;
    406         this->mGains[1] = 1.0f;
    407         this->mDestroyRequested = SL_BOOLEAN_FALSE;
    408         }
    409         break;
    410     default:
    411         return SL_RESULT_CONTENT_UNSUPPORTED;
    412     }
    413 
    414     assert(NULL != track);
    415     track->mBufferQueue = &this->mBufferQueue;
    416     track->mAudioPlayer = this;
    417     track->mReader = NULL;
    418     track->mAvail = 0;
    419     track->mGains[0] = 1.0f;
    420     track->mGains[1] = 1.0f;
    421     track->mFramesMixed = 0;
    422     return SL_RESULT_SUCCESS;
    423 }
    424 
    425 
    426 /** \brief Called when a gain-related field (mute, solo, volume, stereo position, etc.) updated */
    427 
    428 void audioPlayerGainUpdate(CAudioPlayer *audioPlayer)
    429 {
    430     SLboolean mute = audioPlayer->mVolume.mMute;
    431     SLuint8 muteMask = audioPlayer->mMuteMask;
    432     SLuint8 soloMask = audioPlayer->mSoloMask;
    433     SLmillibel level = audioPlayer->mVolume.mLevel;
    434     SLboolean enableStereoPosition = audioPlayer->mVolume.mEnableStereoPosition;
    435     SLpermille stereoPosition = audioPlayer->mVolume.mStereoPosition;
    436 
    437     if (soloMask) {
    438         muteMask |= ~soloMask;
    439     }
    440     if (mute || !(~muteMask & 3)) {
    441         audioPlayer->mGains[0] = 0.0f;
    442         audioPlayer->mGains[1] = 0.0f;
    443     } else {
    444         float playerGain = powf(10.0f, level / 2000.0f);
    445         unsigned channel;
    446         for (channel = 0; channel < STEREO_CHANNELS; ++channel) {
    447             float gain;
    448             if (muteMask & (1 << channel)) {
    449                 gain = 0.0f;
    450             } else {
    451                 gain = playerGain;
    452                 if (enableStereoPosition) {
    453                     switch (channel) {
    454                     case 0:
    455                         if (stereoPosition > 0) {
    456                             gain *= (1000 - stereoPosition) / 1000.0f;
    457                         }
    458                         break;
    459                     case 1:
    460                         if (stereoPosition < 0) {
    461                             gain *= (1000 + stereoPosition) / 1000.0f;
    462                         }
    463                         break;
    464                     default:
    465                         assert(SL_BOOLEAN_FALSE);
    466                         break;
    467                     }
    468                 }
    469             }
    470             audioPlayer->mGains[channel] = gain;
    471         }
    472     }
    473 }
    474