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