久しぶりに Web Audio API を使ったコードを書いていたら、音を読み込んで再生するだけの簡単なサンプルコードでも音が鳴らないという現象に遭遇しました。
class AudioPlayer { constructor() { this.isPlaying = false; } init = () => { window.AudioContext = window.AudioContext || window.webkitAudioContext; this.context = new AudioContext(); } setBuffer = async () => { const response = await fetch("audio/sample.wav"); const arrayBuffer = await response.arrayBuffer(); this.sampleSource.buffer = await this.context.decodeAudioData(arrayBuffer); } play = () => { if (this.isPlaying){ this.sampleSource?.stop(); } this.sampleSource = this.context.createBufferSource(); this.setBuffer(); this.sampleSource.connect(this.context.destination); this.sampleSource.start(); this.isPlaying = true; } stop = () => { this.sampleSource?.stop(); this.isPlaying = false; } } audioPlayer = new AudioPlayer(); audioPlayer.init() document.querySelector("#play").addEventListener("click", audioPlayer.play); document.querySelector("#stop").addEventListener("click", audioPlayer.stop);
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> </head> <body> <button id="play">play</button> <button id="stop">stop</button> </body> <script src="js/audio.js"></script> </html>
ブラウザを変えて検証したところ、Chromeでのみ音が鳴りませんでした。
そこでChromeでF12を押して開発者ツールを立ち上げたところ、以下のようなWarningが表示されていました。
audio.js:17 The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page. https://goo.gl/7K7WLu
Autoplay policy in Chrome - Chrome Developers
や以下の記事によると、Chrome 71 以降は自動再生に制限があり、ユーザー操作で new AudioContext()
を作成する必要があるようです。
Autoplay policy in Chrome - Chrome Developers では、ユーザー操作をボタンクリックとした場合での対処法を2つ紹介しています。
(1) window.onload
でコンテキストを準備し、ボタンクリック時にresume()
で再開する
// Existing code unchanged. window.onload = function() { var context = new AudioContext(); // Setup all nodes // ... } // One-liner to resume playback when user interacted with the page. document.querySelector('button').addEventListener('click', function() { context.resume().then(() => { console.log('Playback resumed successfully'); }); });
(2) ボタンクリック時にコンテキストを生成する
document.querySelector('button').addEventListener('click', function() { var context = new AudioContext(); // Setup all nodes // ... });
試しに (2) の方法に基づいて、掲載したコードの後半を以下のように変更すると無事Chromeでも音が鳴りました。
//... audioPlayer = new AudioPlayer(); document.querySelector('button').addEventListener('click', audioPlayer.init); document.querySelector("#play").addEventListener("click", audioPlayer.play); document.querySelector("#stop").addEventListener("click", audioPlayer.stop);