よくある接続不良は「TURNが足りない」ことが原因です。STUN は「相手のIP/ポートを知って直通を試す仕組み」。しかし企業ネットワークや携帯キャリアの CGNAT(Carrier‑Grade NAT:大規模NAT) では直通が塞がれやすく、TURN(中継サーバ)を用意しないと繋がりません。
- 必ずTURNを用意(coturn可)。TURNとは Traversal Using Relays around NAT の略で、NATやファイアウォール越えができない場合に中継サーバーを経由して通信を成立させる仕組みです。WebRTCの”最後の砦”となります。
coturn
は代表的なオープンソースTURNサーバーで、本番運用でもよく利用されます。3478/udp
と443/tcp+tlsの両方を開け、TCP/443経由のフォールバックも許可。 - 資格情報は短命トークン化(例: REST APIで1〜10分の有効期限を発行)。漏洩リスクと不正中継を抑制。
- Keepalive/ICE再試行:モバイルやサスペンド復帰でICEが死にがち。DataChannelなら30s前後でping、ICE再収集を自動化。
- 帯域制御:Publisher側では映像送信の上限ビットレートを
maxbitrate
で設定できます。また Simulcast(同じ映像を複数解像度で送信)やSVC(映像を層ごとに分割して送信) を有効化すると、受信側は自分の回線状態に応じて最適な解像度や層だけを受け取れます。これにより、通信が弱い端末でも自動的に低画質ストリームを受け取り、途切れにくくなります。 - 監視:
getStats()
を使うとWebRTCの通信状態を数値で確認できます。例えばcurrentRoundTripTime
は端末間の往復遅延、bitrate
は実際に流れている通信速度、nackCount
はパケット再送要求の回数、framesDropped
は処理落ちしたフレーム数を意味します。これらを定期的に記録すれば、どこで遅延や映像途切れが起きているかを推測できます。また Relayed比率(TURN経由の割合)が急に増えたとき は、直接接続できなくなり中継頼みになっているサインで、ネットワーク障害や環境悪化の早期検知に役立ちます。 - 運用の落とし穴:本番運用では思わぬ環境依存の問題に遭遇します。例えば IPv6オンリー環境(NAT64) ではIPv4前提の設計が通じず接続できないことがあります。また ブラウザのタブを非アクティブにすると省電力機能で処理が止まる、モバイルOSではアプリがバックグラウンドに移動すると強制的に接続が切られる といった事象も頻発します。こうしたケースに備えて、アプリ側には 再接続のリトライ処理 を必ず組み込む必要があります。
おまけ — Djangoとのつなぎ込み(最低限の型)
- 方針:DjangoはHTTP APIと認証、RTC(Real-Time Communication)/ML(Machine Learning)は別プロセス(SFUやgRPCサーバ)に。疎結合にして可用性を確保。
- gRPCをブラウザから使うなら:ネイティブgRPCは不可、gRPC-Web(+Envoy/Envoy Gateway)かConnect-Webを。双方向ストリーミングが必要ならWebSocketで代替。
- Django→gRPC(ML)呼び出し(非同期)
# views.py (Django 4+, ASGIサーバで稼働想定) from django.http import JsonResponse import grpc, asyncio from foo_pb2 import PredictRequest from foo_pb2_grpc import InferenceStub async def infer(request): data = request.body # 例: 前段でバリデーション済み async with grpc.aio.insecure_channel( "ml-svc:50051", options=[ ("grpc.keepalive_time_ms", 15000), ("grpc.keepalive_timeout_ms", 5000), ("grpc.max_receive_message_length", 10 * 1024 * 1024), ], ) as ch: stub = InferenceStub(ch) resp = await stub.Predict(PredictRequest(payload=data), deadline=1.0) return JsonResponse({"ok": True, "result": resp.label})
運用Tip:deadline
必須(SLO担保と負荷時の早期棚卸し)。リトライは冪等なRPCのみに。