玩式草子─ソフトウェアとたわむれる日々

第95回 「らじる☆らじる」をHLS経由で

この記事を読むのに必要な時間:およそ 6 分

radiru_rec.pyスクリプトの修正

さて,HLSの扱い方がだいたいわかったので,録音用スクリプトを生成するradiru_rec.pyを修正して,HLSに対応してみましょう。今回はダウンロードにffmpegを使うことにしました。

まず,ffmpegでHLSをダウンロードできるか確認します。HLSで配信される音声データはAAC(Advanced Audio Codec)でエンコードされており,それをHTTPS経由でダウンロードすることになるため,受信側にもAACとSSLの機能が必要になります。

たとえばPlamo-6.xのffmpegはライセンスの関係でOpenSSLのライブラリを組み込んでいないため,そのままでは「らじる☆らじる」の録音には利用できないのでご注意ください。

まずはffmpegの入力元(-i オプション)にNHK FMのURLを指定して,30秒分ほどデータをダウンロードしてみます。

$ ffmpeg -i https://nhkradioakfm-i.akamaihd.net/hls/live/512290/1-fm/1-fm-01.m3u8 -t 30 -movflags faststart -c copy -bsf:a aac_adtstoasc test.m4a
ffmpeg version 3.3.2 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 7.1.0 (GCC)
  configuration: --prefix=/usr --enable-gpl --enable-version3 --enable-nonfree --disable-static --enable-shared --disable-debug --enable-libass --enable-libfdk-aac --enable-libfreetype --enable-libmp3lame --enable-libopus --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-openssl
...
[hls,applehttp @ 0x670340] Opening 'https://nhkradioakfm-i.akamaihd.net/hls/live/512290/1-fm/1-fm-20170831T143716-01-111/1946.ts' for reading
Input #0, hls,applehttp, from 'https://nhkradioakfm-i.akamaihd.net/hls/live/512290/1-fm/1-fm-01.m3u8':
  Duration: N/A, start: 13154.032222, bitrate: N/A
  Program 0 
    Metadata:
      variant_bitrate : 0
    Stream #0:0: Audio: aac (HE-AAC) ([15][0][0][0] / 0x000F), 48000 Hz, stereo, fltp
...
Press [q] to stop, [?] for help
[hls,applehttp @ 0x670340] Opening 'https://nhkradioakfm-i.akamaihd.net/hls/live/512290/1-fm/1-fm-20170831T143716-01-111/1947.ts' for reading
[hls,applehttp @ 0x670340] Opening 'https://nhkradioakfm-i.akamaihd.net/hls/live/512290/1-fm/1-fm-20170831T143716-01-111/1948.ts' for reading
[ipod @ 0x6c47e0] Starting second pass: moving the moov atom to the beginning of the file
size=     180kB time=00:00:29.99 bitrate=  49.0kbits/s speed= 192x    
video:0kB audio:176kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 1.971487%

上記コマンドラインのオプションとして指定している -t 30 は30秒間録音する指示,-movflags faststartは動画サイズや再生時間などのメタ情報を記録している"moov atom"と呼ばれる領域をファイルの先頭部分に移動させる指示,-bsf:a aac_adtstoasc はMPEG TS形式用のAACデータをMP4形式用に変換する指示です。こうしてダウンロードしたファイルは180KBほどのAACコーデックの音声データと認識されました。

$ ls -lh test.m4a 
-rw-r--r--+ 1 kojima users 180K  9月 27日  12:38 test.m4a
$ file test.m4a 
test.m4a: ISO Media, Apple iTunes ALAC/AAC-LC (.M4A) Audio

ffmpegでデータを正しく受信できたので,次はチャンネルの設定です。⁠らじる☆らじる」の各チャンネルのURLはconfig_web.xmlというファイルに記載されています。このファイルを見ると,札幌,仙台,東京,名古屋,大阪,広島,松山,福岡のそれぞれに,ラジオ第一と第二,FMの各URLが用意されているようです。

config_web.xmlファイル

