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