スマートフォン向けのページで音を鳴らす方法は、大きく分けて audio 要素と Web Audio API の 2 つです。どちらを使う場合も、自動再生の決まりや端末ごとの制限を知っておかないと、「パソコンでは鳴るのに、スマートフォンでは鳴らない」ということになります。ここでは、これまでの記事の内容を含めて、スマートフォンの Web で音を鳴らすときの要点をまとめます。

audio 要素と Web Audio API の使い分け

audio 要素Web Audio API
向いている音BGM、話し声、長い音声効果音、短い音の繰り返し
読み込み少しずつ読みながら再生できる全体を読み込んで展開してから鳴らす
重ねて鳴らす苦手 (要素を増やすと不安定)得意 (同じ音をいくつでも重ねられる)
タイミング多少ずれる細かく指定できる
再生ボタンなどの部品controls で用意される自分で作る

audio 要素は、ファイルを少しずつ読みながら再生できるので、長い音声に向いています。controls 属性を付ければ、再生ボタンやシークバーもブラウザーが用意してくれます。

Web Audio API は、音声データをメモリに展開しておき、JavaScript から鳴らす仕組みです。鳴らすまでの遅れが小さく、同じ音を重ねて鳴らしたり、start() に時刻を渡して鳴らすタイミングを細かく決めたりできます。ゲームの効果音や、リズムに合わせた音に向いています。

// 0.5 秒おきに 4 回、同じ音を鳴らす (context と buffer は用意してあるものとする)
const now = context.currentTime;
for (let i = 0; i < 4; i++) {
  const source = context.createBufferSource(); // 音源のノードは鳴らすたびに作る
  source.buffer = buffer;
  source.connect(context.destination);
  source.start(now + i * 0.5); // 鳴らす時刻を秒で指定する
}

ただし、音声データは展開すると元のファイルよりずっと大きくなります。長い音声を全部展開するとメモリを多く使うので、BGM は audio 要素に任せるのが無難です。

自動再生には利用者の操作が要る

今のスマートフォンのブラウザーでは、音の出る再生を、利用者の操作 (タップなど) 無しに始めることはできません。audio 要素の play() も、Web Audio API の AudioContext も、最初の操作の中で再生や resume() を呼ぶ必要があります。音を消した動画の自動再生は許されます。

play() は Promise を返すので、失敗したときに再生ボタンを見せるようにしておきます。どこまでが「操作に続く処理」と見なされるかは、「音声の再生は、利用者の操作の中で始める」で詳しく説明しています。

形式と配信

形式は、MP3 か AAC (.m4a) を用意しておけば、今の主なブラウザーで再生できます。容量を抑えたい場合は Opus などを先に、MP3 を最後にして、audio 要素の中に source 要素を並べます。対応の確かめ方は「Android のブラウザーで音声を再生する」にまとめました。

再生できない原因が、配信する側にあることもあります。プログラムを通して音声を返していると、範囲を指定した要求 (Range リクエスト) に答えられず、Safari で再生できないことがあります。「スマートフォンで音声を再生・シークできないときは、配信のしかたを疑う」を参照してください。

iOS の音量とマナーモード

iOS では、audio 要素の volume プロパティを変えられません。読み取るといつも 1 が返り、音量は端末の音量ボタンで利用者が決めます。ページの中で音量を調整したい場合は、Web Audio API の GainNode を通します。詳しくは「iPhone の Safari で音を鳴らすときの制限と対処」を参照してください。

マナーモード (消音の設定) にしているときに、ページの音が鳴るかどうかは、端末や OS の版、鳴らし方によって違います。audio 要素の音は鳴るのに、Web Audio API の音は鳴らない、といった違いが出ることもあります。音が鳴らないと操作の結果が分からない作りは避け、音と一緒に画面の表示でも結果を伝えるようにします。

かつては Flash で鳴らしていた

audio 要素がまだ広く使えなかったころ、パソコン向けのサイトでは、Flash (Adobe Flash Player で動く仕組み) で音を鳴らすのが一般的でした。ActionScript で効果音を重ねたり、再生の位置を細かく制御したりでき、ブラウザーの違いも気にせずに済んだからです。

しかし、iPhone の Safari は Flash に対応せず、Android でも Flash Player を使えたのは一部の時期・機種に限られました。スマートフォンで音を鳴らすには、audio 要素に頼るしかなかったのです。その後、Web Audio API が広まり、Flash でしていたことの多くはブラウザーだけでできるようになりました。Flash Player は 2020 年末にサポートが終わっていて、今は使えません。Flash で音を鳴らしていたページは、audio 要素や Web Audio API で作り直します。

まとめ

  • BGM や長い音声は audio 要素、効果音や重ねて鳴らす音は Web Audio API を使う
  • 音の出る再生は、利用者の操作の中で始める。play() の失敗を捕まえ、AudioContext は最初の操作で resume() する
  • 形式は MP3 か AAC を用意する。source 要素を並べれば、ブラウザーが再生できるものを選ぶ
  • iOS では volume を変えられない。音量の調整は GainNode で行う
  • マナーモードのときに鳴るかどうかは端末しだい。音だけに頼らず、画面でも結果を伝える
  • Flash はスマートフォンで使えず、2020 年末にサポートも終わった

参考