Slide 1

Slide 1 text

MoQとか勉強会#2 ucchy, tetter

Slide 2

Slide 2 text

- 自己紹介 - 基本仕様ふりかえり - メッセージ編 - シーケンス編 - 最新仕様紹介 - ハッカソンへの取り組み - おまけ 本日の流れ

Slide 3

Slide 3 text

自己紹介

Slide 4

Slide 4 text

SkyWayのWebRTC Researchチーム - 現メンバー - ucchy(@yuki_wtz) - tetter(@tttr_mt) - 旧: y-i(@Kanki2rui) - チームの役割 - 競合調査・業界調査を通してプロダクト方針に口を出す PdM補佐かつR&Dの役割を持つ - イメージ - Cybozu様のフロントエンドエキスパートチーム - WebRTC分野であること・プロダクト方針の寄与する比重が重いのが違い - 具体的な仕事 - 競合のリリースノートやWebRTC関連イベントから得られる示唆をチームに還元する - 社内で50回以上の動向調査共有会を開催 - SkyWayの新機能のための競合調査・ユーザーインタビュー・ PoC開発・正式版設計 - WebRTCの統計分析サービス - ノイズキャンセリング - 最先端技術の調査やPoC開発 - MoQTはココ

Slide 5

Slide 5 text

Media over QUIC Transportに対する我々の考え - WebRTCを適用するユースケースが年々広がっているものの、 P2P前提な仕様やカスタマイズ性の低さ などが気になっていた - WebRTC界隈ではWebRTCのカスタマイズ性向上が重要視されている - KrankyGeekやRTC@Scaleは毎年WebRTCのカスタマイズの話ばかり - ex) keyframeじゃなくてLong Term Reference使ってパケロス耐性を向上させる - ex) bluetoothで視聴only -> 発話モードに切り替えた時にプロファイル変更がされて音質が 下がる問題を独自プロファイルで対処する - ex) ノイズキャンセリング処理を無理やり挟み込む - しかし、WebRTCのカスタマイズ性向上のための機能 (EncodedTransformやRTP Transport)が全 ブラウザで使えるようになるのがいつになるのか分からない - ブラウザが対応しないと (頑張っても)Nativeアプリにしか導入できない - Media over QUIC Transportではこれらの問題に (結果的に)対処できる可能性が高い - (今はライブ配信の比重が大きいが、一応ウェブ会議もユースケースには入っていた )

Slide 6

Slide 6 text

Media over QUIC Transportへの取り組み - 幾つかの目的でMoQTへの取り組みを開始 - (SkyWayはHLS/WebRTC配信を提供しないため )ライブ配信のユースケースと課題を理解する - SkyWayのカスタマイズ性向上のための素振り - MoQTがWebRTCを置き換えてしまうならそれはそれで - そうでない場合もMoQTで自前構築した経験は WebRTCにもそのまま流用できる - 2023年の半ば頃からy-iが初期開発を担当(draft-00 ~ draft-01) - 2024年からucchy / tetterが引き継いで開発(draft-01 ~ draft-07) - ~2024/09 手元でmetaのmoq-go-server/moq-encoder-playerと相互接続試験 -> OSS化 - 2024/09~ IETF121に向けてdraft-06実装 - 2024/11 IETF121(tetter参戦)

Slide 7

Slide 7 text

各種メッセージ (draft-06までで重要だったもの)

Slide 8

Slide 8 text

SETUP - CLIENT_SETUP / SERVER_SETUPの二つがある - 仕様では書かれていないが基本的にはCLIENT_SETUP -> SERVER_SETUP - CLIENTが対応versionを記載してSERVERが確定させる - 仕様的に Supported Version (i) になっているので単数に見えるがいずれ複数になりそう - Paramertersの種類 - ROLE: Pub/Sub/PubSubを指定する(不要論が出ていて議論になっているらしい) - PATH: QUICの時のみ使う。WebTransの場合はURL指定で問題なく動く - MAX_SUBSCRIBE_ID: Subscriberに最大Subscription数を伝える

Slide 9

Slide 9 text

