Loading include/private/media/AudioTrackShared.h +1 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ namespace android { // for audio_track_cblk_t::mState, to match TrackBase.h static inline constexpr int CBLK_STATE_IDLE = 0; static inline constexpr int CBLK_STATE_ACTIVE = 6; static inline constexpr int CBLK_STATE_PAUSING = 7; /** Loading media/codec2/sfplugin/CCodecConfig.cpp +3 −0 Original line number Diff line number Diff line Loading @@ -928,6 +928,9 @@ void CCodecConfig::initializeStandardParams() { add(ConfigMapper(KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT, C2_PARAMKEY_MAX_CHANNEL_COUNT, "value") .limitTo(D::AUDIO & (D::CONFIG | D::PARAM | D::READ))); add(ConfigMapper(KEY_MAX_OUTPUT_CHANNEL_COUNT, C2_PARAMKEY_MAX_CHANNEL_COUNT, "value") .limitTo(D::AUDIO & (D::CONFIG | D::PARAM | D::READ))); add(ConfigMapper(KEY_AAC_SBR_MODE, C2_PARAMKEY_AAC_SBR_MODE, "value") .limitTo(D::AUDIO & D::ENCODER & (D::CONFIG | D::PARAM | D::READ)) .withMapper([](C2Value v) -> C2Value { Loading media/libaaudio/src/core/AAudioAudio.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -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); } // ============================================================ Loading media/libaaudio/tests/test_various.cpp +54 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <gtest/gtest.h> #include <unistd.h> #include <thread> // Callback function that does nothing. aaudio_data_callback_result_t NoopDataCallbackProc( Loading @@ -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, Loading Loading @@ -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() { Loading media/libaudioclient/AudioTrack.cpp +20 −3 Original line number Diff line number Diff line Loading @@ -975,8 +975,16 @@ bool AudioTrack::pauseAndWait(const std::chrono::milliseconds& timeout) { using namespace std::chrono_literals; // We use atomic access here for state variables - these are used as hints // to ensure we have ramped down audio. const int priorState = mProxy->getState(); const uint32_t priorPosition = mProxy->getPosition().unsignedValue(); pause(); // Only if we were previously active, do we wait to ramp down the audio. if (priorState != CBLK_STATE_ACTIVE) return true; AutoMutex lock(mLock); // offload and direct tracks do not wait because pause volume ramp is handled by hardware. if (isOffloadedOrDirect_l()) return true; Loading @@ -984,16 +992,25 @@ bool AudioTrack::pauseAndWait(const std::chrono::milliseconds& timeout) // Wait for the track state to be anything besides pausing. // This ensures that the volume has ramped down. constexpr auto SLEEP_INTERVAL_MS = 10ms; constexpr auto POSITION_TIMEOUT_MS = 40ms; // don't wait longer than this for position change. auto begin = std::chrono::steady_clock::now(); while (true) { // wait for state to change // Wait for state and position to change. // After pause() the server state should be PAUSING, but that may immediately // convert to PAUSED by prepareTracks before data is read into the mixer. // Hence we check that the state is not PAUSING and that the server position // has advanced to be a more reliable estimate that the volume ramp has completed. const int state = mProxy->getState(); const uint32_t position = mProxy->getPosition().unsignedValue(); mLock.unlock(); // only local variables accessed until lock. auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::steady_clock::now() - begin); if (state != CBLK_STATE_PAUSING) { ALOGV("%s: success state:%d after %lld ms", __func__, state, elapsed.count()); if (state != CBLK_STATE_PAUSING && (elapsed >= POSITION_TIMEOUT_MS || position != priorPosition)) { ALOGV("%s: success state:%d, position:%u after %lld ms" " (prior state:%d prior position:%u)", __func__, state, position, elapsed.count(), priorState, priorPosition); return true; } std::chrono::milliseconds remaining = timeout - elapsed; Loading Loading
include/private/media/AudioTrackShared.h +1 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ namespace android { // for audio_track_cblk_t::mState, to match TrackBase.h static inline constexpr int CBLK_STATE_IDLE = 0; static inline constexpr int CBLK_STATE_ACTIVE = 6; static inline constexpr int CBLK_STATE_PAUSING = 7; /** Loading
media/codec2/sfplugin/CCodecConfig.cpp +3 −0 Original line number Diff line number Diff line Loading @@ -928,6 +928,9 @@ void CCodecConfig::initializeStandardParams() { add(ConfigMapper(KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT, C2_PARAMKEY_MAX_CHANNEL_COUNT, "value") .limitTo(D::AUDIO & (D::CONFIG | D::PARAM | D::READ))); add(ConfigMapper(KEY_MAX_OUTPUT_CHANNEL_COUNT, C2_PARAMKEY_MAX_CHANNEL_COUNT, "value") .limitTo(D::AUDIO & (D::CONFIG | D::PARAM | D::READ))); add(ConfigMapper(KEY_AAC_SBR_MODE, C2_PARAMKEY_AAC_SBR_MODE, "value") .limitTo(D::AUDIO & D::ENCODER & (D::CONFIG | D::PARAM | D::READ)) .withMapper([](C2Value v) -> C2Value { Loading
media/libaaudio/src/core/AAudioAudio.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -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); } // ============================================================ Loading
media/libaaudio/tests/test_various.cpp +54 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <gtest/gtest.h> #include <unistd.h> #include <thread> // Callback function that does nothing. aaudio_data_callback_result_t NoopDataCallbackProc( Loading @@ -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, Loading Loading @@ -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() { Loading
media/libaudioclient/AudioTrack.cpp +20 −3 Original line number Diff line number Diff line Loading @@ -975,8 +975,16 @@ bool AudioTrack::pauseAndWait(const std::chrono::milliseconds& timeout) { using namespace std::chrono_literals; // We use atomic access here for state variables - these are used as hints // to ensure we have ramped down audio. const int priorState = mProxy->getState(); const uint32_t priorPosition = mProxy->getPosition().unsignedValue(); pause(); // Only if we were previously active, do we wait to ramp down the audio. if (priorState != CBLK_STATE_ACTIVE) return true; AutoMutex lock(mLock); // offload and direct tracks do not wait because pause volume ramp is handled by hardware. if (isOffloadedOrDirect_l()) return true; Loading @@ -984,16 +992,25 @@ bool AudioTrack::pauseAndWait(const std::chrono::milliseconds& timeout) // Wait for the track state to be anything besides pausing. // This ensures that the volume has ramped down. constexpr auto SLEEP_INTERVAL_MS = 10ms; constexpr auto POSITION_TIMEOUT_MS = 40ms; // don't wait longer than this for position change. auto begin = std::chrono::steady_clock::now(); while (true) { // wait for state to change // Wait for state and position to change. // After pause() the server state should be PAUSING, but that may immediately // convert to PAUSED by prepareTracks before data is read into the mixer. // Hence we check that the state is not PAUSING and that the server position // has advanced to be a more reliable estimate that the volume ramp has completed. const int state = mProxy->getState(); const uint32_t position = mProxy->getPosition().unsignedValue(); mLock.unlock(); // only local variables accessed until lock. auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( std::chrono::steady_clock::now() - begin); if (state != CBLK_STATE_PAUSING) { ALOGV("%s: success state:%d after %lld ms", __func__, state, elapsed.count()); if (state != CBLK_STATE_PAUSING && (elapsed >= POSITION_TIMEOUT_MS || position != priorPosition)) { ALOGV("%s: success state:%d, position:%u after %lld ms" " (prior state:%d prior position:%u)", __func__, state, position, elapsed.count(), priorState, priorPosition); return true; } std::chrono::milliseconds remaining = timeout - elapsed; Loading