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

Commit f5aba82c authored by Eric Laurent's avatar Eric Laurent
Browse files

Fix issue 2046140: master: media_server crash when powering down A2DP headset...

Fix issue 2046140: master: media_server crash when powering down A2DP headset while a ringtone is playing.

This is because the AudioFlinger duplicating thread is closed while the output tracks are still active. This cause the output tracks objects to be destroyed at a time where they can be in use by the destination output mixer.

The fix consists in adding the OutputTrack to the track list (mTracks) of its destination thread so that a strong reference is help during the mixer processed and the track is detroyed only when safe by destination thread.

Also added detection of problems when creating the output track (e.g. no more tracks in mixer). In this case the output track is not added to output track list of duplicating thread.
parent 9e7b8194
Loading
Loading
Loading
Loading
+28 −21
Original line number Diff line number Diff line
@@ -1860,9 +1860,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
                         mSuspended) {
                if (!mStandby) {
                    for (size_t i = 0; i < outputTracks.size(); i++) {
                        mLock.unlock();
                        outputTracks[i]->stop();
                        mLock.lock();
                    }
                    mStandby = true;
                    mBytesWritten = 0;
@@ -1903,9 +1901,9 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
            if (!mSuspended) {
                for (size_t i = 0; i < outputTracks.size(); i++) {
                    outputTracks[i]->write(curBuf, mFrameCount);
                    mustSleep = false;
                }
                mStandby = false;
                mustSleep = false;
                mBytesWritten += mixBufferSize;
            }
        } else {
@@ -1935,11 +1933,14 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
        outputTracks.clear();
    }

    { // scope for the mLock

        Mutex::Autolock _l(mLock);
        if (!mStandby) {
        for (size_t i = 0; i < outputTracks.size(); i++) {
            mLock.unlock();
            outputTracks[i]->stop();
            mLock.lock();
            LOGV("DuplicatingThread() exiting out of standby");
            for (size_t i = 0; i < mOutputTracks.size(); i++) {
                mOutputTracks[i]->destroy();
            }
        }
    }

@@ -1957,16 +1958,19 @@ void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
                                            mFormat,
                                            mChannelCount,
                                            frameCount);
    if (outputTrack->cblk() != NULL) {
        thread->setStreamVolume(AudioSystem::NUM_STREAM_TYPES, 1.0f);
        mOutputTracks.add(outputTrack);
        LOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread);
    }
}

void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread)
{
    Mutex::Autolock _l(mLock);
    for (size_t i = 0; i < mOutputTracks.size(); i++) {
        if (mOutputTracks[i]->thread() == (ThreadBase *)thread) {
            mOutputTracks[i]->destroy();
            mOutputTracks.removeAt(i);
            return;
        }
@@ -2456,20 +2460,23 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack(
{

    PlaybackThread *playbackThread = (PlaybackThread *)thread.unsafe_get();
    if (mCblk != NULL) {
        mCblk->out = 1;
        mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
        mCblk->volume[0] = mCblk->volume[1] = 0x1000;
        mOutBuffer.frameCount = 0;
        mWaitTimeMs = (playbackThread->frameCount() * 2 * 1000) / playbackThread->sampleRate();

        playbackThread->mTracks.add(this);
        LOGV("OutputTrack constructor mCblk %p, mBuffer %p, mCblk->buffers %p, mCblk->frameCount %d, mCblk->sampleRate %d, mCblk->channels %d mBufferEnd %p mWaitTimeMs %d",
                mCblk, mBuffer, mCblk->buffers, mCblk->frameCount, mCblk->sampleRate, mCblk->channels, mBufferEnd, mWaitTimeMs);

    } else {
        LOGW("Error creating output track on thread %p", playbackThread);
    }
}

AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack()
{
    stop();
    clearBufferQueue();
}

status_t AudioFlinger::PlaybackThread::OutputTrack::start()
+2 −4
Original line number Diff line number Diff line
@@ -245,6 +245,7 @@ private:
            virtual status_t    start() = 0;
            virtual void        stop() = 0;
                    sp<IMemory> getCblk() const;
                    audio_track_cblk_t* cblk() const { return mCblk; }

        protected:
            friend class ThreadBase;
@@ -260,10 +261,6 @@ private:
            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
            virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);

            audio_track_cblk_t* cblk() const {
                return mCblk;
            }

            int format() const {
                return mFormat;
            }
@@ -528,6 +525,7 @@ private:
    private:

        friend class AudioFlinger;
        friend class OutputTrack;
        friend class Track;
        friend class TrackBase;
        friend class MixerThread;