• 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 #include <sys/types.h>
18 
19 #include "aaudio/AudioStreamAAudio.h"
20 #include "FilterAudioStream.h"
21 #include "OboeDebug.h"
22 #include "oboe/Oboe.h"
23 #include "oboe/AudioStreamBuilder.h"
24 #include "opensles/AudioInputStreamOpenSLES.h"
25 #include "opensles/AudioOutputStreamOpenSLES.h"
26 #include "opensles/AudioStreamOpenSLES.h"
27 #include "QuirksManager.h"
28 
29 bool oboe::OboeGlobals::mWorkaroundsEnabled = true;
30 
31 namespace oboe {
32 
33 /**
34  * The following default values are used when oboe does not have any better way of determining the optimal values
35  * for an audio stream. This can happen when:
36  *
37  * - Client is creating a stream on API < 26 (OpenSLES) but has not supplied the optimal sample
38  * rate and/or frames per burst
39  * - Client is creating a stream on API 16 (OpenSLES) where AudioManager.PROPERTY_OUTPUT_* values
40  * are not available
41  */
42 int32_t DefaultStreamValues::SampleRate = 48000; // Common rate for mobile audio and video
43 int32_t DefaultStreamValues::FramesPerBurst = 192; // 4 msec at 48000 Hz
44 int32_t DefaultStreamValues::ChannelCount = 2; // Stereo
45 
46 constexpr int kBufferSizeInBurstsForLowLatencyStreams = 2;
47 
48 #ifndef OBOE_ENABLE_AAUDIO
49 // Set OBOE_ENABLE_AAUDIO to 0 if you want to disable the AAudio API.
50 // This might be useful if you want to force all the unit tests to use OpenSL ES.
51 #define OBOE_ENABLE_AAUDIO 1
52 #endif
53 
isAAudioSupported()54 bool AudioStreamBuilder::isAAudioSupported() {
55     return AudioStreamAAudio::isSupported() && OBOE_ENABLE_AAUDIO;
56 }
57 
isAAudioRecommended()58 bool AudioStreamBuilder::isAAudioRecommended() {
59     // See https://github.com/google/oboe/issues/40,
60     // AAudio may not be stable on Android O, depending on how it is used.
61     // To be safe, use AAudio only on O_MR1 and above.
62     return (getSdkVersion() >= __ANDROID_API_O_MR1__) && isAAudioSupported();
63 }
64 
build()65 AudioStream *AudioStreamBuilder::build() {
66     AudioStream *stream = nullptr;
67     if (isAAudioRecommended() && mAudioApi != AudioApi::OpenSLES) {
68         stream = new AudioStreamAAudio(*this);
69     } else if (isAAudioSupported() && mAudioApi == AudioApi::AAudio) {
70         stream = new AudioStreamAAudio(*this);
71         LOGE("Creating AAudio stream on 8.0 because it was specified. This is error prone.");
72     } else {
73         if (getDirection() == oboe::Direction::Output) {
74             stream = new AudioOutputStreamOpenSLES(*this);
75         } else if (getDirection() == oboe::Direction::Input) {
76             stream = new AudioInputStreamOpenSLES(*this);
77         }
78     }
79     return stream;
80 }
81 
isCompatible(AudioStreamBase & other)82 bool AudioStreamBuilder::isCompatible(AudioStreamBase &other) {
83     return (getSampleRate() == oboe::Unspecified || getSampleRate() == other.getSampleRate())
84            && (getFormat() == (AudioFormat)oboe::Unspecified || getFormat() == other.getFormat())
85            && (getFramesPerCallback() == oboe::Unspecified || getFramesPerCallback() == other.getFramesPerCallback())
86            && (getChannelCount() == oboe::Unspecified || getChannelCount() == other.getChannelCount());
87 }
88 
openStream(AudioStream ** streamPP)89 Result AudioStreamBuilder::openStream(AudioStream **streamPP) {
90     auto result = isValidConfig();
91     if (result != Result::OK) {
92         return result;
93     }
94 
95     LOGI("%s() %s -------- %s --------",
96          __func__, getDirection() == Direction::Input ? "INPUT" : "OUTPUT", getVersionText());
97 
98     if (streamPP == nullptr) {
99         return Result::ErrorNull;
100     }
101     *streamPP = nullptr;
102 
103     AudioStream *streamP = nullptr;
104 
105     // Maybe make a FilterInputStream.
106     AudioStreamBuilder childBuilder(*this);
107     // Check need for conversion and modify childBuilder for optimal stream.
108     bool conversionNeeded = QuirksManager::getInstance().isConversionNeeded(*this, childBuilder);
109     // Do we need to make a child stream and convert.
110     if (conversionNeeded) {
111         AudioStream *tempStream;
112 
113         result = childBuilder.openStream(&tempStream);
114         if (result != Result::OK) {
115             return result;
116         }
117 
118         if (isCompatible(*tempStream)) {
119             // The child stream would work as the requested stream so we can just use it directly.
120             *streamPP = tempStream;
121             return result;
122         } else {
123             AudioStreamBuilder parentBuilder = *this;
124             // Build a stream that is as close as possible to the childStream.
125             if (getFormat() == oboe::AudioFormat::Unspecified) {
126                 parentBuilder.setFormat(tempStream->getFormat());
127             }
128             if (getChannelCount() == oboe::Unspecified) {
129                 parentBuilder.setChannelCount(tempStream->getChannelCount());
130             }
131             if (getSampleRate() == oboe::Unspecified) {
132                 parentBuilder.setSampleRate(tempStream->getSampleRate());
133             }
134             if (getFramesPerCallback() == oboe::Unspecified) {
135                 parentBuilder.setFramesPerCallback(tempStream->getFramesPerCallback());
136             }
137 
138             // Use childStream in a FilterAudioStream.
139             LOGI("%s() create a FilterAudioStream for data conversion.", __func__);
140             FilterAudioStream *filterStream = new FilterAudioStream(parentBuilder, tempStream);
141             result = filterStream->configureFlowGraph();
142             if (result !=  Result::OK) {
143                 filterStream->close();
144                 delete filterStream;
145                 // Just open streamP the old way.
146             } else {
147                 streamP = static_cast<AudioStream *>(filterStream);
148             }
149         }
150     }
151 
152     if (streamP == nullptr) {
153         streamP = build();
154         if (streamP == nullptr) {
155             return Result::ErrorNull;
156         }
157     }
158 
159     result = streamP->open(); // TODO review API
160     if (result == Result::OK) {
161 
162         int32_t  optimalBufferSize = -1;
163         // Use a reasonable default buffer size.
164         if (streamP->getDirection() == Direction::Input) {
165             // For input, small size does not improve latency because the stream is usually
166             // run close to empty. And a low size can result in XRuns so always use the maximum.
167             optimalBufferSize = streamP->getBufferCapacityInFrames();
168         } else if (streamP->getPerformanceMode() == PerformanceMode::LowLatency
169                 && streamP->getDirection() == Direction::Output)  { // Output check is redundant.
170             optimalBufferSize = streamP->getFramesPerBurst() *
171                                     kBufferSizeInBurstsForLowLatencyStreams;
172         }
173         if (optimalBufferSize >= 0) {
174             auto setBufferResult = streamP->setBufferSizeInFrames(optimalBufferSize);
175             if (!setBufferResult) {
176                 LOGW("Failed to setBufferSizeInFrames(%d). Error was %s",
177                      optimalBufferSize,
178                      convertToText(setBufferResult.error()));
179             }
180         }
181 
182         *streamPP = streamP;
183     } else {
184         delete streamP;
185     }
186     return result;
187 }
188 
openManagedStream(oboe::ManagedStream & stream)189 Result AudioStreamBuilder::openManagedStream(oboe::ManagedStream &stream) {
190     stream.reset();
191     auto result = isValidConfig();
192     if (result != Result::OK) {
193         return result;
194     }
195     AudioStream *streamptr;
196     result = openStream(&streamptr);
197     stream.reset(streamptr);
198     return result;
199 }
200 
openStream(std::shared_ptr<AudioStream> & sharedStream)201 Result AudioStreamBuilder::openStream(std::shared_ptr<AudioStream> &sharedStream) {
202     sharedStream.reset();
203     auto result = isValidConfig();
204     if (result != Result::OK) {
205         return result;
206     }
207     AudioStream *streamptr;
208     result = openStream(&streamptr);
209     if (result == Result::OK) {
210         sharedStream.reset(streamptr);
211         // Save a weak_ptr in the stream for use with callbacks.
212         streamptr->setWeakThis(sharedStream);
213     }
214     return result;
215 }
216 
217 } // namespace oboe
218