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 class MyCallback : public AudioStreamDataCallback {
23 public:
onAudioReady(AudioStream * oboeStream,void * audioData,int32_t numFrames)24 DataCallbackResult onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) override {
25 return DataCallbackResult::Continue;
26 }
27 };
28
29 class StreamClosedReturnValues : public ::testing::Test {
30
31 protected:
32
openStream()33 bool openStream() {
34 Result r = mBuilder.openStream(&mStream);
35 EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
36 return (r == Result::OK);
37 }
38
closeStream()39 bool closeStream() {
40 Result r = mStream->close();
41 EXPECT_EQ(r, Result::OK) << "Failed to close stream. " << convertToText(r);
42 return (r == Result::OK);
43 }
44
openAndCloseStream()45 bool openAndCloseStream() {
46 if (!openStream() || !closeStream())
47 return false;
48 StreamState s = mStream->getState();
49 EXPECT_EQ(s, StreamState::Closed) << "Stream state " << convertToText(mStream->getState());
50 return (s == StreamState::Closed);
51 }
52
getNanoseconds()53 static int64_t getNanoseconds() {
54 struct timespec time;
55 int result = clock_gettime(CLOCK_MONOTONIC, &time);
56 if (result < 0) {
57 return result;
58 }
59 return (time.tv_sec * (int64_t)1e9) + time.tv_nsec;
60 }
61
62 int32_t mElapsedTimeMillis = 0; // used for passing back a value from a test function.
63 // ASSERT_* requires a void return type.
measureCloseTime(int32_t delayMillis)64 void measureCloseTime(int32_t delayMillis) {
65 ASSERT_TRUE(openStream());
66 mStream->setDelayBeforeCloseMillis(delayMillis);
67 ASSERT_EQ(delayMillis, mStream->getDelayBeforeCloseMillis());
68 // Measure time it takes to close.
69 int64_t startTimeMillis = getNanoseconds() / 1e6;
70 ASSERT_TRUE(closeStream());
71 int64_t stopTimeMillis = getNanoseconds() / 1e6;
72 int32_t elapsedTimeMillis = (int32_t)(stopTimeMillis - startTimeMillis);
73 ASSERT_GE(elapsedTimeMillis, delayMillis);
74 mElapsedTimeMillis = elapsedTimeMillis;
75 }
76
testDelayBeforeClose()77 void testDelayBeforeClose() {
78 const int32_t delayMillis = 100;
79 measureCloseTime(0);
80 int32_t elapsedTimeMillis1 = mElapsedTimeMillis;
81 // Do it again with a longer sleep using setDelayBeforeCloseMillis.
82 // The increase in elapsed time should match the added delay.
83 measureCloseTime(delayMillis);
84 int32_t elapsedTimeMillis2 = mElapsedTimeMillis;
85 int32_t extraElapsedTime = elapsedTimeMillis2 - elapsedTimeMillis1;
86 // Expect the additional elapsed time to be close to the added delay.
87 ASSERT_LE(abs(extraElapsedTime - delayMillis), delayMillis / 5);
88 }
89
90 AudioStreamBuilder mBuilder;
91 AudioStream *mStream = nullptr;
92
93 };
94
TEST_F(StreamClosedReturnValues,GetChannelCountReturnsLastKnownValue)95 TEST_F(StreamClosedReturnValues, GetChannelCountReturnsLastKnownValue){
96
97 mBuilder.setChannelCount(2);
98 ASSERT_TRUE(openAndCloseStream());
99 ASSERT_EQ(mStream->getChannelCount(), 2);
100 }
101
TEST_F(StreamClosedReturnValues,GetDirectionReturnsLastKnownValue)102 TEST_F(StreamClosedReturnValues, GetDirectionReturnsLastKnownValue){
103
104 // Note that when testing on the emulator setting the direction to Input will result in ErrorInternal when
105 // opening the stream
106 mBuilder.setDirection(Direction::Input);
107 ASSERT_TRUE(openAndCloseStream());
108 ASSERT_EQ(mStream->getDirection(), Direction::Input);
109 }
110
TEST_F(StreamClosedReturnValues,GetSampleRateReturnsLastKnownValue)111 TEST_F(StreamClosedReturnValues, GetSampleRateReturnsLastKnownValue){
112
113 mBuilder.setSampleRate(8000);
114 ASSERT_TRUE(openAndCloseStream());
115 ASSERT_EQ(mStream->getSampleRate(), 8000);
116 }
117
TEST_F(StreamClosedReturnValues,GetFramesPerCallbackReturnsLastKnownValue)118 TEST_F(StreamClosedReturnValues, GetFramesPerCallbackReturnsLastKnownValue) {
119
120 mBuilder.setFramesPerCallback(192);
121 ASSERT_TRUE(openAndCloseStream());
122 ASSERT_EQ(mStream->getFramesPerCallback(), 192);
123 }
124
TEST_F(StreamClosedReturnValues,GetFormatReturnsLastKnownValue)125 TEST_F(StreamClosedReturnValues, GetFormatReturnsLastKnownValue) {
126
127 mBuilder.setFormat(AudioFormat::I16);
128 ASSERT_TRUE(openAndCloseStream());
129 ASSERT_EQ(mStream->getFormat(), AudioFormat::I16);
130 }
131
TEST_F(StreamClosedReturnValues,GetBufferSizeInFramesReturnsLastKnownValue)132 TEST_F(StreamClosedReturnValues, GetBufferSizeInFramesReturnsLastKnownValue) {
133
134 ASSERT_TRUE(openStream());
135 int32_t bufferSize = mStream->getBufferSizeInFrames();
136 ASSERT_TRUE(closeStream());
137 ASSERT_EQ(mStream->getBufferSizeInFrames(), bufferSize);
138 }
139
TEST_F(StreamClosedReturnValues,GetBufferCapacityInFramesReturnsLastKnownValue)140 TEST_F(StreamClosedReturnValues, GetBufferCapacityInFramesReturnsLastKnownValue) {
141
142 ASSERT_TRUE(openStream());
143 int32_t bufferCapacity = mStream->getBufferCapacityInFrames();
144 ASSERT_TRUE(closeStream());
145 ASSERT_EQ(mStream->getBufferCapacityInFrames(), bufferCapacity);
146 }
147
TEST_F(StreamClosedReturnValues,GetSharingModeReturnsLastKnownValue)148 TEST_F(StreamClosedReturnValues, GetSharingModeReturnsLastKnownValue) {
149
150 ASSERT_TRUE(openStream());
151 SharingMode s = mStream->getSharingMode();
152 ASSERT_TRUE(closeStream());
153 ASSERT_EQ(mStream->getSharingMode(), s);
154 }
155
TEST_F(StreamClosedReturnValues,GetPerformanceModeReturnsLastKnownValue)156 TEST_F(StreamClosedReturnValues, GetPerformanceModeReturnsLastKnownValue) {
157
158 ASSERT_TRUE(openStream());
159 PerformanceMode p = mStream->getPerformanceMode();
160 ASSERT_TRUE(closeStream());
161 ASSERT_EQ(mStream->getPerformanceMode(), p);
162 }
163
TEST_F(StreamClosedReturnValues,GetDeviceIdReturnsLastKnownValue)164 TEST_F(StreamClosedReturnValues, GetDeviceIdReturnsLastKnownValue) {
165
166 ASSERT_TRUE(openStream());
167 int32_t d = mStream->getDeviceId();
168 ASSERT_TRUE(closeStream());
169 ASSERT_EQ(mStream->getDeviceId(), d);
170 }
171
TEST_F(StreamClosedReturnValues,GetDataCallbackReturnsLastKnownValue)172 TEST_F(StreamClosedReturnValues, GetDataCallbackReturnsLastKnownValue) {
173
174 AudioStreamDataCallback *callback = new MyCallback();
175 mBuilder.setDataCallback(callback);
176 ASSERT_TRUE(openAndCloseStream());
177
178 AudioStreamDataCallback *callback2 = mStream->getDataCallback();
179 ASSERT_EQ(callback, callback2);
180 }
181
TEST_F(StreamClosedReturnValues,GetUsageReturnsLastKnownValue)182 TEST_F(StreamClosedReturnValues, GetUsageReturnsLastKnownValue){
183 ASSERT_TRUE(openStream());
184 Usage u = mStream->getUsage();
185 ASSERT_TRUE(closeStream());
186 ASSERT_EQ(mStream->getUsage(), u);
187 }
188
TEST_F(StreamClosedReturnValues,GetContentTypeReturnsLastKnownValue)189 TEST_F(StreamClosedReturnValues, GetContentTypeReturnsLastKnownValue){
190 ASSERT_TRUE(openStream());
191 ContentType c = mStream->getContentType();
192 ASSERT_TRUE(closeStream());
193 ASSERT_EQ(mStream->getContentType(), c);
194 }
195
TEST_F(StreamClosedReturnValues,GetInputPresetReturnsLastKnownValue)196 TEST_F(StreamClosedReturnValues, GetInputPresetReturnsLastKnownValue){
197 ASSERT_TRUE(openStream());
198 auto i = mStream->getInputPreset();
199 ASSERT_TRUE(closeStream());
200 ASSERT_EQ(mStream->getInputPreset(), i);
201 }
202
TEST_F(StreamClosedReturnValues,GetSessionIdReturnsLastKnownValue)203 TEST_F(StreamClosedReturnValues, GetSessionIdReturnsLastKnownValue){
204 ASSERT_TRUE(openStream());
205 auto s = mStream->getSessionId();
206 ASSERT_TRUE(closeStream());
207 ASSERT_EQ(mStream->getSessionId(), s);
208 }
209
TEST_F(StreamClosedReturnValues,StreamStateIsClosed)210 TEST_F(StreamClosedReturnValues, StreamStateIsClosed){
211 ASSERT_TRUE(openAndCloseStream());
212 ASSERT_EQ(mStream->getState(), StreamState::Closed);
213 }
214
TEST_F(StreamClosedReturnValues,GetXRunCountReturnsLastKnownValue)215 TEST_F(StreamClosedReturnValues, GetXRunCountReturnsLastKnownValue){
216
217 ASSERT_TRUE(openStream());
218 if (mStream->isXRunCountSupported()){
219 auto i = mStream->getXRunCount();
220 ASSERT_EQ(mStream->getXRunCount(), i);
221 }
222 ASSERT_TRUE(closeStream());
223 }
224
TEST_F(StreamClosedReturnValues,GetFramesPerBurstReturnsLastKnownValue)225 TEST_F(StreamClosedReturnValues, GetFramesPerBurstReturnsLastKnownValue){
226
227 ASSERT_TRUE(openStream());
228 auto f = mStream->getFramesPerBurst();
229 ASSERT_TRUE(closeStream());
230 ASSERT_EQ(mStream->getFramesPerBurst(), f);
231 }
232
TEST_F(StreamClosedReturnValues,GetBytesPerFrameReturnsLastKnownValue)233 TEST_F(StreamClosedReturnValues, GetBytesPerFrameReturnsLastKnownValue){
234 ASSERT_TRUE(openStream());
235 auto f = mStream->getBytesPerFrame();
236 ASSERT_TRUE(closeStream());
237 ASSERT_EQ(mStream->getBytesPerFrame(), f);
238 }
239
TEST_F(StreamClosedReturnValues,GetBytesPerSampleReturnsLastKnownValue)240 TEST_F(StreamClosedReturnValues, GetBytesPerSampleReturnsLastKnownValue){
241 ASSERT_TRUE(openStream());
242 auto f = mStream->getBytesPerSample();
243 ASSERT_TRUE(closeStream());
244 ASSERT_EQ(mStream->getBytesPerSample(), f);
245 }
246
TEST_F(StreamClosedReturnValues,GetFramesWrittenReturnsLastKnownValue)247 TEST_F(StreamClosedReturnValues, GetFramesWrittenReturnsLastKnownValue){
248 mBuilder.setFormat(AudioFormat::I16);
249 mBuilder.setChannelCount(1);
250 ASSERT_TRUE(openStream());
251 ASSERT_EQ(mStream->setBufferSizeInFrames(mStream->getBufferCapacityInFrames()), Result::OK);
252 mStream->start();
253
254 int16_t buffer[4] = { 1, 2, 3, 4 };
255 Result r = mStream->write(&buffer, 4, 0);
256 if (r != Result::OK) {
257 FAIL() << "Could not write to audio stream";
258 }
259
260 auto f = mStream->getFramesWritten();
261 ASSERT_EQ(f, 4);
262
263 ASSERT_TRUE(closeStream());
264 ASSERT_EQ(mStream->getFramesWritten(), f);
265 }
266
TEST_F(StreamClosedReturnValues,GetFramesReadReturnsLastKnownValue)267 TEST_F(StreamClosedReturnValues, GetFramesReadReturnsLastKnownValue) {
268
269 mBuilder.setDirection(Direction::Input);
270 mBuilder.setFormat(AudioFormat::I16);
271 mBuilder.setChannelCount(1);
272
273 ASSERT_TRUE(openStream());
274 mStream->start();
275
276 int16_t buffer[192];
277 auto r = mStream->read(&buffer, 192, 1000 * kNanosPerMillisecond);
278 ASSERT_EQ(r.value(), 192);
279
280 auto f = mStream->getFramesRead();
281 ASSERT_EQ(f, 192);
282
283 ASSERT_TRUE(closeStream());
284 ASSERT_EQ(mStream->getFramesRead(), f);
285 }
286
TEST_F(StreamClosedReturnValues,GetTimestampReturnsErrorClosedIfSupported)287 TEST_F(StreamClosedReturnValues, GetTimestampReturnsErrorClosedIfSupported){
288
289 ASSERT_TRUE(openStream());
290
291 int64_t framePosition;
292 int64_t presentationTime;
293
294 auto r = mStream->getTimestamp(CLOCK_MONOTONIC, &framePosition, &presentationTime);
295 bool isTimestampSupported = (r == Result::OK);
296
297 ASSERT_TRUE(closeStream());
298
299 if (isTimestampSupported){
300 ASSERT_EQ(mStream->getTimestamp(CLOCK_MONOTONIC, &framePosition, &presentationTime), Result::ErrorClosed);
301 }
302 }
303
TEST_F(StreamClosedReturnValues,GetAudioApiReturnsLastKnownValue)304 TEST_F(StreamClosedReturnValues, GetAudioApiReturnsLastKnownValue){
305 ASSERT_TRUE(openStream());
306 AudioApi a = mStream->getAudioApi();
307 ASSERT_TRUE(closeStream());
308 ASSERT_EQ(mStream->getAudioApi(), a);
309 }
310
TEST_F(StreamClosedReturnValues,GetUsesAAudioReturnsLastKnownValue)311 TEST_F(StreamClosedReturnValues, GetUsesAAudioReturnsLastKnownValue){
312 ASSERT_TRUE(openStream());
313 bool a = mStream->usesAAudio();
314 ASSERT_TRUE(closeStream());
315 ASSERT_EQ(mStream->usesAAudio(), a);
316 }
317
TEST_F(StreamClosedReturnValues,StreamStateControlsReturnClosed)318 TEST_F(StreamClosedReturnValues, StreamStateControlsReturnClosed){
319
320 ASSERT_TRUE(openAndCloseStream());
321 Result r = mStream->close();
322 EXPECT_EQ(r, Result::ErrorClosed) << convertToText(r);
323 r = mStream->start();
324 EXPECT_EQ(r, Result::ErrorClosed) << convertToText(r);
325 EXPECT_EQ(mStream->pause(), Result::ErrorClosed);
326 EXPECT_EQ(mStream->flush(), Result::ErrorClosed);
327 EXPECT_EQ(mStream->stop(), Result::ErrorClosed);
328 EXPECT_EQ(mStream->requestStart(), Result::ErrorClosed);
329 EXPECT_EQ(mStream->requestPause(), Result::ErrorClosed);
330 EXPECT_EQ(mStream->requestFlush(), Result::ErrorClosed);
331 EXPECT_EQ(mStream->requestStop(), Result::ErrorClosed);
332 }
333
TEST_F(StreamClosedReturnValues,WaitForStateChangeReturnsClosed)334 TEST_F(StreamClosedReturnValues, WaitForStateChangeReturnsClosed){
335
336 ASSERT_TRUE(openAndCloseStream());
337 StreamState next;
338 Result r = mStream->waitForStateChange(StreamState::Open, &next, 0);
339 EXPECT_TRUE(r == Result::OK || r == Result::ErrorClosed) << convertToText(r);
340 }
341
TEST_F(StreamClosedReturnValues,SetBufferSizeInFramesReturnsClosed)342 TEST_F(StreamClosedReturnValues, SetBufferSizeInFramesReturnsClosed){
343
344 ASSERT_TRUE(openAndCloseStream());
345 auto r = mStream->setBufferSizeInFrames(192);
346 ASSERT_EQ(r.error(), Result::ErrorClosed);
347 }
348
TEST_F(StreamClosedReturnValues,CalculateLatencyInMillisReturnsClosedIfSupported)349 TEST_F(StreamClosedReturnValues, CalculateLatencyInMillisReturnsClosedIfSupported){
350
351 ASSERT_TRUE(openAndCloseStream());
352
353 if (mStream->getAudioApi() == AudioApi::AAudio){
354 auto r = mStream->calculateLatencyMillis();
355 ASSERT_EQ(r.error(), Result::ErrorInvalidState);
356 }
357 }
358
TEST_F(StreamClosedReturnValues,ReadReturnsClosed)359 TEST_F(StreamClosedReturnValues, ReadReturnsClosed){
360
361 ASSERT_TRUE(openAndCloseStream());
362
363 int buffer[8]{0};
364 auto r = mStream->read(buffer, 1, 0);
365 ASSERT_EQ(r.error(), Result::ErrorClosed);
366 }
367
TEST_F(StreamClosedReturnValues,WriteReturnsClosed)368 TEST_F(StreamClosedReturnValues, WriteReturnsClosed){
369
370 ASSERT_TRUE(openAndCloseStream());
371
372 int buffer[8]{0};
373 auto r = mStream->write(buffer, 1, 0);
374 ASSERT_EQ(r.error(), Result::ErrorClosed);
375 }
376
TEST_F(StreamClosedReturnValues,DelayBeforeCloseInput)377 TEST_F(StreamClosedReturnValues, DelayBeforeCloseInput){
378 if (AudioStreamBuilder::isAAudioRecommended()) {
379 mBuilder.setDirection(Direction::Input);
380 testDelayBeforeClose();
381 }
382 }
383
TEST_F(StreamClosedReturnValues,DelayBeforeCloseOutput)384 TEST_F(StreamClosedReturnValues, DelayBeforeCloseOutput){
385 if (AudioStreamBuilder::isAAudioRecommended()) {
386 mBuilder.setDirection(Direction::Output);
387 testDelayBeforeClose();
388 }
389 }
390
TEST_F(StreamClosedReturnValues,DelayBeforeCloseInputOpenSL)391 TEST_F(StreamClosedReturnValues, DelayBeforeCloseInputOpenSL){
392 mBuilder.setAudioApi(AudioApi::OpenSLES);
393 mBuilder.setDirection(Direction::Input);
394 testDelayBeforeClose();
395 }
396
TEST_F(StreamClosedReturnValues,DelayBeforeCloseOutputOpenSL)397 TEST_F(StreamClosedReturnValues, DelayBeforeCloseOutputOpenSL){
398 mBuilder.setAudioApi(AudioApi::OpenSLES);
399 mBuilder.setDirection(Direction::Output);
400 testDelayBeforeClose();
401 }
402