• 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 #ifndef OBOE_STREAM_H_
18 #define OBOE_STREAM_H_
19 
20 #include <atomic>
21 #include <cstdint>
22 #include <ctime>
23 #include <mutex>
24 #include "oboe/Definitions.h"
25 #include "oboe/ResultWithValue.h"
26 #include "oboe/AudioStreamBuilder.h"
27 #include "oboe/AudioStreamBase.h"
28 
29 namespace oboe {
30 
31 /**
32  * The default number of nanoseconds to wait for when performing state change operations on the
33  * stream, such as `start` and `stop`.
34  *
35  * @see oboe::AudioStream::start
36  */
37 constexpr int64_t kDefaultTimeoutNanos = (2000 * kNanosPerMillisecond);
38 
39 /**
40  * Base class for Oboe C++ audio stream.
41  */
42 class AudioStream : public AudioStreamBase {
43     friend class AudioStreamBuilder; // allow access to setWeakThis() and lockWeakThis()
44 public:
45 
AudioStream()46     AudioStream() {}
47 
48     /**
49      * Construct an `AudioStream` using the given `AudioStreamBuilder`
50      *
51      * @param builder containing all the stream's attributes
52      */
53     explicit AudioStream(const AudioStreamBuilder &builder);
54 
55     virtual ~AudioStream();
56 
57     /**
58      * Open a stream based on the current settings.
59      *
60      * Note that we do not recommend re-opening a stream that has been closed.
61      * TODO Should we prevent re-opening?
62      *
63      * @return
64      */
open()65     virtual Result open() {
66         return Result::OK; // Called by subclasses. Might do more in the future.
67     }
68 
69     /**
70      * Free the audio resources associated with a stream created by AAudioStreamBuilder_openStream().
71      *
72      * AAudioStream_close() should be called at some point after calling this function.
73      *
74      * After this call, the stream will be in AAUDIO_STREAM_STATE_CLOSING
75      *
76      * This function is useful if you want to release the audio resources immediately, but still allow
77      * queries to the stream to occur from other threads. This often happens if you are monitoring
78      * stream progress from a UI thread.
79      *
80      * NOTE: This function is only fully implemented for MMAP streams, which are low latency streams
81      * supported by some devices. On other "Legacy" streams some audio resources will still be in use
82      * and some callbacks may still be in process after this call.
83      *
84      * Available in AAudio since API level 30. Returns Result::ErrorUnimplemented otherwise.
85      *
86      * * @return either Result::OK or an error.
87      */
release()88     virtual Result release() {
89         return Result::ErrorUnimplemented;
90     }
91 
92     /**
93      * Close the stream and deallocate any resources from the open() call.
94      */
95     virtual Result close();
96 
97     /**
98      * Start the stream. This will block until the stream has been started, an error occurs
99      * or `timeoutNanoseconds` has been reached.
100      */
101     virtual Result start(int64_t timeoutNanoseconds = kDefaultTimeoutNanos);
102 
103     /**
104      * Pause the stream. This will block until the stream has been paused, an error occurs
105      * or `timeoutNanoseconds` has been reached.
106      */
107     virtual Result pause(int64_t timeoutNanoseconds = kDefaultTimeoutNanos);
108 
109     /**
110      * Flush the stream. This will block until the stream has been flushed, an error occurs
111      * or `timeoutNanoseconds` has been reached.
112      */
113     virtual Result flush(int64_t timeoutNanoseconds = kDefaultTimeoutNanos);
114 
115     /**
116      * Stop the stream. This will block until the stream has been stopped, an error occurs
117      * or `timeoutNanoseconds` has been reached.
118      */
119     virtual Result stop(int64_t timeoutNanoseconds = kDefaultTimeoutNanos);
120 
121     /* Asynchronous requests.
122      * Use waitForStateChange() if you need to wait for completion.
123      */
124 
125     /**
126      * Start the stream asynchronously. Returns immediately (does not block). Equivalent to calling
127      * `start(0)`.
128      */
129     virtual Result requestStart() = 0;
130 
131     /**
132      * Pause the stream asynchronously. Returns immediately (does not block). Equivalent to calling
133      * `pause(0)`.
134      */
135     virtual Result requestPause() = 0;
136 
137     /**
138      * Flush the stream asynchronously. Returns immediately (does not block). Equivalent to calling
139      * `flush(0)`.
140      */
141     virtual Result requestFlush() = 0;
142 
143     /**
144      * Stop the stream asynchronously. Returns immediately (does not block). Equivalent to calling
145      * `stop(0)`.
146      */
147     virtual Result requestStop() = 0;
148 
149     /**
150      * Query the current state, eg. StreamState::Pausing
151      *
152      * @return state or a negative error.
153      */
154     virtual StreamState getState() = 0;
155 
156     /**
157      * Wait until the stream's current state no longer matches the input state.
158      * The input state is passed to avoid race conditions caused by the state
159      * changing between calls.
160      *
161      * Note that generally applications do not need to call this. It is considered
162      * an advanced technique and is mostly used for testing.
163      *
164      * <pre><code>
165      * int64_t timeoutNanos = 500 * kNanosPerMillisecond; // arbitrary 1/2 second
166      * StreamState currentState = stream->getState();
167      * StreamState nextState = StreamState::Unknown;
168      * while (result == Result::OK && currentState != StreamState::Paused) {
169      *     result = stream->waitForStateChange(
170      *                                   currentState, &nextState, timeoutNanos);
171      *     currentState = nextState;
172      * }
173      * </code></pre>
174      *
175      * If the state does not change within the timeout period then it will
176      * return ErrorTimeout. This is true even if timeoutNanoseconds is zero.
177      *
178      * @param inputState The state we want to change away from.
179      * @param nextState Pointer to a variable that will be set to the new state.
180      * @param timeoutNanoseconds The maximum time to wait in nanoseconds.
181      * @return Result::OK or a Result::Error.
182      */
183     virtual Result waitForStateChange(StreamState inputState,
184                                           StreamState *nextState,
185                                           int64_t timeoutNanoseconds) = 0;
186 
187     /**
188     * This can be used to adjust the latency of the buffer by changing
189     * the threshold where blocking will occur.
190     * By combining this with getXRunCount(), the latency can be tuned
191     * at run-time for each device.
192     *
193     * This cannot be set higher than getBufferCapacity().
194     *
195     * This should only be used with Output streams. It will
196     * be ignored for Input streams because they are generally kept as empty as possible.
197     *
198     * For OpenSL ES, this method only has an effect on output stream that do NOT
199     * use a callback. The blocking writes goes into a buffer in Oboe and the size of that
200     * buffer is controlled by this method.
201     *
202     * @param requestedFrames requested number of frames that can be filled without blocking
203     * @return the resulting buffer size in frames (obtained using value()) or an error (obtained
204     * using error())
205     */
setBufferSizeInFrames(int32_t)206     virtual ResultWithValue<int32_t> setBufferSizeInFrames(int32_t /* requestedFrames  */) {
207         return Result::ErrorUnimplemented;
208     }
209 
210     /**
211      * An XRun is an Underrun or an Overrun.
212      * During playing, an underrun will occur if the stream is not written in time
213      * and the system runs out of valid data.
214      * During recording, an overrun will occur if the stream is not read in time
215      * and there is no place to put the incoming data so it is discarded.
216      *
217      * An underrun or overrun can cause an audible "pop" or "glitch".
218      *
219      * @return a result which is either Result::OK with the xRun count as the value, or a
220      * Result::Error* code
221      */
getXRunCount()222     virtual ResultWithValue<int32_t> getXRunCount() {
223         return ResultWithValue<int32_t>(Result::ErrorUnimplemented);
224     }
225 
226     /**
227      * @return true if XRun counts are supported on the stream
228      */
229     virtual bool isXRunCountSupported() const = 0;
230 
231     /**
232      * Query the number of frames that are read or written by the endpoint at one time.
233      *
234      * @return burst size
235      */
getFramesPerBurst()236     int32_t getFramesPerBurst() const {
237         return mFramesPerBurst;
238     }
239 
240     /**
241      * Get the number of bytes in each audio frame. This is calculated using the channel count
242      * and the sample format. For example, a 2 channel floating point stream will have
243      * 2 * 4 = 8 bytes per frame.
244      *
245      * @return number of bytes in each audio frame.
246      */
getBytesPerFrame()247     int32_t getBytesPerFrame() const { return mChannelCount * getBytesPerSample(); }
248 
249     /**
250      * Get the number of bytes per sample. This is calculated using the sample format. For example,
251      * a stream using 16-bit integer samples will have 2 bytes per sample.
252      *
253      * @return the number of bytes per sample.
254      */
255     int32_t getBytesPerSample() const;
256 
257     /**
258      * The number of audio frames written into the stream.
259      * This monotonic counter will never get reset.
260      *
261      * @return the number of frames written so far
262      */
263     virtual int64_t getFramesWritten();
264 
265     /**
266      * The number of audio frames read from the stream.
267      * This monotonic counter will never get reset.
268      *
269      * @return the number of frames read so far
270      */
271     virtual int64_t getFramesRead();
272 
273     /**
274      * Calculate the latency of a stream based on getTimestamp().
275      *
276      * Output latency is the time it takes for a given frame to travel from the
277      * app to some type of digital-to-analog converter. If the DAC is external, for example
278      * in a USB interface or a TV connected by HDMI, then there may be additional latency
279      * that the Android device is unaware of.
280      *
281      * Input latency is the time it takes to a given frame to travel from an analog-to-digital
282      * converter (ADC) to the app.
283      *
284      * Note that the latency of an OUTPUT stream will increase abruptly when you write data to it
285      * and then decrease slowly over time as the data is consumed.
286      *
287      * The latency of an INPUT stream will decrease abruptly when you read data from it
288      * and then increase slowly over time as more data arrives.
289      *
290      * The latency of an OUTPUT stream is generally higher than the INPUT latency
291      * because an app generally tries to keep the OUTPUT buffer full and the INPUT buffer empty.
292      *
293      * Note that due to issues in Android before R, we recommend NOT calling
294      * this method from a data callback. See this tech note for more details.
295      * https://github.com/google/oboe/wiki/TechNote_ReleaseBuffer
296      *
297      * @return a ResultWithValue which has a result of Result::OK and a value containing the latency
298      * in milliseconds, or a result of Result::Error*.
299      */
calculateLatencyMillis()300     virtual ResultWithValue<double> calculateLatencyMillis() {
301         return ResultWithValue<double>(Result::ErrorUnimplemented);
302     }
303 
304     /**
305      * Get the estimated time that the frame at `framePosition` entered or left the audio processing
306      * pipeline.
307      *
308      * This can be used to coordinate events and interactions with the external environment, and to
309      * estimate the latency of an audio stream. An example of usage can be found in the hello-oboe
310      * sample (search for "calculateCurrentOutputLatencyMillis").
311      *
312      * The time is based on the implementation's best effort, using whatever knowledge is available
313      * to the system, but cannot account for any delay unknown to the implementation.
314      *
315      * Note that due to issues in Android before R, we recommend NOT calling
316      * this method from a data callback. See this tech note for more details.
317      * https://github.com/google/oboe/wiki/TechNote_ReleaseBuffer
318      *
319      * @deprecated since 1.0, use AudioStream::getTimestamp(clockid_t clockId) instead, which
320      * returns ResultWithValue
321      * @param clockId the type of clock to use e.g. CLOCK_MONOTONIC
322      * @param framePosition the frame number to query
323      * @param timeNanoseconds an output parameter which will contain the presentation timestamp
324      */
getTimestamp(clockid_t,int64_t *,int64_t *)325     virtual Result getTimestamp(clockid_t /* clockId  */,
326                                 int64_t* /* framePosition */,
327                                 int64_t* /* timeNanoseconds */) {
328         return Result::ErrorUnimplemented;
329     }
330 
331     /**
332      * Get the estimated time that the frame at `framePosition` entered or left the audio processing
333      * pipeline.
334      *
335      * This can be used to coordinate events and interactions with the external environment, and to
336      * estimate the latency of an audio stream. An example of usage can be found in the hello-oboe
337      * sample (search for "calculateCurrentOutputLatencyMillis").
338      *
339      * The time is based on the implementation's best effort, using whatever knowledge is available
340      * to the system, but cannot account for any delay unknown to the implementation.
341      *
342      * Note that due to issues in Android before R, we recommend NOT calling
343      * this method from a data callback. See this tech note for more details.
344      * https://github.com/google/oboe/wiki/TechNote_ReleaseBuffer
345      *
346      * See
347      * @param clockId the type of clock to use e.g. CLOCK_MONOTONIC
348      * @return a FrameTimestamp containing the position and time at which a particular audio frame
349      * entered or left the audio processing pipeline, or an error if the operation failed.
350      */
351     virtual ResultWithValue<FrameTimestamp> getTimestamp(clockid_t /* clockId */);
352 
353     // ============== I/O ===========================
354     /**
355      * Write data from the supplied buffer into the stream. This method will block until the write
356      * is complete or it runs out of time.
357      *
358      * If `timeoutNanoseconds` is zero then this call will not wait.
359      *
360      * @param buffer The address of the first sample.
361      * @param numFrames Number of frames to write. Only complete frames will be written.
362      * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
363      * @return a ResultWithValue which has a result of Result::OK and a value containing the number
364      * of frames actually written, or result of Result::Error*.
365      */
write(const void *,int32_t,int64_t)366     virtual ResultWithValue<int32_t> write(const void* /* buffer */,
367                              int32_t /* numFrames */,
368                              int64_t /* timeoutNanoseconds */ ) {
369         return ResultWithValue<int32_t>(Result::ErrorUnimplemented);
370     }
371 
372     /**
373      * Read data into the supplied buffer from the stream. This method will block until the read
374      * is complete or it runs out of time.
375      *
376      * If `timeoutNanoseconds` is zero then this call will not wait.
377      *
378      * @param buffer The address of the first sample.
379      * @param numFrames Number of frames to read. Only complete frames will be read.
380      * @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
381      * @return a ResultWithValue which has a result of Result::OK and a value containing the number
382      * of frames actually read, or result of Result::Error*.
383      */
read(void *,int32_t,int64_t)384     virtual ResultWithValue<int32_t> read(void* /* buffer */,
385                             int32_t /* numFrames */,
386                             int64_t /* timeoutNanoseconds */) {
387         return ResultWithValue<int32_t>(Result::ErrorUnimplemented);
388     }
389 
390     /**
391      * Get the underlying audio API which the stream uses.
392      *
393      * @return the API that this stream uses.
394      */
395     virtual AudioApi getAudioApi() const = 0;
396 
397     /**
398      * Returns true if the underlying audio API is AAudio.
399      *
400      * @return true if this stream is implemented using the AAudio API.
401      */
usesAAudio()402     bool usesAAudio() const {
403         return getAudioApi() == AudioApi::AAudio;
404     }
405 
406     /**
407      * Only for debugging. Do not use in production.
408      * If you need to call this method something is wrong.
409      * If you think you need it for production then please let us know
410      * so we can modify Oboe so that you don't need this.
411      *
412      * @return nullptr or a pointer to a stream from the system API
413      */
getUnderlyingStream()414     virtual void *getUnderlyingStream() const {
415         return nullptr;
416     }
417 
418     /**
419      * Update mFramesWritten.
420      * For internal use only.
421      */
422     virtual void updateFramesWritten() = 0;
423 
424     /**
425      * Update mFramesRead.
426      * For internal use only.
427      */
428     virtual void updateFramesRead() = 0;
429 
430     /*
431      * Swap old callback for new callback.
432      * This not atomic.
433      * This should only be used internally.
434      * @param dataCallback
435      * @return previous dataCallback
436      */
swapDataCallback(AudioStreamDataCallback * dataCallback)437     AudioStreamDataCallback *swapDataCallback(AudioStreamDataCallback *dataCallback) {
438         AudioStreamDataCallback *previousCallback = mDataCallback;
439         mDataCallback = dataCallback;
440         return previousCallback;
441     }
442 
443     /*
444      * Swap old callback for new callback.
445      * This not atomic.
446      * This should only be used internally.
447      * @param errorCallback
448      * @return previous errorCallback
449      */
swapErrorCallback(AudioStreamErrorCallback * errorCallback)450     AudioStreamErrorCallback *swapErrorCallback(AudioStreamErrorCallback *errorCallback) {
451         AudioStreamErrorCallback *previousCallback = mErrorCallback;
452         mErrorCallback = errorCallback;
453         return previousCallback;
454     }
455 
456     /**
457      * @return number of frames of data currently in the buffer
458      */
459     ResultWithValue<int32_t> getAvailableFrames();
460 
461     /**
462      * Wait until the stream has a minimum amount of data available in its buffer.
463      * This can be used with an EXCLUSIVE MMAP input stream to avoid reading data too close to
464      * the DSP write position, which may cause glitches.
465      *
466      * Starting with Oboe 1.7.1, the numFrames will be clipped internally against the
467      * BufferCapacity minus BurstSize. This is to prevent trying to wait for more frames
468      * than could possibly be available. In this case, the return value may be less than numFrames.
469      * Note that there may still be glitching if numFrames is too high.
470      *
471      * @param numFrames requested minimum frames available
472      * @param timeoutNanoseconds
473      * @return number of frames available, ErrorTimeout
474      */
475     ResultWithValue<int32_t> waitForAvailableFrames(int32_t numFrames,
476                                                     int64_t timeoutNanoseconds);
477 
478     /**
479      * @return last result passed from an error callback
480      */
getLastErrorCallbackResult()481     virtual oboe::Result getLastErrorCallbackResult() const {
482         return mErrorCallbackResult;
483     }
484 
485 
getDelayBeforeCloseMillis()486     int32_t getDelayBeforeCloseMillis() const {
487         return mDelayBeforeCloseMillis;
488     }
489 
490     /**
491      * Set the time to sleep before closing the internal stream.
492      *
493      * Sometimes a callback can occur shortly after a stream has been stopped and
494      * even after a close! If the stream has been closed then the callback
495      * might access memory that has been freed, which could cause a crash.
496      * This seems to be more likely in Android P or earlier.
497      * But it can also occur in later versions. By sleeping, we give time for
498      * the callback threads to finish.
499      *
500      * Note that this only has an effect when OboeGlobals::areWorkaroundsEnabled() is true.
501      *
502      * @param delayBeforeCloseMillis time to sleep before close.
503      */
setDelayBeforeCloseMillis(int32_t delayBeforeCloseMillis)504     void setDelayBeforeCloseMillis(int32_t delayBeforeCloseMillis) {
505         mDelayBeforeCloseMillis = delayBeforeCloseMillis;
506     }
507 
508     /**
509      * Enable or disable a device specific CPU performance hint.
510      * Runtime benchmarks such as the callback duration may be used to
511      * speed up the CPU and improve real-time performance.
512      *
513      * Note that this feature is device specific and may not be implemented.
514      * Also the benefits may vary by device.
515      *
516      * The flag will be checked in the Oboe data callback. If it transitions from false to true
517      * then the PerformanceHint feature will be started.
518      * This only needs to be called once for each stream.
519      *
520      * You may want to enable this if you have a dynamically changing workload
521      * and you notice that you are getting under-runs and glitches when your workload increases.
522      * This might happen, for example, if you suddenly go from playing one note to
523      * ten notes on a synthesizer.
524      *
525      * Try the "CPU Load" test in OboeTester if you would like to experiment with this interactively.
526      *
527      * On some devices, this may be implemented using the "ADPF" library.
528      *
529      * @param enabled true if you would like a performance boost, default is false
530      */
setPerformanceHintEnabled(bool enabled)531     void setPerformanceHintEnabled(bool enabled) {
532         mPerformanceHintEnabled = enabled;
533     }
534 
535     /**
536      * This only tells you if the feature has been requested.
537      * It does not tell you if the PerformanceHint feature is implemented or active on the device.
538      *
539      * @return true if set using setPerformanceHintEnabled().
540      */
isPerformanceHintEnabled()541     bool isPerformanceHintEnabled() {
542         return mPerformanceHintEnabled;
543     }
544 
545     /**
546      * Use this to give the performance manager more information about your workload.
547      * You can call this at the beginning of the callback when you figure
548      * out what your workload will be.
549      *
550      * Call this if (1) you have called setPerformanceHintEnabled(true), and
551      * (2) you have a varying workload, and
552      * (3) you hear glitches when your workload suddenly increases.
553      *
554      * This might happen when you go from a single note to a big chord on a synthesizer.
555      *
556      * The workload can be in your own units. If you are synthesizing music
557      * then the workload could be the number of active voices.
558      * If your app is a game then it could be the number of sound effects.
559      * The units are arbitrary. They just have to be proportional to
560      * the estimated computational load. For example, if some of your voices take 20%
561      * more computation than a basic voice then assign 6 units to the complex voice
562      * and 5 units to the basic voice.
563      *
564      * The performance hint code can use this as an advance warning that the callback duration
565      * will probably increase. Rather than wait for the long duration and possibly under-run,
566      * we can boost the CPU immediately before we start doing the calculations.
567      *
568      * @param appWorkload workload in application units, such as number of voices
569      * @return OK or an error such as ErrorInvalidState if the PerformanceHint was not enabled.
570      */
reportWorkload(int32_t appWorkload)571     virtual oboe::Result reportWorkload(int32_t appWorkload) {
572         std::ignore = appWorkload;
573         return oboe::Result::ErrorUnimplemented;
574     }
575 
setOffloadDelayPadding(int32_t delayInFrames,int32_t paddingInFrames)576     virtual oboe::Result setOffloadDelayPadding(int32_t delayInFrames, int32_t paddingInFrames) {
577         std::ignore = delayInFrames;
578         std::ignore = paddingInFrames;
579         return Result::ErrorUnimplemented;
580     }
581 
getOffloadDelay()582     virtual ResultWithValue<int32_t> getOffloadDelay() {
583         return ResultWithValue<int32_t>(Result::ErrorUnimplemented);
584     }
585 
getOffloadPadding()586     virtual ResultWithValue<int32_t> getOffloadPadding() {
587         return ResultWithValue<int32_t>(Result::ErrorUnimplemented);
588     }
589 
setOffloadEndOfStream()590     virtual oboe::Result setOffloadEndOfStream() {
591         return Result::ErrorUnimplemented;
592     }
593 
594 protected:
595 
596     /**
597      * This is used to detect more than one error callback from a stream.
598      * These were bugs in some versions of Android that caused multiple error callbacks.
599      * Internal bug b/63087953
600      *
601      * Calling this sets an atomic<bool> true and returns the previous value.
602      *
603      * @return false on first call, true on subsequent calls
604      */
wasErrorCallbackCalled()605     bool wasErrorCallbackCalled() {
606         return mErrorCallbackCalled.exchange(true);
607     }
608 
609     /**
610      * Wait for a transition from one state to another.
611      * @return OK if the endingState was observed, or ErrorUnexpectedState
612      *   if any state that was not the startingState or endingState was observed
613      *   or ErrorTimeout.
614      */
615     virtual Result waitForStateTransition(StreamState startingState,
616                                           StreamState endingState,
617                                           int64_t timeoutNanoseconds);
618 
619     /**
620      * Override this to provide a default for when the application did not specify a callback.
621      *
622      * @param audioData
623      * @param numFrames
624      * @return result
625      */
onDefaultCallback(void *,int)626     virtual DataCallbackResult onDefaultCallback(void* /* audioData  */, int /* numFrames */) {
627         return DataCallbackResult::Stop;
628     }
629 
630     /**
631      * Override this to provide your own behaviour for the audio callback
632      *
633      * @param audioData container array which audio frames will be written into or read from
634      * @param numFrames number of frames which were read/written
635      * @return the result of the callback: stop or continue
636      *
637      */
638     DataCallbackResult fireDataCallback(void *audioData, int numFrames);
639 
640     /**
641      * @return true if callbacks may be called
642      */
isDataCallbackEnabled()643     bool isDataCallbackEnabled() {
644         return mDataCallbackEnabled;
645     }
646 
647     /**
648      * This can be set false internally to prevent callbacks
649      * after DataCallbackResult::Stop has been returned.
650      */
setDataCallbackEnabled(bool enabled)651     void setDataCallbackEnabled(bool enabled) {
652         mDataCallbackEnabled = enabled;
653     }
654 
655     /**
656      * This should only be called as a stream is being opened.
657      * Otherwise we might override setDelayBeforeCloseMillis().
658      */
659     void calculateDefaultDelayBeforeCloseMillis();
660 
661     /**
662      * Try to avoid a race condition when closing.
663      */
sleepBeforeClose()664     void sleepBeforeClose() {
665         if (mDelayBeforeCloseMillis > 0) {
666             usleep(mDelayBeforeCloseMillis * 1000);
667         }
668     }
669 
670     /**
671      * This may be called internally at the beginning of a callback.
672      */
beginPerformanceHintInCallback()673     virtual void beginPerformanceHintInCallback() {}
674 
675     /**
676      * This may be called internally at the end of a callback.
677      * @param numFrames passed to the callback
678      */
endPerformanceHintInCallback(int32_t)679     virtual void endPerformanceHintInCallback(int32_t /*numFrames*/) {}
680 
681     /**
682      * This will be called when the stream is closed just in case performance hints were enabled.
683      */
closePerformanceHint()684     virtual void closePerformanceHint() {}
685 
686     /*
687      * Set a weak_ptr to this stream from the shared_ptr so that we can
688      * later use a shared_ptr in the error callback.
689      */
setWeakThis(std::shared_ptr<oboe::AudioStream> & sharedStream)690     void setWeakThis(std::shared_ptr<oboe::AudioStream> &sharedStream) {
691         mWeakThis = sharedStream;
692     }
693 
694     /*
695      * Make a shared_ptr that will prevent this stream from being deleted.
696      */
lockWeakThis()697     std::shared_ptr<oboe::AudioStream> lockWeakThis() {
698         return mWeakThis.lock();
699     }
700 
701     std::weak_ptr<AudioStream> mWeakThis; // weak pointer to this object
702 
703     /**
704      * Number of frames which have been written into the stream
705      *
706      * This is signed integer to match the counters in AAudio.
707      * At audio rates, the counter will overflow in about six million years.
708      */
709     std::atomic<int64_t> mFramesWritten{};
710 
711     /**
712      * Number of frames which have been read from the stream.
713      *
714      * This is signed integer to match the counters in AAudio.
715      * At audio rates, the counter will overflow in about six million years.
716      */
717     std::atomic<int64_t> mFramesRead{};
718 
719     std::mutex           mLock; // for synchronizing start/stop/close
720 
721     oboe::Result         mErrorCallbackResult = oboe::Result::OK;
722 
723     /**
724      * Number of frames which will be copied to/from the audio device in a single read/write
725      * operation
726      */
727     int32_t              mFramesPerBurst = kUnspecified;
728 
729     // Time to sleep in order to prevent a race condition with a callback after a close().
730     // Two milliseconds may be enough but 10 msec is even safer.
731     static constexpr int kMinDelayBeforeCloseMillis = 10;
732     int32_t              mDelayBeforeCloseMillis = kMinDelayBeforeCloseMillis;
733 
734 private:
735 
736     // Log the scheduler if it changes.
737     void                 checkScheduler();
738     int                  mPreviousScheduler = -1;
739 
740     std::atomic<bool>    mDataCallbackEnabled{false};
741     std::atomic<bool>    mErrorCallbackCalled{false};
742 
743     std::atomic<bool>    mPerformanceHintEnabled{false}; // set only by app
744 };
745 
746 /**
747  * This struct is a stateless functor which closes an AudioStream prior to its deletion.
748  * This means it can be used to safely delete a smart pointer referring to an open stream.
749  */
750     struct StreamDeleterFunctor {
operatorStreamDeleterFunctor751         void operator()(AudioStream  *audioStream) {
752             if (audioStream) {
753                 audioStream->close();
754             }
755             delete audioStream;
756         }
757     };
758 } // namespace oboe
759 
760 #endif /* OBOE_STREAM_H_ */
761