♻️ refactor: extract DecoderThread and clean up identifiers
parent
f7c38d88de
commit
70e5182dfc
118
src/main.rs
118
src/main.rs
|
@ -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)]
|
||||
|
|
Loading…
Reference in New Issue