世界を動かす技術を、日本語で。

OpenAIのWebRTCの問題

概要

  • OpenAIの技術ブログを受けて、WebRTCの音声AI用途への不適合を指摘
  • WebRTCの設計思想や実装上の問題点を具体的に解説
  • ポート管理やロードバランシングの課題を詳細に分析
  • 代替案としてWebSocketやQUIC/WebTransportの活用を提案
  • 音声AIサービスのスケーラビリティやユーザー体験向上のための技術選択を論考

OpenAIのブログとWebRTC批判

  • OpenAI が数日前に公開した技術ブログへの強い反応
  • WebRTC を音声AI用途で使うことへの否定的立場
  • WebRTC の仕様・実装経験者としての見解
    • TwitchでWebRTC SFUをGoで自作、その後RustでDiscord向けに再実装
    • WebRTC の複雑な標準(約45のRFC+ドラフト)への苦言
  • WebRTC を二度と使いたくないという強い意志

WebRTCとVoice AIの相性問題

  • WebRTC はリアルタイム会話向け設計
    • 音声パケットを積極的にドロップし、低遅延を最優先
    • ネットワーク品質が悪いとユーザーの発話が欠落する
  • Voice AI では200ms遅延しても正確なプロンプト伝送が重要
  • WebRTC の実装では再送が困難、Discordでも対応不能だった経験
  • WebRTC のジッタバッファが極端に小さい設計
  • 今後Voice AIの遅延は下がるが、音質劣化とのトレードオフが残る

TTS(Text-to-Speech)とWebRTCの非効率

  • TTSは リアルタイムより速く音声生成 可能
    • 2秒のGPU処理で8秒の音声生成例
    • 理想はバッファリング再生だが、WebRTCは到着順再生のみ
  • WebRTC はバッファリングができず、ネットワーク障害時に音声が欠落
  • OpenAIは人工的な遅延を導入しつつ、パケットを積極的に破棄
  • 例えるならYouTube動画を画面共有するような非効率

ポート管理とロードバランシングの課題

  • TCPサーバー は1ポートで複数クライアントを管理
    • クライアントのIP/ポート変更で接続が切れる問題
    • 再接続時の高コスト(TCP+TLSハンドシェイク)
  • WebRTC は各接続でエフェメラルポートを割り当て
    • サーバーのポート数制限、ファイアウォール問題
    • Kubernetes環境での運用困難
  • 多くのサービスはWebRTC仕様を無視し、1ポートに多重化
    • TwitchはUDP:443、Discordは50000-50032ポート使用
    • UDP直接通信プロトコル(STUN, SRTP, DTLS等)のパケットルーティング課題

WebRTCの接続確立の遅さ

  • WebRTC 接続確立には最低8RTT必要
    • シグナリングサーバー、メディアサーバー間で複数プロトコルのハンドシェイク
    • P2P前提設計による冗長な手順
    • シグナリングとメディアサーバーが同一ホストでも冗長な通信が発生

WebRTCのフォークとネイティブアプリ化

  • Google Meet 以外の会議アプリはWebRTCの制約回避のためネイティブアプリ化傾向
  • Discordも独自フォークでWebRTCのごく一部のみ実装
  • Webクライアント向けには全仕様実装が必要で技術的負債が大きい

代替案:WebSocket/QUIC/WebTransportの活用

  • WebSocket による音声ストリーミングを推奨
    • 既存のTCP/HTTPインフラ利用、Kubernetesとの親和性
    • 単純でスケールしやすい設計
  • 将来的には MoQWebTransport (QUICベース)の利用を提案
    • QUICは1RTTで接続確立、効率的なコネクション管理
    • CONNECTION_ID によるポートに依存しないルーティング
    • IP/ポート変更時も自動で接続維持
  • QUIC-LB によるステートレスなロードバランシング
    • バックエンドIDをCONNECTION_IDに埋め込むことで、DB不要のパケット転送

結論:Voice AIサービスの技術選択指針

  • WebRTC は音声AI用途に不向き、根本的な設計上の制約
  • 現実的な選択肢として WebSocket、将来的には QUIC/WebTransport への移行
  • スケーラビリティ、ユーザー体験、運用コストの観点からも新技術への転換が望ましい

