diff --git a/src/audio.rs b/src/audio.rs index 1620d2b..8da7384 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -156,18 +156,16 @@ impl AudioSink { } fn process(&mut self, scope: &ProcessScope) -> Result<(), AudioError> { - let mut next_outbuf = match self.sample_src.try_recv() { - Ok(buf) => buf, - Err(tokio::sync::mpsc::error::TryRecvError::Empty) => return Ok(()), - Err(err) => return Err(err.into()) - }; - self.output_buf.append(&mut next_outbuf); + if let Ok(buf) = self.sample_src.try_recv() { + self.output_buf.extend(buf); + } if self.port.connected_count()? > 0 && !self.output_buf.is_empty() { let outbuf = self.port.as_mut_slice(scope); - let mut next_segment: Vec = self.output_buf.drain(0..(outbuf.len()).min(self.output_buf.len())).collect(); + let mut next_segment: Vec = self.output_buf.drain(..(outbuf.len()).min(self.output_buf.len())).collect(); let underrun = outbuf.len() - next_segment.len(); if underrun > 0 { + log::warn!("Audio stream underrun: {} samples", underrun); next_segment.extend(std::iter::repeat_n(0., underrun)); } diff --git a/src/sfx.rs b/src/sfx.rs index 84cc12c..ae888fe 100644 --- a/src/sfx.rs +++ b/src/sfx.rs @@ -41,13 +41,23 @@ pub async fn start_sfx(audio_sink: AudioOutStream) -> SfxControl { .probe(&hint, mss, fmt_opts, meta_opts) .expect("Unsupported audio format"); let track = format.default_track(TrackType::Audio).expect("No audio track"); + let track_id = track.id; let dec_opts = Default::default(); let mut decoder = symphonia::default::get_codecs() .make_audio_decoder( track.codec_params.as_ref().expect("codec params missing").audio().unwrap(), &dec_opts ).expect("Unsupported audio codec"); + + let sample_rate = decoder.codec_params().sample_rate.unwrap(); + let channel_num = decoder.codec_params().channels.as_ref().unwrap().count(); + log::debug!("Resampling {} -> {}", sample_rate, audio_sink.sample_rate); + // Our resampler works on a mono input + let mut bitrate_resample = resampler::ResamplerFir::new_from_hz(channel_num, sample_rate, audio_sink.sample_rate, Default::default(), Default::default()); + log::debug!("Starting stream"); + let mut audio_out_buf = vec![]; + let mut channel_bufs: Vec = vec![]; loop { let packet = match format.next_packet() { Ok(Some(packet)) => packet, @@ -55,19 +65,40 @@ pub async fn start_sfx(audio_sink: AudioOutStream) -> SfxControl { Err(err) => panic!() }; + if packet.track_id != track_id { + continue + } + match decoder.decode_ref(&packet.as_packet_ref()) { Ok(samples) => { - let mut channel_bufs: Vec = vec![]; - samples.copy_to_vec_interleaved(&mut channel_bufs); - let audio_out_buf: Vec = channel_bufs.windows(samples.byte_len_per_plane()).map(|channels| { + channel_bufs.resize(samples.samples_interleaved(), 0.); + samples.copy_to_slice_interleaved(&mut channel_bufs); + + let mut resampled = [0.; 2048]; + let (_, write_count) = bitrate_resample.resample(&channel_bufs, &mut resampled).unwrap(); + + // First we convert the audio feed from stereo down to mono by simple average + // TODO: This should be something smarter, like a saturating add..? + let mono_stream = resampled[..write_count].chunks(channel_num).map(|channels| { let total_volume = channels.iter().cloned().reduce(|a, b| a + b).unwrap_or_default(); - total_volume / (channels.len() as f32) - }).collect(); - audio_sink.sink.send(audio_out_buf).await.unwrap(); + total_volume / (channel_num as f32) + }); + + // Then we write out the resampled audio to our staging buffer + audio_out_buf.extend(mono_stream); + + // Once we have 1024 samples (jack default, I guess), we send it to the audio output + if audio_out_buf.len() >= 1024 { + audio_sink.sink.send(audio_out_buf).await.unwrap(); + audio_out_buf = vec![]; + } }, Err(err) => panic!() } } + if !audio_out_buf.is_empty() { + audio_sink.sink.send(audio_out_buf).await.unwrap(); + } log::debug!("Playback complete"); } }