IOutputMixExt.cpp revision b7154f2324c8ae44b820c07c69aaa80a4bb9e418
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; 29b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt *thisExt = 30b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten (IOutputMixExt *) self; 31b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME Finding one interface from another, but is it exposed? 32b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMix *this = 33b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten &((COutputMix *) thisExt->mThis)->mOutputMix; 34b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned activeMask = this->mActiveMask; 35b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten struct Track *track = &this->mTracks[0]; 36b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned i; 37b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean mixBufferHasData = SL_BOOLEAN_FALSE; 38b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME O(32) loop even when few tracks are active. 39b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // To avoid loop, use activeMask to check for active track(s) 40b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // and decide whether we actually need to copy or mix. 41b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten for (i = 0; 0 != activeMask; ++i, ++track, activeMask >>= 1) { 42b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(i < 32); 43b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!(activeMask & 1)) 44b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 45b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is allocated 46b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IPlay *play = track->mPlay; 47b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL == play) 48b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 49b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is initialized 50b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (SL_PLAYSTATE_PLAYING != play->mState) 51b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 52b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is playing 53b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten void *dstWriter = pBuffer; 54b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned desired = size; 55b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean trackContributedToMix = SL_BOOLEAN_FALSE; 56b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten while (desired > 0) { 57b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IBufferQueue *bufferQueue; 58b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten const struct BufferHeader *oldFront, *newFront, *rear; 59b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned actual = desired; 60b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail < actual) 61b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten actual = track->mAvail; 62b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // force actual to be a frame multiple 63b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (actual > 0) { 64b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME check for either mute or volume 0 65b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // in which case skip the input buffer processing 66b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(NULL != track->mReader); 67b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME && gain == 1.0 68b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (mixBufferHasData) { 69b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten stereo *mixBuffer = (stereo *) dstWriter; 70b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten const stereo *source = (const stereo *) track->mReader; 71b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned j; 72b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, 73b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten ++source) { 74b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // apply gain here 75b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBuffer->left += source->left; 76b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBuffer->right += source->right; 77b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 78b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } else { 79b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memcpy(dstWriter, track->mReader, actual); 80b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten trackContributedToMix = SL_BOOLEAN_TRUE; 81b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 82b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten dstWriter = (char *) dstWriter + actual; 83b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten desired -= actual; 84b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mReader = (char *) track->mReader + actual; 85b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mAvail -= actual; 86b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail == 0) { 87b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten bufferQueue = track->mBufferQueue; 88b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != bufferQueue) { 89b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten oldFront = bufferQueue->mFront; 90b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten rear = bufferQueue->mRear; 91b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(oldFront != rear); 92b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten newFront = oldFront; 93b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (++newFront == 94b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten &bufferQueue->mArray[bufferQueue->mNumBuffers]) 95b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten newFront = bufferQueue->mArray; 96b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten bufferQueue->mFront = (struct BufferHeader *) newFront; 97b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(0 < bufferQueue->mState.count); 98b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten --bufferQueue->mState.count; 99b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME here or in Enqueue? 100b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten ++bufferQueue->mState.playIndex; 101b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME a good time to do an early warning 102b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // callback depending on buffer count 103b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 104b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 105b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 106b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 107b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // actual == 0 108b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten bufferQueue = track->mBufferQueue; 109b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != bufferQueue) { 110b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten oldFront = bufferQueue->mFront; 111b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten rear = bufferQueue->mRear; 112b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (oldFront != rear) { 113b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastengot_one: 114b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(0 < bufferQueue->mState.count); 115b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mReader = oldFront->mBuffer; 116b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mAvail = oldFront->mSize; 117b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 118b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 119b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME should be able to configure when to 120b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // kick off the callback e.g. high/low water-marks etc. 121b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // need data but none available, attempt a desperate callback 122b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten slBufferQueueCallback callback = bufferQueue->mCallback; 123b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != callback) { 124b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten (*callback)((SLBufferQueueItf) bufferQueue, 125b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten bufferQueue->mContext); 126b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // if lucky, the callback enqueued a buffer 127b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (rear != bufferQueue->mRear) 128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten goto got_one; 129b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // unlucky, queue still empty, the callback failed 130b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 131b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // here on underflow due to no callback, or failed callback 132b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME underflow, send silence (or previous buffer?) 133b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // we did a callback to try to kick start again but failed 134b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // should log this 135b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 136b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // no buffer queue or underflow, clear out rest of partial buffer 137b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!mixBufferHasData && trackContributedToMix) 138b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(dstWriter, 0, actual); 139b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 140b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 141b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (trackContributedToMix) 142b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBufferHasData = SL_BOOLEAN_TRUE; 143b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 144b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // No active tracks, so output silence 145b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!mixBufferHasData) 146b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(pBuffer, 0, size); 147b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 148b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 149b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = { 150b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt_FillBuffer 151b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}; 152b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 153b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenvoid IOutputMixExt_init(void *self) 154b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 155b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt *this = (IOutputMixExt *) self; 156b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten this->mItf = &IOutputMixExt_Itf; 157b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 158b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 159b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif // USE_OUTPUTMIXEXT 160