IOutputMixExt.c revision acd88797a1d3b8225bab888d29036e245f275be5
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; 30daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten IOutputMix *this = &((COutputMix *) thisExt->mThis)->mOutputMix; 31b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned activeMask = this->mActiveMask; 32daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten struct Track *track = this->mTracks; 33b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned i; 34b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean mixBufferHasData = SL_BOOLEAN_FALSE; 35b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME O(32) loop even when few tracks are active. 36b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // To avoid loop, use activeMask to check for active track(s) 37b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // and decide whether we actually need to copy or mix. 38b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten for (i = 0; 0 != activeMask; ++i, ++track, activeMask >>= 1) { 39b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(i < 32); 40b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!(activeMask & 1)) 41b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 42b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is allocated 43b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IPlay *play = track->mPlay; 44b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL == play) 45b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 46b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is initialized 47b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (SL_PLAYSTATE_PLAYING != play->mState) 48b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 49b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is playing 50b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten void *dstWriter = pBuffer; 51b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned desired = size; 52b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean trackContributedToMix = SL_BOOLEAN_FALSE; 53b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten while (desired > 0) { 54b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IBufferQueue *bufferQueue; 55b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten const struct BufferHeader *oldFront, *newFront, *rear; 56b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned actual = desired; 57b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail < actual) 58b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten actual = track->mAvail; 59b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // force actual to be a frame multiple 60b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (actual > 0) { 61b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME check for either mute or volume 0 62b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // in which case skip the input buffer processing 63b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(NULL != track->mReader); 64b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME && gain == 1.0 65b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (mixBufferHasData) { 66b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten stereo *mixBuffer = (stereo *) dstWriter; 67b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten const stereo *source = (const stereo *) track->mReader; 68b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned j; 69b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, 70b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten ++source) { 71b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // apply gain here 72b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBuffer->left += source->left; 73b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBuffer->right += source->right; 74b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 75b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } else { 76daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // apply gain during copy 77b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memcpy(dstWriter, track->mReader, actual); 78b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten trackContributedToMix = SL_BOOLEAN_TRUE; 79b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 80b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten dstWriter = (char *) dstWriter + actual; 81b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten desired -= actual; 82b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mReader = (char *) track->mReader + actual; 83b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mAvail -= actual; 84b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail == 0) { 85b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten bufferQueue = track->mBufferQueue; 86b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != bufferQueue) { 87b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten oldFront = bufferQueue->mFront; 88b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten rear = bufferQueue->mRear; 89b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(oldFront != rear); 90b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten newFront = oldFront; 91daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers]) 92b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten newFront = bufferQueue->mArray; 93b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten bufferQueue->mFront = (struct BufferHeader *) newFront; 94b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(0 < bufferQueue->mState.count); 95b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten --bufferQueue->mState.count; 96b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME here or in Enqueue? 97b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten ++bufferQueue->mState.playIndex; 98b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME a good time to do an early warning 99b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // callback depending on buffer count 100b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 101b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 102b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 103b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 104b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // actual == 0 105b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten bufferQueue = track->mBufferQueue; 106b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != bufferQueue) { 107b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten oldFront = bufferQueue->mFront; 108b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten rear = bufferQueue->mRear; 109b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (oldFront != rear) { 110b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastengot_one: 111b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(0 < bufferQueue->mState.count); 112b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mReader = oldFront->mBuffer; 113b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mAvail = oldFront->mSize; 114b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 115b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 116b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME should be able to configure when to 117b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // kick off the callback e.g. high/low water-marks etc. 118b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // need data but none available, attempt a desperate callback 119b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten slBufferQueueCallback callback = bufferQueue->mCallback; 120b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != callback) { 121daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten (*callback)((SLBufferQueueItf) bufferQueue, bufferQueue->mContext); 122b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // if lucky, the callback enqueued a buffer 123b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (rear != bufferQueue->mRear) 124b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten goto got_one; 125b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // unlucky, queue still empty, the callback failed 126b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 127b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // here on underflow due to no callback, or failed callback 128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME underflow, send silence (or previous buffer?) 129b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // we did a callback to try to kick start again but failed 130b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // should log this 131b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 132b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // no buffer queue or underflow, clear out rest of partial buffer 133b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!mixBufferHasData && trackContributedToMix) 134b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(dstWriter, 0, actual); 135b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 136b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 137b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (trackContributedToMix) 138b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBufferHasData = SL_BOOLEAN_TRUE; 139b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 140b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // No active tracks, so output silence 141b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!mixBufferHasData) 142b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(pBuffer, 0, size); 143b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 144b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 145b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = { 146b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt_FillBuffer 147b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}; 148b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 149b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenvoid IOutputMixExt_init(void *self) 150b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 151b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt *this = (IOutputMixExt *) self; 152b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten this->mItf = &IOutputMixExt_Itf; 153b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 154b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 155acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *this) 156daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{ 157acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten //const SLDataSource *pAudioSrc = &this->mDataSource.u.mSource; 158acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten const SLDataSink *pAudioSnk = &this->mDataSink.u.mSink; 159daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten struct Track *track = NULL; 160daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten switch (*(SLuint32 *)pAudioSnk->pLocator) { 161daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten case SL_DATALOCATOR_OUTPUTMIX: 162daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten { 163daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // pAudioSnk->pFormat is ignored 164daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten IOutputMix *om = &((COutputMix *) ((SLDataLocator_OutputMix *) pAudioSnk->pLocator)->outputMix)->mOutputMix; 165daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // allocate an entry within OutputMix for this track 166daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // FIXME O(n) 167daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten unsigned i; 168daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten for (i = 0, track = &om->mTracks[0]; i < 32; ++i, ++track) { 169daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten if (om->mActiveMask & (1 << i)) 170daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten continue; 171daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten om->mActiveMask |= 1 << i; 172daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 173daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 174daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten if (32 <= i) { 175daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // FIXME Need a better error code for all slots full in output mix 176daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_MEMORY_FAILURE; 177daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 178daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 179daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 180daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten default: 181daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 182daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 183daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 184acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mBufferQueue = &this->mBufferQueue; 185acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mPlay = &this->mPlay; 186acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten // next 2 fields must be initialized explicitly (not part of this) 187acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mReader = NULL; 188acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mAvail = 0; 189daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_SUCCESS; 190daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten} 191daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 192b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif // USE_OUTPUTMIXEXT 193