Skip to content

Instantly share code, notes, and snippets.

@voluntas
Last active March 28, 2024 12:31
Show Gist options
  • Star 131 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save voluntas/4d2bd3e878965bdd747a to your computer and use it in GitHub Desktop.
Save voluntas/4d2bd3e878965bdd747a to your computer and use it in GitHub Desktop.
WebRTC SFU コトハジメ

WebRTC SFU コトハジメ

日時

2023-12-03

voluntas

バージョン

2023.1

url

https://voluntas.github.io

この記事が良いと思ったらこの記事に Star をお願いします

depth

2

概要

この資料は WebRTC SFU を 1 から開発した知見を、一般的な WebRTC の知識がある人向けで書いています。

もし一般的な WebRTC の知識を知りたい場合は WebRTC コトハジメ をお勧めします。

自己紹介

株式会社時雨堂 が開発、販売している WebRTC SFU Sora の製品管理者です。 主に製品設計や WebRTC で利用されているプロトコルスタックの開発を担当しています。

どんな感じで作ったのかは別件で話しているので、興味あればどうぞ。

WebRTC SFU をフルスクラッチで作ってみた

注意

この資料はもともと WebRTC Conference Japan 2016-02-16 ~ 17 の発表者向け資料でしたが、 発表後に全面書き直しを行いました。そのため発表当時の資料とはまったく別物になっています。

WebRTC SFU

WebRTC SFU (Selective Forwarding Unit) は全ての通信をサーバ経由で配信する一つの方法です。 今までは MCU が主力でしたが MCU は CPU リソースを消費しすぎることから SFU が注目されています。

簡単な SFU の図

image

マルチストリームの図

image

詳細な SFU の図

image

SFU はサーバサイドで一切映像を加工しません。転送するだけのため、CPU リソースを MCU ほど消費しません。

SFU で一番 CPU リソースを消費するのは暗号です。受信したパケットを復号化して再度暗号化して送信するコストが一番高くなります。

なぜ WebRTC SFU を作ったのか

  • P2P では管理側がコントロールしにくいことから、結局サーバ経由になると考えたから
  • マシンパワーが弱い端末では中継サーバを介してのリアルタイム配信が必要になると考えた
  • サーバでの録画価値の需要が高いと考えた

なぜ MCU ではだめなのか

  • MCU だと合成と変換のために CPU リソースを消費しすぎる
  • MCU だと新しいコーデックへの対応が遅れている
    • VP9 や AV1 に対応している MCU は見たことない
  • MCU はシステムとして提供されることが多く、汎用性がない
    • ベンダーロックが強すぎる

シグナリング

WebRTC SFU でもシグナリングは必要です。ただ通常のシグナリングとは異なります。

通常シグナリングは自分が Offer を生成し、相手に届けて、相手から Answer をもらいます。 SFU の場合は Offer をサーバから送る場合もあります。これは SFU の実装依存になります。

SFU から Offer が送られてきて、 Answer をクライアントが送る図

image

DTLS

メディアチャネル

WebRTC のメディアチャネルは DTLS のハンドシェイクを使用し、 SRTP に使用するマスターシークレットを交換します。 DTLS の Cipher Suite で定義された暗号で暗号化はされません。

そのため、 WebRTC メディアチャネルの通信は DTLS を使いつつも、実際の暗号化は全て SRTP を使用します。

WebRTC SFU では、 DTLS-SRTP という特殊な暗号方式を話せる必要があります。 よく誤解される TURN サーバでは暗号を解いている、というのがあります。 実際は解いていませんが、サーバ経由にすると暗号をほどいているのだろうというイメージがあるのだと思います。

SFU はこれを実際に行っています。

SFU で暗号化の中身を見れているという図

image

TURN は暗号を解いてない図

image

データチャネル

WebRTC のデータチャネルは DTLS ハンドシェイクを使用しそのまま DTLS を利用します。 DTLS 上にのせるプロトコルは SCTP と呼ばれるプロトコルです。

RFC 4960 - Stream Control Transmission Protocol

具体的には データチャネル拡張 over SCTP over DTLS over UDP という構成になります。

SRTP

WebRTC SFU のメディアチャネルで使われている DTLS-SRTP の SRTP は映像や音声のプロトコルである RTP に Secure を付けたプロトコルです。 Secure RTP の略。そのままです。

RTP/RTCP に対して、暗号化を行います。その暗号化を行うための鍵の生成については DTLS で生成したマスターシークレットを使います。

この部分は特に SRTP の RFC から逸脱しておらず、ほぼそのまま適用されており、 WebRTC だから何か特殊なことはしていません。 SIP で使われている SRTP と同様です。ただし暗号方式は AES-CTR か AES-GCM が採用されています。

AES-CTR から AES-GCM への移行はまだ時間がかかっているようです。 もともとこの暗号方式は DTLS の ClientHello 拡張の use_srtp にて定義可能です。 クライアントから提示するため、クライアントが AES-GCM に対応さえすれば、サーバは追従するだけです。

全てのブラウザが使用する暗号鍵は異なります。

image

