1 #include <oboe/Oboe.h>/*
2 * Copyright 2018 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 #include <gtest/gtest.h>
18 #include <oboe/Oboe.h>
19 #include <android/api-level.h>
20
21 using namespace oboe;
22
23 class CallbackSizeMonitor : public AudioStreamCallback {
24 public:
onAudioReady(AudioStream * oboeStream,void * audioData,int32_t numFrames)25 DataCallbackResult onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) override {
26 framesPerCallback = numFrames;
27 callbackCount++;
28 return DataCallbackResult::Continue;
29 }
30
31 // This is exposed publicly so that the number of frames per callback can be tested.
32 std::atomic<int32_t> framesPerCallback{0};
33 std::atomic<int32_t> callbackCount{0};
34 };
35
36 class StreamOpen : public ::testing::Test {
37
38 protected:
39
openStream()40 bool openStream() {
41 Result r = mBuilder.openStream(&mStream);
42 EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
43 EXPECT_EQ(0, openCount) << "Should start with a fresh object every time.";
44 openCount++;
45 return (r == Result::OK);
46 }
47
closeStream()48 bool closeStream() {
49 Result r = mStream->close();
50 EXPECT_EQ(r, Result::OK) << "Failed to close stream. " << convertToText(r);
51 usleep(500 * 1000); // give previous stream time to settle
52 return (r == Result::OK);
53 }
54
checkSampleRateConversionAdvancing(Direction direction)55 void checkSampleRateConversionAdvancing(Direction direction) {
56 CallbackSizeMonitor callback;
57
58 mBuilder.setDirection(direction);
59 mBuilder.setAudioApi(AudioApi::AAudio);
60 mBuilder.setCallback(&callback);
61 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
62 mBuilder.setSampleRate(44100);
63 mBuilder.setSampleRateConversionQuality(SampleRateConversionQuality::Medium);
64
65 ASSERT_TRUE(openStream());
66
67 ASSERT_EQ(mStream->requestStart(), Result::OK);
68 int timeout = 20;
69 while (callback.framesPerCallback == 0 && timeout > 0) {
70 usleep(50 * 1000);
71 timeout--;
72 }
73
74 // Catch Issue #1166
75 mStream->getTimestamp(CLOCK_MONOTONIC); // should not crash
76 mStream->getTimestamp(CLOCK_MONOTONIC, nullptr, nullptr); // should not crash
77
78 ASSERT_GT(callback.callbackCount, 0);
79 ASSERT_GT(callback.framesPerCallback, 0);
80 ASSERT_EQ(mStream->requestStop(), Result::OK);
81
82 ASSERT_TRUE(closeStream());
83 }
84
85 AudioStreamBuilder mBuilder;
86 AudioStream *mStream = nullptr;
87 int32_t openCount = 0;
88
89 };
90
TEST_F(StreamOpen,ForOpenSLESDefaultSampleRateIsUsed)91 TEST_F(StreamOpen, ForOpenSLESDefaultSampleRateIsUsed){
92
93 DefaultStreamValues::SampleRate = 44100;
94 DefaultStreamValues::FramesPerBurst = 192;
95 mBuilder.setAudioApi(AudioApi::OpenSLES);
96 ASSERT_TRUE(openStream());
97 ASSERT_EQ(mStream->getSampleRate(), 44100);
98 ASSERT_TRUE(closeStream());
99 }
100
TEST_F(StreamOpen,ForOpenSLESDefaultFramesPerBurstIsUsed)101 TEST_F(StreamOpen, ForOpenSLESDefaultFramesPerBurstIsUsed){
102
103 DefaultStreamValues::SampleRate = 48000;
104 DefaultStreamValues::FramesPerBurst = 128; // used for low latency
105 mBuilder.setAudioApi(AudioApi::OpenSLES);
106 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
107 ASSERT_TRUE(openStream());
108 ASSERT_EQ(mStream->getFramesPerBurst(), 128);
109 ASSERT_TRUE(closeStream());
110 }
111
TEST_F(StreamOpen,ForOpenSLESDefaultChannelCountIsUsed)112 TEST_F(StreamOpen, ForOpenSLESDefaultChannelCountIsUsed){
113
114 DefaultStreamValues::ChannelCount = 1;
115 mBuilder.setAudioApi(AudioApi::OpenSLES);
116 ASSERT_TRUE(openStream());
117 ASSERT_EQ(mStream->getChannelCount(), 1);
118 ASSERT_TRUE(closeStream());
119 }
120
TEST_F(StreamOpen,OutputForOpenSLESPerformanceModeShouldBeNone)121 TEST_F(StreamOpen, OutputForOpenSLESPerformanceModeShouldBeNone){
122 // We will not get a LowLatency stream if we request 16000 Hz.
123 mBuilder.setSampleRate(16000);
124 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
125 mBuilder.setDirection(Direction::Output);
126 mBuilder.setAudioApi(AudioApi::OpenSLES);
127 ASSERT_TRUE(openStream());
128 ASSERT_EQ((int)mStream->getPerformanceMode(), (int)PerformanceMode::None);
129 ASSERT_TRUE(closeStream());
130 }
131
TEST_F(StreamOpen,InputForOpenSLESPerformanceModeShouldBeNone)132 TEST_F(StreamOpen, InputForOpenSLESPerformanceModeShouldBeNone){
133 // We will not get a LowLatency stream if we request 16000 Hz.
134 mBuilder.setSampleRate(16000);
135 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
136 mBuilder.setDirection(Direction::Input);
137 mBuilder.setAudioApi(AudioApi::OpenSLES);
138 ASSERT_TRUE(openStream());
139 ASSERT_EQ((int)mStream->getPerformanceMode(), (int)PerformanceMode::None);
140 ASSERT_TRUE(closeStream());
141 }
142
TEST_F(StreamOpen,ForOpenSlesIllegalFormatRejectedOutput)143 TEST_F(StreamOpen, ForOpenSlesIllegalFormatRejectedOutput) {
144 mBuilder.setAudioApi(AudioApi::OpenSLES);
145 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
146 mBuilder.setFormat(static_cast<AudioFormat>(666));
147 Result r = mBuilder.openStream(&mStream);
148 EXPECT_NE(r, Result::OK) << "Should not open stream " << convertToText(r);
149 if (mStream != nullptr) {
150 mStream->close(); // just in case it accidentally opened
151 }
152 }
153
TEST_F(StreamOpen,ForOpenSlesIllegalFormatRejectedInput)154 TEST_F(StreamOpen, ForOpenSlesIllegalFormatRejectedInput) {
155 mBuilder.setAudioApi(AudioApi::OpenSLES);
156 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
157 mBuilder.setDirection(Direction::Input);
158 mBuilder.setFormat(static_cast<AudioFormat>(666));
159 Result r = mBuilder.openStream(&mStream);
160 EXPECT_NE(r, Result::OK) << "Should not open stream " << convertToText(r);
161 if (mStream != nullptr) {
162 mStream->close(); // just in case it accidentally opened
163 }
164 }
165
166 // Make sure the callback is called with the requested FramesPerCallback
TEST_F(StreamOpen,OpenSLESFramesPerCallback)167 TEST_F(StreamOpen, OpenSLESFramesPerCallback) {
168 const int kRequestedFramesPerCallback = 417;
169 CallbackSizeMonitor callback;
170
171 DefaultStreamValues::SampleRate = 48000;
172 DefaultStreamValues::ChannelCount = 2;
173 DefaultStreamValues::FramesPerBurst = 192;
174 mBuilder.setAudioApi(AudioApi::OpenSLES);
175 mBuilder.setFramesPerCallback(kRequestedFramesPerCallback);
176 mBuilder.setCallback(&callback);
177 ASSERT_TRUE(openStream());
178 ASSERT_EQ(mStream->requestStart(), Result::OK);
179 int timeout = 20;
180 while (callback.framesPerCallback == 0 && timeout > 0) {
181 usleep(50 * 1000);
182 timeout--;
183 }
184 ASSERT_EQ(kRequestedFramesPerCallback, callback.framesPerCallback);
185 ASSERT_EQ(kRequestedFramesPerCallback, mStream->getFramesPerCallback());
186 ASSERT_EQ(mStream->requestStop(), Result::OK);
187 ASSERT_TRUE(closeStream());
188 }
189
190 /* TODO - This is hanging!
191 // Make sure the LowLatency callback has the requested FramesPerCallback.
192 TEST_F(StreamOpen, AAudioFramesPerCallbackLowLatency) {
193 const int kRequestedFramesPerCallback = 192;
194 CallbackSizeMonitor callback;
195
196 mBuilder.setAudioApi(AudioApi::AAudio);
197 mBuilder.setFramesPerCallback(kRequestedFramesPerCallback);
198 mBuilder.setCallback(&callback);
199 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
200 ASSERT_TRUE(openStream());
201 ASSERT_EQ(kRequestedFramesPerCallback, mStream->getFramesPerCallback());
202 ASSERT_EQ(mStream->requestStart(), Result::OK);
203 int timeout = 20;
204 while (callback.framesPerCallback == 0 && timeout > 0) {
205 usleep(50 * 1000);
206 timeout--;
207 }
208 ASSERT_EQ(kRequestedFramesPerCallback, callback.framesPerCallback);
209 ASSERT_EQ(mStream->requestStop(), Result::OK);
210 ASSERT_TRUE(closeStream());
211 }
212 */
213
214 /* TODO - This is hanging!
215 // Make sure the regular callback has the requested FramesPerCallback.
216 TEST_F(StreamOpen, AAudioFramesPerCallbackNone) {
217 const int kRequestedFramesPerCallback = 1024;
218 CallbackSizeMonitor callback;
219
220 mBuilder.setAudioApi(AudioApi::AAudio);
221 mBuilder.setFramesPerCallback(kRequestedFramesPerCallback);
222 mBuilder.setCallback(&callback);
223 mBuilder.setPerformanceMode(PerformanceMode::None);
224 ASSERT_TRUE(openStream());
225 ASSERT_EQ(kRequestedFramesPerCallback, mStream->getFramesPerCallback());
226 ASSERT_EQ(mStream->setBufferSizeInFrames(mStream->getBufferCapacityInFrames()), Result::OK);
227 ASSERT_EQ(mStream->requestStart(), Result::OK);
228 int timeout = 20;
229 while (callback.framesPerCallback == 0 && timeout > 0) {
230 usleep(50 * 1000);
231 timeout--;
232 }
233 ASSERT_EQ(kRequestedFramesPerCallback, callback.framesPerCallback);
234 ASSERT_EQ(mStream->requestStop(), Result::OK);
235 ASSERT_TRUE(closeStream());
236 }
237 */
238
TEST_F(StreamOpen,RecordingFormatUnspecifiedReturnsI16BeforeMarshmallow)239 TEST_F(StreamOpen, RecordingFormatUnspecifiedReturnsI16BeforeMarshmallow){
240
241 if (getSdkVersion() < __ANDROID_API_M__){
242 mBuilder.setDirection(Direction::Input);
243 mBuilder.setFormat(AudioFormat::Unspecified);
244 ASSERT_TRUE(openStream());
245 ASSERT_EQ(mStream->getFormat(), AudioFormat::I16);
246 ASSERT_TRUE(closeStream());
247 }
248 }
249
TEST_F(StreamOpen,RecordingFormatUnspecifiedReturnsFloatOnMarshmallowAndLater)250 TEST_F(StreamOpen, RecordingFormatUnspecifiedReturnsFloatOnMarshmallowAndLater){
251
252 if (getSdkVersion() >= __ANDROID_API_M__){
253 mBuilder.setDirection(Direction::Input);
254 mBuilder.setFormat(AudioFormat::Unspecified);
255 ASSERT_TRUE(openStream());
256 ASSERT_EQ(mStream->getFormat(), AudioFormat::Float);
257 ASSERT_TRUE(closeStream());
258 }
259 }
260
TEST_F(StreamOpen,RecordingFormatFloatReturnsErrorBeforeMarshmallow)261 TEST_F(StreamOpen, RecordingFormatFloatReturnsErrorBeforeMarshmallow){
262
263 if (getSdkVersion() < __ANDROID_API_M__){
264 mBuilder.setDirection(Direction::Input);
265 mBuilder.setFormat(AudioFormat::Float);
266 Result r = mBuilder.openStream(&mStream);
267 ASSERT_EQ(r, Result::ErrorInvalidFormat) << convertToText(r);
268 ASSERT_TRUE(closeStream());
269 }
270 }
271
TEST_F(StreamOpen,RecordingFormatFloatReturnsFloatOnMarshmallowAndLater)272 TEST_F(StreamOpen, RecordingFormatFloatReturnsFloatOnMarshmallowAndLater){
273
274 if (getSdkVersion() >= __ANDROID_API_M__){
275 mBuilder.setDirection(Direction::Input);
276 mBuilder.setFormat(AudioFormat::Float);
277 ASSERT_TRUE(openStream());
278 ASSERT_EQ(mStream->getFormat(), AudioFormat::Float);
279 ASSERT_TRUE(closeStream());
280 }
281 }
282
TEST_F(StreamOpen,RecordingFormatI16ReturnsI16)283 TEST_F(StreamOpen, RecordingFormatI16ReturnsI16){
284
285 mBuilder.setDirection(Direction::Input);
286 mBuilder.setFormat(AudioFormat::I16);
287 ASSERT_TRUE(openStream());
288 ASSERT_EQ(mStream->getFormat(), AudioFormat::I16);
289 ASSERT_TRUE(closeStream());
290 }
291
TEST_F(StreamOpen,PlaybackFormatUnspecifiedReturnsI16BeforeLollipop)292 TEST_F(StreamOpen, PlaybackFormatUnspecifiedReturnsI16BeforeLollipop){
293
294 if (getSdkVersion() < __ANDROID_API_L__){
295 mBuilder.setDirection(Direction::Output);
296 mBuilder.setFormat(AudioFormat::Unspecified);
297 ASSERT_TRUE(openStream());
298 ASSERT_EQ(mStream->getFormat(), AudioFormat::I16);
299 ASSERT_TRUE(closeStream());
300 }
301 }
302
TEST_F(StreamOpen,PlaybackFormatUnspecifiedReturnsFloatOnLollipopAndLater)303 TEST_F(StreamOpen, PlaybackFormatUnspecifiedReturnsFloatOnLollipopAndLater){
304
305 if (getSdkVersion() >= __ANDROID_API_L__){
306 mBuilder.setDirection(Direction::Output);
307 mBuilder.setFormat(AudioFormat::Unspecified);
308 ASSERT_TRUE(openStream());
309 ASSERT_EQ(mStream->getFormat(), AudioFormat::Float);
310 ASSERT_TRUE(closeStream());
311 }
312 }
313
TEST_F(StreamOpen,PlaybackFormatFloatReturnsErrorBeforeLollipop)314 TEST_F(StreamOpen, PlaybackFormatFloatReturnsErrorBeforeLollipop){
315
316 if (getSdkVersion() < __ANDROID_API_L__){
317 mBuilder.setDirection(Direction::Output);
318 mBuilder.setFormat(AudioFormat::Float);
319 Result r = mBuilder.openStream(&mStream);
320 ASSERT_EQ(r, Result::ErrorInvalidFormat);
321 ASSERT_TRUE(closeStream());
322 }
323 }
324
TEST_F(StreamOpen,PlaybackFormatFloatReturnsFloatOnLollipopAndLater)325 TEST_F(StreamOpen, PlaybackFormatFloatReturnsFloatOnLollipopAndLater){
326
327 if (getSdkVersion() >= __ANDROID_API_L__){
328 mBuilder.setDirection(Direction::Output);
329 mBuilder.setFormat(AudioFormat::Float);
330 ASSERT_TRUE(openStream());
331 ASSERT_EQ(mStream->getFormat(), AudioFormat::Float);
332 ASSERT_TRUE(closeStream());
333 }
334 }
335
TEST_F(StreamOpen,PlaybackFormatI16ReturnsI16)336 TEST_F(StreamOpen, PlaybackFormatI16ReturnsI16) {
337 mBuilder.setDirection(Direction::Output);
338 mBuilder.setFormat(AudioFormat::I16);
339 ASSERT_TRUE(openStream());
340 ASSERT_EQ(mStream->getFormat(), AudioFormat::I16);
341 ASSERT_TRUE(closeStream());
342 }
343
TEST_F(StreamOpen,OpenCloseLowLatencyStream)344 TEST_F(StreamOpen, OpenCloseLowLatencyStream){
345 mBuilder.setDirection(Direction::Output);
346 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
347 float *buf = new float[100];
348 ASSERT_TRUE(openStream());
349 delete[] buf;
350 ASSERT_TRUE(closeStream());
351 }
352
TEST_F(StreamOpen,LowLatencyStreamHasSmallBufferSize)353 TEST_F(StreamOpen, LowLatencyStreamHasSmallBufferSize){
354
355 if (mBuilder.isAAudioRecommended()) {
356 mBuilder.setDirection(Direction::Output);
357 mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
358 ASSERT_TRUE(openStream());
359 int32_t bufferSize = mStream->getBufferSizeInFrames();
360 int32_t burst = mStream->getFramesPerBurst();
361 ASSERT_TRUE(closeStream());
362 ASSERT_LE(bufferSize, burst * 3);
363 }
364 }
365
366 // See if sample rate conversion by Oboe is calling the callback.
TEST_F(StreamOpen,AAudioOutputSampleRate44100)367 TEST_F(StreamOpen, AAudioOutputSampleRate44100) {
368 checkSampleRateConversionAdvancing(Direction::Output);
369 }
370
371 // See if sample rate conversion by Oboe is calling the callback.
TEST_F(StreamOpen,AAudioInputSampleRate44100)372 TEST_F(StreamOpen, AAudioInputSampleRate44100) {
373 checkSampleRateConversionAdvancing(Direction::Input);
374 }
375