1 /*
2 * Copyright (C) 2019 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 whether a stream dies if it is written to after a delay.
18 // Maybe because the message queue from the AAudio service fills up.
19
20 #define LOG_TAG "test_full_queue"
21 //#define LOG_NDEBUG 0
22 #include <utils/Log.h>
23
24 #include <stdio.h>
25 #include <unistd.h>
26
27 #include <aaudio/AAudio.h>
28 #include <gtest/gtest.h>
29 #include <cstdlib>
30 #include <algorithm>
31
32 constexpr int64_t kNanosPerMillisecond = 1e6;
33 constexpr int64_t kMicrosPerMillisecond = 1000;
34 constexpr int64_t kTimeoutNanos = 50 * kNanosPerMillisecond;
35 constexpr int kNumFrames = 256;
36 constexpr int kChannelCount = 2;
37 constexpr int kNumSamples = kChannelCount * kNumFrames;
38
checkFullQueue(aaudio_performance_mode_t perfMode,aaudio_sharing_mode_t sharingMode,int32_t sleepMillis)39 static void checkFullQueue(aaudio_performance_mode_t perfMode,
40 aaudio_sharing_mode_t sharingMode,
41 int32_t sleepMillis) {
42 aaudio_result_t result;
43 std::unique_ptr<float[]> buffer = std::make_unique<float[]>(kNumSamples);
44 for (int i = 0; i < kNumSamples; i++) {
45 buffer[i] = (drand48() - 0.5) * 0.05; // random buzzy waveform
46 }
47
48 AAudioStreamBuilder *aaudioBuilder = nullptr;
49
50 // Use an AAudioStreamBuilder to contain requested parameters.
51 ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
52
53 // Request stream properties.
54 AAudioStreamBuilder_setChannelCount(aaudioBuilder, kChannelCount);
55 AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, perfMode);
56 AAudioStreamBuilder_setSharingMode(aaudioBuilder, sharingMode);
57
58 // Create an AAudioStream using the Builder.
59 AAudioStream *aaudioStream = nullptr;
60 ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder,
61 &aaudioStream));
62 AAudioStreamBuilder_delete(aaudioBuilder);
63
64 int bufferSize = std::max(
65 2 * AAudioStream_getFramesPerBurst(aaudioStream),
66 2 * kNumFrames
67 );
68 AAudioStream_setBufferSizeInFrames(aaudioStream, bufferSize);
69
70 EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream));
71
72 #if 0
73 int32_t capacity = AAudioStream_getBufferCapacityInFrames(aaudioStream);
74 ASSERT_LT(20, capacity);
75 int numWrites = 30 * capacity / kNumFrames;
76 #else
77 int32_t sampleRate = AAudioStream_getSampleRate(aaudioStream);
78 EXPECT_LT(7000, sampleRate);
79 int numWrites = 1 * sampleRate / kNumFrames;
80 #endif
81
82 for (int i = 0; i < numWrites/2; i++) {
83 result = AAudioStream_write(aaudioStream,
84 buffer.get(),
85 kNumFrames,
86 kTimeoutNanos);
87 EXPECT_EQ(kNumFrames, result);
88 if (kNumFrames != result) break;
89 }
90
91 // Sleep for awhile. This might kill the stream.
92 ALOGD("%s() start sleeping %d millis", __func__, sleepMillis);
93 usleep(sleepMillis * kMicrosPerMillisecond);
94 ALOGD("%s() start writing", __func__);
95
96 // Let CPU catch up with the hardware.
97 int64_t framesRead = AAudioStream_getFramesRead(aaudioStream);
98 int64_t framesWritten = AAudioStream_getFramesWritten(aaudioStream);
99
100 ALOGD("%s() after hang, read = %jd, written = %jd, w-r = %jd",
101 __func__, (intmax_t) framesRead, (intmax_t) framesWritten,
102 (intmax_t)(framesWritten - framesRead));
103 int countDown = 2 * sleepMillis * sampleRate / (kNumFrames * 1000);
104 do {
105 result = AAudioStream_write(aaudioStream,
106 buffer.get(),
107 kNumFrames,
108 kTimeoutNanos);
109
110 ALOGD("%s() catching up, wrote %d frames", __func__, result);
111 framesRead = AAudioStream_getFramesRead(aaudioStream);
112 framesWritten = AAudioStream_getFramesWritten(aaudioStream);
113 countDown--;
114 } while ((framesRead > framesWritten)
115 && (countDown > 0)
116 && (kNumFrames == result));
117 EXPECT_LE(framesRead, framesWritten);
118 EXPECT_GT(countDown, 0);
119 EXPECT_EQ(kNumFrames, result);
120 ALOGD("%s() after catch up, read = %jd, written = %jd, w-r = %jd",
121 __func__, (intmax_t) framesRead, (intmax_t) framesWritten,
122 (intmax_t)(framesWritten - framesRead));
123
124 // Try to keep the stream full.
125 for (int i = 0; i < numWrites; i++) {
126 ALOGD("%s() try to write", __func__);
127 result = AAudioStream_write(aaudioStream,
128 buffer.get(),
129 kNumFrames,
130 kTimeoutNanos);
131 ALOGD("%s() wrote %d frames", __func__, result);
132 EXPECT_EQ(kNumFrames, result);
133 if (kNumFrames != result) break;
134 }
135
136 EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
137
138 EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
139 }
140
141 // ==== Default Latency, SHARED ===========
TEST(test_full_queue,aaudio_full_queue_perf_none_sh_50)142 TEST(test_full_queue, aaudio_full_queue_perf_none_sh_50) {
143 checkFullQueue(AAUDIO_PERFORMANCE_MODE_NONE,
144 AAUDIO_SHARING_MODE_SHARED, 50 /* sleepMillis */);
145 }
146
TEST(test_full_queue,aaudio_full_queue_perf_none_sh_400)147 TEST(test_full_queue, aaudio_full_queue_perf_none_sh_400) {
148 checkFullQueue(AAUDIO_PERFORMANCE_MODE_NONE,
149 AAUDIO_SHARING_MODE_SHARED, 400 /* sleepMillis */);
150 }
151
TEST(test_full_queue,aaudio_full_queue_perf_none_sh_1000)152 TEST(test_full_queue, aaudio_full_queue_perf_none_sh_1000) {
153 checkFullQueue(AAUDIO_PERFORMANCE_MODE_NONE,
154 AAUDIO_SHARING_MODE_SHARED, 1000 /* sleepMillis */);
155 }
156
157 // ==== Low Latency, SHARED ===========
TEST(test_full_queue,aaudio_full_queue_low_latency_sh_50)158 TEST(test_full_queue, aaudio_full_queue_low_latency_sh_50) {
159 checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
160 AAUDIO_SHARING_MODE_SHARED, 50 /* sleepMillis */);
161 }
162
TEST(test_full_queue,aaudio_full_queue_low_latency_sh_400)163 TEST(test_full_queue, aaudio_full_queue_low_latency_sh_400) {
164 checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
165 AAUDIO_SHARING_MODE_SHARED, 400 /* sleepMillis */);
166 }
167
TEST(test_full_queue,aaudio_full_queue_low_latency_sh_1000)168 TEST(test_full_queue, aaudio_full_queue_low_latency_sh_1000) {
169 checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
170 AAUDIO_SHARING_MODE_SHARED, 1000 /* sleepMillis */);
171 }
172
173 // ==== Low Latency, EXCLUSIVE ===========
TEST(test_full_queue,aaudio_full_queue_low_latency_excl_50)174 TEST(test_full_queue, aaudio_full_queue_low_latency_excl_50) {
175 checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
176 AAUDIO_SHARING_MODE_EXCLUSIVE, 50 /* sleepMillis */);
177 }
178
TEST(test_full_queue,aaudio_full_queue_low_latency_excl_400)179 TEST(test_full_queue, aaudio_full_queue_low_latency_excl_400) {
180 checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
181 AAUDIO_SHARING_MODE_EXCLUSIVE, 400 /* sleepMillis */);
182 }
183
TEST(test_full_queue,aaudio_full_queue_low_latency_excl_1000)184 TEST(test_full_queue, aaudio_full_queue_low_latency_excl_1000) {
185 checkFullQueue(AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
186 AAUDIO_SHARING_MODE_EXCLUSIVE, 1000 /* sleepMillis */);
187 }
188