DMM.comの、一番深くておもしろいトコロ。

WebRTCを利用した超低遅延な映像配信

WebRTCを利用した超低遅延な映像配信

  • このエントリーをはてなブックマークに追加

はじめに

こんにちは。ライブコミュニケーション事業部 2.0スクラムチームの菊池です。 現在稼働しているライブ配信サービスのFlashからWebRTCへのリプレイスを行っています。 主にバックエンドを担当しています。
今回はなぜWebRTCを選択したのか、また、開発における苦労などのお話をさせていただきます。

2.0スクラムチームについてはこちら inside.dmm.com

なぜFlash -> WebRTCにしたのか

Flashから他の技術へ置き換えるならば、候補になるのは、 視聴側であれば以下の3つでしょうか。

  • HLS(HTTP Live Streaming)
  • WebRTC
  • MPEG-DASH ※対応ブラウザが少ない

MPEG-DASHに関しては現状対応ブラウザが少ないので現実的ではないでしょう。その上で、配信側は外部ツールを使ずブラウザのみで完結させるのであればWebRTC一択、という結論になりました。 なので、配信→視聴の組み合わせ的に以下のどちらかになるでしょう。

  • WebRTC -> HLS
  • WebRTC -> WebRTC

何を採用するべきかは、サービスの性質によって変わってきます。
例えばYouTubeのライブ配信では最低数秒の遅延があります。
YouTubeのように一人のユーザが多数のユーザに映像を一方向的に配信する形式では、数秒程度の遅延なら視聴者はほとんどそれを意識せずに配信を楽しむことができるでしょう。
また、ユーザ方向からのアクションとしてテキストチャットを送ることができます。
ユーザはこの時、配信者のリアクションで遅延があることに気づきますが、テキストチャットの場合ほとんど問題にならないでしょう。

しかし、今回リプレイスするサービスでは配信者と視聴者が双方向に映像と音声を送り合ってビデオチャットする機能があります。
そうなった場合に許される遅延は1秒未満と考えています。
音声による会話だと、遅延が数秒あるだけでものすごい不便さを感じてしまいます。

f:id:lc_team:20190527201628j:plainf:id:lc_team:20190527201643j:plain

YouTubeなどのライブ配信サービスはHLSを使用しています。
HLSでは、配信側のクライアントから送られてきた映像をサーバで数秒の動画ファイルに分割します。
この数秒の動画ファイルをwebサーバに配置し、クライアントにpullさせる方式です。

HLSを採用する場合のメリットはCDNを利用できること。 ダウンロードした分に関しては映像が止まったりせずにスムーズに再生できます。 また動画ファイルをすぐに破棄せずに保持しておけば過去にさかのぼって配信を視聴することも可能になります。
一方で、デメリットは遅延です。
私自身が他のサービスでHLSを採用したケースでは、遅延がどうしても5〜6秒ぐらいは出てしまいました。
チューニング次第ではもっと短くできますが、1秒未満というのは難しいです。

そこで今回のプロジェクトではWebRTCを採用することになりました。
UDPベースで直接映像を視聴クライアントに直接送信する方式のWebRTCでは、「超低遅延な映像配信」が可能になります。
ただし、回線の品質などの影響をもろに受けるのでHLSに比べて安定性という面では劣ってしまいます。

WebRTC.org

ですので、数秒の遅延が許されるのならばHLSの採用を検討するべきです。

SFUによる配信側の負荷軽減

WebRTCのシンプルな構成では、単にクライアント同士が直接コネクションを張って通信します。

f:id:lc_team:20190611194604p:plain

しかし、視聴クライアントが多くなると、そのすべてとコネクションを張らなければならない配信側の負荷が上がってしまう。 今回のサービスでは1つのチャンネルを数十から数百のユーザが一度に視聴する場合があるので、この状態ではサービスを提供できません。

配信側クライアントの負荷を軽減するために SFU(Selective Forwarding Unit )という仕組みがあります。 簡単に説明すると映像や音声のやり取りをサーバ経由で行います。

WebRTCをサーバ経由して使用することによって視聴側も配信側もすべてのクライアントがサーバとの単一のコネクションを持てば良いことになるので、視聴クライアントが増えても配信クライアントの負荷は上がりません。

f:id:lc_team:20190611194621p:plain

また他にも、SFUを使用すればサーバ側で映像の録画ができたり、認証機能を付けたりできるようにもなるメリットがあります。

サイマルキャストによる複数画質の配信

様々な環境のユーザに対して安定したサービスの提供をするためには、視聴側に視聴画質を選択できるようにしたほうが親切です。 遅い回線なら画質の低い映像を受信してスムーズに視聴し、速い回線なら画質の高い映像を視聴できるからです。

