IOutputMixExt.c revision 18abcc4b70fab1f84d6fbebac3a8e34480a6c4d3
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#ifdef USE_OUTPUTMIXEXT 23b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 24b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten// Used by SDL but not specific to or dependent on SDL 25b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 26e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten// Summary of the gain, as an optimization for the mixer 27e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 2840d1c40832a448e23d0bb37512aee53222575c2eGlenn Kastentypedef enum { 29e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten GAIN_MUTE = 0, // mValue == 0.0f within epsilon 30e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten GAIN_UNITY = 1, // mValue == 1.0f within epsilon 31e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten GAIN_OTHER = 2 // 0.0f < mValue < 1.0f 3240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten} Summary; 3340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten 34ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 354b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten/** Check whether a track has any data for us to read. */ 364b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 37369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kastenstatic SLboolean track_check(Track *track) 384b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten{ 394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten SLboolean trackHasData = SL_BOOLEAN_FALSE; 404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 414b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten CAudioPlayer *audioPlayer = track->mAudioPlayer; 424b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (NULL != audioPlayer) { 434b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // track is initialized 454b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 464b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten object_lock_exclusive(&audioPlayer->mObject); 474b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 484b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten SLboolean doBroadcast = SL_BOOLEAN_FALSE; 494b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten const BufferHeader *oldFront; 504b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 514b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (audioPlayer->mBufferQueue.mClearRequested) { 524b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // application thread(s) that call BufferQueue::Clear while mixer is active 534b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // is active will block synchronously until mixer acknowledges the Clear request 544b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mBufferQueue.mFront = &audioPlayer->mBufferQueue.mArray[0]; 554b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mBufferQueue.mRear = &audioPlayer->mBufferQueue.mArray[0]; 564b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mBufferQueue.mState.count = 0; 574b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mBufferQueue.mClearRequested = SL_BOOLEAN_FALSE; 584b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mReader = NULL; 594b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mAvail = 0; 604b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten doBroadcast = SL_BOOLEAN_TRUE; 614b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 624b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 634b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten switch (audioPlayer->mPlay.mState) { 644b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 654b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten case SL_PLAYSTATE_PLAYING: // continue playing current track data 664b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (0 < track->mAvail) { 674b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten trackHasData = SL_BOOLEAN_TRUE; 684b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten break; 694b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 704b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 714b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // try to get another buffer from queue 724b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten oldFront = audioPlayer->mBufferQueue.mFront; 734b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (oldFront != audioPlayer->mBufferQueue.mRear) { 744b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten assert(0 < audioPlayer->mBufferQueue.mState.count); 754b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mReader = oldFront->mBuffer; 764b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mAvail = oldFront->mSize; 774b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // note that the buffer stays on the queue while we are reading 784b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mPlay.mState = SL_PLAYSTATE_PLAYING; 794b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten trackHasData = SL_BOOLEAN_TRUE; 804b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } else { 814b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // no buffers on queue, so playable but not playing 824b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // NTH should be able to call a desperation callback when completely starved, 834b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // or call less often than every buffer based on high/low water-marks 844b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 854b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten break; 864b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 874b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten case SL_PLAYSTATE_STOPPING: // application thread(s) called Play::SetPlayState(STOPPED) 884b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mPlay.mPosition = (SLmillisecond) 0; 894b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten audioPlayer->mPlay.mState = SL_PLAYSTATE_STOPPED; 904b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten oldFront = audioPlayer->mBufferQueue.mFront; 914b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (oldFront != audioPlayer->mBufferQueue.mRear) { 924b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten assert(0 < audioPlayer->mBufferQueue.mState.count); 934b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mReader = oldFront->mBuffer; 944b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mAvail = oldFront->mSize; 954b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 964b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten doBroadcast = SL_BOOLEAN_TRUE; 974b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten break; 984b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 994b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten case SL_PLAYSTATE_STOPPED: // idle 1004b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten case SL_PLAYSTATE_PAUSED: // idle 1014b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten break; 1024b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten default: 1044b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten assert(SL_BOOLEAN_FALSE); 1054b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten break; 1064b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 1074b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1084b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (doBroadcast) 1094b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten object_cond_broadcast(&audioPlayer->mObject); 1104b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten object_unlock_exclusive(&audioPlayer->mObject); 1124b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 1144b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1154b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten return trackHasData; 1164b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1174b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten} 1184b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 119b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic void IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size) 120b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 121ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_ENTER_INTERFACE_VOID 122ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 123b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // Force to be a multiple of a frame, assumes stereo 16-bit PCM 124b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten size &= ~3; 125daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten IOutputMixExt *thisExt = (IOutputMixExt *) self; 126d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten IOutputMix *this = &((COutputMix *) InterfaceToIObject(thisExt))->mOutputMix; 127b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned activeMask = this->mActiveMask; 128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean mixBufferHasData = SL_BOOLEAN_FALSE; 129d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten while (activeMask) { 130d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned i = ctz(activeMask); 131d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(MAX_TRACK > i); 132d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten activeMask &= ~(1 << i); 133369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten Track *track = &this->mTracks[i]; 1344b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 135b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is allocated 1364b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 1374b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (!track_check(track)) 138b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 1394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten 140b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is playing 141b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten void *dstWriter = pBuffer; 142b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned desired = size; 143b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean trackContributedToMix = SL_BOOLEAN_FALSE; 144e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten float gains[STEREO_CHANNELS]; 145e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten Summary summaries[STEREO_CHANNELS]; 146e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten unsigned channel; 147e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten for (channel = 0; channel < STEREO_CHANNELS; ++channel) { 148e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten float gain = track->mGains[channel]; 149e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten gains[channel] = gain; 150e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten Summary summary; 151e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (gain <= 0.001) 152e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summary = GAIN_MUTE; 153e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten else if (gain >= 0.999) 154e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summary = GAIN_UNITY; 155e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten else 156e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summary = GAIN_OTHER; 157e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summaries[channel] = summary; 1586a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten } 159b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten while (desired > 0) { 160b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned actual = desired; 161b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail < actual) 162b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten actual = track->mAvail; 163b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // force actual to be a frame multiple 164b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (actual > 0) { 165b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(NULL != track->mReader); 166276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten stereo *mixBuffer = (stereo *) dstWriter; 167276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten const stereo *source = (const stereo *) track->mReader; 168276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten unsigned j; 169e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (GAIN_MUTE != summaries[0] || GAIN_MUTE != summaries[1]) { 17040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten if (mixBufferHasData) { 17140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // apply gain during add 172e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) { 17340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 174e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->left += (short) (source->left * track->mGains[0]); 175e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->right += (short) (source->right * track->mGains[1]); 17640d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 17740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // no gain adjustment needed, so do a simple add 17840d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } else { 17940d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 18040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten mixBuffer->left += source->left; 18140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten mixBuffer->right += source->right; 18240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 18340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 18440d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } else { 18540d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // apply gain during copy 186e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) { 18740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 188e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->left = (short) (source->left * track->mGains[0]); 189e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->right = (short) (source->right * track->mGains[1]); 19040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 19140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // no gain adjustment needed, so do a simple copy 19240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } else { 19340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten memcpy(dstWriter, track->mReader, actual); 19440d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 195276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten } 196b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten trackContributedToMix = SL_BOOLEAN_TRUE; 197b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 198b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten dstWriter = (char *) dstWriter + actual; 199b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten desired -= actual; 200b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mReader = (char *) track->mReader + actual; 201b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mAvail -= actual; 202b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail == 0) { 2034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten IBufferQueue *bufferQueue = &track->mAudioPlayer->mBufferQueue; 2044b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten interface_lock_exclusive(bufferQueue); 2054b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten const BufferHeader *oldFront, *newFront, *rear; 2064b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten oldFront = bufferQueue->mFront; 2074b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten rear = bufferQueue->mRear; 2084b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // a buffer stays on queue while playing, so it better still be there 2094b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten assert(oldFront != rear); 2104b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten newFront = oldFront; 2114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1]) 2124b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten newFront = bufferQueue->mArray; 2134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten bufferQueue->mFront = (BufferHeader *) newFront; 2144b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten assert(0 < bufferQueue->mState.count); 2154b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten --bufferQueue->mState.count; 2164b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (newFront != rear) { 2174b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // we don't acknowledge application requests between buffers 2184b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // within the same mixer frame 219b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(0 < bufferQueue->mState.count); 2204b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mReader = newFront->mBuffer; 2214b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mAvail = newFront->mSize; 2224b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten } 2234b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // else we would set play state to playable but not playing during next mixer 2244b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // frame if the queue is still empty at that time 2254b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten ++bufferQueue->mState.playIndex; 2264b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten slBufferQueueCallback callback = bufferQueue->mCallback; 2274b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten void *context = bufferQueue->mContext; 2284b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten interface_unlock_exclusive(bufferQueue); 2294b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // The callback function is called on each buffer completion 2304b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (NULL != callback) { 2314b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten (*callback)((SLBufferQueueItf) bufferQueue, context); 2324b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // Maybe it enqueued another buffer, or maybe it didn't. 2334b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // We will find out later during the next mixer frame. 234b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 235b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 236e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten // no lock, but safe b/c noone else updates this field 237e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mFrameCounter += actual >> 2; // sizeof(short) * STEREO_CHANNELS 2387a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten // NTH Calling the callback too often, should depend on requested update period 2394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // FIXME need a lock to get these pointers, and called too often 2404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (track->mAudioPlayer->mPlay.mCallback) 2414b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten (*track->mAudioPlayer->mPlay.mCallback)(&track->mAudioPlayer->mPlay.mItf, 2424b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten track->mAudioPlayer->mPlay.mContext, SL_PLAYEVENT_HEADMOVING); 243b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 244b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 2454b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // we need more data: desired > 0 but actual == 0 2464b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten if (track_check(track)) 2474b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten continue; 2484b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten // underflow: clear out rest of partial buffer (NTH synthesize comfort noise) 249b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!mixBufferHasData && trackContributedToMix) 250b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(dstWriter, 0, actual); 251b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 252b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 253b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (trackContributedToMix) 254b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBufferHasData = SL_BOOLEAN_TRUE; 255b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 256b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // No active tracks, so output silence 257b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!mixBufferHasData) 258b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(pBuffer, 0, size); 259ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 260ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten SL_LEAVE_INTERFACE_VOID 261b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 262b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 263ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten 264b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = { 265b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt_FillBuffer 266b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}; 267b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 268b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenvoid IOutputMixExt_init(void *self) 269b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 270b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt *this = (IOutputMixExt *) self; 271b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten this->mItf = &IOutputMixExt_Itf; 272b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 273b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 274acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *this) 275daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{ 276e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten this->mTrack = NULL; 277acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten const SLDataSink *pAudioSnk = &this->mDataSink.u.mSink; 278369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten Track *track = NULL; 279daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten switch (*(SLuint32 *)pAudioSnk->pLocator) { 280daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten case SL_DATALOCATOR_OUTPUTMIX: 281daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten { 282daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // pAudioSnk->pFormat is ignored 283e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten IOutputMix *om = &((COutputMix *) ((SLDataLocator_OutputMix *) 284e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten pAudioSnk->pLocator)->outputMix)->mOutputMix; 285daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // allocate an entry within OutputMix for this track 286d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten interface_lock_exclusive(om); 287d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned availMask = ~om->mActiveMask; 288d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten if (!availMask) { 289d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten interface_unlock_exclusive(om); 290d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // All track slots full in output mix 291daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_MEMORY_FAILURE; 292daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 293d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned i = ctz(availMask); 294d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(MAX_TRACK > i); 295d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten om->mActiveMask |= 1 << i; 296d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten track = &om->mTracks[i]; 297276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten track->mAudioPlayer = NULL; // only field that is accessed before full initialization 298d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten interface_unlock_exclusive(om); 299e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten this->mTrack = track; 300daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 301daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 302daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten default: 303daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 304daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 305daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 306d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // FIXME Wrong place for this initialization; should first pre-allocate a track slot 307d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // using OutputMixExt.mTrackCount, then initialize full audio player, then do track bit 308d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // allocation, initialize rest of track, and doubly-link track to player (currently single). 309d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(NULL != track); 310acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mBufferQueue = &this->mBufferQueue; 311276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten track->mAudioPlayer = this; 312acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mReader = NULL; 313acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mAvail = 0; 314e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mGains[0] = 1.0f; 315e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mGains[1] = 1.0f; 316e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mFrameCounter = 0; 317daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_SUCCESS; 318daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten} 319daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 320e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kastenvoid audioPlayerGainUpdate(CAudioPlayer *audioPlayer) 321e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten{ 322e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten // FIXME need a lock on the track while updating gain 323369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten Track *track = audioPlayer->mTrack; 324e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 325e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (NULL == track) 326e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten return; 327e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 328e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLboolean mute = audioPlayer->mVolume.mMute; 329b91e32605ecf39e34ad39936b1ee193bb4e30225Glenn Kasten SLuint8 muteMask = audioPlayer->mMuteMask; 330b91e32605ecf39e34ad39936b1ee193bb4e30225Glenn Kasten SLuint8 soloMask = audioPlayer->mSoloMask; 331e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLmillibel level = audioPlayer->mVolume.mLevel; 332e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLboolean enableStereoPosition = audioPlayer->mVolume.mEnableStereoPosition; 333e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLpermille stereoPosition = audioPlayer->mVolume.mStereoPosition; 334e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 335e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (soloMask) 336e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten muteMask |= ~soloMask; 337e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (mute || !(~muteMask & 3)) { 33818abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten track->mGains[0] = 0.0f; 33918abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten track->mGains[1] = 0.0f; 340e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } else { 34118abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten float playerGain = powf(10.0f, level / 2000.0f); 342e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten unsigned channel; 343e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten for (channel = 0; channel < STEREO_CHANNELS; ++channel) { 344e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten float gain; 345e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (muteMask & (1 << channel)) 34618abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten gain = 0.0f; 347e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten else { 348e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten gain = playerGain; 349e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (enableStereoPosition) { 350e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten switch (channel) { 351e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten case 0: 352e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (stereoPosition > 0) 35318abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten gain *= (1000 - stereoPosition) / 1000.0f; 354e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten break; 355e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten case 1: 356e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (stereoPosition < 0) 35718abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten gain *= (1000 + stereoPosition) / 1000.0f; 358e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten break; 359e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten default: 360e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten assert(SL_BOOLEAN_FALSE); 361e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten break; 362e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 363e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 364e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 365e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mGains[channel] = gain; 366e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 367e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 368e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten} 369e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 370b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif // USE_OUTPUTMIXEXT 371