1188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten/*
2188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Copyright (C) 2010 The Android Open Source Project
3188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten *
4188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * you may not use this file except in compliance with the License.
6188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * You may obtain a copy of the License at
7188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten *
8188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten *
10188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * Unless required by applicable law or agreed to in writing, software
11188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * See the License for the specific language governing permissions and
14188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten * limitations under the License.
15188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten */
16188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
17188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten/* OutputMixExt implementation */
18188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
19188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten#include "sles_allinclusive.h"
2015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten#include <math.h>
21188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
22188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
234f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten// OutputMixExt is used by SDL, but is not specific to or dependent on SDL
24188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
2551cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten
2651cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten// stereo is a frame consisting of a pair of 16-bit PCM samples
2751cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten
2851cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kastentypedef struct {
2951cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten    short left;
3051cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten    short right;
3151cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten} stereo;
3251cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten
3351cb31b09f6af53402b3fbe7e9de29badc1155a2Glenn Kasten
346aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten/** \brief Summary of the gain, as an optimization for the mixer */
3515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten
367e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kastentypedef enum {
3715f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    GAIN_MUTE  = 0,  // mValue == 0.0f within epsilon
3815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    GAIN_UNITY = 1,  // mValue == 1.0f within epsilon
3915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    GAIN_OTHER = 2   // 0.0f < mValue < 1.0f
407e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten} Summary;
417e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten
42f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten
436aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten/** \brief Check whether a track has any data for us to read */
4423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
4510ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kastenstatic SLboolean track_check(Track *track)
4623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten{
474f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten    assert(NULL != track);
4823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten    SLboolean trackHasData = SL_BOOLEAN_FALSE;
4923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
5023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten    CAudioPlayer *audioPlayer = track->mAudioPlayer;
5123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten    if (NULL != audioPlayer) {
5223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
5323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        // track is initialized
5423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
554f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        // FIXME This lock could block and result in stuttering;
564f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        // a trylock with retry or lockless solution would be ideal
5723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        object_lock_exclusive(&audioPlayer->mObject);
584f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        assert(audioPlayer->mTrack == track);
5923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
6066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        SLuint32 framesMixed = track->mFramesMixed;
6166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        if (0 != framesMixed) {
6266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            track->mFramesMixed = 0;
6366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            audioPlayer->mPlay.mFramesSinceLastSeek += framesMixed;
6466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            audioPlayer->mPlay.mFramesSincePositionUpdate += framesMixed;
6566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        }
6666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten
6723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        SLboolean doBroadcast = SL_BOOLEAN_FALSE;
6823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        const BufferHeader *oldFront;
6923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
7023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        if (audioPlayer->mBufferQueue.mClearRequested) {
7123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            // application thread(s) that call BufferQueue::Clear while mixer is active
724f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            // will block synchronously until mixer acknowledges the Clear request
7323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            audioPlayer->mBufferQueue.mFront = &audioPlayer->mBufferQueue.mArray[0];
7423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            audioPlayer->mBufferQueue.mRear = &audioPlayer->mBufferQueue.mArray[0];
7523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            audioPlayer->mBufferQueue.mState.count = 0;
7607c35e6e57ff8945c4dd836be4486a62316ac64bGlenn Kasten            audioPlayer->mBufferQueue.mState.playIndex = 0;
7723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            audioPlayer->mBufferQueue.mClearRequested = SL_BOOLEAN_FALSE;
7823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            track->mReader = NULL;
7923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            track->mAvail = 0;
8023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            doBroadcast = SL_BOOLEAN_TRUE;
8123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        }
8223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
834f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        if (audioPlayer->mDestroyRequested) {
844f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            // an application thread that calls Object::Destroy while mixer is active will block
854f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            // synchronously in the PreDestroy hook until mixer acknowledges the Destroy request
8631df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten            COutputMix *outputMix = CAudioPlayer_GetOutputMix(audioPlayer);
874f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            unsigned i = track - outputMix->mOutputMixExt.mTracks;
884f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            assert( /* 0 <= i && */ i < MAX_TRACK);
894f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            unsigned mask = 1 << i;
904f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            track->mAudioPlayer = NULL;
914f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            assert(outputMix->mOutputMixExt.mActiveMask & mask);
924f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            outputMix->mOutputMixExt.mActiveMask &= ~mask;
934f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            audioPlayer->mTrack = NULL;
944f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            audioPlayer->mDestroyRequested = SL_BOOLEAN_FALSE;
954f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            doBroadcast = SL_BOOLEAN_TRUE;
964f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            goto broadcast;
974f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        }
984f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten
9923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        switch (audioPlayer->mPlay.mState) {
10023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
10123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        case SL_PLAYSTATE_PLAYING:  // continue playing current track data
10223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            if (0 < track->mAvail) {
10323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                trackHasData = SL_BOOLEAN_TRUE;
10423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                break;
10523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            }
10623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
10723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            // try to get another buffer from queue
10823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            oldFront = audioPlayer->mBufferQueue.mFront;
10923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            if (oldFront != audioPlayer->mBufferQueue.mRear) {
11023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                assert(0 < audioPlayer->mBufferQueue.mState.count);
11123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                track->mReader = oldFront->mBuffer;
11223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                track->mAvail = oldFront->mSize;
11323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                // note that the buffer stays on the queue while we are reading
11423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                audioPlayer->mPlay.mState = SL_PLAYSTATE_PLAYING;
11523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                trackHasData = SL_BOOLEAN_TRUE;
11623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            } else {
11723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                // no buffers on queue, so playable but not playing
11823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                // NTH should be able to call a desperation callback when completely starved,
11923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                // or call less often than every buffer based on high/low water-marks
12023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            }
1214f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten
1224f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            // copy gains from audio player to track
1234f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            track->mGains[0] = audioPlayer->mGains[0];
1244f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            track->mGains[1] = audioPlayer->mGains[1];
12523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            break;
12623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
12723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        case SL_PLAYSTATE_STOPPING: // application thread(s) called Play::SetPlayState(STOPPED)
12823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            audioPlayer->mPlay.mPosition = (SLmillisecond) 0;
12966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            audioPlayer->mPlay.mFramesSinceLastSeek = 0;
13066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            audioPlayer->mPlay.mFramesSincePositionUpdate = 0;
13166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            audioPlayer->mPlay.mLastSeekPosition = 0;
13223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            audioPlayer->mPlay.mState = SL_PLAYSTATE_STOPPED;
13366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            // stop cancels a pending seek
13466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN;
13523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            oldFront = audioPlayer->mBufferQueue.mFront;
13623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            if (oldFront != audioPlayer->mBufferQueue.mRear) {
13723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                assert(0 < audioPlayer->mBufferQueue.mState.count);
13823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                track->mReader = oldFront->mBuffer;
13923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                track->mAvail = oldFront->mSize;
14023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            }
14123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            doBroadcast = SL_BOOLEAN_TRUE;
14223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            break;
14323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
14423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        case SL_PLAYSTATE_STOPPED:  // idle
14523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        case SL_PLAYSTATE_PAUSED:   // idle
14623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            break;
14723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
14823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        default:
14923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            assert(SL_BOOLEAN_FALSE);
15023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            break;
15123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        }
15223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
1534f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kastenbroadcast:
15466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        if (doBroadcast) {
15523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            object_cond_broadcast(&audioPlayer->mObject);
15666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        }
15723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
15823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten        object_unlock_exclusive(&audioPlayer->mObject);
15923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
16023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten    }
16123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
16223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten    return trackHasData;
16323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
16423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten}
16523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
1666aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten
1674f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten/** \brief This is the track mixer: fill the specified 16-bit stereo PCM buffer */
1686aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten
1699c03f04a9c6cc2a821182c8be8f2efe964a27efeGlenn Kastenvoid IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size)
170188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten{
171f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten    SL_ENTER_INTERFACE_VOID
172f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten
173188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    // Force to be a multiple of a frame, assumes stereo 16-bit PCM
174188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    size &= ~3;
175188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    SLboolean mixBufferHasData = SL_BOOLEAN_FALSE;
17650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    IOutputMixExt *thiz = (IOutputMixExt *) self;
17750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    IObject *thisObject = thiz->mThis;
17831df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten    // This lock should never block, except when the application destroys the output mix object
17931df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten    object_lock_exclusive(thisObject);
18031df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten    unsigned activeMask;
18131df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten    // If the output mix is marked for destruction, then acknowledge the request
18250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    if (thiz->mDestroyRequested) {
1833be625f40588941aa23e35fed5cb693ddc9718daGlenn Kasten        IEngine *thisEngine = &thisObject->mEngine->mEngine;
18431df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten        interface_lock_exclusive(thisEngine);
18531df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten        assert(&thisEngine->mOutputMix->mObject == thisObject);
18631df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten        thisEngine->mOutputMix = NULL;
18731df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten        // Note we don't attempt to connect another output mix, even if there is one
18831df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten        interface_unlock_exclusive(thisEngine);
18931df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten        // Acknowledge the destroy request, and notify the pre-destroy hook
19050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mDestroyRequested = SL_BOOLEAN_FALSE;
19131df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten        object_cond_broadcast(thisObject);
19231df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten        activeMask = 0;
19331df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten    } else {
19450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        activeMask = thiz->mActiveMask;
19531df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten    }
19632a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten    while (activeMask) {
19732a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten        unsigned i = ctz(activeMask);
19832a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten        assert(MAX_TRACK > i);
19932a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten        activeMask &= ~(1 << i);
20050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        Track *track = &thiz->mTracks[i];
20123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
202188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        // track is allocated
20323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
20466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        if (!track_check(track)) {
205188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten            continue;
20666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        }
20723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten
208188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        // track is playing
209188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        void *dstWriter = pBuffer;
210188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        unsigned desired = size;
211188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        SLboolean trackContributedToMix = SL_BOOLEAN_FALSE;
21215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten        float gains[STEREO_CHANNELS];
21315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten        Summary summaries[STEREO_CHANNELS];
21415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten        unsigned channel;
21515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten        for (channel = 0; channel < STEREO_CHANNELS; ++channel) {
21615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten            float gain = track->mGains[channel];
21715f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten            gains[channel] = gain;
21815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten            Summary summary;
21966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            if (gain <= 0.001) {
22015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                summary = GAIN_MUTE;
22166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            } else if (gain >= 0.999) {
22215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                summary = GAIN_UNITY;
22366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            } else {
22415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                summary = GAIN_OTHER;
22566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            }
22615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten            summaries[channel] = summary;
227ffeb2e16c2886eefa88d6eaf4c7be78c2eced82bGlenn Kasten        }
228188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        while (desired > 0) {
229188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten            unsigned actual = desired;
23066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            if (track->mAvail < actual) {
231188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                actual = track->mAvail;
23266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            }
233188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten            // force actual to be a frame multiple
234188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten            if (actual > 0) {
235188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                assert(NULL != track->mReader);
2363cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten                stereo *mixBuffer = (stereo *) dstWriter;
2373cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten                const stereo *source = (const stereo *) track->mReader;
2383cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten                unsigned j;
23915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                if (GAIN_MUTE != summaries[0] || GAIN_MUTE != summaries[1]) {
2407e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                    if (mixBufferHasData) {
2417e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                        // apply gain during add
24215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                        if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) {
2437e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                            for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
24415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                                mixBuffer->left += (short) (source->left * track->mGains[0]);
24515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                                mixBuffer->right += (short) (source->right * track->mGains[1]);
2467e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                            }
2477e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                        // no gain adjustment needed, so do a simple add
2487e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                        } else {
2497e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                            for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
2507e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                                mixBuffer->left += source->left;
2517e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                                mixBuffer->right += source->right;
2527e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                            }
2537e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                        }
2547e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                    } else {
2557e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                        // apply gain during copy
25615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                        if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) {
2577e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                            for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
25815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                                mixBuffer->left = (short) (source->left * track->mGains[0]);
25915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                                mixBuffer->right = (short) (source->right * track->mGains[1]);
2607e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                            }
2617e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                        // no gain adjustment needed, so do a simple copy
2627e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                        } else {
2637e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                            memcpy(dstWriter, track->mReader, actual);
2647e5dd9fa6ab032d7eeaac79bee4370a133eda8c2Glenn Kasten                        }
2653cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten                    }
266188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                    trackContributedToMix = SL_BOOLEAN_TRUE;
267188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                }
268188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                dstWriter = (char *) dstWriter + actual;
269188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                desired -= actual;
270188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                track->mReader = (char *) track->mReader + actual;
271188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                track->mAvail -= actual;
272188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                if (track->mAvail == 0) {
27323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    IBufferQueue *bufferQueue = &track->mAudioPlayer->mBufferQueue;
27423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    interface_lock_exclusive(bufferQueue);
27523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    const BufferHeader *oldFront, *newFront, *rear;
27623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    oldFront = bufferQueue->mFront;
27723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    rear = bufferQueue->mRear;
27823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    // a buffer stays on queue while playing, so it better still be there
27923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    assert(oldFront != rear);
28023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    newFront = oldFront;
28166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                    if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1]) {
28223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                        newFront = bufferQueue->mArray;
28366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                    }
28423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    bufferQueue->mFront = (BufferHeader *) newFront;
28523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    assert(0 < bufferQueue->mState.count);
28623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    --bufferQueue->mState.count;
28723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    if (newFront != rear) {
28823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                        // we don't acknowledge application requests between buffers
28923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                        // within the same mixer frame
290188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                        assert(0 < bufferQueue->mState.count);
29123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                        track->mReader = newFront->mBuffer;
29223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                        track->mAvail = newFront->mSize;
29323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    }
29423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    // else we would set play state to playable but not playing during next mixer
29523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    // frame if the queue is still empty at that time
29623c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    ++bufferQueue->mState.playIndex;
29723c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    slBufferQueueCallback callback = bufferQueue->mCallback;
29823c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    void *context = bufferQueue->mContext;
29923c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    interface_unlock_exclusive(bufferQueue);
30023c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    // The callback function is called on each buffer completion
30123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                    if (NULL != callback) {
30223c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                        (*callback)((SLBufferQueueItf) bufferQueue, context);
30323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                        // Maybe it enqueued another buffer, or maybe it didn't.
30423c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                        // We will find out later during the next mixer frame.
305188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                    }
306188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                }
30766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                // no lock, but safe because noone else updates this field
30866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                track->mFramesMixed += actual >> 2;    // sizeof(short) * STEREO_CHANNELS
309188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                continue;
310188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten            }
31123c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            // we need more data: desired > 0 but actual == 0
31266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            if (track_check(track)) {
31323c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten                continue;
31466f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            }
31523c38816f7c210afae5072fd44658c98fec7e119Glenn Kasten            // underflow: clear out rest of partial buffer (NTH synthesize comfort noise)
31666f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            if (!mixBufferHasData && trackContributedToMix) {
317188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten                memset(dstWriter, 0, actual);
31866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            }
319188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten            break;
320188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        }
32166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        if (trackContributedToMix) {
322188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten            mixBufferHasData = SL_BOOLEAN_TRUE;
32366f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten        }
324188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    }
32531df22b193ea7c7c331d26a27fa6756a89c8ec3cGlenn Kasten    object_unlock_exclusive(thisObject);
326188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    // No active tracks, so output silence
32766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    if (!mixBufferHasData) {
328188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten        memset(pBuffer, 0, size);
32966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    }
330f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten
331f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten    SL_LEAVE_INTERFACE_VOID
332188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten}
333188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
334f156301680273e71e56e898f98798f5b5b2431f6Glenn Kasten
335188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = {
336188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten    IOutputMixExt_FillBuffer
337188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten};
338188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten
339188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kastenvoid IOutputMixExt_init(void *self)
340188a1af5a1d2e2c339cded3dc5bbd99c2fd89fefGlenn Kasten{
34150bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    IOutputMixExt *thiz = (IOutputMixExt *) self;
34250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    thiz->mItf = &IOutputMixExt_Itf;
34350bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    thiz->mActiveMask = 0;
34450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    Track *track = &thiz->mTracks[0];
3454f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten    unsigned i;
3464f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten    for (i = 0; i < MAX_TRACK; ++i, ++track) {
3474f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        track->mAudioPlayer = NULL;
3484f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten    }
34950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    thiz->mDestroyRequested = SL_BOOLEAN_FALSE;
3506aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten}
3516aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten
3526aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten
3536aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten/** \brief Called by Engine::CreateAudioPlayer to allocate a track */
3546aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten
35550bccde01980ae803b8656e8b08ecacb65540f50Glenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *thiz)
356f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten{
35750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    thiz->mTrack = NULL;
358182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten
359182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten    // check the source for compatibility
36050bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    switch (thiz->mDataSource.mLocator.mLocatorType) {
361182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten    case SL_DATALOCATOR_BUFFERQUEUE:
362182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten#ifdef ANDROID
363182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten    case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
364182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten#endif
36550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        switch (thiz->mDataSource.mFormat.mFormatType) {
366182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten        case SL_DATAFORMAT_PCM:
367182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten#ifdef USE_SDL
368182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten            // SDL is hard-coded to 44.1 kHz, and there is no sample rate converter
36950bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten            if (SL_SAMPLINGRATE_44_1 != thiz->mDataSource.mFormat.mPCM.samplesPerSec)
370182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten                return SL_RESULT_CONTENT_UNSUPPORTED;
371182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten#endif
372182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten            break;
373182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten        default:
374182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten            break;
375182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten        }
376182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten        break;
377182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten    default:
378182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten        break;
379182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten    }
380182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten
381182f822e7110bac4947ba8bded1c90ce8050c0fdGlenn Kasten    // check the sink for compatibility
38250bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    const SLDataSink *pAudioSnk = &thiz->mDataSink.u.mSink;
38310ee2bc6119445f4339ecef998c40c9cc95057cdGlenn Kasten    Track *track = NULL;
384f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    switch (*(SLuint32 *)pAudioSnk->pLocator) {
385f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    case SL_DATALOCATOR_OUTPUTMIX:
386f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        {
387f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        // pAudioSnk->pFormat is ignored
3884f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        IOutputMixExt *omExt = &((COutputMix *) ((SLDataLocator_OutputMix *)
3894f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            pAudioSnk->pLocator)->outputMix)->mOutputMixExt;
390f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        // allocate an entry within OutputMix for this track
3914f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        interface_lock_exclusive(omExt);
3924f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        unsigned availMask = ~omExt->mActiveMask;
39332a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten        if (!availMask) {
3944f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            interface_unlock_exclusive(omExt);
39532a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten            // All track slots full in output mix
396f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten            return SL_RESULT_MEMORY_FAILURE;
397f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        }
39832a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten        unsigned i = ctz(availMask);
39932a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten        assert(MAX_TRACK > i);
4004f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        omExt->mActiveMask |= 1 << i;
4014f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        track = &omExt->mTracks[i];
4023cdc48ac145e12a40b0ff0f90e8c01bec269bc38Glenn Kasten        track->mAudioPlayer = NULL;    // only field that is accessed before full initialization
4034f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        interface_unlock_exclusive(omExt);
40450bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mTrack = track;
40550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mGains[0] = 1.0f;
40650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mGains[1] = 1.0f;
40750bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten        thiz->mDestroyRequested = SL_BOOLEAN_FALSE;
408f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        }
409f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        break;
410f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    default:
411f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten        return SL_RESULT_CONTENT_UNSUPPORTED;
412f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    }
413f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten
41432a32a4674ed760e1ab6bf4b4349216bbfa75735Glenn Kasten    assert(NULL != track);
41550bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    track->mBufferQueue = &thiz->mBufferQueue;
41650bccde01980ae803b8656e8b08ecacb65540f50Glenn Kasten    track->mAudioPlayer = thiz;
4174c0d2128c7c0a8b40803026d92083b6affc417d2Glenn Kasten    track->mReader = NULL;
4184c0d2128c7c0a8b40803026d92083b6affc417d2Glenn Kasten    track->mAvail = 0;
41915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    track->mGains[0] = 1.0f;
42015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    track->mGains[1] = 1.0f;
42166f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    track->mFramesMixed = 0;
422f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten    return SL_RESULT_SUCCESS;
423f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten}
424f6f90fc5202248e2ae0abde6e655d7186cebc6afGlenn Kasten
4256aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten
4266aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten/** \brief Called when a gain-related field (mute, solo, volume, stereo position, etc.) updated */
4276aa121077e8981b7d9f46471bdaa1a11211057e8Glenn Kasten
42815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kastenvoid audioPlayerGainUpdate(CAudioPlayer *audioPlayer)
42915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten{
43015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    SLboolean mute = audioPlayer->mVolume.mMute;
4319c2a7b1e9f8203bf9de26efca0f1f805038b1f2bGlenn Kasten    SLuint8 muteMask = audioPlayer->mMuteMask;
4329c2a7b1e9f8203bf9de26efca0f1f805038b1f2bGlenn Kasten    SLuint8 soloMask = audioPlayer->mSoloMask;
43315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    SLmillibel level = audioPlayer->mVolume.mLevel;
43415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    SLboolean enableStereoPosition = audioPlayer->mVolume.mEnableStereoPosition;
43515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    SLpermille stereoPosition = audioPlayer->mVolume.mStereoPosition;
43615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten
43766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    if (soloMask) {
43815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten        muteMask |= ~soloMask;
43966f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten    }
44015f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    if (mute || !(~muteMask & 3)) {
4414f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        audioPlayer->mGains[0] = 0.0f;
4424f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten        audioPlayer->mGains[1] = 0.0f;
44315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    } else {
4448252e6c392af287088a55d6d31b5ba7f80f13ca4Glenn Kasten        float playerGain = powf(10.0f, level / 2000.0f);
44515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten        unsigned channel;
44615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten        for (channel = 0; channel < STEREO_CHANNELS; ++channel) {
44715f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten            float gain;
44866f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            if (muteMask & (1 << channel)) {
4498252e6c392af287088a55d6d31b5ba7f80f13ca4Glenn Kasten                gain = 0.0f;
45066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten            } else {
45115f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                gain = playerGain;
45215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                if (enableStereoPosition) {
45315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                    switch (channel) {
45415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                    case 0:
45566f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                        if (stereoPosition > 0) {
4568252e6c392af287088a55d6d31b5ba7f80f13ca4Glenn Kasten                            gain *= (1000 - stereoPosition) / 1000.0f;
45766f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                        }
45815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                        break;
45915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                    case 1:
46066f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                        if (stereoPosition < 0) {
4618252e6c392af287088a55d6d31b5ba7f80f13ca4Glenn Kasten                            gain *= (1000 + stereoPosition) / 1000.0f;
46266f75c45c9aea410b1f913d76995661e72571b67Glenn Kasten                        }
46315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                        break;
46415f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                    default:
46515f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                        assert(SL_BOOLEAN_FALSE);
46615f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                        break;
46715f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                    }
46815f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten                }
46915f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten            }
4704f924ff768d761f53db6fa2dbfb794ba7a65e776Glenn Kasten            audioPlayer->mGains[channel] = gain;
47115f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten        }
47215f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten    }
47315f9f5e609265dff9d6036af38bea084c42a702aGlenn Kasten}
474