先日のUGでもみんな気になってる感じがあり、個人的にも気になっており、現状をまとめておこうかと思い。
`setSinkId()`について
const devices = await navigator.mediaDevices.enumerateDevices(); const [{ deviceId }] = devices.filter(device => device.kind === 'audiooutput'); const $audio = document.createElement('audio'); await $audio.setSinkId(deviceId);
というように、`deviceId`を指定して、その要素の出力先を変えられるAPIがいちおう存在します。
入力を変えるのに`getUserMedia()`を使うので、その反対って感じ。
`enumerateDevices()`で、`kind`が`audiooutput`なものが返ってくるので、それを使う。
ちなみにこいつらはまとめて「Audio Output Devices API」といいます。
`HTMLMediaElement.prototype.setSinkId()`なので、`audio`でも`video`でも使える。
肝心のブラウザサポートは?
Safari
未実装。
macのSafariですら気配ないので、iOS Safariに来るのはいったいいつの日か・・・!
Chromeでしか動かない問題
幸か不幸かChromeでは実装されてるので、他のブラウザの利用者から「なんでできないの?」って言われる問題。
このAPIに限らず、ブラウザAPIではあるあるネタであり昔からずっとあるやつです。
これは機能をリリースする前に各ブラウザの互換性を調べるしかなくて、Polyfillもできないのであればすっぱり諦めるくらいがよいかなと思ってます。どうしようもないので。
まぁブラウザではなくOSの設定を変えればよいという話ではあるので、そこをUIでなんとかできなくも・・ない・・?
Bluetoothヘッドセット問題 その1
マイクだけ認識される問題。
たとえばFirefoxとかで、Bluetoothヘッドセットをつないだ状態で、`enumerateDevices()`する。
すると、`audioinput`にそれが現れるので、`getUserMedia()`で利用ちゃう、みたいなケース。
- 入力: ヘッドセット
- 出力: 本体スピーカー
というちぐはぐな状態になってしまう。
対策としてはやはり、
- 手動でOS側の出力先を変える
- もう外部デバイス切り替えをUIで実装しない
- 内部デバイスは`gUM()`前に取れるやつなのでそれだけ使う
このへんは要件次第ってやつよね・・。
Bluetoothヘッドセット問題 その2
たとえばiOSのSafariだと、Bluetoothヘッドセットをつないでも、`enumerateDevices()`で出てこない。
`audiooutput`だけでなく、`audioinput`にも出てこない。
ただヘッドセットが認識されると、自動的にマイクもスピーカーも切り替わるはず。
そこが上手くいかない場合は、またしてもOSの設定を見直すしかない。
iOSなら、
- 設定 > 一般 > アクセシビリティ > 通話オーディオルーティング
- 自動 / Bluetoothヘッドセット / スピーカー
これを自動にしておくだけでよいはず。
まとめ
そういう意味では、
- 外部デバイスの切り替えはOSの設定でやるようにしてしまう
- UIで実装しない
のが、もしかして一番キレイな解決策やったりするんかな・・・とか最近は思ってます。
あとはWebを捨ててNativeでやるとか?(そういうAPIたぶんあると思うので)
Web屋は実装されるのをひたすら待つ。