You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Rust中实现多个MP3文件的无缝播放?

问题:Rodio顺序播放MP3文件出现间隙

我从SoundCloud下载了一些MP3文件,希望按顺序播放它们,但使用Rodio库尝试时,音频之间总会出现微小的间隙。

使用的代码

use cpal::{traits::HostTrait, SampleRate, SupportedStreamConfig};
use rodio::{Decoder, Source};
use std::{fs::File, u64};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let default_device = cpal::default_host()
        .default_output_device()
        .ok_or("No default audio output device is found.")?;
    let (_stream, stream_handle) = rodio::OutputStream::try_from_device_config(&default_device, 
        SupportedStreamConfig::new(1, SampleRate(44100), cpal::SupportedBufferSize::Range { min: 5000, max: 35000 }, cpal::SampleFormat::U64)
    )?;
    let sink = rodio::Sink::try_new(&stream_handle).unwrap();
    let data1 = Decoder::new(File::open("1.mp3").unwrap()).unwrap().buffered();
    let data2 = Decoder::new(File::open("2.mp3").unwrap()).unwrap().buffered();
    let data3 = Decoder::new(File::open("3.mp3").unwrap()).unwrap().buffered();
    sink.append(data1);
    sink.append(data2);
    sink.append(data3);
    
    
    std::thread::sleep(std::time::Duration::from_secs(u64::MAX));
    Ok(())
}

依赖配置

rodio = {version="0.17",features=["symphonia-all"]}

我曾尝试使用minimp3后端,还试过Kira库,但由于不知道如何顺序播放文件,效果更差。请问该如何解决这个问题?


解决方案

1. 使用设备默认流配置而非硬编码

你手动创建的SupportedStreamConfig可能和设备实际支持的参数不匹配,引发缓冲异常。应该优先获取设备的默认配置:

let default_config = default_device.default_output_config()?;
let (_stream, stream_handle) = rodio::OutputStream::try_from_device_config(&default_device, &default_config.into())?;

2. 预解码合并音频源

间隙的核心原因是Rodio切换音频源时,需要时间初始化新文件的解码流程。可以提前将所有音频解码为统一格式,合并成单个连续的Source:

use rodio::{Decoder, Source, OutputStream, Sink};
use std::{fs::File, io::BufReader};

fn load_audio(path: &str) -> impl Source<Item = f32> {
    let file = BufReader::new(File::open(path).unwrap());
    Decoder::new(file).unwrap()
        .convert_samples() // 统一转换为f32样本格式
        .buffered(1024 * 64) // 增大预缓冲容量
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let (_stream, stream_handle) = OutputStream::try_default()?;
    let sink = Sink::try_new(&stream_handle)?;

    // 合并所有音频源为连续流
    let combined_source = load_audio("1.mp3")
        .chain(load_audio("2.mp3"))
        .chain(load_audio("3.mp3"));

    sink.append(combined_source);
    sink.sleep_until_end(); // 等待播放完成,替代无限sleep

    Ok(())
}

3. Kira顺序播放实现

如果想尝试Kira,可以通过播放回调实现无缝顺序播放:

use kira::{
    manager::{AudioManager, AudioManagerSettings, backend::cpal::CpalBackend},
    sound::SoundSettings,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut manager = AudioManager::<CpalBackend>::new(AudioManagerSettings::default())?;

    // 链式回调实现顺序播放
    let sound1 = manager.load_sound("1.mp3", SoundSettings::default())?;
    manager.play(sound1, |_| {
        let sound2 = manager.load_sound("2.mp3", SoundSettings::default()).unwrap();
        manager.play(sound2, |_| {
            let sound3 = manager.load_sound("3.mp3", SoundSettings::default()).unwrap();
            manager.play(sound3, |_| {}).unwrap();
        }).unwrap();
    })?;

    loop {
        manager.update()?;
        std::thread::sleep(std::time::Duration::from_millis(10));
    }
}

内容的提问来源于stack exchange,提问作者Bence

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 17:03:15