IOutputMixExt.c revision acd88797a1d3b8225bab888d29036e245f275be5
1b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten/*
2b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * Copyright (C) 2010 The Android Open Source Project
3b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten *
4b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * you may not use this file except in compliance with the License.
6b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * You may obtain a copy of the License at
7b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten *
8b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten *
10b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * Unless required by applicable law or agreed to in writing, software
11b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * See the License for the specific language governing permissions and
14b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten * limitations under the License.
15b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten */
16b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
17b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten/* OutputMixExt implementation */
18b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
19b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#include "sles_allinclusive.h"
20b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
21b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#ifdef USE_OUTPUTMIXEXT
22b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
23b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten// Used by SDL but not specific to or dependent on SDL
24b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
25b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic void IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size)
26b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
27b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // Force to be a multiple of a frame, assumes stereo 16-bit PCM
28b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    size &= ~3;
29daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    IOutputMixExt *thisExt = (IOutputMixExt *) self;
30daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    IOutputMix *this = &((COutputMix *) thisExt->mThis)->mOutputMix;
31b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    unsigned activeMask = this->mActiveMask;
32daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    struct Track *track = this->mTracks;
33b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    unsigned i;
34b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    SLboolean mixBufferHasData = SL_BOOLEAN_FALSE;
35b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // FIXME O(32) loop even when few tracks are active.
36b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // To avoid loop, use activeMask to check for active track(s)
37b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // and decide whether we actually need to copy or mix.
38b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    for (i = 0; 0 != activeMask; ++i, ++track, activeMask >>= 1) {
39b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        assert(i < 32);
40b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        if (!(activeMask & 1))
41b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            continue;
42b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        // track is allocated
43b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        IPlay *play = track->mPlay;
44b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        if (NULL == play)
45b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            continue;
46b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        // track is initialized
47b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        if (SL_PLAYSTATE_PLAYING != play->mState)
48b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            continue;
49b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        // track is playing
50b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        void *dstWriter = pBuffer;
51b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        unsigned desired = size;
52b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        SLboolean trackContributedToMix = SL_BOOLEAN_FALSE;
53b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        while (desired > 0) {
54b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            IBufferQueue *bufferQueue;
55b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            const struct BufferHeader *oldFront, *newFront, *rear;
56b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            unsigned actual = desired;
57b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (track->mAvail < actual)
58b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                actual = track->mAvail;
59b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            // force actual to be a frame multiple
60b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (actual > 0) {
61b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // FIXME check for either mute or volume 0
62b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // in which case skip the input buffer processing
63b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                assert(NULL != track->mReader);
64b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // FIXME && gain == 1.0
65b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                if (mixBufferHasData) {
66b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    stereo *mixBuffer = (stereo *) dstWriter;
67b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    const stereo *source = (const stereo *) track->mReader;
68b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    unsigned j;
69b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer,
70b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        ++source) {
71b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        // apply gain here
72b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        mixBuffer->left += source->left;
73b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        mixBuffer->right += source->right;
74b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    }
75b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                } else {
76daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten                    // apply gain during copy
77b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    memcpy(dstWriter, track->mReader, actual);
78b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    trackContributedToMix = SL_BOOLEAN_TRUE;
79b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
80b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                dstWriter = (char *) dstWriter + actual;
81b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                desired -= actual;
82b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                track->mReader = (char *) track->mReader + actual;
83b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                track->mAvail -= actual;
84b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                if (track->mAvail == 0) {
85b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    bufferQueue = track->mBufferQueue;
86b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    if (NULL != bufferQueue) {
87b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        oldFront = bufferQueue->mFront;
88b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        rear = bufferQueue->mRear;
89b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        assert(oldFront != rear);
90b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        newFront = oldFront;
91daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten                        if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers])
92b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                            newFront = bufferQueue->mArray;
93b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        bufferQueue->mFront = (struct BufferHeader *) newFront;
94b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        assert(0 < bufferQueue->mState.count);
95b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        --bufferQueue->mState.count;
96b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        // FIXME here or in Enqueue?
97b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        ++bufferQueue->mState.playIndex;
98b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        // FIXME a good time to do an early warning
99b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        // callback depending on buffer count
100b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    }
101b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
102b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                continue;
103b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            }
104b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            // actual == 0
105b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            bufferQueue = track->mBufferQueue;
106b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (NULL != bufferQueue) {
107b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                oldFront = bufferQueue->mFront;
108b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                rear = bufferQueue->mRear;
109b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                if (oldFront != rear) {
110b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastengot_one:
111b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    assert(0 < bufferQueue->mState.count);
112b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    track->mReader = oldFront->mBuffer;
113b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    track->mAvail = oldFront->mSize;
114b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    continue;
115b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
116b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // FIXME should be able to configure when to
117b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // kick off the callback e.g. high/low water-marks etc.
118b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // need data but none available, attempt a desperate callback
119b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                slBufferQueueCallback callback = bufferQueue->mCallback;
120b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                if (NULL != callback) {
121daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten                    (*callback)((SLBufferQueueItf) bufferQueue, bufferQueue->mContext);
122b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    // if lucky, the callback enqueued a buffer
123b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    if (rear != bufferQueue->mRear)
124b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                        goto got_one;
125b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                    // unlucky, queue still empty, the callback failed
126b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                }
127b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // here on underflow due to no callback, or failed callback
128b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // FIXME underflow, send silence (or previous buffer?)
129b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // we did a callback to try to kick start again but failed
130b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                // should log this
131b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            }
132b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            // no buffer queue or underflow, clear out rest of partial buffer
133b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            if (!mixBufferHasData && trackContributedToMix)
134b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten                memset(dstWriter, 0, actual);
135b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            break;
136b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        }
137b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        if (trackContributedToMix)
138b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten            mixBufferHasData = SL_BOOLEAN_TRUE;
139b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    }
140b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    // No active tracks, so output silence
141b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    if (!mixBufferHasData)
142b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten        memset(pBuffer, 0, size);
143b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
144b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
145b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenstatic const struct SLOutputMixExtItf_ IOutputMixExt_Itf = {
146b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    IOutputMixExt_FillBuffer
147b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten};
148b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
149b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kastenvoid IOutputMixExt_init(void *self)
150b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten{
151b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    IOutputMixExt *this = (IOutputMixExt *) self;
152b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten    this->mItf = &IOutputMixExt_Itf;
153b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten}
154b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten
155acd88797a1d3b8225bab888d29036e245f275be5Glenn KastenSLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *this)
156daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten{
157acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    //const SLDataSource *pAudioSrc = &this->mDataSource.u.mSource;
158acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    const SLDataSink *pAudioSnk = &this->mDataSink.u.mSink;
159daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    struct Track *track = NULL;
160daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    switch (*(SLuint32 *)pAudioSnk->pLocator) {
161daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    case SL_DATALOCATOR_OUTPUTMIX:
162daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        {
163daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        // pAudioSnk->pFormat is ignored
164daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        IOutputMix *om = &((COutputMix *) ((SLDataLocator_OutputMix *) pAudioSnk->pLocator)->outputMix)->mOutputMix;
165daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        // allocate an entry within OutputMix for this track
166daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        // FIXME O(n)
167daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        unsigned i;
168daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        for (i = 0, track = &om->mTracks[0]; i < 32; ++i, ++track) {
169daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            if (om->mActiveMask & (1 << i))
170daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten                continue;
171daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            om->mActiveMask |= 1 << i;
172daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            break;
173daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
174daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        if (32 <= i) {
175daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            // FIXME Need a better error code for all slots full in output mix
176daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten            return SL_RESULT_MEMORY_FAILURE;
177daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
178daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        }
179daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        break;
180daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    default:
181daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten        return SL_RESULT_CONTENT_UNSUPPORTED;
182daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    }
183daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten
184acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mBufferQueue = &this->mBufferQueue;
185acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mPlay = &this->mPlay;
186acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    // next 2 fields must be initialized explicitly (not part of this)
187acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mReader = NULL;
188acd88797a1d3b8225bab888d29036e245f275be5Glenn Kasten    track->mAvail = 0;
189daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten    return SL_RESULT_SUCCESS;
190daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten}
191daf661248ff6ea2e21799e5114c78b7c1d49630eGlenn Kasten
192b7154f2324c8ae44b820c07c69aaa80a4bb9e418Glenn Kasten#endif // USE_OUTPUTMIXEXT
193