05. 購読: SUBSCRIBE と PUBLISH

🎯 この章のゴール

  • 購読(subscription)の状態遷移と、SUBSCRIBE(pull)/ PUBLISH(push)の違いを説明できる
  • Track Alias・Largest Object・Location フィルタを理解する
  • ライブ中のトラックへの 4 通りの途中参加方法を選べる
  • REQUEST_UPDATE による更新・一時停止と、PUBLISH_DONE による終了を知る

💡 ひとことで言うと

購読は「新しく出た Object を届け続けてもらう契約」。どこから届けるか(フィルタ)、どれくらい急ぐか(優先度)を契約時に決め、あとから変更もできます。

購読の状態遷移

購読は SUBSCRIBE(サブスクライバ発)でも PUBLISH(パブリッシャ発)でも始められます。

stateDiagram-v2
  [*] --> Idle
  Idle --> PendingSub: SUBSCRIBE(サブスクライバ)
  Idle --> PendingPub: PUBLISH(パブリッシャ)
  PendingSub --> Established: SUBSCRIBE_OK
  PendingSub --> Terminated: SUBSCRIBE_ERROR
  PendingPub --> Established: PUBLISH_OK
  PendingPub --> Terminated: PUBLISH_ERROR
  Established --> Established: REQUEST_UPDATE
  Established --> Terminated: STOP_SENDING(サブスクライバ)
  Established --> Terminated: PUBLISH_DONE(パブリッシャ)
  PendingSub: Pending (Subscriber)
  PendingPub: Pending (Publisher)
  • 終了はサブスクライバなら STOP_SENDING(リクエストのキャンセル)、パブリッシャなら PUBLISH_DONE を送ってストリームを閉じる
  • REQUEST_ERROR で終わったリクエストでは Object は一切送られない

SUBSCRIBE: サブスクライバから頼む

SUBSCRIBE {
  Type = 0x3, Length,
  Request ID,
  Track Namespace, Track Name,      ← どのトラックか
  Number of Parameters, Parameters  ← どう届けてほしいか
}

主なパラメータ:

パラメータ意味
LOCATION_FILTERどの範囲の Object を送るか(後述)
FILL_PARAMETERS過去分を fill fetch ストリームで補う(06 章)
SUBSCRIBER_PRIORITYこの購読の優先度(0 が最高、省略時 128)
GROUP_ORDERGroup を昇順(古い順)/ 降順(新しい順)どちらで優先するか
FORWARD0 なら一時停止状態で開始(省略時 1)
SUBGROUP_DELIVERY_TIMEOUT / OBJECT_DELIVERY_TIMEOUT遅れたデータを諦めるまでの時間(09 章)
RENDEZVOUS_TIMEOUTパブリッシャがまだいないとき、リレーに待ってもらう時間
NEW_GROUP_REQUEST新しい Group を始めてほしいと依頼(後述)
AUTHORIZATION_TOKEN認可トークン

成功すると、パブリッシャは同じストリームで SUBSCRIBE_OK を返します。

SUBSCRIBE_OK {
  Type = 0x4, Length,
  Track Alias,                       ← データ側で使う短い ID
  Number of Parameters, Parameters,  ← LARGEST_OBJECT, EXPIRES
  Track Properties                   ← 既定の優先度、キャッシュ期間など
}
sequenceDiagram
  participant S as サブスクライバ
  participant P as パブリッシャ
  S->>P: [新しい双方向ストリーム] SUBSCRIBE (Request ID=4, (live, alice) / video, LOCATION_FILTER=Next Group)
  P-->>S: SUBSCRIBE_OK (Track Alias=7, LARGEST_OBJECT={41, 12})
  P->>S: [単方向ストリーム] SUBGROUP_HEADER (Alias=7, Group=42) + Object 0, 1, 2…
  P->>S: [単方向ストリーム] SUBGROUP_HEADER (Alias=7, Group=43) + Object 0, 1, 2…
  S->>P: STOP_SENDING(購読終了)

Track Alias

データストリームやデータグラムは、長い Full Track Name の代わりに Track Alias(数値)でトラックを指します。Alias はパブリッシャが決め、SUBSCRIBE_OK か PUBLISH で伝えます。

  • 同じセッションで、同時に 2 つの異なるトラックに同じ Alias を使ってはいけない(DUPLICATE_TRACK_ALIAS)
  • 制御メッセージより先にデータが届くことがあるので、受信側は未知の Alias のデータをしばらくバッファしてよい

Largest Object

Largest Object は、パブリッシャから見てそのトラックで最も大きい Location の Object です(まだ受信途中かもしれない)。SUBSCRIBE_OK の LARGEST_OBJECT パラメータで分かります。ここから次の 2 つの位置が決まります。

  • Next Object = {Largest.Group, Largest.Object + 1}(何もなければ {0, 0})
  • Next Group = {Largest.Group + 1, 0}

PUBLISH: パブリッシャから押し込む

パブリッシャは PUBLISH で、相手に頼まれる前に購読を始められます。PUBLISH 自体に Track Alias やトラックのプロパティが入っていて、サブスクライバは REQUEST_OK(PUBLISH_OK)か REQUEST_ERROR(PUBLISH_ERROR)で応えます。

  • 遅延を減らすため、PUBLISH_OK を待たずに Object を送り始めてもよい
  • 興味のない PUBLISH には UNINTERESTED で断り、関連ストリームを STOP_SENDING する
  • リレーは、相手が興味を持ち認可されていると分かるまで PUBLISH を送ってはいけない。その意思表示に使うのが SUBSCRIBE_TRACKS などです(07 章)

Location フィルタ: どこから届けるか

LOCATION_FILTER パラメータで、購読が送る範囲を指定します。

