FastMixer.cpp revision 97b5d0d5b5ef766eb5dd680d05a5d199662d4ae0
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 if (current->mColdGen != coldGen) { 134 int32_t *coldFutexAddr = current->mColdFutexAddr; 135 ALOG_ASSERT(coldFutexAddr != NULL); 136 int32_t old = android_atomic_dec(coldFutexAddr); 137 if (old <= 0) { 138 __futex_syscall4(coldFutexAddr, FUTEX_WAIT_PRIVATE, old - 1, NULL); 139 } 140 sleepNs = -1; 141 coldGen = current->mColdGen; 142 } else { 143 sleepNs = FAST_HOT_IDLE_NS; 144 } 145 continue; 146 case FastMixerState::EXIT: 147 delete mixer; 148 delete[] mixBuffer; 149 return false; 150 case FastMixerState::MIX: 151 case FastMixerState::WRITE: 152 case FastMixerState::MIX_WRITE: 153 break; 154 default: 155 LOG_FATAL("bad command %d", command); 156 } 157 158 // there is a non-idle state available to us; did the state change? 159 size_t frameCount = current->mFrameCount; 160 if (current != previous) { 161 162 // handle state change here, but since we want to diff the state, 163 // we're prepared for previous == &initial the first time through 164 unsigned previousTrackMask; 165 166 // check for change in output HAL configuration 167 NBAIO_Format previousFormat = format; 168 if (current->mOutputSinkGen != outputSinkGen) { 169 outputSink = current->mOutputSink; 170 outputSinkGen = current->mOutputSinkGen; 171 if (outputSink == NULL) { 172 format = Format_Invalid; 173 sampleRate = 0; 174 } else { 175 format = outputSink->format(); 176 sampleRate = Format_sampleRate(format); 177 ALOG_ASSERT(Format_channelCount(format) == 2); 178 } 179 } 180 181 if ((format != previousFormat) || (frameCount != previous->mFrameCount)) { 182 // FIXME to avoid priority inversion, don't delete here 183 delete mixer; 184 mixer = NULL; 185 delete[] mixBuffer; 186 mixBuffer = NULL; 187 if (frameCount > 0 && sampleRate > 0) { 188 // FIXME new may block for unbounded time at internal mutex of the heap 189 // implementation; it would be better to have normal mixer allocate for us 190 // to avoid blocking here and to prevent possible priority inversion 191 mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks); 192 mixBuffer = new short[frameCount * 2]; 193 periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00 194 underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75 195 overrunNs = (frameCount * 250000000LL) / sampleRate; // 0.25 196 } else { 197 periodNs = 0; 198 underrunNs = 0; 199 overrunNs = 0; 200 } 201 mixBufferState = UNDEFINED; 202#if !LOG_NDEBUG 203 for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) { 204 fastTrackNames[i] = -1; 205 } 206#endif 207 // we need to reconfigure all active tracks 208 previousTrackMask = 0; 209 fastTracksGen = current->mFastTracksGen - 1; 210 } else { 211 previousTrackMask = previous->mTrackMask; 212 } 213 214 // check for change in active track set 215 unsigned currentTrackMask = current->mTrackMask; 216 if (current->mFastTracksGen != fastTracksGen) { 217 ALOG_ASSERT(mixBuffer != NULL); 218 int name; 219 220 // process removed tracks first to avoid running out of track names 221 unsigned removedTracks = previousTrackMask & ~currentTrackMask; 222 while (removedTracks != 0) { 223 i = __builtin_ctz(removedTracks); 224 removedTracks &= ~(1 << i); 225 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 226 if (mixer != NULL) { 227 name = fastTrackNames[i]; 228 ALOG_ASSERT(name >= 0); 229 mixer->deleteTrackName(name); 230 } 231#if !LOG_NDEBUG 232 fastTrackNames[i] = -1; 233#endif 234 generations[i] = fastTrack->mGeneration; 235 } 236 237 // now process added tracks 238 unsigned addedTracks = currentTrackMask & ~previousTrackMask; 239 while (addedTracks != 0) { 240 i = __builtin_ctz(addedTracks); 241 addedTracks &= ~(1 << i); 242 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 243 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 244 ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1); 245 if (mixer != NULL) { 246 name = mixer->getTrackName(); 247 ALOG_ASSERT(name >= 0); 248 fastTrackNames[i] = name; 249 mixer->setBufferProvider(name, bufferProvider); 250 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, 251 (void *) mixBuffer); 252 // newly allocated track names default to full scale volume 253 mixer->enable(name); 254 } 255 generations[i] = fastTrack->mGeneration; 256 } 257 258 // finally process modified tracks; these use the same slot 259 // but may have a different buffer provider or volume provider 260 unsigned modifiedTracks = currentTrackMask & previousTrackMask; 261 while (modifiedTracks != 0) { 262 i = __builtin_ctz(modifiedTracks); 263 modifiedTracks &= ~(1 << i); 264 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 265 if (fastTrack->mGeneration != generations[i]) { 266 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 267 ALOG_ASSERT(bufferProvider != NULL); 268 if (mixer != NULL) { 269 name = fastTrackNames[i]; 270 ALOG_ASSERT(name >= 0); 271 mixer->setBufferProvider(name, bufferProvider); 272 if (fastTrack->mVolumeProvider == NULL) { 273 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, 274 (void *)0x1000); 275 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, 276 (void *)0x1000); 277 } 278 // already enabled 279 } 280 generations[i] = fastTrack->mGeneration; 281 } 282 } 283 284 fastTracksGen = current->mFastTracksGen; 285 286 dumpState->mNumTracks = popcount(currentTrackMask); 287 } 288 289#if 1 // FIXME shouldn't need this 290 // only process state change once 291 previous = current; 292#endif 293 } 294 295 // do work using current state here 296 if ((command & FastMixerState::MIX) && (mixer != NULL)) { 297 ALOG_ASSERT(mixBuffer != NULL); 298 // update volumes 299 unsigned volumeTracks = current->mTrackMask; 300 while (volumeTracks != 0) { 301 i = __builtin_ctz(volumeTracks); 302 volumeTracks &= ~(1 << i); 303 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 304 int name = fastTrackNames[i]; 305 ALOG_ASSERT(name >= 0); 306 if (fastTrack->mVolumeProvider != NULL) { 307 uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); 308 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, 309 (void *)(vlr & 0xFFFF)); 310 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, 311 (void *)(vlr >> 16)); 312 } 313 } 314 // process() is CPU-bound 315 mixer->process(AudioBufferProvider::kInvalidPTS); 316 mixBufferState = MIXED; 317 } else if (mixBufferState == MIXED) { 318 mixBufferState = UNDEFINED; 319 } 320 if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) { 321 if (mixBufferState == UNDEFINED) { 322 memset(mixBuffer, 0, frameCount * 2 * sizeof(short)); 323 mixBufferState = ZEROED; 324 } 325 // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink, 326 // but this code should be modified to handle both non-blocking and blocking sinks 327 dumpState->mWriteSequence++; 328 ssize_t framesWritten = outputSink->write(mixBuffer, frameCount); 329 dumpState->mWriteSequence++; 330 if (framesWritten >= 0) { 331 dumpState->mFramesWritten += framesWritten; 332 } else { 333 dumpState->mWriteErrors++; 334 } 335 // FIXME count # of writes blocked excessively, CPU usage, etc. for dump 336 } 337 338 // To be exactly periodic, compute the next sleep time based on current time. 339 // This code doesn't have long-term stability when the sink is non-blocking. 340 // FIXME To avoid drift, use the local audio clock or watch the sink's fill status. 341 struct timespec newTs; 342 int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); 343 if (rc == 0) { 344 if (oldTsValid) { 345 time_t sec = newTs.tv_sec - oldTs.tv_sec; 346 long nsec = newTs.tv_nsec - oldTs.tv_nsec; 347 if (nsec < 0) { 348 --sec; 349 nsec += 1000000000; 350 } 351 if (sec > 0 || nsec > underrunNs) { 352 // FIXME only log occasionally 353 ALOGV("underrun: time since last cycle %d.%03ld sec", 354 (int) sec, nsec / 1000000L); 355 dumpState->mUnderruns++; 356 sleepNs = -1; 357 ignoreNextOverrun = true; 358 } else if (nsec < overrunNs) { 359 if (ignoreNextOverrun) { 360 ignoreNextOverrun = false; 361 } else { 362 // FIXME only log occasionally 363 ALOGV("overrun: time since last cycle %d.%03ld sec", 364 (int) sec, nsec / 1000000L); 365 dumpState->mOverruns++; 366 } 367 sleepNs = periodNs - overrunNs; 368 } else { 369 sleepNs = -1; 370 ignoreNextOverrun = false; 371 } 372#ifdef FAST_MIXER_STATISTICS 373 // long-term statistics 374 cts.sample(sec + nsec * 1e-9); 375 if (cts.n() >= kMaxSamples) { 376 dumpState->mMean = cts.mean(); 377 dumpState->mMinimum = cts.minimum(); 378 dumpState->mMaximum = cts.maximum(); 379 dumpState->mStddev = cts.stddev(); 380 cts.reset(); 381 } 382#endif 383 } else { 384 // first time through the loop 385 oldTsValid = true; 386 sleepNs = periodNs; 387 ignoreNextOverrun = true; 388 } 389 oldTs = newTs; 390 } else { 391 // monotonic clock is broken 392 oldTsValid = false; 393 sleepNs = periodNs; 394 } 395 396 } // for (;;) 397 398 // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion 399} 400 401FastMixerDumpState::FastMixerDumpState() : 402 mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0), 403 mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0) 404#ifdef FAST_MIXER_STATISTICS 405 , mMean(0.0), mMinimum(0.0), mMaximum(0.0), mStddev(0.0) 406#endif 407{ 408} 409 410FastMixerDumpState::~FastMixerDumpState() 411{ 412} 413 414void FastMixerDumpState::dump(int fd) 415{ 416#define COMMAND_MAX 32 417 char string[COMMAND_MAX]; 418 switch (mCommand) { 419 case FastMixerState::INITIAL: 420 strcpy(string, "INITIAL"); 421 break; 422 case FastMixerState::HOT_IDLE: 423 strcpy(string, "HOT_IDLE"); 424 break; 425 case FastMixerState::COLD_IDLE: 426 strcpy(string, "COLD_IDLE"); 427 break; 428 case FastMixerState::EXIT: 429 strcpy(string, "EXIT"); 430 break; 431 case FastMixerState::MIX: 432 strcpy(string, "MIX"); 433 break; 434 case FastMixerState::WRITE: 435 strcpy(string, "WRITE"); 436 break; 437 case FastMixerState::MIX_WRITE: 438 strcpy(string, "MIX_WRITE"); 439 break; 440 default: 441 snprintf(string, COMMAND_MAX, "%d", mCommand); 442 break; 443 } 444 fdprintf(fd, "FastMixer command=%s writeSequence=%u framesWritten=%u\n" 445 " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n", 446 string, mWriteSequence, mFramesWritten, 447 mNumTracks, mWriteErrors, mUnderruns, mOverruns); 448#ifdef FAST_MIXER_STATISTICS 449 fdprintf(fd, " cycle time in ms: mean=%.1f min=%.1f max=%.1f stddev=%.1f\n", 450 mMean*1e3, mMinimum*1e3, mMaximum*1e3, mStddev*1e3); 451#endif 452} 453 454} // namespace android 455