Hackerたちの意見

これ、すごく片寄った書き方だね。確かにWebRTCには限界があるけど、標準に頼ることで正確性が増して、長期的なエンジニアリングコストも減るんだよ。WebRTCが複雑だからって、それが間違ってるわけじゃない。公共のインターネット上でのリアルタイムメディアは複雑なんだよね。それに、ネットワーキングは本質的に状態を持つものだし。NATトラバーサル、ジッターバッファ、混雑制御、パケットロス、コーデックの状態、暗号化、セッションルーティングは、音声をTCPやWebSocketに載せたからって消えるわけじゃない。そう思うのは、アーキテクチャの明確さじゃなくて、ただ見えにくいところに複雑さを移してるだけだよ。

「どれくらい難しいの?」ってストローマンが言った。2026年になっても、テレカンファレンスはまだこんなにひどい状態だ。何十億ドルも儲けられるのに、Zoomはせいぜい普通だし、Microsoftの何とかみたいにひどいこともある。テレカンファレンスが手探りの混乱じゃないところを見たことがないよ。

QUICも標準だよ。

ブログの著者が自分のことを説明し始めたのに気づいたかもしれないね。「6年前にTwitchでWebRTC SFUを書いたんだ。最初はOpenAIと同じくPion(Go)を使ってたけど、ベンチマークで遅すぎるってわかったからフォークしたんだ。結局、すべてのプロトコルを再実装しちゃったよ、もちろんね!1年前にはDiscordでRustでWebRTC SFUを書き直した。やっぱりそうなるよね!トレンドに気づいてるかも。面白い事実:WebRTCは2000年代初頭からの約45のRFCで構成されてるんだ。そして、技術的にはドラフトのままの事実上の標準もある(例:TWCC、REMB)。すべてを実装しなきゃいけないときは、全然面白くない事実だよ。私を認定WebRTCエキスパートだと思ってもらっていいよ。だから、二度とWebRTCを使いたくないんだ。彼らは「普通のやり方」を試して十分すぎるほどやったと思うけど、どう思う?」

このかわいそうな人。WebRTCを実装するのが嫌いなプロトコルはあまりないよ。シンプルなクライアントを作るには、SDP、TURN/STUN、アイス候補、オファー、ピアツーピアプロトコル、そして毎回ゼロから実装する複雑なハンドシェイクにすぐに慣れなきゃいけない。あのプロトコルの全体を再構築するなんて想像もつかないよ。

Microsoft Graph APIを使ってメールとやり取りしようとしたことある?

どのプラットフォームをターゲットにしてて、そんなに苦労したの?フラストレーションがあったのは残念だね。教育やライブラリが増えて、少しずつ良くなってるといいな。Codexとかが今はすごく簡単にそれを処理できるのも驚きだよね。

この理由でLiveKitが好きだし、彼らのCEOもクールだよ。

WebRTCは、ネットワークの状態が悪いときに私のプロンプトを劣化させたり落としたりする。 リアルタイムが欲しいなら、それに対処するのが現実だよ。リアルタイムを望まないなら、すべてをSTT -> プロンプト -> TTSとして考えるべきかも。そうなると、音声をワイヤーで送る必要すらないかもね。

そうだね。遅延を軽減するための追加の設定があるかもしれないけど、クライアントはSTT -> プロンプト -> TTSの遅延に対処したくないみたい。会話が「リアル」に感じられれば、たまに品質の問題があっても我慢するみたいだね。

リアルタイムが欲しいってこと?OpenAIのユースケースはリアルタイムを必要としないってことじゃない?OpenAIが応答するとき、ユーザーが聞く必要がある前にほとんどの音声が準備されてる。リアルタイムより早く音声を生成するから、リアルタイムプロトコルは合わないよね。

