use alloc::vec::Vec;
use crate::{AudioBuffer, Result, TimestampMs};
#[must_use]
pub trait Fingerprinter {
type Output;
type Config: Clone + Send + Sync;
fn name(&self) -> &'static str;
fn config(&self) -> &Self::Config;
fn required_sample_rate(&self) -> u32;
fn min_samples(&self) -> usize;
fn extract(&mut self, audio: AudioBuffer<'_>) -> Result<Self::Output>;
}
#[must_use]
pub trait StreamingFingerprinter {
type Frame;
fn push(&mut self, samples: &[f32]) -> Vec<(TimestampMs, Self::Frame)>;
fn flush(&mut self) -> Vec<(TimestampMs, Self::Frame)>;
fn latency_ms(&self) -> u32;
fn push_with<F>(&mut self, samples: &[f32], mut callback: F) -> usize
where
F: FnMut(TimestampMs, &Self::Frame),
{
let frames = self.push(samples);
let n = frames.len();
for (t, frame) in frames {
callback(t, &frame);
}
n
}
fn flush_with<F>(&mut self, mut callback: F) -> usize
where
F: FnMut(TimestampMs, &Self::Frame),
{
let frames = self.flush();
let n = frames.len();
for (t, frame) in frames {
callback(t, &frame);
}
n
}
}
#[cfg(test)]
mod tests {
use alloc::vec;
use super::*;
struct CountByThree {
count: u32,
buffered: Vec<u32>,
}
impl CountByThree {
fn new() -> Self {
Self {
count: 0,
buffered: Vec::new(),
}
}
}
impl StreamingFingerprinter for CountByThree {
type Frame = u32;
fn push(&mut self, samples: &[f32]) -> Vec<(TimestampMs, u32)> {
let mut out = Vec::new();
for _ in samples {
self.count += 1;
if self.count % 3 == 0 {
out.push((TimestampMs(self.count as u64), self.count));
}
}
self.buffered.extend(out.iter().map(|(_, f)| *f));
out
}
fn flush(&mut self) -> Vec<(TimestampMs, u32)> {
let pending: Vec<u32> = self.buffered.drain(..).collect();
pending
.into_iter()
.map(|v| (TimestampMs(v as u64 + 100), v))
.collect()
}
fn latency_ms(&self) -> u32 {
0
}
}
#[test]
fn push_with_default_impl_matches_push() {
let samples = vec![0.0_f32; 10];
let mut fp = CountByThree::new();
let mut a: Vec<(TimestampMs, u32)> = Vec::new();
a.extend(fp.push(&samples));
a.extend(fp.push(&[]));
let mut fp = CountByThree::new();
let mut b: Vec<(TimestampMs, u32)> = Vec::new();
fp.push_with(&samples, |t, f| b.push((t, *f)));
fp.push_with(&[], |t, f| b.push((t, *f)));
assert_eq!(
a.len(),
b.len(),
"push_with must call back in the same order as push yields"
);
assert_eq!(a, b, "push_with must mirror push output exactly");
}
#[test]
fn flush_with_default_impl_matches_flush() {
let mut fp = CountByThree::new();
let samples = vec![0.0_f32; 9];
let _ = fp.push(&samples);
let pending: Vec<_> = fp.flush();
let mut fp = CountByThree::new();
let _ = fp.push(&samples);
let mut collected = Vec::new();
let n = fp.flush_with(|t, f| collected.push((t, *f)));
assert_eq!(n, pending.len());
assert_eq!(collected, pending, "flush_with must mirror flush");
}
#[test]
fn push_with_reports_emitted_count() {
let mut fp = CountByThree::new();
let n = fp.push_with(&[0.0_f32; 9], |_, _| {});
assert_eq!(n, 3);
let n = fp.push_with(&[0.0_f32; 2], |_, _| {});
assert_eq!(n, 0);
}
}