11. プロパティ・エラー・拡張性

🎯 この章のゴール

  • Message Parameter と Track / Object Property の違いを説明できる
  • 代表的なプロパティ(優先度の既定値、キャッシュ期間、Gap、Immutable Properties)を知る
  • エラーの 4 つの層と、GREASE による拡張性の確保を理解する

💡 ひとことで言うと

パラメータは「配達員へのメモ」、プロパティは「荷物に貼られたラベル」。メモはその区間の配達員だけが読んで捨てる。ラベルは荷物と一緒に最後まで旅をします。

パラメータ vs プロパティ

Message ParameterTrack PropertyObject Property
付く場所制御メッセージ(SUBSCRIBE など)PUBLISH・SUBSCRIBE_OK・FETCH_OK などの末尾Object ヘッダー
誰向けそのメッセージの相手だけトラックの全受信者Object の全受信者
リレーは転送?❌ しない(参考にはする)✅ する✅ する
未知の値セッションを閉じる(PROTOCOL_VIOLATION)転送・キャッシュする転送・キャッシュする
例SUBSCRIBER_PRIORITY、LOCATION_FILTERDEFAULT_PUBLISHER_PRIORITY、MAX_CACHE_DURATIONPrior Group ID Gap、LOC の Timestamp

SUBSCRIBE や FETCH のパラメータは、届け方(範囲・優先度・タイムアウトなど)を変えるだけで、Object のペイロードを変えさせてはいけません。トラック名がキャッシュキーとして機能する前提(スコープ内の一意性)を守るためです。

draft-22 で定義されているプロパティ

プロパティType対象意味
OBJECT_DELIVERY_TIMEOUT0x02Track / ObjectObject の遅延タイムアウト(09 章)
MAX_CACHE_DURATION0x04Trackキャッシュから配ってよい最大ミリ秒
SUBGROUP_DELIVERY_TIMEOUT0x06Track / ObjectSubgroup の遅延タイムアウト
Immutable Properties0x0BTrack / Object変更不可のプロパティを入れる箱
DEFAULT_PUBLISHER_PRIORITY0x0ETrackPublisher Priority の既定値(省略時 128)
DEFAULT_PUBLISHER_GROUP_ORDER0x22Trackパブリッシャ希望の Group Order(省略時 Ascending)
DYNAMIC_GROUPS0x30TrackNEW_GROUP_REQUEST に対応するか
Prior Group ID Gap0x3CObjectこの Group の前の N 個の Group は存在しない
Prior Object ID Gap0x3EObjectこの Object の前の N 個の Object は存在しない

Key-Value-Pair なので、Type が偶数なら値は vi64、奇数ならバイト列です(04 章)。

アプリ用の予約範囲

0x78〜0x7F(1 バイト)と 0x3800〜0x3FFF(2 バイト)はアプリ専用で、IANA が将来割り当てることはありません。登録なしにフォーマット固有のメタデータに使えます。リレーは意味を解釈せずそのまま転送します。

Gap プロパティ: 「ない」ことを伝える

Object ID や Group ID の飛びは、それだけでは「存在しない」のか「まだ届かない」のか分かりません(03 章)。オリジナルのパブリッシャは Gap プロパティで明示できます。

  • Group 7 の次に Group 10 を出すなら、Group 10 の Object に Prior Group ID Gap = 2(8 と 9 は存在しない)
  • Object 7 の次に Object 10 を出すなら、Object 10 に Prior Object ID Gap = 2

付けられるのはオリジナルのパブリッシャだけで、リレーは追加してはいけません。

Immutable Properties: 改ざんできないラベル

通常のプロパティはリレーが(規則の範囲で)追加・変更できます。オリジナルのパブリッシャが「リレーに見せたいが変えられたくない」メタデータは Immutable Properties に入れます。

Object Header                                    Object Payload
+--------+-------+------------+-------+   +--------------------+
| Object | Ext 1 | Immutable  | Ext N |   | Private Properties |
| Fields |       | Properties |       |   | App Payload        |
+--------+-------+------------+-------+   +--------------------+
                  ^^^^^^^^^^^^              ^^^^^^^^^^^^^^^^^^^^
                  e2e で認証(AAD)           e2e で暗号化 + 認証
