投稿者: tong

HTLM5、JavascriptでAudioオブジェクトのcurrentTime = 0では頭出しができなくなる現象について

非常にご無沙汰をしております。tongでございます。
ここまで間があいてしまいますと「あんた誰?」みたいな方ばかりかと思いますが、自己紹介は無しの方向でお願いします。
私事で色々ございましてなりを潜めておりましたが生活の為にお仕事はする訳で、そこで「ちょいとハマった」事があって調べても中々わからなかったので、ここに書いておけば誰かの助けになるかなと言う事で書いておこうと思います。

背景説明としてはWebアプリの開発から7年くらい離れていたのですが、色々あって昔 自分がFlashで作った真面目な仕事のWebアプリ化を断ったら他所に頼んだけど失敗したので再度舞い戻って来た。って感じの話。

記事内容はタイトルの通りで、ネットワークの遅延を防ぐために100個位の短い音声ファイル(えっちぃ声じゃ無いよ)を先読みしてユーザー操作に応じて再生するって感じの挙動。

引っかかったのは2点で、一つは動的にAudio「タグ」を大量に生成してHTMLのエレメントに追加するとFirefoxでは読み込みに引っ掛かりが出る場合があること。
今回はAudioタグのコントロールを表示したりしないので、Javascriptのオブジェクトとして扱ってやれば回避可能でした。

もう一つは、Mac OS XのApple Safariのみ先読みした音声ファイルの2度目の再生が出来ない、あるいは途中から再生されると言う現象。
最初は「またアップルかっ!」とキレそうになるも、そこはホレ大人ですから落ち着いてよく考えてみる。
すると、まず途中から再生されるのは1回目の再生時に最後まで再生されない場合に再生位置が残っているのでは無いかと言う推察に至ります。

途中から再生されちゃダメなら再生前に頭出しすりゃ良いじゃん。って事で「currentTime = 0」を入れる訳ですが、これが出来ない。

なにこれ?

ReadOnlyでもないプロパティーに値がセットできないのは変です。異常です。
この辺をWebで検索するとSafariとChromeの自動再生回避ばかりが引っかかるんだけど、そうじゃないんだよね・・・
って事でさらに調べて行くと「new Audio(‘URL’)でAudioオブジェクトを再度作るとcurrentTime = 0じゃ無くても頭出しできるよっ」みたいな記述がSafari開発者のコミュニティーで見つかったので早速実装。

ふむ、確かにSafariでは動く。しかし他のブラウザでテストを行うとFireFoxで動かないでは無いか。
件のページにも今のSafariは「さすがはSafari、大量にオブジェクトを作っても何とも無いぜ」だけど昔は大量にオブジェクトをnewすると動作が不安定になったってあって「やっぱりアップル関係者はSafariしか考えてないなっ!」となって居た訳です。

その後もcurrentTime = 0関連で、メモリー上に「先頭が0以外の値のAudioストリームデーターはcurrentTimeを0に出来ない」とか、色々出てきて「先頭が0以外の値のAudioストリームデーター」ってどんなよ?ってなるのですが、「あぁユーザーがコントローラーで再生位置をジャンプしたりするとそうなるか、メモリー上に無いなら出来ないわな」。
そして「new Audio(‘URL’)」で解消できるって事はダメな時はメモリー上にデーターが無かったって事であり、currentTime = 0に気を取られていたけど、これはもっと別の現象なのではと言う考えに至り・・・

そう、そうなんです。
これは「何らかの原因でメモリー上に音声データーが無い」事が原因なんですね。

ここで種明かしをすると、この現象はガーベイジコレクトが原因なんですね。
と言うか昔、同じECMAスクリプトであるActionScriptでも同じ現象に出くわした事が有った気がしてきました。

ガーベイジコレクトとは使用メモリーの節約機能で、ロードやアクセスしてから時間が経ったオブジェクトはエントリのためのオブジェクトのガワだけ残して実体はメモリーから削除されちゃうんです。
このため最初の頃はちゃんと再生できていた音声が時間が経つと正しく再生できなかったり、頭出しが出来ない等の現象が起きてしまう訳です。

では具体的にはどう対策したらよいのかと言いますと、new Audio(‘URL’)でAudioオブジェクトを大量に作ると言う方法ではAudioオブジェクトの作り過ぎでスマートじゃない。何よりFireFoxで動かないなどの弊害があります。
これを回避するには、新しくオブジェクトを作るのではなくAudioオブジェクト.load(‘URL’)とします。

//先読みでデーターをロードする
let soundObj_0 = new Audio(‘sound/sound_0.mp3’); //プリロード


//どのタイミングで音声データーが使われるか分からないので
//使うときはとにかくloadしてしまう
soundObj_0.load(‘sound/sound_0.mp3’); //再生前に無条件にロード
soundObj_0.currentTime = 0;  //念のために再生位置を0リセット
soundObj_0.play();  //音声再生

こんな感じですかね。

なお、2回目のload(‘URL’)はブラウザ キャッシュからロードが行われるので読み込みにネットワークの遅延は出ないようです。

めでたしめでたし。


インサルト・インサート for スマートデバイス 販売申請中

現在DLsiteDMM同人で販売中の「インサルト・インサート」ですが、アンドロイド版としてインサルト・インサート for スマートデバイスの販売申請を行いました。
近日公開予定です。 販売開始されました。

諸般の事情でDLsiteのみの販売となりますがよろしくお願いします。

作品内容につきましてはこちらをご覧ください。


インサルト・インサート 不具合修正

前回5月20日のDMM版の更新においてゲームの進行が途中で止まる不具合のご連絡をいただきました。

内部を検証しました結果DMM版において一部ファイル名が正しく設定されていない不具合が見つかりましたので、修正を行いDMM様に再登録を行いました。

当該バージョンをお買い上げ、ダウンロードされましたお客様にはご迷惑をおかけした事をお詫び申し上げます。

現在は修正版がアップロードされていますので、お手数ですがダウンロード・再インストールのほどよろしくお願いいたします。


インサルト・インサート 機能追加

現在DLsiteDMM同人で販売中のインサルト・インサートですが、以下の機能追加を実施しました。

  1. 設定画面を追加しました。
    メニュー内の「設定」ボタンで表示されます。
    音声と効果音(インサルト・インサートでは使われていませんが、いいんちょ的にはBGMも)で、それぞれON・OFFの設定が可能になりました。
  2. 効果音を追加しました。
    いわゆる「ヌチャ音」です。今まで効果音は音声と同一チャンネルで再生していたため、音声かヌチャ音かどちらか片方しか再生されませんでしたが、今回の変更で効果音専用チャンネルを設け音声と同時に「ヌチャヌチャ」と再生されるようになりました。
  3. 使用フォントをIPA明朝に変更しました。
    これは、現在制作中の「Android版」で一部機種においてAdobe Airアプリのデバイスフォントが表示されない問題に対応したためです。

現在各販売サイトで審査中となっていますが、近日中に公開されると思いますので是非お試しください。


インサルト・インサート 無音パッチ

先日公開しました「インサルト・インサート」ですが、音声についてコメントをいただきました。
詳しい経緯は該当コメントをお読みいただければと思いますが、対応としまして「無音パッチ」を作成しましたので、もし音声が無い方が良いと言う方はそちらをお使いいただければと思います。

インサルト・インサート 無音パッチ