こんにちは、著者です。私のコメントの返信があまり面白くないことをお詫びします。すべての低遅延アプリケーションは、品質と遅延のトレードオフを決めなきゃいけないんです。混雑がキューイング(=遅延)を引き起こし、それを避けるためには何かをスキップする必要がある(品質を下げる)。WebRTCの遅延と品質の調整は固定されてる。遅延を最小限に抑えるのは得意だけど、柔軟性が欠けてるんだ。それでも(使おうと)WebRTCを使うのは、あなたが示唆したように、ブラウザのサポートがそれを唯一の選択肢の一つにしてるから。もちろん、今まではね!WebTransportを使えば、一般的なプロトコルを通じてWebRTCのような動作を実現できる。ストリームをドロップ/リセットするまでの待機時間を自分で決められるんだ。ブログで言いたかったのは、ユーザーはしばしばストリーミングを求めるけど、ドロップは望んでいないってこと。もちろん、WebRTCなしで音声の入出力をストリーミングすることはできる。アプリケーションは、音声パケットが永遠に失われるタイミングを決めるべきだと思う…それは50msなのか500msなのか5000msなのか?私の主張は、音声AIは50msの選択肢を選ぶべきじゃないってこと。

ChatGPTを使ってるときに切断されたことはあんまりないな。ジェミニがイライラする部分だね。アプリをバックグラウンドにして再開すると、レスポンスや割り当てられたIDの会話が消えちゃうんだ。ハハ。

