extern crate sdl2; use sdl2::audio::{AudioCallback, AudioSpecDesired}; use sdl2::AudioSubsystem; use std::time::Duration; use std::sync::mpsc; use std::i16; const RECORDING_LENGTH_SECONDS: usize = 3; struct Recording { record_buffer: Vec, pos: usize, done_sender: mpsc::Sender>, done: bool, } // Append the input of the callback to the record_buffer. // When the record_buffer is full, send it to the main thread via done_sender. impl AudioCallback for Recording { type Channel = i16; fn callback(&mut self, input: &mut [i16]) { if self.done { return; } for x in input { self.record_buffer[self.pos] = *x; self.pos += 1; if self.pos >= self.record_buffer.len() { self.done = true; self.done_sender.send(self.record_buffer.clone()) .expect("could not send record buffer"); break; } } } } fn record(audio_subsystem: &AudioSubsystem, desired_spec: &AudioSpecDesired) -> Result, String> { println!("Capturing {:} seconds... Please rock!", RECORDING_LENGTH_SECONDS); let (done_sender, done_receiver) = mpsc::channel(); let capture_device = audio_subsystem.open_capture(None, desired_spec, |spec| { println!("Capture Spec = {:?}", spec); Recording { record_buffer: vec![0; spec.freq as usize * RECORDING_LENGTH_SECONDS * spec.channels as usize], pos: 0, done_sender, done: false } })?; println!("AudioDriver: {:?}", capture_device.subsystem().current_audio_driver()); capture_device.resume(); // Wait until the recording is done. let recorded_vec = done_receiver.recv().map_err(|e| e.to_string())?; capture_device.pause(); // Device is automatically closed when dropped. // Depending on your system it might be even important that the capture_device is dropped // before the playback starts. Ok(recorded_vec) } /// Returns a percent value fn calculate_average_volume(recorded_vec: &[i16]) -> f32 { let sum: i64 = recorded_vec.iter().map(|&x| (x as i64).abs()).sum(); (sum as f32) / (recorded_vec.len() as f32) / (i16::MAX as f32) * 100.0 } /// Returns a percent value fn calculate_max_volume(recorded_vec: &[i16]) -> f32 { let max: i64 = recorded_vec.iter().map(|&x| (x as i64).abs()).max() .expect("expected at least one value in recorded_vec"); (max as f32) / (i16::MAX as f32) * 100.0 } struct SoundPlayback { data: Vec, pos: usize, } impl AudioCallback for SoundPlayback { type Channel = i16; fn callback(&mut self, out: &mut [i16]) { for dst in out.iter_mut() { *dst = *self.data.get(self.pos).unwrap_or(&0); self.pos += 1; } } } fn replay_recorded_vec(audio_subsystem: &AudioSubsystem, desired_spec: &AudioSpecDesired, recorded_vec: Vec) -> Result<(), String> { println!("Playing..."); let playback_device = audio_subsystem.open_playback(None, desired_spec, |spec| { println!("Playback Spec = {:?}", spec); SoundPlayback { data: recorded_vec, pos: 0, } })?; // Start playback playback_device.resume(); std::thread::sleep(Duration::from_secs(RECORDING_LENGTH_SECONDS as u64)); // Device is automatically closed when dropped Ok(()) } fn main() -> Result<(), String> { let sdl_context = sdl2::init()?; let audio_subsystem = sdl_context.audio()?; let desired_spec = AudioSpecDesired { freq: None, channels: None, samples: None }; let recorded_vec = record(&audio_subsystem, &desired_spec)?; println!("Average Volume of your Recording = {:?}%", calculate_average_volume(&recorded_vec)); println!("Max Volume of your Recording = {:?}%", calculate_max_volume(&recorded_vec)); replay_recorded_vec(&audio_subsystem, &desired_spec, recorded_vec)?; Ok(()) }