IOutputMixExt.c revision 9e60b0a390d780539459f41c2bf4a45a326a7b62
1b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten/* 2b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * Copyright (C) 2010 The Android Open Source Project 3b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * 4b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License"); 5b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * you may not use this file except in compliance with the License. 6b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * You may obtain a copy of the License at 7b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * 8b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * http://www.apache.org/licenses/LICENSE-2.0 9b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * 10b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * Unless required by applicable law or agreed to in writing, software 11b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS, 12b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * See the License for the specific language governing permissions and 14b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * limitations under the License. 15b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten */ 16b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 17b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten/* OutputMixExt implementation */ 18b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 19b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#include "sles_allinclusive.h" 20e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten#include <math.h> 21b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 22b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 23928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten// OutputMixExt is used by SDL, but is not specific to or dependent on SDL 24b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 25a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten 26a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten// stereo is a frame consisting of a pair of 16-bit PCM samples 27a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten 28a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kastentypedef struct { 29a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten short left; 30a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten short right; 31a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten} stereo; 32a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten 33a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten 34343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten/** \brief Summary of the gain, as an optimization for the mixer */ 35e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 3640d1c40832a448e23d0bb37512aee53222575c2eGlenn Kastentypedef enum { 37e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten GAIN_MUTE = 0, // mValue == 0.0f within epsilon 38e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten GAIN_UNITY = 1, // mValue == 1.0f within epsilon 39e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten GAIN_OTHER = 2 // 0.0f < mValue < 1.0f 4040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten} Summary; 4140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten 42ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 43343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten/** \brief Check whether a track has any data for us to read */ 444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 45369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kastenstatic SLboolean track_check(Track *track) 464b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten{ 47928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten assert(NULL != track); 484b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten SLboolean trackHasData = SL_BOOLEAN_FALSE; 494b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 504b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten CAudioPlayer *audioPlayer = track->mAudioPlayer; 514b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (NULL != audioPlayer) { 524b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 534b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // track is initialized 544b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 55928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // FIXME This lock could block and result in stuttering; 56928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // a trylock with retry or lockless solution would be ideal 574b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten object_lock_exclusive(&audioPlayer->mObject); 58928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten assert(audioPlayer->mTrack == track); 594b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 608c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten SLuint32 framesMixed = track->mFramesMixed; 618c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (0 != framesMixed) { 628c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten track->mFramesMixed = 0; 638c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten audioPlayer->mPlay.mFramesSinceLastSeek += framesMixed; 648c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten audioPlayer->mPlay.mFramesSincePositionUpdate += framesMixed; 658c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 668c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten 674b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten SLboolean doBroadcast = SL_BOOLEAN_FALSE; 684b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten const BufferHeader *oldFront; 694b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 704b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (audioPlayer->mBufferQueue.mClearRequested) { 714b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // application thread(s) that call BufferQueue::Clear while mixer is active 72928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // will block synchronously until mixer acknowledges the Clear request 734b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mBufferQueue.mFront = &audioPlayer->mBufferQueue.mArray[0]; 744b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mBufferQueue.mRear = &audioPlayer->mBufferQueue.mArray[0]; 754b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mBufferQueue.mState.count = 0; 764f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten audioPlayer->mBufferQueue.mState.playIndex = 0; 774b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mBufferQueue.mClearRequested = SL_BOOLEAN_FALSE; 784b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mReader = NULL; 794b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mAvail = 0; 804b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten doBroadcast = SL_BOOLEAN_TRUE; 814b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 824b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 83928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten if (audioPlayer->mDestroyRequested) { 84928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // an application thread that calls Object::Destroy while mixer is active will block 85928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // synchronously in the PreDestroy hook until mixer acknowledges the Destroy request 86f51dba65751107c930759938775b75531ec1f330Glenn Kasten COutputMix *outputMix = CAudioPlayer_GetOutputMix(audioPlayer); 87928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten unsigned i = track - outputMix->mOutputMixExt.mTracks; 88928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten assert( /* 0 <= i && */ i < MAX_TRACK); 89928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten unsigned mask = 1 << i; 90928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten track->mAudioPlayer = NULL; 91928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten assert(outputMix->mOutputMixExt.mActiveMask & mask); 92928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten outputMix->mOutputMixExt.mActiveMask &= ~mask; 93928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten audioPlayer->mTrack = NULL; 94928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten audioPlayer->mDestroyRequested = SL_BOOLEAN_FALSE; 95928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten doBroadcast = SL_BOOLEAN_TRUE; 96928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten goto broadcast; 97928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 98928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten 994b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten switch (audioPlayer->mPlay.mState) { 1004b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1014b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten case SL_PLAYSTATE_PLAYING: // continue playing current track data 1024b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (0 < track->mAvail) { 1034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten trackHasData = SL_BOOLEAN_TRUE; 1044b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten break; 1054b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 1064b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1074b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // try to get another buffer from queue 1084b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten oldFront = audioPlayer->mBufferQueue.mFront; 1094b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (oldFront != audioPlayer->mBufferQueue.mRear) { 1104b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten assert(0 < audioPlayer->mBufferQueue.mState.count); 1114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mReader = oldFront->mBuffer; 1124b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mAvail = oldFront->mSize; 1134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // note that the buffer stays on the queue while we are reading 1144b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mPlay.mState = SL_PLAYSTATE_PLAYING; 1154b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten trackHasData = SL_BOOLEAN_TRUE; 1164b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } else { 1174b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // no buffers on queue, so playable but not playing 1184b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // NTH should be able to call a desperation callback when completely starved, 1194b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // or call less often than every buffer based on high/low water-marks 1204b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 121928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten 122928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten // copy gains from audio player to track 123928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten track->mGains[0] = audioPlayer->mGains[0]; 124928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten track->mGains[1] = audioPlayer->mGains[1]; 1254b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten break; 1264b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1274b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten case SL_PLAYSTATE_STOPPING: // application thread(s) called Play::SetPlayState(STOPPED) 1284b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mPlay.mPosition = (SLmillisecond) 0; 1298c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten audioPlayer->mPlay.mFramesSinceLastSeek = 0; 1308c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten audioPlayer->mPlay.mFramesSincePositionUpdate = 0; 1318c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten audioPlayer->mPlay.mLastSeekPosition = 0; 1324b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mPlay.mState = SL_PLAYSTATE_STOPPED; 1338c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // stop cancels a pending seek 1348c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN; 1354b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten oldFront = audioPlayer->mBufferQueue.mFront; 1364b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (oldFront != audioPlayer->mBufferQueue.mRear) { 1374b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten assert(0 < audioPlayer->mBufferQueue.mState.count); 1384b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mReader = oldFront->mBuffer; 1394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mAvail = oldFront->mSize; 1404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 1414b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten doBroadcast = SL_BOOLEAN_TRUE; 1424b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten break; 1434b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten case SL_PLAYSTATE_STOPPED: // idle 1454b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten case SL_PLAYSTATE_PAUSED: // idle 1464b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten break; 1474b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1484b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten default: 1494b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten assert(SL_BOOLEAN_FALSE); 1504b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten break; 1514b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 1524b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 153928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kastenbroadcast: 1548c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (doBroadcast) { 1554b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten object_cond_broadcast(&audioPlayer->mObject); 1568c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 1574b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1584b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten object_unlock_exclusive(&audioPlayer->mObject); 1594b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1604b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 1614b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1624b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten return trackHasData; 1634b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1644b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten} 1654b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 166343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten 167928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief This is the track mixer: fill the specified 16-bit stereo PCM buffer */ 168343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten 169e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kastenvoid IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size) 170b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 171ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE_VOID 172ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 173b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // Force to be a multiple of a frame, assumes stereo 16-bit PCM 174b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten size &= ~3; 175b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean mixBufferHasData = SL_BOOLEAN_FALSE; 176f51dba65751107c930759938775b75531ec1f330Glenn Kasten IOutputMixExt *this = (IOutputMixExt *) self; 177f51dba65751107c930759938775b75531ec1f330Glenn Kasten IObject *thisObject = this->mThis; 178f51dba65751107c930759938775b75531ec1f330Glenn Kasten // This lock should never block, except when the application destroys the output mix object 179f51dba65751107c930759938775b75531ec1f330Glenn Kasten object_lock_exclusive(thisObject); 180f51dba65751107c930759938775b75531ec1f330Glenn Kasten unsigned activeMask; 181f51dba65751107c930759938775b75531ec1f330Glenn Kasten // If the output mix is marked for destruction, then acknowledge the request 182f51dba65751107c930759938775b75531ec1f330Glenn Kasten if (this->mDestroyRequested) { 183f51dba65751107c930759938775b75531ec1f330Glenn Kasten IEngine *thisEngine = thisObject->mEngine; 184f51dba65751107c930759938775b75531ec1f330Glenn Kasten interface_lock_exclusive(thisEngine); 185f51dba65751107c930759938775b75531ec1f330Glenn Kasten assert(&thisEngine->mOutputMix->mObject == thisObject); 186f51dba65751107c930759938775b75531ec1f330Glenn Kasten thisEngine->mOutputMix = NULL; 187f51dba65751107c930759938775b75531ec1f330Glenn Kasten // Note we don't attempt to connect another output mix, even if there is one 188f51dba65751107c930759938775b75531ec1f330Glenn Kasten interface_unlock_exclusive(thisEngine); 189f51dba65751107c930759938775b75531ec1f330Glenn Kasten // Acknowledge the destroy request, and notify the pre-destroy hook 190f51dba65751107c930759938775b75531ec1f330Glenn Kasten this->mDestroyRequested = SL_BOOLEAN_FALSE; 191f51dba65751107c930759938775b75531ec1f330Glenn Kasten object_cond_broadcast(thisObject); 192f51dba65751107c930759938775b75531ec1f330Glenn Kasten activeMask = 0; 193f51dba65751107c930759938775b75531ec1f330Glenn Kasten } else { 194f51dba65751107c930759938775b75531ec1f330Glenn Kasten activeMask = this->mActiveMask; 195f51dba65751107c930759938775b75531ec1f330Glenn Kasten } 196d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten while (activeMask) { 197d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned i = ctz(activeMask); 198d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(MAX_TRACK > i); 199d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten activeMask &= ~(1 << i); 200369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten Track *track = &this->mTracks[i]; 2014b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 202b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is allocated 2034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 2048c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (!track_check(track)) { 205b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 2068c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 2074b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 208b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is playing 209b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten void *dstWriter = pBuffer; 210b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned desired = size; 211b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean trackContributedToMix = SL_BOOLEAN_FALSE; 212e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten float gains[STEREO_CHANNELS]; 213e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten Summary summaries[STEREO_CHANNELS]; 214e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten unsigned channel; 215e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten for (channel = 0; channel < STEREO_CHANNELS; ++channel) { 216e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten float gain = track->mGains[channel]; 217e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten gains[channel] = gain; 218e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten Summary summary; 2198c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (gain <= 0.001) { 220e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summary = GAIN_MUTE; 2218c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } else if (gain >= 0.999) { 222e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summary = GAIN_UNITY; 2238c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } else { 224e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summary = GAIN_OTHER; 2258c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 226e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summaries[channel] = summary; 2276a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten } 228b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten while (desired > 0) { 229b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned actual = desired; 2308c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (track->mAvail < actual) { 231b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten actual = track->mAvail; 2328c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 233b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // force actual to be a frame multiple 234b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (actual > 0) { 235b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(NULL != track->mReader); 236276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten stereo *mixBuffer = (stereo *) dstWriter; 237276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten const stereo *source = (const stereo *) track->mReader; 238276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten unsigned j; 239e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (GAIN_MUTE != summaries[0] || GAIN_MUTE != summaries[1]) { 24040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten if (mixBufferHasData) { 24140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // apply gain during add 242e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) { 24340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 244e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->left += (short) (source->left * track->mGains[0]); 245e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->right += (short) (source->right * track->mGains[1]); 24640d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 24740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // no gain adjustment needed, so do a simple add 24840d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } else { 24940d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 25040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten mixBuffer->left += source->left; 25140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten mixBuffer->right += source->right; 25240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 25340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 25440d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } else { 25540d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // apply gain during copy 256e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) { 25740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 258e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->left = (short) (source->left * track->mGains[0]); 259e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->right = (short) (source->right * track->mGains[1]); 26040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 26140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // no gain adjustment needed, so do a simple copy 26240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } else { 26340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten memcpy(dstWriter, track->mReader, actual); 26440d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 265276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten } 266b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten trackContributedToMix = SL_BOOLEAN_TRUE; 267b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 268b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten dstWriter = (char *) dstWriter + actual; 269b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten desired -= actual; 270b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mReader = (char *) track->mReader + actual; 271b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mAvail -= actual; 272b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail == 0) { 2734b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten IBufferQueue *bufferQueue = &track->mAudioPlayer->mBufferQueue; 2744b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten interface_lock_exclusive(bufferQueue); 2754b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten const BufferHeader *oldFront, *newFront, *rear; 2764b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten oldFront = bufferQueue->mFront; 2774b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten rear = bufferQueue->mRear; 2784b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // a buffer stays on queue while playing, so it better still be there 2794b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten assert(oldFront != rear); 2804b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten newFront = oldFront; 2818c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1]) { 2824b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten newFront = bufferQueue->mArray; 2838c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 2844b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten bufferQueue->mFront = (BufferHeader *) newFront; 2854b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten assert(0 < bufferQueue->mState.count); 2864b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten --bufferQueue->mState.count; 2874b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (newFront != rear) { 2884b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // we don't acknowledge application requests between buffers 2894b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // within the same mixer frame 290b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(0 < bufferQueue->mState.count); 2914b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mReader = newFront->mBuffer; 2924b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mAvail = newFront->mSize; 2934b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 2944b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // else we would set play state to playable but not playing during next mixer 2954b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // frame if the queue is still empty at that time 2964b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten ++bufferQueue->mState.playIndex; 2974b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten slBufferQueueCallback callback = bufferQueue->mCallback; 2984b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten void *context = bufferQueue->mContext; 2994b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten interface_unlock_exclusive(bufferQueue); 3004b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // The callback function is called on each buffer completion 3014b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (NULL != callback) { 3024b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten (*callback)((SLBufferQueueItf) bufferQueue, context); 3034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // Maybe it enqueued another buffer, or maybe it didn't. 3044b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // We will find out later during the next mixer frame. 305b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 306b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 3078c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten // no lock, but safe because noone else updates this field 3088c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten track->mFramesMixed += actual >> 2; // sizeof(short) * STEREO_CHANNELS 309b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 310b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 3114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // we need more data: desired > 0 but actual == 0 3128c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (track_check(track)) { 3134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten continue; 3148c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 3154b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // underflow: clear out rest of partial buffer (NTH synthesize comfort noise) 3168c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (!mixBufferHasData && trackContributedToMix) { 317b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(dstWriter, 0, actual); 3188c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 319b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 320b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 3218c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (trackContributedToMix) { 322b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBufferHasData = SL_BOOLEAN_TRUE; 3238c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 324b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 325f51dba65751107c930759938775b75531ec1f330Glenn Kasten object_unlock_exclusive(thisObject); 326b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // No active tracks, so output silence 3278c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (!mixBufferHasData) { 328b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(pBuffer, 0, size); 3298c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 330ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 331ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE_VOID 332b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 333b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 334ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 335b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = { 336b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt_FillBuffer 337b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}; 338b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 339b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenvoid IOutputMixExt_init(void *self) 340b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 341b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt *this = (IOutputMixExt *) self; 342b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten this->mItf = &IOutputMixExt_Itf; 343928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten this->mActiveMask = 0; 344928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten Track *track = &this->mTracks[0]; 345928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten unsigned i; 346928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten for (i = 0; i < MAX_TRACK; ++i, ++track) { 347928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten track->mAudioPlayer = NULL; 348928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten } 349f51dba65751107c930759938775b75531ec1f330Glenn Kasten this->mDestroyRequested = SL_BOOLEAN_FALSE; 350343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten} 351343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten 352343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten 353343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten/** \brief Called by Engine::CreateAudioPlayer to allocate a track */ 354343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten 355acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *this) 356daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{ 357e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten this->mTrack = NULL; 3589e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten 3599e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten // check the source for compatibility 3609e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten switch (this->mDataSource.mLocator.mLocatorType) { 3619e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten case SL_DATALOCATOR_BUFFERQUEUE: 3629e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten#ifdef ANDROID 3639e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE: 3649e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten#endif 3659e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten switch (this->mDataSource.mFormat.mFormatType) { 3669e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten case SL_DATAFORMAT_PCM: 3679e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten#ifdef USE_SDL 3689e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten // SDL is hard-coded to 44.1 kHz, and there is no sample rate converter 3699e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten if (SL_SAMPLINGRATE_44_1 != this->mDataSource.mFormat.mPCM.samplesPerSec) 3709e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 3719e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten#endif 3729e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten break; 3739e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten default: 3749e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten break; 3759e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten } 3769e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten break; 3779e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten default: 3789e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten break; 3799e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten } 3809e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten 3819e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten // check the sink for compatibility 382acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten const SLDataSink *pAudioSnk = &this->mDataSink.u.mSink; 383369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten Track *track = NULL; 384daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten switch (*(SLuint32 *)pAudioSnk->pLocator) { 385daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten case SL_DATALOCATOR_OUTPUTMIX: 386daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten { 387daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // pAudioSnk->pFormat is ignored 388928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten IOutputMixExt *omExt = &((COutputMix *) ((SLDataLocator_OutputMix *) 389928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten pAudioSnk->pLocator)->outputMix)->mOutputMixExt; 390daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // allocate an entry within OutputMix for this track 391928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten interface_lock_exclusive(omExt); 392928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten unsigned availMask = ~omExt->mActiveMask; 393d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten if (!availMask) { 394928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten interface_unlock_exclusive(omExt); 395d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // All track slots full in output mix 396daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_MEMORY_FAILURE; 397daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 398d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned i = ctz(availMask); 399d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(MAX_TRACK > i); 400928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten omExt->mActiveMask |= 1 << i; 401928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten track = &omExt->mTracks[i]; 402276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten track->mAudioPlayer = NULL; // only field that is accessed before full initialization 403928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten interface_unlock_exclusive(omExt); 404e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten this->mTrack = track; 405928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten this->mGains[0] = 1.0f; 406928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten this->mGains[1] = 1.0f; 407928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten this->mDestroyRequested = SL_BOOLEAN_FALSE; 408daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 409daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 410daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten default: 411daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 412daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 413daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 414d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(NULL != track); 415acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mBufferQueue = &this->mBufferQueue; 416276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten track->mAudioPlayer = this; 417acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mReader = NULL; 418acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mAvail = 0; 419e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mGains[0] = 1.0f; 420e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mGains[1] = 1.0f; 4218c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten track->mFramesMixed = 0; 422daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_SUCCESS; 423daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten} 424daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 425343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten 426343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten/** \brief Called when a gain-related field (mute, solo, volume, stereo position, etc.) updated */ 427343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten 428e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kastenvoid audioPlayerGainUpdate(CAudioPlayer *audioPlayer) 429e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten{ 430e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLboolean mute = audioPlayer->mVolume.mMute; 431b91e32605ecf39e34ad39936b1ee193bb4e30225Glenn Kasten SLuint8 muteMask = audioPlayer->mMuteMask; 432b91e32605ecf39e34ad39936b1ee193bb4e30225Glenn Kasten SLuint8 soloMask = audioPlayer->mSoloMask; 433e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLmillibel level = audioPlayer->mVolume.mLevel; 434e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLboolean enableStereoPosition = audioPlayer->mVolume.mEnableStereoPosition; 435e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLpermille stereoPosition = audioPlayer->mVolume.mStereoPosition; 436e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 4378c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (soloMask) { 438e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten muteMask |= ~soloMask; 4398c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 440e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (mute || !(~muteMask & 3)) { 441928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten audioPlayer->mGains[0] = 0.0f; 442928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten audioPlayer->mGains[1] = 0.0f; 443e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } else { 44418abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten float playerGain = powf(10.0f, level / 2000.0f); 445e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten unsigned channel; 446e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten for (channel = 0; channel < STEREO_CHANNELS; ++channel) { 447e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten float gain; 4488c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (muteMask & (1 << channel)) { 44918abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten gain = 0.0f; 4508c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } else { 451e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten gain = playerGain; 452e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (enableStereoPosition) { 453e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten switch (channel) { 454e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten case 0: 4558c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (stereoPosition > 0) { 45618abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten gain *= (1000 - stereoPosition) / 1000.0f; 4578c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 458e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten break; 459e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten case 1: 4608c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten if (stereoPosition < 0) { 46118abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten gain *= (1000 + stereoPosition) / 1000.0f; 4628c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten } 463e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten break; 464e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten default: 465e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten assert(SL_BOOLEAN_FALSE); 466e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten break; 467e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 468e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 469e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 470928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten audioPlayer->mGains[channel] = gain; 471e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 472e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 473e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten} 474