ウェブ オーディオで出力先デバイスを変更する

François Beaufort
François Beaufort

これまで、出力音声出力デバイスの設定は、HTMLMediaElement.setSinkId() を使用して <video><audio> でのみ可能でした。Web Audio では、AudioContext はデフォルト デバイスを使用しており、ユーザーがシステム オーディオ出力デバイスを手動で変更する必要がありました。

Chrome 110 以降では、AudioContext.setSinkId() を使用して、許可された任意のデバイスに Web Audio のオーディオ出力をプログラムで転送できます。

これは、さまざまなリアルタイム コミュニケーション シナリオで特に役立ちます。たとえば、ウェブアプリでは、これを使用して、Bluetooth ヘッドセットやスピーカーフォンなどの特定のオーディオ出力デバイスに出力をプログラムで転送できます。

オーディオ出力を特定のデバイスに転送する

まず、宛先として使用するオーディオ出力デバイスの ID が必要です。navigator.mediaDevices.enumerateDevices() を使用して利用可能なメディア デバイスのリストを取得し、オーディオ出力デバイスのみをフィルタして、選択したオーディオ出力デバイスの deviceId 属性を取得します。空の文字列 "" 値は、deviceId のデフォルト デバイスとして使用することもできます。

オーディオ出力デバイスの ID を取得したら、AudioContext を作成し、audioContext.setSinkId(deviceId) を呼び出します。成功すると、選択した接続済み出力デバイスに音声がルーティングされると、返された Promise が解決します。AudioContext が閉じられている場合は失敗することがあります。

次の例は、必要に応じてマイクへのアクセスをリクエストし、Web Audio の音声出力を利用可能な最初の出力デバイスに転送する方法を示しています。

const permission = await navigator.permissions.query({ name: "microphone" });
if (permission.state == "prompt") {
  // More audio outputs are available when user grants access to the mic.
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
  stream.getTracks().forEach((track) => track.stop());
}

// Request a list of media devices and filter audio output devices.
const devices = await navigator.mediaDevices.enumerateDevices();
const audioOutputs = devices.filter(device => device.kind == "audiooutput");

const audioContext = new AudioContext();

// Pick the first available audio output.
const deviceId = audioOutputs[0].deviceId;
await audioContext.setSinkId(deviceId);

AudioContext を作成するときに、deviceIdsinkId パラメータとして渡すこともできます。

const audioContext = new AudioContext({ sinkId: deviceId });

ミュートされた AudioContext で音声をレンダリングする

Web Audio で「サイレント出力デバイス」を指定できるようになりました。これにより、消費電力を最小限に抑えることができます。今回は、文字列値ではなく { type: "none" }AudioContext.setSinkId() に渡します。

audioContext.currentTime でアクセスできるオーディオ クロックは、オーディオグラフをレンダリングするために引き続き進みます。このミュートされた AudioContext の主な目的は、可聴音を生成せずにオーディオグラフをレンダリングすることです。主なユースケースは、音声を出さずにマイク入力を分析することです。

// Silent Web Audio output.
await audioContext.setSinkId({ type: "none" });

特徴検出

AudioContext.setSinkId() がサポートされているかどうかを確認するには、次のコマンドを使用します。

if ("setSinkId" in AudioContext.prototype) {
  // AudioContext.setSinkId() is supported.
}

サンプル

AudioContext.setSinkId() を試すためのデモは https://sinkid.glitch.me/ で利用できます。

ブラウザ サポート

AudioContext.setSinkId() は Chrome 110 以降で利用できます。

フィードバック

Chrome チームとウェブ標準コミュニティでは、AudioContext.setSinkId() に関するご意見をお待ちしております。フィードバックをお送りいただくには、既存の GitHub Issues にコメントするか、新しい Issues を作成してください。

謝辞

この記事のレビューをしてくれた Hongchan Choi 氏と Michael Wilson 氏に感謝します。

カレンダーの画像は、UnsplashSteve Harvey によるものです。