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

Commit 9e9a95b3 authored by Phil Burk's avatar Phil Burk
Browse files

aaudio: fix race condition in requestStart()

Set callback enable flag before starting AudioTrack callback.

Bug: 72115512
Test: Repeat:  adb shell write_sine_callback -pn -s4
Test: 20 times and make sure framesWritten is advancing.
Change-Id: I670fde46da0dccf8a6d03478fe2aa8b7ad596a3b
parent 87b46795
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -86,10 +86,15 @@ void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode
            // AudioRecord::Buffer
            // TODO define our own AudioBuffer and pass it from the subclasses.
            AudioTrack::Buffer *audioBuffer = static_cast<AudioTrack::Buffer *>(info);
            if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED || !mCallbackEnabled.load()) {
            if (getState() == AAUDIO_STREAM_STATE_DISCONNECTED) {
                ALOGW("processCallbackCommon() data, stream disconnected");
                audioBuffer->size = SIZE_STOP_CALLBACKS;
            } else if (!mCallbackEnabled.load()) {
                ALOGW("processCallbackCommon() stopping because callback disabled");
                audioBuffer->size = SIZE_STOP_CALLBACKS;
            } else {
                if (audioBuffer->frameCount == 0) {
                    ALOGW("processCallbackCommon() data, frameCount is zero");
                    return;
                }

@@ -106,7 +111,7 @@ void AudioStreamLegacy::processCallbackCommon(aaudio_callback_operation_t opcode
                if (callbackResult == AAUDIO_CALLBACK_RESULT_CONTINUE) {
                    audioBuffer->size = audioBuffer->frameCount * getBytesPerFrame();
                } else { // STOP or invalid result
                    ALOGW("%s() stop stream by faking an error", __func__);
                    ALOGW("%s() callback requested stop, fake an error", __func__);
                    audioBuffer->size = SIZE_STOP_CALLBACKS;
                    // Disable the callback just in case AudioFlinger keeps trying to call us.
                    mCallbackEnabled.store(false);
+0 −3
Original line number Diff line number Diff line
@@ -121,9 +121,6 @@ protected:

    void forceDisconnect(bool errorCallbackEnabled = true);

    void onStart() { mCallbackEnabled.store(true); }
    void onStop() { mCallbackEnabled.store(false); }

    int64_t incrementFramesWritten(int32_t frames) {
        return mFramesWritten.increment(frames);
    }
+4 −2
Original line number Diff line number Diff line
@@ -234,11 +234,13 @@ aaudio_result_t AudioStreamRecord::requestStart()
        return AAudioConvert_androidToAAudioResult(err);
    }

    // Enable callback before starting AudioTrack to avoid shutting
    // down because of a race condition.
    mCallbackEnabled.store(true);
    err = mAudioRecord->start();
    if (err != OK) {
        return AAudioConvert_androidToAAudioResult(err);
    } else {
        onStart();
        setState(AAUDIO_STREAM_STATE_STARTING);
    }
    return AAUDIO_OK;
@@ -248,11 +250,11 @@ aaudio_result_t AudioStreamRecord::requestStop() {
    if (mAudioRecord.get() == nullptr) {
        return AAUDIO_ERROR_INVALID_STATE;
    }
    onStop();
    setState(AAUDIO_STREAM_STATE_STOPPING);
    incrementFramesWritten(getFramesRead() - getFramesWritten()); // TODO review
    mTimestampPosition.set(getFramesRead());
    mAudioRecord->stop();
    mCallbackEnabled.store(false);
    mFramesRead.reset32();
    mTimestampPosition.reset32();
    // Pass false to prevent errorCallback from being called after disconnect
+5 −3
Original line number Diff line number Diff line
@@ -259,11 +259,13 @@ aaudio_result_t AudioStreamTrack::requestStart() {
        return AAudioConvert_androidToAAudioResult(err);
    }

    // Enable callback before starting AudioTrack to avoid shutting
    // down because of a race condition.
    mCallbackEnabled.store(true);
    err = mAudioTrack->start();
    if (err != OK) {
        return AAudioConvert_androidToAAudioResult(err);
    } else {
        onStart();
        setState(AAUDIO_STREAM_STATE_STARTING);
    }
    return AAUDIO_OK;
@@ -280,9 +282,9 @@ aaudio_result_t AudioStreamTrack::requestPause() {
              AAudio_convertStreamStateToText(getState()));
        return AAUDIO_ERROR_INVALID_STATE;
    }
    onStop();
    setState(AAUDIO_STREAM_STATE_PAUSING);
    mAudioTrack->pause();
    mCallbackEnabled.store(false);
    status_t err = mAudioTrack->getPosition(&mPositionWhenPausing);
    if (err != OK) {
        return AAudioConvert_androidToAAudioResult(err);
@@ -311,13 +313,13 @@ aaudio_result_t AudioStreamTrack::requestStop() {
        ALOGE("requestStop() no AudioTrack");
        return AAUDIO_ERROR_INVALID_STATE;
    }
    onStop();
    setState(AAUDIO_STREAM_STATE_STOPPING);
    incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
    mTimestampPosition.set(getFramesWritten());
    mFramesWritten.reset32();
    mTimestampPosition.reset32();
    mAudioTrack->stop();
    mCallbackEnabled.store(false);
    return checkForDisconnectRequest(false);;
}