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
23928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten// OutputMixExt is used by SDL, but is not specific to or dependent on SDL
24b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
25a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
26a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten// stereo is a frame consisting of a pair of 16-bit PCM samples
27a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
28a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kastentypedef struct {
29a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    short left;
30a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten    short right;
31a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten} stereo;
32a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
33a3080daa505f91df51a808c85ddb37c48745bf7cGlenn Kasten
34343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten/** \brief Summary of the gain, as an optimization for the mixer */
35e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten
3640d1c40832a448e23d0bb37512aee53222575c2eGlenn Kastentypedef enum {
37e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    GAIN_MUTE  = 0,  // mValue == 0.0f within epsilon
38e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    GAIN_UNITY = 1,  // mValue == 1.0f within epsilon
39e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    GAIN_OTHER = 2   // 0.0f < mValue < 1.0f
4040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten} Summary;
4140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten
42ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
43343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten/** \brief Check whether a track has any data for us to read */
444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
45369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kastenstatic SLboolean track_check(Track *track)
464b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten{
47928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    assert(NULL != track);
484b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    SLboolean trackHasData = SL_BOOLEAN_FALSE;
494b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
504b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    CAudioPlayer *audioPlayer = track->mAudioPlayer;
514b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    if (NULL != audioPlayer) {
524b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
534b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        // track is initialized
544b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
55928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        // FIXME This lock could block and result in stuttering;
56928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        // a trylock with retry or lockless solution would be ideal
574b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        object_lock_exclusive(&audioPlayer->mObject);
58928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        assert(audioPlayer->mTrack == track);
594b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
608c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        SLuint32 framesMixed = track->mFramesMixed;
618c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (0 != framesMixed) {
628c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            track->mFramesMixed = 0;
638c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            audioPlayer->mPlay.mFramesSinceLastSeek += framesMixed;
648c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            audioPlayer->mPlay.mFramesSincePositionUpdate += framesMixed;
658c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
668c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten
674b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        SLboolean doBroadcast = SL_BOOLEAN_FALSE;
684b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        const BufferHeader *oldFront;
694b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
704b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        if (audioPlayer->mBufferQueue.mClearRequested) {
714b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // application thread(s) that call BufferQueue::Clear while mixer is active
72928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            // will block synchronously until mixer acknowledges the Clear request
734b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mBufferQueue.mFront = &audioPlayer->mBufferQueue.mArray[0];
744b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mBufferQueue.mRear = &audioPlayer->mBufferQueue.mArray[0];
754b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mBufferQueue.mState.count = 0;
764f064c143ef2b26347130a49788116b5d2e1252aGlenn Kasten            audioPlayer->mBufferQueue.mState.playIndex = 0;
774b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mBufferQueue.mClearRequested = SL_BOOLEAN_FALSE;
784b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            track->mReader = NULL;
794b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            track->mAvail = 0;
804b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            doBroadcast = SL_BOOLEAN_TRUE;
814b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        }
824b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
83928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        if (audioPlayer->mDestroyRequested) {
84928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            // an application thread that calls Object::Destroy while mixer is active will block
85928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            // synchronously in the PreDestroy hook until mixer acknowledges the Destroy request
86f51dba65751107c930759938775b75531ec1f330Glenn Kasten            COutputMix *outputMix = CAudioPlayer_GetOutputMix(audioPlayer);
87928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            unsigned i = track - outputMix->mOutputMixExt.mTracks;
88928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            assert( /* 0 <= i && */ i < MAX_TRACK);
89928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            unsigned mask = 1 << i;
90928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            track->mAudioPlayer = NULL;
91928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            assert(outputMix->mOutputMixExt.mActiveMask & mask);
92928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            outputMix->mOutputMixExt.mActiveMask &= ~mask;
93928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            audioPlayer->mTrack = NULL;
94928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            audioPlayer->mDestroyRequested = SL_BOOLEAN_FALSE;
95928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            doBroadcast = SL_BOOLEAN_TRUE;
96928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            goto broadcast;
97928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        }
98928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
994b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        switch (audioPlayer->mPlay.mState) {
1004b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1014b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_PLAYING:  // continue playing current track data
1024b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            if (0 < track->mAvail) {
1034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                trackHasData = SL_BOOLEAN_TRUE;
1044b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                break;
1054b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            }
1064b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1074b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // try to get another buffer from queue
1084b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            oldFront = audioPlayer->mBufferQueue.mFront;
1094b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            if (oldFront != audioPlayer->mBufferQueue.mRear) {
1104b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                assert(0 < audioPlayer->mBufferQueue.mState.count);
1114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                track->mReader = oldFront->mBuffer;
1124b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                track->mAvail = oldFront->mSize;
1134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // note that the buffer stays on the queue while we are reading
1144b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                audioPlayer->mPlay.mState = SL_PLAYSTATE_PLAYING;
1154b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                trackHasData = SL_BOOLEAN_TRUE;
1164b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            } else {
1174b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // no buffers on queue, so playable but not playing
1184b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // NTH should be able to call a desperation callback when completely starved,
1194b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                // or call less often than every buffer based on high/low water-marks
1204b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            }
121928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten
122928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            // copy gains from audio player to track
123928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            track->mGains[0] = audioPlayer->mGains[0];
124928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            track->mGains[1] = audioPlayer->mGains[1];
1254b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1264b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1274b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_STOPPING: // application thread(s) called Play::SetPlayState(STOPPED)
1284b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mPlay.mPosition = (SLmillisecond) 0;
1298c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            audioPlayer->mPlay.mFramesSinceLastSeek = 0;
1308c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            audioPlayer->mPlay.mFramesSincePositionUpdate = 0;
1318c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            audioPlayer->mPlay.mLastSeekPosition = 0;
1324b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            audioPlayer->mPlay.mState = SL_PLAYSTATE_STOPPED;
1338c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            // stop cancels a pending seek
1348c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN;
1354b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            oldFront = audioPlayer->mBufferQueue.mFront;
1364b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            if (oldFront != audioPlayer->mBufferQueue.mRear) {
1374b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                assert(0 < audioPlayer->mBufferQueue.mState.count);
1384b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                track->mReader = oldFront->mBuffer;
1394b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                track->mAvail = oldFront->mSize;
1404b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            }
1414b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            doBroadcast = SL_BOOLEAN_TRUE;
1424b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1434b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1444b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_STOPPED:  // idle
1454b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        case SL_PLAYSTATE_PAUSED:   // idle
1464b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1474b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1484b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        default:
1494b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            assert(SL_BOOLEAN_FALSE);
1504b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            break;
1514b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        }
1524b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
153928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kastenbroadcast:
1548c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (doBroadcast) {
1554b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            object_cond_broadcast(&audioPlayer->mObject);
1568c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
1574b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1584b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten        object_unlock_exclusive(&audioPlayer->mObject);
1594b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1604b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    }
1614b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1624b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten    return trackHasData;
1634b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
1644b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten}
1654b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
166343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
167928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten/** \brief This is the track mixer: fill the specified 16-bit stereo PCM buffer */
168343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
169e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kastenvoid IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size)
170b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
171ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_ENTER_INTERFACE_VOID
172ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
173b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // Force to be a multiple of a frame, assumes stereo 16-bit PCM
174b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    size &= ~3;
175b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    SLboolean mixBufferHasData = SL_BOOLEAN_FALSE;
176bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IOutputMixExt *thiz = (IOutputMixExt *) self;
177bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IObject *thisObject = thiz->mThis;
178f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // This lock should never block, except when the application destroys the output mix object
179f51dba65751107c930759938775b75531ec1f330Glenn Kasten    object_lock_exclusive(thisObject);
180f51dba65751107c930759938775b75531ec1f330Glenn Kasten    unsigned activeMask;
181f51dba65751107c930759938775b75531ec1f330Glenn Kasten    // If the output mix is marked for destruction, then acknowledge the request
182bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    if (thiz->mDestroyRequested) {
183b0ab2dee391dd2cb257faeaba252ee6ecccc5f03Glenn Kasten        IEngine *thisEngine = &thisObject->mEngine->mEngine;
184f51dba65751107c930759938775b75531ec1f330Glenn Kasten        interface_lock_exclusive(thisEngine);
185f51dba65751107c930759938775b75531ec1f330Glenn Kasten        assert(&thisEngine->mOutputMix->mObject == thisObject);
186f51dba65751107c930759938775b75531ec1f330Glenn Kasten        thisEngine->mOutputMix = NULL;
187f51dba65751107c930759938775b75531ec1f330Glenn Kasten        // Note we don't attempt to connect another output mix, even if there is one
188f51dba65751107c930759938775b75531ec1f330Glenn Kasten        interface_unlock_exclusive(thisEngine);
189f51dba65751107c930759938775b75531ec1f330Glenn Kasten        // Acknowledge the destroy request, and notify the pre-destroy hook
190bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mDestroyRequested = SL_BOOLEAN_FALSE;
191f51dba65751107c930759938775b75531ec1f330Glenn Kasten        object_cond_broadcast(thisObject);
192f51dba65751107c930759938775b75531ec1f330Glenn Kasten        activeMask = 0;
193f51dba65751107c930759938775b75531ec1f330Glenn Kasten    } else {
194bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        activeMask = thiz->mActiveMask;
195f51dba65751107c930759938775b75531ec1f330Glenn Kasten    }
196d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    while (activeMask) {
197d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        unsigned i = ctz(activeMask);
198d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        assert(MAX_TRACK > i);
199d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        activeMask &= ~(1 << i);
200bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        Track *track = &thiz->mTracks[i];
2014b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
202b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        // track is allocated
2034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
2048c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (!track_check(track)) {
205b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            continue;
2068c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
2074b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten
208b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        // track is playing
209b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        void *dstWriter = pBuffer;
210b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        unsigned desired = size;
211b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        SLboolean trackContributedToMix = SL_BOOLEAN_FALSE;
212e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        float gains[STEREO_CHANNELS];
213e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        Summary summaries[STEREO_CHANNELS];
214e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        unsigned channel;
215e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        for (channel = 0; channel < STEREO_CHANNELS; ++channel) {
216e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            float gain = track->mGains[channel];
217e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            gains[channel] = gain;
218e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            Summary summary;
2198c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (gain <= 0.001) {
220e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                summary = GAIN_MUTE;
2218c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            } else if (gain >= 0.999) {
222e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                summary = GAIN_UNITY;
2238c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            } else {
224e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                summary = GAIN_OTHER;
2258c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
226e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            summaries[channel] = summary;
2276a357b8fa57b0bc1557cd5ab9f9fb86aabaaa18cGlenn Kasten        }
228b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        while (desired > 0) {
229b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            unsigned actual = desired;
2308c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (track->mAvail < actual) {
231b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                actual = track->mAvail;
2328c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
233b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            // force actual to be a frame multiple
234b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (actual > 0) {
235b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                assert(NULL != track->mReader);
236276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                stereo *mixBuffer = (stereo *) dstWriter;
237276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                const stereo *source = (const stereo *) track->mReader;
238276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                unsigned j;
239e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                if (GAIN_MUTE != summaries[0] || GAIN_MUTE != summaries[1]) {
24040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                    if (mixBufferHasData) {
24140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        // apply gain during add
242e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) {
24340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
244e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                                mixBuffer->left += (short) (source->left * track->mGains[0]);
245e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                                mixBuffer->right += (short) (source->right * track->mGains[1]);
24640d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            }
24740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        // no gain adjustment needed, so do a simple add
24840d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        } else {
24940d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
25040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                                mixBuffer->left += source->left;
25140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                                mixBuffer->right += source->right;
25240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            }
25340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        }
25440d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                    } else {
25540d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        // apply gain during copy
256e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) {
25740d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
258e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                                mixBuffer->left = (short) (source->left * track->mGains[0]);
259e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                                mixBuffer->right = (short) (source->right * track->mGains[1]);
26040d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            }
26140d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        // no gain adjustment needed, so do a simple copy
26240d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        } else {
26340d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                            memcpy(dstWriter, track->mReader, actual);
26440d1c40832a448e23d0bb37512aee53222575c2eGlenn Kasten                        }
265276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten                    }
266b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    trackContributedToMix = SL_BOOLEAN_TRUE;
267b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
268b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                dstWriter = (char *) dstWriter + actual;
269b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                desired -= actual;
270b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                track->mReader = (char *) track->mReader + actual;
271b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                track->mAvail -= actual;
272b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                if (track->mAvail == 0) {
2734b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    IBufferQueue *bufferQueue = &track->mAudioPlayer->mBufferQueue;
2744b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    interface_lock_exclusive(bufferQueue);
2754b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    const BufferHeader *oldFront, *newFront, *rear;
2764b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    oldFront = bufferQueue->mFront;
2774b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    rear = bufferQueue->mRear;
2784b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    // a buffer stays on queue while playing, so it better still be there
2794b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    assert(oldFront != rear);
2804b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    newFront = oldFront;
2818c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                    if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1]) {
2824b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        newFront = bufferQueue->mArray;
2838c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                    }
2844b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    bufferQueue->mFront = (BufferHeader *) newFront;
2854b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    assert(0 < bufferQueue->mState.count);
2864b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    --bufferQueue->mState.count;
2874b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    if (newFront != rear) {
2884b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        // we don't acknowledge application requests between buffers
2894b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        // within the same mixer frame
290b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        assert(0 < bufferQueue->mState.count);
2914b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        track->mReader = newFront->mBuffer;
2924b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        track->mAvail = newFront->mSize;
2934b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    }
2944b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    // else we would set play state to playable but not playing during next mixer
2954b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    // frame if the queue is still empty at that time
2964b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    ++bufferQueue->mState.playIndex;
2974b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    slBufferQueueCallback callback = bufferQueue->mCallback;
2984b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    void *context = bufferQueue->mContext;
2994b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    interface_unlock_exclusive(bufferQueue);
3004b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    // The callback function is called on each buffer completion
3014b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                    if (NULL != callback) {
3024b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        (*callback)((SLBufferQueueItf) bufferQueue, context);
3034b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        // Maybe it enqueued another buffer, or maybe it didn't.
3044b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                        // We will find out later during the next mixer frame.
305b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    }
306b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
3078c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                // no lock, but safe because noone else updates this field
3088c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                track->mFramesMixed += actual >> 2;    // sizeof(short) * STEREO_CHANNELS
309b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                continue;
310b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            }
3114b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // we need more data: desired > 0 but actual == 0
3128c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (track_check(track)) {
3134b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten                continue;
3148c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
3154b65ef9efdf5aba01bea89d8cdd64f500560a28dGlenn Kasten            // underflow: clear out rest of partial buffer (NTH synthesize comfort noise)
3168c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (!mixBufferHasData && trackContributedToMix) {
317b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                memset(dstWriter, 0, actual);
3188c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            }
319b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            break;
320b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        }
3218c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        if (trackContributedToMix) {
322b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            mixBufferHasData = SL_BOOLEAN_TRUE;
3238c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten        }
324b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
325f51dba65751107c930759938775b75531ec1f330Glenn Kasten    object_unlock_exclusive(thisObject);
326b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // No active tracks, so output silence
3278c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (!mixBufferHasData) {
328b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        memset(pBuffer, 0, size);
3298c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
330ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
331ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten    SL_LEAVE_INTERFACE_VOID
332b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
333b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
334ed46c29d6a09112dbbf584c82953f63289596fd6Glenn Kasten
335b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = {
336b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    IOutputMixExt_FillBuffer
337b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten};
338b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
339b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenvoid IOutputMixExt_init(void *self)
340b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
341bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    IOutputMixExt *thiz = (IOutputMixExt *) self;
342bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mItf = &IOutputMixExt_Itf;
343bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mActiveMask = 0;
344bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    Track *track = &thiz->mTracks[0];
345928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    unsigned i;
346928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    for (i = 0; i < MAX_TRACK; ++i, ++track) {
347928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        track->mAudioPlayer = NULL;
348928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten    }
349bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mDestroyRequested = SL_BOOLEAN_FALSE;
350343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten}
351343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
352343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
353343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten/** \brief Called by Engine::CreateAudioPlayer to allocate a track */
354343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
355bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *thiz)
356daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{
357bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    thiz->mTrack = NULL;
3589e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten
3599e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    // check the source for compatibility
360bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    switch (thiz->mDataSource.mLocator.mLocatorType) {
3619e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    case SL_DATALOCATOR_BUFFERQUEUE:
3629e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten#ifdef ANDROID
3639e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
3649e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten#endif
365bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        switch (thiz->mDataSource.mFormat.mFormatType) {
3669e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        case SL_DATAFORMAT_PCM:
3679e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten#ifdef USE_SDL
3689e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            // SDL is hard-coded to 44.1 kHz, and there is no sample rate converter
369bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten            if (SL_SAMPLINGRATE_44_1 != thiz->mDataSource.mFormat.mPCM.samplesPerSec)
3709e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten                return SL_RESULT_CONTENT_UNSUPPORTED;
3719e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten#endif
3729e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            break;
3739e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        default:
3749e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten            break;
3759e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        }
3769e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        break;
3779e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    default:
3789e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten        break;
3799e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    }
3809e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten
3819e60b0a390d780539459f41c2bf4a45a326a7b62Glenn Kasten    // check the sink for compatibility
382bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    const SLDataSink *pAudioSnk = &thiz->mDataSink.u.mSink;
383369f3138f19f7102bf0f98b890ab84c8df633a93Glenn Kasten    Track *track = NULL;
384daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    switch (*(SLuint32 *)pAudioSnk->pLocator) {
385daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    case SL_DATALOCATOR_OUTPUTMIX:
386daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        {
387daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        // pAudioSnk->pFormat is ignored
388928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        IOutputMixExt *omExt = &((COutputMix *) ((SLDataLocator_OutputMix *)
389928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            pAudioSnk->pLocator)->outputMix)->mOutputMixExt;
390daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        // allocate an entry within OutputMix for this track
391928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        interface_lock_exclusive(omExt);
392928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        unsigned availMask = ~omExt->mActiveMask;
393d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        if (!availMask) {
394928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            interface_unlock_exclusive(omExt);
395d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten            // All track slots full in output mix
396daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            return SL_RESULT_MEMORY_FAILURE;
397daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
398d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        unsigned i = ctz(availMask);
399d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten        assert(MAX_TRACK > i);
400928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        omExt->mActiveMask |= 1 << i;
401928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        track = &omExt->mTracks[i];
402276cab2d983b892d1b634474b6249f6bec400c76Glenn Kasten        track->mAudioPlayer = NULL;    // only field that is accessed before full initialization
403928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        interface_unlock_exclusive(omExt);
404bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mTrack = track;
405bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mGains[0] = 1.0f;
406bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mGains[1] = 1.0f;
407bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten        thiz->mDestroyRequested = SL_BOOLEAN_FALSE;
408daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
409daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        break;
410daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    default:
411daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        return SL_RESULT_CONTENT_UNSUPPORTED;
412daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    }
413daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten
414d07ed7df4ec9338f97f12627690d58ed9b34f25bGlenn Kasten    assert(NULL != track);
415bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    track->mBufferQueue = &thiz->mBufferQueue;
416bcc5c7225e3b7a1dbf2e9e830987f69167acf06fGlenn Kasten    track->mAudioPlayer = thiz;
417acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mReader = NULL;
418acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mAvail = 0;
419e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    track->mGains[0] = 1.0f;
420e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    track->mGains[1] = 1.0f;
4218c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    track->mFramesMixed = 0;
422daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    return SL_RESULT_SUCCESS;
423daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten}
424daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten
425343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
426343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten/** \brief Called when a gain-related field (mute, solo, volume, stereo position, etc.) updated */
427343c522ebf4f9c321eef8c3b3b2945f1c1cb8846Glenn Kasten
428e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kastenvoid audioPlayerGainUpdate(CAudioPlayer *audioPlayer)
429e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten{
430e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLboolean mute = audioPlayer->mVolume.mMute;
431b91e32605ecf39e34ad39936b1ee193bb4e30225Glenn Kasten    SLuint8 muteMask = audioPlayer->mMuteMask;
432b91e32605ecf39e34ad39936b1ee193bb4e30225Glenn Kasten    SLuint8 soloMask = audioPlayer->mSoloMask;
433e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLmillibel level = audioPlayer->mVolume.mLevel;
434e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLboolean enableStereoPosition = audioPlayer->mVolume.mEnableStereoPosition;
435e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    SLpermille stereoPosition = audioPlayer->mVolume.mStereoPosition;
436e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten
4378c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    if (soloMask) {
438e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        muteMask |= ~soloMask;
4398c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten    }
440e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    if (mute || !(~muteMask & 3)) {
441928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        audioPlayer->mGains[0] = 0.0f;
442928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten        audioPlayer->mGains[1] = 0.0f;
443e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    } else {
44418abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten        float playerGain = powf(10.0f, level / 2000.0f);
445e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        unsigned channel;
446e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        for (channel = 0; channel < STEREO_CHANNELS; ++channel) {
447e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            float gain;
4488c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            if (muteMask & (1 << channel)) {
44918abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten                gain = 0.0f;
4508c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten            } else {
451e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                gain = playerGain;
452e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                if (enableStereoPosition) {
453e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                    switch (channel) {
454e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                    case 0:
4558c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                        if (stereoPosition > 0) {
45618abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten                            gain *= (1000 - stereoPosition) / 1000.0f;
4578c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                        }
458e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        break;
459e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                    case 1:
4608c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                        if (stereoPosition < 0) {
46118abcc4b70fab1f84d6fbebac3a8e34480a6c4d3Glenn Kasten                            gain *= (1000 + stereoPosition) / 1000.0f;
4628c065779232fdd89abace68d2fc7bea786a010d7Glenn Kasten                        }
463e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        break;
464e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                    default:
465e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        assert(SL_BOOLEAN_FALSE);
466e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                        break;
467e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                    }
468e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten                }
469e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten            }
470928ea4ffff40c82987cfb1ac9e3095fdc6968709Glenn Kasten            audioPlayer->mGains[channel] = gain;
471e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten        }
472e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten    }
473e5bf0d2c9531a7064eb3ddcafaf93ac1b0974037Glenn Kasten}
474