• 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     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