• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #ifndef __ANDROID_API_S__
22 #define __ANDROID_API_S__ 31
23 #endif
24 
25 using namespace oboe;
26 
27 class CallbackSizeMonitor : public AudioStreamCallback {
28 public:
onAudioReady(AudioStream * oboeStream,void * audioData,int32_t numFrames)29     DataCallbackResult onAudioReady(AudioStream *oboeStream, void *audioData, int32_t numFrames) override {
30         framesPerCallback = numFrames;
31         callbackCount++;
32         return DataCallbackResult::Continue;
33     }
34 
35     // This is exposed publicly so that the number of frames per callback can be tested.
36     std::atomic<int32_t> framesPerCallback{0};
37     std::atomic<int32_t> callbackCount{0};
38 };
39 
40 class StreamOpen : public ::testing::Test {
41 
42 protected:
43 
openStream()44     bool openStream() {
45         EXPECT_EQ(mStream, nullptr);
46         Result r = mBuilder.openStream(&mStream);
47         EXPECT_EQ(r, Result::OK) << "Failed to open stream " << convertToText(r);
48         EXPECT_EQ(0, openCount) << "Should start with a fresh object every time.";
49         openCount++;
50         return (r == Result::OK);
51     }
52 
closeStream()53     bool closeStream() {
54         if (mStream != nullptr){
55           Result r = mStream->close();
56           EXPECT_EQ(r, Result::OK) << "Failed to close stream. " << convertToText(r);
57           usleep(500 * 1000); // give previous stream time to settle
58           mStream = nullptr;
59           return (r == Result::OK);
60         } else {
61           return true;
62         }
63     }
64 
checkSampleRateConversionAdvancing(Direction direction)65     void checkSampleRateConversionAdvancing(Direction direction) {
66         CallbackSizeMonitor callback;
67 
68         mBuilder.setDirection(direction);
69         if (mBuilder.isAAudioRecommended()) {
70             mBuilder.setAudioApi(AudioApi::AAudio);
71         }
72         mBuilder.setCallback(&callback);
73         mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
74         mBuilder.setSampleRate(44100);
75         mBuilder.setSampleRateConversionQuality(SampleRateConversionQuality::Medium);
76 
77         ASSERT_TRUE(openStream());
78 
79         ASSERT_EQ(mStream->requestStart(), Result::OK);
80         int timeout = 20;
81         while (callback.framesPerCallback == 0 && timeout > 0) {
82             usleep(50 * 1000);
83             timeout--;
84         }
85 
86         // Catch Issue #1166
87         mStream->getTimestamp(CLOCK_MONOTONIC); // should not crash
88         mStream->getTimestamp(CLOCK_MONOTONIC, nullptr, nullptr); // should not crash
89 
90         ASSERT_GT(callback.callbackCount, 0);
91         ASSERT_GT(callback.framesPerCallback, 0);
92         ASSERT_EQ(mStream->requestStop(), Result::OK);
93 
94         ASSERT_TRUE(closeStream());
95     }
96 
97     AudioStreamBuilder mBuilder;
98     AudioStream *mStream = nullptr;
99     int32_t openCount = 0;
100 
101 };
102 
103 class StreamOpenOutput : public StreamOpen {};
104 class StreamOpenInput : public StreamOpen {};
105 
TEST_F(StreamOpenOutput,ForOpenSLESDefaultSampleRateIsUsed)106 TEST_F(StreamOpenOutput, ForOpenSLESDefaultSampleRateIsUsed){
107 
108     DefaultStreamValues::SampleRate = 44100;
109     DefaultStreamValues::FramesPerBurst = 192;
110     mBuilder.setAudioApi(AudioApi::OpenSLES);
111     ASSERT_TRUE(openStream());
112     ASSERT_EQ(mStream->getSampleRate(), 44100);
113     ASSERT_TRUE(closeStream());
114 }
115 
TEST_F(StreamOpenOutput,ForOpenSLESDefaultFramesPerBurstIsUsed)116 TEST_F(StreamOpenOutput, ForOpenSLESDefaultFramesPerBurstIsUsed){
117 
118     DefaultStreamValues::SampleRate = 48000;
119     DefaultStreamValues::FramesPerBurst = 128; // used for low latency
120     mBuilder.setAudioApi(AudioApi::OpenSLES);
121     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
122     ASSERT_TRUE(openStream());
123     // Some devices like emulators may not support Low Latency
124     if (mStream->getPerformanceMode() == PerformanceMode::LowLatency) {
125         ASSERT_EQ(mStream->getFramesPerBurst(), 128);
126     }
127     ASSERT_TRUE(closeStream());
128 }
129 
TEST_F(StreamOpenOutput,ForOpenSLESDefaultChannelCountIsUsed)130 TEST_F(StreamOpenOutput, ForOpenSLESDefaultChannelCountIsUsed){
131 
132     DefaultStreamValues::ChannelCount = 1;
133     mBuilder.setAudioApi(AudioApi::OpenSLES);
134     ASSERT_TRUE(openStream());
135     ASSERT_EQ(mStream->getChannelCount(), 1);
136     ASSERT_TRUE(closeStream());
137 }
138 
TEST_F(StreamOpenOutput,OutputForOpenSLESPerformanceModeShouldBeNone)139 TEST_F(StreamOpenOutput, OutputForOpenSLESPerformanceModeShouldBeNone){
140     // We will not get a LowLatency stream if we request 16000 Hz.
141     mBuilder.setSampleRate(16000);
142     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
143     mBuilder.setDirection(Direction::Output);
144     mBuilder.setAudioApi(AudioApi::OpenSLES);
145 	  ASSERT_TRUE(openStream());
146     ASSERT_EQ((int)mStream->getPerformanceMode(), (int)PerformanceMode::None);
147     ASSERT_TRUE(closeStream());
148 }
149 
TEST_F(StreamOpenInput,InputForOpenSLESPerformanceModeShouldBeNone)150 TEST_F(StreamOpenInput, InputForOpenSLESPerformanceModeShouldBeNone){
151     // We will not get a LowLatency stream if we request 16000 Hz.
152     mBuilder.setSampleRate(16000);
153     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
154     mBuilder.setDirection(Direction::Input);
155     mBuilder.setAudioApi(AudioApi::OpenSLES);
156     ASSERT_TRUE(openStream());
157     ASSERT_EQ((int)mStream->getPerformanceMode(), (int)PerformanceMode::None);
158     ASSERT_TRUE(closeStream());
159 }
160 
TEST_F(StreamOpenOutput,ForOpenSlesIllegalFormatRejectedOutput)161 TEST_F(StreamOpenOutput, ForOpenSlesIllegalFormatRejectedOutput) {
162     mBuilder.setAudioApi(AudioApi::OpenSLES);
163     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
164     mBuilder.setFormat(static_cast<AudioFormat>(666));
165     Result r = mBuilder.openStream(&mStream);
166     EXPECT_NE(r, Result::OK) << "Should not open stream " << convertToText(r);
167     if (mStream != nullptr) {
168         mStream->close(); // just in case it accidentally opened
169     }
170 }
171 
TEST_F(StreamOpenInput,ForOpenSlesIllegalFormatRejectedInput)172 TEST_F(StreamOpenInput, ForOpenSlesIllegalFormatRejectedInput) {
173     mBuilder.setAudioApi(AudioApi::OpenSLES);
174     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
175     mBuilder.setDirection(Direction::Input);
176     mBuilder.setFormat(static_cast<AudioFormat>(666));
177     Result r = mBuilder.openStream(&mStream);
178     EXPECT_NE(r, Result::OK) << "Should not open stream " << convertToText(r);
179     if (mStream != nullptr) {
180         mStream->close(); // just in case it accidentally opened
181     }
182 }
183 
184 // Make sure the callback is called with the requested FramesPerCallback
TEST_F(StreamOpenOutput,OpenSLESFramesPerCallback)185 TEST_F(StreamOpenOutput, OpenSLESFramesPerCallback) {
186     const int kRequestedFramesPerCallback = 417;
187     CallbackSizeMonitor callback;
188 
189     DefaultStreamValues::SampleRate = 48000;
190     DefaultStreamValues::ChannelCount = 2;
191     DefaultStreamValues::FramesPerBurst = 192;
192     mBuilder.setAudioApi(AudioApi::OpenSLES);
193     mBuilder.setFramesPerCallback(kRequestedFramesPerCallback);
194     mBuilder.setCallback(&callback);
195     ASSERT_TRUE(openStream());
196     ASSERT_EQ(mStream->requestStart(), Result::OK);
197     int timeout = 20;
198     while (callback.framesPerCallback == 0 && timeout > 0) {
199         usleep(50 * 1000);
200         timeout--;
201     }
202     ASSERT_EQ(kRequestedFramesPerCallback, callback.framesPerCallback);
203     ASSERT_EQ(kRequestedFramesPerCallback, mStream->getFramesPerCallback());
204     ASSERT_EQ(mStream->requestStop(), Result::OK);
205     ASSERT_TRUE(closeStream());
206 }
207 
208 // Make sure the LowLatency callback has the requested FramesPerCallback.
TEST_F(StreamOpen,AAudioFramesPerCallbackLowLatency)209 TEST_F(StreamOpen, AAudioFramesPerCallbackLowLatency) {
210     const int kRequestedFramesPerCallback = 192;
211     CallbackSizeMonitor callback;
212 
213     mBuilder.setAudioApi(AudioApi::AAudio);
214     mBuilder.setFramesPerCallback(kRequestedFramesPerCallback);
215     mBuilder.setCallback(&callback);
216     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
217     ASSERT_TRUE(openStream());
218     ASSERT_EQ(kRequestedFramesPerCallback, mStream->getFramesPerCallback());
219     ASSERT_EQ(mStream->requestStart(), Result::OK);
220     int timeout = 20;
221     while (callback.framesPerCallback == 0 && timeout > 0) {
222         usleep(50 * 1000);
223         timeout--;
224     }
225     ASSERT_EQ(kRequestedFramesPerCallback, callback.framesPerCallback);
226     ASSERT_EQ(mStream->requestStop(), Result::OK);
227     ASSERT_TRUE(closeStream());
228 }
229 
230 // Make sure the regular callback has the requested FramesPerCallback.
TEST_F(StreamOpen,AAudioFramesPerCallbackNone)231 TEST_F(StreamOpen, AAudioFramesPerCallbackNone) {
232     const int kRequestedFramesPerCallback = 1024;
233     CallbackSizeMonitor callback;
234 
235     mBuilder.setAudioApi(AudioApi::AAudio);
236     mBuilder.setFramesPerCallback(kRequestedFramesPerCallback);
237     mBuilder.setCallback(&callback);
238     mBuilder.setPerformanceMode(PerformanceMode::None);
239     ASSERT_TRUE(openStream());
240     ASSERT_EQ(kRequestedFramesPerCallback, mStream->getFramesPerCallback());
241     ASSERT_EQ(mStream->requestStart(), Result::OK);
242     int timeout = 20;
243     while (callback.framesPerCallback == 0 && timeout > 0) {
244         usleep(50 * 1000);
245         timeout--;
246     }
247     ASSERT_EQ(kRequestedFramesPerCallback, callback.framesPerCallback);
248     ASSERT_EQ(mStream->requestStop(), Result::OK);
249     ASSERT_TRUE(closeStream());
250 }
251 
TEST_F(StreamOpenInput,RecordingFormatUnspecifiedReturnsI16BeforeMarshmallow)252 TEST_F(StreamOpenInput, RecordingFormatUnspecifiedReturnsI16BeforeMarshmallow){
253 
254     if (getSdkVersion() < __ANDROID_API_M__){
255         mBuilder.setDirection(Direction::Input);
256         mBuilder.setFormat(AudioFormat::Unspecified);
257         ASSERT_TRUE(openStream());
258         ASSERT_EQ(mStream->getFormat(), AudioFormat::I16);
259         ASSERT_TRUE(closeStream());
260     }
261 }
262 
TEST_F(StreamOpenInput,RecordingFormatUnspecifiedReturnsFloatOnMarshmallowAndLater)263 TEST_F(StreamOpenInput, RecordingFormatUnspecifiedReturnsFloatOnMarshmallowAndLater){
264 
265     if (getSdkVersion() >= __ANDROID_API_M__){
266         mBuilder.setDirection(Direction::Input);
267         mBuilder.setFormat(AudioFormat::Unspecified);
268         ASSERT_TRUE(openStream());
269         ASSERT_EQ(mStream->getFormat(), AudioFormat::Float);
270         ASSERT_TRUE(closeStream());
271     }
272 }
273 
TEST_F(StreamOpenInput,RecordingFormatFloatReturnsErrorBeforeMarshmallow)274 TEST_F(StreamOpenInput, RecordingFormatFloatReturnsErrorBeforeMarshmallow){
275 
276     if (getSdkVersion() < __ANDROID_API_M__){
277         mBuilder.setDirection(Direction::Input);
278         mBuilder.setFormat(AudioFormat::Float);
279         Result r = mBuilder.openStream(&mStream);
280         ASSERT_EQ(r, Result::ErrorInvalidFormat) << convertToText(r);
281         ASSERT_TRUE(closeStream());
282     }
283 }
284 
TEST_F(StreamOpenInput,RecordingFormatFloatReturnsFloatOnMarshmallowAndLater)285 TEST_F(StreamOpenInput, RecordingFormatFloatReturnsFloatOnMarshmallowAndLater){
286 
287     if (getSdkVersion() >= __ANDROID_API_M__){
288         mBuilder.setDirection(Direction::Input);
289         mBuilder.setFormat(AudioFormat::Float);
290         ASSERT_TRUE(openStream());
291         ASSERT_EQ(mStream->getFormat(), AudioFormat::Float);
292         ASSERT_TRUE(closeStream());
293     }
294 }
295 
TEST_F(StreamOpenInput,RecordingFormatI16ReturnsI16)296 TEST_F(StreamOpenInput, RecordingFormatI16ReturnsI16){
297 
298     mBuilder.setDirection(Direction::Input);
299     mBuilder.setFormat(AudioFormat::I16);
300     ASSERT_TRUE(openStream());
301     ASSERT_EQ(mStream->getFormat(), AudioFormat::I16);
302     ASSERT_TRUE(closeStream());
303 }
304 
TEST_F(StreamOpenOutput,PlaybackFormatUnspecifiedReturnsI16BeforeLollipop)305 TEST_F(StreamOpenOutput, PlaybackFormatUnspecifiedReturnsI16BeforeLollipop){
306 
307     if (getSdkVersion() < __ANDROID_API_L__){
308         mBuilder.setDirection(Direction::Output);
309         mBuilder.setFormat(AudioFormat::Unspecified);
310         ASSERT_TRUE(openStream());
311         ASSERT_EQ(mStream->getFormat(), AudioFormat::I16);
312         ASSERT_TRUE(closeStream());
313     }
314 }
315 
TEST_F(StreamOpenOutput,PlaybackFormatUnspecifiedReturnsFloatOnLollipopAndLater)316 TEST_F(StreamOpenOutput, PlaybackFormatUnspecifiedReturnsFloatOnLollipopAndLater){
317 
318     if (getSdkVersion() >= __ANDROID_API_L__){
319         mBuilder.setDirection(Direction::Output);
320         mBuilder.setFormat(AudioFormat::Unspecified);
321         ASSERT_TRUE(openStream());
322         ASSERT_EQ(mStream->getFormat(), AudioFormat::Float);
323         ASSERT_TRUE(closeStream());
324     }
325 }
326 
TEST_F(StreamOpenOutput,PlaybackFormatFloatReturnsErrorBeforeLollipop)327 TEST_F(StreamOpenOutput, PlaybackFormatFloatReturnsErrorBeforeLollipop){
328 
329     if (getSdkVersion() < __ANDROID_API_L__){
330         mBuilder.setDirection(Direction::Output);
331         mBuilder.setFormat(AudioFormat::Float);
332         Result r = mBuilder.openStream(&mStream);
333         ASSERT_EQ(r, Result::ErrorInvalidFormat);
334         ASSERT_TRUE(closeStream());
335     }
336 }
337 
TEST_F(StreamOpenOutput,PlaybackFormatFloatReturnsFloatWithFormatConversionAllowed)338 TEST_F(StreamOpenOutput, PlaybackFormatFloatReturnsFloatWithFormatConversionAllowed){
339     mBuilder.setDirection(Direction::Output);
340     mBuilder.setFormat(AudioFormat::Float);
341     mBuilder.setFormatConversionAllowed(true);
342     ASSERT_TRUE(openStream());
343     ASSERT_EQ(mStream->getFormat(), AudioFormat::Float);
344     ASSERT_TRUE(closeStream());
345 }
346 
TEST_F(StreamOpenOutput,PlaybackFormatFloatReturnsFloatOnLollipopAndLater)347 TEST_F(StreamOpenOutput, PlaybackFormatFloatReturnsFloatOnLollipopAndLater){
348 
349     if (getSdkVersion() >= __ANDROID_API_L__){
350         mBuilder.setDirection(Direction::Output);
351         mBuilder.setFormat(AudioFormat::Float);
352         ASSERT_TRUE(openStream());
353         ASSERT_EQ(mStream->getFormat(), AudioFormat::Float);
354         ASSERT_TRUE(closeStream());
355     }
356 }
357 
TEST_F(StreamOpenOutput,PlaybackFormatI16ReturnsI16)358 TEST_F(StreamOpenOutput, PlaybackFormatI16ReturnsI16) {
359     mBuilder.setDirection(Direction::Output);
360     mBuilder.setFormat(AudioFormat::I16);
361     ASSERT_TRUE(openStream());
362     ASSERT_EQ(mStream->getFormat(), AudioFormat::I16);
363     ASSERT_TRUE(closeStream());
364 }
365 
TEST_F(StreamOpenOutput,OpenCloseLowLatencyStream)366 TEST_F(StreamOpenOutput, OpenCloseLowLatencyStream){
367     mBuilder.setDirection(Direction::Output);
368     mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
369     float *buf = new float[100];
370     ASSERT_TRUE(openStream());
371     delete[] buf;
372     ASSERT_TRUE(closeStream());
373 }
374 
TEST_F(StreamOpenOutput,LowLatencyStreamHasSmallBufferSize)375 TEST_F(StreamOpenOutput, LowLatencyStreamHasSmallBufferSize){
376 
377     if (mBuilder.isAAudioRecommended()) {
378         mBuilder.setDirection(Direction::Output);
379         mBuilder.setPerformanceMode(PerformanceMode::LowLatency);
380         ASSERT_TRUE(openStream());
381         int32_t bufferSize = mStream->getBufferSizeInFrames();
382         int32_t burst = mStream->getFramesPerBurst();
383         ASSERT_TRUE(closeStream());
384         ASSERT_LE(bufferSize, burst * 3);
385     }
386 }
387 
388 // See if sample rate conversion by Oboe is calling the callback.
TEST_F(StreamOpenOutput,AAudioOutputSampleRate44100)389 TEST_F(StreamOpenOutput, AAudioOutputSampleRate44100) {
390     checkSampleRateConversionAdvancing(Direction::Output);
391 }
392 
393 // See if sample rate conversion by Oboe is calling the callback.
TEST_F(StreamOpenInput,AAudioInputSampleRate44100)394 TEST_F(StreamOpenInput, AAudioInputSampleRate44100) {
395     checkSampleRateConversionAdvancing(Direction::Input);
396 }
397 
TEST_F(StreamOpenOutput,AAudioOutputSetPackageName)398 TEST_F(StreamOpenOutput, AAudioOutputSetPackageName){
399     if (getSdkVersion() >= __ANDROID_API_S__){
400         mBuilder.setAudioApi(AudioApi::AAudio);
401         mBuilder.setPackageName("com.google.oboe.tests.unittestrunner");
402         ASSERT_TRUE(openStream());
403         ASSERT_EQ(mStream->requestStart(), Result::OK);
404         ASSERT_TRUE(closeStream());
405     }
406 }
407 
TEST_F(StreamOpenInput,AAudioInputSetPackageName)408 TEST_F(StreamOpenInput, AAudioInputSetPackageName){
409     if (getSdkVersion() >= __ANDROID_API_S__){
410         mBuilder.setDirection(Direction::Input);
411         mBuilder.setAudioApi(AudioApi::AAudio);
412         mBuilder.setPackageName("com.google.oboe.tests.unittestrunner");
413         ASSERT_TRUE(openStream());
414         ASSERT_EQ(mStream->requestStart(), Result::OK);
415         ASSERT_TRUE(closeStream());
416     }
417 }
418 
TEST_F(StreamOpenOutput,AAudioOutputSetAttributionTag)419 TEST_F(StreamOpenOutput, AAudioOutputSetAttributionTag){
420     if (getSdkVersion() >= __ANDROID_API_S__){
421         mBuilder.setAudioApi(AudioApi::AAudio);
422         mBuilder.setAttributionTag("TestSetOutputAttributionTag");
423         ASSERT_TRUE(openStream());
424         ASSERT_EQ(mStream->requestStart(), Result::OK);
425         ASSERT_TRUE(closeStream());
426     }
427 }
428 
TEST_F(StreamOpenInput,AAudioInputSetAttributionTag)429 TEST_F(StreamOpenInput, AAudioInputSetAttributionTag){
430     if (getSdkVersion() >= __ANDROID_API_S__){
431         mBuilder.setDirection(Direction::Input);
432         mBuilder.setAudioApi(AudioApi::AAudio);
433         mBuilder.setAttributionTag("TestSetInputAttributionTag");
434         ASSERT_TRUE(openStream());
435         ASSERT_EQ(mStream->requestStart(), Result::OK);
436         ASSERT_TRUE(closeStream());
437     }
438 }
439 
TEST_F(StreamOpenOutput,OutputForOpenSLESPerformanceModeNoneGetBufferSizeInFrames)440 TEST_F(StreamOpenOutput, OutputForOpenSLESPerformanceModeNoneGetBufferSizeInFrames){
441     mBuilder.setPerformanceMode(PerformanceMode::None);
442     mBuilder.setAudioApi(AudioApi::OpenSLES);
443     ASSERT_TRUE(openStream());
444     EXPECT_GT(mStream->getBufferSizeInFrames(), 0);
445     ASSERT_TRUE(closeStream());
446 }
447 
TEST_F(StreamOpenOutput,OboeExtensions)448 TEST_F(StreamOpenOutput, OboeExtensions){
449     if (OboeExtensions::isMMapSupported()) {
450         ASSERT_EQ(OboeExtensions::setMMapEnabled(true), 0);
451         ASSERT_TRUE(OboeExtensions::isMMapEnabled());
452 
453         ASSERT_EQ(OboeExtensions::setMMapEnabled(false), 0);
454         ASSERT_FALSE(OboeExtensions::isMMapEnabled());
455         ASSERT_TRUE(openStream());
456         EXPECT_FALSE(OboeExtensions::isMMapUsed(mStream));
457         ASSERT_TRUE(closeStream());
458 
459         ASSERT_EQ(OboeExtensions::setMMapEnabled(true), 0);
460         ASSERT_TRUE(OboeExtensions::isMMapEnabled());
461     }
462 }
463