この暗号部分ですが、 SFU の一番のリソースボトルネックになります。 画質がよくなればなるほどパケットの量は増え、復号化と暗号化の量が増えます。つまり SFU は暗号化さえ耐えきれば良いのです。

とくに AES-CTR の場合は同時に HMAC も利用するためコストが高いと言われています。

SDP

WebRTC SFU では SDP を自前で生成する必要があります。

マルチストリーム

私はマルチストリームは WebRTC のキラー機能だと考えています。 1 つのコネクションに動的に映像や音声を追加したり削除したりするのを気軽にできるからです。

特にマルチストリームは映像や音声を合成できない SFU にとっては、キモとなる技術です。 ここをどのくらい自由度をつけつつも、気軽に使えるようにするかが SFU の差別化となるでしょう。

Multiplexing

WebRTC では RTP/RTCP のポートを節約するための Multiplexing に対応しています。

簡単に言うと RTP と RTCP に使用するポートを同じにするという仕組みです。 もともとは RTP と RTCP のポートは別でした。 RTP のポートに +1 したものを RTCP として使うという感じです。

ただ、その場合はポート番号を使いすぎてしまうことから、一つに節約するという戦略がとられました。RTP/RTCP を一つにする、という仕組みです。さらに、音声と映像の RTP/RTCP も同じにしてしまうという仕組みも追加されました。

つまり本来は 音声で 2 つ、動画で 2 つ使っていたポートを 1 つにまとめるという仕組みです。 これのおかげで複数の DTLS セッションを張る必要もなくなり、一つのセッションを使い回すことができるようになりました。判断は SSRC やペイロードタイプで十分判断できます。

現時点で Multiplexing は普通で、むしろ対応していない方が特殊な状況です。

Negotiating Media Multiplexing Using the Session Description Protocol (SDP)

STUN

WebRTC SFU で STUN は UDP ホールパンチング用に使用します。 基本的に WebRTC SFU 自体はグローバルにいることから、STUN がどうこうというのは基本的にはクライアントが判断するための材料になります。

SFU は送られてきた STUN パケットを送り返したり、クライアントからの Candidate に対して STUN パケットを送ったりします。判断自体は全てクライアントが行うのでサーバが判断する必要はありません。

RTCP

WebRTC SFU を開発する上でコアとなるのが RTCP の生成です。 SFU では RTP をコピーして複数の宛先に転送します。 そのため、受け取り先が複数います。ただもともと WebRTC では相手は 1 人しか想定されていません。そのため、動作に支障が出てきます。

RTCP は主に Sender Report と Receiver Report があります。この中に Feedback Message や Bye などが含まれてきます。 Sender Report は映像や音声を配信している側が、こんな感じで送ってるよと送ったパケット数や時間などを送る仕組みになっています。 Receiver Report は Report Block を利用して、受け取ったパケットの総数やジッターなど実際にどんな状況なのかを伝えていきます。

Sender Report を送った側はそれをみて映像の品質を動的に変更していきます。 動的に映像の品質を変えることで相手の通信状況を考慮した動作が可能になるのです。が、これが SFU ではとても邪魔です。

なぜなら相手が 1 人ではなく N 人になるからです。一人でも回線品質が悪い人がいるとその人に引っ張られてしまうことになります。

RTCP を動的に生成する図

image

マルチストリーム

SDP の部分でも説明しましたがここでもう一度説明します。

マルチストリームは全てのやりとりを一つのポート、つまり一つの DTLS でやりとりを行う技術です。 映像や音声を後から追加したり、流れている映像や通信を削除したりすることもできます。

参加者を動的に追加したり、削除したりを新しいコネクションを張らずに実現できるわけです。

マルチストリームの図

image

複数人数でのマルチストリームの図

image

視聴者との直接やりとり

マルチストリームを上手く活用することで、接続を増やすことなく、切断することなく、 今視聴者として参加している人を配信者として動的に参加させることが可能になります。

マルチストリームは配信者と視聴者を動的に切り替えたりすることができるようになるのです。

最初は一人だけが配信してそれ以外は視聴者

image

その後、誰かが質問をしてきたので、見ている人全員にも見えるようになる

image

質問が終わったので質問した人は視聴している一人になる

image

このように動的に配信者を参加させることが可能になります。

サイマルキャスト

サイマルキャストは複数画質の映像を配信側が送りつける方式です。 この方式を使う事で SFU では回線速度が遅いクライアントへは低画質、回線速度が早いクライアントへは高画質の映像を配信するといったことが可能になります。

この技術は SFU の課題であった全員に同一画質しか送れないという問題を解決します。

image

現時点では主要なブラウザすべて RFC 準拠のサイマルキャストを実装しています。

録画

WebRTC をサーバ経由で扱うメリットの一つとしてあげられるのが録画機能です。 クライアントで録画する機能はそもそも WebRTC が API の一つとして提供しています。

録画はその処理をサーバ側で行う機能です。サーバはパケットを受信したら暗号を復号して、暗号化してから送信しています。 そのためサーバには暗号化されていないパケットが存在できます。

