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