ここで作ったOSSにScalable Video Coding(SVC)のサポートを入れた.
0.7.1から使えるようになっている.
SVCとは
https://zenn.dev/yohhoy/articles/webrtc-svcext-av1
この辺が参考になる.やりたいこととしては,受信側がPCのスペックや回線スピードに合わせて適切な解像度/FPSで映像を受信するためのものだ.もともとRheomeshではSimulcastをサポートしており,SVCはサポートしていなかった.
Simulcastの場合,本当に複数本の映像を送信側が送る必要がある.高解像度・中解像度・低解像度の映像をそれぞれ送信しつつ,受信側で適切なものを選んで受信させるという方式だ.この場合の問題点は,送信側が3本映像を送らなきゃいけないとういことだ.同じ映像なのに,解像度ごとに2本3本と送る必要が有り,これは結構無駄な気がする.
SVCはこれに対して,送る映像は1本で良い.その中で,空間スケーラビリティ・時間スケーラビリティに分割されたパケットが送られてきて,SFUサーバ側でフィルタリングして受信側に渡してやる.例えば受信側が十分はスペック・回線スピードであれば,すべてのデータを渡すことで,高解像度・高FPSの映像を受信させる.逆に受信側が低スペックの場合であれば,SFUサーバ側で低解像度・低FPSのパケットのみをフィルタリングして送ってやることで,実際に低スペックに合わせた映像を受信することができる.
使い方
配信側
配信側はサーバでの設定は一切不要だ,クライアント側の設定だけで完結する.
https://h3poteto.github.io/rheomesh//pages/02_getting_started/#publish
この例でpublishする際に,
import { SVCEncodings } from "rheomesh"; const publisher = await publishTransport.current!.publish(track, { encodings: SVCEncodings(), preferredCodec: "AV1", });
とすることでSVCが有効なpublisherとなる.ちなみにSVCはAV1もしくはVP9でサポートされている.
SVCEncodings は現状 L2T3_KEY になっているが,別にここは好きに変更してもらっても構わない.型は Array<SVCRTCRtpEncodingParameters> なので,
encodings: [{ scalabilityMode: "L2T3_KEY" }]
みたいな形になっていれば問題ない.
受信側
受信側は,受信クライアントから「どのSID, TIDのパケットを受信したいか」を受け取る必要がある.
exampleでは,このようなWebSocketのメッセージを受信する.
そして,
if let Err(err) = subscriber.set_preferred_layer(sid, tid).await { tracing::error!("Failed to set preferred layer: {}", err); }
こんなメソッドを呼び出してやればよい.これで,このsubscriberは指定されたSID, TIDのパケットのみを受け取るようになる.
今後の予定とか
今のところ受信側が手動で,というか意図的にSIDやTIDを指定して映像を切り替える必要がある.これはこれで必要なシーンはあると思う.例えば特定の映像だけデカく表示したいとか,その他の映像はアイコン程度の大きさで良い場合とかね.
ただ,一般的なミーティングにおけるユースケースだと,いちいちクライアントがどのSID/TIDを指定すべきかの判断材料があまりない.なので,できれば受信側から受け取れるRTCPに含まれる情報から,帯域等のフィードバックを得られれば,それによりSFUサーバ側で自動判定してやるロジックを入れたいとは思っている.そうすれば,送信側でSVC指定するだけで,受信側は自動選択になるはずだ.