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
+37 -6
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();
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");
}
}