【AI Shift Advent Calendar 2021】hls.jsを使った音声の再生

こんにちは。Development Teamの市村です。
本記事はAI Shift Advent Calendar 2021の20日目の記事です。
今回の記事では、hls.jsというJavaScriptライブラリを使ったHLS形式の音声の再生について書きたいと思います。

はじめに

HLS(HTTP Live Streaming)はApple社が開発した動画や音声をストリーミング配信するための規格です。
HLSはSafariでは再生可能ですが、Chrome、FirefoxなどのブラウザはHLSに対応していません。
hls.jsを使用するとHLS非対応のブラウザでもHLSの再生が可能となります。
今回はhls.jsを使って音声データを再生してみました。
使用したhls.jsのバージョンは0.14.7になります。

プレイリスト

hls.jsにSourceとして読み込ませるプレイリストには以下のように細かく分割したセグメントファイル(.tsファイル)や再生時間などが記されています。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:5.120000,
file0.ts
#EXTINF:4.992000,
file1.ts
#EXTINF:4.992000,
file2.ts
#EXTINF:4.992000,
file3.ts
#EXTINF:4.992000,
file4.ts
#EXTINF:4.992000,
file5.ts
#EXTINF:4.992000,
file6.ts
#EXTINF:4.096000,
file7.ts
#EXT-X-ENDLIST

今回はこのセグメントファイルの部分に認証情報を付加したいと思います。

インストール

以下のコマンドでインストールします。

npm install hls.js

hls.jsについて

hls.jsのセットアップでは以下のようにHLSオブジェクトを作成します。

import Hls from 'hls.js';

const hls = new Hls();

HLSのインスタンス化の際に、様々な設定パラメータを渡す事によって既存の動作を上書きする事ができます。
例えば、startPositionを以下のように設定すると、再生開始位置を25秒に設定する事ができます。

const hls = new Hls({startPosition: 25});

hls.jsの主な機能はLoaderやControllerなどいくつかのサブシステムに分割されていますが
Hlsコンストラクタの引数として設定パラメータを指定する事でこのサブシステムの処理を上書きする事もできます。
例えば後で述べるカスタマイズしたプレイリストローダーのように、独自のローダーを定義して既存の処理を上書きする事ができます。

// pLoaderを設定パラメータとして渡す事で、ローダの処理を上書きする事ができる。
const hls = new Hls({ pLoader: CustomLoader }); 

hls.jsで設定可能なパラメータはこちらになります。

hls.jsのイベントについて

hls.jsにはこちらのようなイベントがあり、以下の例のように各イベントをsubscribeする事ができます。

// メディアソースがメディアelementにアタッチされた時に通知される
hls.on(Hls.Events.MEDIA_ATTACHED, onMediaAttached); 

// エラーが発生した時に通知される
hls.on(Hls.Events.ERROR, onError); 

ローダーの役割

fLoader
フラグメント、プレイリスト中に記述されたtsファイルのLoadを担当する。

pLoader
プレイリスト、m3u8ファイルのLoadを担当する。

以上をふまえて、実装していきたいと思います。

Audioタグの準備

HTMLに以下のようにAudioタグを準備します。

<audio
  id='audio'
  controls=true
>
  <source src='プレイリストのURL' type='application/x-mpegURL' />
</audio>  

カスタマイズしたプレイリストローダーの定義

プレイリストの中身を操作するため、以下のように独自にカスタマイズしたプレイリストローダーを定義しました。

import Hls, { LoaderConfig } from 'hls.js';

const process = (playlist: string | ArrayBuffer) => {
  // ここでセグメントファイルに認証情報を付加します。詳細は割愛させていただきます。
   return playlist;
};

class CustomLoader extends Hls.DefaultConfig.loader {
  public constructor(config: LoaderConfig) {
    super(config);
     const load = this.load.bind(this);
     this.load = async function(context, config, callbacks) {
       if (context.type === 'manifest') {
          const onSuccess = callbacks.onSuccess;
           callbacks.onSuccess = function(response, stats, context) {
             response.data = process(response.data);
             onSuccess(response, stats, context);
           };
         }
         load(context, config, callbacks);
       };
     }
   }

上で定義したCustomLoaderをpLoaderとして指定します。これにより、デフォルトのローダーを独自の実装で上書きする事ができます。

const audio = document.getElementById('auido');
if (Hls.isSupported()) {  
  const hls = new Hls({ pLoader: CustomLoader });
  hls.attachMedia(audio);
  hls.on(Hls.Events.MEDIA_ATTACHED, () => {
    hls.loadSource('プレイリストURL');
  });
}
// 今回Hls.isSupported()がfalseだった場合の処理は今回は割愛させていただきます。

以上の実装で、音声データを再生する事ができました。

まとめ

hls.jsは公式ドキュメントも分かりやすく書かれていて、比較的シンプルなコードでHLSの再生が可能だったので、非常に助かりました。
公式ドキュメントのサンプルコードはvideoタグを利用した物でしたが、audioタグでも問題なく再生できて良かったです。
最後まで読んでいただきありがとうございました。

参考

hls.js
https://github.com/video-dev/hls.js/