为何无法用单个源播放多首歌曲?Rodio播放问题求解
问题原因与修复方案
问题原因
直接拼接两个MP3文件的二进制数据,无法被rodio的Decoder正确识别为两首独立歌曲。MP3是带有特定头部信息的格式,每个文件的头部仅描述自身音频数据,拼接后的数据流没有统一标识告知解码器“此处为下一首歌的起始”,解码器解析完第一首歌的所有帧后,会判定流已结束,随即停止解码。
修复方案
针对本地文件示例的修复
无需拼接数据,分别解码每个文件并依次添加到sink中即可实现连续播放:
use std::{fs, io::Cursor}; fn main() { let (_stream, handle) = rodio::OutputStream::try_default().unwrap(); let sink = rodio::Sink::try_new(&handle).unwrap(); // 分别解码每首歌并添加到播放队列 let song1 = rodio::Decoder::new(Cursor::new(fs::read("guiro-sweep.mp3").unwrap())).unwrap(); sink.append(song1); let song2 = rodio::Decoder::new(Cursor::new(fs::read("on_the_moon.mp3").unwrap())).unwrap(); sink.append(song2); sink.sleep_until_end(); }
sink会自动按添加顺序播放音频源,第一首播放完毕后无缝切换到第二首。
针对客户端-服务器分块传输场景的修复
服务器需先发送歌曲数据的长度标识,客户端接收时先读取长度,再获取对应长度的完整歌曲数据,单独解码后添加到sink:
use std::{io::{self, Read}, net::TcpStream}; use rodio::{Decoder, OutputStream, Sink}; use std::io::Cursor; fn main() { let (_stream, handle) = OutputStream::try_default().unwrap(); let sink = Sink::try_new(&handle).unwrap(); let mut stream = TcpStream::connect("server_addr:port").unwrap(); let mut len_buffer = [0; 8]; // 用8字节存储歌曲数据长度(对应u64类型) loop { // 先读取歌曲数据长度 match stream.read_exact(&mut len_buffer) { Ok(_) => { let data_len = u64::from_be_bytes(len_buffer) as usize; let mut song_data = vec![0; data_len]; // 读取完整的单首歌数据 stream.read_exact(&mut song_data).unwrap(); // 解码并添加到播放队列 let decoder = Decoder::new(Cursor::new(song_data)).unwrap(); sink.append(decoder); } Err(e) => { eprintln!("接收失败: {}", e); break; } } } sink.sleep_until_end(); }
内容的提问来源于stack exchange,提问作者Andrii Hurman
相关产品推荐
相关产品推荐

