こんにちは!CyberAgentでソフトウェアエンジニアを務めている松澤(@thmatuza)です。

この度サイバーエージェントグループでの技術カンファレンスCA BASE CAMPにて登壇させていただきました。WebRTCとコラボ配信についてお話ししました。

本記事では登壇内容を紹介します。

 

1.コラボ配信

コラボ配信は、近年様々なライブ配信サービスで実装されている機能で、離れた場所にいる2人以上の配信者がいっしょに配信する機能です。まずこの動画を見てください。

この動画は、ある配信アプリのテレビコマーシャルです。CM中で、人気の配信者が一人で配信を開始します。その配信を教室で見ていた学生さんが、「コラボする」というボタンをクリックすると、配信者へ通知が行き、配信者が承認すると、映像が分割され、人気配信者と視聴者がいっしょに生配信できるようになります。これがコラボ配信機能です。

コラボ配信を導入すると、ライブ配信サービスにいろいろな可能性が広がります。

まず視聴者が人気配信者と、カメラ越しで面と向かって会話をすることができるようになります。

離れた場所にいるミュージシャンの配信者達が、いっしょに演奏して配信することができるようになります。

離れた場所にいる配信者同士が、ダンス対決しているところや、料理対決しているところ、お絵かき対決しているところなどを配信することができます。

 

次に、コラボ配信を実現するためのシステム構成について考えてみます。

まずそれぞれの視聴端末で2つの映像を受信して、映像を合成して表示する方法が考えられます。

上図のようにそれぞれの配信者は、独立したメディアストリームをサーバーへ送信して、配信サーバーが両方のストリームを視聴端末それぞれへ転送します。

この方法の利点は、視聴端末で映像の合成を行うため、視聴端末ごとに合成レイアウトを変更することができるという点です。

例えば、このように視聴端末1では、配信者①の映像を大きく表示して、視聴端末2では配信者②の映像を大きく表示させることができます。

一方次のような欠点があります。

それぞれの視聴端末で複数のメディアストリームを受信する必要があるため、視聴端末での受信ビットレートが大きくなってしまいます。

また視聴アプリでの合成処理をiOS、Android、Webすべてに実装する必要があります。

さらに、それぞれの配信者は独立にストリームを配信しているため、配信者同士で会話することができません。

コラボ配信では、配信者同士で会話できることが重要であるため、別の実現方法を考えてみます。

配信者同士がP2P通信でお互いの映像、音声を送信し合うようにしてみます。

これで配信者同士が会話できるようになります。

配信端末の一つをホスト端末とします。

ホスト端末では、映像を合成して、一つにまとめた合成映像を配信サーバーへ送信します。

配信サーバーは、その合成映像を視聴者へ転送します。

この方法の利点は、ホスト端末で映像が合成され、それ以降は一本のメディアストリームになるため、配信サーバー、視聴ソフトの改造が不要であることです。

一方次のような欠点があります。

まずホスト端末に処理が集中してしまうため、ホスト端末への負荷が高くなります。

また、ホスト端末は、ゲスト配信端末と配信サーバーの両方に映像を送信するため、ホスト端末のアップリンク帯域が2倍になります。

さらにホスト端末とゲスト端末が直接通信する必要があるため、ファイアウォールの影響を受けやすいという問題があります。

これらの欠点を補うためにシステム構成を少し変更してみます。

配信端末同士は、直接通信し合うのではなく、クラウド上にある配信サーバーを介して通信するようにします。

配信サーバは、受信したストリームを、別の配信端末へ折り返します。

配信サーバーは、さらに受信したストリームを合成します。そして一本になった合成映像を視聴端末へ配信します。

この構成では、配信者同士が、クラウド上にある配信サーバーを介して通信し合うため、ファイアウォールの影響を受けづらいという利点があります。

しかし配信サーバーに重い処理が集中するため、高スペックな配信サーバーが求められるという欠点もあります。

これまで上げたコラボ配信のシステム構成には、それぞれ一長一短がありました。私が知る限り、構成案3がコラボ配信の実装でよく用いられています。しかし、特殊なケースで構成案1,構成案2も有効だと思います。