よく誤解されますが TURN サーバの場合は暗号化されたパケットをそのまま流れます、そのため TURN サーバは何が流れているかを把握できません。

録画は WebRTC で配信をするにあたり、様々可能性を持っています。リアルタイムという遅延の少ない世界で見る映像を後出しで見ることができるようになるためです。

遅延が少ない世界と、遅延を気にしない世界の両方に存在できるようになります。

TURN

グローバルに存在する WebRTC SFU といえども、 TURN は必要になる場合があります。それは TCP や TLS しか使えない世界だったりする場合です。 もちろん UDP の場合でも TURN が必要になる場合もありますが、ほとんどの場合は TCP や TLS での配信が求められるために必要となるでしょう。

ただ、今後は TCP のためだけに TURN サーバを立てる必要もなくなるかもしれません。

ICE-TCP

ICE というのは STUN と TURN を合わせた仕組みを指しますが、 ICE-TCP という技術があります。これは Chrome では有効になっています。

実は WebRTC SFU は ICE-TCP との相性がとても良いです。

TURN-TCP を使うにはまず STUN を TCP で繋げられるようにする必要があります。WebRTC SFU として ICE-TCP を採用すると TURN サーバが不要になります。 ただし、実装としては TCP というワンクッションが一度入ります。

TCP で SFU がパケットを受け取ってその中のパケットをは DTLS-SRTP なのです。 つまりただの TCP のトンネルを SFU にはるだけです。その中を普通に DTLS-SRTP パケットを投げつけてきます。

これで UDP が通れない場合や、TCP で 443 番しか空いていない場合とかも解決です。

image

SFU に求められる機能

WebRTC SFU は MCU と比較すると様々な点で弱い点がありますが、そこを補うために MCU でも利用されている仕組みを求められます。

マルチストリームへの対応

合成を行わない SFU ではマルチストリームへの対応は必須です。

サイマルキャストへの対応

画質をユーザごとに選べない SFU ではサイマルキャストを利用した画質選択機能は必須です。

動的なビットレートの変更

配信者の回線が不安定だったり、マシンスペックが低いと判断したら、動的に配信するビットレートを変更する機能です。

もともと P2P では実現している機能を SFU でも実現する必要があります。

この機能を実現することで MCU が得意とする会議システムへでの採用が増えると考えています。

音量により配信する音声や映像を制限する機能

配信するクライアントが 10 名になると WebRTC SFU の場合は受信する音声や映像が 9 名分になります。 これは受信するクライアントの負荷がとても高くなります。

そのため直近の音声を発した人 3 名程度のみの音声や映像を配信し、それ以外を配信しない仕組みを導入することで負荷を大幅に下げることが可能になります。

この機能を実現することで MCU が得意とする会議システムへでの採用が増えると考えています。

外部連携機能

SFU は音声や映像を変換する機能を持っていません。そのため大規模な配信を行うことは難しくなります。

そこで外部のツールと連動し、 WebRTC to HLS/MPEG-DASH といった大規模への配信を実現するような仕組みが必要になります。

広告

WebRTC SFU Sora

WebRTC SFU Sora

商用の WebRTC SFU です。価格は同時 100 接続で年間利用料ライセンス 84 万円です。 毎年かかります。製品のサポート料金込みです。200 接続だと年間 168 万円です。

複数人数での会議や、 数百人への配信、一対一の面談など様々な用途に利用可能です。

パッケージで提供しますので、自社で運用が可能です。 AWS だろうが GCP だろうが、オンプレだろうがなんでも好きな環境で動かすことができます。

サーバさえあれば起動までは 30 分です。デモ機能が内蔵しているので確認が簡単です。

  • SDL を利用した送受信対応 Momo と合わせて利用可能です
  • 大変多くのお客様に採用いただいております
  • とにかく 落ちないこと を目的に作っています
  • とにかく 繋がること を目的に作っています
  • とにかく 手間がかからないこと を目的に作っています
  • 最新ブラウザのアップデートに追従しています
  • シグナリングサーバ内蔵ですので別途立てる必要はありません
  • TURN サーバ内蔵ですので別途立てる必要ありません
  • 日本語によるサポート対応しています
  • フルスクラッチ自前実装なのですべて把握しています
  • 1:1 の双方向に対応しています
  • 1:1000 の片方向に対応しています
  • 3:1000 といった配信者が複数の片方向にも対応しています
  • スポットライトという機能を利用することで 200 人以上の会議に対応しています
  • 録画機能があります
  • Chrome / Firefox / Edge / Safari といった主要ブラウザ全てに対応しています
  • Apache 2.0 ライセンスで様々なクライアント SDK を公開しています
  • 既存システムとの連携を重視しており、Web フック機能を利用して簡単に連携が可能です
    • 認証や、クライアントの接続切断などもすべて HTTP での通知を既存のシステムに送ることができます

興味のある方はお気軽に sora at shiguredo.jp までお問い合わせください。

紹介や検討資料も公開しております。

Sora Cloud

Sora Cloud

  • 同時接続数と帯域で課金する Sora のクラウド版です
  • 転送量や利用時間におびえることなく利用可能です
  • Sora の運用から解放されます
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment