IOutputMixExt.c revision 18abcc4b70fab1f84d6fbebac3a8e34480a6c4d3
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
354b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten/** Check whether a track has any data for us to read. */
364b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
37369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kastenstatic SLboolean track_check(Track *track)
384b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten{
394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    SLboolean trackHasData = SL_BOOLEAN_FALSE;
404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
414b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    CAudioPlayer *audioPlayer = track->mAudioPlayer;
424b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    if (NULL != audioPlayer) {
434b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // track is initialized
454b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
464b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        object_lock_exclusive(&audioPlayer->mObject);
474b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
484b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        SLboolean doBroadcast = SL_BOOLEAN_FALSE;
494b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        const BufferHeader *oldFront;
504b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
514b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        if (audioPlayer->mBufferQueue.mClearRequested) {
524b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // application thread(s) that call BufferQueue::Clear while mixer is active
534b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // is active will block synchronously until mixer acknowledges the Clear request
544b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mBufferQueue.mFront = &audioPlayer->mBufferQueue.mArray[0];
554b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mBufferQueue.mRear = &audioPlayer->mBufferQueue.mArray[0];
564b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mBufferQueue.mState.count = 0;
574b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mBufferQueue.mClearRequested = SL_BOOLEAN_FALSE;
584b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            track->mReader = NULL;
594b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            track->mAvail = 0;
604b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            doBroadcast = SL_BOOLEAN_TRUE;
614b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        }
624b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
634b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        switch (audioPlayer->mPlay.mState) {
644b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
654b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_PLAYING:  // continue playing current track data
664b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            if (0 < track->mAvail) {
674b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                trackHasData = SL_BOOLEAN_TRUE;
684b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                break;
694b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            }
704b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
714b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // try to get another buffer from queue
724b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            oldFront = audioPlayer->mBufferQueue.mFront;
734b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            if (oldFront != audioPlayer->mBufferQueue.mRear) {
744b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                assert(0 < audioPlayer->mBufferQueue.mState.count);
754b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                track->mReader = oldFront->mBuffer;
764b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                track->mAvail = oldFront->mSize;
774b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // note that the buffer stays on the queue while we are reading
784b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                audioPlayer->mPlay.mState = SL_PLAYSTATE_PLAYING;
794b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                trackHasData = SL_BOOLEAN_TRUE;
804b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            } else {
814b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // no buffers on queue, so playable but not playing
824b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // NTH should be able to call a desperation callback when completely starved,
834b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // or call less often than every buffer based on high/low water-marks
844b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            }
854b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
864b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
874b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_STOPPING: // application thread(s) called Play::SetPlayState(STOPPED)
884b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mPlay.mPosition = (SLmillisecond) 0;
894b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mPlay.mState = SL_PLAYSTATE_STOPPED;
904b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            oldFront = audioPlayer->mBufferQueue.mFront;
914b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            if (oldFront != audioPlayer->mBufferQueue.mRear) {
924b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                assert(0 < audioPlayer->mBufferQueue.mState.count);
934b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                track->mReader = oldFront->mBuffer;
944b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                track->mAvail = oldFront->mSize;
954b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            }
964b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            doBroadcast = SL_BOOLEAN_TRUE;
974b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
984b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
994b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_STOPPED:  // idle
1004b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_PAUSED:   // idle
1014b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1024b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        default:
1044b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            assert(SL_BOOLEAN_FALSE);
1054b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1064b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        }
1074b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1084b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        if (doBroadcast)
1094b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            object_cond_broadcast(&audioPlayer->mObject);
1104b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        object_unlock_exclusive(&audioPlayer->mObject);
1124b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    }
1144b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1154b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    return trackHasData;
1164b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1174b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten}
1184b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
119b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic void IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size)
120b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
121ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE_VOID
122ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
123b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // Force to be a multiple of a frame, assumes stereo 16-bit PCM
124b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    size &= ~3;
125daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    IOutputMixExt *thisExt = (IOutputMixExt *) self;
126d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    IOutputMix *this = &((COutputMix *) InterfaceToIObject(thisExt))->mOutputMix;
127b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    unsigned activeMask = this->mActiveMask;
128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    SLboolean mixBufferHasData = SL_BOOLEAN_FALSE;
129d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    while (activeMask) {
130d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        unsigned i = ctz(activeMask);
131d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        assert(MAX_TRACK > i);
132d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        activeMask &= ~(1 << i);
133369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten        Track *track = &this->mTracks[i];
1344b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
135b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        // track is allocated
1364b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1374b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        if (!track_check(track))
138b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            continue;
1394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
140b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        // track is playing
141b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        void *dstWriter = pBuffer;
142b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        unsigned desired = size;
143b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        SLboolean trackContributedToMix = SL_BOOLEAN_FALSE;
144e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        float gains[STEREO_CHANNELS];
145e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        Summary summaries[STEREO_CHANNELS];
146e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        unsigned channel;
147e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        for (channel = 0; channel < STEREO_CHANNELS; ++channel) {
148e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            float gain = track->mGains[channel];
149e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            gains[channel] = gain;
150e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            Summary summary;
151e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            if (gain <= 0.001)
152e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                summary = GAIN_MUTE;
153e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            else if (gain >= 0.999)
154e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                summary = GAIN_UNITY;
155e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            else
156e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                summary = GAIN_OTHER;
157e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            summaries[channel] = summary;
1586a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten        }
159b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        while (desired > 0) {
160b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            unsigned actual = desired;
161b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (track->mAvail < actual)
162b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                actual = track->mAvail;
163b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            // force actual to be a frame multiple
164b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (actual > 0) {
165b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                assert(NULL != track->mReader);
166276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                stereo *mixBuffer = (stereo *) dstWriter;
167276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                const stereo *source = (const stereo *) track->mReader;
168276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                unsigned j;
169e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                if (GAIN_MUTE != summaries[0] || GAIN_MUTE != summaries[1]) {
17040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                    if (mixBufferHasData) {
17140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        // apply gain during add
172e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) {
17340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
174e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                                mixBuffer->left += (short) (source->left * track->mGains[0]);
175e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                                mixBuffer->right += (short) (source->right * track->mGains[1]);
17640d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            }
17740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        // no gain adjustment needed, so do a simple add
17840d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        } else {
17940d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
18040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                                mixBuffer->left += source->left;
18140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                                mixBuffer->right += source->right;
18240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            }
18340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        }
18440d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                    } else {
18540d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        // apply gain during copy
186e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) {
18740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
188e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                                mixBuffer->left = (short) (source->left * track->mGains[0]);
189e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                                mixBuffer->right = (short) (source->right * track->mGains[1]);
19040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            }
19140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        // no gain adjustment needed, so do a simple copy
19240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        } else {
19340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            memcpy(dstWriter, track->mReader, actual);
19440d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        }
195276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                    }
196b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    trackContributedToMix = SL_BOOLEAN_TRUE;
197b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
198b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                dstWriter = (char *) dstWriter + actual;
199b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                desired -= actual;
200b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                track->mReader = (char *) track->mReader + actual;
201b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                track->mAvail -= actual;
202b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                if (track->mAvail == 0) {
2034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    IBufferQueue *bufferQueue = &track->mAudioPlayer->mBufferQueue;
2044b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    interface_lock_exclusive(bufferQueue);
2054b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    const BufferHeader *oldFront, *newFront, *rear;
2064b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    oldFront = bufferQueue->mFront;
2074b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    rear = bufferQueue->mRear;
2084b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    // a buffer stays on queue while playing, so it better still be there
2094b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    assert(oldFront != rear);
2104b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    newFront = oldFront;
2114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1])
2124b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        newFront = bufferQueue->mArray;
2134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    bufferQueue->mFront = (BufferHeader *) newFront;
2144b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    assert(0 < bufferQueue->mState.count);
2154b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    --bufferQueue->mState.count;
2164b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    if (newFront != rear) {
2174b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        // we don't acknowledge application requests between buffers
2184b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        // within the same mixer frame
219b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        assert(0 < bufferQueue->mState.count);
2204b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        track->mReader = newFront->mBuffer;
2214b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        track->mAvail = newFront->mSize;
2224b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    }
2234b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    // else we would set play state to playable but not playing during next mixer
2244b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    // frame if the queue is still empty at that time
2254b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    ++bufferQueue->mState.playIndex;
2264b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    slBufferQueueCallback callback = bufferQueue->mCallback;
2274b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    void *context = bufferQueue->mContext;
2284b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    interface_unlock_exclusive(bufferQueue);
2294b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    // The callback function is called on each buffer completion
2304b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    if (NULL != callback) {
2314b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        (*callback)((SLBufferQueueItf) bufferQueue, context);
2324b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        // Maybe it enqueued another buffer, or maybe it didn't.
2334b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        // We will find out later during the next mixer frame.
234b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    }
235b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
236e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                // no lock, but safe b/c noone else updates this field
237e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                track->mFrameCounter += actual >> 2;    // sizeof(short) * STEREO_CHANNELS
2387a79f519d89eb0e1a5b3f4005484b16d6854d7e2Glenn Kasten                // NTH Calling the callback too often, should depend on requested update period
2394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // FIXME need a lock to get these pointers, and called too often
2404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                if (track->mAudioPlayer->mPlay.mCallback)
2414b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    (*track->mAudioPlayer->mPlay.mCallback)(&track->mAudioPlayer->mPlay.mItf,
2424b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        track->mAudioPlayer->mPlay.mContext, SL_PLAYEVENT_HEADMOVING);
243b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                continue;
244b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            }
2454b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // we need more data: desired > 0 but actual == 0
2464b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            if (track_check(track))
2474b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                continue;
2484b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // underflow: clear out rest of partial buffer (NTH synthesize comfort noise)
249b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (!mixBufferHasData && trackContributedToMix)
250b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                memset(dstWriter, 0, actual);
251b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            break;
252b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        }
253b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        if (trackContributedToMix)
254b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            mixBufferHasData = SL_BOOLEAN_TRUE;
255b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
256b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // No active tracks, so output silence
257b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    if (!mixBufferHasData)
258b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        memset(pBuffer, 0, size);
259ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
260ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE_VOID
261b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
262b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
263ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
264b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = {
265b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    IOutputMixExt_FillBuffer
266b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten};
267b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
268b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenvoid IOutputMixExt_init(void *self)
269b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
270b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    IOutputMixExt *this = (IOutputMixExt *) self;
271b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    this->mItf = &IOutputMixExt_Itf;
272b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
273b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
274acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *this)
275daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{
276e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    this->mTrack = NULL;
277acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    const SLDataSink *pAudioSnk = &this->mDataSink.u.mSink;
278369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten    Track *track = NULL;
279daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    switch (*(SLuint32 *)pAudioSnk->pLocator) {
280daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    case SL_DATALOCATOR_OUTPUTMIX:
281daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        {
282daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        // pAudioSnk->pFormat is ignored
283e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        IOutputMix *om = &((COutputMix *) ((SLDataLocator_OutputMix *)
284e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            pAudioSnk->pLocator)->outputMix)->mOutputMix;
285daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        // allocate an entry within OutputMix for this track
286d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        interface_lock_exclusive(om);
287d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        unsigned availMask = ~om->mActiveMask;
288d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        if (!availMask) {
289d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten            interface_unlock_exclusive(om);
290d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten            // All track slots full in output mix
291daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            return SL_RESULT_MEMORY_FAILURE;
292daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
293d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        unsigned i = ctz(availMask);
294d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        assert(MAX_TRACK > i);
295d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        om->mActiveMask |= 1 << i;
296d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        track = &om->mTracks[i];
297276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        track->mAudioPlayer = NULL;    // only field that is accessed before full initialization
298d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        interface_unlock_exclusive(om);
299e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        this->mTrack = track;
300daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
301daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        break;
302daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    default:
303daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        return SL_RESULT_CONTENT_UNSUPPORTED;
304daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    }
305daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten
306d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    // FIXME Wrong place for this initialization; should first pre-allocate a track slot
307d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    // using OutputMixExt.mTrackCount, then initialize full audio player, then do track bit
308d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    // allocation, initialize rest of track, and doubly-link track to player (currently single).
309d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    assert(NULL != track);
310acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mBufferQueue = &this->mBufferQueue;
311276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten    track->mAudioPlayer = this;
312acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mReader = NULL;
313acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mAvail = 0;
314e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    track->mGains[0] = 1.0f;
315e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    track->mGains[1] = 1.0f;
316e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    track->mFrameCounter = 0;
317daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    return SL_RESULT_SUCCESS;
318daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten}
319daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten
320e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kastenvoid audioPlayerGainUpdate(CAudioPlayer *audioPlayer)
321e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten{
322e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    // FIXME need a lock on the track while updating gain
323369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten    Track *track = audioPlayer->mTrack;
324e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten
325e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    if (NULL == track)
326e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        return;
327e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten
328e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLboolean mute = audioPlayer->mVolume.mMute;
329b91e32605ecf39e34ad39936b1ee193bb4e30225Glenn Kasten    SLuint8 muteMask = audioPlayer->mMuteMask;
330b91e32605ecf39e34ad39936b1ee193bb4e30225Glenn Kasten    SLuint8 soloMask = audioPlayer->mSoloMask;
331e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLmillibel level = audioPlayer->mVolume.mLevel;
332e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLboolean enableStereoPosition = audioPlayer->mVolume.mEnableStereoPosition;
333e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLpermille stereoPosition = audioPlayer->mVolume.mStereoPosition;
334e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten
335e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    if (soloMask)
336e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        muteMask |= ~soloMask;
337e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    if (mute || !(~muteMask & 3)) {
33818abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten        track->mGains[0] = 0.0f;
33918abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten        track->mGains[1] = 0.0f;
340e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    } else {
34118abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten        float playerGain = powf(10.0f, level / 2000.0f);
342e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        unsigned channel;
343e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        for (channel = 0; channel < STEREO_CHANNELS; ++channel) {
344e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            float gain;
345e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            if (muteMask & (1 << channel))
34618abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten                gain = 0.0f;
347e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            else {
348e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                gain = playerGain;
349e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                if (enableStereoPosition) {
350e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                    switch (channel) {
351e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                    case 0:
352e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        if (stereoPosition > 0)
35318abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten                            gain *= (1000 - stereoPosition) / 1000.0f;
354e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        break;
355e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                    case 1:
356e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        if (stereoPosition < 0)
35718abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten                            gain *= (1000 + stereoPosition) / 1000.0f;
358e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        break;
359e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                    default:
360e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        assert(SL_BOOLEAN_FALSE);
361e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        break;
362e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                    }
363e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                }
364e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            }
365e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            track->mGains[channel] = gain;
366e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        }
367e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    }
368e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten}
369e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten
370b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif // USE_OUTPUTMIXEXT
371