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

François Beaufort
François Beaufort

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

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

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

特定のデバイスに音声出力をルーティングする

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

オーディオ出力デバイスの識別子を取得したら、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 の作成時に sinkId パラメータとして deviceId を渡すこともできます。

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://codepen.io/web-dot-dev/pen/emNwEaN/ でご覧いただけます。

ブラウザ サポート

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

フィードバック

Chrome チームとウェブ標準コミュニティは、AudioContext.setSinkId() の使用感について皆様のご意見をお待ちしています。フィードバックは、既存の GitHub の問題にコメントするか、新しい問題を提出して提供してください。

謝辞

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

カレンダーの画像: Steve HarveyUnsplash