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