use std::path::{Path, PathBuf};
use super::wav::wav_spec;
#[cfg(test)]
pub(in crate::audio) use recordings::spooled;
#[cfg(test)]
pub(crate) use recordings::{Pace, paced, recorded};
pub(crate) const FIXTURE_SAMPLES: usize = 16_000;
pub fn canonical_fixture(directory: &Path) -> PathBuf {
write_fixture(directory, wav_spec(), FIXTURE_SAMPLES)
}
pub fn fixture_of(directory: &Path, samples: usize) -> PathBuf {
write_fixture(directory, wav_spec(), samples)
}
pub(crate) fn write_fixture(directory: &Path, spec: hound::WavSpec, samples: usize) -> PathBuf {
let path = directory.join("fixture.wav");
let mut writer = hound::WavWriter::create(&path, spec).expect("fixture must be writable");
for index in 0..samples {
writer
.write_sample((index % 100) as i16)
.expect("fixture sample must be writable");
}
writer.finalize().expect("fixture must finalize");
path
}
#[cfg(test)]
mod recordings {
use std::sync::Mutex;
use std::time::Duration;
use super::super::recording::ends;
use super::super::spool::WavSpool;
use super::super::{CaptureError, RecordingReader, RecordingWriter};
pub(crate) fn recorded(samples: &[i16]) -> (tempfile::TempDir, RecordingReader) {
let directory = tempfile::TempDir::new().expect("test directory should be created");
let recording = RecordingReader::from_pcm16_in(directory.path(), samples)
.expect("samples are writable");
(directory, recording)
}
pub(crate) fn paced(batches: Vec<Vec<i16>>) -> (tempfile::TempDir, RecordingReader, Pace) {
let (directory, writer, mut spool, recording) = spooled();
let (advance, wait) = std::sync::mpsc::channel();
let (acknowledge, written) = std::sync::mpsc::channel();
advance.send(()).expect("the first permit is delivered");
std::thread::spawn(move || {
let count = batches.len();
for (index, batch) in batches.into_iter().enumerate() {
if wait.recv().is_err() {
break;
}
spool.write_samples(&batch).expect("samples are writable");
if index + 1 < count {
let _ = acknowledge.send(());
}
}
writer.close(spool.finish().map_err(CaptureError::from));
let _ = acknowledge.send(());
});
written.recv().expect("the first batch is written");
(
directory,
recording,
Pace {
advance,
written: Mutex::new(written),
},
)
}
pub(crate) struct Pace {
advance: std::sync::mpsc::Sender<()>,
written: Mutex<std::sync::mpsc::Receiver<()>>,
}
impl Pace {
pub(crate) fn advance(&self) {
if self.advance.send(()).is_ok() {
let _ = self.written.lock().expect("no poison").recv();
}
}
}
pub(in crate::audio) fn spooled() -> (
tempfile::TempDir,
RecordingWriter,
WavSpool,
RecordingReader,
) {
let directory = tempfile::TempDir::new().expect("test directory should be created");
let (recording, writer) = ends();
let spool = WavSpool::create(directory.path(), Duration::from_secs(15 * 60), &writer)
.expect("the recording should be creatable");
(directory, writer, spool, recording)
}
}