WebRTCでは、複数の画質の映像を提供する方法としてサイマルキャストがあります。 配信クライアントから複数の画質の映像を配信するもので、サーバで処理をして映像を分けるのではなく初めから配信側で複数の映像を同時に送信する点がポイントです。 そのため、配信側で単一の画質の映像を配信する時に比べて負荷が上がってしまうという問題があります。 今回のプロジェクトでは、このサイマルキャストはいったん見送ることにしました。

コーデックの選択

コーデックとは映像をエンコードする時のアルゴリズムを指します。 どのコーデックを使用して映像をエンコードするかでも画質やクライアントの負荷が 変わってきます。 たいていの場合、候補として上がってくるのが以下の3つでしょう。

  • VP8 容量はそんなに節約できない。いまさら採用するメリットはないかも。
  • VP9 容量がかなり節約できるが、CPU負荷高め。
  • H264 対応ブラウザ多い。

それぞれで対応するブラウザなどが変わってくるので、どのブラウザをサポートしてどのブラウザをサポートしないのかなどで採用するコーデックが変わってきます。

地味な画質のチューニング

リプレイスに際して画質の見直しも行われました。
既存のシステムが作られてから15年ほど経っているので、「高画質」という言葉の意味もだいぶ変わっています。 かといって、何も考えずに高画質にしようとすると動画が重くなってしまうので、画像の大きさやフレームレートを調整してビットレートをどこまでさげられるのかといった地味なチューニングを行うことになります。
数値ではわからない感性的な品質なので、少しずつ値を変えていって見た目を比較していく作業が必要になります。
動きの大きい場合と小さい場合で圧縮率が変わり、動くとノイズは大きくなります。
なので止まったままだと正しく品質を判定できないので、カメラに向かってずっと手をふっていたりする必要があります。
これが結構疲れます。
サービスの性質上、動きが多いのか少ないのかで適切な値が結構変わってくるんじゃないでしょうか。

f:id:lc_team:20190603172414p:plain

「おッ案外きれいだ!」

f:id:lc_team:20190603172429p:plain

「あれ、」

f:id:lc_team:20190603172635p:plain

「動いたらだめだー」

監視の回線とマシンスペック

サービスの運用業務の1つに配信の監視があります。 ルールに違反している配信を即座に停止し、警告を出すという業務です。 監視クライアントでは一度に何十もの映像を同時に表示しなければならないのですが、配信側の負荷を考えてサイマルキャストをしないという方針をとったため、監視クライアントもユーザと同じ画質の映像を受信しなければならなくなってしまいました。

そのため、監視をするためのPCの要求スペックがとても高くなってしまいました。 実機での検証ではGPUの有無、ブラウザの種類等の条件を変えて映像のカクつきやユーザ側の視聴クライアントとの遅延の差を比較していきました。

検証でわかったのは、ChromeではGPUを使ってCPUの負荷を抑えてくれている。 一方、FirefoxではGPUを全然使ってくれないということでした。
同じPCを使ってもFirefoxとChromeでは2倍ぐらいの差がありました。

監視のために結構高いGPUを積んだPCを採用しようとしています。
開発に使っているPCよりもハイスペックで羨ましいです。

さらに、コストが高くなってしまうのはPC本体の価格だけではありませんでした。
ネット回線の費用がとんでもなく高額になってしまったのです。
そこで考えたのが、VDIを使えば監視に使用する回線を節約できるのではないかということです。 しかし、試しにVDIのサービスを利用して検証してみたのですが値段が手頃で要求に見合うスペックのVDIを提供しているサービスがなくこの案は不採用になりました。
結構いいアイディアだと思っていたのですが。

その他いろいろな問題

ブラウザのバージョンアップが怖い話

ブラウザのバージョンアップ後に動かなくなってしまうことが結構あったりします。

仮想カメラが使えない話

仮想カメラアプリケーションが使えない不具合に遭遇したWindowsのFirefox。 デバイスの順番によっても影響があるので、外部カメラをもう一台つなぐと回避できたりする。 WebRTCのテストサイトもうまく動作しないです。 Firefoxの不具合っぽいんですが、これって解消されるのでしょうか。(執筆時点でのバージョンは67.0)。

負荷分散が大変そうな話

視聴クライアントとサーバとの接続が張りっぱなしになるので、負荷分散が難しいですよね。 HLSだったらとても楽なんですが。 配信を開始する時にどのSFUのサーバを使用するかを選択するのですが 人気の配信者だと多くの視聴者が集まって負荷が高くなります。 誰が人気の配信者なのかを覚えておいて、同じサーバに 固まらないようにするなどの工夫が必要なのかなと考えていたり・・・・。

さいごに

というわけで、あれこれ書いてきましたが、リプレイス作業は現在も真っ只中で進行中です。ここで挙げたものはごく一部のもので様々な問題とぶつかっていますが、もし皆さんがWebRTCの開発をする際は参考にしていただけたら嬉しいです。

dmm-corp.com