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},
ptr::null_mut,
};
use super::{
audio_stream_base_fmt, wrap_result, wrap_status, AudioApi, AudioCallbackWrapper,
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()) })
.unwrap()
}
fn get_xrun_count(&self) -> Result<i32> {
wrap_result(unsafe { ffi::oboe_AudioStream_getXRunCount(self._raw_stream()) })
}
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_close(self._raw_stream_mut() as *mut _ as *mut c_void)
})
}
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)
}
#[repr(transparent)]
struct AudioStreamHandle(*mut ffi::oboe_AudioStream);
impl From<*mut ffi::oboe_AudioStream> for AudioStreamHandle {
fn from(raw: *mut ffi::oboe_AudioStream) -> Self {
Self(raw)
}
}
impl Default for AudioStreamHandle {
fn default() -> Self {
Self(null_mut())
}
}
impl Drop for AudioStreamHandle {
fn drop(&mut self) {
unsafe { ffi::oboe_AudioStream_delete(self.0) }
}
}
impl Deref for AudioStreamHandle {
type Target = ffi::oboe_AudioStream;
fn deref(&self) -> &Self::Target {
unsafe { &(*self.0) }
}
}
impl DerefMut for AudioStreamHandle {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &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,
#[used]
callback: AudioCallbackWrapper<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_raw(
raw: *mut ffi::oboe_AudioStream,
callback: AudioCallbackWrapper<D, F>,
) -> Self {
Self {
raw: raw.into(),
callback,
}
}
}
impl<D, T> RawAudioStreamBase for AudioStreamAsync<D, T> {
fn _raw_base(&self) -> &ffi::oboe_AudioStreamBase {
unsafe { &*ffi::oboe_AudioStream_getBase(self.raw.0) }
}
fn _raw_base_mut(&mut self) -> &mut ffi::oboe_AudioStreamBase {
unsafe { &mut *ffi::oboe_AudioStream_getBase(self.raw.0) }
}
}
impl<D, F> RawAudioStream for AudioStreamAsync<D, F> {
fn _raw_stream(&self) -> &ffi::oboe_AudioStream {
unsafe { transmute(&*self.raw) }
}
fn _raw_stream_mut(&mut self) -> &mut ffi::oboe_AudioStream {
unsafe { transmute(&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_raw(raw: *mut ffi::oboe_AudioStream) -> Self {
Self {
raw: raw.into(),
_phantom: PhantomData,
}
}
}
impl<D, T> RawAudioStreamBase for AudioStreamSync<D, T> {
fn _raw_base(&self) -> &ffi::oboe_AudioStreamBase {
unsafe { transmute(&&*self.raw) }
}
fn _raw_base_mut(&mut self) -> &mut ffi::oboe_AudioStreamBase {
unsafe { transmute(&mut &mut *self.raw) }
}
}
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,
)
})
}
}