/* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include using namespace oboe; class TestStreamWaitState : public ::testing::Test { protected: void SetUp(){ mBuilder.setPerformanceMode(PerformanceMode::None); mBuilder.setDirection(Direction::Output); } bool openStream(Direction direction, PerformanceMode perfMode) { mBuilder.setDirection(direction); mBuilder.setPerformanceMode(perfMode); Result r = mBuilder.openStream(&mStream); EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r); if (r != Result::OK) return false; Direction d = mStream->getDirection(); EXPECT_EQ(d, direction) << convertToText(mStream->getDirection()); return (d == direction); } bool openStream(AudioStreamBuilder &builder) { Result r = builder.openStream(&mStream); EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r); return (r == Result::OK); } bool closeStream() { Result r = mStream->close(); EXPECT_TRUE(r == Result::OK || r == Result::ErrorClosed) << "Failed to close stream. " << convertToText(r); return (r == Result::OK || r == Result::ErrorClosed); } // if zero then don't wait for a state change void checkWaitForStateChangeTimeout(int64_t timeout = kTimeoutInNanos) { StreamState next = StreamState::Unknown; Result result = mStream->waitForStateChange(mStream->getState(), &next, timeout); EXPECT_EQ(Result::ErrorTimeout, result); } void checkStopWhileWaiting() { StreamState next = StreamState::Unknown; auto r = mStream->requestStart(); EXPECT_EQ(r, Result::OK); r = mStream->waitForStateChange(StreamState::Starting, &next, kTimeoutInNanos); EXPECT_EQ(r, Result::OK); EXPECT_EQ(next, StreamState::Started) << "next = " << convertToText(next); AudioStream *str = mStream; std::thread stopper([str] { usleep(200 * 1000); str->requestStop(); }); r = mStream->waitForStateChange(StreamState::Started, &next, 1000 * kNanosPerMillisecond); stopper.join(); EXPECT_EQ(r, Result::OK); // May have caught in stopping transition. Wait for full stop. if (next == StreamState::Stopping) { r = mStream->waitForStateChange(StreamState::Stopping, &next, 1000 * kNanosPerMillisecond); EXPECT_EQ(r, Result::OK); } ASSERT_EQ(next, StreamState::Stopped) << "next = " << convertToText(next); } void checkCloseWhileWaiting() { StreamState next = StreamState::Unknown; auto r = mStream->requestStart(); EXPECT_EQ(r, Result::OK); r = mStream->waitForStateChange(StreamState::Starting, &next, kTimeoutInNanos); EXPECT_EQ(r, Result::OK); EXPECT_EQ(next, StreamState::Started) << "next = " << convertToText(next); AudioStream *str = mStream; std::thread closer([str] { usleep(200 * 1000); str->close(); }); r = mStream->waitForStateChange(StreamState::Started, &next, 1000 * kNanosPerMillisecond); closer.join(); // You might catch this at any point in stopping or closing. EXPECT_TRUE(r == Result::OK || r == Result::ErrorClosed) << "r = " << convertToText(r); ASSERT_TRUE(next == StreamState::Stopping || next == StreamState::Stopped || next == StreamState::Pausing || next == StreamState::Paused || next == StreamState::Closed) << "next = " << convertToText(next); } AudioStreamBuilder mBuilder; AudioStream *mStream = nullptr; static constexpr int kTimeoutInNanos = 100 * kNanosPerMillisecond; }; // Test return of error timeout when zero passed as the timeoutNanos. TEST_F(TestStreamWaitState, OutputLowWaitZero) { ASSERT_TRUE(openStream(Direction::Output, PerformanceMode::LowLatency)); checkWaitForStateChangeTimeout(0); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputNoneWaitZero) { ASSERT_TRUE(openStream(Direction::Output, PerformanceMode::None)); checkWaitForStateChangeTimeout(0); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputLowWaitZeroSLES) { AudioStreamBuilder builder; builder.setPerformanceMode(PerformanceMode::LowLatency); builder.setAudioApi(AudioApi::OpenSLES); ASSERT_TRUE(openStream(builder)); checkWaitForStateChangeTimeout(0); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputNoneWaitZeroSLES) { AudioStreamBuilder builder; builder.setPerformanceMode(PerformanceMode::None); builder.setAudioApi(AudioApi::OpenSLES); ASSERT_TRUE(openStream(builder)); checkWaitForStateChangeTimeout(0); ASSERT_TRUE(closeStream()); } // Test actual timeout. TEST_F(TestStreamWaitState, OutputLowWaitNonZero) { ASSERT_TRUE(openStream(Direction::Output, PerformanceMode::LowLatency)); checkWaitForStateChangeTimeout(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputNoneWaitNonZero) { ASSERT_TRUE(openStream(Direction::Output, PerformanceMode::None)); checkWaitForStateChangeTimeout(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputLowWaitNonZeroSLES) { AudioStreamBuilder builder; builder.setPerformanceMode(PerformanceMode::LowLatency); builder.setAudioApi(AudioApi::OpenSLES); ASSERT_TRUE(openStream(builder)); checkWaitForStateChangeTimeout(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputNoneWaitNonZeroSLES) { AudioStreamBuilder builder; builder.setPerformanceMode(PerformanceMode::None); builder.setAudioApi(AudioApi::OpenSLES); ASSERT_TRUE(openStream(builder)); checkWaitForStateChangeTimeout(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputLowStopWhileWaiting) { ASSERT_TRUE(openStream(Direction::Output, PerformanceMode::LowLatency)); checkStopWhileWaiting(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputNoneStopWhileWaiting) { ASSERT_TRUE(openStream(Direction::Output, PerformanceMode::LowLatency)); checkStopWhileWaiting(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputLowStopWhileWaitingSLES) { AudioStreamBuilder builder; builder.setPerformanceMode(PerformanceMode::LowLatency); builder.setAudioApi(AudioApi::OpenSLES); ASSERT_TRUE(openStream(builder)); checkStopWhileWaiting(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputLowCloseWhileWaiting) { ASSERT_TRUE(openStream(Direction::Output, PerformanceMode::LowLatency)); checkCloseWhileWaiting(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputNoneCloseWhileWaiting) { ASSERT_TRUE(openStream(Direction::Output, PerformanceMode::None)); checkCloseWhileWaiting(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, InputLowCloseWhileWaiting) { ASSERT_TRUE(openStream(Direction::Input, PerformanceMode::LowLatency)); checkCloseWhileWaiting(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, InputNoneCloseWhileWaiting) { ASSERT_TRUE(openStream(Direction::Input, PerformanceMode::None)); checkCloseWhileWaiting(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputNoneCloseWhileWaitingSLES) { AudioStreamBuilder builder; builder.setPerformanceMode(PerformanceMode::None); builder.setAudioApi(AudioApi::OpenSLES); ASSERT_TRUE(openStream(builder)); checkCloseWhileWaiting(); ASSERT_TRUE(closeStream()); } TEST_F(TestStreamWaitState, OutputLowCloseWhileWaitingSLES) { AudioStreamBuilder builder; builder.setPerformanceMode(PerformanceMode::LowLatency); builder.setAudioApi(AudioApi::OpenSLES); ASSERT_TRUE(openStream(builder)); checkCloseWhileWaiting(); ASSERT_TRUE(closeStream()); }