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

Commit 85aca658 authored by Eric Laurent's avatar Eric Laurent Committed by Android Git Automerger
Browse files

am d33712d7: am 145cf5d8: Merge "audioflinger: implement pause/resume for...

am d33712d7: am 145cf5d8: Merge "audioflinger: implement pause/resume for direct outputs" into lmp-mr1-dev

* commit 'd33712d7':
  audioflinger: implement pause/resume for direct outputs
parents 22dfb932 d33712d7
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -335,6 +335,11 @@ status_t AudioTrack::set(
                ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST);
    }

    // force direct flag if HW A/V sync requested
    if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) {
        flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT);
    }

    if (flags & AUDIO_OUTPUT_FLAG_DIRECT) {
        if (audio_is_linear_pcm(format)) {
            mFrameSize = channelCount * audio_bytes_per_sample(format);
+106 −21
Original line number Diff line number Diff line
@@ -1197,6 +1197,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
        mScreenState(AudioFlinger::mScreenState),
        // index 0 is reserved for normal mixer's submix
        mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1),
        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
        // mLatchD, mLatchQ,
        mLatchDValid(false), mLatchQValid(false)
{
@@ -1847,6 +1848,19 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
        }
    }

    mHwSupportsPause = false;
    if (mOutput->flags & AUDIO_OUTPUT_FLAG_DIRECT) {
        if (mOutput->stream->pause != NULL) {
            if (mOutput->stream->resume != NULL) {
                mHwSupportsPause = true;
            } else {
                ALOGW("direct output implements pause but not resume");
            }
        } else if (mOutput->stream->resume != NULL) {
            ALOGW("direct output implements resume but not pause");
        }
    }

    // Calculate size of normal sink buffer relative to the HAL output buffer size
    double multiplier = 1.0;
    if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
@@ -3078,6 +3092,7 @@ void AudioFlinger::PlaybackThread::threadLoop_standby()
        mCallbackThread->setWriteBlocked(mWriteAckSequence);
        mCallbackThread->setDraining(mDrainSequence);
    }
    mHwPaused = false;
}

void AudioFlinger::PlaybackThread::onAddNewTrack_l()
@@ -3990,6 +4005,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
{
    size_t count = mActiveTracks.size();
    mixer_state mixerStatus = MIXER_IDLE;
    bool doHwPause = false;
    bool doHwResume = false;
    bool flushPending = false;

    // find out which tracks need to be processed
    for (size_t i = 0; i < count; i++) {
@@ -4008,6 +4026,28 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
        sp<Track> l = mLatestActiveTrack.promote();
        bool last = l.get() == track;

        if (mHwSupportsPause && track->isPausing()) {
            track->setPaused();
            if (last && !mHwPaused) {
                doHwPause = true;
                mHwPaused = true;
            }
            tracksToRemove->add(track);
        } else if (track->isFlushPending()) {
            track->flushAck();
            if (last) {
                flushPending = true;
            }
        } else if (mHwSupportsPause && track->isResumePending()){
            track->resumeAck();
            if (last) {
                if (mHwPaused) {
                    doHwResume = true;
                    mHwPaused = false;
                }
            }
        }

        // The first time a track is added we wait
        // for all its buffers to be filled before processing it.
        // Allow draining the buffer in case the client
@@ -4031,8 +4071,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
                track->mFillingUpStatus = Track::FS_ACTIVE;
                // make sure processVolume_l() will apply new volume even if 0
                mLeftVolFloat = mRightVolFloat = -1.0;
                if (track->mState == TrackBase::RESUMING) {
                    track->mState = TrackBase::ACTIVE;
                if (!mHwSupportsPause) {
                    track->resumeAck();
                }
            }

@@ -4095,6 +4135,30 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep
        }
    }

    // if an active track did not command a flush, check for pending flush on stopped tracks
    if (!flushPending) {
        for (size_t i = 0; i < mTracks.size(); i++) {
            if (mTracks[i]->isFlushPending()) {
                mTracks[i]->flushAck();
                flushPending = true;
            }
        }
    }

    // make sure the pause/flush/resume sequence is executed in the right order.
    // If a flush is pending and a track is active but the HW is not paused, force a HW pause
    // before flush and then resume HW. This can happen in case of pause/flush/resume
    // if resume is received before pause is executed.
    if (mHwSupportsPause && !mStandby &&
            (doHwPause || (flushPending && !mHwPaused && (count != 0)))) {
        mOutput->stream->pause(mOutput->stream);
    }
    if (flushPending) {
        flushHw_l();
    }
    if (mHwSupportsPause && !mStandby && doHwResume) {
        mOutput->stream->resume(mOutput->stream);
    }
    // remove all the tracks that need to be...
    removeTracks_l(*tracksToRemove);

@@ -4127,6 +4191,11 @@ void AudioFlinger::DirectOutputThread::threadLoop_mix()

