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

Commit 318e42a8 authored by Robert Wu's avatar Robert Wu Committed by Phil Burk
Browse files

Fix AAudio waiting for stop SIGABRT

WaitForStateChange is a function that notifies the user if the
state moves from a specific state. When the state moves to closed,
however, a SIGABRT is thrown because waitForStateChange is in a
deleted pointer.

android::sp has a property where casting an instance to a sp increments
the usage count by 1. Thus, by adding casting the AAudioStream to a sp,
the AAudioStream is no longer deleted when the stream closes. With this
change, the SIGABRT is no longer thrown.

Bug: 63089499
Test: Ran new wait_for_state_change_closed with and without change.
Verified that the test fails before the cl and the test now passes
after the change.

Change-Id: Id865ef3f55f3cf006fd94d7b376d1b87ad999ca5
Merged-In: Id865ef3f55f3cf006fd94d7b376d1b87ad999ca5
(cherry picked from commit 676764f2)
parent 65cef33d
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -352,7 +352,8 @@ AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* stream,
{

    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
    return audioStream->waitForStateChange(inputState, nextState, timeoutNanoseconds);
    android::sp<AudioStream> spAudioStream(audioStream);
    return spAudioStream->waitForStateChange(inputState, nextState, timeoutNanoseconds);
}

// ============================================================
+54 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@

#include <gtest/gtest.h>
#include <unistd.h>
#include <thread>

// Callback function that does nothing.
aaudio_data_callback_result_t NoopDataCallbackProc(
@@ -51,6 +52,7 @@ aaudio_data_callback_result_t NoopDataCallbackProc(
}

constexpr int64_t NANOS_PER_MILLISECOND = 1000 * 1000;
constexpr int64_t MICROS_PER_MILLISECOND = 1000;

void checkReleaseThenClose(aaudio_performance_mode_t perfMode,
        aaudio_sharing_mode_t sharingMode,
@@ -762,6 +764,58 @@ TEST(test_various, aaudio_callback_once_lowlat) {
    checkCallbackOnce(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
}

void waitForStateChangeToClosingorClosed(AAudioStream **stream, std::atomic<bool>* isReady)
{
    *isReady = true;
    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN;
    EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(*stream,
                                                         AAUDIO_STREAM_STATE_OPEN, &state,
                                                         10000 * NANOS_PER_MILLISECOND));
    if ((state != AAUDIO_STREAM_STATE_CLOSING) && (state != AAUDIO_STREAM_STATE_CLOSED)){
        FAIL() << "ERROR - State not closing or closed. Current state: " <<
                AAudio_convertStreamStateToText(state);
    }
}

void testWaitForStateChangeClose(aaudio_performance_mode_t perfMode) {
    AAudioStreamBuilder *aaudioBuilder = nullptr;
    AAudioStream *aaudioStream = nullptr;

    ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
    AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));

    // Verify Open State
    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN;
    EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
                                                         AAUDIO_STREAM_STATE_UNKNOWN, &state,
                                                         1000 * NANOS_PER_MILLISECOND));
    EXPECT_EQ(AAUDIO_STREAM_STATE_OPEN, state);

    std::atomic<bool> isWaitThreadReady{false};

    // Spawn a new thread to wait for the state change
    std::thread waitThread (waitForStateChangeToClosingorClosed, &aaudioStream,
                            &isWaitThreadReady);

    // Wait for worker thread to be ready
    while (!isWaitThreadReady) {
        usleep(MICROS_PER_MILLISECOND);
    }
    // Sleep an additional millisecond to make sure waitForAudioThread is called
    usleep(MICROS_PER_MILLISECOND);
    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
    waitThread.join();
}

TEST(test_various, wait_for_state_change_close_none) {
    testWaitForStateChangeClose(AAUDIO_PERFORMANCE_MODE_NONE);
}

TEST(test_various, wait_for_state_change_close_lowlat) {
    testWaitForStateChangeClose(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
}

// ************************************************************
struct WakeUpCallbackData {
    void wakeOther() {