Stories

Detail Return Return

【Rust GUI開發入門】編寫一個本地音樂播放器(2. Rodio播放庫的使用) - Stories Detail

本系列教程對應的代碼已開源在 Github zeedle

添加依賴

在Cargo.toml添加:

[dependencies]
rodio = "0.21.1"

添加/播放/暫停音頻

use std::{thread, time::Duration};

use rodio::Decoder;
fn main() {
    // create an output stream
    let stream_handle = rodio::OutputStreamBuilder::from_default_device()
        .expect("no output device available")
        .open_stream()
        .expect("failed to open output stream");
    // create a sink to play audio
    let sink = rodio::Sink::connect_new(&stream_handle.mixer());
    // open an audio file
    let file = std::fs::File::open("audios/愛情轉移.flac").expect("failed to open audio file");
    // decode the audio file
    let source = Decoder::try_from(file).expect("failed to decode audio file");
    // append the audio source to the sink & auto play
    sink.append(source);
    // sleep for a while to let the audio play
    thread::sleep(Duration::from_secs(20));
    // pause the audio playback explicitly
    sink.pause();
    // sleep for a while
    thread::sleep(Duration::from_secs(20));
    // resume the audio playback explicitly
    sink.play();
    // keep the main thread alive while the audio is playing
    thread::sleep(Duration::from_secs(20));
}

代碼及主要API解讀

  • stream_handle 是音頻流句柄,直接跟硬件相關
  • rodio::Sink::connect_new 連接到音頻流,返回一個Sink對象,是輸出到stream_handle對應device的“音頻管理器”
  • Decoder::try_from(file) 嘗試解碼音頻文件
  • sink.append 向音頻管理器中添加source並立刻自動啓動播放
  • sink.pause 顯式停止音頻播放
  • sink.play 顯式恢復音頻播放
  • sink.clear 清除sink中存儲的所有source,釋放資源(這裏並未用到)

注意

執行上述代碼,會:

  1. 播放20秒音頻
  2. 停止20秒
  3. 再播放20秒音頻
  4. 程序退出

如果sink.append之後沒有thread::sleep,程序會立刻結束,任何聲音都不會被播放,這是因為,根據Rust變量的生命週期,stream_handle變量會在main函數右括號}處立刻釋放,由於stream_handle管理了計算機音頻輸出設備硬件資源,當它超出生命週期被釋放時,與之關聯的任何音頻播放(也就是sink中存在的所有source)都會被強制停止,這是Rodio庫為了保護硬件資源做出的一個設計,大大減小了硬件不可控事件的出現。

還有一些額外的事情需要注意:

  • stream_handle直接持有了硬件資源,因此它不是線程安全的,無法在線程之間安全傳遞
  • sink藉助stream_handle操控音頻播放,因此stream_handle的生命週期一定長於sink
  • sink是線程安全的,可以在線程之間安全傳遞,後面製作音樂播放器時會大量用到這個特性,它能同時存在於UI線程與後台線程中,只要確保stream_handle的生命週期長於sink

Add a new Comments

Some HTML is okay.