ジェミニってWebSocketだと思う?重いカスタムアプリケーションで独自のメディア処理をしようとすると、同じような経験をするよ。AudioContextや再開の問題にぶつかるし…その辺のコーナーケースを扱うのが本当に面倒なんだ :(

まず技術的なポイントに答えるけど、その後はWebRTCじゃない未来が見えると思ってる。WebTransportやWebCodecsが進んでる方向には合わないと思うけど。>「…でもユーザーとしては、遅い/高価なプロンプトが正確になるために200ms余計に待つ方がいい」これは私がもらうフィードバックとは真逆だね。ユーザーは即座のレスポンスを求めてる。レスポンス生成に遅延があったり中断があると、魔法が消えちゃう。リアルタイムより早く送信したくないし、もしユーザーがモデルを中断したら、3分の音声を送信して10秒しか再生されなかったら無駄になっちゃう。> TTSはリアルタイムより早い https://research.nvidia.com/labs/adlr/personaplex/ 最新の音声AIは、著者が説明しているものから離れてきてる。20msで入出力されてるし。> ユーザーのソースIP/ポートが変わらないことを本当に願ってる、なぜならその機能を壊しちゃったから。それはサポートされてる。ufragの新しいIPが来たらそれもサポートされる。> 最低でも8回の往復(RTT)が必要だって?それは間違いだよ。https://datatracker.ietf.org/doc/draft-hancke-webrtc-sped/ > 音声をWebSocketでストリーミングするだけだよ。AECみたいなものを失うよ。それにクライアントに複雑さを押し付けることになる。WebRTCのシンプルさ(createOffer -> setRemoteDescription)が人々を簡単にオンボードさせてるんだ。多くの開発者はRealtime API + WebSocketで苦労してた(コードが多くて手作業が必要だった)。---- 私が選べるなら、Offer/Answerモデルを選んで、DTLS+SCTPの代わりにQUICを使うかな。RTPをQUICでやるのもありかも?プロトコル自体にはあまり強い意見はないけど、もっと大きなコードフットプリントで複数のクライアント(顧客のクライアント)にコードを配布する方法がわからないんだ。

…でもユーザーとしては、遅い/高価なプロンプトが正確になるために、200ms余分に待つ方がいい。これにはめっちゃ反対。会話モードがあると、ほぼ普通の会話ができるから、ゲームチェンジャーだと思う。もしレイテンシーを50-100ms短縮できたら嬉しいし、200ms増えたら使わなくなるかも。深いリサーチが必要な時はテキストを使って、プロンプトを慎重に作成するけど、外出中はスタートレックのコンピュータと会話したいんだよね。面白いことに、別のテック企業で関連するプロジェクトに関わっていて、この意見を言ったら、たくさんの反対があったのが明らかだった。会話の流暢さが一番重要な機能だと思うのに、まだ驚いてる。

リアルタイムよりも早く送信したくないよ。ユーザーがモデルを中断したら、3分の音声を送信しても10秒しか再生されないって、無駄な帯域を使っただけだよ。1秒ずつ送信すれば十分。20msや10分を一度に送る理由なんてない。どちらもバカげてる。

こんにちは、ショーンさん。1. ユーザーはもちろんレイテンシーを下げたいけど、LLMが「聞き間違える」回数も減らしたいんだよね。レイテンシーと品質のトレードオフについてA/Bテストをするのは素晴らしいけど、WebRTCだとその調整が難しいんだ。2. TTSの専門家じゃないけど、結果を少しずつ出すメリットって何?シリコンは時間の数字がどれだけ早く増えるかなんて気にしないでしょ?3. そうだね、クライアントがIPが変わったことに気づいてICE再交渉ができることもある。でも、たいていは気づかないし、サーバーが変化を検出するのに頼ることが多いけど、LBの設定だとそれができないんだ。大したことじゃないけど、すでにいろいろと面倒なことをしなきゃいけないのが残念。4. そのドラフトは7 RTTになるってこと?また、いくつかはパイプライン化できるから、実際の数はもう少し低いけど。実際の問題は、P2Pを使う場合に二重のTLSハンドシェイクを引き起こす必須のシグナリングサーバーだよ。5. もちろんWebRTCは新しい開発者には簡単だけど、それが大企業のOpenAIにとっては問題を引き起こすこともある。RTP over QUICをいじってみるべきだと思うし、手伝いたいよ。コードサイズが心配なら、ブラウザ(そしていつかOS)がQUICライブラリを提供してくれるし、MoQに近いものに切り替えれば、QUICがフラグメンテーションや再送、輻輳制御を処理してくれる。アプリケーションは意外と小さくなるよ。RoQ/MoQの主な欠点は、QUICが輻輳制御されているためGCCを実装できないこと。今のところブラウザから送信する際はcubic/BBRに縛られてる。

クライアントに複雑さを押し付けることになるよ。WebRTCのシンプルさ(createOffer -> setRemoteDescription)が、人々が簡単にオンボードできる理由なんだ。WebRTCは複雑で、ライブラリであっても(すでに使っているブラウザに組み込まれているライブラリであっても)。クライアント/サーバーの音声インタラクションでは、わざわざ使う理由が見当たらない。別の方法で音声サンプルを送信した方がいいし、再生のためにジッターバッファのロジックを借りるのもありだよ。今の仕事は音声とビデオ会議、1対1の通話に関わっていて、WebRTCは本当に複雑なんだ。すぐに製品を立ち上げられたけど、無茶なことをすると修正が大変だし、クライアントのためにフォークしてもね。TURNについては大きな愚痴が書けるよ。[1] TURNは、クライアントがアロケーションをリクエストするときに、一時的なポートではなく、ランデブーIDを割り当てるべきだと思う。その後、ピアはサービスポートでTURNサーバーに接続し、ランデブーIDへの接続をリクエストする。クライアントがピアアドレスを知って許可を追加する必要がなくなる。エンドツーエンドの中継接続に到達するための通信が少なくて済むんだ。高度なクラスターは、IDに情報をエンコードして、クライアントとピアがそれぞれ近くのTURNサーバーに連絡できるようにし、サーバーが接続を調整できるようにする。あまり高度でないクラスターは、IDとともにTURNサーバーのIPとサービスポートを共有する必要がある。

この分野にはかなりの経験があるよ(特許出願もいくつかあるし)。Alexaの場合、デバイスはサーバーに接続を確立して、その接続を維持し、ウェイクワードを検出した後に基本的にHTTP2/SPDYみたいなものを送信してた。これにより、話し終わる前にSTTが処理を始められるから、最後の数チャンクの処理にはほんの少しの遅延しかない。回答は同じ接続で返ってくる。OpenAIの場合、Alexaのように持続的な接続を維持するのは難しいけど、電話からHTTP2を使うことができて、iOSとAndroidはその接続をほぼ魔法のように管理してくれる。著者は絶対に正しい、リアルタイムプロトコルは必要ない。すべてのデータを取得する方が重要だよ。ユーザーは500msを超えない限り遅延に気づかないからね。特に携帯電話の時代では、ほとんどの人がリアルタイムの人間同士のコミュニケーションに遅延があるのに慣れてるし。(OpenAIやAnthropicで働いてるなら、ぜひ連絡してね。もっと詳しく話せるのが嬉しいから。)

「著者は絶対に正しい。リアルタイムプロトコルは必要ない。すべてのデータを取得することがもっと重要だ。ユーザーは500msを超えない限り遅延に気づかないだろう」ってのは、私の経験とは違うな。音声で1日6000件の会話を運用していて、WebRTC + カスケーディング(STT/LLM/TTS)アーキテクチャを使ってる。もしかしたらコメントを誤解したかもしれないけど、その500msは今の最先端の音声実装のフロアみたいなもので、運が良ければ、無駄を省いて、推測デコーディングや推論などの高価なことをやってる。LLMのパスだけで450msかかる。商業用の音声AIでは、1msがすごく重要なんだ。そこに200msや300msを追加したら、会話が本当に劣化する。私たちはビジネスをサポートするために多くの音声関連のことをやっていて、主に技術に詳しくないユーザーを相手にしてる。昨年の試みでは、ターンからターンのレイテンシーが1200ms-1500msくらいで、ユーザーの混乱や中断、会話の放棄、全体的に非常に不快な体験を引き起こした。今はツールの使用に応じてターンからターンで約700msになっていて、まあまあの体験に近づいてきてる。実際の人とのインタラクションに匹敵するくらい。さらに100msを削減するためにかなりのコストをかけてる。推測的なLLMパスや推測的なツール実行(ユーザーが話している間にいくつかのLLM推論を行うけど、非冪等のツール呼び出しを実行する前に、そのLLMパスが使えるかどうか、ユーザーが文の最後に重要なことを言っていないかを確認する)を使って、100-200msを削減しようとしてる。500msが無関係だと言う人は、他のユースケースを説明してるんだと思う。私の音声AIの経験では、問題は時々のWebRTCパケットのドロップじゃない。実際の難しい問題は、強い背景ノイズ、エコー、そしてもちろんアクセントなんだ。WebRTCはその洗練されたAEC実装のおかげで、少なくともエコーの問題にはかなり役立ってる。OpenAIのスケールで実装するのが大変なのはわかるけど、ハイパースケールアプリケーション以外には、たくさんの良い解決策や商業プロバイダー(例えば、Dailyなど)があって、問題にならない。解決すべき本当の問題はまだ他にある。でも、500msを私のレイテンシーバジェットに追加したら、私のアプリケーションは終わりだよ。

メッシュホスティングされた管理されたWebRTCクラウドで、GeminiライブAPIを運用してるんだけど、めちゃくちゃうまくいってるよ。もう2年も使ってる。WebSocketを試したり、一時的なキーを扱ったりできるけど、音声エージェントを大規模に運用している人たちと話すと、WebRTCやPipecat、そしてこの分野の問題解決に割り当てられたリソースで多くの問題が解決されてるって感じる。確かにオーバーキルな気もするけど、接続が確立されると、ほんとに魔法みたいだよ。スタートアップ時間やバッファリングも解決されて、音声接続が早くなったしね。https://github.com/pipecat-ai/pipecat-examples/tree/main/ins...(動画は難しいけど)

「WebRTCが問題だ」というのは釣りだね。彼の本当の主張は「WebRTCにはクラウドの音声AIのスケーリングを妨げる厄介なトランスポート層の特性がある」ってこと。自分のスタートアップでこれに再び取り組まなきゃいけなくなって、WebRTCを捨てたら何を失うかを思い出したよ。オーディオDSPパイプライン、送信側VAD、エコーキャンセリング、ノイズ抑制、NATトラバーサルの成熟度、コーデック統合、ブラウザの普及など。

クラウドサービスと話すときはNATトラバーサルはいらないよ。

元の記事を読んだときに思ったことそのままだったけど、正直言うとWebTransportは今年Safariがサポートを出したばかりで、やっと主流に入ってきた感じだね。

P2PビデオのためにWebRTCデータチャネルを使ってたのを思い出すなぁ。ブラウザからブラウザへのUDPっていいよね :) 楽しい思い出だ。読んでくれてありがとう!