新SkyWayでPublish / Subscribeをどう設計するか?実装でハマるポイントまとめ
新SkyWay(@skyway-sdk/room)は、WebRTCの通信を
Publish / Subscribeモデルで扱う設計になっています。
一見シンプルですが、この部分を正しく理解していないと、
- 映像が一部のユーザーだけ見えない
- 後から参加した人に映像が届かない
- 再接続後に通信が壊れる
といった問題が起きやすくなります。
この記事では、Publish / Subscribeの基本と、実装でハマりやすいポイントを整理します。
Publish / Subscribeの基本
新SkyWayでは、通信は次の流れで行われます。
Stream ↓ publish Publication ↓ subscribe Subscription ↓ RemoteStream
重要なのは、
Streamを公開する側(Publish)と受信する側(Subscribe)が分かれている
という点です。
よくある最初の実装
最初に書きがちなコードはこんな感じです。
room.onStreamPublished.add(async (e) => {
await member.subscribe(e.publication.id);
});
新しいStreamが来たらsubscribeする、というシンプルな実装です。
ただ、このままだと不具合が発生します。
この実装の問題点
問題は、
既に存在しているPublicationを拾えない
ことです。
onStreamPublished は、
- 新しく公開されたStream
しか通知しません。
そのため、
- 自分が後からRoomに参加した場合
- 既に配信されている映像
これらは取得できません。
結果として、
- 相手は配信しているのに見えない
- 人によって見える・見えないが発生する
という状態になります。
正しいSubscribeの実装パターン
新SkyWayでは、Subscribeは必ず2段構えにします。
① 既存のPublicationをsubscribe
room.publications.forEach(pub => {
if (pub.publisher.id !== member.id) {
member.subscribe(pub.id);
}
});
② 新規のPublicationをsubscribe
room.onStreamPublished.add(async (e) => {
if (e.publication.publisher.id !== member.id) {
await member.subscribe(e.publication.id);
}
});
この2つをセットで実装するのが基本です。
なぜこの設計が必要なのか
新SkyWayでは、
- PublicationはRoomに存在する
- SubscriptionはMemberごとに作られる
- 自動購読は行われない
という仕様になっています。
つまり、
「何を受信するか」はクライアント側が明示的に決める必要がある
という設計です。
自分のStreamをsubscribeしない
Subscribe処理では、必ずこの条件を入れます。
if (pub.publisher.id !== member.id)
これを入れないと、
- 自分の映像を自分で再生する
- 音声がループする
といった問題が発生します。
UIとSubscriptionはセットで管理する
もう一つ重要なのが、
UIの状態とSubscriptionを一致させる
ことです。
例えば、
- 映像を非表示にした
- 通話UIからユーザーを消した
といった場合、DOMを消すだけではなく、
subscription.unsubscribe();
まで行う必要があります。
これをやらないと、
- 裏で受信し続ける
- 帯域を無駄に使う
- CPU負荷が上がる
といった問題につながります。
再接続時の挙動に注意する
新SkyWayでは、
- Subscriptionは自動復元されない
- Publicationも再利用されない
という前提があります。
そのため、
再接続後は必ずsubscribeをやり直す必要があります
この前提で設計しておくと、後から安定します。
実務で使える実装パターン
実際のプロジェクトでは、次のようにまとめておくと扱いやすいです。
function setupSubscriptions(room, member) {
// 既存のPublication
room.publications.forEach(pub => {
if (pub.publisher.id !== member.id) {
member.subscribe(pub.id);
}
});
// 新規のPublication
room.onStreamPublished.add(e => {
if (e.publication.publisher.id !== member.id) {
member.subscribe(e.publication.id);
}
});
}
これを
- Room参加時
- 再接続時
の両方で呼びます。
よくあるミス
実際にハマりやすいポイントをまとめると以下です。
- onStreamPublishedだけで実装している
- 既存Publicationをsubscribeしていない
- unsubscribeしていない
- 自分のStreamをsubscribeしている
- 再接続時の処理を考慮していない
まとめ
新SkyWayでは、通信は
- Publish(公開)
- Subscribe(購読)
によって構成されます。
そのため、
受信処理は自動ではなく、自分で設計する必要がある
という前提になります。
特に重要なのはこの2つです。
- subscribeは必ず2段構えにする
- UIとSubscriptionを同期する
この2点を押さえておくと、
安定したリアルタイム通信が実装しやすくなります。