今日のラーメン:本牧家 本店(上永谷) 並+小ライス

かつての家系御三家の一角が、惜しまれつつも閉店するということで久しぶりに訪問。クラシカル家系の歴史ある味わいにしんみり


iOS safariで音声の自動再生ができない

ちょっと複数の音声ファイルを続けて再生させるWebアプリをNext.jsで作っていたのだが、iPhoneで音声が再生されない事象に遭遇。

Webのマルチメディア系を触っている人ならあるあるなのだが、自動再生ポリシーが効いてて、ユーザーのアクション(クリックなど)の後でないと音声が再生されない。

最初にボタンクリックしたあと音声ファイルを連続して再生させる作りにしていたのだが、2つ目以降もユーザーアクションがないと自動再生されないのだ。

Reactの音声再生コンポーネントの有名所のreact-audio-playerreact-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インスタンスは、当初の問題だった自動再生ポリシーの制約も受けないという棚ぼた的解決に至った。

failed to fetch remote resource: Forbidden

React(Next.js)+WebAudioで簡単なオーディオプレイヤー+スペクトラムアナライザをつくる - Qiita

趣味で音楽をつくっているのですが、それ用の特設サイトをNext.jsでつくったのにあわせてオーディオプレイヤー(スペクトラムアナライザ付き)をReact+WebAudioでつくってみました。実際の結果https://romot...

上記記事とか見ると、useEffect内でシングルトン的なAudioContextインスタンスの作り方をしてるけど、まあ単純なSPAだし使い回さないからいいかなと。