xref: /aosp_15_r20/cts/tests/tests/nativemedia/aaudio/jni/test_aaudio_callback.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1 /*
2  * Copyright 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 #define LOG_NDEBUG 0
18 #define LOG_TAG "AAudioTest"
19 
20 #include <atomic>
21 #include <tuple>
22 
23 #include <aaudio/AAudio.h>
24 #include <android/log.h>
25 #include <gtest/gtest.h>
26 
27 #include "test_aaudio.h"
28 #include "utils.h"
29 
30 constexpr int kExtremelyHighCallbackPeriodMillis = 200;
31 constexpr int kExpectedCallbackCount = 5;
32 constexpr int kPollTimeMillis = 5;
33 
measureLatency(AAudioStream * stream)34 static int32_t measureLatency(AAudioStream *stream) {
35     int64_t presentationTime = 0;
36     int64_t presentationPosition = 0;
37     int64_t now = getNanoseconds();
38     int32_t sampleRate = AAudioStream_getSampleRate(stream);
39     int64_t framesWritten = AAudioStream_getFramesWritten(stream);
40     aaudio_result_t result = AAudioStream_getTimestamp(stream,
41                                                        CLOCK_MONOTONIC,
42                                                        &presentationPosition,
43                                                        &presentationTime);
44     if (result < 0) {
45         return result;
46     }
47     // Calculate when the last frame written would be played.
48     int64_t deltaFrames = framesWritten - presentationPosition;
49     if (deltaFrames < 0) {
50         __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "Underrun detected: %lld frames",
51                 (long long)(-deltaFrames));
52         return 0;
53     }
54     int64_t calculatedDeltaNanos = deltaFrames * NANOS_PER_SECOND / sampleRate;
55     int64_t calculatedTimeNanos = presentationTime +  calculatedDeltaNanos;
56     int64_t latencyNanos = calculatedTimeNanos - now;
57     int32_t latencyMillis = (int32_t) ((latencyNanos + NANOS_PER_MILLISECOND - 1)
58                             / NANOS_PER_MILLISECOND);
59     return latencyMillis;
60 }
61 
62 using CbTestParams = std::tuple<aaudio_sharing_mode_t, int32_t,
63                                 aaudio_performance_mode_t, int32_t, aaudio_format_t, int32_t>;
64 enum {
65     PARAM_SHARING_MODE = 0,
66     PARAM_FRAMES_PER_CB,
67     PARAM_PERF_MODE,
68     PARAM_ALLOW_MMAP,
69     PARAM_AUDIO_FORMAT,
70     PARAM_SAMPLE_RATE
71 };
72 
73 enum {
74     MMAP_NOT_ALLOWED,
75     MMAP_ALLOWED,
76 };
77 
allowMMapToString(int allow)78 static const char* allowMMapToString(int allow) {
79     switch (allow) {
80         case MMAP_NOT_ALLOWED: return "NOTMMAP";
81         case MMAP_ALLOWED:
82         default:
83             return "MMAPOK";
84     }
85 }
86 
audioFormatToString(aaudio_format_t format)87 static const char* audioFormatToString(aaudio_format_t format) {
88     switch (format) {
89         case AAUDIO_FORMAT_UNSPECIFIED: return "UNSP";
90         case AAUDIO_FORMAT_PCM_I16: return "I16";
91         case AAUDIO_FORMAT_PCM_FLOAT: return "FLT";
92         default:
93             return "BAD";
94     }
95 }
96 
getTestName(const::testing::TestParamInfo<CbTestParams> & info)97 static std::string getTestName(const ::testing::TestParamInfo<CbTestParams>& info) {
98     return std::string()
99             + sharingModeToString(std::get<PARAM_SHARING_MODE>(info.param))
100             + "__" + std::to_string(std::get<PARAM_FRAMES_PER_CB>(info.param))
101             + "__" + performanceModeToString(std::get<PARAM_PERF_MODE>(info.param))
102             + "__" + allowMMapToString(std::get<PARAM_ALLOW_MMAP>(info.param))
103             + "__" + audioFormatToString(std::get<PARAM_AUDIO_FORMAT>(info.param))
104             + "__" + std::to_string(std::get<PARAM_SAMPLE_RATE>(info.param))
105             ;
106 }
107 
108 template<typename T>
109 class AAudioStreamCallbackTest : public AAudioCtsBase,
110                                  public ::testing::WithParamInterface<CbTestParams> {
111   protected:
112     struct AAudioCallbackTestData {
113         int32_t expectedFramesPerCallback;
114         int32_t actualFramesPerCallback;
115         int32_t minLatency;
116         int32_t maxLatency;
117         std::atomic<aaudio_result_t> callbackError;
118         std::atomic<int32_t> callbackCount;
119         std::atomic<bool> returnStop;
120 
AAudioCallbackTestDataAAudioStreamCallbackTest::AAudioCallbackTestData121         AAudioCallbackTestData() {
122             reset(0);
123         }
resetAAudioStreamCallbackTest::AAudioCallbackTestData124         void reset(int32_t expectedFramesPerCb) {
125             expectedFramesPerCallback = expectedFramesPerCb;
126             actualFramesPerCallback = 0;
127             minLatency = INT32_MAX;
128             maxLatency = 0;
129             callbackError = AAUDIO_OK;
130             callbackCount = 0;
131             returnStop = false;
132         }
updateFrameCountAAudioStreamCallbackTest::AAudioCallbackTestData133         void updateFrameCount(int32_t numFrames) {
134             if (numFrames != expectedFramesPerCallback) {
135                 // record unexpected framecounts
136                 actualFramesPerCallback = numFrames;
137             } else if (actualFramesPerCallback == 0) {
138                 // record at least one frame count
139                 actualFramesPerCallback = numFrames;
140             }
141         }
updateLatencyAAudioStreamCallbackTest::AAudioCallbackTestData142         void updateLatency(int32_t latency) {
143             if (latency <= 0) return;
144             minLatency = std::min(minLatency, latency);
145             maxLatency = std::max(maxLatency, latency);
146         }
waitForNCallbacksAAudioStreamCallbackTest::AAudioCallbackTestData147         bool waitForNCallbacks(int32_t n) {
148             int32_t timeTakenMillis = 0;
149             // Expect each callback to take less than kExtremelyHighCallbackPeriodMillis
150             while (timeTakenMillis < kExtremelyHighCallbackPeriodMillis * n) {
151                 if (callbackCount >= n) {
152                     return true;
153                 }
154                 usleep(kPollTimeMillis * MICROS_PER_MILLISECOND);
155                 timeTakenMillis += kPollTimeMillis;
156             }
157             return false;
158         }
159     };
160 
createAndVerifyHonoringMMap()161     void createAndVerifyHonoringMMap() {
162         aaudio_policy_t originalPolicy = AAUDIO_POLICY_AUTO;
163 
164         // Turn off MMap if requested.
165         bool allowMMap = std::get<PARAM_ALLOW_MMAP>(GetParam()) == MMAP_ALLOWED;
166         if (AAudioExtensions::getInstance().isMMapSupported()) {
167             originalPolicy = AAudioExtensions::getInstance().getMMapPolicy();
168             AAudioExtensions::getInstance().setMMapEnabled(allowMMap);
169         }
170 
171         mHelper->createAndVerifyStream(&mSetupSuccessful);
172 
173         // Restore policy for next test.
174         if (AAudioExtensions::getInstance().isMMapSupported()) {
175             AAudioExtensions::getInstance().setMMapPolicy(originalPolicy);
176         }
177         // Make sure we do not get MMAP when we disable it.
178         if (mSetupSuccessful && !allowMMap) {
179             ASSERT_FALSE(AAudioExtensions::getInstance().isMMapUsed(mHelper->stream()));
180         }
181     }
182 
183     static void MyErrorCallbackProc(AAudioStream *stream, void *userData, aaudio_result_t error);
184 
builder() const185     AAudioStreamBuilder* builder() const { return mHelper->builder(); }
stream() const186     AAudioStream* stream() const { return mHelper->stream(); }
actual() const187     const StreamBuilderHelper::Parameters& actual() const { return mHelper->actual(); }
188 
189     std::unique_ptr<T> mHelper;
190     bool mSetupSuccessful = false;
191     std::unique_ptr<AAudioCallbackTestData> mCbData;
192 };
193 
194 template<typename T>
MyErrorCallbackProc(AAudioStream *,void * userData,aaudio_result_t error)195 void AAudioStreamCallbackTest<T>::MyErrorCallbackProc(
196         AAudioStream* /*stream*/, void *userData, aaudio_result_t error) {
197     AAudioCallbackTestData *myData = static_cast<AAudioCallbackTestData*>(userData);
198     myData->callbackError = error;
199 }
200 
201 
202 class AAudioInputStreamCallbackTest : public AAudioStreamCallbackTest<InputStreamBuilderHelper> {
203   protected:
204     void SetUp() override;
205 
206     static aaudio_data_callback_result_t MyDataCallbackProc(
207             AAudioStream *stream, void *userData, void *audioData, int32_t numFrames);
208 };
209 
MyDataCallbackProc(AAudioStream *,void * userData,void *,int32_t numFrames)210 aaudio_data_callback_result_t AAudioInputStreamCallbackTest::MyDataCallbackProc(
211         AAudioStream* /*stream*/, void *userData, void* /*audioData*/, int32_t numFrames) {
212     AAudioCallbackTestData *myData = static_cast<AAudioCallbackTestData*>(userData);
213     myData->updateFrameCount(numFrames);
214     // No latency measurement as there is no API for querying capture position.
215     myData->callbackCount++;
216     return myData->returnStop ? AAUDIO_CALLBACK_RESULT_STOP : AAUDIO_CALLBACK_RESULT_CONTINUE;
217 }
218 
SetUp()219 void AAudioInputStreamCallbackTest::SetUp() {
220     AAudioCtsBase::SetUp();
221 
222     mSetupSuccessful = false;
223     if (!deviceSupportsFeature(FEATURE_RECORDING)) return;
224     mHelper.reset(new InputStreamBuilderHelper(
225                     std::get<PARAM_SHARING_MODE>(GetParam()),
226                     std::get<PARAM_PERF_MODE>(GetParam()),
227                     std::get<PARAM_AUDIO_FORMAT>(GetParam()),
228                     std::get<PARAM_SAMPLE_RATE>(GetParam()))
229                     );
230     mHelper->initBuilder();
231 
232     int32_t framesPerDataCallback = std::get<PARAM_FRAMES_PER_CB>(GetParam());
233     mCbData.reset(new AAudioCallbackTestData());
234     AAudioStreamBuilder_setErrorCallback(builder(), &MyErrorCallbackProc, mCbData.get());
235     AAudioStreamBuilder_setDataCallback(builder(), &MyDataCallbackProc, mCbData.get());
236     if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
237         AAudioStreamBuilder_setFramesPerDataCallback(builder(), framesPerDataCallback);
238     }
239 
240     createAndVerifyHonoringMMap();
241 }
242 
243 // Test starting and stopping an INPUT AAudioStream that uses a Callback
TEST_P(AAudioInputStreamCallbackTest,testRecording)244 TEST_P(AAudioInputStreamCallbackTest, testRecording) {
245     if (!mSetupSuccessful) return;
246 
247     const int32_t framesPerDataCallback = std::get<PARAM_FRAMES_PER_CB>(GetParam());
248     const int32_t streamFramesPerDataCallback = AAudioStream_getFramesPerDataCallback(stream());
249     if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
250         ASSERT_EQ(framesPerDataCallback, streamFramesPerDataCallback);
251     }
252     const int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream());
253     const int32_t callbackCountsPerBurst = streamFramesPerDataCallback == AAUDIO_UNSPECIFIED ? 1
254             : (framesPerBurst + streamFramesPerDataCallback - 1) / streamFramesPerDataCallback;
255 
256     // Try both methods of stopping a stream.
257     const int kNumMethods = 2;
258 
259     constexpr int kMaxXRunCount = 0;
260 
261     // Start/stop more than once to see if it fails after the first time.
262     // Also check to make sure we do not get callbacks after the stop.
263     for (int loopIndex = 0; loopIndex < kNumMethods; loopIndex++) {
264         mCbData->reset(streamFramesPerDataCallback);
265 
266         mHelper->startStream();
267         // See b/62090113. For legacy path, the device is only known after
268         // the stream has been started.
269         EXPECT_NE(AAUDIO_UNSPECIFIED, AAudioStream_getDeviceId(stream()));
270         EXPECT_TRUE(mCbData->waitForNCallbacks(kExpectedCallbackCount));
271 
272         ASSERT_EQ(AAUDIO_OK, mCbData->callbackError);
273         ASSERT_GE(mCbData->callbackCount, kExpectedCallbackCount);
274 
275         ASSERT_LE(AAudioStream_getXRunCount(stream()), kMaxXRunCount);
276 
277         switch (loopIndex % kNumMethods) {
278             case 0:
279                 mCbData->returnStop = true; // callback return
280                 mHelper->waitForState(AAUDIO_STREAM_STATE_STOPPED);
281                 break;
282             case 1:
283                 mHelper->stopStream();
284                 break;
285         }
286 
287         int32_t oldCallbackCount = mCbData->callbackCount;
288         EXPECT_GE(oldCallbackCount, kExpectedCallbackCount);
289         usleep(kExtremelyHighCallbackPeriodMillis * MICROS_PER_MILLISECOND);
290         if ((AAudioExtensions::getInstance().isMMapUsed(mHelper->stream()))) {
291             EXPECT_EQ(oldCallbackCount, mCbData->callbackCount); // expect not advancing
292         } else {
293             // Allow requesting at most one burst size data from callback after stopping
294             EXPECT_GE(mCbData->callbackCount, oldCallbackCount);
295             EXPECT_LE(mCbData->callbackCount, oldCallbackCount + callbackCountsPerBurst);
296         }
297 
298         if (streamFramesPerDataCallback != AAUDIO_UNSPECIFIED) {
299             ASSERT_EQ(streamFramesPerDataCallback, mCbData->actualFramesPerCallback);
300         }
301 
302         ASSERT_EQ(AAUDIO_OK, mCbData->callbackError);
303     }
304 }
305 
306 INSTANTIATE_TEST_CASE_P(SPM, AAudioInputStreamCallbackTest,
307         ::testing::Values(
308                 std::make_tuple(
309                         AAUDIO_SHARING_MODE_SHARED,
310                         AAUDIO_UNSPECIFIED,
311                         AAUDIO_PERFORMANCE_MODE_NONE,
312                         MMAP_ALLOWED,
313                         AAUDIO_FORMAT_UNSPECIFIED,
314                         48000),
315                 // cb buffer size: arbitrary prime number < 96
316                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_NONE, MMAP_ALLOWED,
317                         AAUDIO_FORMAT_UNSPECIFIED, 48000),
318                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
319                         AAUDIO_FORMAT_UNSPECIFIED, 48000),
320                 std::make_tuple(AAUDIO_SHARING_MODE_EXCLUSIVE, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
321                         AAUDIO_FORMAT_UNSPECIFIED, 48000),
322                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_NOT_ALLOWED,
323                         AAUDIO_FORMAT_PCM_I16, 48000),
324                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_NOT_ALLOWED,
325                         AAUDIO_FORMAT_PCM_FLOAT, 48000),
326                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
327                         AAUDIO_FORMAT_UNSPECIFIED, 44100),
328                 std::make_tuple(AAUDIO_SHARING_MODE_EXCLUSIVE, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
329                         AAUDIO_FORMAT_UNSPECIFIED, 44100),
330                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_NOT_ALLOWED,
331                         AAUDIO_FORMAT_UNSPECIFIED, 44100),
332                 // cb buffer size: arbitrary prime number > 192
333                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 223, AAUDIO_PERFORMANCE_MODE_NONE, MMAP_ALLOWED,
334                         AAUDIO_FORMAT_UNSPECIFIED, 48000),
335                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 223, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
336                         AAUDIO_FORMAT_UNSPECIFIED, 48000),
337                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 223, AAUDIO_PERFORMANCE_MODE_NONE, MMAP_ALLOWED,
338                         AAUDIO_FORMAT_UNSPECIFIED, 11025),
339                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 223, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
340                         AAUDIO_FORMAT_UNSPECIFIED, 11025),
341                 // Recording in POWER_SAVING mode isn't supported, b/62291775.
342                 std::make_tuple(
343                         AAUDIO_SHARING_MODE_SHARED,
344                         AAUDIO_UNSPECIFIED,
345                         AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
346                         MMAP_ALLOWED,
347                         AAUDIO_FORMAT_UNSPECIFIED,
348                         48000),
349                 std::make_tuple(
350                         AAUDIO_SHARING_MODE_EXCLUSIVE,
351                         AAUDIO_UNSPECIFIED,
352                         AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
353                         MMAP_ALLOWED,
354                         AAUDIO_FORMAT_UNSPECIFIED,
355                         48000),
356                 std::make_tuple(
357                         AAUDIO_SHARING_MODE_EXCLUSIVE,
358                         AAUDIO_UNSPECIFIED,
359                         AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
360                         MMAP_ALLOWED,
361                         AAUDIO_FORMAT_UNSPECIFIED,
362                         88200)),
363         &getTestName);
364 
365 
366 class AAudioOutputStreamCallbackTest : public AAudioStreamCallbackTest<OutputStreamBuilderHelper> {
367   protected:
368     void SetUp() override;
369 
370     static aaudio_data_callback_result_t MyDataCallbackProc(
371             AAudioStream *stream, void *userData, void *audioData, int32_t numFrames);
372 };
373 
374 // Callback function that fills the audio output buffer.
MyDataCallbackProc(AAudioStream * stream,void * userData,void * audioData,int32_t numFrames)375 aaudio_data_callback_result_t AAudioOutputStreamCallbackTest::MyDataCallbackProc(
376         AAudioStream *stream,
377         void *userData,
378         void *audioData,
379         int32_t numFrames) {
380     int32_t channelCount = AAudioStream_getChannelCount(stream);
381     int32_t numSamples = channelCount * numFrames;
382     if (AAudioStream_getFormat(stream) == AAUDIO_FORMAT_PCM_I16) {
383         int16_t *shortData = (int16_t *) audioData;
384         for (int i = 0; i < numSamples; i++) *shortData++ = 0;
385     } else if (AAudioStream_getFormat(stream) == AAUDIO_FORMAT_PCM_FLOAT) {
386         float *floatData = (float *) audioData;
387         for (int i = 0; i < numSamples; i++) *floatData++ = 0.0f;
388     }
389 
390     AAudioCallbackTestData *myData = static_cast<AAudioCallbackTestData*>(userData);
391     myData->updateFrameCount(numFrames);
392     myData->updateLatency(measureLatency(stream));
393     myData->callbackCount++;
394     return myData->returnStop ? AAUDIO_CALLBACK_RESULT_STOP : AAUDIO_CALLBACK_RESULT_CONTINUE;
395 }
396 
SetUp()397 void AAudioOutputStreamCallbackTest::SetUp() {
398     AAudioCtsBase::SetUp();
399 
400     mSetupSuccessful = false;
401     if (!deviceSupportsFeature(FEATURE_PLAYBACK)) return;
402     mHelper.reset(new OutputStreamBuilderHelper(
403                     std::get<PARAM_SHARING_MODE>(GetParam()),
404                     std::get<PARAM_PERF_MODE>(GetParam()),
405                     std::get<PARAM_AUDIO_FORMAT>(GetParam()),
406                     std::get<PARAM_SAMPLE_RATE>(GetParam()))
407                     );
408     mHelper->initBuilder();
409 
410     int32_t framesPerDataCallback = std::get<PARAM_FRAMES_PER_CB>(GetParam());
411     mCbData.reset(new AAudioCallbackTestData());
412     AAudioStreamBuilder_setErrorCallback(builder(), &MyErrorCallbackProc, mCbData.get());
413     AAudioStreamBuilder_setDataCallback(builder(), &MyDataCallbackProc, mCbData.get());
414     if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
415         AAudioStreamBuilder_setFramesPerDataCallback(builder(), framesPerDataCallback);
416     }
417 
418     createAndVerifyHonoringMMap();
419 
420 }
421 
422 // Test starting and stopping an OUTPUT AAudioStream that uses a Callback
TEST_P(AAudioOutputStreamCallbackTest,testPlayback)423 TEST_P(AAudioOutputStreamCallbackTest, testPlayback) {
424     if (!mSetupSuccessful) return;
425 
426     const int32_t framesPerDataCallback = std::get<PARAM_FRAMES_PER_CB>(GetParam());
427     const int32_t streamFramesPerDataCallback = AAudioStream_getFramesPerDataCallback(stream());
428     if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
429         ASSERT_EQ(framesPerDataCallback, streamFramesPerDataCallback);
430     }
431     const int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream());
432     const int32_t callbackCountsPerBurst = streamFramesPerDataCallback == AAUDIO_UNSPECIFIED ? 1
433                 : (framesPerBurst + streamFramesPerDataCallback - 1) / streamFramesPerDataCallback;
434 
435     // Try all 3 methods of stopping/pausing a stream.
436     constexpr int kNumMethods = 3;
437 
438     // Pausing or stopping an output stream without setting returnStop sometimes results in a xRun.
439     constexpr int kMaxXRunCount = 1;
440 
441     // Start/stop more than once to see if it fails after the first time.
442     // Also check to make sure we do not get callbacks after the stop.
443     for (int loopIndex = 0; loopIndex < kNumMethods; loopIndex++) {
444         mCbData->reset(streamFramesPerDataCallback);
445 
446         mHelper->startStream();
447         // See b/62090113. For legacy path, the device is only known after
448         // the stream has been started.
449         EXPECT_NE(AAUDIO_UNSPECIFIED, AAudioStream_getDeviceId(stream()));
450         EXPECT_TRUE(mCbData->waitForNCallbacks(kExpectedCallbackCount));
451 
452         ASSERT_EQ(AAUDIO_OK, mCbData->callbackError);
453         ASSERT_GE(mCbData->callbackCount, kExpectedCallbackCount);
454 
455         ASSERT_LE(AAudioStream_getXRunCount(stream()), kMaxXRunCount);
456 
457         switch (loopIndex % kNumMethods) {
458             case 0:
459                 mCbData->returnStop = true; // callback return
460                 mHelper->waitForState(AAUDIO_STREAM_STATE_STOPPED);
461                 break;
462             case 1:
463                 mHelper->pauseStream();
464                 break;
465             case 2:
466                 mHelper->stopStream();
467                 break;
468         }
469 
470         int32_t oldCallbackCount = mCbData->callbackCount;
471         EXPECT_GE(oldCallbackCount, kExpectedCallbackCount);
472         usleep(kExtremelyHighCallbackPeriodMillis * MICROS_PER_MILLISECOND);
473         if (AAudioExtensions::getInstance().isMMapUsed(mHelper->stream())) {
474             EXPECT_EQ(oldCallbackCount, mCbData->callbackCount); // expect not advancing
475         } else {
476             // Allow requesting at most one burst size data from callback after stopping
477             EXPECT_GE(mCbData->callbackCount, oldCallbackCount);
478             EXPECT_LE(mCbData->callbackCount, oldCallbackCount + callbackCountsPerBurst);
479         }
480 
481         if (streamFramesPerDataCallback != AAUDIO_UNSPECIFIED) {
482             ASSERT_EQ(streamFramesPerDataCallback, mCbData->actualFramesPerCallback);
483         }
484 
485         EXPECT_GE(mCbData->minLatency, 1);   // Absurdly low
486         // We only issue a warning here because the CDD does not mandate a specific minimum latency
487         if (mCbData->maxLatency > 300) {
488             __android_log_print(ANDROID_LOG_WARN, LOG_TAG,
489                     "Suspiciously high callback latency: %d", mCbData->maxLatency);
490         }
491         //printf("latency: %d, %d\n", mCbData->minLatency, mCbData->maxLatency);
492 
493         ASSERT_EQ(AAUDIO_OK, mCbData->callbackError);
494     }
495 }
496 
497 INSTANTIATE_TEST_CASE_P(SPM, AAudioOutputStreamCallbackTest,
498         ::testing::Values(
499                 std::make_tuple(
500                         AAUDIO_SHARING_MODE_SHARED,
501                         AAUDIO_UNSPECIFIED,
502                         AAUDIO_PERFORMANCE_MODE_NONE,
503                         MMAP_ALLOWED,
504                         AAUDIO_FORMAT_UNSPECIFIED,
505                         48000),
506                 // cb buffer size: arbitrary prime number < 96
507                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_NONE, MMAP_ALLOWED,
508                         AAUDIO_FORMAT_UNSPECIFIED, 48000),
509                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
510                         AAUDIO_FORMAT_UNSPECIFIED, 48000),
511                 std::make_tuple(AAUDIO_SHARING_MODE_EXCLUSIVE, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
512                         AAUDIO_FORMAT_UNSPECIFIED, 48000),
513                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_NOT_ALLOWED,
514                         AAUDIO_FORMAT_PCM_I16, 48000),
515                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_NOT_ALLOWED,
516                         AAUDIO_FORMAT_PCM_FLOAT, 48000),
517                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
518                         AAUDIO_FORMAT_UNSPECIFIED, 44100),
519                 std::make_tuple(AAUDIO_SHARING_MODE_EXCLUSIVE, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
520                         AAUDIO_FORMAT_UNSPECIFIED, 44100),
521                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 67, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_NOT_ALLOWED,
522                         AAUDIO_FORMAT_UNSPECIFIED, 44100),
523                 // cb buffer size: arbitrary prime number > 192
524                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 223, AAUDIO_PERFORMANCE_MODE_NONE, MMAP_ALLOWED,
525                         AAUDIO_FORMAT_UNSPECIFIED, 48000),
526                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 223, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
527                         AAUDIO_FORMAT_UNSPECIFIED, 48000),
528                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 223, AAUDIO_PERFORMANCE_MODE_NONE, MMAP_ALLOWED,
529                         AAUDIO_FORMAT_UNSPECIFIED, 11025),
530                 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, 223, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, MMAP_ALLOWED,
531                         AAUDIO_FORMAT_UNSPECIFIED, 11025),
532                 std::make_tuple(
533                         AAUDIO_SHARING_MODE_SHARED,
534                         AAUDIO_UNSPECIFIED,
535                         AAUDIO_PERFORMANCE_MODE_POWER_SAVING,
536                         MMAP_ALLOWED,
537                         AAUDIO_FORMAT_UNSPECIFIED,
538                         48000),
539                 std::make_tuple(
540                         AAUDIO_SHARING_MODE_SHARED,
541                         AAUDIO_UNSPECIFIED,
542                         AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
543                         MMAP_ALLOWED,
544                         AAUDIO_FORMAT_UNSPECIFIED,
545                         48000),
546                 std::make_tuple(
547                         AAUDIO_SHARING_MODE_EXCLUSIVE,
548                         AAUDIO_UNSPECIFIED,
549                         AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
550                         MMAP_ALLOWED,
551                         AAUDIO_FORMAT_UNSPECIFIED,
552                         48000),
553                 std::make_tuple(
554                         AAUDIO_SHARING_MODE_EXCLUSIVE,
555                         AAUDIO_UNSPECIFIED,
556                         AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
557                         MMAP_ALLOWED,
558                         AAUDIO_FORMAT_UNSPECIFIED,
559                         88200)),
560         &getTestName);
561