まずEスポーツでプレイヤー同士がコラボを配信するケースでは、プレイヤー同士が会話をする必要はないか、ゲーム自体にコミュニケーションの手段がすでに備わっている可能性が高いです。その場合、配信者同士の通信は重要でありません。そのため、構成案1も有効だと考えられます。

次に、何らかの理由で配信サーバーを改造することができないケースがあると思います。その場合、構成案2が有効だと考えられます。配信者がSkypeを使ってコラボ配信することがしばしば行われますが、これは構成案2に似ていると思います。Wirecastに最近Rendezvous機能というものが搭載されましたが、これも構成案2に似ています。

それ以外のケースでは、構成案3が適していることが多いと思います。これから、主に構成案3の実現方法について書きます。

2.WebRTC

現在、配信アプリから配信サーバーへ映像を伝送するのに最も一般的に使われているプロトコルはRTMPです。クラウド上にある配信サーバーへの通信は安定しているので、通常の配信ではRTMPで十分なことが多いです。

しかし、コラボ配信では配信者同士が双方向通信する必要があります。片方の配信者の電波が悪くなったら、一方の配信者が低ビットレートに切り替えるなどの仕組みが必要になってくるかもしれません。RTMPはこのような処理には向いていません。

このような双方向通信に向いている技術としてWebRTCがあります。WebRTCは、その名の通りWebブラウザ同士でリアルタイム通信を行うための技術です。

WebRTC以前は、Webブラウザ同士でリアルタイム通信を行うためには、Flashなどのプラグインを使う必要がありました。Flashの衰退に伴い、リアルタイム通信をWebブラウザの標準機能とする動きが始まり、WebRTCが誕生しました。

WebRTCはWebブラウザ向けの技術ですが、実際はNative APIを使用することにより、iOS、AndroidアプリでWebRTCを直接使うことも可能です。実際Google HangoutsやFacebook Messengerのアプリは、WebRTCを使って通信を行っています。

コラボ配信は、ビデオ会議システムに似ていますが、次にWebRTCでどのようにビデオ会議を実現するかについて見ていきます。

WebRTCでビデオ会議を実現するためには、一般的に3つの方法があります。

Mesh、MCU、SFUと呼ばれます。

これらについて長所短所を見ていきます。

メッシュ型では、各端末が、他のすべての端末にストリームデータを送信します。

この方法では、サーバーが必要ないという利点があります。

また、映像合成のレイアウトは、各端末で自由に設定することが可能です。

欠点は、アップリンク、ダウンリンクとも[参加端末数 – 1]のストリームデータを送受信するため、データ転送量が非常に大きくなることです。

これに対してMCU (Multipoint Control Unit)と呼ばれる方法では、端末同士は直接通信せずに、一度サーバーへストリームデータを送信します。サーバーは受信したすべての映像を合成して一本のストリームデータにまとめます。各端末はこの合成された一本のストリームデータを受信して、表示します。

この方法の利点は、端末がどれだけ増えても、各端末は一つのストリームデータのみ送受信するので転送量が大幅に減ることです。

欠点は、サーバーで映像合成を行うためにサーバー負荷が非常に高くなるということです。

また各端末ではサーバーで合成された映像をそのまま表示するしかなく、端末ごとに映像合成レイアウトを変更するということはできません。

SFU – Selective Forwarding UnitはMesh型とMCU型の中間のような方式です。

MCUと同様に各端末はサーバーへストリームデータを送信します。しかし、サーバーは映像の合成はせずに、そのままのストリームデータを各端末へ転送します。

この方法では、ダウンリンク帯域はMesh方式と変わらず [参加端末数 – 1]分必要になります。

しかし、アップリンクの帯域はMCUと同様に一つのストリームデータ分だけになります。

また、映像合成のレイアウトは各端末で自由に設定できます。

次に先に述べたコラボ配信システム構成案3をWebRTCを使って実現する方法について考えてみます。配信アプリ同士の通信についてはSFUを使います。こうすることにより配信アプリごとに合成レイアウトを変更することが可能になります。

