IOutputMixExt.cpp revision 6a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18c
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
23276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten#include <math.h>
24276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten
25b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten// Used by SDL but not specific to or dependent on SDL
26b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
27b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic void IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size)
28b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
29b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // Force to be a multiple of a frame, assumes stereo 16-bit PCM
30b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    size &= ~3;
31daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    IOutputMixExt *thisExt = (IOutputMixExt *) self;
32d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    IOutputMix *this = &((COutputMix *) InterfaceToIObject(thisExt))->mOutputMix;
33b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    unsigned activeMask = this->mActiveMask;
34b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    SLboolean mixBufferHasData = SL_BOOLEAN_FALSE;
35d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    while (activeMask) {
36d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        unsigned i = ctz(activeMask);
37d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        assert(MAX_TRACK > i);
38d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        activeMask &= ~(1 << i);
39d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        struct Track *track = &this->mTracks[i];
40b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        // track is allocated
41276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        CAudioPlayer *audioPlayer = track->mAudioPlayer;
42276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        if (NULL == audioPlayer)
43b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            continue;
44b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        // track is initialized
45276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        if (SL_PLAYSTATE_PLAYING != audioPlayer->mPlay.mState)
46b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            continue;
47b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        // track is playing
48b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        void *dstWriter = pBuffer;
49b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        unsigned desired = size;
50b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        SLboolean trackContributedToMix = SL_BOOLEAN_FALSE;
513a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten        IBufferQueue *bufferQueue = track->mBufferQueue;
52276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        // should compute elsewhere
53276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        double gains[2];
546a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten        if (audioPlayer->mVolume.mMute || !(~audioPlayer->mMuteSolo.mMuteMask & 3)) {
556a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            gains[0] = 0.0;
566a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            gains[1] = 0.0;
576a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten        } else {
586a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            double playerVolume = pow(10.0, audioPlayer->mVolume.mLevel / 2000.0);
596a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            SLboolean enableStereoPosition = audioPlayer->mVolume.mEnableStereoPosition;
606a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            SLpermille stereoPosition = audioPlayer->mVolume.mStereoPosition;
616a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            if (audioPlayer->mMuteSolo.mMuteMask & 1)
626a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten                gains[0] = 0.0;
636a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            else {
646a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten                gains[0] = playerVolume;
656a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten                if (enableStereoPosition && stereoPosition < 0)
666a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten                    gains[0] *= -stereoPosition / 1000.0;
676a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            }
686a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            if (audioPlayer->mMuteSolo.mMuteMask & 2)
696a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten                gains[1] = 0.0;
706a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            else {
716a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten                gains[1] = playerVolume;
726a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten                if (enableStereoPosition && stereoPosition > 0)
736a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten                    gains[1] *= stereoPosition / 1000.0;
746a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten            }
756a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten        }
76b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        while (desired > 0) {
77d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten            const BufferHeader *oldFront, *newFront, *rear;
78b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            unsigned actual = desired;
79b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (track->mAvail < actual)
80b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                actual = track->mAvail;
81b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            // force actual to be a frame multiple
82b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (actual > 0) {
836a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten                // FIXME check for gain 0 in which case skip the input buffer processing
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;
88b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                if (mixBufferHasData) {
89276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                    for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
90276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                        mixBuffer->left += (short) (source->left * gains[0]);
91276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                        mixBuffer->right += (short) (source->right * gains[1]);
92b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    }
936a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten                } else if (gains[0] >= 0.999 && gains[1] >= 0.999) {
94276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                    // no gain adjustment needed, so do a simple copy
95276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                    memcpy(dstWriter, track->mReader, actual);
96276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                    trackContributedToMix = SL_BOOLEAN_TRUE;
97b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                } else {
98daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten                    // apply gain during copy
99276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                    for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
100276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                        mixBuffer->left = (short) (source->left * gains[0]);
101276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                        mixBuffer->right = (short) (source->right * gains[1]);
102276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                    }
103b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    trackContributedToMix = SL_BOOLEAN_TRUE;
104b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
105b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                dstWriter = (char *) dstWriter + actual;
106b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                desired -= actual;
107b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                track->mReader = (char *) track->mReader + actual;
108b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                track->mAvail -= actual;
109b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                if (track->mAvail == 0) {
110b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    if (NULL != bufferQueue) {
1113a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten                        interface_lock_exclusive(bufferQueue);
112b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        oldFront = bufferQueue->mFront;
113b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        rear = bufferQueue->mRear;
114b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        assert(oldFront != rear);
115b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        newFront = oldFront;
116d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                        if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1])
117b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                            newFront = bufferQueue->mArray;
118d2a7f0d6883a6d3835642e7b282f05ed1c54fe63Glenn Kasten                        bufferQueue->mFront = (BufferHeader *) newFront;
119b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        assert(0 < bufferQueue->mState.count);
120b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        --bufferQueue->mState.count;
121b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        // FIXME here or in Enqueue?
122b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        ++bufferQueue->mState.playIndex;
1233a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten                        interface_unlock_exclusive(bufferQueue);
124b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        // FIXME a good time to do an early warning
125b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        // callback depending on buffer count
126b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    }
127b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                continue;
129b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            }
130b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            // actual == 0
131b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (NULL != bufferQueue) {
1323a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten                interface_lock_shared(bufferQueue);
133b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                oldFront = bufferQueue->mFront;
134b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                rear = bufferQueue->mRear;
135b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                if (oldFront != rear) {
136b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastengot_one:
137b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    assert(0 < bufferQueue->mState.count);
138b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    track->mReader = oldFront->mBuffer;
139b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    track->mAvail = oldFront->mSize;
1403a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten                    interface_unlock_shared(bufferQueue);
141b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    continue;
142b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
143b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // FIXME should be able to configure when to
144b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // kick off the callback e.g. high/low water-marks etc.
145b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // need data but none available, attempt a desperate callback
146b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                slBufferQueueCallback callback = bufferQueue->mCallback;
1473a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten                void *context = bufferQueue->mContext;
1483a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten                interface_unlock_shared(bufferQueue);
149b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                if (NULL != callback) {
1503a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten                    (*callback)((SLBufferQueueItf) bufferQueue, context);
151b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    // if lucky, the callback enqueued a buffer
1523a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten                    interface_lock_shared(bufferQueue);
153b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    if (rear != bufferQueue->mRear)
154b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        goto got_one;
1553a413f1863daa026ed2b9fc9eac01e1341116cdbGlenn Kasten                    interface_unlock_shared(bufferQueue);
156b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    // unlucky, queue still empty, the callback failed
157b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
158b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // here on underflow due to no callback, or failed callback
159b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // FIXME underflow, send silence (or previous buffer?)
160b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // we did a callback to try to kick start again but failed
161b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // should log this
162b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            }
163b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            // no buffer queue or underflow, clear out rest of partial buffer
164b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (!mixBufferHasData && trackContributedToMix)
165b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                memset(dstWriter, 0, actual);
166b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            break;
167b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        }
168b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        if (trackContributedToMix)
169b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            mixBufferHasData = SL_BOOLEAN_TRUE;
170b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
171b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // No active tracks, so output silence
172b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    if (!mixBufferHasData)
173b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        memset(pBuffer, 0, size);
174b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
175b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
176b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = {
177b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    IOutputMixExt_FillBuffer
178b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten};
179b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
180b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenvoid IOutputMixExt_init(void *self)
181b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
182b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    IOutputMixExt *this = (IOutputMixExt *) self;
183b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    this->mItf = &IOutputMixExt_Itf;
184b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
185b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
186acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *this)
187daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{
188acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    const SLDataSink *pAudioSnk = &this->mDataSink.u.mSink;
189daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    struct Track *track = NULL;
190daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    switch (*(SLuint32 *)pAudioSnk->pLocator) {
191daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    case SL_DATALOCATOR_OUTPUTMIX:
192daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        {
193daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        // pAudioSnk->pFormat is ignored
194daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        IOutputMix *om = &((COutputMix *) ((SLDataLocator_OutputMix *) pAudioSnk->pLocator)->outputMix)->mOutputMix;
195daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        // allocate an entry within OutputMix for this track
196d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        interface_lock_exclusive(om);
197d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        unsigned availMask = ~om->mActiveMask;
198d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        if (!availMask) {
199d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten            interface_unlock_exclusive(om);
200d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten            // All track slots full in output mix
201daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            return SL_RESULT_MEMORY_FAILURE;
202daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
203d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        unsigned i = ctz(availMask);
204d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        assert(MAX_TRACK > i);
205d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        om->mActiveMask |= 1 << i;
206d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        track = &om->mTracks[i];
207276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        track->mAudioPlayer = NULL;    // only field that is accessed before full initialization
208d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        interface_unlock_exclusive(om);
209daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
210daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        break;
211daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    default:
212daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        return SL_RESULT_CONTENT_UNSUPPORTED;
213daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    }
214daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten
215d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    // FIXME Wrong place for this initialization; should first pre-allocate a track slot
216d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    // using OutputMixExt.mTrackCount, then initialize full audio player, then do track bit
217d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    // allocation, initialize rest of track, and doubly-link track to player (currently single).
218d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    assert(NULL != track);
219acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mBufferQueue = &this->mBufferQueue;
220276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    track->mAudioPlayer = this;
221acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mReader = NULL;
222acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mAvail = 0;
2236a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    //track->mGains[0] = 0;
2246a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten    //track->mGains[1] = 0;
225daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    return SL_RESULT_SUCCESS;
226daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten}
227daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten
228b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif // USE_OUTPUTMIXEXT
229