use crate::input::{AudioStream, Input, LiveInput};
use byteorder::{LittleEndian, WriteBytesExt};
use std::io::{ErrorKind as IoErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write};
use symphonia::core::io::MediaSource;
const FMT_HEADER: &[u8; 16] = b"SbirdRaw\0\0\0\0\0\0\0\0";
pub struct RawAdapter<A> {
prepend: [u8; 16],
inner: A,
pos: u64,
}
impl<A: MediaSource> RawAdapter<A> {
pub fn new(audio_source: A, sample_rate: u32, channel_count: u32) -> Self {
let mut prepend: [u8; 16] = *FMT_HEADER;
let mut write_space = &mut prepend[8..];
write_space
.write_u32::<LittleEndian>(sample_rate)
.expect("Prepend buffer is sized to include enough space for sample rate.");
write_space
.write_u32::<LittleEndian>(channel_count)
.expect("Prepend buffer is sized to include enough space for number of channels.");
Self {
prepend,
inner: audio_source,
pos: 0,
}
}
}
impl<A: MediaSource> Read for RawAdapter<A> {
fn read(&mut self, mut buf: &mut [u8]) -> IoResult<usize> {
let out = if self.pos < self.prepend.len() as u64 {
let upos = self.pos as usize;
let remaining = self.prepend.len() - upos;
let to_write = buf.len().min(remaining);
buf.write(&self.prepend[upos..][..to_write])
} else {
self.inner.read(buf)
};
if let Ok(n) = out {
self.pos += n as u64;
}
out
}
}
impl<A: MediaSource> Seek for RawAdapter<A> {
fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
if self.is_seekable() {
let target_pos = match pos {
SeekFrom::Start(p) => p,
SeekFrom::End(_) => return Err(IoErrorKind::Unsupported.into()),
SeekFrom::Current(p) if p.unsigned_abs() > self.pos =>
return Err(IoErrorKind::InvalidInput.into()),
SeekFrom::Current(p) => (self.pos as i64 + p) as u64,
};
let out = if target_pos as usize <= self.prepend.len() {
self.inner.rewind().map(|()| 0)
} else {
self.inner.seek(SeekFrom::Start(target_pos))
};
match out {
Ok(0) => self.pos = target_pos,
Ok(a) => self.pos = a + self.prepend.len() as u64,
_ => {},
}
out.map(|_| self.pos)
} else {
Err(IoErrorKind::Unsupported.into())
}
}
}
impl<A: MediaSource> MediaSource for RawAdapter<A> {
fn is_seekable(&self) -> bool {
self.inner.is_seekable()
}
fn byte_len(&self) -> Option<u64> {
self.inner.byte_len().map(|m| m + self.prepend.len() as u64)
}
}
impl<A: MediaSource + Send + Sync + 'static> From<RawAdapter<A>> for Input {
fn from(val: RawAdapter<A>) -> Self {
let live = LiveInput::Raw(AudioStream {
input: Box::new(val),
});
Input::Live(live, None)
}
}