xref: /aosp_15_r20/external/oboe/tests/testStreamStates.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
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