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

Commit 2774144f authored by Eric Laurent's avatar Eric Laurent
Browse files

AudioFlinger: mix track only when really ready (2)

This problem due to the way audio buffers are mixed when
low power mode is active was addressed by commits 19ddf0eb
and 8a04fe03 but only partially. As a matter of fact, when more
than one audio track is playing, the problem is still present.
This is most noticeable when playing music with screen off
and a notification or navigation instruction is played: in this case,
the music or notification is likely to skip.

The fix consists in declaring the mixer ready if all active tracks
are ready. Previous behavior was to declare ready if at least one track was
ready. To avoid that one application failing to fill the track buffer blocks other
tracks indefinitely, this condition is respected only if the mixer was ready
in the previous round.

Issue 5799167.

Change-Id: Iabd4ca08d3d45f563d9824c8a03c2c68a43ae179
parent 86d24aa3
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -1832,7 +1832,7 @@ uint32_t AudioFlinger::PlaybackThread::activeSleepTimeUs()

AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
    :   PlaybackThread(audioFlinger, output, id, device),
        mAudioMixer(0)
        mAudioMixer(0), mPrevMixerStatus(MIXER_IDLE)
{
    mType = ThreadBase::MIXER;
    mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
@@ -1945,6 +1945,7 @@ bool AudioFlinger::MixerThread::threadLoop()
                    LOGV("MixerThread %p TID %d waking up\n", this, gettid());
                    acquireWakeLock_l();

                    mPrevMixerStatus = MIXER_IDLE;
                    if (mMasterMute == false) {
                        char value[PROPERTY_VALUE_MAX];
                        property_get("ro.audio.silent", value, "0");
@@ -2103,11 +2104,11 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track
        // make sure that we have enough frames to mix one full buffer.
        // enforce this condition only once to enable draining the buffer in case the client
        // app does not call stop() and relies on underrun to stop:
        // hence the test on (track->mRetryCount >= kMaxTrackRetries) meaning the track was mixed
        // hence the test on (mPrevMixerStatus == MIXER_TRACKS_READY) meaning the track was mixed
        // during last round
        uint32_t minFrames = 1;
        if (!track->isStopped() && !track->isPausing() &&
                (track->mRetryCount >= kMaxTrackRetries)) {
                (mPrevMixerStatus == MIXER_TRACKS_READY)) {
            if (t->sampleRate() == (int)mSampleRate) {
                minFrames = mFrameCount;
            } else {
@@ -2229,7 +2230,13 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track

            // reset retry count
            track->mRetryCount = kMaxTrackRetries;
            // If one track is ready, set the mixer ready if:
            //  - the mixer was not ready during previous round OR
            //  - no other track is not ready
            if (mPrevMixerStatus != MIXER_TRACKS_READY ||
                    mixerStatus != MIXER_TRACKS_ENABLED) {
                mixerStatus = MIXER_TRACKS_READY;
            }
        } else {
            //LOGV("track %d u=%08x, s=%08x [NOT READY] on thread %p", track->name(), cblk->user, cblk->server, this);
            if (track->isStopped()) {
@@ -2247,7 +2254,11 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track
                    tracksToRemove->add(track);
                    // indicate to client process that the track was disabled because of underrun
                    android_atomic_or(CBLK_DISABLED_ON, &cblk->flags);
                } else if (mixerStatus != MIXER_TRACKS_READY) {
                // If one track is not ready, mark the mixer also not ready if:
                //  - the mixer was ready during previous round OR
                //  - no other track is ready
                } else if (mPrevMixerStatus == MIXER_TRACKS_READY ||
                                mixerStatus != MIXER_TRACKS_READY) {
                    mixerStatus = MIXER_TRACKS_ENABLED;
                }
            }
@@ -2281,6 +2292,7 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track
        memset(mMixBuffer, 0, mFrameCount * mChannelCount * sizeof(int16_t));
    }

    mPrevMixerStatus = mixerStatus;
    return mixerStatus;
}

@@ -3016,6 +3028,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
                    LOGV("DuplicatingThread %p TID %d waking up\n", this, gettid());
                    acquireWakeLock_l();

                    mPrevMixerStatus = MIXER_IDLE;
                    if (mMasterMute == false) {
                        char value[PROPERTY_VALUE_MAX];
                        property_get("ro.audio.silent", value, "0");
+3 −1
Original line number Diff line number Diff line
@@ -837,6 +837,8 @@ private:
        virtual     uint32_t    suspendSleepTimeUs();

                    AudioMixer* mAudioMixer;
                    uint32_t    mPrevMixerStatus; // previous status (mixer_state) returned by
                                                  // prepareTracks_l()
    };

    class DirectOutputThread : public PlaybackThread {