Rust中rodio Sink在函数作用域变化时停止播放的问题
Rust rodio Sink 无声音问题排查与解决
你遇到的核心问题是rodio的音频播放是异步后台执行的。当new函数返回后,如果主线程没有等待播放完成就直接退出,整个进程会终止,负责音频播放的后台线程也会被强制停止,自然听不到声音。而添加sleep时,主线程处于阻塞状态,后台线程有足够时间完成播放,所以能听到声音。
虽然你在Player结构体中保留了OutputStream、OutputStreamHandle和Sink,避免了对象提前销毁的问题,但这只能保证资源不被提前释放,无法阻止主线程退出导致整个进程结束。
解决方案
方案一:给Player添加等待播放完成的方法
在Player结构体中封装等待逻辑,在合适的时机调用,让主线程等待音频播放结束:
use rodio::{OutputStream, OutputStreamHandle, Sink, Source, SineWave}; use std::time::Duration; pub struct Player { streamhandle: (OutputStream, OutputStreamHandle), sink: Sink, // playback: PlayBack, // 根据你的实际类型初始化 } impl Player { pub fn new() -> Player { let (stream, stream_handle) = OutputStream::try_default().unwrap(); let sink = Sink::try_new(&stream_handle).unwrap(); let source = SineWave::new(200.0) .take_duration(Duration::from_secs_f32(2.0)) .amplify(0.10); sink.append(source); Player { sink, streamhandle: (stream, stream_handle), // playback: PlayBack::new(), } } // 阻塞当前线程,直到所有音频播放完成 pub fn wait_until_end(&self) { self.sink.sleep_until_end(); } } // 调用示例 fn main() { let player = Player::new(); player.wait_until_end(); // 主线程等待音频播放完毕再退出 }
方案二:在new函数中直接等待播放完成(按需选择)
如果你的场景是创建Player后立即播放并等待结束,可以在new函数内部阻塞,直到播放完成再返回Player:
pub fn new() -> Player { let (stream, stream_handle) = OutputStream::try_default().unwrap(); let sink = Sink::try_new(&stream_handle).unwrap(); let source = SineWave::new(200.0) .take_duration(Duration::from_secs_f32(2.0)) .amplify(0.10); sink.append(source); // 等待播放完成后再返回Player sink.sleep_until_end(); Player { sink, streamhandle: (stream, stream_handle), // playback: PlayBack::new(), } }
说明
sink.sleep_until_end()会阻塞当前线程,直到Sink中的所有音频源播放完毕。- 如果你的播放器需要支持暂停、切换曲目等动态操作,优先选择方案一,在需要等待的时机调用
wait_until_end,避免阻塞Player的初始化流程。
内容的提问来源于stack exchange,提问作者KfK
相关产品推荐
相关产品推荐

