🐛 bug: yep sure enough I wasn't flushing the resampler properly.
I feel like I've done this _exact_ project 3 times nowmain
							parent
							
								
									096b5aeb65
								
							
						
					
					
						commit
						336c94e39c
					
				|  | @ -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 <bool> { | ||||
| 		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); | ||||
| 			} | ||||
|  |  | |||
							
								
								
									
										97
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										97
									
								
								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); | ||||
| 	
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 _
						_