1188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten/* 2188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Copyright (C) 2010 The Android Open Source Project 3188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * 4188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 5188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * you may not use this file except in compliance with the License. 6188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * You may obtain a copy of the License at 7188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * 8188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 9188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * 10188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Unless required by applicable law or agreed to in writing, software 11188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 12188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * See the License for the specific language governing permissions and 14188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * limitations under the License. 15188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten */ 16188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 17188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten/* OutputMixExt implementation */ 18188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 19188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten#include "sles_allinclusive.h" 2015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten#include <math.h> 21188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 22188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 234f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten// OutputMixExt is used by SDL, but is not specific to or dependent on SDL 24188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 2551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten 2651cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten// stereo is a frame consisting of a pair of 16-bit PCM samples 2751cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten 2851cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kastentypedef struct { 2951cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten short left; 3051cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten short right; 3151cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten} stereo; 3251cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten 3351cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten 346aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten/** \brief Summary of the gain, as an optimization for the mixer */ 3515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten 367e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kastentypedef enum { 3715f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten GAIN_MUTE = 0, // mValue == 0.0f within epsilon 3815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten GAIN_UNITY = 1, // mValue == 1.0f within epsilon 3915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten GAIN_OTHER = 2 // 0.0f < mValue < 1.0f 407e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten} Summary; 417e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten 42f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten 436aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten/** \brief Check whether a track has any data for us to read */ 4423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 4510ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kastenstatic SLboolean track_check(Track *track) 4623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten{ 474f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten assert(NULL != track); 4823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten SLboolean trackHasData = SL_BOOLEAN_FALSE; 4923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 5023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten CAudioPlayer *audioPlayer = track->mAudioPlayer; 5123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten if (NULL != audioPlayer) { 5223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 5323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // track is initialized 5423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 554f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten // FIXME This lock could block and result in stuttering; 564f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten // a trylock with retry or lockless solution would be ideal 5723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten object_lock_exclusive(&audioPlayer->mObject); 584f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten assert(audioPlayer->mTrack == track); 5923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 6066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten SLuint32 framesMixed = track->mFramesMixed; 6166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (0 != framesMixed) { 6266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten track->mFramesMixed = 0; 6366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten audioPlayer->mPlay.mFramesSinceLastSeek += framesMixed; 6466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten audioPlayer->mPlay.mFramesSincePositionUpdate += framesMixed; 6566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 6666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten 6723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten SLboolean doBroadcast = SL_BOOLEAN_FALSE; 6823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten const BufferHeader *oldFront; 6923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 7023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten if (audioPlayer->mBufferQueue.mClearRequested) { 7123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // application thread(s) that call BufferQueue::Clear while mixer is active 724f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten // will block synchronously until mixer acknowledges the Clear request 7323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten audioPlayer->mBufferQueue.mFront = &audioPlayer->mBufferQueue.mArray[0]; 7423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten audioPlayer->mBufferQueue.mRear = &audioPlayer->mBufferQueue.mArray[0]; 7523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten audioPlayer->mBufferQueue.mState.count = 0; 7607c35e6e57ff8945c4dd836be4486a62316ac64bGlenn Kasten audioPlayer->mBufferQueue.mState.playIndex = 0; 7723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten audioPlayer->mBufferQueue.mClearRequested = SL_BOOLEAN_FALSE; 7823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten track->mReader = NULL; 7923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten track->mAvail = 0; 8023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten doBroadcast = SL_BOOLEAN_TRUE; 8123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten } 8223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 834f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten if (audioPlayer->mDestroyRequested) { 844f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten // an application thread that calls Object::Destroy while mixer is active will block 854f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten // synchronously in the PreDestroy hook until mixer acknowledges the Destroy request 8631df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten COutputMix *outputMix = CAudioPlayer_GetOutputMix(audioPlayer); 874f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten unsigned i = track - outputMix->mOutputMixExt.mTracks; 884f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten assert( /* 0 <= i && */ i < MAX_TRACK); 894f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten unsigned mask = 1 << i; 904f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten track->mAudioPlayer = NULL; 914f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten assert(outputMix->mOutputMixExt.mActiveMask & mask); 924f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten outputMix->mOutputMixExt.mActiveMask &= ~mask; 934f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten audioPlayer->mTrack = NULL; 944f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten audioPlayer->mDestroyRequested = SL_BOOLEAN_FALSE; 954f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten doBroadcast = SL_BOOLEAN_TRUE; 964f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten goto broadcast; 974f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten } 984f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten 9923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten switch (audioPlayer->mPlay.mState) { 10023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 10123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten case SL_PLAYSTATE_PLAYING: // continue playing current track data 10223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten if (0 < track->mAvail) { 10323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten trackHasData = SL_BOOLEAN_TRUE; 10423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten break; 10523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten } 10623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 10723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // try to get another buffer from queue 10823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten oldFront = audioPlayer->mBufferQueue.mFront; 10923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten if (oldFront != audioPlayer->mBufferQueue.mRear) { 11023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten assert(0 < audioPlayer->mBufferQueue.mState.count); 11123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten track->mReader = oldFront->mBuffer; 11223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten track->mAvail = oldFront->mSize; 11323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // note that the buffer stays on the queue while we are reading 11423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten audioPlayer->mPlay.mState = SL_PLAYSTATE_PLAYING; 11523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten trackHasData = SL_BOOLEAN_TRUE; 11623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten } else { 11723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // no buffers on queue, so playable but not playing 11823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // NTH should be able to call a desperation callback when completely starved, 11923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // or call less often than every buffer based on high/low water-marks 12023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten } 1214f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten 1224f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten // copy gains from audio player to track 1234f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten track->mGains[0] = audioPlayer->mGains[0]; 1244f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten track->mGains[1] = audioPlayer->mGains[1]; 12523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten break; 12623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 12723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten case SL_PLAYSTATE_STOPPING: // application thread(s) called Play::SetPlayState(STOPPED) 12823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten audioPlayer->mPlay.mPosition = (SLmillisecond) 0; 12966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten audioPlayer->mPlay.mFramesSinceLastSeek = 0; 13066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten audioPlayer->mPlay.mFramesSincePositionUpdate = 0; 13166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten audioPlayer->mPlay.mLastSeekPosition = 0; 13223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten audioPlayer->mPlay.mState = SL_PLAYSTATE_STOPPED; 13366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // stop cancels a pending seek 13466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN; 13523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten oldFront = audioPlayer->mBufferQueue.mFront; 13623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten if (oldFront != audioPlayer->mBufferQueue.mRear) { 13723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten assert(0 < audioPlayer->mBufferQueue.mState.count); 13823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten track->mReader = oldFront->mBuffer; 13923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten track->mAvail = oldFront->mSize; 14023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten } 14123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten doBroadcast = SL_BOOLEAN_TRUE; 14223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten break; 14323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 14423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten case SL_PLAYSTATE_STOPPED: // idle 14523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten case SL_PLAYSTATE_PAUSED: // idle 14623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten break; 14723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 14823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten default: 14923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten assert(SL_BOOLEAN_FALSE); 15023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten break; 15123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten } 15223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 1534f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kastenbroadcast: 15466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (doBroadcast) { 15523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten object_cond_broadcast(&audioPlayer->mObject); 15666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 15723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 15823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten object_unlock_exclusive(&audioPlayer->mObject); 15923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 16023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten } 16123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 16223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten return trackHasData; 16323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 16423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten} 16523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 1666aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten 1674f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten/** \brief This is the track mixer: fill the specified 16-bit stereo PCM buffer */ 1686aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten 1699c03f04a9c6cc2a821182c8be8f2efe964a27efeGlenn Kastenvoid IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size) 170188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten{ 171f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten SL_ENTER_INTERFACE_VOID 172f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten 173188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten // Force to be a multiple of a frame, assumes stereo 16-bit PCM 174188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten size &= ~3; 175188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten SLboolean mixBufferHasData = SL_BOOLEAN_FALSE; 17650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten IOutputMixExt *thiz = (IOutputMixExt *) self; 17750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten IObject *thisObject = thiz->mThis; 17831df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten // This lock should never block, except when the application destroys the output mix object 17931df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten object_lock_exclusive(thisObject); 18031df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten unsigned activeMask; 18131df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten // If the output mix is marked for destruction, then acknowledge the request 18250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten if (thiz->mDestroyRequested) { 1833be625f40588941aa23e35fed5cb693ddc9718daGlenn Kasten IEngine *thisEngine = &thisObject->mEngine->mEngine; 18431df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten interface_lock_exclusive(thisEngine); 18531df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten assert(&thisEngine->mOutputMix->mObject == thisObject); 18631df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten thisEngine->mOutputMix = NULL; 18731df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten // Note we don't attempt to connect another output mix, even if there is one 18831df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten interface_unlock_exclusive(thisEngine); 18931df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten // Acknowledge the destroy request, and notify the pre-destroy hook 19050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mDestroyRequested = SL_BOOLEAN_FALSE; 19131df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten object_cond_broadcast(thisObject); 19231df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten activeMask = 0; 19331df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten } else { 19450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten activeMask = thiz->mActiveMask; 19531df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten } 19632a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten while (activeMask) { 19732a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten unsigned i = ctz(activeMask); 19832a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten assert(MAX_TRACK > i); 19932a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten activeMask &= ~(1 << i); 20050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten Track *track = &thiz->mTracks[i]; 20123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 202188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten // track is allocated 20323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 20466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (!track_check(track)) { 205188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten continue; 20666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 20723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten 208188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten // track is playing 209188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten void *dstWriter = pBuffer; 210188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten unsigned desired = size; 211188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten SLboolean trackContributedToMix = SL_BOOLEAN_FALSE; 21215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten float gains[STEREO_CHANNELS]; 21315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten Summary summaries[STEREO_CHANNELS]; 21415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten unsigned channel; 21515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten for (channel = 0; channel < STEREO_CHANNELS; ++channel) { 21615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten float gain = track->mGains[channel]; 21715f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten gains[channel] = gain; 21815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten Summary summary; 21966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (gain <= 0.001) { 22015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten summary = GAIN_MUTE; 22166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } else if (gain >= 0.999) { 22215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten summary = GAIN_UNITY; 22366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } else { 22415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten summary = GAIN_OTHER; 22566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 22615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten summaries[channel] = summary; 227ffeb2e16c2886eefa88d6eaf4c7be78c2eced82bGlenn Kasten } 228188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten while (desired > 0) { 229188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten unsigned actual = desired; 23066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (track->mAvail < actual) { 231188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten actual = track->mAvail; 23266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 233188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten // force actual to be a frame multiple 234188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten if (actual > 0) { 235188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten assert(NULL != track->mReader); 2363cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten stereo *mixBuffer = (stereo *) dstWriter; 2373cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten const stereo *source = (const stereo *) track->mReader; 2383cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten unsigned j; 23915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten if (GAIN_MUTE != summaries[0] || GAIN_MUTE != summaries[1]) { 2407e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten if (mixBufferHasData) { 2417e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten // apply gain during add 24215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) { 2437e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 24415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten mixBuffer->left += (short) (source->left * track->mGains[0]); 24515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten mixBuffer->right += (short) (source->right * track->mGains[1]); 2467e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten } 2477e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten // no gain adjustment needed, so do a simple add 2487e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten } else { 2497e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 2507e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten mixBuffer->left += source->left; 2517e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten mixBuffer->right += source->right; 2527e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten } 2537e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten } 2547e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten } else { 2557e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten // apply gain during copy 25615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) { 2577e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 25815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten mixBuffer->left = (short) (source->left * track->mGains[0]); 25915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten mixBuffer->right = (short) (source->right * track->mGains[1]); 2607e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten } 2617e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten // no gain adjustment needed, so do a simple copy 2627e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten } else { 2637e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten memcpy(dstWriter, track->mReader, actual); 2647e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten } 2653cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten } 266188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten trackContributedToMix = SL_BOOLEAN_TRUE; 267188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 268188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten dstWriter = (char *) dstWriter + actual; 269188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten desired -= actual; 270188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten track->mReader = (char *) track->mReader + actual; 271188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten track->mAvail -= actual; 272188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten if (track->mAvail == 0) { 27323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten IBufferQueue *bufferQueue = &track->mAudioPlayer->mBufferQueue; 27423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten interface_lock_exclusive(bufferQueue); 27523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten const BufferHeader *oldFront, *newFront, *rear; 27623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten oldFront = bufferQueue->mFront; 27723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten rear = bufferQueue->mRear; 27823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // a buffer stays on queue while playing, so it better still be there 27923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten assert(oldFront != rear); 28023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten newFront = oldFront; 28166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1]) { 28223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten newFront = bufferQueue->mArray; 28366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 28423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten bufferQueue->mFront = (BufferHeader *) newFront; 28523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten assert(0 < bufferQueue->mState.count); 28623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten --bufferQueue->mState.count; 28723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten if (newFront != rear) { 28823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // we don't acknowledge application requests between buffers 28923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // within the same mixer frame 290188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten assert(0 < bufferQueue->mState.count); 29123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten track->mReader = newFront->mBuffer; 29223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten track->mAvail = newFront->mSize; 29323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten } 29423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // else we would set play state to playable but not playing during next mixer 29523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // frame if the queue is still empty at that time 29623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten ++bufferQueue->mState.playIndex; 29723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten slBufferQueueCallback callback = bufferQueue->mCallback; 29823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten void *context = bufferQueue->mContext; 29923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten interface_unlock_exclusive(bufferQueue); 30023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // The callback function is called on each buffer completion 30123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten if (NULL != callback) { 30223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten (*callback)((SLBufferQueueItf) bufferQueue, context); 30323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // Maybe it enqueued another buffer, or maybe it didn't. 30423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // We will find out later during the next mixer frame. 305188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 306188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 30766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten // no lock, but safe because noone else updates this field 30866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten track->mFramesMixed += actual >> 2; // sizeof(short) * STEREO_CHANNELS 309188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten continue; 310188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 31123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // we need more data: desired > 0 but actual == 0 31266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (track_check(track)) { 31323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten continue; 31466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 31523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten // underflow: clear out rest of partial buffer (NTH synthesize comfort noise) 31666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (!mixBufferHasData && trackContributedToMix) { 317188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten memset(dstWriter, 0, actual); 31866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 319188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten break; 320188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 32166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (trackContributedToMix) { 322188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten mixBufferHasData = SL_BOOLEAN_TRUE; 32366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 324188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten } 32531df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten object_unlock_exclusive(thisObject); 326188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten // No active tracks, so output silence 32766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (!mixBufferHasData) { 328188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten memset(pBuffer, 0, size); 32966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 330f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten 331f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten SL_LEAVE_INTERFACE_VOID 332188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten} 333188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 334f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten 335188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = { 336188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten IOutputMixExt_FillBuffer 337188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten}; 338188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten 339188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kastenvoid IOutputMixExt_init(void *self) 340188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten{ 34150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten IOutputMixExt *thiz = (IOutputMixExt *) self; 34250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mItf = &IOutputMixExt_Itf; 34350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mActiveMask = 0; 34450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten Track *track = &thiz->mTracks[0]; 3454f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten unsigned i; 3464f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten for (i = 0; i < MAX_TRACK; ++i, ++track) { 3474f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten track->mAudioPlayer = NULL; 3484f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten } 34950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mDestroyRequested = SL_BOOLEAN_FALSE; 3506aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten} 3516aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten 3526aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten 3536aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten/** \brief Called by Engine::CreateAudioPlayer to allocate a track */ 3546aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten 35550bccde01980ae803b8656e8b08ecacb65540f50Glenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *thiz) 356f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten{ 35750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mTrack = NULL; 358182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten 359182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten // check the source for compatibility 36050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten switch (thiz->mDataSource.mLocator.mLocatorType) { 361182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten case SL_DATALOCATOR_BUFFERQUEUE: 362182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten#ifdef ANDROID 363182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: 364182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten#endif 36550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten switch (thiz->mDataSource.mFormat.mFormatType) { 366182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten case SL_DATAFORMAT_PCM: 367182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten#ifdef USE_SDL 368182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten // SDL is hard-coded to 44.1 kHz, and there is no sample rate converter 36950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten if (SL_SAMPLINGRATE_44_1 != thiz->mDataSource.mFormat.mPCM.samplesPerSec) 370182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 371182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten#endif 372182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten break; 373182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten default: 374182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten break; 375182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten } 376182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten break; 377182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten default: 378182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten break; 379182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten } 380182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten 381182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten // check the sink for compatibility 38250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten const SLDataSink *pAudioSnk = &thiz->mDataSink.u.mSink; 38310ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten Track *track = NULL; 384f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten switch (*(SLuint32 *)pAudioSnk->pLocator) { 385f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten case SL_DATALOCATOR_OUTPUTMIX: 386f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten { 387f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten // pAudioSnk->pFormat is ignored 3884f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten IOutputMixExt *omExt = &((COutputMix *) ((SLDataLocator_OutputMix *) 3894f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten pAudioSnk->pLocator)->outputMix)->mOutputMixExt; 390f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten // allocate an entry within OutputMix for this track 3914f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten interface_lock_exclusive(omExt); 3924f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten unsigned availMask = ~omExt->mActiveMask; 39332a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten if (!availMask) { 3944f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten interface_unlock_exclusive(omExt); 39532a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten // All track slots full in output mix 396f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten return SL_RESULT_MEMORY_FAILURE; 397f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten } 39832a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten unsigned i = ctz(availMask); 39932a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten assert(MAX_TRACK > i); 4004f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten omExt->mActiveMask |= 1 << i; 4014f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten track = &omExt->mTracks[i]; 4023cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten track->mAudioPlayer = NULL; // only field that is accessed before full initialization 4034f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten interface_unlock_exclusive(omExt); 40450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mTrack = track; 40550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mGains[0] = 1.0f; 40650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mGains[1] = 1.0f; 40750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten thiz->mDestroyRequested = SL_BOOLEAN_FALSE; 408f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten } 409f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten break; 410f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten default: 411f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 412f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten } 413f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten 41432a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten assert(NULL != track); 41550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten track->mBufferQueue = &thiz->mBufferQueue; 41650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten track->mAudioPlayer = thiz; 4174c0d2128c7c0a8b40803026d92083b6affc417d2Glenn Kasten track->mReader = NULL; 4184c0d2128c7c0a8b40803026d92083b6affc417d2Glenn Kasten track->mAvail = 0; 41915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten track->mGains[0] = 1.0f; 42015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten track->mGains[1] = 1.0f; 42166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten track->mFramesMixed = 0; 422f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten return SL_RESULT_SUCCESS; 423f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten} 424f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten 4256aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten 4266aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten/** \brief Called when a gain-related field (mute, solo, volume, stereo position, etc.) updated */ 4276aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten 42815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kastenvoid audioPlayerGainUpdate(CAudioPlayer *audioPlayer) 42915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten{ 43015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten SLboolean mute = audioPlayer->mVolume.mMute; 4319c2a7b1e9f8203bf9de26efca0f1f805038b1f2bGlenn Kasten SLuint8 muteMask = audioPlayer->mMuteMask; 4329c2a7b1e9f8203bf9de26efca0f1f805038b1f2bGlenn Kasten SLuint8 soloMask = audioPlayer->mSoloMask; 43315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten SLmillibel level = audioPlayer->mVolume.mLevel; 43415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten SLboolean enableStereoPosition = audioPlayer->mVolume.mEnableStereoPosition; 43515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten SLpermille stereoPosition = audioPlayer->mVolume.mStereoPosition; 43615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten 43766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (soloMask) { 43815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten muteMask |= ~soloMask; 43966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 44015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten if (mute || !(~muteMask & 3)) { 4414f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten audioPlayer->mGains[0] = 0.0f; 4424f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten audioPlayer->mGains[1] = 0.0f; 44315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten } else { 4448252e6c392af287088a55d6d31b5ba7f80f13ca4Glenn Kasten float playerGain = powf(10.0f, level / 2000.0f); 44515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten unsigned channel; 44615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten for (channel = 0; channel < STEREO_CHANNELS; ++channel) { 44715f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten float gain; 44866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (muteMask & (1 << channel)) { 4498252e6c392af287088a55d6d31b5ba7f80f13ca4Glenn Kasten gain = 0.0f; 45066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } else { 45115f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten gain = playerGain; 45215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten if (enableStereoPosition) { 45315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten switch (channel) { 45415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten case 0: 45566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (stereoPosition > 0) { 4568252e6c392af287088a55d6d31b5ba7f80f13ca4Glenn Kasten gain *= (1000 - stereoPosition) / 1000.0f; 45766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 45815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten break; 45915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten case 1: 46066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten if (stereoPosition < 0) { 4618252e6c392af287088a55d6d31b5ba7f80f13ca4Glenn Kasten gain *= (1000 + stereoPosition) / 1000.0f; 46266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten } 46315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten break; 46415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten default: 46515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten assert(SL_BOOLEAN_FALSE); 46615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten break; 46715f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten } 46815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten } 46915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten } 4704f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten audioPlayer->mGains[channel] = gain; 47115f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten } 47215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten } 47315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten} 474