Skip to content

Instantly share code, notes, and snippets.

@voluntas
Last active November 2, 2015 07:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save voluntas/7547c305ac7a8a9c62c1 to your computer and use it in GitHub Desktop.
Save voluntas/7547c305ac7a8a9c62c1 to your computer and use it in GitHub Desktop.
WebRTC SFU をフルスクラッチで作ってみた

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

@voluntas

バージョン

0.0.0

url

https://voluntas.github.io/

2015 年 11 月 04 日に行われる WebRTC Meetup Japan 向けの発表資料です。

自己紹介

時雨堂 という零細企業を経営しています。

twitter は @voluntas

モチベーション

  • 日本だと誰も作ってなさそうだったし、面白そうだと思ったから。
  • テレビ会議システムにはあまり興味なく配信システムに興味があった。
  • 音声や映像のリアルタイムな共有に興味があった
  • Erlang による DTLS の実装のめどがついたから。

実装の流れ

DTLS 1.0 を実装する

Erlang には DTLS の実装がまだ公式にないこと、TLS は実装経験があるのでなんとかなると思ってた。前職で UDP 上で TLS を実現する EAP-TLS とかを書いていた。

Chrome がまだ DTLS 1.0 なのでまずは 1.0 から。

UDP なのでシーケンス番号が入ってきたり少しずつ違う。DTLS 1.0 は TLS 1.1 ベース。

CipherSuites は決め打ちした。ECDHE で RSA そして AES-CBC で実装。

実装終わって openssl でテストして動作した。

DTLS 1.2 を実装する

今後考えるとやっておきたい、ということで実装。

ついでに AEAD 認証に対応しておきたい。AES-GCM と CHACHA20 に定める。

実装終わってテスト通った。ただ DTLS 1.0 邪魔だなと思い始める。

全消しして 1.2 のみのコードにする。Chrome は追従するだろうと読む。 Chrome M47 から徐々に DTLS 1.2 になる模様。Firefox はすでに DTLS 1.2 。

SRTP を組み込んだので、ライブラリ的には DTLS-SRTP ライブラリ。

SDP パーサを実装する

投げるにしても受け取るにしても必要ということで作る。文字列はだるい。 いろいろな SDP をパーサに食べさせてテスト、問題なさそうということで完成。

## STUN ライブラリ

すでに実装してたので ICE に対応させて終わり。

RTP ライブラリ

すでに持っていたがいけてなかったのでほぼ書き直し。かなりの頻度で書き直したり機能追加したりした。

SRTP ライブラリ

SRTCP 系の対応が死にそうになる。独自すぎる。一通り退治して実際に WebRTC の SRTP パケットを受け取って無事動く。確認は明らかに変な値じゃないかを確認する。暗号系の怖いところはとりあえず復号はできてしまうところを。

間違ってるかどうかはアプリでしか判断できない。

WebRTC SFU に着手

とりあえず作ったライブラリを組み上げてみる。シグナリングサーバーがいないとダメなので組み上げたらシグナリングサーバーの開発へ。

シグナリングサーバーの開発

SkyWay で経験していたが方向が逆向きなので一から設計。WebRTC SFU では SFU から Offer を出す。

さらに接続の認証方式などをあとで考えられるようにしてざっくり実装。

まずは WebSocket だけで対応。XHR へのダウングレードは後回し。

シグナリングサーバーを組み込む

認証は後回し。動くところまで持っていく。

まずは配信者だけで確認。なんとなくデコードできていそうというところまで持っていく。

次に視聴者を追加。ここで最初に視聴者をつながないと画面が映らないことに気づく。FIR を投げないとダメとアドバイスをいただく。

視聴者の DTLS が完了したタイミングで SFU が FIR を配信者に送る仕組みを入れる。大量接続を踏まえ 500 ms単位で接続を間引きして FIR を送らないようにする仕組みを追加。

無事動作するようになる。

パケットの解析

RTP/RTCP が生で見られるようになったのでパースできてないのを実装したりする。

いつも通り WS デバッガーをくっつけて流れてるパケットを WS で気軽に閲覧できるようにする。

Firefox と Chrome の Application layer な RTCP に対応数。

デモ

ここで WebRTC SFU のローカルでの起動デモを見せる。

WS デバッガーも見せる。

課題

それといった課題はあまりないが、明示的に解決しなければいけないのは RTCP の代理返信。

RTCP 問題

今は RR を全部送ってるので間引きする。間引き後は SR->RR は配信者と SFU で閉じる。視聴者からの RR は SFU で集約して SFU の RR 生成時に全体の総意を汲み取りつつ反映する。

特徴

自社製品の宣伝です

アプリとの連携がキモなので連携部分を重要視した。

ステートフル、データレス

サーバ自体には一切情報を追加したりせず、起動したらすぐ使える。

接続の認証がしたい、チャネル単位で接続数制限がしたい、時間制限がしたい。 全て WebRTC SFU がデリゲーションしてくるので、アプリ側で実装可能。

データを持たないため、台数さえ増やせばいいのでスケールさせやすい。

ストリーム API

WebRTC SFU に WS で接続することで、クライアントの接続や、一定間隔での接続時間の通知などステートが変化したときにストリームでデータを送ってくる。

リアルタイムにアプリ側で判断が可能。

アクション API

SFU に対して叩く API でチャネル単位での全員切断や、指定した接続の切断。さらにチャネルの接続一覧などがとれる。

アプリはストリーム API でリアルタイムに受け取るステート変化に対してアクションを起こすことが可能になる。

イベント API

認証などの同期的に判断が必要なのは指定した HTTP API を叩いてくれ、200 だったら OK という動作をする。

全てアプリ側で判断できるため、データベースに悩む必要が無い。

今後

録画

VP8 であれば WebM 形式での保存を目指す。ただ H.264 がメインになる可能性があるのでまだ様子見。

おもしろい機能ではあるので、対応はしていきたい。

H.264

Chrome が H.264 になると強い。HW が H.264 なのが多いため。

SDP 部分しか影響ないのでそこを接続時に切り替える。

配信者がフォーマットを選べるようにする。

Multistream

閲覧者が複数の配信を Multistream で同時に見れるようにする。

これは複数カメラの配置に対して需要がありそうなので前倒しで実装していく予定。

音声

年末までには実装。別に難しくない。

Simulcast

Firefox に来たらすぐに対応。

TURN/STUN

自前開発があるので、SFU に組み込む。 主に TCP -> UDP への変換が目的になるが、 SFU に組み込むことで TCP -> TURN -> SFU -> UDP みたいにできる。 わざわざ一回ネットワークを経由しなくて良くなる。

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment