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

フランソワ ボーフォール
François Beaufort

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

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

この機能は、リアルタイムのさまざまなコミュニケーション シナリオで特に役立ちます。たとえば、ウェブアプリはこれを使用して、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.
}

サンプル

https://sinkid.glitch.me/ で、AudioContext.setSinkId() を使ったデモをご覧いただけます。

ブラウザ サポート

AudioContext.setSinkId() は Chrome 110 以降でご利用いただけます。

フィードバック

Chrome チームとウェブ標準コミュニティは、AudioContext.setSinkId() の使用感についてご共有ください。既存の問題にコメントするか、新しい GitHub の問題を報告してフィードバックをお寄せください。

謝辞

この記事のレビューに協力してくれた Hongchan ChoiMichael Wilson に感謝します。

Steve Harvey 氏による Unsplash のカレンダー画像写真