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