simple-peerを使ってボイスチャットをするwebアプリを作ってたらstream関連のWeb Audio APIで3時間くらい沼にはまってしまったので供養しようと思います。
問題提起
peer.on("stream", stream => {
const audioElement = document.querySelector("audio");
audioElement.srcObject = stream;
audioElement.play();
});
simple-peerのgithubに例示されているようにAudioElementのsrcObjectに直接streamを代入した場合はどのブラウザでも音が鳴るのですが、
let audioContext = new AudioContext();
peer.on("stream", stream => {
const audioElement = document.querySelector("audio");
const mediaStreamSource = audioContext.createMediaStreamSource(stream);
const destination = audioContext.createMediaStreamDestination();
mediaStreamSource.connect(destination);
audioElement.srcObject = destination.stream;
audioElement.play();
});
Web Audio APIを噛ませた場合、Safariなどでは音が鳴るのにも関わらずChromeでは音が鳴らなくなってしまいます。
原因
何年も前からあるChromeのバグ ( https://issues.chromium.org/issues/40094084 ) が原因のようで、elementのsourceになっていないstreamは音がならないようになってしまっているようです(多分)。
で、どうすればいいのよ?
適当なelementのsrcObjectに生のstreamを入れた後、別のelementにWeb Audio APIから出力したstreamを入れるとChromeでも鳴るようになります。
この時、未編集の音とWeb Audio APIで編集した音が2重で鳴ってしまうので生のstreamが入っているelementはmutedをtrueに設定しておきます。
let audioContext = new AudioContext();
peer.on("stream", stream => {
/* 適当なAudioElementのsrcObjectにstreamを直接入れる */
const fakeAudioElement = document.querySelector("audio"); /* new Audio()とかでも可 */
fakeAudioElement.srcObject = stream;
fakeAudioElement.muted = true;
fakeAudioElement.play();
/* 別のAudioElementにWeb Audio APIから出力したstreamを入れる */
const audioElement = new Audio();
const mediaStreamSource = audioContext.createMediaStreamSource(stream);
const destination = audioContext.createMediaStreamDestination();
// TODO: write Web Audio API processing here
mediaStreamSource.connect(destination);
audioElement.srcObject = destination.stream;
audioElement.play();
});
これで鳴るようになっている...はず!
参考文献
(最終閲覧日はともに2024/05/29)