1use crate::ffi;
12use std::fmt;
13
14#[repr(C)]
19pub struct AudioBuffer {
20 pub number_channels: u32,
22 pub data_bytes_size: u32,
24 data_ptr: *mut std::ffi::c_void,
25}
26
27impl PartialEq for AudioBuffer {
28 fn eq(&self, other: &Self) -> bool {
29 self.number_channels == other.number_channels
30 && self.data_bytes_size == other.data_bytes_size
31 && self.data_ptr == other.data_ptr
32 }
33}
34
35impl Eq for AudioBuffer {}
36
37impl std::hash::Hash for AudioBuffer {
38 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
39 self.number_channels.hash(state);
40 self.data_bytes_size.hash(state);
41 self.data_ptr.hash(state);
42 }
43}
44
45impl fmt::Display for AudioBuffer {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 write!(
48 f,
49 "AudioBuffer({} channels, {} bytes)",
50 self.number_channels, self.data_bytes_size
51 )
52 }
53}
54
55impl AudioBuffer {
56 #[must_use]
58 pub fn data(&self) -> &[u8] {
59 if self.data_ptr.is_null() || self.data_bytes_size == 0 {
60 &[]
61 } else {
62 unsafe {
63 std::slice::from_raw_parts(
64 self.data_ptr as *const u8,
65 self.data_bytes_size as usize,
66 )
67 }
68 }
69 }
70
71 #[must_use]
73 pub const fn data_byte_size(&self) -> usize {
74 self.data_bytes_size as usize
75 }
76}
77
78pub struct AudioBufferRef<'a> {
80 buffer: &'a AudioBuffer,
81}
82
83impl AudioBufferRef<'_> {
84 #[must_use]
86 pub const fn data_byte_size(&self) -> usize {
87 self.buffer.data_byte_size()
88 }
89
90 #[must_use]
92 pub fn data(&self) -> &[u8] {
93 self.buffer.data()
94 }
95}
96
97impl std::fmt::Debug for AudioBufferRef<'_> {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 f.debug_struct("AudioBufferRef")
100 .field("channels", &self.buffer.number_channels)
101 .field("data_bytes", &self.buffer.data_bytes_size)
102 .finish()
103 }
104}
105
106impl std::fmt::Debug for AudioBuffer {
107 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108 f.debug_struct("AudioBuffer")
109 .field("number_channels", &self.number_channels)
110 .field("data_bytes_size", &self.data_bytes_size)
111 .finish_non_exhaustive()
112 }
113}
114
115#[repr(C)]
117#[derive(Debug)]
118pub struct AudioBufferListRaw {
119 pub(crate) num_buffers: u32,
121 pub(crate) buffers_ptr: *mut AudioBuffer,
123 pub(crate) buffers_len: usize,
125}
126
127pub struct AudioBufferList {
132 pub(crate) inner: AudioBufferListRaw,
134 pub(crate) block_buffer_ptr: *mut std::ffi::c_void,
136}
137
138impl AudioBufferList {
139 pub(crate) unsafe fn from_bridge(
140 num_buffers: u32,
141 buffers_ptr: *mut AudioBuffer,
142 buffers_len: usize,
143 block_buffer_ptr: *mut std::ffi::c_void,
144 ) -> Option<Self> {
145 let list = Self {
146 inner: AudioBufferListRaw {
147 num_buffers,
148 buffers_ptr,
149 buffers_len,
150 },
151 block_buffer_ptr,
152 };
153 let consistent = !buffers_ptr.is_null()
154 && !block_buffer_ptr.is_null()
155 && usize::try_from(num_buffers).is_ok_and(|count| count == buffers_len);
156 consistent.then_some(list)
157 }
158
159 #[must_use]
161 pub const fn num_buffers(&self) -> usize {
162 self.inner.num_buffers as usize
163 }
164
165 #[must_use]
167 pub fn get(&self, index: usize) -> Option<&AudioBuffer> {
168 if index >= self.num_buffers() {
169 None
170 } else {
171 unsafe { Some(&*self.inner.buffers_ptr.add(index)) }
172 }
173 }
174
175 #[must_use]
177 pub fn buffer(&self, index: usize) -> Option<AudioBufferRef<'_>> {
178 self.get(index).map(|buffer| AudioBufferRef { buffer })
179 }
180
181 #[must_use]
183 pub const fn iter(&self) -> AudioBufferListIter<'_> {
184 AudioBufferListIter {
185 list: self,
186 index: 0,
187 }
188 }
189}
190
191impl Drop for AudioBufferList {
192 fn drop(&mut self) {
193 if !self.inner.buffers_ptr.is_null() {
194 unsafe { ffi::acf_cm_audio_buffer_array_free(self.inner.buffers_ptr.cast()) };
195 }
196 if !self.block_buffer_ptr.is_null() {
198 unsafe {
199 ffi::cm_block_buffer_release(self.block_buffer_ptr);
200 }
201 }
202 }
203}
204
205impl<'a> IntoIterator for &'a AudioBufferList {
206 type Item = &'a AudioBuffer;
207 type IntoIter = AudioBufferListIter<'a>;
208
209 fn into_iter(self) -> Self::IntoIter {
210 self.iter()
211 }
212}
213
214impl fmt::Display for AudioBufferList {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 write!(f, "AudioBufferList({} buffers)", self.num_buffers())
217 }
218}
219
220impl fmt::Debug for AudioBufferList {
221 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222 f.debug_struct("AudioBufferList")
223 .field("num_buffers", &self.num_buffers())
224 .finish()
225 }
226}
227
228pub struct AudioBufferListIter<'a> {
230 list: &'a AudioBufferList,
231 index: usize,
232}
233
234impl std::fmt::Debug for AudioBufferListIter<'_> {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 f.debug_struct("AudioBufferListIter")
237 .field("total", &self.list.num_buffers())
238 .field(
239 "remaining",
240 &(self.list.num_buffers().saturating_sub(self.index)),
241 )
242 .finish()
243 }
244}
245
246impl<'a> Iterator for AudioBufferListIter<'a> {
247 type Item = &'a AudioBuffer;
248
249 fn next(&mut self) -> Option<Self::Item> {
250 if self.index < self.list.num_buffers() {
251 let buffer = self.list.get(self.index);
252 self.index += 1;
253 buffer
254 } else {
255 None
256 }
257 }
258}