Simulcast が動いた日

恒例の動いた日シリーズです。

Simulcast は複数解像度、複数ビットレートの映像を出力する機能です。Chrome と Firefox に実装されています。

今回は Chrome から Simulcast で複数の映像を自社製品である WebRTC SFU に配信できたので、それについてまとめていきます。

自社製品の WebRTC SFU Sora はサーバから offer を送りクライアントが answer を返すという仕組みをとっています。そのため Simulcast を受け取れる Offer を投げています。そして配信クライアントは Simulcast 向けの SDP が必要になります。

残念ながら現時点では SDP をクライアント側で無理やり書き換える以外の手はありません。

v=0
o=- 8019123471049418574 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE video_uMs9cb
a=msid-semantic: WMS AWqU2MqZks1ff8twOIEOIff3NaKwI8oGZwkL
m=video 9 UDP/TLS/RTP/SAVPF 120
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:bYbs
a=ice-pwd:LFowwitSR9qxD32H+/W9QadB
a=ice-options:trickle
a=fingerprint:sha-256 13:04:9A:93:EF:77:15:89:80:61:56:85:95:03:3B:A9:30:C6:54:59:CA:D1:F5:8C:6E:8C:11:F4:C0:68:C9:9D
a=setup:active
a=mid:video_uMs9cb
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=sendonly
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:120 VP8/90000
a=rtcp-fb:120 goog-remb
a=rtcp-fb:120 ccm fir
a=rtcp-fb:120 nack
a=rtcp-fb:120 nack pli
a=ssrc-group:SIM 581991945 581991946 581991947
a=ssrc:581991945 cname:+xhg00jf61swepu4
a=ssrc:581991945 msid:AWqU2MqZks1ff8twOIEOIff3NaKwI8oGZwkL bbbbb662-d24d-4afb-a493-fa1983a595ca
a=ssrc:581991945 mslabel:AWqU2MqZks1ff8twOIEOIff3NaKwI8oGZwkL
a=ssrc:581991945 label:bbbbb662-d24d-4afb-a493-fa1983a595ca
a=ssrc:581991946 cname:+xhg00jf61swepu4
a=ssrc:581991946 msid:AWqU2MqZks1ff8twOIEOIff3NaKwI8oGZwkL bbbbb662-d24d-4afb-a493-fa1983a595ca
a=ssrc:581991946 mslabel:AWqU2MqZks1ff8twOIEOIff3NaKwI8oGZwkL
a=ssrc:581991946 label:bbbbb662-d24d-4afb-a493-fa1983a595ca
a=ssrc:581991947 cname:+xhg00jf61swepu4
a=ssrc:581991947 msid:AWqU2MqZks1ff8twOIEOIff3NaKwI8oGZwkL bbbbb662-d24d-4afb-a493-fa1983a595ca
a=ssrc:581991947 mslabel:AWqU2MqZks1ff8twOIEOIff3NaKwI8oGZwkL
a=ssrc:581991947 label:bbbbb662-d24d-4afb-a493-fa1983a595ca

これはクライアントが生成した Offer を書き換えています。今後は SDP を書き換えずに WebRTC API だけでできるようになるといいのですが … 。これを setLocalDescription に指定するだけで Simulcast が利用可能になります。

解像度とビットレート

Chrome の場合はハードコードです。自分が利用可能なビットレートと解像度から勝手に判断されます。

const SimulcastFormat kSimulcastFormats[] = {
{1920, 1080, 3, 5000, 4000, 800},
{1280, 720, 3, 2500, 2500, 600},
{960, 540, 3, 900, 900, 450},
{640, 360, 2, 700, 500, 150},
{480, 270, 2, 450, 350, 150},
{320, 180, 1, 200, 150, 30},
{0, 0, 1, 200, 150, 30}
};

左から解像度 幅と高さで次は配信数で、あとは最大、ターゲット、最小ビットレートです。

解像度は getUserMedia で配信側が取得した解像度が最大のものが使われます。VGA (640x480) を採用すればそれ以下しか配信されません。つまり 640x360 から 0x0 の中から2つということです。HD (1280x720)にすれば 3 つ選ばれます。

これは WebRTC SFU 側で VP8 の解像度をパースして確認したときのログです。3 種類の解像度を表示したログです。

19:31:53.285 [debug] SIMULCAST-RESOLUTION | 640x360
19:31:53.290 [debug] SIMULCAST-RESOLUTION | 320x180
19:31:53.302 [debug] SIMULCAST-RESOLUTION | 1280x720

getUserMedia では HD で、ビットレートは 2500k をサーバから指定しました。見事に 3 種類の解像度が送られてきています。ビットレートは 2500k、500k、150k の三種類になりました。

受信から配信へ

今の時点で実現できているのは Chrome から Simulcast で配信する部分です。WebRTC SFU には最大 3 種類の解像度が送られてきます。

視聴側にはこの3種類の解像度から1つ選んで配信することになります。視聴側から送られてくる帯域推定の結果を見て、指定した解像度の映像のみを送ります。

こうすることで視聴者の帯域が配信者よりも少ない場合でも、視聴者にあった解像度で受信することができます。

WebRTC SFU の課題の解決

Simulcast を利用することで WebRTC SFU を利用した課題を解決することができるようになります。それは配信者と視聴者が同一の待機を保持する必要があるという課題です。

WebRTC SFU は変換しないため、配信者が配信する映像をそのまま視聴者に送ります。配信者の帯域と CPU に余裕があるからと高解像度な映像を送ってしまうと、帯域が狭かったり CPU が弱い視聴者は全く見ることができなくなります。

Simulcast は視聴者の選択肢を増やすことで、視聴者は自分の帯域にあった解像度で映像を見ることができるようになります。

今後に向けて

Simulcast は自分が考えていた技術よりもかなり便利な技術だということがわかりました。むしろ Simulcast 配信はデフォルトでも良いくらいだと考えています。これをマルチストリームなどにも積極的に導入できるように勧めていく予定です。

Erlang/OTP / 時雨堂 / WebRTC / E2EE

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store