blob: 0ec4052be13bd8eab198a0c98e79cd27ebb5614f [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);
Result r = mBuilder.openStream(&mStream);
EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
EXPECT_EQ(mStream->getDirection(), direction) << convertToText(mStream->getDirection());
return (r == Result::OK);
}
bool openStream(AudioStreamBuilder &builder) {
Result r = builder.openStream(&mStream);
EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
return (r == Result::OK);
}
void closeStream() {
if (mStream != nullptr){
Result r = mStream->close();
mStream = nullptr;
if (r != Result::OK && r != Result::ErrorClosed){
FAIL() << "Failed to close stream. " << convertToText(r);
}
}
}
void checkWaitZeroTimeout() {
StreamState next = StreamState::Unknown;
int64_t timeout = 0; // don't wait for a state change
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_F(TestStreamWaitState, OutputLowWaitZero) {
openStream(Direction::Output, PerformanceMode::LowLatency);
checkWaitZeroTimeout();
closeStream();
}
TEST_F(TestStreamWaitState, OutputNoneWaitZero) {
openStream(Direction::Output, PerformanceMode::None);
checkWaitZeroTimeout();
closeStream();
}
TEST_F(TestStreamWaitState, OutputLowWaitZeroSLES) {
AudioStreamBuilder builder;
builder.setPerformanceMode(PerformanceMode::LowLatency);
builder.setAudioApi(AudioApi::OpenSLES);
openStream(builder);
checkWaitZeroTimeout();
closeStream();
}
TEST_F(TestStreamWaitState, OutputNoneWaitZeroSLES) {
AudioStreamBuilder builder;
builder.setPerformanceMode(PerformanceMode::None);
builder.setAudioApi(AudioApi::OpenSLES);
openStream(builder);
checkWaitZeroTimeout();
closeStream();
}
TEST_F(TestStreamWaitState, OutputLowStopWhileWaiting) {
openStream(Direction::Output, PerformanceMode::LowLatency);
checkStopWhileWaiting();
closeStream();
}
TEST_F(TestStreamWaitState, OutputNoneStopWhileWaiting) {
openStream(Direction::Output, PerformanceMode::LowLatency);
checkStopWhileWaiting();
closeStream();
}
TEST_F(TestStreamWaitState, OutputLowStopWhileWaitingSLES) {
AudioStreamBuilder builder;
builder.setPerformanceMode(PerformanceMode::LowLatency);
builder.setAudioApi(AudioApi::OpenSLES);
openStream(builder);
checkStopWhileWaiting();
closeStream();
}
TEST_F(TestStreamWaitState, OutputLowCloseWhileWaiting) {
openStream(Direction::Output, PerformanceMode::LowLatency);
checkCloseWhileWaiting();
closeStream();
}
TEST_F(TestStreamWaitState, OutputNoneCloseWhileWaiting) {
openStream(Direction::Output, PerformanceMode::None);
checkCloseWhileWaiting();
closeStream();
}
TEST_F(TestStreamWaitState, InputLowCloseWhileWaiting) {
openStream(Direction::Input, PerformanceMode::LowLatency);
checkCloseWhileWaiting();
closeStream();
}
TEST_F(TestStreamWaitState, InputNoneCloseWhileWaiting) {
openStream(Direction::Input, PerformanceMode::None);
checkCloseWhileWaiting();
closeStream();
}
TEST_F(TestStreamWaitState, OutputNoneCloseWhileWaitingSLES) {
AudioStreamBuilder builder;
builder.setPerformanceMode(PerformanceMode::None);
builder.setAudioApi(AudioApi::OpenSLES);
openStream(builder);
checkCloseWhileWaiting();
closeStream();
}
TEST_F(TestStreamWaitState, OutputLowCloseWhileWaitingSLES) {
AudioStreamBuilder builder;
builder.setPerformanceMode(PerformanceMode::LowLatency);
builder.setAudioApi(AudioApi::OpenSLES);
openStream(builder);
checkCloseWhileWaiting();
closeStream();
}