FastMixer.cpp revision 21e8c50bd13ebe44f3088e26c9c6df0e163c469c
1/* 2 * Copyright (C) 2012 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#define LOG_TAG "FastMixer" 18//#define LOG_NDEBUG 0 19 20#include <sys/atomics.h> 21#include <time.h> 22#include <utils/Log.h> 23#include <system/audio.h> 24#ifdef FAST_MIXER_STATISTICS 25#include <cpustats/CentralTendencyStatistics.h> 26#endif 27#include "AudioMixer.h" 28#include "FastMixer.h" 29 30#define FAST_HOT_IDLE_NS 1000000L // 1 ms: time to sleep while hot idling 31#define FAST_DEFAULT_NS 999999999L // ~1 sec: default time to sleep 32 33namespace android { 34 35// Fast mixer thread 36bool FastMixer::threadLoop() 37{ 38 static const FastMixerState initial; 39 const FastMixerState *previous = &initial, *current = &initial; 40 FastMixerState preIdle; // copy of state before we went into idle 41 struct timespec oldTs = {0, 0}; 42 bool oldTsValid = false; 43 long slopNs = 0; // accumulated time we've woken up too early (> 0) or too late (< 0) 44 long sleepNs = -1; // -1: busy wait, 0: sched_yield, > 0: nanosleep 45 int fastTrackNames[FastMixerState::kMaxFastTracks]; // handles used by mixer to identify tracks 46 int generations[FastMixerState::kMaxFastTracks]; // last observed mFastTracks[i].mGeneration 47 unsigned i; 48 for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) { 49 fastTrackNames[i] = -1; 50 generations[i] = 0; 51 } 52 NBAIO_Sink *outputSink = NULL; 53 int outputSinkGen = 0; 54 AudioMixer* mixer = NULL; 55 short *mixBuffer = NULL; 56 enum {UNDEFINED, MIXED, ZEROED} mixBufferState = UNDEFINED; 57 NBAIO_Format format = Format_Invalid; 58 unsigned sampleRate = 0; 59 int fastTracksGen = 0; 60 long periodNs = 0; // expected period; the time required to render one mix buffer 61 long underrunNs = 0; // an underrun is likely if an actual cycle is greater than this value 62 long overrunNs = 0; // an overrun is likely if an actual cycle if less than this value 63 FastMixerDumpState dummyDumpState, *dumpState = &dummyDumpState; 64 bool ignoreNextOverrun = true; // used to ignore initial overrun and first after an underrun 65#ifdef FAST_MIXER_STATISTICS 66 CentralTendencyStatistics cts; // cycle times in seconds 67 static const unsigned kMaxSamples = 1000; 68#endif 69 unsigned coldGen = 0; // last observed mColdGen 70 71 for (;;) { 72 73 // either nanosleep, sched_yield, or busy wait 74 if (sleepNs >= 0) { 75 if (sleepNs > 0) { 76 ALOG_ASSERT(sleepNs < 1000000000); 77 const struct timespec req = {0, sleepNs}; 78 nanosleep(&req, NULL); 79 } else { 80 sched_yield(); 81 } 82 } 83 // default to long sleep for next cycle 84 sleepNs = FAST_DEFAULT_NS; 85 86 // poll for state change 87 const FastMixerState *next = mSQ.poll(); 88 if (next == NULL) { 89 // continue to use the default initial state until a real state is available 90 ALOG_ASSERT(current == &initial && previous == &initial); 91 next = current; 92 } 93 94 FastMixerState::Command command = next->mCommand; 95 if (next != current) { 96 97 // As soon as possible of learning of a new dump area, start using it 98 dumpState = next->mDumpState != NULL ? next->mDumpState : &dummyDumpState; 99 100 // We want to always have a valid reference to the previous (non-idle) state. 101 // However, the state queue only guarantees access to current and previous states. 102 // So when there is a transition from a non-idle state into an idle state, we make a 103 // copy of the last known non-idle state so it is still available on return from idle. 104 // The possible transitions are: 105 // non-idle -> non-idle update previous from current in-place 106 // non-idle -> idle update previous from copy of current 107 // idle -> idle don't update previous 108 // idle -> non-idle don't update previous 109 if (!(current->mCommand & FastMixerState::IDLE)) { 110 if (command & FastMixerState::IDLE) { 111 preIdle = *current; 112 current = &preIdle; 113 oldTsValid = false; 114 ignoreNextOverrun = true; 115 } 116 previous = current; 117 } 118 current = next; 119 } 120#if !LOG_NDEBUG 121 next = NULL; // not referenced again 122#endif 123 124 dumpState->mCommand = command; 125 126 switch (command) { 127 case FastMixerState::INITIAL: 128 case FastMixerState::HOT_IDLE: 129 sleepNs = FAST_HOT_IDLE_NS; 130 continue; 131 case FastMixerState::COLD_IDLE: 132 // only perform a cold idle command once 133 // FIXME consider checking previous state and only perform if previous != COLD_IDLE 134 if (current->mColdGen != coldGen) { 135 int32_t *coldFutexAddr = current->mColdFutexAddr; 136 ALOG_ASSERT(coldFutexAddr != NULL); 137 int32_t old = android_atomic_dec(coldFutexAddr); 138 if (old <= 0) { 139 __futex_syscall4(coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL); 140 } 141 sleepNs = -1; 142 coldGen = current->mColdGen; 143 } else { 144 sleepNs = FAST_HOT_IDLE_NS; 145 } 146 continue; 147 case FastMixerState::EXIT: 148 delete mixer; 149 delete[] mixBuffer; 150 return false; 151 case FastMixerState::MIX: 152 case FastMixerState::WRITE: 153 case FastMixerState::MIX_WRITE: 154 break; 155 default: 156 LOG_FATAL("bad command %d", command); 157 } 158 159 // there is a non-idle state available to us; did the state change? 160 size_t frameCount = current->mFrameCount; 161 if (current != previous) { 162 163 // handle state change here, but since we want to diff the state, 164 // we're prepared for previous == &initial the first time through 165 unsigned previousTrackMask; 166 167 // check for change in output HAL configuration 168 NBAIO_Format previousFormat = format; 169 if (current->mOutputSinkGen != outputSinkGen) { 170 outputSink = current->mOutputSink; 171 outputSinkGen = current->mOutputSinkGen; 172 if (outputSink == NULL) { 173 format = Format_Invalid; 174 sampleRate = 0; 175 } else { 176 format = outputSink->format(); 177 sampleRate = Format_sampleRate(format); 178 ALOG_ASSERT(Format_channelCount(format) == 2); 179 } 180 dumpState->mSampleRate = sampleRate; 181 } 182 183 if ((format != previousFormat) || (frameCount != previous->mFrameCount)) { 184 // FIXME to avoid priority inversion, don't delete here 185 delete mixer; 186 mixer = NULL; 187 delete[] mixBuffer; 188 mixBuffer = NULL; 189 if (frameCount > 0 && sampleRate > 0) { 190 // FIXME new may block for unbounded time at internal mutex of the heap 191 // implementation; it would be better to have normal mixer allocate for us 192 // to avoid blocking here and to prevent possible priority inversion 193 mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks); 194 mixBuffer = new short[frameCount * 2]; 195 periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00 196 underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75 197 overrunNs = (frameCount * 250000000LL) / sampleRate; // 0.25 198 } else { 199 periodNs = 0; 200 underrunNs = 0; 201 overrunNs = 0; 202 } 203 mixBufferState = UNDEFINED; 204#if !LOG_NDEBUG 205 for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) { 206 fastTrackNames[i] = -1; 207 } 208#endif 209 // we need to reconfigure all active tracks 210 previousTrackMask = 0; 211 fastTracksGen = current->mFastTracksGen - 1; 212 dumpState->mFrameCount = frameCount; 213 } else { 214 previousTrackMask = previous->mTrackMask; 215 } 216 217 // check for change in active track set 218 unsigned currentTrackMask = current->mTrackMask; 219 if (current->mFastTracksGen != fastTracksGen) { 220 ALOG_ASSERT(mixBuffer != NULL); 221 int name; 222 223 // process removed tracks first to avoid running out of track names 224 unsigned removedTracks = previousTrackMask & ~currentTrackMask; 225 while (removedTracks != 0) { 226 i = __builtin_ctz(removedTracks); 227 removedTracks &= ~(1 << i); 228 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 229 if (mixer != NULL) { 230 name = fastTrackNames[i]; 231 ALOG_ASSERT(name >= 0); 232 mixer->deleteTrackName(name); 233 } 234#if !LOG_NDEBUG 235 fastTrackNames[i] = -1; 236#endif 237 generations[i] = fastTrack->mGeneration; 238 } 239 240 // now process added tracks 241 unsigned addedTracks = currentTrackMask & ~previousTrackMask; 242 while (addedTracks != 0) { 243 i = __builtin_ctz(addedTracks); 244 addedTracks &= ~(1 << i); 245 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 246 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 247 ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1); 248 if (mixer != NULL) { 249 // calling getTrackName with default channel mask 250 name = mixer->getTrackName(AUDIO_CHANNEL_OUT_STEREO); 251 ALOG_ASSERT(name >= 0); 252 fastTrackNames[i] = name; 253 mixer->setBufferProvider(name, bufferProvider); 254 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, 255 (void *) mixBuffer); 256 // newly allocated track names default to full scale volume 257 if (fastTrack->mSampleRate != 0 && fastTrack->mSampleRate != sampleRate) { 258 mixer->setParameter(name, AudioMixer::RESAMPLE, 259 AudioMixer::SAMPLE_RATE, (void*) fastTrack->mSampleRate); 260 } 261 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, 262 (void *) fastTrack->mChannelMask); 263 mixer->enable(name); 264 } 265 generations[i] = fastTrack->mGeneration; 266 } 267 268 // finally process modified tracks; these use the same slot 269 // but may have a different buffer provider or volume provider 270 unsigned modifiedTracks = currentTrackMask & previousTrackMask; 271 while (modifiedTracks != 0) { 272 i = __builtin_ctz(modifiedTracks); 273 modifiedTracks &= ~(1 << i); 274 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 275 if (fastTrack->mGeneration != generations[i]) { 276 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 277 ALOG_ASSERT(bufferProvider != NULL); 278 if (mixer != NULL) { 279 name = fastTrackNames[i]; 280 ALOG_ASSERT(name >= 0); 281 mixer->setBufferProvider(name, bufferProvider); 282 if (fastTrack->mVolumeProvider == NULL) { 283 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, 284 (void *)0x1000); 285 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, 286 (void *)0x1000); 287 } 288 if (fastTrack->mSampleRate != 0 && 289 fastTrack->mSampleRate != sampleRate) { 290 mixer->setParameter(name, AudioMixer::RESAMPLE, 291 AudioMixer::SAMPLE_RATE, (void*) fastTrack->mSampleRate); 292 } else { 293 mixer->setParameter(name, AudioMixer::RESAMPLE, 294 AudioMixer::REMOVE, NULL); 295 } 296 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, 297 (void *) fastTrack->mChannelMask); 298 // already enabled 299 } 300 generations[i] = fastTrack->mGeneration; 301 } 302 } 303 304 fastTracksGen = current->mFastTracksGen; 305 306 dumpState->mNumTracks = popcount(currentTrackMask); 307 } 308 309#if 1 // FIXME shouldn't need this 310 // only process state change once 311 previous = current; 312#endif 313 } 314 315 // do work using current state here 316 if ((command & FastMixerState::MIX) && (mixer != NULL)) { 317 ALOG_ASSERT(mixBuffer != NULL); 318 // update volumes 319 unsigned volumeTracks = current->mTrackMask; 320 while (volumeTracks != 0) { 321 i = __builtin_ctz(volumeTracks); 322 volumeTracks &= ~(1 << i); 323 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 324 int name = fastTrackNames[i]; 325 ALOG_ASSERT(name >= 0); 326 if (fastTrack->mVolumeProvider != NULL) { 327 uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); 328 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, 329 (void *)(vlr & 0xFFFF)); 330 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, 331 (void *)(vlr >> 16)); 332 } 333 } 334 // process() is CPU-bound 335 mixer->process(AudioBufferProvider::kInvalidPTS); 336 mixBufferState = MIXED; 337 } else if (mixBufferState == MIXED) { 338 mixBufferState = UNDEFINED; 339 } 340 if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) { 341 if (mixBufferState == UNDEFINED) { 342 memset(mixBuffer, 0, frameCount * 2 * sizeof(short)); 343 mixBufferState = ZEROED; 344 } 345 // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink, 346 // but this code should be modified to handle both non-blocking and blocking sinks 347 dumpState->mWriteSequence++; 348 ssize_t framesWritten = outputSink->write(mixBuffer, frameCount); 349 dumpState->mWriteSequence++; 350 if (framesWritten >= 0) { 351 dumpState->mFramesWritten += framesWritten; 352 } else { 353 dumpState->mWriteErrors++; 354 } 355 // FIXME count # of writes blocked excessively, CPU usage, etc. for dump 356 } 357 358 // To be exactly periodic, compute the next sleep time based on current time. 359 // This code doesn't have long-term stability when the sink is non-blocking. 360 // FIXME To avoid drift, use the local audio clock or watch the sink's fill status. 361 struct timespec newTs; 362 int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); 363 if (rc == 0) { 364 if (oldTsValid) { 365 time_t sec = newTs.tv_sec - oldTs.tv_sec; 366 long nsec = newTs.tv_nsec - oldTs.tv_nsec; 367 if (nsec < 0) { 368 --sec; 369 nsec += 1000000000; 370 } 371 if (sec > 0 || nsec > underrunNs) { 372 // FIXME only log occasionally 373 ALOGV("underrun: time since last cycle %d.%03ld sec", 374 (int) sec, nsec / 1000000L); 375 dumpState->mUnderruns++; 376 sleepNs = -1; 377 ignoreNextOverrun = true; 378 } else if (nsec < overrunNs) { 379 if (ignoreNextOverrun) { 380 ignoreNextOverrun = false; 381 } else { 382 // FIXME only log occasionally 383 ALOGV("overrun: time since last cycle %d.%03ld sec", 384 (int) sec, nsec / 1000000L); 385 dumpState->mOverruns++; 386 } 387 sleepNs = periodNs - overrunNs; 388 } else { 389 sleepNs = -1; 390 ignoreNextOverrun = false; 391 } 392#ifdef FAST_MIXER_STATISTICS 393 // long-term statistics 394 cts.sample(sec + nsec * 1e-9); 395 if (cts.n() >= kMaxSamples) { 396 dumpState->mMean = cts.mean(); 397 dumpState->mMinimum = cts.minimum(); 398 dumpState->mMaximum = cts.maximum(); 399 dumpState->mStddev = cts.stddev(); 400 cts.reset(); 401 } 402#endif 403 } else { 404 // first time through the loop 405 oldTsValid = true; 406 sleepNs = periodNs; 407 ignoreNextOverrun = true; 408 } 409 oldTs = newTs; 410 } else { 411 // monotonic clock is broken 412 oldTsValid = false; 413 sleepNs = periodNs; 414 } 415 416 } // for (;;) 417 418 // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion 419} 420 421FastMixerDumpState::FastMixerDumpState() : 422 mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0), 423 mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0), 424 mSampleRate(0), mFrameCount(0) 425#ifdef FAST_MIXER_STATISTICS 426 , mMean(0.0), mMinimum(0.0), mMaximum(0.0), mStddev(0.0) 427#endif 428{ 429} 430 431FastMixerDumpState::~FastMixerDumpState() 432{ 433} 434 435void FastMixerDumpState::dump(int fd) 436{ 437#define COMMAND_MAX 32 438 char string[COMMAND_MAX]; 439 switch (mCommand) { 440 case FastMixerState::INITIAL: 441 strcpy(string, "INITIAL"); 442 break; 443 case FastMixerState::HOT_IDLE: 444 strcpy(string, "HOT_IDLE"); 445 break; 446 case FastMixerState::COLD_IDLE: 447 strcpy(string, "COLD_IDLE"); 448 break; 449 case FastMixerState::EXIT: 450 strcpy(string, "EXIT"); 451 break; 452 case FastMixerState::MIX: 453 strcpy(string, "MIX"); 454 break; 455 case FastMixerState::WRITE: 456 strcpy(string, "WRITE"); 457 break; 458 case FastMixerState::MIX_WRITE: 459 strcpy(string, "MIX_WRITE"); 460 break; 461 default: 462 snprintf(string, COMMAND_MAX, "%d", mCommand); 463 break; 464 } 465 fdprintf(fd, "FastMixer command=%s writeSequence=%u framesWritten=%u\n" 466 " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n" 467 " sampleRate=%u frameCount=%u\n", 468 string, mWriteSequence, mFramesWritten, 469 mNumTracks, mWriteErrors, mUnderruns, mOverruns, 470 mSampleRate, mFrameCount); 471#ifdef FAST_MIXER_STATISTICS 472 fdprintf(fd, " cycle time in ms: mean=%.1f min=%.1f max=%.1f stddev=%.1f\n", 473 mMean*1e3, mMinimum*1e3, mMaximum*1e3, mStddev*1e3); 474#endif 475} 476 477} // namespace android 478