FastMixer.cpp revision 4dd03b5b68dcd8eb5f5ffe2cfe93d26b8f08b848
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// <IMPORTANT_WARNING> 18// Design rules for threadLoop() are given in the comments at section "Fast mixer thread" of 19// StateQueue.h. In particular, avoid library and system calls except at well-known points. 20// The design rules are only for threadLoop(), and don't apply to FastMixerDumpState methods. 21// </IMPORTANT_WARNING> 22 23#define LOG_TAG "FastMixer" 24//#define LOG_NDEBUG 0 25 26#define ATRACE_TAG ATRACE_TAG_AUDIO 27 28#include "Configuration.h" 29#include <time.h> 30#include <utils/Debug.h> 31#include <utils/Log.h> 32#include <utils/Trace.h> 33#include <system/audio.h> 34#ifdef FAST_THREAD_STATISTICS 35#include <cpustats/CentralTendencyStatistics.h> 36#ifdef CPU_FREQUENCY_STATISTICS 37#include <cpustats/ThreadCpuUsage.h> 38#endif 39#endif 40#include <audio_utils/format.h> 41#include "AudioMixer.h" 42#include "FastMixer.h" 43 44#define FCC_2 2 // fixed channel count assumption 45 46namespace android { 47 48/*static*/ const FastMixerState FastMixer::sInitial; 49 50FastMixer::FastMixer() : FastThread(), 51 mSlopNs(0), 52 // mFastTrackNames 53 // mGenerations 54 mOutputSink(NULL), 55 mOutputSinkGen(0), 56 mMixer(NULL), 57 mSinkBuffer(NULL), 58 mSinkBufferSize(0), 59 mSinkChannelCount(FCC_2), 60 mMixerBuffer(NULL), 61 mMixerBufferSize(0), 62 mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT), 63 mMixerBufferState(UNDEFINED), 64 mFormat(Format_Invalid), 65 mSampleRate(0), 66 mFastTracksGen(0), 67 mTotalNativeFramesWritten(0), 68 // timestamp 69 mNativeFramesWrittenButNotPresented(0) // the = 0 is to silence the compiler 70{ 71 // FIXME pass sInitial as parameter to base class constructor, and make it static local 72 mPrevious = &sInitial; 73 mCurrent = &sInitial; 74 75 mDummyDumpState = &mDummyFastMixerDumpState; 76 // TODO: Add channel mask to NBAIO_Format. 77 // We assume that the channel mask must be a valid positional channel mask. 78 mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount); 79 80 unsigned i; 81 for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) { 82 mFastTrackNames[i] = -1; 83 mGenerations[i] = 0; 84 } 85#ifdef FAST_THREAD_STATISTICS 86 mOldLoad.tv_sec = 0; 87 mOldLoad.tv_nsec = 0; 88#endif 89} 90 91FastMixer::~FastMixer() 92{ 93} 94 95FastMixerStateQueue* FastMixer::sq() 96{ 97 return &mSQ; 98} 99 100const FastThreadState *FastMixer::poll() 101{ 102 return mSQ.poll(); 103} 104 105void FastMixer::setLog(NBLog::Writer *logWriter) 106{ 107 if (mMixer != NULL) { 108 mMixer->setLog(logWriter); 109 } 110} 111 112void FastMixer::onIdle() 113{ 114 mPreIdle = *(const FastMixerState *)mCurrent; 115 mCurrent = &mPreIdle; 116} 117 118void FastMixer::onExit() 119{ 120 delete mMixer; 121 free(mMixerBuffer); 122 free(mSinkBuffer); 123} 124 125bool FastMixer::isSubClassCommand(FastThreadState::Command command) 126{ 127 switch ((FastMixerState::Command) command) { 128 case FastMixerState::MIX: 129 case FastMixerState::WRITE: 130 case FastMixerState::MIX_WRITE: 131 return true; 132 default: 133 return false; 134 } 135} 136 137void FastMixer::onStateChange() 138{ 139 const FastMixerState * const current = (const FastMixerState *) mCurrent; 140 const FastMixerState * const previous = (const FastMixerState *) mPrevious; 141 FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState; 142 const size_t frameCount = current->mFrameCount; 143 144 // handle state change here, but since we want to diff the state, 145 // we're prepared for previous == &sInitial the first time through 146 unsigned previousTrackMask; 147 148 // check for change in output HAL configuration 149 NBAIO_Format previousFormat = mFormat; 150 if (current->mOutputSinkGen != mOutputSinkGen) { 151 mOutputSink = current->mOutputSink; 152 mOutputSinkGen = current->mOutputSinkGen; 153 if (mOutputSink == NULL) { 154 mFormat = Format_Invalid; 155 mSampleRate = 0; 156 mSinkChannelCount = 0; 157 mSinkChannelMask = AUDIO_CHANNEL_NONE; 158 } else { 159 mFormat = mOutputSink->format(); 160 mSampleRate = Format_sampleRate(mFormat); 161 mSinkChannelCount = Format_channelCount(mFormat); 162 LOG_ALWAYS_FATAL_IF(mSinkChannelCount > AudioMixer::MAX_NUM_CHANNELS); 163 164 // TODO: Add channel mask to NBAIO_Format 165 // We assume that the channel mask must be a valid positional channel mask. 166 mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount); 167 } 168 dumpState->mSampleRate = mSampleRate; 169 } 170 171 if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) { 172 // FIXME to avoid priority inversion, don't delete here 173 delete mMixer; 174 mMixer = NULL; 175 free(mMixerBuffer); 176 mMixerBuffer = NULL; 177 free(mSinkBuffer); 178 mSinkBuffer = NULL; 179 if (frameCount > 0 && mSampleRate > 0) { 180 // FIXME new may block for unbounded time at internal mutex of the heap 181 // implementation; it would be better to have normal mixer allocate for us 182 // to avoid blocking here and to prevent possible priority inversion 183 mMixer = new AudioMixer(frameCount, mSampleRate, FastMixerState::kMaxFastTracks); 184 const size_t mixerFrameSize = mSinkChannelCount 185 * audio_bytes_per_sample(mMixerBufferFormat); 186 mMixerBufferSize = mixerFrameSize * frameCount; 187 (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize); 188 const size_t sinkFrameSize = mSinkChannelCount 189 * audio_bytes_per_sample(mFormat.mFormat); 190 if (sinkFrameSize > mixerFrameSize) { // need a sink buffer 191 mSinkBufferSize = sinkFrameSize * frameCount; 192 (void)posix_memalign(&mSinkBuffer, 32, mSinkBufferSize); 193 } 194 mPeriodNs = (frameCount * 1000000000LL) / mSampleRate; // 1.00 195 mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate; // 1.75 196 mOverrunNs = (frameCount * 500000000LL) / mSampleRate; // 0.50 197 mForceNs = (frameCount * 950000000LL) / mSampleRate; // 0.95 198 mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate; // 0.75 199 mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate; // 1.25 200 } else { 201 mPeriodNs = 0; 202 mUnderrunNs = 0; 203 mOverrunNs = 0; 204 mForceNs = 0; 205 mWarmupNsMin = 0; 206 mWarmupNsMax = LONG_MAX; 207 } 208 mMixerBufferState = UNDEFINED; 209#if !LOG_NDEBUG 210 for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) { 211 mFastTrackNames[i] = -1; 212 } 213#endif 214 // we need to reconfigure all active tracks 215 previousTrackMask = 0; 216 mFastTracksGen = current->mFastTracksGen - 1; 217 dumpState->mFrameCount = frameCount; 218 } else { 219 previousTrackMask = previous->mTrackMask; 220 } 221 222 // check for change in active track set 223 const unsigned currentTrackMask = current->mTrackMask; 224 dumpState->mTrackMask = currentTrackMask; 225 if (current->mFastTracksGen != mFastTracksGen) { 226 ALOG_ASSERT(mMixerBuffer != NULL); 227 int name; 228 229 // process removed tracks first to avoid running out of track names 230 unsigned removedTracks = previousTrackMask & ~currentTrackMask; 231 while (removedTracks != 0) { 232 int i = __builtin_ctz(removedTracks); 233 removedTracks &= ~(1 << i); 234 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 235 ALOG_ASSERT(fastTrack->mBufferProvider == NULL); 236 if (mMixer != NULL) { 237 name = mFastTrackNames[i]; 238 ALOG_ASSERT(name >= 0); 239 mMixer->deleteTrackName(name); 240 } 241#if !LOG_NDEBUG 242 mFastTrackNames[i] = -1; 243#endif 244 // don't reset track dump state, since other side is ignoring it 245 mGenerations[i] = fastTrack->mGeneration; 246 } 247 248 // now process added tracks 249 unsigned addedTracks = currentTrackMask & ~previousTrackMask; 250 while (addedTracks != 0) { 251 int i = __builtin_ctz(addedTracks); 252 addedTracks &= ~(1 << i); 253 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 254 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 255 ALOG_ASSERT(bufferProvider != NULL && mFastTrackNames[i] == -1); 256 if (mMixer != NULL) { 257 name = mMixer->getTrackName(fastTrack->mChannelMask, 258 fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX); 259 ALOG_ASSERT(name >= 0); 260 mFastTrackNames[i] = name; 261 mMixer->setBufferProvider(name, bufferProvider); 262 mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, 263 (void *)mMixerBuffer); 264 // newly allocated track names default to full scale volume 265 mMixer->setParameter( 266 name, 267 AudioMixer::TRACK, 268 AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat); 269 mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT, 270 (void *)(uintptr_t)fastTrack->mFormat); 271 mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, 272 (void *)(uintptr_t)fastTrack->mChannelMask); 273 mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, 274 (void *)(uintptr_t)mSinkChannelMask); 275 mMixer->enable(name); 276 } 277 mGenerations[i] = fastTrack->mGeneration; 278 } 279 280 // finally process (potentially) modified tracks; these use the same slot 281 // but may have a different buffer provider or volume provider 282 unsigned modifiedTracks = currentTrackMask & previousTrackMask; 283 while (modifiedTracks != 0) { 284 int i = __builtin_ctz(modifiedTracks); 285 modifiedTracks &= ~(1 << i); 286 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 287 if (fastTrack->mGeneration != mGenerations[i]) { 288 // this track was actually modified 289 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 290 ALOG_ASSERT(bufferProvider != NULL); 291 if (mMixer != NULL) { 292 name = mFastTrackNames[i]; 293 ALOG_ASSERT(name >= 0); 294 mMixer->setBufferProvider(name, bufferProvider); 295 if (fastTrack->mVolumeProvider == NULL) { 296 float f = AudioMixer::UNITY_GAIN_FLOAT; 297 mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f); 298 mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f); 299 } 300 mMixer->setParameter(name, AudioMixer::RESAMPLE, 301 AudioMixer::REMOVE, NULL); 302 mMixer->setParameter( 303 name, 304 AudioMixer::TRACK, 305 AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat); 306 mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT, 307 (void *)(uintptr_t)fastTrack->mFormat); 308 mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, 309 (void *)(uintptr_t)fastTrack->mChannelMask); 310 mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, 311 (void *)(uintptr_t)mSinkChannelMask); 312 // already enabled 313 } 314 mGenerations[i] = fastTrack->mGeneration; 315 } 316 } 317 318 mFastTracksGen = current->mFastTracksGen; 319 320 dumpState->mNumTracks = popcount(currentTrackMask); 321 } 322} 323 324void FastMixer::onWork() 325{ 326 const FastMixerState * const current = (const FastMixerState *) mCurrent; 327 FastMixerDumpState * const dumpState = (FastMixerDumpState *) mDumpState; 328 const FastMixerState::Command command = mCommand; 329 const size_t frameCount = current->mFrameCount; 330 331 if ((command & FastMixerState::MIX) && (mMixer != NULL) && mIsWarm) { 332 ALOG_ASSERT(mMixerBuffer != NULL); 333 // for each track, update volume and check for underrun 334 unsigned currentTrackMask = current->mTrackMask; 335 while (currentTrackMask != 0) { 336 int i = __builtin_ctz(currentTrackMask); 337 currentTrackMask &= ~(1 << i); 338 const FastTrack* fastTrack = ¤t->mFastTracks[i]; 339 340 // Refresh the per-track timestamp 341 if (mTimestampStatus == NO_ERROR) { 342 uint32_t trackFramesWrittenButNotPresented = 343 mNativeFramesWrittenButNotPresented; 344 uint32_t trackFramesWritten = fastTrack->mBufferProvider->framesReleased(); 345 // Can't provide an AudioTimestamp before first frame presented, 346 // or during the brief 32-bit wraparound window 347 if (trackFramesWritten >= trackFramesWrittenButNotPresented) { 348 AudioTimestamp perTrackTimestamp; 349 perTrackTimestamp.mPosition = 350 trackFramesWritten - trackFramesWrittenButNotPresented; 351 perTrackTimestamp.mTime = mTimestamp.mTime; 352 fastTrack->mBufferProvider->onTimestamp(perTrackTimestamp); 353 } 354 } 355 356 int name = mFastTrackNames[i]; 357 ALOG_ASSERT(name >= 0); 358 if (fastTrack->mVolumeProvider != NULL) { 359 gain_minifloat_packed_t vlr = fastTrack->mVolumeProvider->getVolumeLR(); 360 float vlf = float_from_gain(gain_minifloat_unpack_left(vlr)); 361 float vrf = float_from_gain(gain_minifloat_unpack_right(vlr)); 362 363 mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf); 364 mMixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &vrf); 365 } 366 // FIXME The current implementation of framesReady() for fast tracks 367 // takes a tryLock, which can block 368 // up to 1 ms. If enough active tracks all blocked in sequence, this would result 369 // in the overall fast mix cycle being delayed. Should use a non-blocking FIFO. 370 size_t framesReady = fastTrack->mBufferProvider->framesReady(); 371 if (ATRACE_ENABLED()) { 372 // I wish we had formatted trace names 373 char traceName[16]; 374 strcpy(traceName, "fRdy"); 375 traceName[4] = i + (i < 10 ? '0' : 'A' - 10); 376 traceName[5] = '\0'; 377 ATRACE_INT(traceName, framesReady); 378 } 379 FastTrackDump *ftDump = &dumpState->mTracks[i]; 380 FastTrackUnderruns underruns = ftDump->mUnderruns; 381 if (framesReady < frameCount) { 382 if (framesReady == 0) { 383 underruns.mBitFields.mEmpty++; 384 underruns.mBitFields.mMostRecent = UNDERRUN_EMPTY; 385 mMixer->disable(name); 386 } else { 387 // allow mixing partial buffer 388 underruns.mBitFields.mPartial++; 389 underruns.mBitFields.mMostRecent = UNDERRUN_PARTIAL; 390 mMixer->enable(name); 391 } 392 } else { 393 underruns.mBitFields.mFull++; 394 underruns.mBitFields.mMostRecent = UNDERRUN_FULL; 395 mMixer->enable(name); 396 } 397 ftDump->mUnderruns = underruns; 398 ftDump->mFramesReady = framesReady; 399 } 400 401 int64_t pts; 402 if (mOutputSink == NULL || (OK != mOutputSink->getNextWriteTimestamp(&pts))) { 403 pts = AudioBufferProvider::kInvalidPTS; 404 } 405 406 // process() is CPU-bound 407 mMixer->process(pts); 408 mMixerBufferState = MIXED; 409 } else if (mMixerBufferState == MIXED) { 410 mMixerBufferState = UNDEFINED; 411 } 412 //bool didFullWrite = false; // dumpsys could display a count of partial writes 413 if ((command & FastMixerState::WRITE) && (mOutputSink != NULL) && (mMixerBuffer != NULL)) { 414 if (mMixerBufferState == UNDEFINED) { 415 memset(mMixerBuffer, 0, mMixerBufferSize); 416 mMixerBufferState = ZEROED; 417 } 418 void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer; 419 if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format 420 memcpy_by_audio_format(buffer, mFormat.mFormat, mMixerBuffer, mMixerBufferFormat, 421 frameCount * Format_channelCount(mFormat)); 422 } 423 // if non-NULL, then duplicate write() to this non-blocking sink 424 NBAIO_Sink* teeSink; 425 if ((teeSink = current->mTeeSink) != NULL) { 426 (void) teeSink->write(buffer, frameCount); 427 } 428 // FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink, 429 // but this code should be modified to handle both non-blocking and blocking sinks 430 dumpState->mWriteSequence++; 431 ATRACE_BEGIN("write"); 432 ssize_t framesWritten = mOutputSink->write(buffer, frameCount); 433 ATRACE_END(); 434 dumpState->mWriteSequence++; 435 if (framesWritten >= 0) { 436 ALOG_ASSERT((size_t) framesWritten <= frameCount); 437 mTotalNativeFramesWritten += framesWritten; 438 dumpState->mFramesWritten = mTotalNativeFramesWritten; 439 //if ((size_t) framesWritten == frameCount) { 440 // didFullWrite = true; 441 //} 442 } else { 443 dumpState->mWriteErrors++; 444 } 445 mAttemptedWrite = true; 446 // FIXME count # of writes blocked excessively, CPU usage, etc. for dump 447 448 mTimestampStatus = mOutputSink->getTimestamp(mTimestamp); 449 if (mTimestampStatus == NO_ERROR) { 450 uint32_t totalNativeFramesPresented = mTimestamp.mPosition; 451 if (totalNativeFramesPresented <= mTotalNativeFramesWritten) { 452 mNativeFramesWrittenButNotPresented = 453 mTotalNativeFramesWritten - totalNativeFramesPresented; 454 } else { 455 // HAL reported that more frames were presented than were written 456 mTimestampStatus = INVALID_OPERATION; 457 } 458 } 459 } 460} 461 462} // namespace android 463