IOutputMixExt.c revision e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037
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 34b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic void IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size) 35b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 36b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // Force to be a multiple of a frame, assumes stereo 16-bit PCM 37b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten size &= ~3; 38daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten IOutputMixExt *thisExt = (IOutputMixExt *) self; 39d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten IOutputMix *this = &((COutputMix *) InterfaceToIObject(thisExt))->mOutputMix; 40b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned activeMask = this->mActiveMask; 41b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean mixBufferHasData = SL_BOOLEAN_FALSE; 42d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten while (activeMask) { 43d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned i = ctz(activeMask); 44d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(MAX_TRACK > i); 45d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten activeMask &= ~(1 << i); 46d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten struct Track *track = &this->mTracks[i]; 47b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is allocated 48276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten CAudioPlayer *audioPlayer = track->mAudioPlayer; 49276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten if (NULL == audioPlayer) 50b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 51b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is initialized 52276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten if (SL_PLAYSTATE_PLAYING != audioPlayer->mPlay.mState) 53b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 54b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // track is playing 55b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten void *dstWriter = pBuffer; 56b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned desired = size; 57b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten SLboolean trackContributedToMix = SL_BOOLEAN_FALSE; 583a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten IBufferQueue *bufferQueue = track->mBufferQueue; 59e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten float gains[STEREO_CHANNELS]; 60e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten Summary summaries[STEREO_CHANNELS]; 61e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten unsigned channel; 62e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten for (channel = 0; channel < STEREO_CHANNELS; ++channel) { 63e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten float gain = track->mGains[channel]; 64e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten gains[channel] = gain; 65e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten Summary summary; 66e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (gain <= 0.001) 67e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summary = GAIN_MUTE; 68e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten else if (gain >= 0.999) 69e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summary = GAIN_UNITY; 70e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten else 71e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summary = GAIN_OTHER; 72e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten summaries[channel] = summary; 736a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten } 74b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten while (desired > 0) { 75d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten const BufferHeader *oldFront, *newFront, *rear; 76b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten unsigned actual = desired; 77b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail < actual) 78b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten actual = track->mAvail; 79b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // force actual to be a frame multiple 80b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (actual > 0) { 81b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(NULL != track->mReader); 82276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten stereo *mixBuffer = (stereo *) dstWriter; 83276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten const stereo *source = (const stereo *) track->mReader; 84276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten unsigned j; 85e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (GAIN_MUTE != summaries[0] || GAIN_MUTE != summaries[1]) { 8640d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten if (mixBufferHasData) { 8740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // apply gain during add 88e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) { 8940d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 90e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->left += (short) (source->left * track->mGains[0]); 91e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->right += (short) (source->right * track->mGains[1]); 9240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 9340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // no gain adjustment needed, so do a simple add 9440d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } else { 9540d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 9640d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten mixBuffer->left += source->left; 9740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten mixBuffer->right += source->right; 9840d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 9940d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 10040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } else { 10140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // apply gain during copy 102e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) { 10340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) { 104e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->left = (short) (source->left * track->mGains[0]); 105e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten mixBuffer->right = (short) (source->right * track->mGains[1]); 10640d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 10740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // no gain adjustment needed, so do a simple copy 10840d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } else { 10940d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten memcpy(dstWriter, track->mReader, actual); 11040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten } 111276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten } 112b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten trackContributedToMix = SL_BOOLEAN_TRUE; 113b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 114b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten dstWriter = (char *) dstWriter + actual; 115b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten desired -= actual; 116b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mReader = (char *) track->mReader + actual; 117b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mAvail -= actual; 118b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (track->mAvail == 0) { 119b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != bufferQueue) { 1203a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_lock_exclusive(bufferQueue); 121b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten oldFront = bufferQueue->mFront; 122b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten rear = bufferQueue->mRear; 123b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(oldFront != rear); 124b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten newFront = oldFront; 125d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1]) 126b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten newFront = bufferQueue->mArray; 127d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten bufferQueue->mFront = (BufferHeader *) newFront; 128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(0 < bufferQueue->mState.count); 129b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten --bufferQueue->mState.count; 130b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten ++bufferQueue->mState.playIndex; 1313a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_unlock_exclusive(bufferQueue); 13240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten // A good place to do an early warning callback depending on buffer count 133b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 134b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 135e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten // no lock, but safe b/c noone else updates this field 136e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mFrameCounter += actual >> 2; // sizeof(short) * STEREO_CHANNELS 137e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten // FIXME Calling the callback too often, should depend on requested update period 138e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (audioPlayer->mPlay.mCallback) 139e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten (*audioPlayer->mPlay.mCallback)(&audioPlayer->mPlay.mItf, 140e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten audioPlayer->mPlay.mContext, SL_PLAYEVENT_HEADMOVING); 141b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 142b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 143b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // actual == 0 144b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != bufferQueue) { 1453a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_lock_shared(bufferQueue); 146b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten oldFront = bufferQueue->mFront; 147b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten rear = bufferQueue->mRear; 148b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (oldFront != rear) { 149b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastengot_one: 150b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten assert(0 < bufferQueue->mState.count); 151b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mReader = oldFront->mBuffer; 152b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten track->mAvail = oldFront->mSize; 1533a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_unlock_shared(bufferQueue); 154b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten continue; 155b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 156b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME should be able to configure when to 157b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // kick off the callback e.g. high/low water-marks etc. 158b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // need data but none available, attempt a desperate callback 159b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten slBufferQueueCallback callback = bufferQueue->mCallback; 1603a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten void *context = bufferQueue->mContext; 1613a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_unlock_shared(bufferQueue); 162b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (NULL != callback) { 1633a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten (*callback)((SLBufferQueueItf) bufferQueue, context); 164b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // if lucky, the callback enqueued a buffer 1653a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_lock_shared(bufferQueue); 166b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (rear != bufferQueue->mRear) 167b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten goto got_one; 1683a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten interface_unlock_shared(bufferQueue); 169b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // unlucky, queue still empty, the callback failed 170b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 171b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // here on underflow due to no callback, or failed callback 172b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // FIXME underflow, send silence (or previous buffer?) 173b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // we did a callback to try to kick start again but failed 174b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // should log this 175b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 176b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // no buffer queue or underflow, clear out rest of partial buffer 177b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!mixBufferHasData && trackContributedToMix) 178b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(dstWriter, 0, actual); 179b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten break; 180b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 181b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (trackContributedToMix) 182b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten mixBufferHasData = SL_BOOLEAN_TRUE; 183b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten } 184b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten // No active tracks, so output silence 185b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten if (!mixBufferHasData) 186b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten memset(pBuffer, 0, size); 187b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 188b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 189b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = { 190b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt_FillBuffer 191b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}; 192b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 193b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenvoid IOutputMixExt_init(void *self) 194b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{ 195b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten IOutputMixExt *this = (IOutputMixExt *) self; 196b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten this->mItf = &IOutputMixExt_Itf; 197b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten} 198b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten 199acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *this) 200daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{ 201e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten this->mTrack = NULL; 202acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten const SLDataSink *pAudioSnk = &this->mDataSink.u.mSink; 203daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten struct Track *track = NULL; 204daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten switch (*(SLuint32 *)pAudioSnk->pLocator) { 205daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten case SL_DATALOCATOR_OUTPUTMIX: 206daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten { 207daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // pAudioSnk->pFormat is ignored 208e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten IOutputMix *om = &((COutputMix *) ((SLDataLocator_OutputMix *) 209e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten pAudioSnk->pLocator)->outputMix)->mOutputMix; 210daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten // allocate an entry within OutputMix for this track 211d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten interface_lock_exclusive(om); 212d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned availMask = ~om->mActiveMask; 213d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten if (!availMask) { 214d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten interface_unlock_exclusive(om); 215d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // All track slots full in output mix 216daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_MEMORY_FAILURE; 217daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 218d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten unsigned i = ctz(availMask); 219d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(MAX_TRACK > i); 220d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten om->mActiveMask |= 1 << i; 221d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten track = &om->mTracks[i]; 222276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten track->mAudioPlayer = NULL; // only field that is accessed before full initialization 223d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten interface_unlock_exclusive(om); 224e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten this->mTrack = track; 225daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 226daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten break; 227daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten default: 228daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_CONTENT_UNSUPPORTED; 229daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten } 230daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 231d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // FIXME Wrong place for this initialization; should first pre-allocate a track slot 232d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // using OutputMixExt.mTrackCount, then initialize full audio player, then do track bit 233d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten // allocation, initialize rest of track, and doubly-link track to player (currently single). 234d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten assert(NULL != track); 235acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mBufferQueue = &this->mBufferQueue; 236276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten track->mAudioPlayer = this; 237acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mReader = NULL; 238acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten track->mAvail = 0; 239e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mGains[0] = 1.0f; 240e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mGains[1] = 1.0f; 241e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mFrameCounter = 0; 242daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten return SL_RESULT_SUCCESS; 243daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten} 244daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten 245e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kastenvoid audioPlayerGainUpdate(CAudioPlayer *audioPlayer) 246e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten{ 247e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten // FIXME need a lock on the track while updating gain 248e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten struct Track *track = audioPlayer->mTrack; 249e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 250e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (NULL == track) 251e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten return; 252e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 253e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLboolean mute = audioPlayer->mVolume.mMute; 254e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLuint8 muteMask = audioPlayer->mMuteSolo.mMuteMask; 255e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLuint8 soloMask = audioPlayer->mMuteSolo.mSoloMask; 256e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLmillibel level = audioPlayer->mVolume.mLevel; 257e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLboolean enableStereoPosition = audioPlayer->mVolume.mEnableStereoPosition; 258e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten SLpermille stereoPosition = audioPlayer->mVolume.mStereoPosition; 259e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 260e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (soloMask) 261e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten muteMask |= ~soloMask; 262e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (mute || !(~muteMask & 3)) { 263e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mGains[0] = 0.0; 264e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mGains[1] = 0.0; 265e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } else { 266e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten float playerGain = pow(10.0, level / 2000.0); 267e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten unsigned channel; 268e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten for (channel = 0; channel < STEREO_CHANNELS; ++channel) { 269e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten float gain; 270e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (muteMask & (1 << channel)) 271e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten gain = 0.0; 272e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten else { 273e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten gain = playerGain; 274e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (enableStereoPosition) { 275e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten switch (channel) { 276e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten case 0: 277e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (stereoPosition > 0) 278e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten gain *= (1000 - stereoPosition) / 1000.0; 279e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten break; 280e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten case 1: 281e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten if (stereoPosition < 0) 282e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten gain *= (1000 + stereoPosition) / 1000.0; 283e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten break; 284e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten default: 285e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten assert(SL_BOOLEAN_FALSE); 286e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten break; 287e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 288e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 289e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 290e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten track->mGains[channel] = gain; 291e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 292e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten } 293e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten} 294e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten 295b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif // USE_OUTPUTMIXEXT 296