視聴者への配信にはMCUを使います。こうすることにより、ストリームデータが一本になり帯域を大幅に節約することができます。視聴者数が数千以上のときにこの違いは顕著になります。

このようなSFUとMCUのハイブリッドにした場合の、コラボ配信アプリのUIの例を考えてみます。

配信アプリ側では、SFUを使っているため合成レイアウトを自由に設定できます。例えば、ビデオ通話アプリのように相手の映像を画面いっぱいに表示して、自分の映像をその上に小さく重ねるように表示することができます。またボタン一つで自分の映像と相手の映像の表示の仕方を反転することも可能です。

視聴アプリ側では、MCUを使っているため配信サーバーが映像を合成したものをそのまま表示します。この例では配信サーバーが各配信者の映像を横に並べて合成させています。視聴アプリで映像合成のレイアウトを変更することはできませんが、視聴アプリは、一つのストリームデータを表示するだけなので実装はシンプルになります。

3.コラボ配信実装例

3年前にコラボ配信をあるアプリで実装したことがあるのですが、その時の実装詳細について書きます。

配信システム構成はこのようにしました。配信者とWebRTC Media ServerであるKurento Media ServerがSFU形式で通信を行います。

Kurento Media ServerのWebRTC Endpointで受信したストリームデータは、Compositeへ渡され映像合成されます。

合成され一つになったストリームデータは、RTP Endpointを通してWowza Streaming Engineへ渡されます。

Wowza Streaming EngineはRTMPを使って視聴者へ配信します。

「2019/3/5追記 LicodeはMCU機能を持っており、MedoozeはSFU機能を持っているというご指摘を受けました。Licodeについては、transcodingはできるがコラボ配信に必要なmixingがないとうことで話の流れ上MCU無しと上表に記述させていただきました。厳密にはrecodingやstreaming outはできるためご指摘の通りMCU機能を持っていることになります。Medoozeについては私の調査不足です。ごめんなさい。」

様々なWebRTC Media Serverが存在していますが、Kurento Media Serverを選んだのには理由があります。

先ほど述べたとおり、コラボ配信をWebRTCで実現するにはSFUとMCUのハイブリッドのような形式になります。

この表を見ていただくとわかりますが、SFUとMCUの両方をサポートしているWebRTC Media ServerはIntel CS for WebRTCとKurento Media Serverだけです。

Intel CS for WebRTCはクローズドソースであったため、オープンソースであるKurento Media Serverを選択しました。

Kurento Media Serverの特徴は、標準で様々なMedia Elementと呼ばれるコンポーネントが用意されており、これを組み合わせるだけで色々な種類のメディアサーバーを構築することができることです。

この中のWebRTC Endpoint、Composite、RTP Endpointコンポーネントを使用してコラボ配信機能を実装しました。

他のコンポーネントを追加することで簡単に機能拡張できます。

例えば、RecorderEndpointを追加すれば、サーバー録画機能を追加できます。

FaceOverlayFilterを追加すれば、配信者の顔にウサギ耳をつけるような顔フィルター機能を追加できます。

Kurento Media Serverは、有名なオープンソースのメディアフレームワークであるGstreamerベースで開発されています。カスタムGStreamerフィルタを開発することにより、標準のMedia Elementにない機能を開発することも可能です。

Kurento Media Serverはコラボ配信機能を実現するのに十分な機能を持っていましたが、いくつか苦労した点もありました。

標準装備のCompositeコンポーネントは、単純に2つの動画を横に結合するだけのものでした。例えば2つの16:9の映像が、32:9の横長の合成映像になってしまいます。実際にやりたかったのは、それぞれの映像の真ん中を切り抜き横に並べて16:9の合成映像を生成することでした。

この問題に対応するため、カスタムGStreamer合成フィルタを開発する必要がありました。

またKurento Media Serverには正式なiOS、Androidクライアントは存在していません。参考になるソースコードが存在していますが、動作するものではなく、独自にクライアントを開発する必要がありました。

4.今注目しているWebRTC Media Server

このようにKurento Media Serverでのコラボ配信実装の際に、いくつか苦労した点がありました。

