♻️ refactor: extract DecoderThread and clean up identifiers

main
_ 2021-11-13 19:45:16 +00:00
parent f7c38d88de
commit 70e5182dfc
1 changed files with 69 additions and 49 deletions

View File

@ -102,7 +102,7 @@ pub struct SharedState {
pub quit: bool,
}
fn cmd_gui (args: &[String]) -> Result <()> {
fn cmd_gui (_args: &[String]) -> Result <()> {
let (fltk_tx, fltk_rx) = app::channel::<Message> ();
let app = app::App::default ();
@ -151,59 +151,19 @@ fn cmd_play (args: &[String]) -> Result <()> {
.map (|s| s.to_string ())
.collect ();
let pair = Arc::new ((Mutex::new (SharedState::default ()), Condvar::new ()));
let pair2 = Arc::clone (&pair);
let pair3 = Arc::clone (&pair);
let thread_decoder = thread::spawn (move|| {
let (lock, cvar) = &*pair2;
'many_files: for filename in &filenames {
let mut decoder = decoder::Decoder::new (&filename)?;
'one_file: loop {
let frame = match decoder.next ()? {
Some (x) => x,
None => {
tracing::debug! ("Decoder thread finished a file");
break 'one_file;
},
};
let mut decoder_state = cvar.wait_while (lock.lock ().unwrap (), |decoder_state| {
decoder_state.pcm_buffers.samples_available () >= 12_000 &&
! decoder_state.quit
}).unwrap ();
if decoder_state.quit {
break 'many_files;
}
decoder_state.pcm_buffers.produce_bytes (frame.data ().into ());
}
}
Ok::<_, anyhow::Error> (())
});
let shared_state = Arc::new ((Mutex::new (SharedState::default ()), Condvar::new ()));
let pcm_quit = Arc::new ((Mutex::new (false), Condvar::new ()));
let pcm_quit2 = Arc::clone (&pcm_quit);
let audio_output = AudioOutput::new (pcm_quit, pair)?;
let thread_decoder = DecoderThread::new (Arc::clone (&shared_state), filenames);
let audio_output = AudioOutput::new (Arc::clone (&pcm_quit), Arc::clone (&shared_state))?;
tracing::debug! ("Joining decoder thread...");
if false {
let mut decoder_state = pair3.0.lock ().unwrap ();
decoder_state.quit = true;
pair3.1.notify_one ();
}
thread_decoder.join ().unwrap ()?;
thread_decoder.join ()?;
tracing::debug! ("Joining PCM thread...");
let (lock, cvar) = &*pcm_quit2;
let (lock, cvar) = &*pcm_quit;
let _ = cvar.wait (lock.lock ().unwrap ()).unwrap ();
drop (audio_output);
@ -214,6 +174,57 @@ fn cmd_play (args: &[String]) -> Result <()> {
Ok (())
}
struct DecoderThread {
join_handle: thread::JoinHandle <Result <()>>,
}
impl DecoderThread {
pub fn new (
shared_state: Arc <(Mutex <SharedState>, Condvar)>,
filenames: Vec <String>,
) -> Self
{
let join_handle = thread::spawn (move|| {
let (lock, cvar) = &*shared_state;
'many_files: for filename in &filenames {
let mut decoder = decoder::Decoder::new (&filename)?;
'one_file: loop {
let frame = match decoder.next ()? {
Some (x) => x,
None => {
tracing::debug! ("Decoder thread finished a file");
break 'one_file;
},
};
let mut decoder_state = cvar.wait_while (lock.lock ().unwrap (), |decoder_state| {
decoder_state.pcm_buffers.samples_available () >= 12_000 &&
! decoder_state.quit
}).unwrap ();
if decoder_state.quit {
break 'many_files;
}
decoder_state.pcm_buffers.produce_bytes (frame.data ().into ());
}
}
Ok::<_, anyhow::Error> (())
});
Self {
join_handle,
}
}
pub fn join (self) -> Result <()> {
self.join_handle.join ().unwrap ()
}
}
struct AudioOutput {
host: cpal::Host,
device: cpal::Device,
@ -223,8 +234,9 @@ struct AudioOutput {
impl AudioOutput {
pub fn new (
pcm_quit: Arc <(Mutex <bool>, Condvar)>,
pair: Arc <(Mutex <SharedState>, Condvar)>,
) -> Result <Self> {
shared_state: Arc <(Mutex <SharedState>, Condvar)>,
) -> Result <Self>
{
let host = cpal::default_host ();
let device = host.default_output_device ().ok_or_else (|| anyhow! ("can't open cpal device"))?;
@ -239,7 +251,7 @@ impl AudioOutput {
let stream = device.build_output_stream (
&config,
move |data: &mut [f32], _: &cpal::OutputCallbackInfo| {
let (lock, cvar) = &*pair;
let (lock, cvar) = &*shared_state;
let time_start = Instant::now ();
let mut decoder_state = match lock.lock () {
@ -281,6 +293,14 @@ impl AudioOutput {
stream,
})
}
pub fn play (&mut self) -> Result <()> {
Ok (self.stream.play ()?)
}
pub fn pause (&mut self) -> Result <()> {
Ok (self.stream.pause ()?)
}
}
#[cfg (test)]