Web Audio APIでsafariの自動再生ポリシーを回避する
かつての家系御三家の一角が、惜しまれつつも閉店するということで久しぶりに訪問。クラシカル家系の歴史ある味わいにしんみり
iOS safariで音声の自動再生ができない
ちょっと複数の音声ファイルを続けて再生させるWebアプリをNext.jsで作っていたのだが、iPhoneで音声が再生されない事象に遭遇。
Webのマルチメディア系を触っている人ならあるあるなのだが、自動再生ポリシーが効いてて、ユーザーのアクション(クリックなど)の後でないと音声が再生されない。
最初にボタンクリックしたあと音声ファイルを連続して再生させる作りにしていたのだが、2つ目以降もユーザーアクションがないと自動再生されないのだ。
Reactの音声再生コンポーネントの有名所のreact-audio-playerやreact-h5-audio-playerを使ってみたのだが、どちらもダメだった。
ならばWeb Audio APIだ
そこでWeb Audio APIを直接叩いてみることにした。
void axios.get(url, {responseType: 'arraybuffer'}).then(res => {
void audioContext?.decodeAudioData(res.data as ArrayBuffer).then(buffer => {
const source = audioContext?.createBufferSource();
source.buffer = buffer;
source.loop = false;
source.connect(audioContext.destination);
source.onended = () => {
// 再生終了時に次の曲を再生
};
source.start(0);
});
});
ポイントとしては、axios.get()のレスポンスタイプをarraybuffer
にすること。そうすることでレスポンスをaudioContext.decodeAudioData()
に渡すことができる。
と、再生部分のコードはできたのだが、Next.jsではAudioContext
のインスタンスを作れなくて2日ほど悩んだ。
インスタンスを作るにはSSRではできなくて(ブラウザじゃないからそれはそうだ)、結局ボタンのクリックイベントの中でnew AudioContext()
を呼ぶことで解決した。
しかもクリックインベント内なので、そこで作ったAudioContext
インスタンスは、当初の問題だった自動再生ポリシーの制約も受けないという棚ぼた的解決に至った。
React(Next.js)+WebAudioで簡単なオーディオプレイヤー+スペクトラムアナライザをつくる - Qiita
上記記事とか見ると、useEffect内でシングルトン的なAudioContext
インスタンスの作り方をしてるけど、まあ単純なSPAだし使い回さないからいいかなと。