Ext 1, Ext N はリレーが変更・削除してよい
  • リレーは中身を読めるが、追加・変更・削除・再シリアライズは禁止
  • そのため暗号化の AAD(認証付き追加データ)に含めて、改ざんを検知できる
  • リレーに見せる必要すらないメタデータは、プロパティではなくペイロードの中に入れる(LOC の Private Properties など、12 章)

Mandatory Track Properties

Type 0x4000〜0x7FFF のトラックプロパティは「理解できないなら扱ってはいけない」必須プロパティです。未知の必須プロパティ付きのトラックを受け取ったエンドポイントは、そのトラックを処理も転送もせず、UNSUPPORTED_EXTENSION で断ります。後方互換性のないトラック形式を安全に導入するための仕組みです。

エラーの 4 つの層

層伝え方主なコード
セッションCONNECTION_CLOSE / CLOSE_WEBTRANSPORT_SESSIONNO_ERROR、PROTOCOL_VIOLATION、INVALID_REQUEST_ID、DUPLICATE_TRACK_ALIAS、GOAWAY_TIMEOUT、TOO_MANY_REQUEST_UPDATES
リクエストREQUEST_ERRORUNAUTHORIZED、DOES_NOT_EXIST、INVALID_RANGE、TIMEOUT、REDIRECT、PREFIX_OVERLAP、UNINTERESTED、UNSUPPORTED_EXTENSION
購読の終了PUBLISH_DONE の Status CodeTRACK_ENDED、EXPIRED、TOO_FAR_BEHIND、UPDATE_FAILED、GOING_AWAY、MALFORMED_TRACK
データストリームRESET_STREAM のエラーコードDELIVERY_TIMEOUT、CANCELLED、SESSION_CLOSED、UNKNOWN_OBJECT_STATUS、TOO_FAR_BEHIND

Malformed Track(不正なトラック)

パブリッシャが MOQT の制約を破ったトラックは Malformed とみなされます。例:

  • 同じ Subgroup の Object なのに Publisher Priority が前と違う
  • Subgroup の最後(FIN の直前)より大きい Object ID が届いた
  • Group の最後(End of Group)より大きい Object ID が届いた
  • 同じ Object なのに中身や Subgroup ID が違う

検出したリレーは MALFORMED_TRACK で購読や FETCH を終わらせます。

GREASE: 未知の値に強い実装を育てる

拡張性のあるプロトコルでも、「未知の値を受け取ると落ちる実装」が広まると、事実上新しい値を使えなくなります(ossification(硬直化))。MOQT は RFC 9170 の考え方に従い、意味のない予約値 GREASE を定義しています。

GREASE 値 = 0x7f × N + 0x9D   (0x9D, 0x11C, …)

Setup Option、プロパティ、各種エラーコード、認可トークンの種類などのレジストリに GREASE 値が予約されています。実装は日常的にこれらを混ぜて送り、受信側は次のルールで扱います。

  • 未知の Setup Option → 無視
  • 未知のプロパティ → 本章の規則どおり転送・キャッシュ
  • 未知のエラーコード → その文脈の INTERNAL_ERROR と同じ扱い(REQUEST_ERROR や PUBLISH_DONE の未知コードでセッションを閉じてはいけない)

🧪 考えてみよう

あなたの会社独自の「シーン切り替えフラグ」を Object に付けて、リレー経由で視聴アプリに伝えたい。どこに入れるのがよいでしょう? リレーが見る必要がなく秘匿したいなら、ペイロードの中に入れます。リレーにも見せたい(例: リレーが切り替え点で何かする)なら、アプリ用予約範囲の Object Property にします。改ざんされたくなければ、それを Immutable Properties の中に入れます。

📝 まとめ

  • パラメータは 1 区間の取り決め(転送されない、未知はエラー)、プロパティはデータの一部(転送・キャッシュ、未知も保持)
  • Gap プロパティで「存在しない」を明示、Immutable Properties で改ざん検知、Mandatory Track Properties で非互換な拡張を安全に導入
  • エラーはセッション / リクエスト / 購読 / ストリームの 4 層。GREASE で未知の値への耐性を保つ

参考

✅ 理解度クイズ

Q1
Message Parameter と Track / Object Property の違いとして正しいものは?
Q2
リレーが知らない(未対応の)Object Property を受け取った。どうする?
Q3
Immutable Properties の目的は?
Q4
GREASE の目的は?