Jump to the content

スマホ向けオーディオスプライトライブラリを作った

JavaScript

    仕事でスマホで音声再生をすることになって、 単音なら大丈夫かーと思っていたら、仕様的に何個も音を鳴らすことになり、 いろいろ試した結果、オーディオスプライトでの実装が一番安定していたので、 ここ のスクリプトを元に、単音再生用の汎用的なJSライブラリを作った。

    audioSprite.js

    ※サポートブラウザはiOS5+(mobile safari), Android2.3+(標準ブラウザ)
    PCでもひと通り動作検証済み。iOS7に関しては未検証。

    オーディオスプライト

    オーディオスプライトは、CSSスプライトをご存知の方はイメージしやすいかもしれない。 一定の感覚で音声を配置して、シークポイントを変えて再生することで1ファイルで複数のバリエーションの音声を再生することができる。

    iOS における HTML5 の audio 要素に関する制約を克服する

    使い方

    // 初期化
    var player = new audioSprite({
        src: 'audio.mp3',   // 音声ファイルのパス
        n: 1,               // 
        spriteLength: 1,    // 1音あたりの秒数
        trimTime: 0.1       // 終了位置のトリミング時間
    });
    
    // 1番目に配置されている音声を再生
    player.play(1);
    

    音声ファイルのロード完了を待ちたい場合は以下のようにすればいい。

    // 初期化
    var player = new audioSprite({
        src: 'audio.mp3',   // 音声ファイルのパス
        n: 1,               // 
        spriteLength: 1,    // 1音あたりの秒数
        trimTime: 0.1       // 終了位置のトリミング時間
    });
    
    // audio要素のloadeddataイベントにリスナーを登録
    player.tracks[0].audio.addEventListener('loadeddata', function() {
        // 1番目に配置されている音声を再生
        player.play(1);
    
    }, false);
    

    iOS5+とAndroid2.3+に対応するのであれば、ファイル形式は.mp3だけで十分で、 もしPCでも同じく共通のオーディオスプライトを使用したい場合は、Firefox用に.oggファイルを用意して以下のようにすればいい。

    var fileType = /Firefox/.test(navigator.userAgent) ? '.ogg' : '.mp3';
    var player = new audioSprite({
        src: 'audio' + fileType,
        ...
    });
    

    iOSにおける注意点

    iOSでは、ユーザー操作(ここで言うとtouchstartイベントとか)にバインドしないとオーディオファイルがロードされない。 そのため、document自体にtouchstartイベントが発火した時点で、audio.load();が開始されるようにしてある。
    これは意外と軽視されがちなので、コンテンツの設計段階でオーディオ再生前にロード用のボタンを押させる、など導線を考える必要がある。

    window.onloadのタイミングでいいでしょ、とかでは上手くいかない。

    補足:スマホでオーディオスプライトを採用した経緯

    当初、同時に複数の音源を再生したいとの要望が上がっていて、
    正直なところ、これを作るまではスマホの標準ブラウザ(mobile safariやAndroidの標準ブラウザ)で音声再生した経験がなかった。
    ググってみても、iPhoneでは複数音声再生できないという記事が多く見られ、実際に検証した結果、iOS5以下のMobile safariでは無理だった。
    おまけにAndroidでは…、お察しの通りだろう。

    始めは複数のaudio要素を使い回せばいいと思って、
    Android4.0.4の標準ブラウザで複数のaudio要素を置いてみたが、 すべてのaudio要素で指定したファイルのロードが完了しないと音声は再生されないような挙動を示した。

    また、音声を再生終了後に再び始めから再生する時に

    audio.currentTime = 0;
    audio.play();
    

    としたものの、iOSでcurrentTime = 0の指定でエラーになる。

    audio = new Audio(audio.src);
    

    とか再帰的に初期化してみたけども、currentTimeは0にできるが再生の度にリクエストが走っているっぽかった。
    2,3個インスタンスを作ってみたけども、Androidで遅延があまりに酷く、ブラウザフリーズが多発し断念した。 (他にタイマーの処理を走らせていたというのも一因ではある。)

    あとは普通にaudio要素を再生する場合、連続タップして音声再生するようなケースだと、 オーディオスプライトと比べるとレスポンスが格段に悪かった。

    そんなこんなでたどり着いた結果が、オーディオスプライト。 オーディオの管理は決してやりやすいものではないが、 スマホブラウザでの音声再生も頑張ればできるということをお分かりいただければ、自分の苦労も報われると思う。

    注目記事

    最近の記事

    ぼくが書いてます

    フロントエンドエンジニア

    イソップ

    ページの先頭に戻る

    Search results

    ×