1 /*
2 * Copyright 2016 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 <memory>
21 #include <tuple>
22
23 #include <unistd.h>
24
25 #include <aaudio/AAudio.h>
26 #include <android/log.h>
27 #include <gtest/gtest.h>
28
29 #include "test_aaudio.h"
30 #include "utils.h"
31
32 using StreamTestParams = std::tuple<aaudio_sharing_mode_t, aaudio_performance_mode_t>;
33 enum {
34 PARAM_SHARING_MODE = 0,
35 PARAM_PERF_MODE
36 };
37
getTestName(const::testing::TestParamInfo<StreamTestParams> & info)38 static std::string getTestName(const ::testing::TestParamInfo<StreamTestParams>& info) {
39 return std::string() + sharingModeToString(std::get<PARAM_SHARING_MODE>(info.param)) +
40 "__" + performanceModeToString(std::get<PARAM_PERF_MODE>(info.param));
41 }
42
43 template<typename T>
44 class AAudioStreamTest : public ::testing::TestWithParam<StreamTestParams> {
45 protected:
builder() const46 AAudioStreamBuilder* builder() const { return mHelper->builder(); }
stream() const47 AAudioStream* stream() const { return mHelper->stream(); }
actual() const48 const StreamBuilderHelper::Parameters& actual() const { return mHelper->actual(); }
framesPerBurst() const49 int32_t framesPerBurst() const { return mHelper->framesPerBurst(); }
50
51 std::unique_ptr<T> mHelper;
52 bool mSetupSuccesful = false;
53 std::unique_ptr<int16_t[]> mData;
54 };
55
56
57 class AAudioInputStreamTest : public AAudioStreamTest<InputStreamBuilderHelper> {
58 protected:
59 void SetUp() override;
60
61 int32_t mFramesPerRead;
62 };
63
SetUp()64 void AAudioInputStreamTest::SetUp() {
65 mHelper.reset(new InputStreamBuilderHelper(
66 std::get<PARAM_SHARING_MODE>(GetParam()),
67 std::get<PARAM_PERF_MODE>(GetParam())));
68 mHelper->initBuilder();
69 mSetupSuccesful = false;
70 mHelper->createAndVerifyStream(&mSetupSuccesful);
71 if (!mSetupSuccesful) return;
72
73 mFramesPerRead = framesPerBurst();
74 const int32_t framesPerMsec = actual().sampleRate / MILLIS_PER_SECOND;
75 // Some DMA might use very short bursts of 16 frames. We don't need to read such small
76 // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
77 while (mFramesPerRead < framesPerMsec) {
78 mFramesPerRead *= 2;
79 }
80 mData.reset(new int16_t[mFramesPerRead * actual().channelCount]);
81 }
82
TEST_P(AAudioInputStreamTest,testReading)83 TEST_P(AAudioInputStreamTest, testReading) {
84 if (!mSetupSuccesful) return;
85
86 const int32_t framesToRecord = actual().sampleRate; // 1 second
87 EXPECT_EQ(0, AAudioStream_getFramesRead(stream()));
88 EXPECT_EQ(0, AAudioStream_getFramesWritten(stream()));
89 mHelper->startStream();
90 // See b/62090113. For legacy path, the device is only known after
91 // the stream has been started.
92 ASSERT_NE(AAUDIO_UNSPECIFIED, AAudioStream_getDeviceId(stream()));
93 for (int32_t framesLeft = framesToRecord; framesLeft > 0; ) {
94 aaudio_result_t result = AAudioStream_read(
95 stream(), &mData[0], std::min(framesToRecord, mFramesPerRead),
96 DEFAULT_READ_TIMEOUT);
97 ASSERT_GT(result, 0);
98 framesLeft -= result;
99 }
100 mHelper->stopStream();
101 EXPECT_GE(AAudioStream_getFramesRead(stream()), framesToRecord);
102 EXPECT_GE(AAudioStream_getFramesWritten(stream()), framesToRecord);
103 EXPECT_GE(AAudioStream_getXRunCount(stream()), 0);
104 }
105
TEST_P(AAudioInputStreamTest,testStartReadStop)106 TEST_P(AAudioInputStreamTest, testStartReadStop) {
107 if (!mSetupSuccesful) return;
108
109 // Use 1/8 second as start-stops take a lot more time than just recording.
110 const int32_t framesToRecord = actual().sampleRate / 8;
111 EXPECT_EQ(0, AAudioStream_getFramesRead(stream()));
112 EXPECT_EQ(0, AAudioStream_getFramesWritten(stream()));
113 for (int32_t framesLeft = framesToRecord; framesLeft > 0; ) {
114 mHelper->startStream();
115 aaudio_result_t result = AAudioStream_read(
116 stream(), &mData[0], std::min(framesToRecord, mFramesPerRead),
117 DEFAULT_READ_TIMEOUT);
118 ASSERT_GT(result, 0);
119 framesLeft -= result;
120 mHelper->stopStream();
121 }
122 EXPECT_GE(AAudioStream_getFramesRead(stream()), framesToRecord);
123 EXPECT_GE(AAudioStream_getFramesWritten(stream()), framesToRecord);
124 }
125
TEST_P(AAudioInputStreamTest,testReadCounterFreezeAfterStop)126 TEST_P(AAudioInputStreamTest, testReadCounterFreezeAfterStop) {
127 if (!mSetupSuccesful) return;
128
129 const int32_t framesToRecord = actual().sampleRate / 10; // 1/10 second
130 EXPECT_EQ(0, AAudioStream_getFramesRead(stream()));
131 EXPECT_EQ(0, AAudioStream_getFramesWritten(stream()));
132 mHelper->startStream();
133 for (int32_t framesLeft = framesToRecord; framesLeft > 0; ) {
134 aaudio_result_t result = AAudioStream_read(
135 stream(), &mData[0], std::min(framesToRecord, mFramesPerRead),
136 DEFAULT_READ_TIMEOUT);
137 ASSERT_GT(result, 0);
138 framesLeft -= result;
139 }
140 mHelper->stopStream();
141 const int32_t framesReadAtStop = AAudioStream_getFramesRead(stream());
142 const int32_t framesWrittenAtStop = AAudioStream_getFramesWritten(stream());
143 ASSERT_EQ(0, TEMP_FAILURE_RETRY(usleep(100 * MICROS_PER_MILLISECOND)));
144 EXPECT_EQ(framesReadAtStop, AAudioStream_getFramesRead(stream()));
145 EXPECT_EQ(framesWrittenAtStop, AAudioStream_getFramesWritten(stream()));
146 }
147
TEST_P(AAudioInputStreamTest,testPauseAndFlushNotSupported)148 TEST_P(AAudioInputStreamTest, testPauseAndFlushNotSupported) {
149 if (!mSetupSuccesful) return;
150 mHelper->startStream();
151 EXPECT_EQ(AAUDIO_ERROR_UNIMPLEMENTED, AAudioStream_requestPause(stream()));
152 EXPECT_EQ(AAUDIO_ERROR_UNIMPLEMENTED, AAudioStream_requestFlush(stream()));
153 mHelper->stopStream();
154 }
155
156 INSTANTIATE_TEST_CASE_P(SPM, AAudioInputStreamTest,
157 ::testing::Values(
158 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, AAUDIO_PERFORMANCE_MODE_NONE),
159 // Recording in POWER_SAVING mode isn't supported, b/62291775.
160 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY),
161 std::make_tuple(AAUDIO_SHARING_MODE_EXCLUSIVE, AAUDIO_PERFORMANCE_MODE_NONE),
162 std::make_tuple(
163 AAUDIO_SHARING_MODE_EXCLUSIVE, AAUDIO_PERFORMANCE_MODE_POWER_SAVING),
164 std::make_tuple(
165 AAUDIO_SHARING_MODE_EXCLUSIVE, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY)),
166 &getTestName);
167
168
169 class AAudioOutputStreamTest : public AAudioStreamTest<OutputStreamBuilderHelper> {
170 protected:
171 void SetUp() override;
172 };
173
SetUp()174 void AAudioOutputStreamTest::SetUp() {
175 mHelper.reset(new OutputStreamBuilderHelper(
176 std::get<PARAM_SHARING_MODE>(GetParam()),
177 std::get<PARAM_PERF_MODE>(GetParam())));
178 mHelper->initBuilder();
179
180 mSetupSuccesful = false;
181 mHelper->createAndVerifyStream(&mSetupSuccesful);
182 if (!mSetupSuccesful) return;
183
184 // Allocate a buffer for the audio data.
185 // TODO handle possibility of other data formats
186 size_t dataSizeSamples = framesPerBurst() * actual().channelCount;
187 mData.reset(new int16_t[dataSizeSamples]);
188 memset(&mData[0], 0, dataSizeSamples);
189 }
190
TEST_P(AAudioOutputStreamTest,testWriting)191 TEST_P(AAudioOutputStreamTest, testWriting) {
192 if (!mSetupSuccesful) return;
193
194 // Prime the buffer.
195 int32_t framesWritten = 0;
196 int64_t framesTotal = 0;
197 int64_t timeoutNanos = 0;
198 do {
199 framesWritten = AAudioStream_write(
200 stream(), &mData[0], framesPerBurst(), timeoutNanos);
201 // There should be some room for priming the buffer.
202 framesTotal += framesWritten;
203 ASSERT_GE(framesWritten, 0);
204 ASSERT_LE(framesWritten, framesPerBurst());
205 } while (framesWritten > 0);
206 ASSERT_TRUE(framesTotal > 0);
207
208 int writeLoops = 0;
209 int64_t aaudioFramesRead = 0;
210 int64_t aaudioFramesReadPrev = 0;
211 int64_t aaudioFramesReadFinal = 0;
212 int64_t aaudioFramesWritten = 0;
213 // Start/write/pause more than once to see if it fails after the first time.
214 // Write some data and measure the rate to see if the timing is OK.
215 for (int numLoops = 0; numLoops < 2; numLoops++) {
216 mHelper->startStream();
217 // See b/62090113. For legacy path, the device is only known after
218 // the stream has been started.
219 ASSERT_NE(AAUDIO_UNSPECIFIED, AAudioStream_getDeviceId(stream()));
220
221 // Write some data while we are running. Read counter should be advancing.
222 writeLoops = 1 * actual().sampleRate / framesPerBurst(); // 1 second
223 ASSERT_LT(2, writeLoops); // detect absurdly high framesPerBurst
224 timeoutNanos = 100 * (NANOS_PER_SECOND * framesPerBurst() /
225 actual().sampleRate); // N bursts
226 framesWritten = 1;
227 aaudioFramesRead = AAudioStream_getFramesRead(stream());
228 aaudioFramesReadPrev = aaudioFramesRead;
229 int64_t beginTime = getNanoseconds(CLOCK_MONOTONIC);
230 do {
231 framesWritten = AAudioStream_write(
232 stream(), &mData[0], framesPerBurst(), timeoutNanos);
233 EXPECT_EQ(framesPerBurst(), framesWritten);
234
235 framesTotal += framesWritten;
236 aaudioFramesWritten = AAudioStream_getFramesWritten(stream());
237 EXPECT_EQ(framesTotal, aaudioFramesWritten);
238
239 // Try to get a more accurate measure of the sample rate.
240 if (beginTime == 0) {
241 aaudioFramesRead = AAudioStream_getFramesRead(stream());
242 if (aaudioFramesRead > aaudioFramesReadPrev) { // is read pointer advancing
243 beginTime = getNanoseconds(CLOCK_MONOTONIC);
244 aaudioFramesReadPrev = aaudioFramesRead;
245 }
246 }
247 } while (framesWritten > 0 && writeLoops-- > 0);
248
249 aaudioFramesReadFinal = AAudioStream_getFramesRead(stream());
250 ASSERT_GT(aaudioFramesReadFinal, 0);
251 EXPECT_GT(aaudioFramesReadFinal, aaudioFramesReadPrev);
252
253
254 // TODO why is AudioTrack path so inaccurate?
255 /* See b/38268547, there is no way to specify that MMAP mode needs to be used,
256 even EXCLUSIVE mode may fall back to legacy
257 const int64_t endTime = getNanoseconds(CLOCK_MONOTONIC);
258 const double rateTolerance = 200.0; // arbitrary tolerance for sample rate
259 if (std::get<PARAM_SHARING_MODE>(GetParam()) != AAUDIO_SHARING_MODE_SHARED) {
260 // Calculate approximate sample rate and compare with stream rate.
261 double seconds = (endTime - beginTime) / (double) NANOS_PER_SECOND;
262 double measuredRate = (aaudioFramesReadFinal - aaudioFramesReadPrev) / seconds;
263 ASSERT_NEAR(actual().sampleRate, measuredRate, rateTolerance);
264 }
265 */
266
267 mHelper->pauseStream();
268 }
269 EXPECT_GE(AAudioStream_getXRunCount(stream()), 0);
270
271 // Make sure the read counter is not advancing when we are paused.
272 aaudioFramesRead = AAudioStream_getFramesRead(stream());
273 ASSERT_GE(aaudioFramesRead, aaudioFramesReadFinal); // monotonic increase
274 // Currently not possible to enforce for AAudio over AudioTrack (b/33354715).
275 // ASSERT_EQ(0, TEMP_FAILURE_RETRY(usleep(100 * MICROS_PER_MILLISECOND)));
276 // EXPECT_EQ(aaudioFramesRead, AAudioStream_getFramesRead(stream()));
277
278 // ------------------- TEST FLUSH -----------------
279 // Prime the buffer.
280 timeoutNanos = 0;
281 writeLoops = 1000;
282 do {
283 framesWritten = AAudioStream_write(
284 stream(), &mData[0], framesPerBurst(), timeoutNanos);
285 framesTotal += framesWritten;
286 } while (framesWritten > 0 && writeLoops-- > 0);
287 EXPECT_EQ(0, framesWritten);
288
289 mHelper->flushStream();
290
291 // After a flush, the read counter should be caught up with the write counter.
292 aaudioFramesWritten = AAudioStream_getFramesWritten(stream());
293 EXPECT_EQ(framesTotal, aaudioFramesWritten);
294 aaudioFramesRead = AAudioStream_getFramesRead(stream());
295 EXPECT_EQ(aaudioFramesWritten, aaudioFramesRead);
296
297 sleep(1); // FIXME - The write returns 0 if we remove this sleep! Why?
298
299 // The buffer should be empty after a flush so we should be able to write.
300 framesWritten = AAudioStream_write(stream(), &mData[0], framesPerBurst(), timeoutNanos);
301 // There should be some room for priming the buffer.
302 ASSERT_GT(framesWritten, 0);
303 ASSERT_LE(framesWritten, framesPerBurst());
304 }
305
306 // Note that the test for EXCLUSIVE sharing mode may fail gracefully if
307 // this mode isn't supported by the platform.
308 INSTANTIATE_TEST_CASE_P(SPM, AAudioOutputStreamTest,
309 ::testing::Values(
310 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, AAUDIO_PERFORMANCE_MODE_NONE),
311 std::make_tuple(AAUDIO_SHARING_MODE_SHARED, AAUDIO_PERFORMANCE_MODE_POWER_SAVING),
312 // No test for SHARED / LOW_LATENCY, see b/62101041
313 std::make_tuple(AAUDIO_SHARING_MODE_EXCLUSIVE, AAUDIO_PERFORMANCE_MODE_NONE),
314 std::make_tuple(
315 AAUDIO_SHARING_MODE_EXCLUSIVE, AAUDIO_PERFORMANCE_MODE_POWER_SAVING),
316 std::make_tuple(
317 AAUDIO_SHARING_MODE_EXCLUSIVE, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY)),
318 &getTestName);
319
320
main(int argc,char ** argv)321 int main(int argc, char **argv) {
322 testing::InitGoogleTest(&argc, argv);
323
324 return RUN_ALL_TESTS();
325 }
326