1 /*
2 * Copyright 2018 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 <gtest/gtest.h>
18 #include <oboe/Oboe.h>
19
20 using namespace oboe;
21
22 // Sleep between close and open to avoid a race condition inside Android Audio.
23 // On a Pixel 2 emulator on a fast Linux host, the minimum value is around 16 msec.
24 constexpr int kOboeOpenCloseSleepMSec = 100;
25
26 class StreamStates : public ::testing::Test {
27
28 protected:
29
SetUp()30 void SetUp(){
31 mBuilder.setPerformanceMode(PerformanceMode::None);
32 mBuilder.setDirection(Direction::Output);
33 }
34
openStream(Direction direction)35 bool openStream(Direction direction) {
36 usleep(100 * 1000);
37 mBuilder.setDirection(direction);
38 Result r = mBuilder.openStream(&mStream);
39 EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
40 if (r != Result::OK)
41 return false;
42
43 Direction d = mStream->getDirection();
44 EXPECT_EQ(d, direction) << convertToText(mStream->getDirection());
45 return (d == direction);
46 }
47
openStream()48 bool openStream() {
49 return openStream(Direction::Output);
50 }
51
openInputStream()52 bool openInputStream() {
53 return openStream(Direction::Input);
54 }
55
closeStream()56 bool closeStream() {
57 Result r = mStream->close();
58 EXPECT_EQ(r, Result::OK) << "Failed to close stream. " << convertToText(r);
59 return (r == Result::OK);
60 }
61
checkStreamStateIsStartedAfterStartingTwice(Direction direction)62 void checkStreamStateIsStartedAfterStartingTwice(Direction direction) {
63 ASSERT_TRUE(openStream(direction));
64
65 StreamState next = StreamState::Unknown;
66 auto r = mStream->requestStart();
67 EXPECT_EQ(r, Result::OK) << "requestStart returned: " << convertToText(r);
68 r = mStream->waitForStateChange(StreamState::Starting, &next, kTimeoutInNanos);
69 EXPECT_EQ(r, Result::OK);
70 EXPECT_EQ(next, StreamState::Started);
71
72 next = StreamState::Unknown;
73 r = mStream->requestStart();
74 // TODO On P, AAudio is returning ErrorInvalidState for Output and OK for Input
75 // EXPECT_EQ(r, Result::OK) << "requestStart returned: " << convertToText(r);
76 r = mStream->waitForStateChange(StreamState::Starting, &next, kTimeoutInNanos);
77 EXPECT_EQ(r, Result::OK);
78 ASSERT_EQ(next, StreamState::Started);
79
80 ASSERT_TRUE(closeStream());
81 }
82
checkStreamStateIsStoppedAfterStoppingTwice(Direction direction)83 void checkStreamStateIsStoppedAfterStoppingTwice(Direction direction) {
84 ASSERT_TRUE(openStream(direction));
85
86 StreamState next = StreamState::Unknown;
87 auto r = mStream->requestStart();
88 EXPECT_EQ(r, Result::OK);
89
90 r = mStream->requestStop();
91 EXPECT_EQ(r, Result::OK);
92 r = mStream->waitForStateChange(StreamState::Stopping, &next, kTimeoutInNanos);
93 EXPECT_EQ(r, Result::OK);
94 EXPECT_EQ(next, StreamState::Stopped);
95
96 r = mStream->requestStop();
97 EXPECT_EQ(r, Result::OK);
98 next = StreamState::Unknown;
99 r = mStream->waitForStateChange(StreamState::Stopping, &next, kTimeoutInNanos);
100 EXPECT_EQ(r, Result::OK);
101 ASSERT_EQ(next, StreamState::Stopped);
102
103 ASSERT_TRUE(closeStream());
104 }
105
106 // TODO: This seems to fail intermittently on Pixel OC_MR1 !
checkStreamLeftRunningShouldNotInterfereWithNextOpen(Direction direction)107 void checkStreamLeftRunningShouldNotInterfereWithNextOpen(Direction direction) {
108 ASSERT_TRUE(openStream(direction));
109
110 auto r = mStream->requestStart();
111 EXPECT_EQ(r, Result::OK);
112 // It should be safe to close without stopping.
113 // The underlying API should stop the stream.
114 ASSERT_TRUE(closeStream());
115
116 usleep(kOboeOpenCloseSleepMSec * 1000); // avoid race condition in emulator
117
118 ASSERT_TRUE(openInputStream());
119 r = mStream->requestStart();
120 ASSERT_EQ(r, Result::OK) << "requestStart returned: " << convertToText(r);
121
122 r = mStream->requestStop();
123 EXPECT_EQ(r, Result::OK) << "requestStop returned: " << convertToText(r);
124 ASSERT_TRUE(closeStream());
125 }
126
127 AudioStreamBuilder mBuilder;
128 AudioStream *mStream = nullptr;
129 static constexpr int kTimeoutInNanos = 500 * kNanosPerMillisecond;
130
131 };
132
TEST_F(StreamStates,OutputStreamStateIsOpenAfterOpening)133 TEST_F(StreamStates, OutputStreamStateIsOpenAfterOpening){
134 ASSERT_TRUE(openStream());
135 StreamState next = StreamState::Unknown;
136 Result r = mStream->waitForStateChange(StreamState::Uninitialized, &next, kTimeoutInNanos);
137 EXPECT_EQ(r, Result::OK) << convertToText(r);
138 ASSERT_EQ(next, StreamState::Open) << convertToText(next);
139 ASSERT_TRUE(closeStream());
140 }
141
TEST_F(StreamStates,OutputStreamStateIsStartedAfterStarting)142 TEST_F(StreamStates, OutputStreamStateIsStartedAfterStarting){
143
144 ASSERT_TRUE(openStream());
145
146 StreamState next = StreamState::Unknown;
147 auto r = mStream->requestStart();
148 EXPECT_EQ(r, Result::OK);
149
150 r = mStream->waitForStateChange(StreamState::Starting, &next, kTimeoutInNanos);
151 EXPECT_EQ(r, Result::OK);
152 ASSERT_EQ(next, StreamState::Started);
153
154 ASSERT_TRUE(closeStream());
155 }
156
TEST_F(StreamStates,OutputStreamStateIsPausedAfterPausing)157 TEST_F(StreamStates, OutputStreamStateIsPausedAfterPausing){
158
159 ASSERT_TRUE(openStream());
160
161 StreamState next = StreamState::Unknown;
162 auto r = mStream->requestStart();
163 EXPECT_EQ(r, Result::OK);
164
165 r = mStream->requestPause();
166 EXPECT_EQ(r, Result::OK);
167
168 r = mStream->waitForStateChange(StreamState::Pausing, &next, kTimeoutInNanos);
169 EXPECT_EQ(r, Result::OK);
170
171 ASSERT_EQ(next, StreamState::Paused);
172
173 ASSERT_TRUE(closeStream());
174 }
175
TEST_F(StreamStates,OutputStreamStateIsStoppedAfterStopping)176 TEST_F(StreamStates, OutputStreamStateIsStoppedAfterStopping){
177
178 ASSERT_TRUE(openStream());
179
180 StreamState next = StreamState::Unknown;
181 auto r = mStream->requestStart();
182 EXPECT_EQ(r, Result::OK);
183
184 r = mStream->requestStop();
185 r = mStream->waitForStateChange(StreamState::Stopping, &next, kTimeoutInNanos);
186 EXPECT_EQ(r, Result::OK);
187
188 ASSERT_EQ(next, StreamState::Stopped);
189
190 ASSERT_TRUE(closeStream());
191 }
192
TEST_F(StreamStates,InputStreamStateIsOpenAfterOpening)193 TEST_F(StreamStates, InputStreamStateIsOpenAfterOpening){
194 ASSERT_TRUE(openInputStream());
195 StreamState next = StreamState::Unknown;
196 Result r = mStream->waitForStateChange(StreamState::Uninitialized, &next, kTimeoutInNanos);
197 EXPECT_EQ(r, Result::OK) << convertToText(r);
198 ASSERT_EQ(next, StreamState::Open) << convertToText(next);
199 ASSERT_TRUE(closeStream());
200 }
201
TEST_F(StreamStates,InputStreamStateIsStartedAfterStarting)202 TEST_F(StreamStates, InputStreamStateIsStartedAfterStarting){
203
204 ASSERT_TRUE(openInputStream());
205
206 StreamState next = StreamState::Unknown;
207 auto r = mStream->requestStart();
208 EXPECT_EQ(r, Result::OK);
209
210 r = mStream->waitForStateChange(StreamState::Starting, &next, kTimeoutInNanos);
211 EXPECT_EQ(r, Result::OK);
212
213 ASSERT_EQ(next, StreamState::Started);
214
215 ASSERT_TRUE(closeStream());
216 }
217
TEST_F(StreamStates,OutputStreamStateIsStartedAfterStartingTwice)218 TEST_F(StreamStates, OutputStreamStateIsStartedAfterStartingTwice){
219 checkStreamStateIsStartedAfterStartingTwice(Direction::Output);
220 }
221
TEST_F(StreamStates,InputStreamStateIsStartedAfterStartingTwice)222 TEST_F(StreamStates, InputStreamStateIsStartedAfterStartingTwice){
223 checkStreamStateIsStartedAfterStartingTwice(Direction::Input);
224 }
225
TEST_F(StreamStates,OutputStreamStateIsStoppedAfterStoppingTwice)226 TEST_F(StreamStates, OutputStreamStateIsStoppedAfterStoppingTwice){
227 checkStreamStateIsStoppedAfterStoppingTwice(Direction::Output);
228 }
229
TEST_F(StreamStates,InputStreamStateIsStoppedAfterStoppingTwice)230 TEST_F(StreamStates, InputStreamStateIsStoppedAfterStoppingTwice){
231 checkStreamStateIsStoppedAfterStoppingTwice(Direction::Input);
232 }
233
TEST_F(StreamStates,OutputStreamStateIsPausedAfterPausingTwice)234 TEST_F(StreamStates, OutputStreamStateIsPausedAfterPausingTwice){
235 ASSERT_TRUE(openStream());
236
237 StreamState next = StreamState::Unknown;
238 auto r = mStream->requestStart();
239 EXPECT_EQ(r, Result::OK);
240
241 r = mStream->requestPause();
242 EXPECT_EQ(r, Result::OK);
243 r = mStream->waitForStateChange(StreamState::Pausing, &next, kTimeoutInNanos);
244 EXPECT_EQ(r, Result::OK);
245 EXPECT_EQ(next, StreamState::Paused);
246
247 // requestPause() while already paused could leave us in Pausing in AAudio O_MR1.
248 r = mStream->requestPause();
249 EXPECT_EQ(r, Result::OK);
250 next = StreamState::Unknown;
251 r = mStream->waitForStateChange(StreamState::Pausing, &next, kTimeoutInNanos);
252 EXPECT_EQ(r, Result::OK);
253 ASSERT_EQ(next, StreamState::Paused);
254
255 ASSERT_TRUE(closeStream());
256 }
257
TEST_F(StreamStates,InputStreamDoesNotSupportPause)258 TEST_F(StreamStates, InputStreamDoesNotSupportPause){
259
260 ASSERT_TRUE(openInputStream());
261 auto r = mStream->requestStart();
262 EXPECT_EQ(r, Result::OK);
263 r = mStream->requestPause();
264
265 ASSERT_EQ(r, Result::ErrorUnimplemented) << convertToText(r);
266 mStream->requestStop();
267 ASSERT_TRUE(closeStream());
268 }
269
TEST_F(StreamStates,OutputStreamLeftRunningShouldNotInterfereWithNextOpen)270 TEST_F(StreamStates, OutputStreamLeftRunningShouldNotInterfereWithNextOpen) {
271 checkStreamLeftRunningShouldNotInterfereWithNextOpen(Direction::Output);
272 }
273
TEST_F(StreamStates,InputStreamLeftRunningShouldNotInterfereWithNextOpen)274 TEST_F(StreamStates, InputStreamLeftRunningShouldNotInterfereWithNextOpen) {
275 checkStreamLeftRunningShouldNotInterfereWithNextOpen(Direction::Input);
276 }
277
TEST_F(StreamStates,OutputLowLatencyStreamLeftRunningShouldNotInterfereWithNextOpen)278 TEST_F(StreamStates, OutputLowLatencyStreamLeftRunningShouldNotInterfereWithNextOpen) {
279 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
280 checkStreamLeftRunningShouldNotInterfereWithNextOpen(Direction::Output);
281 }
282
TEST_F(StreamStates,InputLowLatencyStreamLeftRunningShouldNotInterfereWithNextOpen)283 TEST_F(StreamStates, InputLowLatencyStreamLeftRunningShouldNotInterfereWithNextOpen) {
284 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
285 checkStreamLeftRunningShouldNotInterfereWithNextOpen(Direction::Input);
286 }
287
TEST_F(StreamStates,InputStreamStateIsStoppedAfterStopping)288 TEST_F(StreamStates, InputStreamStateIsStoppedAfterStopping){
289
290 ASSERT_TRUE(openInputStream());
291
292 StreamState next = StreamState::Unknown;
293 auto r = mStream->requestStart();
294 EXPECT_EQ(r, Result::OK) << "requestStart returned: " << convertToText(r);
295
296 r = mStream->requestStop();
297 EXPECT_EQ(r, Result::OK) << "requestStop returned: " << convertToText(r);
298
299 r = mStream->waitForStateChange(StreamState::Stopping, &next, kTimeoutInNanos);
300 EXPECT_EQ(r, Result::OK) << "waitForStateChange returned: " << convertToText(r);
301
302 ASSERT_EQ(next, StreamState::Stopped);
303
304 ASSERT_TRUE(closeStream());
305 }
306