use num_traits::FromPrimitive;
use oboe_sys as ffi;
use std::{
ffi::c_void,
fmt::{self, Display},
marker::PhantomData,
mem::{transmute, MaybeUninit},
ops::{Deref, DerefMut},
};
use super::{
audio_stream_base_fmt, wrap_result, wrap_status, AudioApi, AudioStreamBase, FrameTimestamp,
Input, IsFrameType, Output, RawAudioInputStream, RawAudioOutputStream, RawAudioStream,
RawAudioStreamBase, Result, Status, StreamState, NANOS_PER_MILLISECOND,
};
pub const DEFAULT_TIMEOUT_NANOS: i64 = 2000 * NANOS_PER_MILLISECOND;
pub trait AudioStreamSafe: AudioStreamBase {
fn get_state(&self) -> StreamState;
fn set_buffer_size_in_frames(&mut self, _requested_frames: i32) -> Result<i32>;
fn get_xrun_count(&self) -> Result<i32>;
fn is_xrun_count_supported(&self) -> bool;
fn get_frames_per_burst(&mut self) -> i32;
fn get_bytes_per_frame(&mut self) -> i32 {
self.get_channel_count() as i32 * self.get_bytes_per_sample()
}
fn get_bytes_per_sample(&mut self) -> i32;
fn calculate_latency_millis(&mut self) -> Result<f64>;
fn get_timestamp(&mut self, clock_id: i32) -> Result<FrameTimestamp>;
fn get_audio_api(&self) -> AudioApi;
fn uses_aaudio(&self) -> bool {
self.get_audio_api() == AudioApi::AAudio
}
fn get_available_frames(&mut self) -> Result<i32>;
}
pub trait AudioStream: AudioStreamSafe {
fn open(&mut self) -> Status {
Ok(())
}
fn close(&mut self) -> Status;
fn start(&mut self) -> Status {
self.start_with_timeout(DEFAULT_TIMEOUT_NANOS)
}
fn start_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status;
fn stop(&mut self) -> Status {
self.stop_with_timeout(DEFAULT_TIMEOUT_NANOS)
}
fn stop_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status;
fn request_start(&mut self) -> Status;
fn request_stop(&mut self) -> Status;
fn wait_for_state_change(
&mut self,
input_state: StreamState,
timeout_nanoseconds: i64,
) -> Result<StreamState>;
fn wait_for_available_frames(
&mut self,
num_frames: i32,
timeout_nanoseconds: i64,
) -> Result<i32>;
}
pub trait AudioInputStreamSafe: AudioStreamSafe {
fn get_frames_read(&mut self) -> i64;
}
pub trait AudioInputStream: AudioStream + AudioInputStreamSafe {}
pub trait AudioInputStreamSync: AudioInputStream {
type FrameType: IsFrameType;
fn read(
&mut self,
_buffer: &mut [<Self::FrameType as IsFrameType>::Type],
_timeout_nanoseconds: i64,
) -> Result<i32>;
}
pub trait AudioOutputStreamSafe: AudioStreamSafe {
fn get_frames_written(&mut self) -> i64;
}
pub trait AudioOutputStream: AudioStream + AudioOutputStreamSafe {
fn pause(&mut self) -> Status {
self.pause_with_timeout(DEFAULT_TIMEOUT_NANOS)
}
fn pause_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status;
fn flush(&mut self) -> Status {
self.flush_with_timeout(DEFAULT_TIMEOUT_NANOS)
}
fn flush_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status;
fn request_pause(&mut self) -> Status;
fn request_flush(&mut self) -> Status;
}
pub trait AudioOutputStreamSync: AudioOutputStream {
type FrameType: IsFrameType;
fn write(
&mut self,
_buffer: &[<Self::FrameType as IsFrameType>::Type],
_timeout_nanoseconds: i64,
) -> Result<i32>;
}
impl<T: RawAudioStream + RawAudioStreamBase> AudioStreamSafe for T {
fn set_buffer_size_in_frames(&mut self, requested_frames: i32) -> Result<i32> {
wrap_result(unsafe {
ffi::oboe_AudioStream_setBufferSizeInFrames(self._raw_stream_mut(), requested_frames)
})
}
fn get_state(&self) -> StreamState {
FromPrimitive::from_i32(unsafe {
ffi::oboe_AudioStream_getState(self._raw_stream() as *const _ as *mut _)
})
.unwrap()
}
fn get_xrun_count(&self) -> Result<i32> {
wrap_result(unsafe {
ffi::oboe_AudioStream_getXRunCount(self._raw_stream() as *const _ as *mut _)
})
}
fn is_xrun_count_supported(&self) -> bool {
unsafe { ffi::oboe_AudioStream_isXRunCountSupported(self._raw_stream()) }
}
fn get_frames_per_burst(&mut self) -> i32 {
unsafe { ffi::oboe_AudioStream_getFramesPerBurst(self._raw_stream_mut()) }
}
fn get_bytes_per_sample(&mut self) -> i32 {
unsafe { ffi::oboe_AudioStream_getBytesPerSample(self._raw_stream_mut()) }
}
fn calculate_latency_millis(&mut self) -> Result<f64> {
wrap_result(unsafe { ffi::oboe_AudioStream_calculateLatencyMillis(self._raw_stream_mut()) })
}
fn get_timestamp(&mut self, clock_id: i32 ) -> Result<FrameTimestamp> {
wrap_result(unsafe {
transmute(ffi::oboe_AudioStream_getTimestamp(
self._raw_stream_mut() as *mut _ as *mut c_void,
clock_id,
))
})
}
fn get_audio_api(&self) -> AudioApi {
FromPrimitive::from_i32(unsafe { ffi::oboe_AudioStream_getAudioApi(self._raw_stream()) })
.unwrap()
}
fn get_available_frames(&mut self) -> Result<i32> {
wrap_result(unsafe { ffi::oboe_AudioStream_getAvailableFrames(self._raw_stream_mut()) })
}
}
impl<T: RawAudioStream + RawAudioStreamBase> AudioStream for T {
fn open(&mut self) -> Status {
wrap_status(unsafe { ffi::oboe_AudioStream_open(self._raw_stream_mut()) })
}
fn close(&mut self) -> Status {
wrap_status(unsafe { ffi::oboe_AudioStream_close1(self._raw_stream_mut()) })
}
fn start_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status {
wrap_status(unsafe {
ffi::oboe_AudioStream_start(
self._raw_stream_mut() as *mut _ as *mut c_void,
timeout_nanoseconds,
)
})
}
fn stop_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status {
wrap_status(unsafe {
ffi::oboe_AudioStream_stop(
self._raw_stream_mut() as *mut _ as *mut c_void,
timeout_nanoseconds,
)
})
}
fn request_start(&mut self) -> Status {
wrap_status(unsafe { ffi::oboe_AudioStream_requestStart(self._raw_stream_mut()) })
}
fn request_stop(&mut self) -> Status {
wrap_status(unsafe { ffi::oboe_AudioStream_requestStop(self._raw_stream_mut()) })
}
fn wait_for_state_change(
&mut self,
input_state: StreamState,
timeout_nanoseconds: i64,
) -> Result<StreamState> {
let mut next_state = MaybeUninit::<StreamState>::uninit();
wrap_status(unsafe {
ffi::oboe_AudioStream_waitForStateChange(
self._raw_stream_mut(),
input_state as i32,
next_state.as_mut_ptr() as *mut i32,
timeout_nanoseconds,
)
})
.map(|_| unsafe { next_state.assume_init() })
}
fn wait_for_available_frames(
&mut self,
num_frames: i32,
timeout_nanoseconds: i64,
) -> Result<i32> {
wrap_result(unsafe {
ffi::oboe_AudioStream_waitForAvailableFrames(
self._raw_stream_mut(),
num_frames,
timeout_nanoseconds,
)
})
}
}
impl<T: RawAudioInputStream + RawAudioStream + RawAudioStreamBase> AudioInputStreamSafe for T {
fn get_frames_read(&mut self) -> i64 {
unsafe {
ffi::oboe_AudioStream_getFramesRead(self._raw_stream_mut() as *mut _ as *mut c_void)
}
}
}
impl<T: RawAudioInputStream + RawAudioStream + RawAudioStreamBase> AudioInputStream for T {}
impl<T: RawAudioOutputStream + RawAudioStream + RawAudioStreamBase> AudioOutputStreamSafe for T {
fn get_frames_written(&mut self) -> i64 {
unsafe {
ffi::oboe_AudioStream_getFramesWritten(self._raw_stream_mut() as *mut _ as *mut c_void)
}
}
}
impl<T: RawAudioOutputStream + RawAudioStream + RawAudioStreamBase> AudioOutputStream for T {
fn pause_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status {
wrap_status(unsafe {
ffi::oboe_AudioStream_pause(
self._raw_stream_mut() as *mut _ as *mut c_void,
timeout_nanoseconds,
)
})
}
fn flush_with_timeout(&mut self, timeout_nanoseconds: i64) -> Status {
wrap_status(unsafe {
ffi::oboe_AudioStream_flush(
self._raw_stream_mut() as *mut _ as *mut c_void,
timeout_nanoseconds,
)
})
}
fn request_pause(&mut self) -> Status {
wrap_status(unsafe { ffi::oboe_AudioStream_requestPause(self._raw_stream_mut()) })
}
fn request_flush(&mut self) -> Status {
wrap_status(unsafe { ffi::oboe_AudioStream_requestFlush(self._raw_stream_mut()) })
}
}
pub(crate) fn audio_stream_fmt<T: AudioStreamSafe>(
stream: &T,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
audio_stream_base_fmt(stream, f)?;
"Audio API: ".fmt(f)?;
fmt::Debug::fmt(&stream.get_audio_api(), f)?;
"\nCurrent state: ".fmt(f)?;
fmt::Debug::fmt(&stream.get_state(), f)?;
"\nXrun count: ".fmt(f)?;
match stream.get_xrun_count() {
Ok(count) => count.fmt(f)?,
Err(error) => fmt::Debug::fmt(&error, f)?,
}
'\n'.fmt(f)
}
pub(crate) struct AudioStreamHandle(ffi::oboe_AudioStreamShared);
impl Clone for AudioStreamHandle {
fn clone(&self) -> Self {
let mut new = Self::default();
unsafe { ffi::oboe_AudioStreamShared_clone(&self.0, new.as_mut()) };
new
}
}
impl Drop for AudioStreamHandle {
fn drop(&mut self) {
unsafe { ffi::oboe_AudioStreamShared_delete(&mut self.0 as *mut _) };
}
}
impl Default for AudioStreamHandle {
fn default() -> Self {
Self(unsafe { MaybeUninit::zeroed().assume_init() })
}
}
impl AsRef<ffi::oboe_AudioStreamShared> for AudioStreamHandle {
fn as_ref(&self) -> &ffi::oboe_AudioStreamShared {
&self.0
}
}
impl AsMut<ffi::oboe_AudioStreamShared> for AudioStreamHandle {
fn as_mut(&mut self) -> &mut ffi::oboe_AudioStreamShared {
&mut self.0
}
}
impl Deref for AudioStreamHandle {
type Target = ffi::oboe_AudioStream;
fn deref(&self) -> &Self::Target {
unsafe { &*ffi::oboe_AudioStreamShared_deref(&self.0 as *const _ as *mut _) }
}
}
impl DerefMut for AudioStreamHandle {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *ffi::oboe_AudioStreamShared_deref(&mut self.0) }
}
}
#[repr(transparent)]
pub struct AudioStreamRef<'s, D> {
raw: &'s mut ffi::oboe_AudioStream,
_phantom: PhantomData<D>,
}
impl<'s, D> fmt::Debug for AudioStreamRef<'s, D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
audio_stream_fmt(self, f)
}
}
impl<'s, D> AudioStreamRef<'s, D> {
pub(crate) fn wrap_raw<'a: 's>(raw: &'a mut ffi::oboe_AudioStream) -> Self {
Self {
raw,
_phantom: PhantomData,
}
}
}
impl<'s, D> RawAudioStreamBase for AudioStreamRef<'s, D> {
fn _raw_base(&self) -> &ffi::oboe_AudioStreamBase {
unsafe { &*ffi::oboe_AudioStream_getBase(self.raw as *const _ as *mut _) }
}
fn _raw_base_mut(&mut self) -> &mut ffi::oboe_AudioStreamBase {
unsafe { &mut *ffi::oboe_AudioStream_getBase(self.raw) }
}
}
impl<'s, D> RawAudioStream for AudioStreamRef<'s, D> {
fn _raw_stream(&self) -> &ffi::oboe_AudioStream {
self.raw
}
fn _raw_stream_mut(&mut self) -> &mut ffi::oboe_AudioStream {
self.raw
}
}
impl<'s> RawAudioInputStream for AudioStreamRef<'s, Input> {}
impl<'s> RawAudioOutputStream for AudioStreamRef<'s, Output> {}
pub struct AudioStreamAsync<D, F> {
raw: AudioStreamHandle,
_phantom: PhantomData<(D, F)>,
}
impl<D, F> fmt::Debug for AudioStreamAsync<D, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
audio_stream_fmt(self, f)
}
}
impl<D, F> AudioStreamAsync<D, F> {
pub(crate) fn wrap_handle(raw: AudioStreamHandle) -> Self {
Self {
raw,
_phantom: PhantomData,
}
}
}
impl<D, F> Drop for AudioStreamAsync<D, F> {
fn drop(&mut self) {
let _ = self.close();
}
}
impl<D, T> RawAudioStreamBase for AudioStreamAsync<D, T> {
fn _raw_base(&self) -> &ffi::oboe_AudioStreamBase {
unsafe { &*ffi::oboe_AudioStream_getBase(&*self.raw as *const _ as *mut _) }
}
fn _raw_base_mut(&mut self) -> &mut ffi::oboe_AudioStreamBase {
unsafe { &mut *ffi::oboe_AudioStream_getBase(&mut *self.raw as *mut _) }
}
}
impl<D, F> RawAudioStream for AudioStreamAsync<D, F> {
fn _raw_stream(&self) -> &ffi::oboe_AudioStream {
&self.raw
}
fn _raw_stream_mut(&mut self) -> &mut ffi::oboe_AudioStream {
&mut self.raw
}
}
impl<F> RawAudioInputStream for AudioStreamAsync<Input, F> {}
impl<F> RawAudioOutputStream for AudioStreamAsync<Output, F> {}
pub struct AudioStreamSync<D, F> {
raw: AudioStreamHandle,
_phantom: PhantomData<(D, F)>,
}
impl<D, F> fmt::Debug for AudioStreamSync<D, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
audio_stream_fmt(self, f)
}
}
impl<D, F> AudioStreamSync<D, F> {
pub(crate) fn wrap_handle(raw: AudioStreamHandle) -> Self {
Self {
raw,
_phantom: PhantomData,
}
}
}
impl<D, F> Drop for AudioStreamSync<D, F> {
fn drop(&mut self) {
let _ = self.close();
}
}
impl<D, T> RawAudioStreamBase for AudioStreamSync<D, T> {
fn _raw_base(&self) -> &ffi::oboe_AudioStreamBase {
unsafe { &*ffi::oboe_AudioStream_getBase(&*self.raw as *const _ as *mut _) }
}
fn _raw_base_mut(&mut self) -> &mut ffi::oboe_AudioStreamBase {
unsafe { &mut *ffi::oboe_AudioStream_getBase(&mut *self.raw as *mut _) }
}
}
impl<D, F> RawAudioStream for AudioStreamSync<D, F> {
fn _raw_stream(&self) -> &ffi::oboe_AudioStream {
&self.raw
}
fn _raw_stream_mut(&mut self) -> &mut ffi::oboe_AudioStream {
&mut self.raw
}
}
impl<F> RawAudioInputStream for AudioStreamSync<Input, F> {}
impl<F> RawAudioOutputStream for AudioStreamSync<Output, F> {}
impl<F: IsFrameType> AudioInputStreamSync for AudioStreamSync<Input, F> {
type FrameType = F;
fn read(
&mut self,
buffer: &mut [<Self::FrameType as IsFrameType>::Type],
timeout_nanoseconds: i64,
) -> Result<i32> {
wrap_result(unsafe {
ffi::oboe_AudioStream_read(
&mut *self.raw,
buffer.as_mut_ptr() as *mut c_void,
buffer.len() as i32,
timeout_nanoseconds,
)
})
}
}
impl<F: IsFrameType> AudioOutputStreamSync for AudioStreamSync<Output, F> {
type FrameType = F;
fn write(
&mut self,
buffer: &[<Self::FrameType as IsFrameType>::Type],
timeout_nanoseconds: i64,
) -> Result<i32> {
wrap_result(unsafe {
ffi::oboe_AudioStream_write(
&mut *self.raw,
buffer.as_ptr() as *const c_void,
buffer.len() as i32,
timeout_nanoseconds,
)
})
}
}