ぽっと通話のしくみ

ぽっと通話は、運営が通信経路としてのサーバを持たない音声通話です。配っているのは静的な HTML 1 枚で、声も、相手探しも、在室の合図も、運営の設備を通りません。このページはその「どうやって」を、リポジトリを読む手前の粒度で書いたものです。

1ファイル(通話アプリ本体 index.html)
1依存ライブラリ(Trystero)
0運営のサーバ(通信経路として)
80+自動テストの判定(回帰テスト)

1. 全体像

公開 Nostr リレー 相手探しの合図だけ(第三者) あなたのブラウザ index.html を開いただけ 鍵・署名・音声処理はここ Cloudflare TURN 中継 ふだんの声の通り道。中身は読めない 相手のブラウザ 同じ index.html 声(WebRTC・暗号化) 直接接続(中継が使えないときだけの予備) pot-turn(運営の Worker) 中継の合鍵を配るだけ。声は通らない

太い線=声(ふだんは中継を通る。相手にあなたの IP は見えない)、点線=合図、薄い点線=中継が使えないときだけの直接接続。運営が動かしているのは破線の枠の Worker だけで、それは両方のブラウザに短命の鍵を発行するだけです。

ブラウザに読み込まれるのは index.html 1 枚と、実行時に CDN から読む Trystero というライブラリだけです。ビルドも、パッケージ管理も、バックエンドもありません。

2. 相手を見つける

同じ部屋を開いた人どうしが出会うには、どこかで「私はここにいます」と合図を交わす必要があります。ぽっと通話はそれを公開の Nostr リレーで行います。Nostr は署名付きの小さな JSON を公開リレーに置いて購読する仕組みで、誰でも運営でき、誰のものでもありません。

3. 声の通り道

声は WebRTC で、ブラウザどうしを直接つなぎます。音声は DTLS-SRTP で暗号化され、途中に運営のサーバはありません。

4. ロビーもサーバなし

「通話中の部屋」の一覧も、集計サーバはありません。ページを開いた人は全員が __lobby__ という隠し部屋の WebRTC メッシュに入り、通話中の人が数秒ごとに在室(部屋 ID・名前・人数・話題タグ)を流します。各自のブラウザがそれを集めて一覧にしています。「いま見ている人数」も同じメッシュのピア数です。

この方式は同時閲覧者が数十人で頭打ちになります。伸ばす必要が出たら、運営サーバを立てるのではなく、在室を公開 Nostr リレーに直接流す方向に倒す、と決めています。

5. 部屋の正体

6. 配信部屋と署名

「主だけが話し、ほかは聞く」を、サーバの権限管理なしで成立させています。

7. 無視は受け取る側で完結

「この人の声を受け取らない」は、相手に何も送らず、自分のブラウザがその人からの音声・ひとこと・相づちを描画しないだけです。接続は切りません(切るとライブラリが即座に張り直すため、実測で捨てた案です)。配信部屋の名簿も同じ関門を通るので、「誰の音を鳴らすか」を決める場所はコード上一か所です。

8. 人数の上限

接続はフルメッシュで、全員が全員につながります。接続数は人数の二乗で増え、音声も人数分アップロードするので、上限を明示的に置いています。

部屋の種類上限快適な範囲
雑談部屋8 人4〜6 人
配信部屋15 人主 1 人+聞き役

満室のとき抜けるのは、あとから入った側だけです(全員が同じ判定を回すと全員が抜けてしまうため、到着順で決めます)。大人数化には SFU(音声を集めて配り直すサーバ)が要ります。それは設備を持たない設計の外側なので、いまは上限のほうを選んでいます。

9. 在室の合図(バナー)

通話中は、その部屋が「いま開いているか」を外のページ(はじめにのバナーなど)が表示できるよう、在室を公開 Nostr リレーに 30 秒ごとに流します。載せるのは部屋名の SHA-256 ハッシュと絵文字だけで、部屋名も人の名前も送りません。リレーは保存しない種類のイベント(ephemeral)を使い、鍵はページごとの使い捨てです。

ハッシュなので、部屋名を知っている人だけがその部屋を見張れます。全部屋の一覧を第三者が覗くことはできません。バナー側は購読するだけで、運営サーバは介しません。

10. スマホ向けの工夫

ぽっと通話の設計の芯は、運営が動かす設備を可能な限りゼロにしたまま、通話を成立させることです。配るのは HTML 1 枚。相手探しは公開リレー、声はブラウザどうし、中継は第三者、ロビーは参加者のブラウザのメッシュ。運営のコードで動いているのは中継の鍵を配る小さな Worker だけで、通信そのものはどこも通りません。

この形にすると、いくつかのことが自然に成り立ちます。

引き換えに、手放したものもあります。過去の会話は残らず、部屋は人がいなくなると消えます。大人数の部屋は作れません。公開リレーや Cloudflare という第三者に依存し、そこが止まれば相手探しや中継も止まります(そのときは直接接続に落ちます)。

だから設計のルールは一つです。自前のサーバを足して解決しない。伸ばしたいものが出てきたら、まず参加者のブラウザと公開の仕組みでできないかを考えます(ロビーの拡張は公開リレーへの直接 publish、在室の表示は購読、といった具合に)。それでも足りないものは、いまは「やらない」と決めています。

12. テストと公開

はじめにへ リポジトリを見る