diff options
| author | Andy Hung <hunga@google.com> | 2015-06-03 20:30:00 +0000 | 
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2015-06-03 20:31:03 +0000 | 
| commit | 9cf332ca156132931da397bae94b89debb40de10 (patch) | |
| tree | 151b5c652bcd2035d6cd65ec633933bd1634c30f /services/audioflinger | |
| parent | 3f980665acd86698a2f8cfce65ab38a7270a5e97 (diff) | |
| parent | 08fb1743f80437c38b4094070d851ea7f6d485e5 (diff) | |
| download | frameworks_av-9cf332ca156132931da397bae94b89debb40de10.zip frameworks_av-9cf332ca156132931da397bae94b89debb40de10.tar.gz frameworks_av-9cf332ca156132931da397bae94b89debb40de10.tar.bz2  | |
Merge "Throttle MixerThread data pull to no more than twice expected rate" into mnc-dev
Diffstat (limited to 'services/audioflinger')
| -rw-r--r-- | services/audioflinger/Threads.cpp | 38 | ||||
| -rw-r--r-- | services/audioflinger/Threads.h | 3 | 
2 files changed, 38 insertions, 3 deletions
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 7809eff..dc6710f 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -2191,6 +2191,10 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()      ALOGI("HAL output buffer size %u frames, normal sink buffer size %u frames", mFrameCount,              mNormalFrameCount); +    // Check if we want to throttle the processing to no more than 2x normal rate +    mThreadThrottle = property_get_bool("af.thread.throttle", true /* default_value */); +    mHalfBufferMs = mNormalFrameCount * 1000 / (2 * mSampleRate); +      // mSinkBuffer is the sink buffer.  Size is always multiple-of-16 frames.      // Originally this was int16_t[] array, need to remove legacy implications.      free(mSinkBuffer); @@ -2908,8 +2912,9 @@ bool AudioFlinger::PlaybackThread::threadLoop()          if (!waitingAsyncCallback()) {              // mSleepTimeUs == 0 means we must write to audio hardware              if (mSleepTimeUs == 0) { +                ssize_t ret = 0;                  if (mBytesRemaining) { -                    ssize_t ret = threadLoop_write(); +                    ret = threadLoop_write();                      if (ret < 0) {                          mBytesRemaining = 0;                      } else { @@ -2920,11 +2925,11 @@ bool AudioFlinger::PlaybackThread::threadLoop()                          (mMixerStatus == MIXER_DRAIN_ALL)) {                      threadLoop_drain();                  } -                if (mType == MIXER) { +                if (mType == MIXER && !mStandby) {                      // write blocked detection                      nsecs_t now = systemTime();                      nsecs_t delta = now - mLastWriteTime; -                    if (!mStandby && delta > maxPeriod) { +                    if (delta > maxPeriod) {                          mNumDelayedWrites++;                          if ((now - lastWarning) > kWarningThrottleNs) {                              ATRACE_NAME("underrun"); @@ -2933,6 +2938,31 @@ bool AudioFlinger::PlaybackThread::threadLoop()                              lastWarning = now;                          }                      } + +                    if (mThreadThrottle +                            && mMixerStatus == MIXER_TRACKS_READY // we are mixing (active tracks) +                            && ret > 0) {                         // we wrote something +                        // Limit MixerThread data processing to no more than twice the +                        // expected processing rate. +                        // +                        // This helps prevent underruns with NuPlayer and other applications +                        // which may set up buffers that are close to the minimum size, or use +                        // deep buffers, and rely on a double-buffering sleep strategy to fill. +                        // +                        // The throttle smooths out sudden large data drains from the device, +                        // e.g. when it comes out of standby, which often causes problems with +                        // (1) mixer threads without a fast mixer (which has its own warm-up) +                        // (2) minimum buffer sized tracks (even if the track is full, +                        //     the app won't fill fast enough to handle the sudden draw). + +                        const int32_t deltaMs = delta / 1000000; +                        const int32_t throttleMs = mHalfBufferMs - deltaMs; +                        if ((signed)mHalfBufferMs >= throttleMs && throttleMs > 0) { +                            usleep(throttleMs * 1000); +                            ALOGD("mixer(%p) throttle: ret(%zd) deltaMs(%d) requires sleep %d ms", +                                    this, ret, deltaMs, throttleMs); +                        } +                    }                  }              } else { @@ -4023,6 +4053,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac              }          } else {              if (framesReady < desiredFrames && !track->isStopped() && !track->isPaused()) { +                ALOGV("track(%p) underrun,  framesReady(%zu) < framesDesired(%zd)", +                        track, framesReady, desiredFrames);                  track->mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);              }              // clear effect chain input buffer if an active track underruns to avoid sending diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 07c226e..7b4fb14 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -613,6 +613,9 @@ protected:      // updated by readOutputParameters_l()      size_t                          mNormalFrameCount;  // normal mixer and effects +    bool                            mThreadThrottle;     // throttle the thread processing +    uint32_t                        mHalfBufferMs;       // half the buffer size in milliseconds +      void*                           mSinkBuffer;         // frame size aligned sink buffer      // TODO:  | 
