use crate::{Received, Sent, adapter::AudioAdapter, frame::AudioFrame};
pub type AdapterAudioFrame<A, B> = AudioFrame<
<A as AudioAdapter>::SampleFormat,
<A as AudioAdapter>::ChannelLayout,
<A as AudioAdapter>::FrameExtra,
B,
>;
pub trait AudioResampler {
type Adapter: AudioAdapter;
type Buffer: AsRef<[u8]>;
type Error;
fn send_frame(
&mut self,
frame: &AdapterAudioFrame<Self::Adapter, Self::Buffer>,
) -> Result<Sent, Self::Error>;
fn receive_frame(
&mut self,
dst: &mut AdapterAudioFrame<Self::Adapter, Self::Buffer>,
) -> Result<Received, Self::Error>;
fn send_eof(&mut self) -> Result<Sent, Self::Error>;
fn flush(&mut self) -> Result<(), Self::Error>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::frame::AudioFrame;
struct ALoop;
impl AudioAdapter for ALoop {
type CodecId = u32;
type SampleFormat = u32;
type ChannelLayout = u32;
type PacketExtra = ();
type FrameExtra = ();
}
#[derive(Debug, PartialEq, Eq)]
enum LoopError {
SourceChanged,
AfterEof,
}
struct LoopResampler {
pending: bool,
eof: bool,
tail: u8,
}
impl LoopResampler {
const fn new() -> Self {
Self {
pending: false,
eof: false,
tail: 0,
}
}
}
impl AudioResampler for LoopResampler {
type Adapter = ALoop;
type Buffer = &'static [u8];
type Error = LoopError;
fn send_frame(
&mut self,
frame: &AudioFrame<u32, u32, (), &'static [u8]>,
) -> Result<Sent, LoopError> {
if self.eof {
return Err(LoopError::AfterEof);
}
if frame.sample_rate() != 48_000 {
return Err(LoopError::SourceChanged);
}
if self.pending {
return Ok(Sent::MustDrain);
}
self.pending = true;
self.tail = 1;
Ok(Sent::Accepted)
}
fn receive_frame(
&mut self,
_dst: &mut AudioFrame<u32, u32, (), &'static [u8]>,
) -> Result<Received, LoopError> {
if self.pending {
self.pending = false;
return Ok(Received::Frame);
}
if !self.eof {
return Ok(Received::NeedsInput);
}
if self.tail > 0 {
self.tail -= 1;
return Ok(Received::Frame);
}
Ok(Received::Ended)
}
fn send_eof(&mut self) -> Result<Sent, LoopError> {
self.eof = true;
Ok(Sent::Accepted)
}
fn flush(&mut self) -> Result<(), LoopError> {
self.pending = false;
self.eof = false;
self.tail = 0;
Ok(())
}
}
fn frame(rate: u32) -> AudioFrame<u32, u32, (), &'static [u8]> {
const EMPTY: &[u8] = &[];
AudioFrame::new(
rate,
1024,
2,
0,
0,
[crate::frame::Plane::new(EMPTY, 0); 8],
1,
(),
)
}
#[test]
fn the_face_is_implementable_and_signals_needs_more_in_the_ok_arm() {
fn _accepts<R: AudioResampler>() {}
_accepts::<LoopResampler>();
let mut r = LoopResampler::new();
let mut dst = frame(48_000);
assert_eq!(r.receive_frame(&mut dst), Ok(Received::NeedsInput));
assert_eq!(r.send_frame(&frame(48_000)), Ok(Sent::Accepted));
assert_eq!(r.receive_frame(&mut dst), Ok(Received::Frame));
assert_eq!(r.receive_frame(&mut dst), Ok(Received::NeedsInput));
}
#[test]
fn a_mid_stream_change_is_refused_by_name() {
let mut r = LoopResampler::new();
assert_eq!(r.send_frame(&frame(48_000)), Ok(Sent::Accepted));
assert_eq!(
r.send_frame(&frame(44_100)),
Err(LoopError::SourceChanged),
"the face never silently reconfigures",
);
}
#[test]
fn flush_drops_the_undrained_tail() {
let mut r = LoopResampler::new();
assert_eq!(r.send_frame(&frame(48_000)), Ok(Sent::Accepted));
r.flush().expect("flush");
let mut dst = frame(48_000);
assert_eq!(r.receive_frame(&mut dst), Ok(Received::NeedsInput));
}
#[test]
fn the_drained_tail_ends_instead_of_asking_for_input_that_cannot_come() {
let mut r = LoopResampler::new();
assert_eq!(r.send_frame(&frame(48_000)), Ok(Sent::Accepted));
assert_eq!(r.send_eof(), Ok(Sent::Accepted));
let mut dst = frame(48_000);
let mut frames = 0_u32;
let mut ended = false;
for _ in 0..64 {
match r
.receive_frame(&mut dst)
.expect("no fault in a clean drain")
{
Received::Frame => frames += 1,
Received::NeedsInput => panic!(
"a resampler that has been told the stream is over asked for input it \
can never get — the caller has nothing left to send, so this is the hang",
),
Received::Ended => {
ended = true;
break;
}
}
}
assert!(ended, "the drain never reached the end of the tail");
assert_eq!(frames, 2, "one queued frame plus the one-frame tail");
assert_eq!(r.receive_frame(&mut dst), Ok(Received::Ended));
}
}