xref: /aosp_15_r20/external/oboe/src/common/AudioStreamBuilder.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
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