oboe/
audio_stream.rs

1use num_traits::FromPrimitive;
2use oboe_sys as ffi;
3use std::{
4    ffi::c_void,
5    fmt::{self, Display},
6    marker::PhantomData,
7    mem::{transmute, MaybeUninit},
8    ops::{Deref, DerefMut},
9};
10
11use super::{
12    audio_stream_base_fmt, wrap_result, wrap_status, AudioApi, AudioStreamBase, FrameTimestamp,
13    Input, IsFrameType, Output, RawAudioInputStream, RawAudioOutputStream, RawAudioStream,
14    RawAudioStreamBase, Result, Status, StreamState, NANOS_PER_MILLISECOND,
15};
16
17/**
18 * The default number of nanoseconds to wait for when performing state change operations on the
19 * stream, such as `start` and `stop`.
20 *
21 * See [AudioStream::start_with_timeout]
22 */
23pub const DEFAULT_TIMEOUT_NANOS: i64 = 2000 * NANOS_PER_MILLISECOND;
24
25/**
26 * Safe base trait for Oboe audio stream.
27 */
28pub trait AudioStreamSafe: AudioStreamBase {
29    /**
30     * Query the current state, eg. `StreamState::Pausing`
31     */
32    fn get_state(&self) -> StreamState;
33
34    /**
35     * This can be used to adjust the latency of the buffer by changing
36     * the threshold where blocking will occur.
37     * By combining this with [`AudioStreamSafe::get_xrun_count`], the latency can be tuned
38     * at run-time for each device.
39     *
40     * This cannot be set higher than [`AudioStreamBase::get_buffer_capacity_in_frames`].
41     */
42    fn set_buffer_size_in_frames(&mut self, _requested_frames: i32) -> Result<i32>;
43
44    /**
45     * An XRun is an Underrun or an Overrun.
46     * During playing, an underrun will occur if the stream is not written in time
47     * and the system runs out of valid data.
48     * During recording, an overrun will occur if the stream is not read in time
49     * and there is no place to put the incoming data so it is discarded.
50     *
51     * An underrun or overrun can cause an audible "pop" or "glitch".
52     */
53    fn get_xrun_count(&self) -> Result<i32>;
54
55    /**
56     * Returns true if XRun counts are supported on the stream
57     */
58    fn is_xrun_count_supported(&self) -> bool;
59
60    /**
61     * Query the number of frames that are read or written by the endpoint at one time.
62     */
63    fn get_frames_per_burst(&mut self) -> i32;
64
65    /**
66     * Get the number of bytes in each audio frame. This is calculated using the channel count
67     * and the sample format. For example, a 2 channel floating point stream will have
68     * 2 * 4 = 8 bytes per frame.
69     */
70    fn get_bytes_per_frame(&mut self) -> i32 {
71        self.get_channel_count() as i32 * self.get_bytes_per_sample()
72    }
73
74    /**
75     * Get the number of bytes per sample. This is calculated using the sample format. For example,
76     * a stream using 16-bit integer samples will have 2 bytes per sample.
77     *
78     * @return the number of bytes per sample.
79     */
80    fn get_bytes_per_sample(&mut self) -> i32;
81
82    /**
83     * Calculate the latency of a stream based on getTimestamp().
84     *
85     * Output latency is the time it takes for a given frame to travel from the
86     * app to some type of digital-to-analog converter. If the DAC is external, for example
87     * in a USB interface or a TV connected by HDMI, then there may be additional latency
88     * that the Android device is unaware of.
89     *
90     * Input latency is the time it takes to a given frame to travel from an analog-to-digital
91     * converter (ADC) to the app.
92     *
93     * Note that the latency of an OUTPUT stream will increase abruptly when you write data to it
94     * and then decrease slowly over time as the data is consumed.
95     *
96     * The latency of an INPUT stream will decrease abruptly when you read data from it
97     * and then increase slowly over time as more data arrives.
98     *
99     * The latency of an OUTPUT stream is generally higher than the INPUT latency
100     * because an app generally tries to keep the OUTPUT buffer full and the INPUT buffer empty.
101     */
102    fn calculate_latency_millis(&mut self) -> Result<f64>;
103
104    /**
105     * Get the estimated time that the frame at `frame_position` entered or left the audio processing
106     * pipeline.
107     *
108     * This can be used to coordinate events and interactions with the external environment, and to
109     * estimate the latency of an audio stream. An example of usage can be found in the hello-oboe
110     * sample (search for "calculate_current_output_latency_millis").
111     *
112     * The time is based on the implementation's best effort, using whatever knowledge is available
113     * to the system, but cannot account for any delay unknown to the implementation.
114     *
115     * @param clockId the type of clock to use e.g. CLOCK_MONOTONIC
116     * @return a FrameTimestamp containing the position and time at which a particular audio frame
117     * entered or left the audio processing pipeline, or an error if the operation failed.
118     */
119    fn get_timestamp(&mut self, clock_id: i32) -> Result<FrameTimestamp>;
120
121    /**
122     * Get the underlying audio API which the stream uses.
123     */
124    fn get_audio_api(&self) -> AudioApi;
125
126    /**
127     * Returns true if the underlying audio API is AAudio.
128     */
129    fn uses_aaudio(&self) -> bool {
130        self.get_audio_api() == AudioApi::AAudio
131    }
132
133    /**
134     * Returns the number of frames of data currently in the buffer
135     */
136    fn get_available_frames(&mut self) -> Result<i32>;
137}
138
139/**
140 * Base trait for Oboe audio stream.
141 */
142pub trait AudioStream: AudioStreamSafe {
143    /**
144     * Open a stream based on the current settings.
145     *
146     * Note that we do not recommend re-opening a stream that has been closed.
147     * TODO Should we prevent re-opening?
148     */
149    fn open(&mut self) -> Status {
150        Ok(())
151    }
152
153    /**
154     * Close the stream and deallocate any resources from the open() call.
155     */
156    fn close(&mut self) -> Status;
157
158    /**
159     * Start the stream. This will block until the stream has been started, an error occurs
160     * or `timeout_nanoseconds` has been reached.
161     */
162    fn start(&mut self) -> Status {
163        self.start_with_timeout(DEFAULT_TIMEOUT_NANOS)
164    }
165
166    /**
167     * Start the stream. This will block until the stream has been started, an error occurs
168     * or `timeout_nanoseconds` has been reached.
169     */
170    fn start_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status;
171
172    /**
173     * Stop the stream. This will block until the stream has been stopped, an error occurs
174     * or `timeoutNanoseconds` has been reached.
175     */
176    fn stop(&mut self) -> Status {
177        self.stop_with_timeout(DEFAULT_TIMEOUT_NANOS)
178    }
179
180    /**
181     * Stop the stream. This will block until the stream has been stopped, an error occurs
182     * or `timeoutNanoseconds` has been reached.
183     */
184    fn stop_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status;
185
186    /**
187     * Start the stream asynchronously. Returns immediately (does not block). Equivalent to calling
188     * `start(0)`.
189     */
190    fn request_start(&mut self) -> Status;
191
192    /**
193     * Stop the stream asynchronously. Returns immediately (does not block). Equivalent to calling
194     * `stop(0)`.
195     */
196    fn request_stop(&mut self) -> Status;
197
198    /**
199     * Wait until the stream's current state no longer matches the input state.
200     * The input state is passed to avoid race conditions caused by the state
201     * changing between calls.
202     *
203     * Note that generally applications do not need to call this. It is considered
204     * an advanced technique and is mostly used for testing.
205     *
206     * ```ignore
207     * const TIMEOUT_NANOS: i64 = 500 * NANOS_PER_MILLISECOND; // arbitrary 1/2 second
208     * let mut current_state = stream.get_state();
209     * loop {
210     *     if let Ok(next_state) = stream.wait_for_state_change(current_state, TIMEOUT_NANOS) {
211     *         if next_state != StreamState::Paused {
212     *             current_state = next_state;
213     *             continue;
214     *         }
215     *     }
216     *     break;
217     * }
218     * ```
219     *
220     * If the state does not change within the timeout period then it will
221     * return [`Error::Timeout`](crate::Error::Timeout). This is true even if timeout_nanoseconds is zero.
222     */
223    fn wait_for_state_change(
224        &mut self,
225        input_state: StreamState,
226        timeout_nanoseconds: i64,
227    ) -> Result<StreamState>;
228
229    /**
230     * Wait until the stream has a minimum amount of data available in its buffer.
231     * This can be used with an EXCLUSIVE MMAP input stream to avoid reading data too close to
232     * the DSP write position, which may cause glitches.
233     */
234    fn wait_for_available_frames(
235        &mut self,
236        num_frames: i32,
237        timeout_nanoseconds: i64,
238    ) -> Result<i32>;
239}
240
241/**
242 * The stream which is used for async audio input
243 */
244pub trait AudioInputStreamSafe: AudioStreamSafe {
245    /**
246     * The number of audio frames read from the stream.
247     * This monotonic counter will never get reset.
248     */
249    fn get_frames_read(&mut self) -> i64;
250}
251
252/**
253 * The stream which is used for audio input
254 */
255pub trait AudioInputStream: AudioStream + AudioInputStreamSafe {}
256
257/**
258 * The stream which can be used for audio input in synchronous mode
259 */
260pub trait AudioInputStreamSync: AudioInputStream {
261    type FrameType: IsFrameType;
262
263    /**
264     * Read data into the supplied buffer from the stream. This method will block until the read
265     * is complete or it runs out of time.
266     *
267     * If `timeout_nanoseconds` is zero then this call will not wait.
268     */
269    fn read(
270        &mut self,
271        _buffer: &mut [<Self::FrameType as IsFrameType>::Type],
272        _timeout_nanoseconds: i64,
273    ) -> Result<i32>;
274}
275
276/**
277 * The stream which is used for async audio output
278 */
279pub trait AudioOutputStreamSafe: AudioStreamSafe {
280    /**
281     * The number of audio frames written into the stream.
282     * This monotonic counter will never get reset.
283     */
284    fn get_frames_written(&mut self) -> i64;
285}
286
287/**
288 * The stream which has pause/flush capabilities
289 */
290pub trait AudioOutputStream: AudioStream + AudioOutputStreamSafe {
291    /**
292     * Pause the stream. This will block until the stream has been paused, an error occurs
293     * or `timeoutNanoseconds` has been reached.
294     */
295    fn pause(&mut self) -> Status {
296        self.pause_with_timeout(DEFAULT_TIMEOUT_NANOS)
297    }
298
299    /**
300     * Pause the stream. This will block until the stream has been paused, an error occurs
301     * or `timeoutNanoseconds` has been reached.
302     */
303    fn pause_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status;
304
305    /**
306     * Flush the stream. This will block until the stream has been flushed, an error occurs
307     * or `timeoutNanoseconds` has been reached.
308     */
309    fn flush(&mut self) -> Status {
310        self.flush_with_timeout(DEFAULT_TIMEOUT_NANOS)
311    }
312
313    /**
314     * Flush the stream. This will block until the stream has been flushed, an error occurs
315     * or `timeoutNanoseconds` has been reached.
316     */
317    fn flush_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status;
318
319    /**
320     * Pause the stream asynchronously. Returns immediately (does not block). Equivalent to calling
321     * `pause(0)`.
322     */
323    fn request_pause(&mut self) -> Status;
324
325    /**
326     * Flush the stream asynchronously. Returns immediately (does not block). Equivalent to calling
327     * `flush(0)`.
328     */
329    fn request_flush(&mut self) -> Status;
330}
331
332/**
333 * The stream which can be used for audio output in synchronous mode
334 */
335pub trait AudioOutputStreamSync: AudioOutputStream {
336    type FrameType: IsFrameType;
337
338    /**
339     * Write data from the supplied buffer into the stream. This method will block until the write
340     * is complete or it runs out of time.
341     *
342     * If `timeout_nanoseconds` is zero then this call will not wait.
343     */
344    fn write(
345        &mut self,
346        _buffer: &[<Self::FrameType as IsFrameType>::Type],
347        _timeout_nanoseconds: i64,
348    ) -> Result<i32>;
349}
350
351impl<T: RawAudioStream + RawAudioStreamBase> AudioStreamSafe for T {
352    fn set_buffer_size_in_frames(&mut self, requested_frames: i32) -> Result<i32> {
353        wrap_result(unsafe {
354            ffi::oboe_AudioStream_setBufferSizeInFrames(self._raw_stream_mut(), requested_frames)
355        })
356    }
357
358    fn get_state(&self) -> StreamState {
359        FromPrimitive::from_i32(unsafe {
360            ffi::oboe_AudioStream_getState(self._raw_stream() as *const _ as *mut _)
361        })
362        .unwrap()
363    }
364
365    fn get_xrun_count(&self) -> Result<i32> {
366        wrap_result(unsafe {
367            ffi::oboe_AudioStream_getXRunCount(self._raw_stream() as *const _ as *mut _)
368        })
369    }
370
371    fn is_xrun_count_supported(&self) -> bool {
372        unsafe { ffi::oboe_AudioStream_isXRunCountSupported(self._raw_stream()) }
373    }
374
375    fn get_frames_per_burst(&mut self) -> i32 {
376        unsafe { ffi::oboe_AudioStream_getFramesPerBurst(self._raw_stream_mut()) }
377    }
378
379    fn get_bytes_per_sample(&mut self) -> i32 {
380        unsafe { ffi::oboe_AudioStream_getBytesPerSample(self._raw_stream_mut()) }
381    }
382
383    fn calculate_latency_millis(&mut self) -> Result<f64> {
384        wrap_result(unsafe { ffi::oboe_AudioStream_calculateLatencyMillis(self._raw_stream_mut()) })
385    }
386
387    fn get_timestamp(&mut self, clock_id: i32 /* clockid_t */) -> Result<FrameTimestamp> {
388        wrap_result(unsafe {
389            transmute(ffi::oboe_AudioStream_getTimestamp(
390                self._raw_stream_mut() as *mut _ as *mut c_void,
391                clock_id,
392            ))
393        })
394    }
395
396    fn get_audio_api(&self) -> AudioApi {
397        FromPrimitive::from_i32(unsafe { ffi::oboe_AudioStream_getAudioApi(self._raw_stream()) })
398            .unwrap()
399    }
400
401    fn get_available_frames(&mut self) -> Result<i32> {
402        wrap_result(unsafe { ffi::oboe_AudioStream_getAvailableFrames(self._raw_stream_mut()) })
403    }
404}
405
406impl<T: RawAudioStream + RawAudioStreamBase> AudioStream for T {
407    fn open(&mut self) -> Status {
408        wrap_status(unsafe { ffi::oboe_AudioStream_open(self._raw_stream_mut()) })
409    }
410
411    fn close(&mut self) -> Status {
412        wrap_status(unsafe { ffi::oboe_AudioStream_close1(self._raw_stream_mut()) })
413    }
414
415    fn start_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status {
416        wrap_status(unsafe {
417            ffi::oboe_AudioStream_start(
418                self._raw_stream_mut() as *mut _ as *mut c_void,
419                timeout_nanoseconds,
420            )
421        })
422    }
423
424    fn stop_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status {
425        wrap_status(unsafe {
426            ffi::oboe_AudioStream_stop(
427                self._raw_stream_mut() as *mut _ as *mut c_void,
428                timeout_nanoseconds,
429            )
430        })
431    }
432
433    fn request_start(&mut self) -> Status {
434        wrap_status(unsafe { ffi::oboe_AudioStream_requestStart(self._raw_stream_mut()) })
435    }
436
437    fn request_stop(&mut self) -> Status {
438        wrap_status(unsafe { ffi::oboe_AudioStream_requestStop(self._raw_stream_mut()) })
439    }
440
441    fn wait_for_state_change(
442        &mut self,
443        input_state: StreamState,
444        timeout_nanoseconds: i64,
445    ) -> Result<StreamState> {
446        let mut next_state = MaybeUninit::<StreamState>::uninit();
447        wrap_status(unsafe {
448            ffi::oboe_AudioStream_waitForStateChange(
449                self._raw_stream_mut(),
450                input_state as i32,
451                next_state.as_mut_ptr() as *mut i32,
452                timeout_nanoseconds,
453            )
454        })
455        .map(|_| unsafe { next_state.assume_init() })
456    }
457
458    fn wait_for_available_frames(
459        &mut self,
460        num_frames: i32,
461        timeout_nanoseconds: i64,
462    ) -> Result<i32> {
463        wrap_result(unsafe {
464            ffi::oboe_AudioStream_waitForAvailableFrames(
465                self._raw_stream_mut(),
466                num_frames,
467                timeout_nanoseconds,
468            )
469        })
470    }
471}
472
473impl<T: RawAudioInputStream + RawAudioStream + RawAudioStreamBase> AudioInputStreamSafe for T {
474    fn get_frames_read(&mut self) -> i64 {
475        unsafe {
476            ffi::oboe_AudioStream_getFramesRead(self._raw_stream_mut() as *mut _ as *mut c_void)
477        }
478    }
479}
480
481impl<T: RawAudioInputStream + RawAudioStream + RawAudioStreamBase> AudioInputStream for T {}
482
483impl<T: RawAudioOutputStream + RawAudioStream + RawAudioStreamBase> AudioOutputStreamSafe for T {
484    fn get_frames_written(&mut self) -> i64 {
485        unsafe {
486            ffi::oboe_AudioStream_getFramesWritten(self._raw_stream_mut() as *mut _ as *mut c_void)
487        }
488    }
489}
490
491impl<T: RawAudioOutputStream + RawAudioStream + RawAudioStreamBase> AudioOutputStream for T {
492    fn pause_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status {
493        wrap_status(unsafe {
494            ffi::oboe_AudioStream_pause(
495                self._raw_stream_mut() as *mut _ as *mut c_void,
496                timeout_nanoseconds,
497            )
498        })
499    }
500
501    fn flush_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status {
502        wrap_status(unsafe {
503            ffi::oboe_AudioStream_flush(
504                self._raw_stream_mut() as *mut _ as *mut c_void,
505                timeout_nanoseconds,
506            )
507        })
508    }
509
510    fn request_pause(&mut self) -> Status {
511        wrap_status(unsafe { ffi::oboe_AudioStream_requestPause(self._raw_stream_mut()) })
512    }
513
514    fn request_flush(&mut self) -> Status {
515        wrap_status(unsafe { ffi::oboe_AudioStream_requestFlush(self._raw_stream_mut()) })
516    }
517}
518
519pub(crate) fn audio_stream_fmt<T: AudioStreamSafe>(
520    stream: &T,
521    f: &mut fmt::Formatter<'_>,
522) -> fmt::Result {
523    audio_stream_base_fmt(stream, f)?;
524    "Audio API: ".fmt(f)?;
525    fmt::Debug::fmt(&stream.get_audio_api(), f)?;
526    "\nCurrent state: ".fmt(f)?;
527    fmt::Debug::fmt(&stream.get_state(), f)?;
528    "\nXrun count: ".fmt(f)?;
529    match stream.get_xrun_count() {
530        Ok(count) => count.fmt(f)?,
531        Err(error) => fmt::Debug::fmt(&error, f)?,
532    }
533    '\n'.fmt(f)
534}
535
536pub(crate) struct AudioStreamHandle(ffi::oboe_AudioStreamShared);
537
538impl Clone for AudioStreamHandle {
539    fn clone(&self) -> Self {
540        // We free to clone shared pointers
541        let mut new = Self::default();
542
543        unsafe { ffi::oboe_AudioStreamShared_clone(&self.0, new.as_mut()) };
544
545        new
546    }
547}
548
549impl Drop for AudioStreamHandle {
550    /// SAFETY: `self.0` must be valid pointers.
551    fn drop(&mut self) {
552        // The error callback could be holding a shared_ptr, so don't delete AudioStream
553        // directly, but only its shared_ptr.
554        unsafe { ffi::oboe_AudioStreamShared_delete(&mut self.0 as *mut _) };
555    }
556}
557
558impl Default for AudioStreamHandle {
559    fn default() -> Self {
560        Self(unsafe { MaybeUninit::zeroed().assume_init() })
561    }
562}
563
564impl AsRef<ffi::oboe_AudioStreamShared> for AudioStreamHandle {
565    fn as_ref(&self) -> &ffi::oboe_AudioStreamShared {
566        &self.0
567    }
568}
569
570impl AsMut<ffi::oboe_AudioStreamShared> for AudioStreamHandle {
571    fn as_mut(&mut self) -> &mut ffi::oboe_AudioStreamShared {
572        &mut self.0
573    }
574}
575
576impl Deref for AudioStreamHandle {
577    type Target = ffi::oboe_AudioStream;
578
579    fn deref(&self) -> &Self::Target {
580        unsafe { &*ffi::oboe_AudioStreamShared_deref(&self.0 as *const _ as *mut _) }
581    }
582}
583
584impl DerefMut for AudioStreamHandle {
585    fn deref_mut(&mut self) -> &mut Self::Target {
586        unsafe { &mut *ffi::oboe_AudioStreamShared_deref(&mut self.0) }
587    }
588}
589
590/**
591 * Reference to the audio stream for passing to callbacks
592 */
593#[repr(transparent)]
594pub struct AudioStreamRef<'s, D> {
595    raw: &'s mut ffi::oboe_AudioStream,
596    _phantom: PhantomData<D>,
597}
598
599impl<'s, D> fmt::Debug for AudioStreamRef<'s, D> {
600    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
601        audio_stream_fmt(self, f)
602    }
603}
604
605impl<'s, D> AudioStreamRef<'s, D> {
606    pub(crate) fn wrap_raw<'a: 's>(raw: &'a mut ffi::oboe_AudioStream) -> Self {
607        Self {
608            raw,
609            _phantom: PhantomData,
610        }
611    }
612}
613
614impl<'s, D> RawAudioStreamBase for AudioStreamRef<'s, D> {
615    fn _raw_base(&self) -> &ffi::oboe_AudioStreamBase {
616        unsafe { &*ffi::oboe_AudioStream_getBase(self.raw as *const _ as *mut _) }
617    }
618
619    fn _raw_base_mut(&mut self) -> &mut ffi::oboe_AudioStreamBase {
620        unsafe { &mut *ffi::oboe_AudioStream_getBase(self.raw) }
621    }
622}
623
624impl<'s, D> RawAudioStream for AudioStreamRef<'s, D> {
625    fn _raw_stream(&self) -> &ffi::oboe_AudioStream {
626        self.raw
627    }
628
629    fn _raw_stream_mut(&mut self) -> &mut ffi::oboe_AudioStream {
630        self.raw
631    }
632}
633
634impl<'s> RawAudioInputStream for AudioStreamRef<'s, Input> {}
635
636impl<'s> RawAudioOutputStream for AudioStreamRef<'s, Output> {}
637
638/**
639 * The audio stream for asynchronous (callback-driven) mode
640 */
641pub struct AudioStreamAsync<D, F> {
642    raw: AudioStreamHandle,
643    _phantom: PhantomData<(D, F)>,
644}
645
646impl<D, F> fmt::Debug for AudioStreamAsync<D, F> {
647    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
648        audio_stream_fmt(self, f)
649    }
650}
651
652impl<D, F> AudioStreamAsync<D, F> {
653    // SAFETY: `raw` must be valid.
654    pub(crate) fn wrap_handle(raw: AudioStreamHandle) -> Self {
655        Self {
656            raw,
657            _phantom: PhantomData,
658        }
659    }
660}
661
662impl<D, F> Drop for AudioStreamAsync<D, F> {
663    fn drop(&mut self) {
664        // SAFETY: As long as the conditions on Self::wrap_raw are guaranteed on the creation of
665        // self, this is safe.
666        let _ = self.close();
667    }
668}
669
670impl<D, T> RawAudioStreamBase for AudioStreamAsync<D, T> {
671    fn _raw_base(&self) -> &ffi::oboe_AudioStreamBase {
672        unsafe { &*ffi::oboe_AudioStream_getBase(&*self.raw as *const _ as *mut _) }
673    }
674
675    fn _raw_base_mut(&mut self) -> &mut ffi::oboe_AudioStreamBase {
676        unsafe { &mut *ffi::oboe_AudioStream_getBase(&mut *self.raw as *mut _) }
677    }
678}
679
680impl<D, F> RawAudioStream for AudioStreamAsync<D, F> {
681    fn _raw_stream(&self) -> &ffi::oboe_AudioStream {
682        &self.raw
683    }
684
685    fn _raw_stream_mut(&mut self) -> &mut ffi::oboe_AudioStream {
686        &mut self.raw
687    }
688}
689
690impl<F> RawAudioInputStream for AudioStreamAsync<Input, F> {}
691
692impl<F> RawAudioOutputStream for AudioStreamAsync<Output, F> {}
693
694/**
695 * The audio stream for synchronous (blocking) mode
696 */
697pub struct AudioStreamSync<D, F> {
698    raw: AudioStreamHandle,
699    _phantom: PhantomData<(D, F)>,
700}
701
702impl<D, F> fmt::Debug for AudioStreamSync<D, F> {
703    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
704        audio_stream_fmt(self, f)
705    }
706}
707
708impl<D, F> AudioStreamSync<D, F> {
709    // SAFETY: `raw` must be valid.
710    pub(crate) fn wrap_handle(raw: AudioStreamHandle) -> Self {
711        Self {
712            raw,
713            _phantom: PhantomData,
714        }
715    }
716}
717
718impl<D, F> Drop for AudioStreamSync<D, F> {
719    fn drop(&mut self) {
720        // SAFETY: As long as the conditions on Self::wrap_raw are guaranteed on the creation of
721        // self, this is safe.
722        let _ = self.close();
723    }
724}
725
726impl<D, T> RawAudioStreamBase for AudioStreamSync<D, T> {
727    fn _raw_base(&self) -> &ffi::oboe_AudioStreamBase {
728        unsafe { &*ffi::oboe_AudioStream_getBase(&*self.raw as *const _ as *mut _) }
729    }
730
731    fn _raw_base_mut(&mut self) -> &mut ffi::oboe_AudioStreamBase {
732        unsafe { &mut *ffi::oboe_AudioStream_getBase(&mut *self.raw as *mut _) }
733    }
734}
735
736impl<D, F> RawAudioStream for AudioStreamSync<D, F> {
737    fn _raw_stream(&self) -> &ffi::oboe_AudioStream {
738        &self.raw
739    }
740
741    fn _raw_stream_mut(&mut self) -> &mut ffi::oboe_AudioStream {
742        &mut self.raw
743    }
744}
745
746impl<F> RawAudioInputStream for AudioStreamSync<Input, F> {}
747
748impl<F> RawAudioOutputStream for AudioStreamSync<Output, F> {}
749
750impl<F: IsFrameType> AudioInputStreamSync for AudioStreamSync<Input, F> {
751    type FrameType = F;
752
753    fn read(
754        &mut self,
755        buffer: &mut [<Self::FrameType as IsFrameType>::Type],
756        timeout_nanoseconds: i64,
757    ) -> Result<i32> {
758        wrap_result(unsafe {
759            ffi::oboe_AudioStream_read(
760                &mut *self.raw,
761                buffer.as_mut_ptr() as *mut c_void,
762                buffer.len() as i32,
763                timeout_nanoseconds,
764            )
765        })
766    }
767}
768
769impl<F: IsFrameType> AudioOutputStreamSync for AudioStreamSync<Output, F> {
770    type FrameType = F;
771
772    fn write(
773        &mut self,
774        buffer: &[<Self::FrameType as IsFrameType>::Type],
775        timeout_nanoseconds: i64,
776    ) -> Result<i32> {
777        wrap_result(unsafe {
778            ffi::oboe_AudioStream_write(
779                &mut *self.raw,
780                buffer.as_ptr() as *const c_void,
781                buffer.len() as i32,
782                timeout_nanoseconds,
783            )
784        })
785    }
786}