iOSでaudioタグの音声が再生されない時の対処法

プログラミング

キーボード入力をトリガーにして音声が再生されるアプリケーションを作成していたところ、MacPCでは音声が再生されるのに、iPadやiPhoneでは音声が再生されないという事象に遭遇したので、その時に行った対処法をご紹介します。

スポンサーリンク

PCでは音声再生できるのに、iPadでは再生されない

今回作成したアプリケーションの仕様は、こんな感じ。

  • キーボードから入力された情報を受け取る
  • 受け取った入力情報の内容によって、異なる音声が再生される
  • 音声の長さは、それぞれ1秒程度
  • 入力情報を受け取った後に実行される音声再生の処理は、非同期で実行される

キーボードから何かしらの情報を入力すれば音が鳴るはずなのですが、PCでは音が鳴るのに、iPadでは何度試しても音が鳴りません。

ソースコードはこんな感じ。

<audio preload="auto" id="audio1">
  <source src="audio/audio1.mp3">
</audio>
<audio preload="auto" id="audio2">
  <source src="audio/audio2.mp3">
</audio>
<audio preload="auto" id="audio3">
  <source src="audio/audio3.mp3">
</audio>
function selectSounds(input){
  if (input === 1){
    promise = sound1();
  }else if(input === 2){
    promise = sound2();
  }else if(input === 3){
    promise = sound3();
  }
  promise.then(
    ・・・省略・・・
  );
}

function sound1(){
  document.getElementById('audio1').play();
}
function sound2(){
  document.getElementById('audio2').play();
}
function sound3(){
  document.getElementById('audio3').play();
}

iOS端末ではaudioタグの音声が自動再生できない

スマホやタブレットで音声が自動再生できない理由

調べてみたところ、iPhoneやiPadなどのiOS端末では音声や動画の自動再生を行うことができないことがわかりました。

この仕組みは、ユーザーの意思とは関係なく動画や音声を再生し、勝手にデータ量を消費する事を防ぐ為のもののようです。

スマホで動画再生をするとたくさんのデータ量を消費するので、Wi-Fi環境でない場合は勝手に再生されてしまうと困っちゃいますよね?

メディアおよびウェブ音声 API の自動再生ガイド - ウェブメディア技術 | MDN
ページが読み込まれるとすぐに音声(または音声トラックを含む動画)の再生を自動的に開始することは、ユーザーにとって歓迎されない驚きです。 メディアの自動再生は便利な目的に役立ちますが、注意して必要なときにだけ使用してください。 ユーザーがこれを制御できるようにするために、ブラウザーは多くの場合、さまざまな形式の自動再生の...

音声を再生させたいのであれば、ユーザ自身にタッチやクリックなどのアクションを行わせる必要があるとのこと。

今回作成したアプリケーションは、音声を自動再生するものではないのですが、どうやら非同期処理で音声を再生しようとすると、ユーザ自身のアクションによる操作ではないと判定されてダメなようです。

タッチやクリックではなく、キーボード入力だったことも原因なのかもしれません。

音声ファイルがロードされているか調べてみた

音声再生について調べていたところ、load()を使って事前に音声ファイルをロードできることがわかりました。

もしかしたら、play()が実行された時に音声ファイルがロードされておらず、そのせいでplay()を実行しても音声が再生されないのかな…。

そう思った私はreadyStateからロード状態を判断してみましたが、値は4(HAVE_ENOUGH_DATA)で、ロード済み・再生可能な状態でした。

function sound1(){
  let sound = document.getElementById('audio1');
  if ( sound.readyState < 4 ) {
    console.log('ロードされていないのでロードします。readyState:' + sound.readyState);
    sound.load();
  }
  sound.play();
}

再生したいファイルが複数ある場合の対処法

モーダルをタッチさせて音声を再生させるようにした

音声ファイルはロード済みなのに再生されない、ということはユーザに画面をタッチさせることで音声を再生させる必要がありそう。

そして、どのように実現させようか考えた結果、今回は初期表示でモーダルを表示させ、必ずユーザーにタッチさせ、その際に音声再生しようと考えました。

タッチ時には無音の音声ファイルを再生させることで、その後キーボードから入力された場合も音が鳴ると考えたのです。

ちなみに、モーダルとタッチのイメージはこんな感じ。

しかし、実際にやってみると、タッチ時の無音の音声ファイルは実行されているのですが、その後のキーボード入力時の音声は再生されません。

どうやらタッチ時に再生された音声ファイル以外は、再生できるようにはならない模様。

音声ファイルが複数ある場合は、再生と同時にロードする

これはどうしたものか…と考えた結果、そうだ!load()すれば上手くいくかも!と思いつきました。

無音の音声ファイルを再生するのと同時に、このアプリケーションで再生したい全ての音声ファイルをload()したのです。

// モーダルをタッチした際に実行される
function soundSilent(){
  let sound = document.getElementById('audio-silent');
  if ( sound.readyState < 4 ) {
    console.log('ロードされていないのでロードします。readyState:' + sound.readyState);
    sound.load();
  }
  // 無音ファイルを再生
  sound.play();

  // あとで再生したい音声ファイルを全てロード
  sound1 = document.getElementById('audio1');
  sound1.load();
  sound2 = document.getElementById('audio2');
  sound1.load();
  sound3 = document.getElementById('audio3');
  sound1.load();
}

これがなんと大正解!!

キーボード入力時の音声も、無事再生されるようになりました!

コメント

タイトルとURLをコピーしました