oneWay遅延58.4ms、史上初の50ms台へ ── 犯人はコードではなくWi-Fiだった
今回の登場人物
John(ジョン)
AI パートナー / session-life 担当
音質改善・音響設計を手がけ、世界初のオンラインセッション体験を目指すsession-lifeのプロジェクトリーダー。遅延という敵と、一番近い場所で戦っている。
音質改善・音響設計に取り組む、世界初を目指すオンラインセッションサービス。現在開発中・公開準備中。
準備中この記事のポイント — 手順・数値・比較・事例・評価
- 【手順】35体のAIエージェントで12,000行を監査: 確定所見28件、7つの波に分けたデプロイ
- 【数値】oneWay遅延 102.8ms → 65ms → 58.4ms: 史上初の50ms台到達
- 【比較】QUIC datagram vs UDP直叩き方式 vs WebRTC data channel: ブラウザ標準APIだけで低遅延通信を実現
- 【事例】「時折震える」の真犯人はコードではなくWi-Fiだった
- 【評価】PLCとAutoJBによる自動チューニング: 遅延削減と震え解消の両立
「時折震える」——session-lifeの音声が、そう表現されるようになったのはいつからだったか。犯人はずっとコードの中にいると思われていた。だが7月2日、Johnが辿り着いた答えは、誰も予想していなかった場所にあった。
課題:「時折震える」の正体を探して
session-lifeは、世界初のオンラインセッション体験を目指すツクルンの自社プロジェクトだ。離れた演奏者同士が同じ部屋にいるように音を合わせるには、片道の遅延を極限まで削る必要がある。だがどれだけコードを磨いても「時折震える」報告が消えなかった。ナミオさんの指示は明快だった。「すべてのソースを徹底的に」。
実装①:35体のAIエージェントで12,000行を監査する
朝、Johnは35体のAIエージェントを並列で走らせ、session-lifeのコードベース約12,000行を監査にかけた。1体1体が担当範囲を持ち、ロジックの矛盾・タイミング処理の甘さ・リソース解放漏れを洗い出す。結果、確定所見は28件。震えの原因候補が数字として可視化された。
実装②:7つの波でデプロイし、震えの犯人を追い詰める
28件を一気に直すのではなく、Johnは7つの波(wave)に分けて修正をデプロイした。1波ごとに実測し、oneWay遅延の変化を確認する。102.8msから始まった数値は波を重ねるごとに縮み、65msまで下がった。だがコードを直しても「時折震える」だけは消えない。疑いの目をコードの外に向けたとき、見えてきたのがWi-Fiだった。震えのタイミングは無線区間の電波状況の揺れと一致していた。真犯人は、機械の中ではなく外にいた。
実装③:QUIC datagramの初疎通とPLC
17:24、ブラウザからQUIC datagramの初疎通に成功した。Jamulus(オンラインセッション用の老舗ソフト、目安として推奨RTTは30ms前後とされる)が25年間UDPを直接叩くことで実現してきた「順序保証を捨てて速度を取る」設計を、session-lifeはブラウザの標準機能だけで実現した。専用アプリなしに低遅延通信の土台へ立てたことになる。18:02には音声本線がQUICに乗った。ちなみに合奏における遅延の知覚は個人差があるが、一般に20〜30ms以下であれば違和感が少なく、50ms前後から演奏のズレを感じ始めると言われる。58.4msはその境界線上にある数字だ。
移行後もまだ「時々コッ」という瞬間的な音の欠落が残っていた。JohnはここにPLC(Packet Loss Concealment=パケット欠落隠蔽)を導入。パケットが届かなかった瞬間を前後の音声から推定して補完する技術だ。これによりジッターバッファ(到着タイミングのゆらぎを吸収する待ち時間)を半分に削れ、oneWay遅延は58.4msまで縮んだ。session-lifeにとって史上初の50ms台だった。
自動化の芽:ナミオさんの一言が消したもの
締めくくりに、ナミオさんが二度同じ問いを投げた。「ここも自動化できないの?」。フラグの切り替え、ジッターバッファの調整幅、出力先の選び直し——人手のチューニングが、この一言で機械側の自動処理に置き換わった。19時、回線混雑の時間帯に、session-lifeは初めて自分でチューニングする姿を見せた。ログにはこう残っている。
[AutoJB] 5→7→9
ジッターバッファのサイズが人の手を介さず変化していく記録だ。ナミオさんの判定はこうだった。「ブラボーはまだ言えない。でも最良にはなってると思う。またやるぞ。」
用語の整理 — 初見でも迷わないために
- QUIC
- Googleが設計し、現在はHTTP/3の基盤プロトコルとして標準化されている通信規格。従来のTCPが「順序保証・再送・輻輳制御」をひとまとめに扱っていたのに対し、QUICはUDPの上に自前で通信管理を組み立て直し、コネクション確立の往復回数を減らし、パケットロス時の影響を1本のストリームに閉じ込められるよう設計されている。UDPの上に構築されているからこそ「順序を待たずに速く送る」datagramモードも用意でき、リアルタイム性が要る音声・映像に向く。
- WebTransport API
- ブラウザがQUIC(HTTP/3)上で双方向通信を行うための標準API。専用アプリのインストールなしに、JavaScriptから
transport.datagramsを呼ぶだけでdatagram(順序保証なし・軽量)とstream(順序保証あり)を使い分けられる。従来ブラウザで低遅延通信をしようとするとWebSocket(TCP)かWebRTCしか選択肢がなかったが、WebTransportはその間を埋める第三の道として登場した。 - oneWay遅延
- 音声データが片道届くまでの時間。往復(RTT)の約半分が目安だが、実測は単純な半分にはならない
- QUIC datagram
- HTTP/3の基盤プロトコルQUICが提供する、順序保証や再送を行わない軽量なデータ送信の仕組み。WebTransport APIから利用できる
- PLC(Packet Loss Concealment)
- パケットが届かなかった瞬間を、直前・直後の音声波形から推定して埋める欠落隠蔽技術。無音や「プツッ」というノイズをそのまま出す代わりに、聞感上自然な補完音を差し込む。Opusなど多くの音声コーデックに標準搭載されている。
- ジッターバッファ
- ネットワーク経由で届くパケットの到着タイミングのゆらぎ(ジッター)を吸収するための待ち時間バッファ。大きくすれば音は途切れにくくなるが遅延が増え、小さくすれば遅延は減るが途切れやすくなる——このトレードオフを、回線状況に応じて動的に調整する仕組みがAutoJBだ。
比較:Jamulus(UDP直叩き)とWebTransport/QUIC方式
オンラインセッションの世界には、すでに25年近い実績を持つJamulusという定番ソフトがある。session-lifeがゼロから設計し直すにあたり、まずJamulus方式との違いを整理した。
| 観点 | Jamulus(UDP直叩き) | WebTransport/QUIC(session-life採用) |
|---|---|---|
| 対応環境 | 専用デスクトップアプリが必須 | ブラウザだけで動作(インストール不要) |
| 実装のしやすさ | 低レベルUDPソケット制御を自前実装する必要あり | WebTransport標準APIで比較的シンプルに実装可能 |
| NAT越え | 専用サーバー・ポート開放の運用ノウハウが確立 | HTTPS/443ポートに相乗りするためNAT・ファイアウォール越えが容易 |
| ブラウザ対応状況 | 非対応(ブラウザからは使えない) | Chrome/Edge系で対応進行中。Safari等は今後の対応待ち |
| 実績・安定性 | 25年の運用実績、コミュニティ資産が豊富 | 比較的新しい技術、session-lifeが実運用で知見を蓄積中 |
専用アプリを前提にできるならJamulus方式の安定性は依然として強い。だがsession-lifeが目指すのは「ブラウザを開くだけで参加できる」体験だ。そのために、実績よりもブラウザ標準対応を優先してWebTransport/QUICを選んだ。
代替手段の検討 — なぜQUICを選んだか
低遅延のリアルタイム音声通信を実現する手段は、QUIC以外にも複数存在する。session-lifeが検討した主な選択肢を整理する。
- WebRTC data channel
- ブラウザ標準でP2P通信ができる仕組みで、既に多くのビデオ会議サービスが採用している。低遅延化のノウハウも蓄積されているが、SDP交渉やICE/STUN/TURNによる接続確立が複雑で、サーバー構成のコストも大きい。session-lifeでは将来的な拡張候補として保留した。
- 生UDP socket(Jamulus方式)
- 最も低レベルで自由度が高いが、ブラウザからは直接扱えない。専用アプリの配布・更新の運用コストが常につきまとう。「ブラウザだけで完結する」というsession-lifeの体験方針とは相容れなかった。
- 独自プロトコル(TCP/UDPを自前設計)
- 理論上は最適化の自由度が最大になるが、輻輳制御・再送制御・暗号化を全て自前で作り込む必要があり、開発・保守コストが跳ね上がる。車輪の再発明を避け、既に標準化・実装が進んでいるQUICの恩恵を受ける方を選んだ。
結論として、「ブラウザだけで完結する低遅延通信」という要件を満たしつつ、標準化された土台の上に乗れる選択肢がWebTransport/QUICだった。25年の実績を持つJamulus方式を否定するのではなく、目指す体験が違うからこそ別の道を選んだ、というのが実際のところだ。
統計で見る58.4msの意味
oneWay遅延58.4msという数字は、単体では意味を持ちにくい。他の基準値と並べて初めて位置づけが分かる。
| 指標 | 目安 | 意味 |
|---|---|---|
| 20〜30ms以下 | 合奏で違和感がほぼない領域 | 同じ部屋で演奏している感覚に近い |
| Jamulus推奨RTT 30ms前後 | oneWay換算で約15ms前後 | 25年の実績が示す「快適に演奏できる」目安 |
| session-life 実測58.4ms | 史上初の50ms台 | 違和感を覚え始める境界線付近まで到達 |
| 50ms前後 | 演奏のズレを感じ始める境界 | ここを下回れるかが次の目標 |
| 102.8ms(この日の開始値) | 明確なズレを感じる領域 | 1日で半分近くまで圧縮した |
Jamulus方式の推奨値と比べればまだ差はある。だが「専用アプリなし・ブラウザだけ」という制約の中で、1日でここまで縮めたという点に意味がある。ナミオさんが「ブラボーはまだ言えない」と言ったのは、この境界線の位置を正確に見ていたからだろう。
【技術コラム】QUIC datagramとPLC、読者が明日試せること
「ブラウザだけで低遅延通信」と聞くと難しそうだが、骨格はシンプルだ。WebTransportというブラウザ標準APIを使うと、QUICの上で順序保証付き通信(stream)と、順序保証を持たない軽量な通信(datagram)を選べる。リアルタイム音声のように「多少欠けても遅れて届くよりマシ」な用途では、datagramの方が有利になる。
// WebTransport datagram の基本形(イメージ)
const transport = new WebTransport("https://example.com/session");
await transport.ready;
const writer = transport.datagrams.writable.getWriter();
await writer.write(audioChunk); // 順序保証なし・軽量送信
datagramを使う場合、パケットが順不同で届いたり届かなかったりすることを前提に設計する。ここでPLC(欠落隠蔽。届かなかった一瞬を前後の波形から推定して埋める技術)が効いてくる。Opusコーデック内蔵のPLCなど既存ライブラリで導入できる場合も多い。ジッターバッファも固定値ではなく可変にできると効果が大きい。混雑時は大きく、安定時は小さく——を実測値から動的に決める仕組みは、比較的小さな実装で導入できる。まず「今のジッターバッファは固定値か、可変か」を確認するところから始めてみてほしい。Wi-Fi起因のジッターが疑わしい場合は、有線LANへの切替・5GHz帯優先・APの設置場所見直しといった基本対策から潰していくのが定石だ。