ANNOUNCE - PublisherがTrack名前空間をアナウンスするためのメッセージ - TrackNamespaceは告知するがTrackNameは告知しない - SUBSCRIBEの時にはTrackNameまで指定するので、何かしらの方法でTrack名を知る必要がある - メディア情報を配布するためのCatalogによって知る想定 - Catalogは`Catalog`というTrackNameで一つのTrackとしてSubscribeできる。SubscriberはまずこのCatalogを SubscribeしてTrackの情報を知る - Parameters - AUTHORIZATION_INFO: Trackレベルで認証情報を設定できる

Slide 10

Slide 10 text

SUBSCRIBE_ANNOUNCES(06ではSUBSCRIBE_NAMESPACE) - Subscriber側が、受け取りたいANNOUNCEをフィルタするためのメッセージ - このメッセージが無いと、ANNOUNCE全てをSubscriber側に送ることになる - Track NamespaceのPrefixを指定し、そのPrefixにマッチするものはSubscriber側にも伝達される - 複数のSUBSCRIBE_ANNOUNCESでTrack Namespace Prefixが被った場合にはエラーを返す - `hoge/fuga` と `hoge/` が指定された場合など

Slide 11

Slide 11 text

SUBSCRIBE - Track Namespace / Track Nameを指定してSubscribeを開始する - SubscribeID: そのセッション内に存在するSubscriptionを見分けるも のであって他のSubscriberとは個別のもの - Track Alias: OBJECTを送信する際にオーバーヘッドを減らすために 設定するIDのようなもの - Subscriber Priority: そのセッション内に存在するSubscriptionの優先 順位を設定するためのもの(0が最優先) - 但し、Controlメッセージ(OBJECT以外)はOBJECTよりも優先さ れる - Filter Type: 受け取りたいOBJECTの指定方法 - LatestGroup - LatestObject - AbsoluteStart - AbsoluteRange - StartGroup/StartObject/EndGroup/EndObject - FilterTypeがLatestGroup/LatestObjectの場合は全てNone - FilterTypeがAbsoluteStartの場合はStartGroup/StartObjectの みを指定。EndGroup/EndObjectはNone - FilterTypeがAbsoluteRangeの場合は全て指定

Slide 12

Slide 12 text

DataStreams(旧OBJECT) - ControlMessage系とは異なり、unidirectional streamもしくはDatagramを用いてやり取りを行う - Datagramで送るかStreamで送るかで2種類の送信方法がある - StreamはTrackとSubgroupで2種類のデータ構造にさらに分かれる - 06 -> 07でSubgroupのみになった。 - つまり06時点では3種類の方法がある。 Object Forwarding Preferenceという名前で区別される - Forwarding Preference = Datagram - Forwarding Preference = Track - Forwarding Preference = Subgroup - 07のタイミングでForwarding Preference = Trackは消滅 - Subgroupが複数なかったとしても Subgroupが一つとして使えるため。大は小を兼ねる

Slide 13

Slide 13 text

DataStreams(旧OBJECT) - Datagramの場合は一つのDatagramで全ての情報が含まれるように設計されている - Streams(Track/Subgroup)の場合はHeaderとObjectで分けるように設計されている - HeaderはSTREAM_HEADER_TRACKとSTREAM_SUBGROUP_HEADERでそれぞれ定義

Slide 14

Slide 14 text

DataStreams(旧OBJECT) - Streamの際のObject本体では、Payload Length = 0の時にObject Statusを送信する。 - Payload Length = 0な理由を伝達する - Normal object - Object does not exist - Indicates end of Group - Indicates end of Track and Group - Indicates end of Subgroup

Slide 15

Slide 15 text

シーケンス

Slide 16

Slide 16 text

SETUPシーケンス - Client(Publisher/Subscriber)がサーバーにCLIENT_SETUPを送ることでセッショ ンの初期化を完了させる

Slide 17

Slide 17 text

ANNOUNCEシーケンス - Original PublisherがANNOUNCE - SUBSCRIBE_ANNOUNCESをしていた場合はそれに マッチするANNOUNCEをSubscriberが受信

Slide 18

Slide 18 text

SUBSCRIBEシーケンス - relayがまだupstream subscriptionがない場 合は、end subscriberからのSUBSCRIBE メッセージをトリガーにupstream subscription を生成し、生成できたらend subscriberに SUBSCRIBE_OKを返す - relayが既にupstream subscriptionを持って いる場合にはend subscriberからの SUBSCRIBEメッセージにSUBSCRIBE_OK を返す

