denny-jack/src/circular_buffer_source.rs

73 lines
1.8 KiB
Rust

use circular_buffer::CircularBuffer;
use songbird::input::core::io::MediaSource;
use std::io::SeekFrom;
use std::{
io::{Read, Seek, Write},
sync::{Arc, Condvar, Mutex},
};
const BUFFER_SIZE: usize = 64 * 1024;
#[derive(Clone, Default)]
pub struct CircularBufferSource {
condvar: Arc<Condvar>,
circular_buffer: Arc<Mutex<CircularBuffer<BUFFER_SIZE, u8>>>,
}
impl Read for CircularBufferSource {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let mut circ_buffer = self.circular_buffer.lock().expect("Mutex was poisoned");
if circ_buffer.is_empty() {
buf.fill(0);
self.condvar.notify_all();
return Ok(buf.len());
}
let bytes_to_read = usize::min(buf.len(), circ_buffer.len());
for (ndx, value) in circ_buffer.drain(0..bytes_to_read).enumerate() {
buf[ndx] = value;
}
self.condvar.notify_all();
Ok(bytes_to_read)
}
}
impl Write for CircularBufferSource {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let mut circ_buffer = self.circular_buffer.lock().expect("Mutex was poisoned");
while circ_buffer.len() + buf.len() > BUFFER_SIZE {
circ_buffer = self.condvar.wait(circ_buffer).expect("Mutex was poisoned");
}
circ_buffer.extend_from_slice(buf);
self.condvar.notify_all();
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl Seek for CircularBufferSource {
fn seek(&mut self, _pos: SeekFrom) -> std::io::Result<u64> {
Err(std::io::ErrorKind::Unsupported.into())
}
}
impl MediaSource for CircularBufferSource {
fn is_seekable(&self) -> bool {
false
}
fn byte_len(&self) -> Option<u64> {
None
}
}