Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b9987ad0 authored by Eric Laurent's avatar Eric Laurent Committed by android-build-merger
Browse files

Merge "audioflinger: various offload playback fixes" into nyc-dev

am: 8b43838c

* commit '8b43838c':
  audioflinger: various offload playback fixes

Change-Id: I1954e445630309c039ade92e545479245de095be
parents ee776534 8b43838c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2150,7 +2150,7 @@ void MediaPlayerService::AudioOutput::CallbackWrapper(
        //
        // The underrun event is sent once per track underrun; the condition is reset
        // when more data is sent to the AudioTrack.
        ALOGI("callbackwrapper: EVENT_UNDERRUN (discarded)");
        ALOGD("callbackwrapper: EVENT_UNDERRUN (discarded)");
        break;

    default:
+1 −2
Original line number Diff line number Diff line
@@ -1847,8 +1847,7 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_

        PlaybackThread *thread;
        if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
            thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady,
                                       config->offload_info.bit_rate);
            thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
            ALOGV("openOutput_l() created offload output: ID %d thread %p", *output, thread);
        } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
                || !isValidPcmSinkFormat(config->format)
+58 −102
Original line number Diff line number Diff line
@@ -110,12 +110,7 @@ static const int8_t kMaxTrackStartupRetries = 50;
// direct outputs can be a scarce resource in audio hardware and should
// be released as quickly as possible.
static const int8_t kMaxTrackRetriesDirect = 2;
// retry count before removing active track in case of underrun on offloaded thread:
// we need to make sure that AudioTrack client has enough time to send large buffers
//FIXME may be more appropriate if expressed in time units. Need to revise how underrun is handled
// for offloaded tracks
static const int8_t kMaxTrackRetriesOffload = 10;
static const int8_t kMaxTrackStartupRetriesOffload = 100;



// don't warn about blocked writes or record buffer overflows more often than this
@@ -148,10 +143,6 @@ static const nsecs_t kOffloadStandbyDelayNs = seconds(1);
// Direct output thread minimum sleep time in idle or active(underrun) state
static const nsecs_t kDirectMinSleepTimeUs = 10000;

// Offloaded output bit rate in bits per second when unknown.
// Used for sleep time calculation, so use a high default bitrate to be conservative on sleep time.
static const uint32_t kOffloadDefaultBitRateBps = 1500000;


// Whether to use fast mixer
static const enum {
@@ -1567,8 +1558,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
                                             audio_io_handle_t id,
                                             audio_devices_t device,
                                             type_t type,
                                             bool systemReady,
                                             uint32_t bitRate)
                                             bool systemReady)
    :   ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type, systemReady),
        mNormalFrameCount(0), mSinkBuffer(NULL),
        mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
@@ -1631,13 +1621,6 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
        mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream);
        mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);
    }

    if (audio_has_proportional_frames(mFormat)) {
        mBufferDurationUs = (uint32_t)((mNormalFrameCount * 1000000LL) / mSampleRate);
    } else {
        bitRate = bitRate != 0 ? bitRate : kOffloadDefaultBitRateBps;
        mBufferDurationUs = (uint32_t)((mBufferSize * 8 * 1000000LL) / bitRate);
    }
}

AudioFlinger::PlaybackThread::~PlaybackThread()
@@ -2049,12 +2032,18 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)

        // set retry count for buffer fill
        if (track->isOffloaded()) {
            if (track->isStopping_1()) {
                track->mRetryCount = kMaxTrackStopRetriesOffload;
            } else {
                track->mRetryCount = kMaxTrackStartupRetriesOffload;
            }
            track->mFillingUpStatus = mStandby ? Track::FS_FILLING : Track::FS_FILLED;
        } else {
            track->mRetryCount = kMaxTrackStartupRetries;
            track->mFillingUpStatus =
                    track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING;
        }

        track->mFillingUpStatus = track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING;
        track->mResetDone = false;
        track->mPresentationCompleteFrames = 0;
        mActiveTracks.add(track);
