diff --git a/src/decoder.rs b/src/decoder.rs index c667aa1..53f5a0e 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -18,6 +18,13 @@ use ffmpeg_next::{ decoder::Audio as DecodeContext, format::context::Input as DemuxContext, software::resampling::Context as ResamplingContext, + util::{ + channel_layout::ChannelLayout, + format::sample::{ + self, + Sample, + }, + }, }; pub const SAMPLE_RATE: u32 = 48000; @@ -92,10 +99,8 @@ impl Decoder { let decoder = stream.codec ().decoder ().audio ()?; let resampler = decoder.resampler ( - ffmpeg_next::util::format::sample::Sample::F32 ( - ffmpeg_next::util::format::sample::Type::Packed, - ), - ffmpeg_next::util::channel_layout::ChannelLayout::STEREO, + Sample::F32 (sample::Type::Packed), + ChannelLayout::STEREO, 48000, )?; @@ -110,15 +115,18 @@ impl Decoder { pub fn fill_buffer (&mut self, pcm_buffers: &mut PcmBuffers) -> Result { match self.resampler.delay () { Some (x) if x.milliseconds > 500 => { - // tracing::trace! ("flushing resampler"); + // tracing::trace! ("flushing resampler ({} ms)", x.milliseconds); let mut frame_resampled = ffmpeg_next::util::frame::Audio::empty (); + frame_resampled.set_channel_layout (ChannelLayout::STEREO); + frame_resampled.set_format (Sample::F32 (sample::Type::Packed)); + frame_resampled.set_rate (48000); if self.resampler.flush (&mut frame_resampled).is_ok () { pcm_buffers.produce_bytes (frame_resampled.data (0)); return Ok (true); } else { - // tracing::warn! ("resampler flushed out a zero-length frame?"); + tracing::error! ("resampler flushed out a zero-length frame?"); } }, _ => {}, @@ -146,11 +154,10 @@ impl Decoder { //eprintln! ("Decoder ran out of work"); if self.resampler.delay ().is_some () { - tracing::trace! ("flushing resampler"); + tracing::trace! ("flushing resampler (out of compressed packets)"); let mut frame_resampled = ffmpeg_next::util::frame::Audio::empty (); if self.resampler.flush (&mut frame_resampled).is_ok () { - //eprintln! ("resampler.flush"); pcm_buffers.produce_bytes (frame_resampled.data (0)); return Ok (true); } diff --git a/src/main.rs b/src/main.rs index ad33717..01df327 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use std::{ use anyhow::{ anyhow, + bail, Result, }; @@ -24,19 +25,78 @@ use cpal::traits::{ mod decoder; fn main () -> Result <()> { - tracing_subscriber::fmt::init (); - tracing::error! ("frik"); - - let pair = Arc::new ((Mutex::new (decoder::SharedState::default ()), Condvar::new ())); - let pair2 = Arc::clone (&pair); - let pair3 = Arc::clone (&pair); - let args: Vec <_> = std::env::args ().collect (); + match args.get (1).map (|s| &s[..]) { + None => bail! ("First argument must be a subcommand like `play`"), + Some ("debug") => cmd_debug (&args [1..]), + Some ("play") => cmd_play (&args [1..]), + Some (_) => bail! ("Unrecognized subcommand"), + } +} + +fn cmd_debug (args: &[String]) -> Result <()> { + tracing_subscriber::fmt::init (); + let filename = args.get (1) .map (|s| s.to_string ()) .unwrap_or_else (|| "test-short.m4a".to_string ()); + let mut decoder = decoder::Decoder::new (&filename)?; + let mut pcm_buffers = decoder::PcmBuffers::default (); + + tracing::debug! ("Constructed decoder"); + + sleep (Duration::from_secs (3)); + + tracing::debug! ("Decoding..."); + + 'decoding: loop { + while pcm_buffers.samples_available () < 48_000 { + if ! decoder.fill_buffer (&mut pcm_buffers)? { + tracing::info! ("Decoder finished"); + break 'decoding; + } + } + + while pcm_buffers.samples_available () > 0 { + let mut buf = vec! [0.0f32; pcm_buffers.samples_available ()]; + pcm_buffers.consume_exact (&mut buf); + } + } + + sleep (Duration::from_secs (3)); + + tracing::debug! ("Dropping resampler..."); + dbg! (decoder.resampler.delay ()); + + drop (decoder.resampler); + sleep (Duration::from_secs (3)); + + tracing::debug! ("Dropping decoder..."); + + drop (decoder.decoder); + sleep (Duration::from_secs (3)); + + tracing::debug! ("Dropping input_ctx..."); + + drop (decoder.input_ctx); + sleep (Duration::from_secs (3)); + + Ok (()) +} + +fn cmd_play (args: &[String]) -> Result <()> { + tracing_subscriber::fmt::init (); + + let filename = args.get (1) + .map (|s| s.to_string ()) + .unwrap_or_else (|| "test-short.m4a".to_string ()); + + let pair = Arc::new ((Mutex::new (decoder::SharedState::default ()), Condvar::new ())); + let pair2 = Arc::clone (&pair); + let pair3 = Arc::clone (&pair); + let thread_decoder = thread::spawn (move|| { let (lock, cvar) = &*pair2; @@ -46,7 +106,7 @@ fn main () -> Result <()> { // tracing::trace! ("decode thread parking"); let mut decoder_state = cvar.wait_while (lock.lock ().unwrap (), |decoder_state| { - decoder_state.pcm_buffers.samples_available () >= 24_000 && + decoder_state.pcm_buffers.samples_available () >= 12_000 && ! decoder_state.quit }).unwrap (); @@ -58,30 +118,15 @@ fn main () -> Result <()> { let pcm_buffers = &mut decoder_state.pcm_buffers; - while pcm_buffers.samples_available () < 48_000 { + while pcm_buffers.samples_available () < 24_000 { // tracing::trace! ("Decoder is trying to work..."); if ! decoder.fill_buffer (pcm_buffers)? { tracing::info! ("Decoder thread is out of work, quitting"); - break; + break 'decoder_thread; } } } - tracing::debug! ("Dropping resampler..."); - - drop (decoder.resampler); - sleep (Duration::from_secs (3)); - - tracing::debug! ("Dropping decoder..."); - - drop (decoder.decoder); - sleep (Duration::from_secs (3)); - - tracing::debug! ("Dropping input_ctx..."); - - drop (decoder.input_ctx); - sleep (Duration::from_secs (3)); - Ok::<_, anyhow::Error> (()) }); @@ -96,8 +141,6 @@ fn main () -> Result <()> { .with_sample_rate (cpal::SampleRate (decoder::SAMPLE_RATE)) .config (); - dbg! (config.clone ()); - let pcm_quit = Arc::new ((Mutex::new (false), Condvar::new ())); let pcm_quit2 = Arc::clone (&pcm_quit);