Slide 19

Slide 19 text

DataStreamsシーケンス - Datagram / StreamでOBJECTを送信。

Slide 20

Slide 20 text

Endシーケンス - EndSubscriber起因の終了 - subscriberがUNSUBSCRIBEによって OBJECTの送信停止をpublisherに依頼す る - publisherはSUBSCRIBE_DONEをレスポ ンスとして返す - OriginalPublisher起因の終了 - publisherがSUBSCRIBE_DONEを送信し て特定のSubscriptionを終了させる - 新規のSubscriptionをさせないために publisherがUNANNOUNCEを送信し、 subscriberがANNOUNCE_CANCELをレ スポンスとして返す

Slide 21

Slide 21 text

Endシーケンス - SUBSCRIBE_DONEはSubscriptionを終了させる ためにpublisherが送信するもの - subscriberが送ってきたUNSUBSCRIBEに 対するレスポンスとしても使う - SUBSCRIBE_DONEのStatusCode - Unsubscribed - Internal Error - Unauthorized - Track Ended - Subscription Ended - Going Away - Expired

Slide 22

Slide 22 text

最新仕様

Slide 23

Slide 23 text

draft-06, 07の要点 - SUBSCRIBE_ANNOUNCES (06で追加) - FETCH (07で追加)

Slide 24

Slide 24 text

SUBSCRIBE_ANNOUCES (旧名: SUBSCRIBE_NAMESPACE) - 事前にSub側からPub側に興味があるANNOUNCEをPrefixで指定できる - 05ではANNOUNCE時に持っているTrack Namespaceをすべて渡すしかなかっ たので、全てのNamespaceは必要ないユースケースで困るため導入 - 現状これを使わなくてもANNOUNCE可能なので、おそらくこうなる - Pub → Relay: - Namespaceの数はあまり多くないので全部渡されても困らない - SUBSCRIBE_ANNOUCESを待たずに持ってる Namespaceをすべて渡す - Relay → Sub - Namespaceの数が膨大になっている可能性があるので全部渡されると困る - SUBSCRIBE_ANNOUCESが届いたら当てはまるものを ANNOUNCEする

Slide 25

Slide 25 text

FETCH - SUBSCRIBEで取れる範囲を未来と過去に分けることに - 未来: SUBSCRIBE - 過去: FETCH - メッセージフォーマットはほぼ同じ draft-06 draft-07

Slide 26

Slide 26 text

IETF121での主要なトピック - JOIN - Priority update - SWITCH - WARP update

Slide 27

Slide 27 text

JOIN - SUBSCRIBEとFETCHを分けたことで、過去から未来にまたがる再生どうするの 問題が発生 - これまでもFETCHのendを99999…にするといった案はあったが微妙だった

Slide 28

Slide 28 text

JOIN - SUBSCRIBEとFETCHを上手く組み合わせても2回分のRTTが発生して微妙

Slide 29

Slide 29 text

JOIN - 解決するために2種類の提案があった - JOINという新たなAPIを定義する - FETCHにJOINするパラメータを追加する

Slide 30

Slide 30 text

JOIN - FETCHではSUBSCRIBEで使用していたPriorityが平坦化されるので、レイヤを分 けて送信し即座に再生する特徴のあるコーデック、例えばkSVCは難しいんじゃな いか?という声 - SVC使用しない95%はカバーできるはず - これは線形にエンコードしていると理解できる場合に有効なオプションである - なのでSub側が理解するための情報を与えることができるようにすべき - 投票の結果、JOINを追加するよりもFETCHを拡張する提案の方が人気

Slide 31

Slide 31 text

- Priorityには、複数のTrackのSubscriber Priorityが等しければその都度最も高い Object (Subgroup) Priorityを持つTrackを選択するという仕様があるが計算コスト が高いと指摘されているのでPriority自体を再考したいという話 Priority update

Slide 32

Slide 32 text

- 2つの提案があった 1. 暗黙的なmax (Object Priority)ではなく明示的なPublisher Priorityを使用する 2. Subscriber PriorityとSubgroup Priorityから選択し、もし一緒だったら以下の順で処理 - 同Track: Track毎に設定されたGroup Orderで指定された次のGroupを選択 - 同Track&Group: Subgroup IDを元に選択 Priority update

Slide 33