最近社内のあるサービスでコラボ配信を実装する予定があったため、現時点でKurento Media Serverよりよい選択肢がないか調査しました。

数年前と状況はあまり変わっていませんでしたが、以前は採用を見送ったIntel Collaboration Suite for WebRTCが気になり調査し始めました。

Intel CS for WebRTCにはいくつかの特徴があります。

まず、コラボ配信で重要なSFUとMCUの両方をサポートしています。

それから、映像合成レイアウトを自由に設定できます。

iOS、Androidクライアントを正式にサポートしています。

この2つはKurento Media Server使用時に問題であったものなので、大変魅力的な特徴です。

また、合成映像をRTMP、RTSPで出力することができ、Wowzaなどに接続すればHLSでの大規模配信も可能です。

標準のWebRTCライブラリは、ビデオコーデックとしてVP8、VP9、H264のみをサポートしています。

しかしIntel CS for WebRTCは標準WebRTCライブラリを改造しており、HEVCもサポートしています。

このように多機能ですが、クローズドソースであるため、細かな調整ができないという問題があります。

Intel CS for WebRTCのもう一つの特徴として、サーバーがいくつかのコンポーネントに別れているというものがあります。

これらのコンポーネントが協調してSFU、MCUの機能を実現します。

それぞれのコンポーネントはNode.jsのアプリケーションとなっています。

コンポーネントは、それぞれ複数デプロイすることが可能です。

例えばWebRTC Accessコンポーネントは5つだけデプロイして、処理が最も重いVideo Processingコンポーネントは20個デプロイするというようなことができます。

標準で負荷分散機構が備わっており、それぞれのコンポーネントごとにスケジューリングポリシーを決定することが可能です。スケジューリングポリシーとして、Last-used、least-used、most-used、round-robin、randomly-pickの5つから選択できます。

標準でフォールトトレランス機構が備わっており、Audio、Video Processing、Cluster Managerコンポーネントについては、一つが死んでも、他のコンポーネントに切り替わることにより自動復旧します。

その他のコンポーネントについても、クライアントへ通知して再接続してもらうことにより復旧可能です

かなり高機能のIntel CS for WebRTCですが、クローズドソースという点が問題でした。しかし、Intel CS for WebRTCがOpen Media Streamerという名前でオープンソース化されることになりました。まず去年の12月にOpen Media StreamerのクライアントがGithub上で公開されました。

Open Media Streamerのサーバー側は、今期リリースされる予定です。

Intel CS for WebRTCのオープンソース化は非常に面白い動きだったので、さっそく私もオープンソースで貢献してみました。

まずOpen Media StreamerのiOSクライアントサンプルアプリケーションを作成してみました。

IntelがObjective-C版のサンプルアプリケーションを、そのうち公開する予定ですが、最近はSwiftが主流になっていることもありSwiftでサンプルアプリケーションを作成しました。

それからOpen Media StreamerのNative SDKをDockerでビルドするスクリプトを作成しました。

WebRTCのAndroidライブラリは、Linux上でしかビルドできないといいう制限があるため、MacやWindowsで開発する場合に、このスクリプトが必要になります。

補足

その後、Open Media StreamerがOpen WebRTC Toolkitという名前に変更されたようです。

#cabasecamp 後に追加で次のオープンソースも公開しました。

Intel CS for WebRTCのKubernetesデプロイ環境
弊社ではサーバーのデプロイにKubernetesを使用しているプロジェクトが多いのですが、Intel CS for WebRTCのDockerイメージ作成環境、Helmチャートを作成しました。AWS上のkopsで作成されたKubernetesクラスタにデプロイするチュートリアルも含まれています。
Open WebRTC ToolkitのMCUサンプルアプリケーションKotlin版
最近、弊社でKotlinを使ったプロジェクトが多くなっているため、Node.jsで書かれたMCUサンプルアプリケーションをKotlin + Ktorで書き直したコードを作成しました。

最後に

WebRTCは今でも日々進化していて面白い技術です。WebRTCとは関係ない動画関連のコーディングをしているときもWebRTCライブラリのソースコードは大変参考になっています。今後もなにか面白いことを発見したら情報をシェアさせていただこうと思います。