😎

RustでWindows Runtimeを利用する

2023/02/28に公開

PC上で鳴っている音楽をタイマーで一定時間経過後に止めたい衝動に駆られたので、Rustで実装してみようと思い立ちました。
とりあえず、他のアプリ等で再生した音楽をどうにかしてRustで作ったプログラムから停止させる必要があります。
いろいろググったりChatGPTと熱い協議を重ねた結果、Windows Runtimeを利用するのがよさそうでした。

調べたこと

Rustで音声を扱うクレートには以下がありました。

cpalはローレベルなオーディオの入出力を扱うクレートで、rodioはそれを利用した音声再生用のクレートみたいです。cpalはクロスプラットフォームかつpure Rustなので利用したかったのですが、APIを一通り触ってみた結果、どうやら無理そうということが分かりました。オーディオデバイスの情報を取得したり、新規に音声を再生することはできそうなのですが、他のアプリで再生し音楽を止める方法がなさそうでした。

Windows Runtimeで音楽を止める

上記方法がだめだったので、Windows Runtime(WinRT)のAPIを叩くことにしました。
WinRTは幸いにも、Rustから簡単に実行する方法が公式で用意されています。
クレートとしてはwindowsという名前で公開されています。

Cargo.tomlに依存クレートとして書く際は、以下のようにします。
まず、今回使いたいのはGlobalSystemMediaTransportControlsSessionManager構造体なので、こちらのドキュメントを見ると、

Required features: "Media_Control"

という記載があります。これをwindows crateのfeatureとして記載することで、構造体を利用できるようになります。
具体的には、以下のように記載します。"Foundation"はこの後のコードで使うRequestAsync()メソッドで必要だったため付け足してます。

Cargo.toml
[dependencies.windows]
version = "0.44.0"
features = [
    "Foundation", 
    "Media_Control"
]

あとは、通常のcrateと同様にuseすればOKでした。(適当にunwrapしてますが目を瞑ってください……。)

main.rs
use windows::Media::Control::GlobalSystemMediaTransportControlsSessionManager;

fn main() {
    let manager = GlobalSystemMediaTransportControlsSessionManager::RequestAsync().unwrap();
    let session = manager.get().unwrap().GetCurrentSession().unwrap();

    session.TryPauseAsync();
    println!("stop");
}

上記を実行すると、音楽が停止します。

まとめ

RustからWinRTを比較的簡単に利用できることが分かりました。
次回はタイマーの機能を作ってみたいと思います。

Discussion