void AudioFlinger::DirectOutputThread::threadLoop_sleepTime()
{
    // do not write to HAL when paused
    if (mHwPaused) {
        sleepTime = idleSleepTime;
        return;
    }
    if (sleepTime == 0) {
        if (mMixerStatus == MIXER_TRACKS_ENABLED) {
            sleepTime = activeSleepTime;
@@ -4139,6 +4208,38 @@ void AudioFlinger::DirectOutputThread::threadLoop_sleepTime()
    }
}

void AudioFlinger::DirectOutputThread::threadLoop_exit()
{
    {
        Mutex::Autolock _l(mLock);
        bool flushPending = false;
        for (size_t i = 0; i < mTracks.size(); i++) {
            if (mTracks[i]->isFlushPending()) {
                mTracks[i]->flushAck();
                flushPending = true;
            }
        }
        if (flushPending) {
            flushHw_l();
        }
    }
    PlaybackThread::threadLoop_exit();
}

// must be called with thread mutex locked
bool AudioFlinger::DirectOutputThread::shouldStandby_l()
{
    bool trackPaused = false;

    // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack
    // after a timeout and we will enter standby then.
    if (mTracks.size() > 0) {
        trackPaused = mTracks[mTracks.size() - 1]->isPaused();
    }

    return !mStandby && !trackPaused;
}

// getTrackName_l() must be called with ThreadBase::mLock held
int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused,
        audio_format_t format __unused, int sessionId __unused)
@@ -4248,9 +4349,11 @@ void AudioFlinger::DirectOutputThread::cacheParameters_l()

void AudioFlinger::DirectOutputThread::flushHw_l()
{
    if (mOutput->stream->flush != NULL)
    if (mOutput->stream->flush != NULL) {
        mOutput->stream->flush(mOutput->stream);
    }
    mHwPaused = false;
}

// ----------------------------------------------------------------------------

@@ -4358,8 +4461,6 @@ void AudioFlinger::AsyncCallbackThread::resetDraining()
AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger,
        AudioStreamOut* output, audio_io_handle_t id, uint32_t device)
    :   DirectOutputThread(audioFlinger, output, id, device, OFFLOAD),
        mHwPaused(false),
        mFlushPending(false),
        mPausedBytesRemaining(0)
{
    //FIXME: mStandby should be set to true by ThreadBase constructor
@@ -4596,21 +4697,6 @@ bool AudioFlinger::OffloadThread::waitingAsyncCallback_l()
    return false;
}

// must be called with thread mutex locked
bool AudioFlinger::OffloadThread::shouldStandby_l()
{
    bool trackPaused = false;

    // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack
    // after a timeout and we will enter standby then.
    if (mTracks.size() > 0) {
        trackPaused = mTracks[mTracks.size() - 1]->isPaused();
    }

    return !mStandby && !trackPaused;
}


bool AudioFlinger::OffloadThread::waitingAsyncCallback()
{
    Mutex::Autolock _l(mLock);
@@ -4625,7 +4711,6 @@ void AudioFlinger::OffloadThread::flushHw_l()
    mBytesRemaining = 0;
    mPausedWriteLength = 0;
    mPausedBytesRemaining = 0;
    mHwPaused = false;

    if (mUseAsyncWrite) {
        // discard any pending drain or write ack by incrementing sequence
+5 −4
Original line number Diff line number Diff line
@@ -809,7 +809,9 @@ public:
protected:
                // accessed by both binder threads and within threadLoop(), lock on mutex needed
                unsigned    mFastTrackAvailMask;    // bit i set if fast track [i] is available

                bool        mHwSupportsPause;
                bool        mHwPaused;
                bool        mFlushPending;
private:
    // timestamp latch:
    //  D input is written by threadLoop_write while mutex is unlocked, and read while locked
@@ -910,6 +912,8 @@ protected:
    virtual     mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
    virtual     void        threadLoop_mix();
    virtual     void        threadLoop_sleepTime();
    virtual     void        threadLoop_exit();
    virtual     bool        shouldStandby_l();

    // volumes last sent to audio HAL with stream->set_volume()
    float mLeftVolFloat;
@@ -940,12 +944,9 @@ protected:

    virtual     bool        waitingAsyncCallback();
    virtual     bool        waitingAsyncCallback_l();
    virtual     bool        shouldStandby_l();
    virtual     void        onAddNewTrack_l();

private:
    bool        mHwPaused;
    bool        mFlushPending;
    size_t      mPausedWriteLength;     // length in bytes of write interrupted by pause
    size_t      mPausedBytesRemaining;  // bytes still waiting in mixbuffer after resume
    wp<Track>   mPreviousTrack;         // used to detect track switch
+4 −5
Original line number Diff line number Diff line
@@ -823,12 +823,11 @@ void AudioFlinger::PlaybackThread::Track::flush()
            // this will be done by prepareTracks_l() when the track is stopped.
            // prepareTracks_l() will see mState == FLUSHED, then
            // remove from active track list, reset(), and trigger presentation complete
            if (isDirect()) {
                mFlushHwPending = true;
            }
            if (playbackThread->mActiveTracks.indexOf(this) < 0) {
                reset();
                if (thread->type() == ThreadBase::DIRECT) {
                    DirectOutputThread *t = (DirectOutputThread *)playbackThread;
                    t->flushHw_l();
                }
            }
        }
        // Prevent flush being lost if the track is flushed and then resumed
@@ -841,7 +840,7 @@ void AudioFlinger::PlaybackThread::Track::flush()
// must be called with thread lock held
void AudioFlinger::PlaybackThread::Track::flushAck()
{
    if (!isOffloaded())
    if (!isOffloaded() && !isDirect())
        return;

    mFlushHwPending = false;