1 /*
2 * Copyright (C) 2017 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 // Test various AAudio features including AAudioStream_setBufferSizeInFrames().
18
19 #include <condition_variable>
20 #include <mutex>
21 #include <stdio.h>
22
23 #include <android-base/macros.h>
24 #include <aaudio/AAudio.h>
25
26 #include <gtest/gtest.h>
27 #include <unistd.h>
28
29 // Callback function that does nothing.
NoopDataCallbackProc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)30 aaudio_data_callback_result_t NoopDataCallbackProc(
31 AAudioStream *stream,
32 void *userData,
33 void *audioData,
34 int32_t numFrames
35 ) {
36 (void) stream;
37 (void) userData;
38 (void) audioData;
39 (void) numFrames;
40 return AAUDIO_CALLBACK_RESULT_CONTINUE;
41 }
42
43 // Test AAudioStream_setBufferSizeInFrames()
44
45 constexpr int64_t NANOS_PER_MILLISECOND = 1000 * 1000;
46
47 enum FunctionToCall {
48 CALL_START, CALL_STOP, CALL_PAUSE, CALL_FLUSH
49 };
50
checkStateTransition(aaudio_performance_mode_t perfMode,aaudio_stream_state_t originalState,FunctionToCall functionToCall,aaudio_result_t expectedResult,aaudio_stream_state_t expectedState)51 void checkStateTransition(aaudio_performance_mode_t perfMode,
52 aaudio_stream_state_t originalState,
53 FunctionToCall functionToCall,
54 aaudio_result_t expectedResult,
55 aaudio_stream_state_t expectedState) {
56 AAudioStreamBuilder *aaudioBuilder = nullptr;
57 AAudioStream *aaudioStream = nullptr;
58
59 // Use an AAudioStreamBuilder to contain requested parameters.
60 ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
61
62 // Request stream properties.
63 AAudioStreamBuilder_setDataCallback(aaudioBuilder, NoopDataCallbackProc, nullptr);
64 AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
65
66 // Create an AAudioStream using the Builder.
67 ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
68
69 // Verify Open State
70 aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN;
71 EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
72 AAUDIO_STREAM_STATE_UNKNOWN, &state,
73 1000 * NANOS_PER_MILLISECOND));
74 EXPECT_EQ(AAUDIO_STREAM_STATE_OPEN, state);
75
76 // Put stream into desired state.
77 aaudio_stream_state_t inputState = AAUDIO_STREAM_STATE_UNINITIALIZED;
78 if (originalState != AAUDIO_STREAM_STATE_OPEN) {
79
80 ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
81
82 if (originalState != AAUDIO_STREAM_STATE_STARTING) {
83
84 ASSERT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
85 AAUDIO_STREAM_STATE_STARTING,
86 &state,
87 1000 * NANOS_PER_MILLISECOND));
88 ASSERT_EQ(AAUDIO_STREAM_STATE_STARTED, state);
89
90 if (originalState == AAUDIO_STREAM_STATE_STOPPING) {
91 ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
92 } else if (originalState == AAUDIO_STREAM_STATE_STOPPED) {
93 ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
94 inputState = AAUDIO_STREAM_STATE_STOPPING;
95 } else if (originalState == AAUDIO_STREAM_STATE_PAUSING) {
96 ASSERT_EQ(AAUDIO_OK, AAudioStream_requestPause(aaudioStream));
97 } else if (originalState == AAUDIO_STREAM_STATE_PAUSED) {
98 ASSERT_EQ(AAUDIO_OK, AAudioStream_requestPause(aaudioStream));
99 inputState = AAUDIO_STREAM_STATE_PAUSING;
100 }
101 }
102 }
103
104 // Wait until past transitional state.
105 if (inputState != AAUDIO_STREAM_STATE_UNINITIALIZED) {
106 ASSERT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
107 inputState,
108 &state,
109 1000 * NANOS_PER_MILLISECOND));
110 ASSERT_EQ(originalState, state);
111 }
112
113 aaudio_stream_state_t transitionalState = originalState;
114 switch(functionToCall) {
115 case FunctionToCall::CALL_START:
116 EXPECT_EQ(expectedResult, AAudioStream_requestStart(aaudioStream));
117 transitionalState = AAUDIO_STREAM_STATE_STARTING;
118 break;
119 case FunctionToCall::CALL_STOP:
120 EXPECT_EQ(expectedResult, AAudioStream_requestStop(aaudioStream));
121 transitionalState = AAUDIO_STREAM_STATE_STOPPING;
122 break;
123 case FunctionToCall::CALL_PAUSE:
124 EXPECT_EQ(expectedResult, AAudioStream_requestPause(aaudioStream));
125 transitionalState = AAUDIO_STREAM_STATE_PAUSING;
126 break;
127 case FunctionToCall::CALL_FLUSH:
128 EXPECT_EQ(expectedResult, AAudioStream_requestFlush(aaudioStream));
129 transitionalState = AAUDIO_STREAM_STATE_FLUSHING;
130 break;
131 }
132
133 EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(aaudioStream,
134 transitionalState,
135 &state,
136 1000 * NANOS_PER_MILLISECOND));
137 // We should not change state when a function fails.
138 if (expectedResult != AAUDIO_OK) {
139 ASSERT_EQ(originalState, expectedState);
140 }
141 EXPECT_EQ(expectedState, state);
142 if (state != expectedState) {
143 printf("ERROR - expected %s, actual = %s\n",
144 AAudio_convertStreamStateToText(expectedState),
145 AAudio_convertStreamStateToText(state));
146 fflush(stdout);
147 }
148
149 AAudioStream_close(aaudioStream);
150 AAudioStreamBuilder_delete(aaudioBuilder);
151 }
152
153 // TODO Use parameterized tests instead of these individual specific tests.
154
155 // OPEN =================================================================
TEST(test_various,aaudio_state_lowlat_open_start)156 TEST(test_various, aaudio_state_lowlat_open_start) {
157 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
158 AAUDIO_STREAM_STATE_OPEN,
159 FunctionToCall::CALL_START,
160 AAUDIO_OK,
161 AAUDIO_STREAM_STATE_STARTED);
162 }
163
TEST(test_various,aaudio_state_none_open_start)164 TEST(test_various, aaudio_state_none_open_start) {
165 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
166 AAUDIO_STREAM_STATE_OPEN,
167 FunctionToCall::CALL_START,
168 AAUDIO_OK,
169 AAUDIO_STREAM_STATE_STARTED);
170 }
171
TEST(test_various,aaudio_state_lowlat_open_stop)172 TEST(test_various, aaudio_state_lowlat_open_stop) {
173 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
174 AAUDIO_STREAM_STATE_OPEN,
175 FunctionToCall::CALL_STOP,
176 AAUDIO_OK,
177 AAUDIO_STREAM_STATE_STOPPED);
178 }
179
TEST(test_various,aaudio_state_none_open_stop)180 TEST(test_various, aaudio_state_none_open_stop) {
181 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
182 AAUDIO_STREAM_STATE_OPEN,
183 FunctionToCall::CALL_STOP,
184 AAUDIO_OK,
185 AAUDIO_STREAM_STATE_STOPPED);
186 }
187
TEST(test_various,aaudio_state_lowlat_open_pause)188 TEST(test_various, aaudio_state_lowlat_open_pause) {
189 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
190 AAUDIO_STREAM_STATE_OPEN,
191 FunctionToCall::CALL_PAUSE,
192 AAUDIO_OK,
193 AAUDIO_STREAM_STATE_PAUSED);
194 }
195
TEST(test_various,aaudio_state_none_open_pause)196 TEST(test_various, aaudio_state_none_open_pause) {
197 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
198 AAUDIO_STREAM_STATE_OPEN,
199 FunctionToCall::CALL_PAUSE,
200 AAUDIO_OK,
201 AAUDIO_STREAM_STATE_PAUSED);
202 }
203
TEST(test_various,aaudio_state_lowlat_open_flush)204 TEST(test_various, aaudio_state_lowlat_open_flush) {
205 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
206 AAUDIO_STREAM_STATE_OPEN,
207 FunctionToCall::CALL_FLUSH,
208 AAUDIO_OK,
209 AAUDIO_STREAM_STATE_FLUSHED);
210 }
211
TEST(test_various,aaudio_state_none_open_flush)212 TEST(test_various, aaudio_state_none_open_flush) {
213 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
214 AAUDIO_STREAM_STATE_OPEN,
215 FunctionToCall::CALL_FLUSH,
216 AAUDIO_OK,
217 AAUDIO_STREAM_STATE_FLUSHED);
218 }
219
220
221 // STARTED =================================================================
TEST(test_various,aaudio_state_lowlat_started_start)222 TEST(test_various, aaudio_state_lowlat_started_start) {
223 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
224 AAUDIO_STREAM_STATE_STARTED,
225 FunctionToCall::CALL_START,
226 AAUDIO_ERROR_INVALID_STATE,
227 AAUDIO_STREAM_STATE_STARTED);
228 }
229
TEST(test_various,aaudio_state_none_started_start)230 TEST(test_various, aaudio_state_none_started_start) {
231 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
232 AAUDIO_STREAM_STATE_STARTED,
233 FunctionToCall::CALL_START,
234 AAUDIO_ERROR_INVALID_STATE,
235 AAUDIO_STREAM_STATE_STARTED);
236 }
237
TEST(test_various,aaudio_state_lowlat_started_stop)238 TEST(test_various, aaudio_state_lowlat_started_stop) {
239 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
240 AAUDIO_STREAM_STATE_STARTED,
241 FunctionToCall::CALL_STOP,
242 AAUDIO_OK,
243 AAUDIO_STREAM_STATE_STOPPED);
244 }
245
TEST(test_various,aaudio_state_none_started_stop)246 TEST(test_various, aaudio_state_none_started_stop) {
247 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
248 AAUDIO_STREAM_STATE_STARTED,
249 FunctionToCall::CALL_STOP,
250 AAUDIO_OK,
251 AAUDIO_STREAM_STATE_STOPPED);
252 }
253
TEST(test_various,aaudio_state_lowlat_started_pause)254 TEST(test_various, aaudio_state_lowlat_started_pause) {
255 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
256 AAUDIO_STREAM_STATE_STARTED,
257 FunctionToCall::CALL_PAUSE,
258 AAUDIO_OK,
259 AAUDIO_STREAM_STATE_PAUSED);
260 }
261
TEST(test_various,aaudio_state_none_started_pause)262 TEST(test_various, aaudio_state_none_started_pause) {
263 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
264 AAUDIO_STREAM_STATE_STARTED,
265 FunctionToCall::CALL_PAUSE,
266 AAUDIO_OK,
267 AAUDIO_STREAM_STATE_PAUSED);
268 }
269
TEST(test_various,aaudio_state_lowlat_started_flush)270 TEST(test_various, aaudio_state_lowlat_started_flush) {
271 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
272 AAUDIO_STREAM_STATE_STARTED,
273 FunctionToCall::CALL_FLUSH,
274 AAUDIO_ERROR_INVALID_STATE,
275 AAUDIO_STREAM_STATE_STARTED);
276 }
277
TEST(test_various,aaudio_state_none_started_flush)278 TEST(test_various, aaudio_state_none_started_flush) {
279 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
280 AAUDIO_STREAM_STATE_STARTED,
281 FunctionToCall::CALL_FLUSH,
282 AAUDIO_ERROR_INVALID_STATE,
283 AAUDIO_STREAM_STATE_STARTED);
284 }
285
286 // STOPPED =================================================================
TEST(test_various,aaudio_state_lowlat_stopped_start)287 TEST(test_various, aaudio_state_lowlat_stopped_start) {
288 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
289 AAUDIO_STREAM_STATE_STOPPED,
290 FunctionToCall::CALL_START,
291 AAUDIO_OK,
292 AAUDIO_STREAM_STATE_STARTED);
293 }
294
TEST(test_various,aaudio_state_none_stopped_start)295 TEST(test_various, aaudio_state_none_stopped_start) {
296 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
297 AAUDIO_STREAM_STATE_STOPPED,
298 FunctionToCall::CALL_START,
299 AAUDIO_OK,
300 AAUDIO_STREAM_STATE_STARTED);
301 }
302
TEST(test_various,aaudio_state_lowlat_stopped_stop)303 TEST(test_various, aaudio_state_lowlat_stopped_stop) {
304 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
305 AAUDIO_STREAM_STATE_STOPPED,
306 FunctionToCall::CALL_STOP,
307 AAUDIO_OK,
308 AAUDIO_STREAM_STATE_STOPPED);
309 }
310
TEST(test_various,aaudio_state_none_stopped_stop)311 TEST(test_various, aaudio_state_none_stopped_stop) {
312 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
313 AAUDIO_STREAM_STATE_STOPPED,
314 FunctionToCall::CALL_STOP,
315 AAUDIO_OK,
316 AAUDIO_STREAM_STATE_STOPPED);
317 }
318
TEST(test_various,aaudio_state_lowlat_stopped_pause)319 TEST(test_various, aaudio_state_lowlat_stopped_pause) {
320 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
321 AAUDIO_STREAM_STATE_STOPPED,
322 FunctionToCall::CALL_PAUSE,
323 AAUDIO_OK,
324 AAUDIO_STREAM_STATE_PAUSED);
325 }
326
TEST(test_various,aaudio_state_none_stopped_pause)327 TEST(test_various, aaudio_state_none_stopped_pause) {
328 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
329 AAUDIO_STREAM_STATE_STOPPED,
330 FunctionToCall::CALL_PAUSE,
331 AAUDIO_OK,
332 AAUDIO_STREAM_STATE_PAUSED);
333 }
334
TEST(test_various,aaudio_state_lowlat_stopped_flush)335 TEST(test_various, aaudio_state_lowlat_stopped_flush) {
336 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
337 AAUDIO_STREAM_STATE_STOPPED,
338 FunctionToCall::CALL_FLUSH,
339 AAUDIO_OK,
340 AAUDIO_STREAM_STATE_FLUSHED);
341 }
342
TEST(test_various,aaudio_state_none_stopped_flush)343 TEST(test_various, aaudio_state_none_stopped_flush) {
344 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
345 AAUDIO_STREAM_STATE_STOPPED,
346 FunctionToCall::CALL_FLUSH,
347 AAUDIO_OK,
348 AAUDIO_STREAM_STATE_FLUSHED);
349 }
350
351 // PAUSED =================================================================
TEST(test_various,aaudio_state_lowlat_paused_start)352 TEST(test_various, aaudio_state_lowlat_paused_start) {
353 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
354 AAUDIO_STREAM_STATE_PAUSED,
355 FunctionToCall::CALL_START,
356 AAUDIO_OK,
357 AAUDIO_STREAM_STATE_STARTED);
358 }
359
TEST(test_various,aaudio_state_none_paused_start)360 TEST(test_various, aaudio_state_none_paused_start) {
361 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
362 AAUDIO_STREAM_STATE_PAUSED,
363 FunctionToCall::CALL_START,
364 AAUDIO_OK,
365 AAUDIO_STREAM_STATE_STARTED);
366 }
367
TEST(test_various,aaudio_state_lowlat_paused_stop)368 TEST(test_various, aaudio_state_lowlat_paused_stop) {
369 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
370 AAUDIO_STREAM_STATE_PAUSED,
371 FunctionToCall::CALL_STOP,
372 AAUDIO_OK,
373 AAUDIO_STREAM_STATE_STOPPED);
374 }
375
TEST(test_various,aaudio_state_none_paused_stop)376 TEST(test_various, aaudio_state_none_paused_stop) {
377 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
378 AAUDIO_STREAM_STATE_PAUSED,
379 FunctionToCall::CALL_STOP,
380 AAUDIO_OK,
381 AAUDIO_STREAM_STATE_STOPPED);
382 }
383
TEST(test_various,aaudio_state_lowlat_paused_pause)384 TEST(test_various, aaudio_state_lowlat_paused_pause) {
385 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
386 AAUDIO_STREAM_STATE_PAUSED,
387 FunctionToCall::CALL_PAUSE,
388 AAUDIO_OK,
389 AAUDIO_STREAM_STATE_PAUSED);
390 }
391
TEST(test_various,aaudio_state_none_paused_pause)392 TEST(test_various, aaudio_state_none_paused_pause) {
393 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
394 AAUDIO_STREAM_STATE_PAUSED,
395 FunctionToCall::CALL_PAUSE,
396 AAUDIO_OK,
397 AAUDIO_STREAM_STATE_PAUSED);
398 }
399
TEST(test_various,aaudio_state_lowlat_paused_flush)400 TEST(test_various, aaudio_state_lowlat_paused_flush) {
401 checkStateTransition(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
402 AAUDIO_STREAM_STATE_PAUSED,
403 FunctionToCall::CALL_FLUSH,
404 AAUDIO_OK,
405 AAUDIO_STREAM_STATE_FLUSHED);
406 }
407
TEST(test_various,aaudio_state_none_paused_flush)408 TEST(test_various, aaudio_state_none_paused_flush) {
409 checkStateTransition(AAUDIO_PERFORMANCE_MODE_NONE,
410 AAUDIO_STREAM_STATE_PAUSED,
411 FunctionToCall::CALL_FLUSH,
412 AAUDIO_OK,
413 AAUDIO_STREAM_STATE_FLUSHED);
414 }
415
416 // ==========================================================================
TEST(test_various,aaudio_set_buffer_size)417 TEST(test_various, aaudio_set_buffer_size) {
418
419 int32_t bufferCapacity;
420 int32_t framesPerBurst = 0;
421 int32_t actualSize = 0;
422
423 AAudioStreamBuilder *aaudioBuilder = nullptr;
424 AAudioStream *aaudioStream = nullptr;
425
426 // Use an AAudioStreamBuilder to contain requested parameters.
427 ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
428
429 // Request stream properties.
430 AAudioStreamBuilder_setDataCallback(aaudioBuilder, NoopDataCallbackProc, nullptr);
431 AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
432
433 // Create an AAudioStream using the Builder.
434 EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
435
436 // This is the number of frames that are read in one chunk by a DMA controller
437 // or a DSP or a mixer.
438 framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
439 bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
440 printf(" bufferCapacity = %d, remainder = %d\n",
441 bufferCapacity, bufferCapacity % framesPerBurst);
442
443 actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, 0);
444 EXPECT_GT(actualSize, 0);
445 EXPECT_LE(actualSize, bufferCapacity);
446
447 actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, 2 * framesPerBurst);
448 EXPECT_GT(actualSize, framesPerBurst);
449 EXPECT_LE(actualSize, bufferCapacity);
450
451 actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, bufferCapacity - 1);
452 EXPECT_GT(actualSize, framesPerBurst);
453 EXPECT_LE(actualSize, bufferCapacity);
454
455 actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, bufferCapacity);
456 EXPECT_GT(actualSize, framesPerBurst);
457 EXPECT_LE(actualSize, bufferCapacity);
458
459 actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, bufferCapacity + 1);
460 EXPECT_GT(actualSize, framesPerBurst);
461 EXPECT_LE(actualSize, bufferCapacity);
462
463 actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, 1234567);
464 EXPECT_GT(actualSize, framesPerBurst);
465 EXPECT_LE(actualSize, bufferCapacity);
466
467 actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, INT32_MAX);
468 EXPECT_GT(actualSize, framesPerBurst);
469 EXPECT_LE(actualSize, bufferCapacity);
470
471 actualSize = AAudioStream_setBufferSizeInFrames(aaudioStream, INT32_MIN);
472 EXPECT_GT(actualSize, 0);
473 EXPECT_LE(actualSize, bufferCapacity);
474
475 AAudioStream_close(aaudioStream);
476 AAudioStreamBuilder_delete(aaudioBuilder);
477 }
478
479 // ************************************************************
480 // Test to make sure that AAUDIO_CALLBACK_RESULT_STOP works.
481
482 // Callback function that counts calls.
CallbackOnceProc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)483 aaudio_data_callback_result_t CallbackOnceProc(
484 AAudioStream *stream,
485 void *userData,
486 void *audioData,
487 int32_t numFrames
488 ) {
489 (void) stream;
490 (void) audioData;
491 (void) numFrames;
492
493 std::atomic<int32_t> *callbackCountPtr = (std::atomic<int32_t> *)userData;
494 (*callbackCountPtr)++;
495
496 return AAUDIO_CALLBACK_RESULT_STOP;
497 }
498
checkCallbackOnce(aaudio_performance_mode_t perfMode)499 void checkCallbackOnce(aaudio_performance_mode_t perfMode) {
500
501 std::atomic<int32_t> callbackCount{0};
502
503 AAudioStreamBuilder *aaudioBuilder = nullptr;
504 AAudioStream *aaudioStream = nullptr;
505
506 // Use an AAudioStreamBuilder to contain requested parameters.
507 ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
508
509 // Request stream properties.
510 AAudioStreamBuilder_setDataCallback(aaudioBuilder, CallbackOnceProc, &callbackCount);
511 AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
512
513 // Create an AAudioStream using the Builder.
514 ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
515 AAudioStreamBuilder_delete(aaudioBuilder);
516
517 ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
518
519 sleep(1); // Give callback a chance to run many times.
520
521 EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
522
523 EXPECT_EQ(1, callbackCount.load()); // should stop after first call
524
525 EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
526 }
527
TEST(test_various,aaudio_callback_once_none)528 TEST(test_various, aaudio_callback_once_none) {
529 checkCallbackOnce(AAUDIO_PERFORMANCE_MODE_NONE);
530 }
531
TEST(test_various,aaudio_callback_once_lowlat)532 TEST(test_various, aaudio_callback_once_lowlat) {
533 checkCallbackOnce(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
534 }
535
536 // ************************************************************
537 struct WakeUpCallbackData {
wakeOtherWakeUpCallbackData538 void wakeOther() {
539 // signal waiting test to wake up
540 {
541 std::lock_guard <std::mutex> lock(mutex);
542 finished = true;
543 }
544 conditionVariable.notify_one();
545 }
546
waitForFinishedWakeUpCallbackData547 void waitForFinished() {
548 std::unique_lock <std::mutex> aLock(mutex);
549 conditionVariable.wait(aLock, [=] { return finished; });
550 }
551
552 // For signalling foreground test when callback finished
553 std::mutex mutex;
554 std::condition_variable conditionVariable;
555 bool finished = false;
556 };
557
558 // Test to make sure we cannot call recursively into the system from a callback.
559 struct DangerousData : public WakeUpCallbackData {
560 aaudio_result_t resultStart = AAUDIO_OK;
561 aaudio_result_t resultStop = AAUDIO_OK;
562 aaudio_result_t resultPause = AAUDIO_OK;
563 aaudio_result_t resultFlush = AAUDIO_OK;
564 aaudio_result_t resultClose = AAUDIO_OK;
565 };
566
567 // Callback function that tries to call back into the stream.
DangerousDataCallbackProc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)568 aaudio_data_callback_result_t DangerousDataCallbackProc(
569 AAudioStream *stream,
570 void *userData,
571 void *audioData,
572 int32_t numFrames) {
573 (void) audioData;
574 (void) numFrames;
575
576 DangerousData *data = (DangerousData *)userData;
577 data->resultStart = AAudioStream_requestStart(stream);
578 data->resultStop = AAudioStream_requestStop(stream);
579 data->resultPause = AAudioStream_requestPause(stream);
580 data->resultFlush = AAudioStream_requestFlush(stream);
581 data->resultClose = AAudioStream_close(stream);
582
583 data->wakeOther();
584
585 return AAUDIO_CALLBACK_RESULT_STOP;
586 }
587
588 //int main() { // To fix Android Studio formatting when editing.
checkDangerousCallback(aaudio_performance_mode_t perfMode)589 void checkDangerousCallback(aaudio_performance_mode_t perfMode) {
590 DangerousData dangerousData;
591 AAudioStreamBuilder *aaudioBuilder = nullptr;
592 AAudioStream *aaudioStream = nullptr;
593
594 // Use an AAudioStreamBuilder to contain requested parameters.
595 ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
596
597 // Request stream properties.
598 AAudioStreamBuilder_setDataCallback(aaudioBuilder, DangerousDataCallbackProc, &dangerousData);
599 AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
600
601 // Create an AAudioStream using the Builder.
602 ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
603 AAudioStreamBuilder_delete(aaudioBuilder);
604
605 ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
606
607 dangerousData.waitForFinished();
608
609 EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
610
611 EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, dangerousData.resultStart);
612 EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, dangerousData.resultStop);
613 EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, dangerousData.resultPause);
614 EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, dangerousData.resultFlush);
615 EXPECT_EQ(AAUDIO_ERROR_INVALID_STATE, dangerousData.resultClose);
616
617 EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
618 }
619
620 //int main() { // To fix Android Studio formatting when editing.
621
TEST(test_various,aaudio_callback_blockers_none)622 TEST(test_various, aaudio_callback_blockers_none) {
623 checkDangerousCallback(AAUDIO_PERFORMANCE_MODE_NONE);
624 }
625
TEST(test_various,aaudio_callback_blockers_lowlat)626 TEST(test_various, aaudio_callback_blockers_lowlat) {
627 checkDangerousCallback(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
628 }
629