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