IOutputMixExt.c revision d07ed7df4ec9338f97f12627690d58ed9b34f25b
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" 20b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 21b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#ifdef USE_OUTPUTMIXEXT 22b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 23b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten// Used by SDL but not specific to or dependent on SDL 24b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 25b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic void IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size) 26b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 27b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // Force to be a multiple of a frame, assumes stereo 16-bit PCM 28b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten size &= ~3; 29daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten IOutputMixExt *thisExt = (IOutputMixExt *) self; 30d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten IOutputMix *this = &((COutputMix *) InterfaceToIObject(thisExt))->mOutputMix; 31b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned activeMask = this->mActiveMask; 32b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean mixBufferHasData = SL_BOOLEAN_FALSE; 33d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten while (activeMask) { 34d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned i = ctz(activeMask); 35d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(MAX_TRACK > i); 36d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten activeMask &= ~(1 << i); 37d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten struct Track *track = &this->mTracks[i]; 38b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is allocated 39b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IPlay *play = track->mPlay; 40b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL == play) 41b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 42b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is initialized 43b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (SL_PLAYSTATE_PLAYING != play->mState) 44b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 45b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is playing 46b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten void *dstWriter = pBuffer; 47b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned desired = size; 48b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean trackContributedToMix = SL_BOOLEAN_FALSE; 493a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten IBufferQueue *bufferQueue = track->mBufferQueue; 50b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten while (desired > 0) { 51d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten const BufferHeader *oldFront, *newFront, *rear; 52b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned actual = desired; 53b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail < actual) 54b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten actual = track->mAvail; 55b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // force actual to be a frame multiple 56b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (actual > 0) { 57b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME check for either mute or volume 0 58b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // in which case skip the input buffer processing 59b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(NULL != track->mReader); 60b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME && gain == 1.0 61b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (mixBufferHasData) { 62b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten stereo *mixBuffer = (stereo *) dstWriter; 63b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten const stereo *source = (const stereo *) track->mReader; 64b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned j; 65b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, 66b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten ++source) { 67b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // apply gain here 68b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBuffer->left += source->left; 69b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBuffer->right += source->right; 70b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 71b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } else { 72daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // apply gain during copy 73b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memcpy(dstWriter, track->mReader, actual); 74b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten trackContributedToMix = SL_BOOLEAN_TRUE; 75b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 76b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten dstWriter = (char *) dstWriter + actual; 77b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten desired -= actual; 78b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mReader = (char *) track->mReader + actual; 79b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mAvail -= actual; 80b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail == 0) { 81b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != bufferQueue) { 823a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_lock_exclusive(bufferQueue); 83b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten oldFront = bufferQueue->mFront; 84b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten rear = bufferQueue->mRear; 85b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(oldFront != rear); 86b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten newFront = oldFront; 87d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1]) 88b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten newFront = bufferQueue->mArray; 89d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten bufferQueue->mFront = (BufferHeader *) newFront; 90b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(0 < bufferQueue->mState.count); 91b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten --bufferQueue->mState.count; 92b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME here or in Enqueue? 93b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten ++bufferQueue->mState.playIndex; 943a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_unlock_exclusive(bufferQueue); 95b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME a good time to do an early warning 96b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // callback depending on buffer count 97b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 98b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 99b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 100b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 101b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // actual == 0 102b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != bufferQueue) { 1033a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_lock_shared(bufferQueue); 104b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten oldFront = bufferQueue->mFront; 105b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten rear = bufferQueue->mRear; 106b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (oldFront != rear) { 107b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastengot_one: 108b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(0 < bufferQueue->mState.count); 109b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mReader = oldFront->mBuffer; 110b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mAvail = oldFront->mSize; 1113a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_unlock_shared(bufferQueue); 112b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 113b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 114b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME should be able to configure when to 115b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // kick off the callback e.g. high/low water-marks etc. 116b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // need data but none available, attempt a desperate callback 117b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten slBufferQueueCallback callback = bufferQueue->mCallback; 1183a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten void *context = bufferQueue->mContext; 1193a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_unlock_shared(bufferQueue); 120b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != callback) { 1213a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten (*callback)((SLBufferQueueItf) bufferQueue, context); 122b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // if lucky, the callback enqueued a buffer 1233a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_lock_shared(bufferQueue); 124b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (rear != bufferQueue->mRear) 125b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten goto got_one; 1263a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_unlock_shared(bufferQueue); 127b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // unlucky, queue still empty, the callback failed 128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 129b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // here on underflow due to no callback, or failed callback 130b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME underflow, send silence (or previous buffer?) 131b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // we did a callback to try to kick start again but failed 132b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // should log this 133b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 134b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // no buffer queue or underflow, clear out rest of partial buffer 135b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!mixBufferHasData && trackContributedToMix) 136b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(dstWriter, 0, actual); 137b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 138b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 139b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (trackContributedToMix) 140b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBufferHasData = SL_BOOLEAN_TRUE; 141b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 142b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // No active tracks, so output silence 143b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!mixBufferHasData) 144b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(pBuffer, 0, size); 145b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 146b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 147b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = { 148b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt_FillBuffer 149b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}; 150b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 151b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenvoid IOutputMixExt_init(void *self) 152b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 153b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt *this = (IOutputMixExt *) self; 154b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten this->mItf = &IOutputMixExt_Itf; 155b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 156b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 157acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *this) 158daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{ 159acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten const SLDataSink *pAudioSnk = &this->mDataSink.u.mSink; 160daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten struct Track *track = NULL; 161daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten switch (*(SLuint32 *)pAudioSnk->pLocator) { 162daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten case SL_DATALOCATOR_OUTPUTMIX: 163daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten { 164daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // pAudioSnk->pFormat is ignored 165daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten IOutputMix *om = &((COutputMix *) ((SLDataLocator_OutputMix *) pAudioSnk->pLocator)->outputMix)->mOutputMix; 166daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // allocate an entry within OutputMix for this track 167d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten interface_lock_exclusive(om); 168d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned availMask = ~om->mActiveMask; 169d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten if (!availMask) { 170d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten interface_unlock_exclusive(om); 171d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // All track slots full in output mix 172daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_MEMORY_FAILURE; 173daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 174d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned i = ctz(availMask); 175d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(MAX_TRACK > i); 176d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten om->mActiveMask |= 1 << i; 177d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten track = &om->mTracks[i]; 178d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten track->mPlay = NULL; // only field that is accessed before full initialization 179d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten interface_unlock_exclusive(om); 180daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 181daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 182daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten default: 183daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 184daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 185daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 186d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // FIXME Wrong place for this initialization; should first pre-allocate a track slot 187d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // using OutputMixExt.mTrackCount, then initialize full audio player, then do track bit 188d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // allocation, initialize rest of track, and doubly-link track to player (currently single). 189d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(NULL != track); 190acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mBufferQueue = &this->mBufferQueue; 191acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mPlay = &this->mPlay; 192acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mReader = NULL; 193acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mAvail = 0; 194daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_SUCCESS; 195daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten} 196daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 197b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif // USE_OUTPUTMIXEXT 198