<radiru_config><!-- お知らせ -->
<info>/radio/include/oshirase.txt</info>
<!-- 各地域のストリームURL -->
<stream_url>
  <data>
    <areajp>札幌</areajp>
    <area>sapporo</area>
    <apikey>700</apikey>
    <areakey>010</areakey>
    <r1hls>
      https://nhkradioikr1-i.akamaihd.net/hls/live/512098/1-r1/1-r1-01.m3u8
    </r1hls>
    <r2hls>
      https://nhkradioakr2-i.akamaihd.net/hls/live/511929/1-r2/1-r2-01.m3u8
    </r2hls>
    <fmhls>
      https://nhkradioikfm-i.akamaihd.net/hls/live/512100/1-fm/1-fm-01.m3u8
    </fmhls>
  </data>
  <data>
    <areajp>仙台</areajp>
...
    <r1hls>
      https://nhkradiohkr1-i.akamaihd.net/hls/live/512075/1-r1/1-r1-01.m3u8
    </r1hls>
    <r2hls>
      https://nhkradioakr2-i.akamaihd.net/hls/live/511929/1-r2/1-r2-01.m3u8
    </r2hls>
...

これらの情報が揃えば,後はradiru_rec.pyのrtmpdumpを使っていた部分をffmpegに直して,各チャンネルのURLを更新するだけです。ついでなのでラジオ第一は大阪放送局も指定できるようにしてみました。

206      if channel == 'r1':
207          url = 'https://nhkradioakr1-i.akamaihd.net/hls/live/511633/1-r1/1-r1-01.m3u8'
208      elif channel == 'r2':
209          url = 'https://nhkradioakr2-i.akamaihd.net/hls/live/511929/1-r2/1-r2-01.m3u8'
210      elif channel == 'fm':
211          url = 'https://nhkradioakfm-i.akamaihd.net/hls/live/512290/1-fm/1-fm-01.m3u8'
212      elif channel == 'r1_kansai': 
213          url = 'https://nhkradiobkr1-i.akamaihd.net/hls/live/512291/1-r1/1-r1-01.m3u8'
214      else:
215          print("channel set error:{0}".format(channel))
216          usage()
217          sys.exit(1)

実際に音声データをダウンロードする部分は,先に指定したオプションをそのまま使う形にしました。

229      lines.append('#!/bin/sh')
230      lines.append('m4afile={0}/{1}.m4a'.format(musicdir, title))
231      lines.append('( ffmpeg -i {0} -t {1} -movflags faststart -c copy -bsf:a aac_adtstoasc  $m4afile ) &'.format(url, sduration))
232      lines.append('sleep 1m')

rtmpdumpを使っていた旧バージョンでは,ダウンロードしたファイルはフラッシュビデオの形式になっていたため,録音終了後,ffmpegを使ってm4a形式に変換する処理が必要でした。一方,HLS経由でダウンロードしたファイルはそのままm4a形式になっているので,その処理を省くことができ,録音用スクリプトは少し短くなりました。

こうして修正したHLSに対応したradiru_rec.pyの新バージョンは,筆者のブログのページに添付しておきましたので,興味ある方はそちらの方から入手してください。


RTMPからHLSに変ってまず気づくことは,各番組の開始時刻が30秒程度遅れることです。RTMP以前に使っていたMMS経由の録音でもほぼ同じ程度の遅延が生じていたので,RTMP(Real Time Messaging Protocol)はその名の通り,リアルタイム性には優れていたのだなぁ,と,改めて感心しました。

また,RTMP配信のころは録音失敗がほとんど無かったのに対し,HLS配信になってからは週に1,2度は録音に失敗していることも気になります。これは,⁠⁠らじる☆らじる」を直接聞いている際にも「⁠メディアがダウンロードできません」旨のエラーになって接続が中断する例を何度か経験したので,録音スクリプトの問題ではなく,サーバの負荷や通信経路の輻輳等に起因する問題のように思います。この問題はクライアント側では如何ともし難いので,⁠らじる☆らじる」がHLS配信の経験を積み重ねて信頼性を改善していくことを期待しています。

著者プロフィール

こじまみつひろ

Plamo Linuxとりまとめ役。もともとは人類学的にハッカー文化を研究しようとしていたものの,いつの間にかミイラ取りがミイラになってOSSの世界にどっぷりと漬かってしまいました。最近は田舎に隠棲して半農半自営な生活をしながらソフトウェアと戯れています。

URLhttp://www.linet.gr.jp/~kojima/Plamo/index.html