use std::collections::BTreeMap;
use std::error::Error;
use std::time::{Duration, Instant};
use pocketstation as pks;
fn main() -> Result<(), Box<dyn Error>> {
let session = pks::Session::builder()
.recording_root("pocketstation-recordings")
.build();
let app = session.capture(pks::Source::application(pks::ApplicationSelector::name(
"PocketStation Demo",
)))?;
let mic = session.capture(pks::Source::microphone_default())?;
let app_audio = session.polled_audio()?;
let mic_audio = session.polled_audio()?;
app.send(app_audio)?;
mic.send(mic_audio)?;
app.record("application")?;
mic.record("microphone")?;
let mut running = session.start()?;
let deadline = Instant::now() + Duration::from_secs(10);
let mut frames_by_stem = BTreeMap::<u64, usize>::new();
while Instant::now() < deadline
&& frames_by_stem.values().filter(|count| **count >= 2).count() < 2
{
if let Ok(batch) = running.try_poll_audio() {
for index in 0..batch.len() {
let frame = batch
.frame(index)
.ok_or("bounded audio batch returned an invalid frame index")?;
let count = frames_by_stem
.entry(frame.lineage().stem_id().get())
.or_default();
*count = count.saturating_add(1);
}
}
std::thread::sleep(Duration::from_millis(1));
}
if frames_by_stem.values().filter(|count| **count >= 2).count() != 2 {
return Err("application and microphone media were not both observed".into());
}
let outcome = running.stop();
if !outcome.is_success() {
return Err("PocketStation Session did not finalize cleanly".into());
}
let recording = running
.recording_outcome()
.ok_or("PocketStation Session did not expose a recording outcome")?;
if recording.state != pks::SessionRecordingState::Complete
|| recording.completed_stems != 2
|| recording.failed_stems != 0
{
return Err("PocketStation multistem recording did not complete".into());
}
Ok(())
}