• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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