• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* OutputMixExt implementation */
18 
19 #include "sles_allinclusive.h"
20 #include <math.h>
21 
22 
23 // OutputMixExt is used by SDL, but is not specific to or dependent on SDL
24 
25 
26 // stereo is a frame consisting of a pair of 16-bit PCM samples
27 
28 typedef struct {
29     short left;
30     short right;
31 } stereo;
32 
33 
34 /** \brief Summary of the gain, as an optimization for the mixer */
35 
36 typedef enum {
37     GAIN_MUTE  = 0,  // mValue == 0.0f within epsilon
38     GAIN_UNITY = 1,  // mValue == 1.0f within epsilon
39     GAIN_OTHER = 2   // 0.0f < mValue < 1.0f
40 } Summary;
41 
42 
43 /** \brief Check whether a track has any data for us to read */
44 
track_check(Track * track)45 static SLboolean track_check(Track *track)
46 {
47     assert(NULL != track);
48     SLboolean trackHasData = SL_BOOLEAN_FALSE;
49 
50     CAudioPlayer *audioPlayer = track->mAudioPlayer;
51     if (NULL != audioPlayer) {
52 
53         // track is initialized
54 
55         // FIXME This lock could block and result in stuttering;
56         // a trylock with retry or lockless solution would be ideal
57         object_lock_exclusive(&audioPlayer->mObject);
58         assert(audioPlayer->mTrack == track);
59 
60         SLuint32 framesMixed = track->mFramesMixed;
61         if (0 != framesMixed) {
62             track->mFramesMixed = 0;
63             audioPlayer->mPlay.mFramesSinceLastSeek += framesMixed;
64             audioPlayer->mPlay.mFramesSincePositionUpdate += framesMixed;
65         }
66 
67         SLboolean doBroadcast = SL_BOOLEAN_FALSE;
68         const BufferHeader *oldFront;
69 
70         if (audioPlayer->mBufferQueue.mClearRequested) {
71             // application thread(s) that call BufferQueue::Clear while mixer is active
72             // will block synchronously until mixer acknowledges the Clear request
73             audioPlayer->mBufferQueue.mFront = &audioPlayer->mBufferQueue.mArray[0];
74             audioPlayer->mBufferQueue.mRear = &audioPlayer->mBufferQueue.mArray[0];
75             audioPlayer->mBufferQueue.mState.count = 0;
76             audioPlayer->mBufferQueue.mState.playIndex = 0;
77             audioPlayer->mBufferQueue.mClearRequested = SL_BOOLEAN_FALSE;
78             track->mReader = NULL;
79             track->mAvail = 0;
80             doBroadcast = SL_BOOLEAN_TRUE;
81         }
82 
83         if (audioPlayer->mDestroyRequested) {
84             // an application thread that calls Object::Destroy while mixer is active will block
85             // synchronously in the PreDestroy hook until mixer acknowledges the Destroy request
86             COutputMix *outputMix = CAudioPlayer_GetOutputMix(audioPlayer);
87             unsigned i = track - outputMix->mOutputMixExt.mTracks;
88             assert( /* 0 <= i && */ i < MAX_TRACK);
89             unsigned mask = 1 << i;
90             track->mAudioPlayer = NULL;
91             assert(outputMix->mOutputMixExt.mActiveMask & mask);
92             outputMix->mOutputMixExt.mActiveMask &= ~mask;
93             audioPlayer->mTrack = NULL;
94             audioPlayer->mDestroyRequested = SL_BOOLEAN_FALSE;
95             doBroadcast = SL_BOOLEAN_TRUE;
96             goto broadcast;
97         }
98 
99         switch (audioPlayer->mPlay.mState) {
100 
101         case SL_PLAYSTATE_PLAYING:  // continue playing current track data
102             if (0 < track->mAvail) {
103                 trackHasData = SL_BOOLEAN_TRUE;
104                 break;
105             }
106 
107             // try to get another buffer from queue
108             oldFront = audioPlayer->mBufferQueue.mFront;
109             if (oldFront != audioPlayer->mBufferQueue.mRear) {
110                 assert(0 < audioPlayer->mBufferQueue.mState.count);
111                 track->mReader = oldFront->mBuffer;
112                 track->mAvail = oldFront->mSize;
113                 // note that the buffer stays on the queue while we are reading
114                 audioPlayer->mPlay.mState = SL_PLAYSTATE_PLAYING;
115                 trackHasData = SL_BOOLEAN_TRUE;
116             } else {
117                 // no buffers on queue, so playable but not playing
118                 // NTH should be able to call a desperation callback when completely starved,
119                 // or call less often than every buffer based on high/low water-marks
120             }
121 
122             // copy gains from audio player to track
123             track->mGains[0] = audioPlayer->mGains[0];
124             track->mGains[1] = audioPlayer->mGains[1];
125             break;
126 
127         case SL_PLAYSTATE_STOPPING: // application thread(s) called Play::SetPlayState(STOPPED)
128             audioPlayer->mPlay.mPosition = (SLmillisecond) 0;
129             audioPlayer->mPlay.mFramesSinceLastSeek = 0;
130             audioPlayer->mPlay.mFramesSincePositionUpdate = 0;
131             audioPlayer->mPlay.mLastSeekPosition = 0;
132             audioPlayer->mPlay.mState = SL_PLAYSTATE_STOPPED;
133             // stop cancels a pending seek
134             audioPlayer->mSeek.mPos = SL_TIME_UNKNOWN;
135             oldFront = audioPlayer->mBufferQueue.mFront;
136             if (oldFront != audioPlayer->mBufferQueue.mRear) {
137                 assert(0 < audioPlayer->mBufferQueue.mState.count);
138                 track->mReader = oldFront->mBuffer;
139                 track->mAvail = oldFront->mSize;
140             }
141             doBroadcast = SL_BOOLEAN_TRUE;
142             break;
143 
144         case SL_PLAYSTATE_STOPPED:  // idle
145         case SL_PLAYSTATE_PAUSED:   // idle
146             break;
147 
148         default:
149             assert(SL_BOOLEAN_FALSE);
150             break;
151         }
152 
153 broadcast:
154         if (doBroadcast) {
155             object_cond_broadcast(&audioPlayer->mObject);
156         }
157 
158         object_unlock_exclusive(&audioPlayer->mObject);
159 
160     }
161 
162     return trackHasData;
163 
164 }
165 
166 
167 /** \brief This is the track mixer: fill the specified 16-bit stereo PCM buffer */
168 
IOutputMixExt_FillBuffer(SLOutputMixExtItf self,void * pBuffer,SLuint32 size)169 void IOutputMixExt_FillBuffer(SLOutputMixExtItf self, void *pBuffer, SLuint32 size)
170 {
171     SL_ENTER_INTERFACE_VOID
172 
173     // Force to be a multiple of a frame, assumes stereo 16-bit PCM
174     size &= ~3;
175     SLboolean mixBufferHasData = SL_BOOLEAN_FALSE;
176     IOutputMixExt *thiz = (IOutputMixExt *) self;
177     IObject *thisObject = thiz->mThis;
178     // This lock should never block, except when the application destroys the output mix object
179     object_lock_exclusive(thisObject);
180     unsigned activeMask;
181     // If the output mix is marked for destruction, then acknowledge the request
182     if (thiz->mDestroyRequested) {
183         IEngine *thisEngine = &thisObject->mEngine->mEngine;
184         interface_lock_exclusive(thisEngine);
185         assert(&thisEngine->mOutputMix->mObject == thisObject);
186         thisEngine->mOutputMix = NULL;
187         // Note we don't attempt to connect another output mix, even if there is one
188         interface_unlock_exclusive(thisEngine);
189         // Acknowledge the destroy request, and notify the pre-destroy hook
190         thiz->mDestroyRequested = SL_BOOLEAN_FALSE;
191         object_cond_broadcast(thisObject);
192         activeMask = 0;
193     } else {
194         activeMask = thiz->mActiveMask;
195     }
196     while (activeMask) {
197         unsigned i = ctz(activeMask);
198         assert(MAX_TRACK > i);
199         activeMask &= ~(1 << i);
200         Track *track = &thiz->mTracks[i];
201 
202         // track is allocated
203 
204         if (!track_check(track)) {
205             continue;
206         }
207 
208         // track is playing
209         void *dstWriter = pBuffer;
210         unsigned desired = size;
211         SLboolean trackContributedToMix = SL_BOOLEAN_FALSE;
212         float gains[STEREO_CHANNELS];
213         Summary summaries[STEREO_CHANNELS];
214         unsigned channel;
215         for (channel = 0; channel < STEREO_CHANNELS; ++channel) {
216             float gain = track->mGains[channel];
217             gains[channel] = gain;
218             Summary summary;
219             if (gain <= 0.001) {
220                 summary = GAIN_MUTE;
221             } else if (gain >= 0.999) {
222                 summary = GAIN_UNITY;
223             } else {
224                 summary = GAIN_OTHER;
225             }
226             summaries[channel] = summary;
227         }
228         while (desired > 0) {
229             unsigned actual = desired;
230             if (track->mAvail < actual) {
231                 actual = track->mAvail;
232             }
233             // force actual to be a frame multiple
234             if (actual > 0) {
235                 assert(NULL != track->mReader);
236                 stereo *mixBuffer = (stereo *) dstWriter;
237                 const stereo *source = (const stereo *) track->mReader;
238                 unsigned j;
239                 if (GAIN_MUTE != summaries[0] || GAIN_MUTE != summaries[1]) {
240                     if (mixBufferHasData) {
241                         // apply gain during add
242                         if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) {
243                             for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
244                                 mixBuffer->left += (short) (source->left * track->mGains[0]);
245                                 mixBuffer->right += (short) (source->right * track->mGains[1]);
246                             }
247                         // no gain adjustment needed, so do a simple add
248                         } else {
249                             for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
250                                 mixBuffer->left += source->left;
251                                 mixBuffer->right += source->right;
252                             }
253                         }
254                     } else {
255                         // apply gain during copy
256                         if (GAIN_UNITY != summaries[0] || GAIN_UNITY != summaries[1]) {
257                             for (j = 0; j < actual; j += sizeof(stereo), ++mixBuffer, ++source) {
258                                 mixBuffer->left = (short) (source->left * track->mGains[0]);
259                                 mixBuffer->right = (short) (source->right * track->mGains[1]);
260                             }
261                         // no gain adjustment needed, so do a simple copy
262                         } else {
263                             memcpy(dstWriter, track->mReader, actual);
264                         }
265                     }
266                     trackContributedToMix = SL_BOOLEAN_TRUE;
267                 }
268                 dstWriter = (char *) dstWriter + actual;
269                 desired -= actual;
270                 track->mReader = (char *) track->mReader + actual;
271                 track->mAvail -= actual;
272                 if (track->mAvail == 0) {
273                     IBufferQueue *bufferQueue = &track->mAudioPlayer->mBufferQueue;
274                     interface_lock_exclusive(bufferQueue);
275                     const BufferHeader *oldFront, *newFront, *rear;
276                     oldFront = bufferQueue->mFront;
277                     rear = bufferQueue->mRear;
278                     // a buffer stays on queue while playing, so it better still be there
279                     assert(oldFront != rear);
280                     newFront = oldFront;
281                     if (++newFront == &bufferQueue->mArray[bufferQueue->mNumBuffers + 1]) {
282                         newFront = bufferQueue->mArray;
283                     }
284                     bufferQueue->mFront = (BufferHeader *) newFront;
285                     assert(0 < bufferQueue->mState.count);
286                     --bufferQueue->mState.count;
287                     if (newFront != rear) {
288                         // we don't acknowledge application requests between buffers
289                         // within the same mixer frame
290                         assert(0 < bufferQueue->mState.count);
291                         track->mReader = newFront->mBuffer;
292                         track->mAvail = newFront->mSize;
293                     }
294                     // else we would set play state to playable but not playing during next mixer
295                     // frame if the queue is still empty at that time
296                     ++bufferQueue->mState.playIndex;
297                     slBufferQueueCallback callback = bufferQueue->mCallback;
298                     void *context = bufferQueue->mContext;
299                     interface_unlock_exclusive(bufferQueue);
300                     // The callback function is called on each buffer completion
301                     if (NULL != callback) {
302                         (*callback)((SLBufferQueueItf) bufferQueue, context);
303                         // Maybe it enqueued another buffer, or maybe it didn't.
304                         // We will find out later during the next mixer frame.
305                     }
306                 }
307                 // no lock, but safe because noone else updates this field
308                 track->mFramesMixed += actual >> 2;    // sizeof(short) * STEREO_CHANNELS
309                 continue;
310             }
311             // we need more data: desired > 0 but actual == 0
312             if (track_check(track)) {
313                 continue;
314             }
315             // underflow: clear out rest of partial buffer (NTH synthesize comfort noise)
316             if (!mixBufferHasData && trackContributedToMix) {
317                 memset(dstWriter, 0, actual);
318             }
319             break;
320         }
321         if (trackContributedToMix) {
322             mixBufferHasData = SL_BOOLEAN_TRUE;
323         }
324     }
325     object_unlock_exclusive(thisObject);
326     // No active tracks, so output silence
327     if (!mixBufferHasData) {
328         memset(pBuffer, 0, size);
329     }
330 
331     SL_LEAVE_INTERFACE_VOID
332 }
333 
334 
335 static const struct SLOutputMixExtItf_ IOutputMixExt_Itf = {
336     IOutputMixExt_FillBuffer
337 };
338 
IOutputMixExt_init(void * self)339 void IOutputMixExt_init(void *self)
340 {
341     IOutputMixExt *thiz = (IOutputMixExt *) self;
342     thiz->mItf = &IOutputMixExt_Itf;
343     thiz->mActiveMask = 0;
344     Track *track = &thiz->mTracks[0];
345     unsigned i;
346     for (i = 0; i < MAX_TRACK; ++i, ++track) {
347         track->mAudioPlayer = NULL;
348     }
349     thiz->mDestroyRequested = SL_BOOLEAN_FALSE;
350 }
351 
352 
353 /** \brief Called by Engine::CreateAudioPlayer to allocate a track */
354 
IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer * thiz)355 SLresult IOutputMixExt_checkAudioPlayerSourceSink(CAudioPlayer *thiz)
356 {
357     thiz->mTrack = NULL;
358 
359     // check the source for compatibility
360     switch (thiz->mDataSource.mLocator.mLocatorType) {
361     case SL_DATALOCATOR_BUFFERQUEUE:
362 #ifdef ANDROID
363     case SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE:
364 #endif
365         switch (thiz->mDataSource.mFormat.mFormatType) {
366         case SL_DATAFORMAT_PCM:
367 #ifdef USE_SDL
368             // SDL is hard-coded to 44.1 kHz, and there is no sample rate converter
369             if (SL_SAMPLINGRATE_44_1 != thiz->mDataSource.mFormat.mPCM.samplesPerSec)
370                 return SL_RESULT_CONTENT_UNSUPPORTED;
371 #endif
372             break;
373         default:
374             break;
375         }
376         break;
377     default:
378         break;
379     }
380 
381     // check the sink for compatibility
382     const SLDataSink *pAudioSnk = &thiz->mDataSink.u.mSink;
383     Track *track = NULL;
384     switch (*(SLuint32 *)pAudioSnk->pLocator) {
385     case SL_DATALOCATOR_OUTPUTMIX:
386         {
387         // pAudioSnk->pFormat is ignored
388         IOutputMixExt *omExt = &((COutputMix *) ((SLDataLocator_OutputMix *)
389             pAudioSnk->pLocator)->outputMix)->mOutputMixExt;
390         // allocate an entry within OutputMix for this track
391         interface_lock_exclusive(omExt);
392         unsigned availMask = ~omExt->mActiveMask;
393         if (!availMask) {
394             interface_unlock_exclusive(omExt);
395             // All track slots full in output mix
396             return SL_RESULT_MEMORY_FAILURE;
397         }
398         unsigned i = ctz(availMask);
399         assert(MAX_TRACK > i);
400         omExt->mActiveMask |= 1 << i;
401         track = &omExt->mTracks[i];
402         track->mAudioPlayer = NULL;    // only field that is accessed before full initialization
403         interface_unlock_exclusive(omExt);
404         thiz->mTrack = track;
405         thiz->mGains[0] = 1.0f;
406         thiz->mGains[1] = 1.0f;
407         thiz->mDestroyRequested = SL_BOOLEAN_FALSE;
408         }
409         break;
410     default:
411         return SL_RESULT_CONTENT_UNSUPPORTED;
412     }
413 
414     assert(NULL != track);
415     track->mBufferQueue = &thiz->mBufferQueue;
416     track->mAudioPlayer = thiz;
417     track->mReader = NULL;
418     track->mAvail = 0;
419     track->mGains[0] = 1.0f;
420     track->mGains[1] = 1.0f;
421     track->mFramesMixed = 0;
422     return SL_RESULT_SUCCESS;
423 }
424 
425 
426 /** \brief Called when a gain-related field (mute, solo, volume, stereo position, etc.) updated */
427 
audioPlayerGainUpdate(CAudioPlayer * audioPlayer)428 void audioPlayerGainUpdate(CAudioPlayer *audioPlayer)
429 {
430     SLboolean mute = audioPlayer->mVolume.mMute;
431     SLuint8 muteMask = audioPlayer->mMuteMask;
432     SLuint8 soloMask = audioPlayer->mSoloMask;
433     SLmillibel level = audioPlayer->mVolume.mLevel;
434     SLboolean enableStereoPosition = audioPlayer->mVolume.mEnableStereoPosition;
435     SLpermille stereoPosition = audioPlayer->mVolume.mStereoPosition;
436 
437     if (soloMask) {
438         muteMask |= ~soloMask;
439     }
440     if (mute || !(~muteMask & 3)) {
441         audioPlayer->mGains[0] = 0.0f;
442         audioPlayer->mGains[1] = 0.0f;
443     } else {
444         float playerGain = powf(10.0f, level / 2000.0f);
445         unsigned channel;
446         for (channel = 0; channel < STEREO_CHANNELS; ++channel) {
447             float gain;
448             if (muteMask & (1 << channel)) {
449                 gain = 0.0f;
450             } else {
451                 gain = playerGain;
452                 if (enableStereoPosition) {
453                     switch (channel) {
454                     case 0:
455                         if (stereoPosition > 0) {
456                             gain *= (1000 - stereoPosition) / 1000.0f;
457                         }
458                         break;
459                     case 1:
460                         if (stereoPosition < 0) {
461                             gain *= (1000 + stereoPosition) / 1000.0f;
462                         }
463                         break;
464                     default:
465                         assert(SL_BOOLEAN_FALSE);
466                         break;
467                     }
468                 }
469             }
470             audioPlayer->mGains[channel] = gain;
471         }
472     }
473 }
474