Slide 33 text

- 提案1はdelivery timeoutを使用すればBaseレイヤを手に入れる事ができる - ただ、提案2はそもそもBaseレイヤを優先するようにできており単純なので賛同の 声が多い - Subgroupと複雑なPriorityやめてTrack毎でレイヤ分ければという声も Priority update

Slide 34

Slide 34 text

- ABRを簡単に実現するための提案 - Latest Group使えば取れるのは もっと前のObjectになるのでは? (心の声) と思ったけど関連Issue あったので後ほど紹介 SWITCH

Slide 35

Slide 35 text

- Subscribe IDを使い回すの?という声 - Track Aliasを変えて見分ければ良い (Track Aliasを用意していた意味が出てきたね ) - 通信状況良くなったから次のGroupから解像度上げるならわかるが、通信状況悪く なったらObject取れないので前のGroupから取るべきでは?という声 - その場合はSWITCHではなくてFETCHで取るべき - 似た仕組みを実際に実装して上手くいったという人もいるので、実際に効率よく切り 替えできるか確認することに - 仮にdownsrtream側の通信状況が変化したからといってupstream側まで影響させ て良いのか?サイマルキャストなら刺さりそうだけど (心の声) SWITCH

Slide 36

Slide 36 text

(Boston) Interimで決まっていた前提 - Catalogは独立したdraftではなくWARPへ統合する - LOCをWARPにおけるメインパッケージにする - CMAFはWARPの拡張の位置づけにする WARP update

Slide 37

Slide 37 text

InterimからIETF121の間の出来事 - Catalogをmediaへ特化するために項目を削っている - CMAFも削った (別のdraftへ載せる予定) - MOQ-MIが出てきた - WCPというパッケージも定義しているし WARPと競合してる? WARP update

Slide 38

Slide 38 text

- MOQ-MIをWARPとマージするのか、WARP-MIを作るべきなのか、WARPとして はどうしたら良いのかという話 - MOQ-MIサイドとしてはただMoQアプリの相互接続に関してメモを残して置きた かっただけで、競合させるつもりはなかったとのこと - WARPはMOQ-MIとマージはせずにCall for Adoptionへと進む予定 WARP update

Slide 39

Slide 39 text

まとめ - SUBSCRIBEをSUBSCRIBEとFETCHに分けたことで考慮しなければならないこと が増えている - Subgroup, Priorityなどの複雑かつ特殊なユースケースへの対応で議論が非常に ややこしくなっている - WARPはCatalog & LOCをマージしてもうすぐWG draftになるだろう - 以前と比べて大分形が変わっている気がするが

Slide 40

Slide 40 text

その他 - Interimが増えてコンセンサス取るの難しいからQUIC WGのやり方を一部借りるら しい - Relayのbuffer内でDURATIONとかDERIVERY_TIMEOUTとか管理しやすくする ためにObjectにTimestamp入れるのはどうかという提案 - 5G対応としてUPFにRelayを置きたいのでPDU Setを格納するための領域がほし いという話 - LOC draftがアップデートしており、MoQのHeader ExtensionにHeader格納したい という話

Slide 41

Slide 41 text

最近気になっているIssue / PR - #502: Extensible Object Headerを追加する予定 - SETUPにREQUESTED-EXTENSIONパラメータを追加してネゴシエートする - #598: SUBSCRIBEが未来と言いつつ少し前も取得してるよね - Latest Groupで取得すると現在の Groupの最初 (つまり過去) のObjectから取得を始める - 結論は出ていないが、 JOIN(0)もしくはSUBSCRIBE+FETCH(0)で対応する形になるかも? - #603: ROLEが活用されてないのでとりあえず消してみる - #607: Group Orderって本当に必要?DSCって使う? - (Group Order: 送信できるGroupが2つ以上あるときにどちらから送るべきか指定できる ) - 元々Twitchがライブエッジに追いつくための仕組みで tail dropに使っていた - SUBSCRIBEに関してはDERIVERY_TIMEOUTがカバーするようになったので不要 - FETCHでは巻き戻しに対応するために必要 - #612: SubgroupのことをうっかりPeepと呼んでしまってる

Slide 42

Slide 42 text

IETFへ向けた取り組み

Slide 43

Slide 43 text

