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