FastMixer.cpp revision 9bd23229fdec1657398abc682ccccfce1c95f8aa
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 // calling getTrackName with default channel mask 247 name = mixer->getTrackName(AUDIO_CHANNEL_OUT_STEREO); 248 ALOG_ASSERT(name >= 0); 249 fastTrackNames[i] = name; 250 mixer->setBufferProvider(name, bufferProvider); 251 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, 252 (void *) mixBuffer); 253 // newly allocated track names default to full scale volume 254 mixer->enable(name); 255 } 256 generations[i] = fastTrack->mGeneration; 257 } 258 259 // finally process modified tracks; these use the same slot 260 // but may have a different buffer provider or volume provider 261 unsigned modifiedTracks = currentTrackMask & previousTrackMask; 262 while (modifiedTracks != 0) { 263 i = __builtin_ctz(modifiedTracks); 264 modifiedTracks &= ~(1 << i); 265 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 266 if (fastTrack->mGeneration != generations[i]) { 267 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 268 ALOG_ASSERT(bufferProvider != NULL); 269 if (mixer != NULL) { 270 name = fastTrackNames[i]; 271 ALOG_ASSERT(name >= 0); 272 mixer->setBufferProvider(name, bufferProvider); 273 if (fastTrack->mVolumeProvider == NULL) { 274 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, 275 (void *)0x1000); 276 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, 277 (void *)0x1000); 278 } 279 // already enabled 280 } 281 generations[i] = fastTrack->mGeneration; 282 } 283 } 284 285 fastTracksGen = current->mFastTracksGen; 286 287 dumpState->mNumTracks = popcount(currentTrackMask); 288 } 289 290#if 1 // FIXME shouldn't need this 291 // only process state change once 292 previous = current; 293#endif 294 } 295 296 // do work using current state here 297 if ((command & FastMixerState::MIX) && (mixer != NULL)) { 298 ALOG_ASSERT(mixBuffer != NULL); 299 // update volumes 300 unsigned volumeTracks = current->mTrackMask; 301 while (volumeTracks != 0) { 302 i = __builtin_ctz(volumeTracks); 303 volumeTracks &= ~(1 << i); 304 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 305 int name = fastTrackNames[i]; 306 ALOG_ASSERT(name >= 0); 307 if (fastTrack->mVolumeProvider != NULL) { 308 uint32_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); 309 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, 310 (void *)(vlr & 0xFFFF)); 311 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, 312 (void *)(vlr >> 16)); 313 } 314 } 315 // process() is CPU-bound 316 mixer->process(AudioBufferProvider::kInvalidPTS); 317 mixBufferState = MIXED; 318 } else if (mixBufferState == MIXED) { 319 mixBufferState = UNDEFINED; 320 } 321 if ((command & FastMixerState::WRITE) && (outputSink != NULL) && (mixBuffer != NULL)) { 322 if (mixBufferState == UNDEFINED) { 323 memset(mixBuffer, 0, frameCount * 2 * sizeof(short)); 324 mixBufferState = ZEROED; 325 } 326 // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink, 327 // but this code should be modified to handle both non-blocking and blocking sinks 328 dumpState->mWriteSequence++; 329 ssize_t framesWritten = outputSink->write(mixBuffer, frameCount); 330 dumpState->mWriteSequence++; 331 if (framesWritten >= 0) { 332 dumpState->mFramesWritten += framesWritten; 333 } else { 334 dumpState->mWriteErrors++; 335 } 336 // FIXME count # of writes blocked excessively, CPU usage, etc. for dump 337 } 338 339 // To be exactly periodic, compute the next sleep time based on current time. 340 // This code doesn't have long-term stability when the sink is non-blocking. 341 // FIXME To avoid drift, use the local audio clock or watch the sink's fill status. 342 struct timespec newTs; 343 int rc = clock_gettime(CLOCK_MONOTONIC, &newTs); 344 if (rc == 0) { 345 if (oldTsValid) { 346 time_t sec = newTs.tv_sec - oldTs.tv_sec; 347 long nsec = newTs.tv_nsec - oldTs.tv_nsec; 348 if (nsec < 0) { 349 --sec; 350 nsec += 1000000000; 351 } 352 if (sec > 0 || nsec > underrunNs) { 353 // FIXME only log occasionally 354 ALOGV("underrun: time since last cycle %d.%03ld sec", 355 (int) sec, nsec / 1000000L); 356 dumpState->mUnderruns++; 357 sleepNs = -1; 358 ignoreNextOverrun = true; 359 } else if (nsec < overrunNs) { 360 if (ignoreNextOverrun) { 361 ignoreNextOverrun = false; 362 } else { 363 // FIXME only log occasionally 364 ALOGV("overrun: time since last cycle %d.%03ld sec", 365 (int) sec, nsec / 1000000L); 366 dumpState->mOverruns++; 367 } 368 sleepNs = periodNs - overrunNs; 369 } else { 370 sleepNs = -1; 371 ignoreNextOverrun = false; 372 } 373#ifdef FAST_MIXER_STATISTICS 374 // long-term statistics 375 cts.sample(sec + nsec * 1e-9); 376 if (cts.n() >= kMaxSamples) { 377 dumpState->mMean = cts.mean(); 378 dumpState->mMinimum = cts.minimum(); 379 dumpState->mMaximum = cts.maximum(); 380 dumpState->mStddev = cts.stddev(); 381 cts.reset(); 382 } 383#endif 384 } else { 385 // first time through the loop 386 oldTsValid = true; 387 sleepNs = periodNs; 388 ignoreNextOverrun = true; 389 } 390 oldTs = newTs; 391 } else { 392 // monotonic clock is broken 393 oldTsValid = false; 394 sleepNs = periodNs; 395 } 396 397 } // for (;;) 398 399 // never return 'true'; Thread::_threadLoop() locks mutex which can result in priority inversion 400} 401 402FastMixerDumpState::FastMixerDumpState() : 403 mCommand(FastMixerState::INITIAL), mWriteSequence(0), mFramesWritten(0), 404 mNumTracks(0), mWriteErrors(0), mUnderruns(0), mOverruns(0) 405#ifdef FAST_MIXER_STATISTICS 406 , mMean(0.0), mMinimum(0.0), mMaximum(0.0), mStddev(0.0) 407#endif 408{ 409} 410 411FastMixerDumpState::~FastMixerDumpState() 412{ 413} 414 415void FastMixerDumpState::dump(int fd) 416{ 417#define COMMAND_MAX 32 418 char string[COMMAND_MAX]; 419 switch (mCommand) { 420 case FastMixerState::INITIAL: 421 strcpy(string, "INITIAL"); 422 break; 423 case FastMixerState::HOT_IDLE: 424 strcpy(string, "HOT_IDLE"); 425 break; 426 case FastMixerState::COLD_IDLE: 427 strcpy(string, "COLD_IDLE"); 428 break; 429 case FastMixerState::EXIT: 430 strcpy(string, "EXIT"); 431 break; 432 case FastMixerState::MIX: 433 strcpy(string, "MIX"); 434 break; 435 case FastMixerState::WRITE: 436 strcpy(string, "WRITE"); 437 break; 438 case FastMixerState::MIX_WRITE: 439 strcpy(string, "MIX_WRITE"); 440 break; 441 default: 442 snprintf(string, COMMAND_MAX, "%d", mCommand); 443 break; 444 } 445 fdprintf(fd, "FastMixer command=%s writeSequence=%u framesWritten=%u\n" 446 " numTracks=%u writeErrors=%u underruns=%u overruns=%u\n", 447 string, mWriteSequence, mFramesWritten, 448 mNumTracks, mWriteErrors, mUnderruns, mOverruns); 449#ifdef FAST_MIXER_STATISTICS 450 fdprintf(fd, " cycle time in ms: mean=%.1f min=%.1f max=%.1f stddev=%.1f\n", 451 mMean*1e3, mMinimum*1e3, mMaximum*1e3, mStddev*1e3); 452#endif 453} 454 455} // namespace android 456