短期間で01 -> 06対応 - IETF121へ参加することが決まったときはまだdraft-01の状態 - 06対応を始めたのは9/25 → 約5週間 - 機能単位でチケット化してみたら約100件 diffはこんなのが続いてる オワタ\(^o^)/

Slide 44

Slide 44 text

それでも何とか対応 - 全機能は無理なので優先度をつけて対応 - IETFの1週間前に07が出てきたが完全無視 - 実現性 >>> 保守性

Slide 45

Slide 45 text

間に合ったけど... - 主要な機能は実装できて無事IETFには参加できた (後述) - でもコードがひどいことに... - 一部1000行超えのファイル爆誕 - 変数名も曖昧なのばかり - 関数も一つ一つが大きすぎる - 今月中にはリファクタ終わらせてmasterへマージしたい

Slide 46

Slide 46 text

苦労したところ - SUBSCRIBEが大成長した - 当時Pub <- Track <- Subという形で管理していたが肥大化しすぎた - Pub <- Subscription <- Track, Sub <- Subscription <- Trackの2つに分離させ、Relayに応じて Pub/Subのリストを管理する形式に変更 draft-01 draft-06

Slide 47

Slide 47 text

苦労したところ - Stream per Trackに頑張って対応した - 01ではObject毎にStreamを立てる仕様 - 06ではDatagramもしくはStream (Track毎に立てるパターン、 Subgroup毎に立てるパターン ) - それぞれ頑張って対応したが、 07で消えてる... draft-06 draft-07

Slide 48

Slide 48 text

ハッカソンについて

Slide 49

Slide 49 text

概要 - draft-06実装を持ち込みInterop Testに参加 - 実装の一部を07へアップデートし、試験表に名前を載せることができた どんな問題が起きたか紹介 現在の試験表

Slide 50

Slide 50 text

Interop Testの中で起きた問題の例 - MAX_SUBSCRIBE_IDの初期値 ( = 0) でSETUPしてしまっていた

Slide 51

Slide 51 text

Interop Testの中で起きた問題の例 - PublisherがGroup Order = 0を返してしまっていた ← SUBSCRIBE_OK ← SUBSCRIBE

Slide 52

Slide 52 text

Interop Testの中で起きた問題の例 - 一人の参加者のclientがSNIを実装しておりエラーになった - 後々調べたところserver_nameに対してIPアドレスを設定するのは無効のため、 moq-wasmが使用しているライブラリが弾いていた (ライブラリバージョンが古かったためアップデートしたら改善した ) global IP

Slide 53

Slide 53 text

Interop Testの中で起きた問題の例 - 接続トライしてくれた参加者のメッセージフォーマットが古かった ← 成功パターン ← 失敗パターン

Slide 54

Slide 54 text

Interop Testの中で起きた問題の例 - 接続トライしてくれた参加者のメッセージフォーマットが古かった ← 失敗パターン ← 成功パターン 06からはPayloadの頭にlengthを入れなければならない

Slide 55

Slide 55 text

学び - MoQ以外にもQUICとかSecurityとかちゃんと学ぼう - Historyちゃんと見ておけば07が出ることは気づけたよね IETF121 IETF120 IETF119 IETF118 今見てみると規則性しかない...

Slide 56

Slide 56 text

おまけ

Slide 57

Slide 57 text

Media over QUICの変だと感じたところ - Interim多すぎ問題 - 2週間に1度開催されてる - 回によっては6〜7h x 2日間とかもある (Boston) - これを全部見ないと全貌にたどり着けない - 基本Meetingの時間が足りなくてみんな早口すぎる - 明確なシーケンスや状態の定義がない - issue#402で進んでいるっぽい - App (WARP) も同じWGで面倒見るのは大変

Slide 58

Slide 58 text

みんなどうやってる? - draftを追いかけて実装を進めること自体が大変 - 複数人で高速でプロトタイピングを回していくのも大変 疑問 - 実現性と保守性はそれぞれ何割くらいで意識すれば良いのか? - そもそも2つ先のdraftのことが読み切れないので実装捨てる覚悟で書く? - draft実装ではどれくらいテスト実装すべきなのか?

Slide 59

Slide 59 text

IETF122へ向けた動き - まずはとにかくリファクタリング - WARPアプリを開発 - Catalog - LOC - 07, 08, (09) 対応