1#![allow(dead_code)]
15
16use alloc::vec::Vec;
17use core::sync::atomic::{AtomicU32, Ordering};
18
19use crate::audio::AudioConfig;
20
21pub struct AudioRingBuffer {
30 data: Vec<u8>,
32 read_pos: AtomicU32,
34 write_pos: AtomicU32,
36 capacity: u32,
38 frame_size: u16,
40}
41
42impl AudioRingBuffer {
43 pub fn new(capacity_frames: u32, frame_size: u16) -> Self {
47 let byte_capacity = capacity_frames * frame_size as u32;
48 Self {
49 data: alloc::vec![0u8; byte_capacity as usize],
50 read_pos: AtomicU32::new(0),
51 write_pos: AtomicU32::new(0),
52 capacity: byte_capacity,
53 frame_size,
54 }
55 }
56
57 pub fn write(&self, data: &[u8]) -> usize {
62 let write = self.write_pos.load(Ordering::Acquire);
63 let read = self.read_pos.load(Ordering::Acquire);
64 let cap = self.capacity;
65
66 let used = if write >= read {
69 write - read
70 } else {
71 cap - read + write
72 };
73 let available = (cap - 1 - used) as usize;
74 let to_write = data.len().min(available);
75
76 if to_write == 0 {
77 return 0;
78 }
79
80 let w = write as usize;
81 let c = cap as usize;
82
83 let first_chunk = (c - w).min(to_write);
85 let second_chunk = to_write - first_chunk;
86
87 let data_ptr = self.data.as_ptr() as *mut u8;
91 unsafe {
92 core::ptr::copy_nonoverlapping(data.as_ptr(), data_ptr.add(w), first_chunk);
93 if second_chunk > 0 {
94 core::ptr::copy_nonoverlapping(
95 data.as_ptr().add(first_chunk),
96 data_ptr,
97 second_chunk,
98 );
99 }
100 }
101
102 let new_write = ((w + to_write) % c) as u32;
103 self.write_pos.store(new_write, Ordering::Release);
104
105 to_write
106 }
107
108 pub fn read(&self, output: &mut [u8]) -> usize {
113 let write = self.write_pos.load(Ordering::Acquire);
114 let read = self.read_pos.load(Ordering::Acquire);
115 let cap = self.capacity;
116
117 let used = if write >= read {
118 (write - read) as usize
119 } else {
120 (cap - read + write) as usize
121 };
122 let to_read = output.len().min(used);
123
124 if to_read == 0 {
125 return 0;
126 }
127
128 let r = read as usize;
129 let c = cap as usize;
130
131 let first_chunk = (c - r).min(to_read);
132 let second_chunk = to_read - first_chunk;
133
134 unsafe {
138 core::ptr::copy_nonoverlapping(
139 self.data.as_ptr().add(r),
140 output.as_mut_ptr(),
141 first_chunk,
142 );
143 if second_chunk > 0 {
144 core::ptr::copy_nonoverlapping(
145 self.data.as_ptr(),
146 output.as_mut_ptr().add(first_chunk),
147 second_chunk,
148 );
149 }
150 }
151
152 let new_read = ((r + to_read) % c) as u32;
153 self.read_pos.store(new_read, Ordering::Release);
154
155 to_read
156 }
157
158 pub fn available_read(&self) -> u32 {
160 let write = self.write_pos.load(Ordering::Acquire);
161 let read = self.read_pos.load(Ordering::Acquire);
162 let cap = self.capacity;
163
164 let used_bytes = if write >= read {
165 write - read
166 } else {
167 cap - read + write
168 };
169
170 if self.frame_size > 0 {
171 used_bytes / self.frame_size as u32
172 } else {
173 0
174 }
175 }
176
177 pub fn available_write(&self) -> u32 {
179 let write = self.write_pos.load(Ordering::Acquire);
180 let read = self.read_pos.load(Ordering::Acquire);
181 let cap = self.capacity;
182
183 let used_bytes = if write >= read {
184 write - read
185 } else {
186 cap - read + write
187 };
188 let available_bytes = cap - 1 - used_bytes;
189
190 if self.frame_size > 0 {
191 available_bytes / self.frame_size as u32
192 } else {
193 0
194 }
195 }
196
197 pub fn clear(&mut self) {
199 self.read_pos.store(0, Ordering::Release);
200 self.write_pos.store(0, Ordering::Release);
201 }
202
203 pub fn is_empty(&self) -> bool {
205 self.read_pos.load(Ordering::Acquire) == self.write_pos.load(Ordering::Acquire)
206 }
207
208 pub fn is_full(&self) -> bool {
210 let write = self.write_pos.load(Ordering::Acquire);
211 let read = self.read_pos.load(Ordering::Acquire);
212 let cap = self.capacity;
213 let used = if write >= read {
214 write - read
215 } else {
216 cap - read + write
217 };
218 used >= cap - 1
219 }
220}
221
222pub struct SharedAudioBuffer {
231 inner: spin::Mutex<AudioRingBuffer>,
233 config: AudioConfig,
235}
236
237impl SharedAudioBuffer {
238 pub fn new(capacity_frames: u32, config: AudioConfig) -> Self {
244 let frame_size = config.frame_size();
245 Self {
246 inner: spin::Mutex::new(AudioRingBuffer::new(capacity_frames, frame_size)),
247 config,
248 }
249 }
250
251 pub fn write_samples(&self, samples: &[i16]) -> usize {
256 let bytes: &[u8] = unsafe {
259 core::slice::from_raw_parts(samples.as_ptr() as *const u8, samples.len() * 2)
260 };
261 let ring = self.inner.lock();
262 let bytes_written = ring.write(bytes);
263 bytes_written / 2
264 }
265
266 pub fn read_samples(&self, output: &mut [i16]) -> usize {
271 let bytes: &mut [u8] = unsafe {
274 core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut u8, output.len() * 2)
275 };
276 let ring = self.inner.lock();
277 let bytes_read = ring.read(bytes);
278 bytes_read / 2
279 }
280
281 pub fn available_read_frames(&self) -> u32 {
283 self.inner.lock().available_read()
284 }
285
286 pub fn available_write_frames(&self) -> u32 {
288 self.inner.lock().available_write()
289 }
290
291 pub fn is_empty(&self) -> bool {
293 self.inner.lock().is_empty()
294 }
295
296 pub fn config(&self) -> &AudioConfig {
298 &self.config
299 }
300}
301
302#[cfg(test)]
307mod tests {
308 use super::*;
309 use crate::audio::SampleFormat;
310
311 fn test_config() -> AudioConfig {
312 AudioConfig {
313 sample_rate: 48000,
314 channels: 1,
315 format: SampleFormat::S16Le,
316 buffer_frames: 256,
317 }
318 }
319
320 #[test]
321 fn test_ring_buffer_write_read() {
322 let ring = AudioRingBuffer::new(64, 2);
323 let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
324
325 let written = ring.write(&data);
326 assert_eq!(written, 8);
327
328 let mut output = [0u8; 8];
329 let read = ring.read(&mut output);
330 assert_eq!(read, 8);
331 assert_eq!(output, data);
332 }
333
334 #[test]
335 fn test_ring_buffer_wrap_around() {
336 let ring = AudioRingBuffer::new(4, 1); let data1 = [10u8, 20, 30];
341 let written1 = ring.write(&data1);
342 assert_eq!(written1, 3);
343
344 let mut out1 = [0u8; 2];
346 let read1 = ring.read(&mut out1);
347 assert_eq!(read1, 2);
348 assert_eq!(out1, [10, 20]);
349
350 let data2 = [40u8, 50];
352 let written2 = ring.write(&data2);
353 assert_eq!(written2, 2);
354
355 let mut out2 = [0u8; 3];
357 let read2 = ring.read(&mut out2);
358 assert_eq!(read2, 3);
359 assert_eq!(out2, [30, 40, 50]);
360 }
361
362 #[test]
363 fn test_ring_buffer_overflow() {
364 let ring = AudioRingBuffer::new(4, 1); let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
368 let written = ring.write(&data);
369 assert_eq!(written, 3);
371
372 assert!(ring.is_full());
373 }
374
375 #[test]
376 fn test_ring_buffer_empty_read() {
377 let ring = AudioRingBuffer::new(32, 2);
378
379 assert!(ring.is_empty());
380
381 let mut output = [0u8; 16];
382 let read = ring.read(&mut output);
383 assert_eq!(read, 0);
384 }
385
386 #[test]
387 fn test_ring_buffer_available() {
388 let ring = AudioRingBuffer::new(8, 2); assert_eq!(ring.available_read(), 0);
391 assert_eq!(ring.available_write(), 7); let data = [0u8; 6]; ring.write(&data);
395
396 assert_eq!(ring.available_read(), 3);
397 assert_eq!(ring.available_write(), 4); }
399
400 #[test]
401 fn test_shared_buffer_samples() {
402 let config = test_config();
403 let buf = SharedAudioBuffer::new(64, config);
404
405 let samples = [100i16, 200, 300, 400];
406 let written = buf.write_samples(&samples);
407 assert_eq!(written, 4);
408
409 let mut output = [0i16; 4];
410 let read = buf.read_samples(&mut output);
411 assert_eq!(read, 4);
412 assert_eq!(output, samples);
413 }
414
415 #[test]
416 fn test_shared_buffer_partial_read() {
417 let config = test_config();
418 let buf = SharedAudioBuffer::new(64, config);
419
420 let samples = [10i16, 20, 30];
421 buf.write_samples(&samples);
422
423 let mut output = [0i16; 2];
425 let read = buf.read_samples(&mut output);
426 assert_eq!(read, 2);
427 assert_eq!(output, [10, 20]);
428
429 let mut output2 = [0i16; 4];
431 let read2 = buf.read_samples(&mut output2);
432 assert_eq!(read2, 1);
433 assert_eq!(output2[0], 30);
434 }
435
436 #[test]
437 fn test_shared_buffer_empty() {
438 let config = test_config();
439 let buf = SharedAudioBuffer::new(64, config);
440
441 assert!(buf.is_empty());
442 assert_eq!(buf.available_read_frames(), 0);
443 }
444}