fix audio playback of 8Khz samples, further cut down on clones/copies

This commit is contained in:
2026-06-22 16:18:52 +02:00
parent 2d95d0c6aa
commit bcf37182fe
2 changed files with 42 additions and 13 deletions
+5 -7
View File
@@ -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<f32> = self.output_buf.drain(0..(outbuf.len()).min(self.output_buf.len())).collect();
let mut next_segment: Vec<f32> = 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));
}
+36 -5
View File
@@ -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<f32> = 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<f32> = vec![];
samples.copy_to_vec_interleaved(&mut channel_bufs);
let audio_out_buf: Vec<f32> = 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();
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");
}
}