blob: 71dd5c9d4d02bd62d66bec46757eb84f975f687a [file] [log] [blame]
/*
* 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 <thread>
#include <gtest/gtest.h>
#include <oboe/Oboe.h>
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());
}