use super::ffi;
use std::fmt;
#[repr(C)]
pub struct AudioBuffer {
number_channels: u32,
data_bytes_size: u32,
data_ptr: *mut std::ffi::c_void,
}
impl PartialEq for AudioBuffer {
fn eq(&self, other: &Self) -> bool {
self.number_channels == other.number_channels
&& self.data_bytes_size == other.data_bytes_size
&& self.data_ptr == other.data_ptr
}
}
impl Eq for AudioBuffer {}
impl std::hash::Hash for AudioBuffer {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.number_channels.hash(state);
self.data_bytes_size.hash(state);
self.data_ptr.hash(state);
}
}
impl fmt::Display for AudioBuffer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"AudioBuffer({} channels, {} bytes)",
self.number_channels, self.data_bytes_size
)
}
}
impl AudioBuffer {
#[must_use]
pub const fn number_channels(&self) -> u32 {
self.number_channels
}
pub fn data(&self) -> &[u8] {
if self.data_ptr.is_null() || self.data_bytes_size == 0 {
&[]
} else {
unsafe {
std::slice::from_raw_parts(
self.data_ptr as *const u8,
self.data_bytes_size as usize,
)
}
}
}
pub unsafe fn data_mut(&mut self) -> &mut [u8] {
if self.data_ptr.is_null() || self.data_bytes_size == 0 {
&mut []
} else {
unsafe {
std::slice::from_raw_parts_mut(
self.data_ptr.cast::<u8>(),
self.data_bytes_size as usize,
)
}
}
}
pub fn data_byte_size(&self) -> usize {
self.data_bytes_size as usize
}
}
pub struct AudioBufferRef<'a> {
buffer: &'a AudioBuffer,
}
impl<'a> AudioBufferRef<'a> {
pub fn data_byte_size(&self) -> usize {
self.buffer.data_byte_size()
}
#[must_use]
pub const fn number_channels(&self) -> u32 {
self.buffer.number_channels
}
pub fn data(&self) -> &'a [u8] {
self.buffer.data()
}
}
impl std::fmt::Debug for AudioBufferRef<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AudioBufferRef")
.field("channels", &self.buffer.number_channels)
.field("data_bytes", &self.buffer.data_bytes_size)
.finish()
}
}
impl std::fmt::Debug for AudioBuffer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AudioBuffer")
.field("number_channels", &self.number_channels)
.field("data_bytes_size", &self.data_bytes_size)
.finish_non_exhaustive()
}
}
#[repr(C)]
#[derive(Debug)]
pub struct AudioBufferListRaw {
pub(crate) num_buffers: u32,
pub(crate) buffers_ptr: *mut AudioBuffer,
pub(crate) buffers_len: usize,
}
pub struct AudioBufferList {
pub(crate) inner: AudioBufferListRaw,
pub(crate) block_buffer_ptr: *mut std::ffi::c_void,
}
impl AudioBufferList {
pub(crate) unsafe fn from_bridge(
num_buffers: u32,
buffers_ptr: *mut AudioBuffer,
buffers_len: usize,
block_buffer_ptr: *mut std::ffi::c_void,
) -> Option<Self> {
let consistent = num_buffers != 0
&& !buffers_ptr.is_null()
&& usize::try_from(num_buffers).is_ok_and(|n| n == buffers_len);
if !consistent {
unsafe { Self::release_bridge_allocations(buffers_ptr, buffers_len, block_buffer_ptr) };
return None;
}
Some(Self {
inner: AudioBufferListRaw {
num_buffers,
buffers_ptr,
buffers_len,
},
block_buffer_ptr,
})
}
unsafe fn release_bridge_allocations(
buffers_ptr: *mut AudioBuffer,
buffers_len: usize,
block_buffer_ptr: *mut std::ffi::c_void,
) {
if !buffers_ptr.is_null() && buffers_len != 0 {
unsafe { ffi::cm_audio_buffer_bridge_array_free(buffers_ptr.cast()) };
}
if !block_buffer_ptr.is_null() {
unsafe {
ffi::cm_block_buffer_release(block_buffer_ptr);
}
}
}
pub fn num_buffers(&self) -> usize {
self.inner.num_buffers as usize
}
pub fn get(&self, index: usize) -> Option<&AudioBuffer> {
if index >= self.num_buffers() {
None
} else {
unsafe { Some(&*self.inner.buffers_ptr.add(index)) }
}
}
pub fn buffer(&self, index: usize) -> Option<AudioBufferRef<'_>> {
self.get(index).map(|buffer| AudioBufferRef { buffer })
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut AudioBuffer> {
if index >= self.num_buffers() {
None
} else {
unsafe { Some(&mut *self.inner.buffers_ptr.add(index)) }
}
}
pub fn iter(&self) -> AudioBufferListIter<'_> {
AudioBufferListIter {
list: self,
index: 0,
}
}
}
impl Drop for AudioBufferList {
fn drop(&mut self) {
unsafe {
Self::release_bridge_allocations(
self.inner.buffers_ptr,
self.inner.buffers_len,
self.block_buffer_ptr,
);
}
}
}
impl<'a> IntoIterator for &'a AudioBufferList {
type Item = &'a AudioBuffer;
type IntoIter = AudioBufferListIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl fmt::Display for AudioBufferList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AudioBufferList({} buffers)", self.num_buffers())
}
}
impl fmt::Debug for AudioBufferList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AudioBufferList")
.field("num_buffers", &self.num_buffers())
.finish()
}
}
pub struct AudioBufferListIter<'a> {
list: &'a AudioBufferList,
index: usize,
}
impl std::fmt::Debug for AudioBufferListIter<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AudioBufferListIter")
.field("total", &self.list.num_buffers())
.field(
"remaining",
&(self.list.num_buffers().saturating_sub(self.index)),
)
.finish()
}
}
impl<'a> Iterator for AudioBufferListIter<'a> {
type Item = &'a AudioBuffer;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.list.num_buffers() {
let buffer = self.list.get(self.index);
self.index += 1;
buffer
} else {
None
}
}
}