Filter Type開始終了
0x00 Noneフィルタなしフィルタなし
0x01 Relative Start{Largest.Group + 1 − StartGroup, 0}無期限
0x02 Absolute Start{StartGroup, StartObject}無期限
0x03 Absolute Start, Group End{StartGroup, StartObject}Group StartGroup + EndGroupDelta の最後
0x04 Absolute Range{StartGroup, StartObject}{StartGroup + EndGroupDelta, EndObject}
0x05 Next ObjectNext Object無期限

Relative Start の StartGroup は「Next Group から何 Group さかのぼるか」です。0 = Next Group、1 = 現在の Group、2 = 1 つ前の Group …… と読みます。

ライブへの途中参加: 4 つのパターン

Group の先頭が参加ポイントなので、「どこから見始めるか」でやり方が変わります。

Group 40Group 41Group 42(未来)Largest {41,12}① すぐ参加(Next Object)② 今の Group の先頭からfill③ 過去の Group からfill④ 次の Group から(Next Group)矢印 = 購読で届く分(subscription-delivered)、帯 = fill fetch ストリームで届く分(fill-delivered)
Largest Object が Group 41 の途中(Object 12)のときの参加パターン
パターンSUBSCRIBE の中身向いている用途
① すぐ参加Location フィルタ = Next Object音声やデータなど、どこからでも使えるもの。Group の途中から届く
② 今の Group の先頭からNext Object + FILL_PARAMETERS(Relative Start、StartGroup=1)映像。キーフレームから復号したい
③ 過去の Group からFILL_PARAMETERS で欲しい Group を指定少しさかのぼって再生、バッファを厚くしたい
④ 次の Group からLocation フィルタ = Next Group次のキーフレームまで待ってもよい、無駄な過去データは不要

Fill の詳しい仕組みは次章で扱います。

Dynamic Groups: 新しい Group を頼む

Group の真ん中で参加すると、②では Group の先頭からのデータを大量に受け取ることになり、④では次の Group まで待たされます。トラックが DYNAMIC_GROUPS プロパティ(値 1)を持っていれば、サブスクライバは NEW_GROUP_REQUEST パラメータで「新しい Group(= 新しいキーフレーム)を始めて」とオリジナルのパブリッシャに頼めます。リレーは同じ依頼を重複して上流に送らないようにまとめます。

購読の更新: REQUEST_UPDATE

購読した側は、同じリクエストストリームで REQUEST_UPDATE を送ってパラメータを変更できます(応答は REQUEST_OK / REQUEST_ERROR)。含めなかったパラメータは変わりません。

  • 一時停止 / 再開: FORWARD を 0 / 1 に。停止中も PUBLISH_DONE などの制御メッセージは届く
  • 優先度の変更: SUBSCRIBER_PRIORITY
  • 範囲の変更: LOCATION_FILTER。開始位置を前にずらすなら FILL_PARAMETERS で過去分を補える
  • 期限の延長: パブリッシャが EXPIRES(ミリ秒)を伝えてきたら、REQUEST_UPDATE(必要なら新しいトークン付き)で延長を頼む

更新が失敗した購読は、パブリッシャが UPDATE_FAILED の PUBLISH_DONE で終了させます。

パブリッシャ側の都合で状態が変わったときは、応答不要の通知 PUBLISH_STATE_NOTIFY で LARGEST_OBJECT・FORWARD・LOCATION_FILTER の現在値を知らせます。

購読の終了: PUBLISH_DONE

パブリッシャは購読をやめるとき、リクエストストリームの最後のメッセージとして PUBLISH_DONE を送ってから FIN します。

PUBLISH_DONE {
  Type = 0xB, Length,
  Status Code,     ← TRACK_ENDED, EXPIRED, TOO_FAR_BEHIND, UPDATE_FAILED …
  Stream Count,    ← この購読のために開いたデータストリームの総数
  Error Reason
}

PUBLISH_DONE は遅れて開くデータストリームより先に届くことがあるので、サブスクライバは Stream Count と受信済みのストリーム数を比べ、一致したら状態を消します(不明ならタイムアウトで消す)。

おまけ: TRACK_STATUS

TRACK_STATUS は「購読はしないけど、今の状態を教えて」というリクエストです。形式は SUBSCRIBE と同じで、パブリッシャは SUBSCRIBE_OK と同じパラメータ(LARGEST_OBJECT など)とプロパティを REQUEST_OK で返し、ストリームを閉じます。

🧪 考えてみよう

ビデオ会議で、画面に表示していない参加者の映像を購読し続けると帯域がもったいない。かといって購読をやめると、再表示したときに購読し直す往復が発生します。こんなときは FORWARD=0 で一時停止しておけば、状態を保ったまま帯域だけを節約できます。再表示するときは FORWARD=1 に加え、NEW_GROUP_REQUEST で新しいキーフレームを頼むと素早く絵が出ます。

📝 まとめ

  • 購読は SUBSCRIBE(pull)でも PUBLISH(push)でも始まり、Established → Terminated へ進む
  • データ側は Track Alias で軽量にトラックを指す。Largest Object から Next Object / Next Group が決まる
  • 途中参加は Location フィルタと FILL_PARAMETERS の組み合わせで 4 パターン
  • REQUEST_UPDATE で一時停止・優先度・範囲を変更、PUBLISH_DONE の Stream Count で後片付け

参考

✅ 理解度クイズ

Q1
購読(subscription)を始められるのは誰?
Q2
Track Alias の目的は?
Q3
今まさに配信中のトラックに「今の Group の先頭から」参加したい。どう SUBSCRIBE する?
Q4
購読を一時停止(pause)するには?
Q5
PUBLISH_DONE に含まれる Stream Count は何に使う?