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

Commit 6100d2d6 authored by Eric Laurent's avatar Eric Laurent
Browse files

Issue 2265163: Audio still reported routed through earpiece on sholes

This is a second attempt to fix the audio routed to earpiece syndrom.
The root cause identified this time is the crash of an application having an active AudioTrack playing on the VOICE_CALL stream type.
When this happens, the AudioTrack destructor is not called and the audio policy manager is not notified of the track stop.
Results a situation where the VOICE_CALL stream is considered as always in use by audio policy manager which makes that audio is routed to earpiece.

The fix consists in moving the track start/stop/close notification to audio policiy manager from AudioTrack to AudioFlinger Track objet.
The net result is that in the case of a client application crash, the AudioFlinger TrackHandle object (which implements the remote side of the IAudioTrack binder interface) destructor is called which in turn destroys the Track object and we can notify the audio policy manager of the track stop and removal.

The same modification is made for AudioRecord although no bug related to record has been reported yet.
Also fixed a potential problem if record stop is called while the record thread is exiting.
parent 583892d0
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -268,7 +268,7 @@ public:
     * Returned value:
     *  handle on audio hardware input
     */
            audio_io_handle_t    getInput() { return mInput; }
            audio_io_handle_t    getInput();

    /* obtains a buffer of "frameCount" frames. The buffer must be
     * filled entirely. If the track is stopped, obtainBuffer() returns
@@ -318,7 +318,8 @@ private:
                                int format,
                                int channelCount,
                                int frameCount,
                                uint32_t flags);
                                uint32_t flags,
                                audio_io_handle_t input);

    sp<IAudioRecord>        mAudioRecord;
    sp<IMemory>             mCblkMemory;
@@ -345,8 +346,8 @@ private:
    bool                    mMarkerReached;
    uint32_t                mNewPosition;
    uint32_t                mUpdatePeriod;
    audio_io_handle_t       mInput;
    uint32_t                mFlags;
    uint32_t                mChannels;
};

}; // namespace android
+39 −31
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ namespace android {
// ---------------------------------------------------------------------------

AudioRecord::AudioRecord()
    : mStatus(NO_INIT), mInput(0)
    : mStatus(NO_INIT)
{
}

@@ -60,7 +60,7 @@ AudioRecord::AudioRecord(
        callback_t cbf,
        void* user,
        int notificationFrames)
    : mStatus(NO_INIT), mInput(0)
    : mStatus(NO_INIT)
{
    mStatus = set(inputSource, sampleRate, format, channels,
            frameCount, flags, cbf, user, notificationFrames);
@@ -79,7 +79,6 @@ AudioRecord::~AudioRecord()
        }
        mAudioRecord.clear();
        IPCThreadState::self()->flushCommands();
        AudioSystem::releaseInput(mInput);
    }
}

@@ -123,9 +122,9 @@ status_t AudioRecord::set(
    }
    int channelCount = AudioSystem::popCount(channels);

    mInput = AudioSystem::getInput(inputSource,
    audio_io_handle_t input = AudioSystem::getInput(inputSource,
                                    sampleRate, format, channels, (AudioSystem::audio_in_acoustics)flags);
    if (mInput == 0) {
    if (input == 0) {
        LOGE("Could not get audio output for stream type %d", inputSource);
        return BAD_VALUE;
    }
@@ -168,7 +167,7 @@ status_t AudioRecord::set(

    // create the IAudioRecord
    status_t status = openRecord(sampleRate, format, channelCount,
                                 frameCount, flags);
                                 frameCount, flags, input);

    if (status != NO_ERROR) {
        return status;
@@ -187,6 +186,7 @@ status_t AudioRecord::set(
    // Update buffer size in case it has been limited by AudioFlinger during track creation
    mFrameCount = mCblk->frameCount;
    mChannelCount = (uint8_t)channelCount;
    mChannels = channels;
    mActive = 0;
    mCbf = cbf;
    mNotificationFrames = notificationFrames;
@@ -265,13 +265,14 @@ status_t AudioRecord::start()
     }

    if (android_atomic_or(1, &mActive) == 0) {
        ret = AudioSystem::startInput(mInput);
        if (ret == NO_ERROR) {
        ret = mAudioRecord->start();
        if (ret == DEAD_OBJECT) {
            LOGV("start() dead IAudioRecord: creating a new one");
            ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount,
                        mFrameCount, mFlags);
                    mFrameCount, mFlags, getInput());
            if (ret == NO_ERROR) {
                ret = mAudioRecord->start();
            }
        }
        if (ret == NO_ERROR) {
            mNewPosition = mCblk->user + mUpdatePeriod;
@@ -284,11 +285,9 @@ status_t AudioRecord::start()
            }
        } else {
            LOGV("start() failed");
                AudioSystem::stopInput(mInput);
            android_atomic_and(~1, &mActive);
        }
    }
    }

    if (t != 0) {
        t->mLock.unlock();
@@ -318,7 +317,6 @@ status_t AudioRecord::stop()
        } else {
            setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
        }
        AudioSystem::stopInput(mInput);
    }

    if (t != 0) {
@@ -395,7 +393,8 @@ status_t AudioRecord::openRecord(
        int format,
        int channelCount,
        int frameCount,
        uint32_t flags)
        uint32_t flags,
        audio_io_handle_t input)
{
    status_t status;
    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
@@ -403,7 +402,7 @@ status_t AudioRecord::openRecord(
        return NO_INIT;
    }

    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), mInput,
    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,
                                                       sampleRate, format,
                                                       channelCount,
                                                       frameCount,
@@ -425,7 +424,8 @@ status_t AudioRecord::openRecord(
    mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
    mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
    mCblk->out = 0;

    mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
    mCblk->waitTimeMs = 0;
    return NO_ERROR;
}

@@ -466,10 +466,10 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
                    if (result == DEAD_OBJECT) {
                        LOGW("obtainBuffer() dead IAudioRecord: creating a new one");
                        result = openRecord(cblk->sampleRate, mFormat, mChannelCount,
                                            mFrameCount, mFlags);
                                            mFrameCount, mFlags, getInput());
                        if (result == NO_ERROR) {
                            cblk = mCblk;
                            cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
                            mAudioRecord->start();
                        }
                    }
                    cblk->lock.lock();
@@ -516,6 +516,14 @@ void AudioRecord::releaseBuffer(Buffer* audioBuffer)
    cblk->stepUser(audioBuffer->frameCount);
}

audio_io_handle_t AudioRecord::getInput()
{
   return AudioSystem::getInput(mInputSource,
                                mCblk->sampleRate,
                                mFormat, mChannels,
                                (AudioSystem::audio_in_acoustics)mFlags);
}

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

ssize_t AudioRecord::read(void* buffer, size_t userSize)
+10 −12
Original line number Diff line number Diff line
@@ -97,7 +97,6 @@ AudioTrack::~AudioTrack()
        }
        mAudioTrack.clear();
        IPCThreadState::self()->flushCommands();
        AudioSystem::releaseOutput(getOutput());
    }
}

@@ -318,8 +317,6 @@ void AudioTrack::start()
     }

    if (android_atomic_or(1, &mActive) == 0) {
        audio_io_handle_t output = getOutput();
        AudioSystem::startOutput(output, (AudioSystem::stream_type)mStreamType);
        mNewPosition = mCblk->server + mUpdatePeriod;
        mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
        mCblk->waitTimeMs = 0;
@@ -333,10 +330,13 @@ void AudioTrack::start()
        if (status == DEAD_OBJECT) {
            LOGV("start() dead IAudioTrack: creating a new one");
            status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount,
                                 mFrameCount, mFlags, mSharedBuffer, output);
                                 mFrameCount, mFlags, mSharedBuffer, getOutput());
            if (status == NO_ERROR) {
                status = mAudioTrack->start();
                if (status == NO_ERROR) {
                    mNewPosition = mCblk->server + mUpdatePeriod;
            mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
            mCblk->waitTimeMs = 0;
                }
            }
        }
        if (status != NO_ERROR) {
            LOGV("start() failed");
@@ -346,7 +346,6 @@ void AudioTrack::start()
            } else {
                setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
            }
            AudioSystem::stopOutput(output, (AudioSystem::stream_type)mStreamType);
        }
    }

@@ -383,7 +382,6 @@ void AudioTrack::stop()
        } else {
            setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
        }
        AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
    }

    if (t != 0) {
@@ -418,9 +416,7 @@ void AudioTrack::pause()
{
    LOGV("pause");
    if (android_atomic_and(~1, &mActive) == 1) {
        mActive = 0;
        mAudioTrack->pause();
        AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
    }
}

@@ -658,7 +654,8 @@ status_t AudioTrack::createTrack(
    }

    mCblk->volumeLR = (int32_t(int16_t(mVolume[LEFT] * 0x1000)) << 16) | int16_t(mVolume[RIGHT] * 0x1000);

    mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
    mCblk->waitTimeMs = 0;
    return NO_ERROR;
}

@@ -709,6 +706,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
                            if (result == NO_ERROR) {
                                cblk = mCblk;
                                cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
                                mAudioTrack->start();
                            }
                        }
                        cblk->lock.lock();