@@ -3181,32 +3170,9 @@ bool AudioFlinger::PlaybackThread::threadLoop()

            } else {
                ATRACE_BEGIN("sleep");
                if ((mType == OFFLOAD) && !audio_has_proportional_frames(mFormat)) {
                Mutex::Autolock _l(mLock);
                    if (!mSignalPending && !exitPending()) {
                        // If more than one buffer has been written to the audio HAL since exiting
                        // standby or last flush, do not sleep more than one buffer duration
                        // since last write and not less than kDirectMinSleepTimeUs.
                        // Wake up if a command is received
                        uint32_t timeoutUs = mSleepTimeUs;
                        if (mBytesWritten >= (int64_t) mBufferSize) {
                            nsecs_t now = systemTime();
                            uint32_t deltaUs = (uint32_t)((now - mLastWriteTime) / 1000);
                            if (timeoutUs + deltaUs > mBufferDurationUs) {
                                if (mBufferDurationUs > deltaUs) {
                                    timeoutUs = mBufferDurationUs - deltaUs;
                                    if (timeoutUs < kDirectMinSleepTimeUs) {
                                        timeoutUs = kDirectMinSleepTimeUs;
                                    }
                                } else {
                                    timeoutUs = kDirectMinSleepTimeUs;
                                }
                            }
                        }
                        mWaitWorkCV.waitRelative(mLock, microseconds((nsecs_t)timeoutUs));
                    }
                } else {
                    usleep(mSleepTimeUs);
                if (!mSignalPending && mConfigEvents.isEmpty() && !exitPending()) {
                    mWaitWorkCV.waitRelative(mLock, microseconds((nsecs_t)mSleepTimeUs));
                }
                ATRACE_END();
            }
@@ -4592,17 +4558,16 @@ void AudioFlinger::MixerThread::cacheParameters_l()
// ----------------------------------------------------------------------------

AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady,
        uint32_t bitRate)
    :   PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady, bitRate)
        AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady)
    :   PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady)
        // mLeftVolFloat, mRightVolFloat
{
}

AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
        AudioStreamOut* output, audio_io_handle_t id, uint32_t device,
        ThreadBase::type_t type, bool systemReady, uint32_t bitRate)
    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady, bitRate)
        ThreadBase::type_t type, bool systemReady)
    :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
        // mLeftVolFloat, mRightVolFloat
{
}
@@ -4908,14 +4873,7 @@ void AudioFlinger::DirectOutputThread::threadLoop_sleepTime()
    }
    if (mSleepTimeUs == 0) {
        if (mMixerStatus == MIXER_TRACKS_ENABLED) {
            // For compressed offload, use faster sleep time when underruning until more than an
            // entire buffer was written to the audio HAL
            if (!audio_has_proportional_frames(mFormat) &&
                    (mType == OFFLOAD) && (mBytesWritten < (int64_t) mBufferSize)) {
                mSleepTimeUs = kDirectMinSleepTimeUs;
            } else {
            mSleepTimeUs = mActiveSleepTimeUs;
            }
        } else {
            mSleepTimeUs = mIdleSleepTimeUs;
        }
@@ -5187,9 +5145,8 @@ void AudioFlinger::AsyncCallbackThread::resetDraining()

// ----------------------------------------------------------------------------
AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
        AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady,
        uint32_t bitRate)
    :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady, bitRate),
        AudioStreamOut* output, audio_io_handle_t id, uint32_t device, bool systemReady)
    :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD, systemReady),
        mPausedWriteLength(0), mPausedBytesRemaining(0), mKeepWakeLock(true)
{
    //FIXME: mStandby should be set to true by ThreadBase constructor
@@ -5273,7 +5230,11 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
            }
            tracksToRemove->add(track);
        } else if (track->isFlushPending()) {
            if (track->isStopping_1()) {
                track->mRetryCount = kMaxTrackStopRetriesOffload;
            } else {
                track->mRetryCount = kMaxTrackRetriesOffload;
            }
            track->flushAck();
            if (last) {
                mFlushPending = true;
@@ -5334,13 +5295,18 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
                }
                mPreviousTrack = track;
                // reset retry count
                if (track->isStopping_1()) {
                    track->mRetryCount = kMaxTrackStopRetriesOffload;
                } else {
                    track->mRetryCount = kMaxTrackRetriesOffload;
                }
                mActiveTrack = t;
                mixerStatus = MIXER_TRACKS_READY;
            }
        } else {
            ALOGVV("OffloadThread: track %d s=%08x [NOT READY]", track->name(), cblk->mServer);
            if (track->isStopping_1()) {
                if (--(track->mRetryCount) <= 0) {
                    // Hardware buffer can hold a large amount of audio so we must
                    // wait for all current track's data to drain before we say
                    // that the track is stopped.
@@ -5348,8 +5314,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
                        // Only start draining when all data in mixbuffer
                        // has been written
                        ALOGV("OffloadThread: underrun and STOPPING_1 -> draining, STOPPING_2");
                    track->mState = TrackBase::STOPPING_2; // so presentation completes after drain
                    // do not drain if no data was ever sent to HAL (mStandby == true)
                        track->mState = TrackBase::STOPPING_2; // so presentation completes after
                        // drain do not drain if no data was ever sent to HAL (mStandby == true)
                        if (last && !mStandby) {
                            // do not modify drain sequence if we are already draining. This happens
                            // when resuming from pause after drain.
@@ -5367,6 +5333,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::OffloadThread::prepareTr
                            }
                        }
                    }
                } else if (last) {
                    ALOGV("stopping1 underrun retries left %d", track->mRetryCount);
                    mixerStatus = MIXER_TRACKS_ENABLED;
                }
            } else if (track->isStopping_2()) {
                // Drain has completed or we are in standby, signal presentation complete
                if (!(mDrainSequence & 1) || !last || mStandby) {
@@ -5456,20 +5426,6 @@ void AudioFlinger::OffloadThread::flushHw_l()
    }
}

