1 /*
2  * Copyright 2015 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 #ifndef OBOE_STREAM_BUILDER_H_
18 #define OBOE_STREAM_BUILDER_H_
19 
20 #include "oboe/Definitions.h"
21 #include "oboe/AudioStreamBase.h"
22 #include "ResultWithValue.h"
23 
24 namespace oboe {
25 
26     // This depends on AudioStream, so we use forward declaration, it will close and delete the stream
27     struct StreamDeleterFunctor;
28     using ManagedStream = std::unique_ptr<AudioStream, StreamDeleterFunctor>;
29 
30 /**
31  * Factory class for an audio Stream.
32  */
33 class AudioStreamBuilder : public AudioStreamBase {
34 public:
35 
AudioStreamBuilder()36     AudioStreamBuilder() : AudioStreamBase() {}
37 
AudioStreamBuilder(const AudioStreamBase & audioStreamBase)38     AudioStreamBuilder(const AudioStreamBase &audioStreamBase): AudioStreamBase(audioStreamBase) {}
39 
40     /**
41      * Request a specific number of channels.
42      *
43      * Default is kUnspecified. If the value is unspecified then
44      * the application should query for the actual value after the stream is opened.
45      */
setChannelCount(int channelCount)46     AudioStreamBuilder *setChannelCount(int channelCount) {
47         mChannelCount = channelCount;
48         return this;
49     }
50 
51     /**
52      * Request the direction for a stream. The default is Direction::Output.
53      *
54      * @param direction Direction::Output or Direction::Input
55      */
setDirection(Direction direction)56     AudioStreamBuilder *setDirection(Direction direction) {
57         mDirection = direction;
58         return this;
59     }
60 
61     /**
62      * Request a specific sample rate in Hz.
63      *
64      * Default is kUnspecified. If the value is unspecified then
65      * the application should query for the actual value after the stream is opened.
66      *
67      * Technically, this should be called the "frame rate" or "frames per second",
68      * because it refers to the number of complete frames transferred per second.
69      * But it is traditionally called "sample rate". Se we use that term.
70      *
71      */
setSampleRate(int32_t sampleRate)72     AudioStreamBuilder *setSampleRate(int32_t sampleRate) {
73         mSampleRate = sampleRate;
74         return this;
75     }
76 
77     /**
78      * @deprecated use `setFramesPerDataCallback` instead.
79      */
setFramesPerCallback(int framesPerCallback)80     AudioStreamBuilder *setFramesPerCallback(int framesPerCallback) {
81         return setFramesPerDataCallback(framesPerCallback);
82     }
83 
84     /**
85      * Request a specific number of frames for the data callback.
86      *
87      * Default is kUnspecified. If the value is unspecified then
88      * the actual number may vary from callback to callback.
89      *
90      * If an application can handle a varying number of frames then we recommend
91      * leaving this unspecified. This allow the underlying API to optimize
92      * the callbacks. But if your application is, for example, doing FFTs or other block
93      * oriented operations, then call this function to get the sizes you need.
94      *
95      * @param framesPerCallback
96      * @return pointer to the builder so calls can be chained
97      */
setFramesPerDataCallback(int framesPerCallback)98     AudioStreamBuilder *setFramesPerDataCallback(int framesPerCallback) {
99         mFramesPerCallback = framesPerCallback;
100         return this;
101     }
102 
103     /**
104      * Request a sample data format, for example Format::Float.
105      *
106      * Default is Format::Unspecified. If the value is unspecified then
107      * the application should query for the actual value after the stream is opened.
108      */
setFormat(AudioFormat format)109     AudioStreamBuilder *setFormat(AudioFormat format) {
110         mFormat = format;
111         return this;
112     }
113 
114     /**
115      * Set the requested buffer capacity in frames.
116      * BufferCapacityInFrames is the maximum possible BufferSizeInFrames.
117      *
118      * The final stream capacity may differ. For AAudio it should be at least this big.
119      * For OpenSL ES, it could be smaller.
120      *
121      * Default is kUnspecified.
122      *
123      * @param bufferCapacityInFrames the desired buffer capacity in frames or kUnspecified
124      * @return pointer to the builder so calls can be chained
125      */
setBufferCapacityInFrames(int32_t bufferCapacityInFrames)126     AudioStreamBuilder *setBufferCapacityInFrames(int32_t bufferCapacityInFrames) {
127         mBufferCapacityInFrames = bufferCapacityInFrames;
128         return this;
129     }
130 
131     /**
132      * Get the audio API which will be requested when opening the stream. No guarantees that this is
133      * the API which will actually be used. Query the stream itself to find out the API which is
134      * being used.
135      *
136      * If you do not specify the API, then AAudio will be used if isAAudioRecommended()
137      * returns true. Otherwise OpenSL ES will be used.
138      *
139      * @return the requested audio API
140      */
getAudioApi()141     AudioApi getAudioApi() const { return mAudioApi; }
142 
143     /**
144      * If you leave this unspecified then Oboe will choose the best API
145      * for the device and SDK version at runtime.
146      *
147      * This should almost always be left unspecified, except for debugging purposes.
148      * Specifying AAudio will force Oboe to use AAudio on 8.0, which is extremely risky.
149      * Specifying OpenSLES should mainly be used to test legacy performance/functionality.
150      *
151      * If the caller requests AAudio and it is supported then AAudio will be used.
152      *
153      * @param audioApi Must be AudioApi::Unspecified, AudioApi::OpenSLES or AudioApi::AAudio.
154      * @return pointer to the builder so calls can be chained
155      */
setAudioApi(AudioApi audioApi)156     AudioStreamBuilder *setAudioApi(AudioApi audioApi) {
157         mAudioApi = audioApi;
158         return this;
159     }
160 
161     /**
162      * Is the AAudio API supported on this device?
163      *
164      * AAudio was introduced in the Oreo 8.0 release.
165      *
166      * @return true if supported
167      */
168     static bool isAAudioSupported();
169 
170     /**
171      * Is the AAudio API recommended this device?
172      *
173      * AAudio may be supported but not recommended because of version specific issues.
174      * AAudio is not recommended for Android 8.0 or earlier versions.
175      *
176      * @return true if recommended
177      */
178     static bool isAAudioRecommended();
179 
180     /**
181      * Request a mode for sharing the device.
182      * The requested sharing mode may not be available.
183      * So the application should query for the actual mode after the stream is opened.
184      *
185      * @param sharingMode SharingMode::Shared or SharingMode::Exclusive
186      * @return pointer to the builder so calls can be chained
187      */
setSharingMode(SharingMode sharingMode)188     AudioStreamBuilder *setSharingMode(SharingMode sharingMode) {
189         mSharingMode = sharingMode;
190         return this;
191     }
192 
193     /**
194      * Request a performance level for the stream.
195      * This will determine the latency, the power consumption, and the level of
196      * protection from glitches.
197      *
198      * @param performanceMode for example, PerformanceMode::LowLatency
199      * @return pointer to the builder so calls can be chained
200      */
setPerformanceMode(PerformanceMode performanceMode)201     AudioStreamBuilder *setPerformanceMode(PerformanceMode performanceMode) {
202         mPerformanceMode = performanceMode;
203         return this;
204     }
205 
206 
207     /**
208      * Set the intended use case for an output stream.
209      *
210      * The system will use this information to optimize the behavior of the stream.
211      * This could, for example, affect how volume and focus is handled for the stream.
212      * The usage is ignored for input streams.
213      *
214      * The default, if you do not call this function, is Usage::Media.
215      *
216      * Added in API level 28.
217      *
218      * @param usage the desired usage, eg. Usage::Game
219      */
setUsage(Usage usage)220     AudioStreamBuilder *setUsage(Usage usage) {
221         mUsage = usage;
222         return this;
223     }
224 
225     /**
226      * Set the type of audio data that an output stream will carry.
227      *
228      * The system will use this information to optimize the behavior of the stream.
229      * This could, for example, affect whether a stream is paused when a notification occurs.
230      * The contentType is ignored for input streams.
231      *
232      * The default, if you do not call this function, is ContentType::Music.
233      *
234      * Added in API level 28.
235      *
236      * @param contentType the type of audio data, eg. ContentType::Speech
237      */
setContentType(ContentType contentType)238     AudioStreamBuilder *setContentType(ContentType contentType) {
239         mContentType = contentType;
240         return this;
241     }
242 
243     /**
244      * Set the input (capture) preset for the stream.
245      *
246      * The system will use this information to optimize the behavior of the stream.
247      * This could, for example, affect which microphones are used and how the
248      * recorded data is processed.
249      *
250      * The default, if you do not call this function, is InputPreset::VoiceRecognition.
251      * That is because VoiceRecognition is the preset with the lowest latency
252      * on many platforms.
253      *
254      * Added in API level 28.
255      *
256      * @param inputPreset the desired configuration for recording
257      */
setInputPreset(InputPreset inputPreset)258     AudioStreamBuilder *setInputPreset(InputPreset inputPreset) {
259         mInputPreset = inputPreset;
260         return this;
261     }
262 
263     /** Set the requested session ID.
264      *
265      * The session ID can be used to associate a stream with effects processors.
266      * The effects are controlled using the Android AudioEffect Java API.
267      *
268      * The default, if you do not call this function, is SessionId::None.
269      *
270      * If set to SessionId::Allocate then a session ID will be allocated
271      * when the stream is opened.
272      *
273      * The allocated session ID can be obtained by calling AudioStream::getSessionId()
274      * and then used with this function when opening another stream.
275      * This allows effects to be shared between streams.
276      *
277      * Session IDs from Oboe can be used the Android Java APIs and vice versa.
278      * So a session ID from an Oboe stream can be passed to Java
279      * and effects applied using the Java AudioEffect API.
280      *
281      * Allocated session IDs will always be positive and nonzero.
282      *
283      * Added in API level 28.
284      *
285      * @param sessionId an allocated sessionID or SessionId::Allocate
286      */
setSessionId(SessionId sessionId)287     AudioStreamBuilder *setSessionId(SessionId sessionId) {
288         mSessionId = sessionId;
289         return this;
290     }
291 
292     /**
293      * Request a stream to a specific audio input/output device given an audio device ID.
294      *
295      * In most cases, the primary device will be the appropriate device to use, and the
296      * deviceId can be left kUnspecified.
297      *
298      * On Android, for example, the ID could be obtained from the Java AudioManager.
299      * AudioManager.getDevices() returns an array of AudioDeviceInfo[], which contains
300      * a getId() method (as well as other type information), that should be passed
301      * to this method.
302      *
303      *
304      * Note that when using OpenSL ES, this will be ignored and the created
305      * stream will have deviceId kUnspecified.
306      *
307      * @param deviceId device identifier or kUnspecified
308      * @return pointer to the builder so calls can be chained
309      */
setDeviceId(int32_t deviceId)310     AudioStreamBuilder *setDeviceId(int32_t deviceId) {
311         mDeviceId = deviceId;
312         return this;
313     }
314 
315     /**
316      * Specifies an object to handle data related callbacks from the underlying API.
317      *
318      * <strong>Important: See AudioStreamCallback for restrictions on what may be called
319      * from the callback methods.</strong>
320      *
321      * @param dataCallback
322      * @return pointer to the builder so calls can be chained
323      */
setDataCallback(oboe::AudioStreamDataCallback * dataCallback)324     AudioStreamBuilder *setDataCallback(oboe::AudioStreamDataCallback *dataCallback) {
325         mDataCallback = dataCallback;
326         return this;
327     }
328 
329     /**
330      * Specifies an object to handle error related callbacks from the underlying API.
331      * This can occur when a stream is disconnected because a headset is plugged in or unplugged.
332      * It can also occur if the audio service fails or if an exclusive stream is stolen by
333      * another stream.
334      *
335      * <strong>Important: See AudioStreamCallback for restrictions on what may be called
336      * from the callback methods.</strong>
337      *
338      * <strong>When an error callback occurs, the associated stream must be stopped and closed
339      * in a separate thread.</strong>
340      *
341      * @param errorCallback
342      * @return pointer to the builder so calls can be chained
343      */
setErrorCallback(oboe::AudioStreamErrorCallback * errorCallback)344     AudioStreamBuilder *setErrorCallback(oboe::AudioStreamErrorCallback *errorCallback) {
345         mErrorCallback = errorCallback;
346         return this;
347     }
348 
349     /**
350      * Specifies an object to handle data or error related callbacks from the underlying API.
351      *
352      * This is the equivalent of calling both setDataCallback() and setErrorCallback().
353      *
354      * <strong>Important: See AudioStreamCallback for restrictions on what may be called
355      * from the callback methods.</strong>
356      *
357      * When an error callback occurs, the associated stream will be stopped and closed in a separate thread.
358      *
359      * A note on why the streamCallback parameter is a raw pointer rather than a smart pointer:
360      *
361      * The caller should retain ownership of the object streamCallback points to. At first glance weak_ptr may seem like
362      * a good candidate for streamCallback as this implies temporary ownership. However, a weak_ptr can only be created
363      * from a shared_ptr. A shared_ptr incurs some performance overhead. The callback object is likely to be accessed
364      * every few milliseconds when the stream requires new data so this overhead is something we want to avoid.
365      *
366      * This leaves a raw pointer as the logical type choice. The only caveat being that the caller must not destroy
367      * the callback before the stream has been closed.
368      *
369      * @param streamCallback
370      * @return pointer to the builder so calls can be chained
371      */
setCallback(AudioStreamCallback * streamCallback)372     AudioStreamBuilder *setCallback(AudioStreamCallback *streamCallback) {
373         // Use the same callback object for both, dual inheritance.
374         mDataCallback = streamCallback;
375         mErrorCallback = streamCallback;
376         return this;
377     }
378 
379     /**
380      * If true then Oboe might convert channel counts to achieve optimal results.
381      * On some versions of Android for example, stereo streams could not use a FAST track.
382      * So a mono stream might be used instead and duplicated to two channels.
383      * On some devices, mono streams might be broken, so a stereo stream might be opened
384      * and converted to mono.
385      *
386      * Default is true.
387      */
setChannelConversionAllowed(bool allowed)388     AudioStreamBuilder *setChannelConversionAllowed(bool allowed) {
389         mChannelConversionAllowed = allowed;
390         return this;
391     }
392 
393     /**
394      * If true then Oboe might convert data formats to achieve optimal results.
395      * On some versions of Android, for example, a float stream could not get a
396      * low latency data path. So an I16 stream might be opened and converted to float.
397      *
398      * Default is false.
399      */
setFormatConversionAllowed(bool allowed)400     AudioStreamBuilder *setFormatConversionAllowed(bool allowed) {
401         mFormatConversionAllowed = allowed;
402         return this;
403     }
404 
405     /**
406      * Specify the quality of the sample rate converter in Oboe.
407      *
408      * If set to None then Oboe will not do sample rate conversion. But the underlying APIs might
409      * still do sample rate conversion if you specify a sample rate.
410      * That can prevent you from getting a low latency stream.
411      *
412      * If you do the conversion in Oboe then you might still get a low latency stream.
413      *
414      * Default is SampleRateConversionQuality::None
415      */
setSampleRateConversionQuality(SampleRateConversionQuality quality)416     AudioStreamBuilder *setSampleRateConversionQuality(SampleRateConversionQuality quality) {
417         mSampleRateConversionQuality = quality;
418         return this;
419     }
420 
421     /**
422      * @return true if AAudio will be used based on the current settings.
423      */
willUseAAudio()424     bool willUseAAudio() const {
425         return (mAudioApi == AudioApi::AAudio && isAAudioSupported())
426                 || (mAudioApi == AudioApi::Unspecified && isAAudioRecommended());
427     }
428 
429     /**
430      * Create and open a stream object based on the current settings.
431      *
432      * The caller owns the pointer to the AudioStream object
433      * and must delete it when finished.
434      *
435      * @deprecated Use openStream(std::shared_ptr<oboe::AudioStream> &stream) instead.
436      * @param stream pointer to a variable to receive the stream address
437      * @return OBOE_OK if successful or a negative error code
438      */
439     Result openStream(AudioStream **stream);
440 
441     /**
442      * Create and open a stream object based on the current settings.
443      *
444      * The caller shares the pointer to the AudioStream object.
445      * The shared_ptr is used internally by Oboe to prevent the stream from being
446      * deleted while it is being used by callbacks.
447      *
448      * @param stream reference to a shared_ptr to receive the stream address
449      * @return OBOE_OK if successful or a negative error code
450      */
451     Result openStream(std::shared_ptr<oboe::AudioStream> &stream);
452 
453     /**
454      * Create and open a ManagedStream object based on the current builder state.
455      *
456      * The caller must create a unique ptr, and pass by reference so it can be
457      * modified to point to an opened stream. The caller owns the unique ptr,
458      * and it will be automatically closed and deleted when going out of scope.
459      *
460      * @deprecated Use openStream(std::shared_ptr<oboe::AudioStream> &stream) instead.
461      * @param stream Reference to the ManagedStream (uniqueptr) used to keep track of stream
462      * @return OBOE_OK if successful or a negative error code.
463      */
464     Result openManagedStream(ManagedStream &stream);
465 
466 private:
467 
468     /**
469      * @param other
470      * @return true if channels, format and sample rate match
471      */
472     bool isCompatible(AudioStreamBase &other);
473 
474     /**
475      * Create an AudioStream object. The AudioStream must be opened before use.
476      *
477      * The caller owns the pointer.
478      *
479      * @return pointer to an AudioStream object or nullptr.
480      */
481     oboe::AudioStream *build();
482 
483     AudioApi       mAudioApi = AudioApi::Unspecified;
484 };
485 
486 } // namespace oboe
487 
488 #endif /* OBOE_STREAM_BUILDER_H_ */
489