FastMixer.cpp revision d2123e631834a887c2d8600c3ac43dda02d47cb9
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_MIXER_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::initial; 49 50FastMixer::FastMixer() : FastThread(), 51 slopNs(0), 52 // fastTrackNames 53 // generations 54 outputSink(NULL), 55 outputSinkGen(0), 56 mixer(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 format(Format_Invalid), 65 sampleRate(0), 66 fastTracksGen(0), 67 totalNativeFramesWritten(0), 68 // timestamp 69 nativeFramesWrittenButNotPresented(0) // the = 0 is to silence the compiler 70{ 71 // FIXME pass initial as parameter to base class constructor, and make it static local 72 previous = &initial; 73 current = &initial; 74 75 mDummyDumpState = &dummyDumpState; 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 fastTrackNames[i] = -1; 83 generations[i] = 0; 84 } 85#ifdef FAST_MIXER_STATISTICS 86 oldLoad.tv_sec = 0; 87 oldLoad.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 (mixer != NULL) { 108 mixer->setLog(logWriter); 109 } 110} 111 112void FastMixer::onIdle() 113{ 114 preIdle = *(const FastMixerState *)current; 115 current = &preIdle; 116} 117 118void FastMixer::onExit() 119{ 120 delete mixer; 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 *) this->current; 140 const FastMixerState * const previous = (const FastMixerState *) this->previous; 141 FastMixerDumpState * const dumpState = (FastMixerDumpState *) this->dumpState; 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 == &initial the first time through 146 unsigned previousTrackMask; 147 148 // check for change in output HAL configuration 149 NBAIO_Format previousFormat = format; 150 if (current->mOutputSinkGen != outputSinkGen) { 151 outputSink = current->mOutputSink; 152 outputSinkGen = current->mOutputSinkGen; 153 if (outputSink == NULL) { 154 format = Format_Invalid; 155 sampleRate = 0; 156 mSinkChannelCount = 0; 157 mSinkChannelMask = AUDIO_CHANNEL_NONE; 158 } else { 159 format = outputSink->format(); 160 sampleRate = Format_sampleRate(format); 161 mSinkChannelCount = Format_channelCount(format); 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 = sampleRate; 169 } 170 171 if ((!Format_isEqual(format, previousFormat)) || (frameCount != previous->mFrameCount)) { 172 // FIXME to avoid priority inversion, don't delete here 173 delete mixer; 174 mixer = NULL; 175 free(mMixerBuffer); 176 mMixerBuffer = NULL; 177 free(mSinkBuffer); 178 mSinkBuffer = NULL; 179 if (frameCount > 0 && sampleRate > 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 mixer = new AudioMixer(frameCount, sampleRate, 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(format.mFormat); 190 if (sinkFrameSize > mixerFrameSize) { // need a sink buffer 191 mSinkBufferSize = sinkFrameSize * frameCount; 192 (void)posix_memalign(&mSinkBuffer, 32, mSinkBufferSize); 193 } 194 periodNs = (frameCount * 1000000000LL) / sampleRate; // 1.00 195 underrunNs = (frameCount * 1750000000LL) / sampleRate; // 1.75 196 overrunNs = (frameCount * 500000000LL) / sampleRate; // 0.50 197 forceNs = (frameCount * 950000000LL) / sampleRate; // 0.95 198 warmupNsMin = (frameCount * 750000000LL) / sampleRate; // 0.75 199 warmupNsMax = (frameCount * 1250000000LL) / sampleRate; // 1.25 200 } else { 201 periodNs = 0; 202 underrunNs = 0; 203 overrunNs = 0; 204 forceNs = 0; 205 warmupNsMin = 0; 206 warmupNsMax = LONG_MAX; 207 } 208 mMixerBufferState = UNDEFINED; 209#if !LOG_NDEBUG 210 for (unsigned i = 0; i < FastMixerState::kMaxFastTracks; ++i) { 211 fastTrackNames[i] = -1; 212 } 213#endif 214 // we need to reconfigure all active tracks 215 previousTrackMask = 0; 216 fastTracksGen = 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 != fastTracksGen) { 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 (mixer != NULL) { 237 name = fastTrackNames[i]; 238 ALOG_ASSERT(name >= 0); 239 mixer->deleteTrackName(name); 240 } 241#if !LOG_NDEBUG 242 fastTrackNames[i] = -1; 243#endif 244 // don't reset track dump state, since other side is ignoring it 245 generations[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 && fastTrackNames[i] == -1); 256 if (mixer != NULL) { 257 name = mixer->getTrackName(fastTrack->mChannelMask, 258 fastTrack->mFormat, AUDIO_SESSION_OUTPUT_MIX); 259 ALOG_ASSERT(name >= 0); 260 fastTrackNames[i] = name; 261 mixer->setBufferProvider(name, bufferProvider); 262 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER, 263 (void *)mMixerBuffer); 264 // newly allocated track names default to full scale volume 265 mixer->setParameter( 266 name, 267 AudioMixer::TRACK, 268 AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat); 269 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT, 270 (void *)(uintptr_t)fastTrack->mFormat); 271 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, 272 (void *)(uintptr_t)fastTrack->mChannelMask); 273 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, 274 (void *)(uintptr_t)mSinkChannelMask); 275 mixer->enable(name); 276 } 277 generations[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 != generations[i]) { 288 // this track was actually modified 289 AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider; 290 ALOG_ASSERT(bufferProvider != NULL); 291 if (mixer != NULL) { 292 name = fastTrackNames[i]; 293 ALOG_ASSERT(name >= 0); 294 mixer->setBufferProvider(name, bufferProvider); 295 if (fastTrack->mVolumeProvider == NULL) { 296 float f = AudioMixer::UNITY_GAIN_FLOAT; 297 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &f); 298 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME1, &f); 299 } 300 mixer->setParameter(name, AudioMixer::RESAMPLE, 301 AudioMixer::REMOVE, NULL); 302 mixer->setParameter( 303 name, 304 AudioMixer::TRACK, 305 AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat); 306 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT, 307 (void *)(uintptr_t)fastTrack->mFormat); 308 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, 309 (void *)(uintptr_t)fastTrack->mChannelMask); 310 mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, 311 (void *)(uintptr_t)mSinkChannelMask); 312 // already enabled 313 } 314 generations[i] = fastTrack->mGeneration; 315 } 316 } 317 318 fastTracksGen = current->mFastTracksGen; 319 320 dumpState->mNumTracks = popcount(currentTrackMask); 321 } 322} 323 324void FastMixer::onWork() 325{ 326 const FastMixerState * const current = (const FastMixerState *) this->current; 327 FastMixerDumpState * const dumpState = (FastMixerDumpState *) this->dumpState; 328 const FastMixerState::Command command = this->command; 329 const size_t frameCount = current->mFrameCount; 330 331 if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) { 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 (timestampStatus == NO_ERROR) { 342 uint32_t trackFramesWrittenButNotPresented = 343 nativeFramesWrittenButNotPresented; 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 = timestamp.mTime; 352 fastTrack->mBufferProvider->onTimestamp(perTrackTimestamp); 353 } 354 } 355 356 int name = fastTrackNames[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 mixer->setParameter(name, AudioMixer::VOLUME, AudioMixer::VOLUME0, &vlf); 364 mixer->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 mixer->disable(name); 386 } else { 387 // allow mixing partial buffer 388 underruns.mBitFields.mPartial++; 389 underruns.mBitFields.mMostRecent = UNDERRUN_PARTIAL; 390 mixer->enable(name); 391 } 392 } else { 393 underruns.mBitFields.mFull++; 394 underruns.mBitFields.mMostRecent = UNDERRUN_FULL; 395 mixer->enable(name); 396 } 397 ftDump->mUnderruns = underruns; 398 ftDump->mFramesReady = framesReady; 399 } 400 401 int64_t pts; 402 if (outputSink == NULL || (OK != outputSink->getNextWriteTimestamp(&pts))) { 403 pts = AudioBufferProvider::kInvalidPTS; 404 } 405 406 // process() is CPU-bound 407 mixer->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) && (outputSink != 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 (format.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format 420 memcpy_by_audio_format(buffer, format.mFormat, mMixerBuffer, mMixerBufferFormat, 421 frameCount * Format_channelCount(format)); 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 = outputSink->write(buffer, frameCount); 433 ATRACE_END(); 434 dumpState->mWriteSequence++; 435 if (framesWritten >= 0) { 436 ALOG_ASSERT((size_t) framesWritten <= frameCount); 437 totalNativeFramesWritten += framesWritten; 438 dumpState->mFramesWritten = totalNativeFramesWritten; 439 //if ((size_t) framesWritten == frameCount) { 440 // didFullWrite = true; 441 //} 442 } else { 443 dumpState->mWriteErrors++; 444 } 445 attemptedWrite = true; 446 // FIXME count # of writes blocked excessively, CPU usage, etc. for dump 447 448 timestampStatus = outputSink->getTimestamp(timestamp); 449 if (timestampStatus == NO_ERROR) { 450 uint32_t totalNativeFramesPresented = timestamp.mPosition; 451 if (totalNativeFramesPresented <= totalNativeFramesWritten) { 452 nativeFramesWrittenButNotPresented = 453 totalNativeFramesWritten - totalNativeFramesPresented; 454 } else { 455 // HAL reported that more frames were presented than were written 456 timestampStatus = INVALID_OPERATION; 457 } 458 } 459 } 460} 461 462} // namespace android 463