1*05767d91SRobert Wu /*
2*05767d91SRobert Wu * Copyright 2022 The Android Open Source Project
3*05767d91SRobert Wu *
4*05767d91SRobert Wu * Licensed under the Apache License, Version 2.0 (the "License");
5*05767d91SRobert Wu * you may not use this file except in compliance with the License.
6*05767d91SRobert Wu * You may obtain a copy of the License at
7*05767d91SRobert Wu *
8*05767d91SRobert Wu * http://www.apache.org/licenses/LICENSE-2.0
9*05767d91SRobert Wu *
10*05767d91SRobert Wu * Unless required by applicable law or agreed to in writing, software
11*05767d91SRobert Wu * distributed under the License is distributed on an "AS IS" BASIS,
12*05767d91SRobert Wu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*05767d91SRobert Wu * See the License for the specific language governing permissions and
14*05767d91SRobert Wu * limitations under the License.
15*05767d91SRobert Wu */
16*05767d91SRobert Wu
17*05767d91SRobert Wu #include <thread>
18*05767d91SRobert Wu
19*05767d91SRobert Wu #include <gtest/gtest.h>
20*05767d91SRobert Wu
21*05767d91SRobert Wu #include <oboe/Oboe.h>
22*05767d91SRobert Wu
23*05767d91SRobert Wu using namespace oboe;
24*05767d91SRobert Wu
25*05767d91SRobert Wu using TestStreamStopParams = std::tuple<Direction, AudioApi, PerformanceMode>;
26*05767d91SRobert Wu
27*05767d91SRobert Wu class TestStreamStop : public ::testing::Test,
28*05767d91SRobert Wu public ::testing::WithParamInterface<TestStreamStopParams> {
29*05767d91SRobert Wu
30*05767d91SRobert Wu protected:
31*05767d91SRobert Wu
SetUp()32*05767d91SRobert Wu void SetUp(){
33*05767d91SRobert Wu mBuilder.setPerformanceMode(PerformanceMode::None);
34*05767d91SRobert Wu mBuilder.setDirection(Direction::Output);
35*05767d91SRobert Wu }
36*05767d91SRobert Wu
openStream(Direction direction,AudioApi audioApi,PerformanceMode perfMode)37*05767d91SRobert Wu bool openStream(Direction direction, AudioApi audioApi, PerformanceMode perfMode) {
38*05767d91SRobert Wu mBuilder.setDirection(direction);
39*05767d91SRobert Wu if (mBuilder.isAAudioRecommended()) {
40*05767d91SRobert Wu mBuilder.setAudioApi(audioApi);
41*05767d91SRobert Wu }
42*05767d91SRobert Wu mBuilder.setPerformanceMode(perfMode);
43*05767d91SRobert Wu mBuilder.setChannelCount(1);
44*05767d91SRobert Wu mBuilder.setFormat(AudioFormat::I16);
45*05767d91SRobert Wu Result r = mBuilder.openStream(&mStream);
46*05767d91SRobert Wu EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
47*05767d91SRobert Wu if (r != Result::OK)
48*05767d91SRobert Wu return false;
49*05767d91SRobert Wu
50*05767d91SRobert Wu Direction d = mStream->getDirection();
51*05767d91SRobert Wu EXPECT_EQ(d, direction) << convertToText(mStream->getDirection());
52*05767d91SRobert Wu return (d == direction);
53*05767d91SRobert Wu }
54*05767d91SRobert Wu
openStream(AudioStreamBuilder & builder)55*05767d91SRobert Wu bool openStream(AudioStreamBuilder &builder) {
56*05767d91SRobert Wu Result r = builder.openStream(&mStream);
57*05767d91SRobert Wu EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
58*05767d91SRobert Wu return (r == Result::OK);
59*05767d91SRobert Wu }
60*05767d91SRobert Wu
stopWhileUsingLargeBuffer()61*05767d91SRobert Wu void stopWhileUsingLargeBuffer() {
62*05767d91SRobert Wu StreamState next = StreamState::Unknown;
63*05767d91SRobert Wu auto r = mStream->requestStart();
64*05767d91SRobert Wu EXPECT_EQ(r, Result::OK);
65*05767d91SRobert Wu r = mStream->waitForStateChange(StreamState::Starting, &next, kTimeoutInNanos);
66*05767d91SRobert Wu EXPECT_EQ(r, Result::OK);
67*05767d91SRobert Wu EXPECT_EQ(next, StreamState::Started) << "next = " << convertToText(next);
68*05767d91SRobert Wu
69*05767d91SRobert Wu AudioStream *str = mStream;
70*05767d91SRobert Wu
71*05767d91SRobert Wu int16_t buffer[kFramesToWrite] = {};
72*05767d91SRobert Wu
73*05767d91SRobert Wu std::thread stopper([str] {
74*05767d91SRobert Wu int64_t estimatedCompletionTimeUs = kMicroSecondsPerSecond * kFramesToWrite / str->getSampleRate();
75*05767d91SRobert Wu usleep(estimatedCompletionTimeUs / 2); // Stop halfway during the read/write
76*05767d91SRobert Wu EXPECT_EQ(str->close(), Result::OK);
77*05767d91SRobert Wu });
78*05767d91SRobert Wu
79*05767d91SRobert Wu if (mBuilder.getDirection() == Direction::Output) {
80*05767d91SRobert Wu r = mStream->write(&buffer, kFramesToWrite, kTimeoutInNanos);
81*05767d91SRobert Wu } else {
82*05767d91SRobert Wu r = mStream->read(&buffer, kFramesToWrite, kTimeoutInNanos);
83*05767d91SRobert Wu }
84*05767d91SRobert Wu if (r != Result::OK) {
85*05767d91SRobert Wu FAIL() << "Could not read/write to audio stream: " << static_cast<int>(r);
86*05767d91SRobert Wu }
87*05767d91SRobert Wu
88*05767d91SRobert Wu stopper.join();
89*05767d91SRobert Wu r = mStream->waitForStateChange(StreamState::Started, &next,
90*05767d91SRobert Wu 1000 * kNanosPerMillisecond);
91*05767d91SRobert Wu if ((r != Result::ErrorClosed) && (r != Result::OK)) {
92*05767d91SRobert Wu FAIL() << "Wrong closed result type: " << static_cast<int>(r);
93*05767d91SRobert Wu }
94*05767d91SRobert Wu }
95*05767d91SRobert Wu
96*05767d91SRobert Wu AudioStreamBuilder mBuilder;
97*05767d91SRobert Wu AudioStream *mStream = nullptr;
98*05767d91SRobert Wu static constexpr int kTimeoutInNanos = 1000 * kNanosPerMillisecond;
99*05767d91SRobert Wu static constexpr int64_t kMicroSecondsPerSecond = 1000000;
100*05767d91SRobert Wu static constexpr int kFramesToWrite = 10000;
101*05767d91SRobert Wu
102*05767d91SRobert Wu };
103*05767d91SRobert Wu
TEST_P(TestStreamStop,VerifyTestStreamStop)104*05767d91SRobert Wu TEST_P(TestStreamStop, VerifyTestStreamStop) {
105*05767d91SRobert Wu const Direction direction = std::get<0>(GetParam());
106*05767d91SRobert Wu const AudioApi audioApi = std::get<1>(GetParam());
107*05767d91SRobert Wu const PerformanceMode performanceMode = std::get<2>(GetParam());
108*05767d91SRobert Wu
109*05767d91SRobert Wu ASSERT_TRUE(openStream(direction, audioApi, performanceMode));
110*05767d91SRobert Wu stopWhileUsingLargeBuffer();
111*05767d91SRobert Wu }
112*05767d91SRobert Wu
113*05767d91SRobert Wu INSTANTIATE_TEST_SUITE_P(
114*05767d91SRobert Wu TestStreamStopTest,
115*05767d91SRobert Wu TestStreamStop,
116*05767d91SRobert Wu ::testing::Values(
117*05767d91SRobert Wu TestStreamStopParams({Direction::Output, AudioApi::AAudio, PerformanceMode::LowLatency}),
118*05767d91SRobert Wu TestStreamStopParams({Direction::Output, AudioApi::AAudio, PerformanceMode::None}),
119*05767d91SRobert Wu TestStreamStopParams({Direction::Output, AudioApi::AAudio, PerformanceMode::PowerSaving}),
120*05767d91SRobert Wu TestStreamStopParams({Direction::Output, AudioApi::OpenSLES, PerformanceMode::LowLatency}),
121*05767d91SRobert Wu TestStreamStopParams({Direction::Output, AudioApi::OpenSLES, PerformanceMode::None}),
122*05767d91SRobert Wu TestStreamStopParams({Direction::Output, AudioApi::OpenSLES, PerformanceMode::PowerSaving}),
123*05767d91SRobert Wu TestStreamStopParams({Direction::Input, AudioApi::AAudio, PerformanceMode::LowLatency}),
124*05767d91SRobert Wu TestStreamStopParams({Direction::Input, AudioApi::AAudio, PerformanceMode::None}),
125*05767d91SRobert Wu TestStreamStopParams({Direction::Input, AudioApi::AAudio, PerformanceMode::PowerSaving}),
126*05767d91SRobert Wu TestStreamStopParams({Direction::Input, AudioApi::OpenSLES, PerformanceMode::LowLatency}),
127*05767d91SRobert Wu TestStreamStopParams({Direction::Input, AudioApi::OpenSLES, PerformanceMode::None}),
128*05767d91SRobert Wu TestStreamStopParams({Direction::Input, AudioApi::OpenSLES, PerformanceMode::PowerSaving})
129*05767d91SRobert Wu )
130*05767d91SRobert Wu );
131