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 28typedef struct { 29 short left; 30 short right; 31} stereo; 32 33 34/** \brief Summary of the gain, as an optimization for the mixer */ 35 36typedef 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 45static 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 153broadcast: 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 169void 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 335static const struct SLOutputMixExtItf_ IOutputMixExt_Itf = { 336 IOutputMixExt_FillBuffer 337}; 338 339void 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 355SLresult 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 428void 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