uint32_t AudioFlinger::OffloadThread::activeSleepTimeUs() const
{
    uint32_t time;
    if (audio_has_proportional_frames(mFormat)) {
        time = PlaybackThread::activeSleepTimeUs();
    } else {
        // sleep time is half the duration of an audio HAL buffer.
        // Note: This can be problematic in case of underrun with variable bit rate and
        // current rate is much less than initial rate.
        time = (uint32_t)max(kDirectMinSleepTimeUs, mBufferDurationUs / 2);
    }
    return time;
}

void AudioFlinger::OffloadThread::invalidateTracks(audio_stream_type_t streamType)
{
    Mutex::Autolock _l(mLock);
+12 −11
Original line number Diff line number Diff line
@@ -486,9 +486,16 @@ public:
        // suspend by audio policy manager is orthogonal to mixer state
    };

    // retry count before removing active track in case of underrun on offloaded thread:
    // we need to make sure that AudioTrack client has enough time to send large buffers
    //FIXME may be more appropriate if expressed in time units. Need to revise how underrun is
    // handled for offloaded tracks
    static const int8_t kMaxTrackRetriesOffload = 20;
    static const int8_t kMaxTrackStartupRetriesOffload = 100;
    static const int8_t kMaxTrackStopRetriesOffload = 2;

    PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
                   audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady,
                   uint32_t bitRate = 0);
                   audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady);
    virtual             ~PlaybackThread();

                void        dump(int fd, const Vector<String16>& args);
@@ -843,8 +850,6 @@ protected:
                bool        mHwSupportsPause;
                bool        mHwPaused;
                bool        mFlushPending;
                uint32_t    mBufferDurationUs;      // estimated duration of an audio HAL buffer
                                                    // based on initial bit rate (offload only)
};

class MixerThread : public PlaybackThread {
@@ -935,8 +940,7 @@ class DirectOutputThread : public PlaybackThread {
public:

    DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
                       audio_io_handle_t id, audio_devices_t device, bool systemReady,
                       uint32_t bitRate = 0);
                       audio_io_handle_t id, audio_devices_t device, bool systemReady);
    virtual                 ~DirectOutputThread();

    // Thread virtuals
@@ -969,7 +973,7 @@ protected:

    DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
                        audio_io_handle_t id, uint32_t device, ThreadBase::type_t type,
                        bool systemReady, uint32_t bitRate = 0);
                        bool systemReady);
    void processVolume_l(Track *track, bool lastTrack);

    // prepareTracks_l() tells threadLoop_mix() the name of the single active track
@@ -985,8 +989,7 @@ class OffloadThread : public DirectOutputThread {
public:

    OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
                        audio_io_handle_t id, uint32_t device,
                        bool systemReady, uint32_t bitRate);
                        audio_io_handle_t id, uint32_t device, bool systemReady);
    virtual                 ~OffloadThread() {};
    virtual     void        flushHw_l();

@@ -995,8 +998,6 @@ protected:
    virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
    virtual     void        threadLoop_exit();

    virtual     uint32_t    activeSleepTimeUs() const;

    virtual     bool        waitingAsyncCallback();
    virtual     bool        waitingAsyncCallback_l();
    virtual     void        invalidateTracks(audio_stream_type_t streamType);
+4 −1
Original line number Diff line number Diff line
@@ -373,7 +373,7 @@ AudioFlinger::PlaybackThread::Track::Track(
    // client == 0 implies sharedBuffer == 0
    ALOG_ASSERT(!(client == 0 && sharedBuffer != 0));

    ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(),
    ALOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %zu", sharedBuffer->pointer(),
            sharedBuffer->size());

    if (mCblk == NULL) {
@@ -728,6 +728,9 @@ void AudioFlinger::PlaybackThread::Track::stop()
                // For an offloaded track this starts a drain and state will
                // move to STOPPING_2 when drain completes and then STOPPED
                mState = STOPPING_1;
                if (isOffloaded()) {
                    mRetryCount = PlaybackThread::kMaxTrackStopRetriesOffload;
                }
            }
            playbackThread->broadcast_l();
            ALOGV("not stopping/stopped => stopping/stopped (%d) on thread %p", mName,