WebSocketもWebRTCも、接続を開いたままにしておくことで、音声の断片ごとに新しいリクエストを送らずに双方向でやり取りできます。違いは、ネットワークの調子が悪いときに何が起きるかです。WebSocketはTCP上で動くので、待つことになってもすべてのバイトが順番どおりに届きます。WebRTCは通常UDP上で動き、メディア向けに作られているので、遅れたパケットは捨てるか補間して再生を続けます。
音声エージェントでは、この違いがそれぞれの置き場所を決めます。WebRTCは、人の端末とサーバーの間、つまりWi-Fiやモバイル回線でパケットが失われる区間のためのものです。WebSocketは、パケットがほとんど失われないサーバー間の区間と、シンプルで順序どおりのメッセージの流れが必要な場面のためのものです。本番環境の音声エージェントの多くは、両方を使っています。
このガイドは、音声エージェントやリアルタイム音声機能のトランスポートを選ぶエンジニア向けです。それぞれのプロトコルの仕組み、音声にとって重要な比較ポイント、そして実際に本番で使われている構成を説明します。
WebRTCとWebSocketの比較
| WebSocket | WebRTC | |
|---|---|---|
| 何か | 双方向のメッセージチャネル | リアルタイムメディアのためのプロトコル群 |
| トランスポート | TCP(wss://ではTLS) | 通常はUDP。フォールバックとしてTURNリレー経由のTCPまたはTLS |
| 配信 | すべてのメッセージを順番どおりに | パケットは捨てられることがあり、遅れた音声は補間される |
| パケットロス時 | 失われたデータが再送されるまでストリームが止まる | 短いノイズはあっても音声は流れ続ける |
| 音声の扱い | なし。形式、バッファ、再生はすべて自分で決める | Opusコーデック、ジッターバッファ、損失補間を内蔵 |
| 接続の確立 | HTTPのアップグレードリクエスト1回 | シグナリング、ICE候補、多くの場合STUNとTURNサーバー |
| サーバー側 | どのWebサーバーや言語でも可 | 通常はメディアサーバーかホスト型プラットフォーム |
| 向いている用途 | サーバー間通信、API、テキストや制御メッセージ | 管理外のネットワーク上のブラウザやモバイルの音声 |
WebSocketの仕組み
WebSocketは、Upgradeヘッダーの付いた通常のHTTPリクエストから始まります。サーバーが受け入れると、同じTCP接続が開いたままになり、どちら側からでもいつでもメッセージを送れます。プロトコルはRFC 6455で定義されており、すべてのブラウザにWebSocket APIがあります。
WebSocketは音声について何も知りません。メッセージはテキストかバイナリのフレームで、中身はアプリケーションが決めます。音声APIでは、base64でエンコードしたPCMを含むJSONイベントか、生のバイナリフレームを送るのが一般的です。コードはマイクから音声を取り込み、断片をエンコードして送信し、受信側では返ってきた音声を再生キューに入れます。
魅力はそのシンプルさです。WebSocketはほとんどのプロキシやロードバランサーを通り、どの言語からも使え、メッセージを読めるのでデバッグも簡単です。その代わりに付いてくるのが、TCPの配信保証です。パケットが失われるとTCPはそれを再送し、それまで後続のデータはアプリケーションに届きません。ファイルのダウンロードならまさに望ましい動作です。しかしライブの音声では、200ミリ秒の再送は200ミリ秒の無音を意味し、そのあと音声がまとめて一気に届きます。
WebRTCの仕組み
WebRTCは、ピア間で音声、映像、データをリアルタイムに送るための標準の集まりです(概要はRFC 8825)。メディア処理の大部分はブラウザが担います。
- コーデック。 ブラウザは音声についてOpusとG.711への対応が必須です(RFC 7874)。Opusは音声を効率よく圧縮し、ネットワークに合わせてビットレートを調整します。
- トランスポート。 メディアはSRTPで、通常はUDP上を流れ、鍵はDTLSで交換されます。暗号化は必須です。
- ジッターバッファと損失補間。 受信側は数十ミリ秒分の音声をためて到着のばらつきをならし、小さな欠落は止まらずに埋めます。
- NAT越え。 ICEはまず直接の経路を試し、STUNでグローバルアドレスを調べ、どれも通らなければTURNリレーにフォールバックします。
- エコーキャンセルとノイズ抑制。 ブラウザはWebRTCの通話にデフォルトでこれらを適用します。
WebRTCが定義していないのはシグナリングです。つまり、メディアを流す前に2つのピアがセッション記述とネットワーク候補を交換する方法です。この部分は自分で作る必要があり、多くの場合それはWebSocketです。だからこそ「WebRTC対WebSocket」という比較は少し奇妙です。多くのWebRTCアプリの中にはWebSocketが入っています。
もうひとつの注意点はサーバー側です。WebRTCはブラウザ同士の通話のために設計されました。相手の「ピア」が音声エージェントの場合、WebRTCを話せるサーバーが必要です。LiveKitのようなメディアサーバー(SFU)か、Dailyのようなホスト型プラットフォームです。TURNサーバーやメディアサーバーを自前で運用するのは、本格的なインフラ作業になります。
音声AIで重要なのはどちらか
音声エージェントには少なくとも3つのネットワーク区間があり、すべてに同じトランスポートを使う必要はありません。
ユーザーの端末からサーバーまで。 家庭のWi-Fi、オフィスのネットワーク、電車の中のスマートフォンを通る区間です。ここではパケットロスやジッターは日常的に起こります。WebRTCはこの区間のために作られました。パケットが失われても音声は流れ続け、帯域が下がればOpusがビットレートを落とし、ブラウザがユーザーのマイクからエージェントの声を取り除きます。ユーザーがブラウザやモバイルアプリからエージェントと話すなら、WebRTCの導入コストに見合う効果が出るのはこの区間です。
サーバーから音声モデルまで。 エージェントは音声認識モデルに音声を、音声合成モデルにテキストをストリーミングします。これらの接続はデータセンター間を結ぶもので、パケットロスはまれなので、TCPの順序どおりの配信はほとんどコストになりません。さらに、音声と並んで順序どおりに届くテキストや制御のイベント、リクエストのコンテキスト、シンプルな認証といった、WebSocketならではの利点も欲しいところです。音声APIが、Cartesiaも含めてWebSocketでストリーミングしているのはこのためです。
電話の通話。 電話回線の発信者は、電話網を経て、SIPとRTP、または電話事業者のメディアストリームでサーバーに届きます。たとえばTwilio Media Streamsは、通話の音声を8 kHzのμ-lawでWebSocket経由でサーバーに転送します。発信者側にはWebRTCもWebSocketもありません。電話エージェントのトランスポートを選んでいるなら、SIPトランクの解説を読んでください。
つまり、問うべきなのは不安定なネットワークがどこにあるかです。その区間にWebRTCを置き、それ以外はすべてWebSocketを使いましょう。
クライアントでもWebSocketで十分な場合
ブラウザのすべての音声機能にWebRTCが必要なわけではありません。次のような場合は、クライアントから直接WebSocketを使うのも妥当な選択です。
- ネットワークが安定している。 社内ツール、キオスク端末、オフィスネットワーク上のデスクトップアプリ、デモなど。
- プロトタイプを作っている。 接続は1本、メディアサーバーもTURNも不要で、すべてのイベントをログに残せます。
- 会話ではない音声。 読み上げ用のストリーミング音声合成や、短い途切れが会話を壊さない音声入力など。
- クライアントがサーバーである。 別の場所から音声を中継するバックエンドやエッジ関数など。
この方法を選ぶなら、音声は小さな断片で送り、再生バッファは短く保ち、ユーザーが割り込んだらすぐに再生を止めてください。リリース前には、パケットロスのあるネットワークでテストしましょう。ブラウザの開発者ツールでは帯域と遅延は制限できてもパケットは落とせないので、OSレベルのネットワークコンディショナーかスマートフォンのテザリングを使います。
実際に使われている構成
フロントエンドはWebRTC、バックエンドはWebSocket。 本番で最も一般的な構成です。ユーザーのブラウザやアプリがLiveKitやDailyのWebRTCルームに参加します。エージェントはサーバー上で動き、同じルームに参加して、WebSocketで音声モデルにストリーミングします。LiveKit AgentsとPipecatはどちらもこの方式で、それぞれのCartesiaプラグインはサーバーからCartesiaへのWebSocketを開きます。LiveKitと、Pipecatを開発するDailyは、どちらもCartesiaの顧客です。DailyのCEOであるKwindla Hultmanはこう述べています。「Cartesia Sonic is the best voice model today for real-time multimodal use cases.」
端から端までWebSocket。 ブラウザはWebSocketでサーバーに音声を送り、サーバーも音声モデルとWebSocketでやり取りします。最もシンプルな構成で、プロトタイプや管理されたネットワークに向いています。Cartesia Managed AgentsもWebSocket接続を直接受け付けるので、信頼できるサーバーや短期のアクセストークンを持つブラウザは、エージェントのコードを動かさずにホスト型のエージェントと話せます。
入口は電話、内部はWebSocket。 電話エージェントでは、通話はSIPや電話事業者経由で届き、エージェントと音声モデルの接続はWebSocketのままです。電話側はManaged Agentsが、Cartesiaの電話番号、Twilio、または自社のSIPトランクを通じて処理します。
WebSocketでCartesiaに音声をストリーミングする
CartesiaのリアルタイムAPIはWebSocketでストリーミングします。
- 音声合成:
wss://api.cartesia.ai/tts/websocketは、LLMから届いたテキストを順に受け取り、音声の断片を返します。1本の接続で複数のコンテキストを扱え、continuationを使えばLLMが返答を書き終える前にSonicが文を話し始められます。 - 音声認識: Ink-2は、WebSocketで受け取った生のPCMストリームを文字起こしし、ターン検出もネイティブに処理します。
- Managed Agents:
wss://api.cartesia.ai/v1/agents/websocket/{agent_id}は、アプリケーションをホスト型のエージェントにつなぎます。base64の音声を20〜100ミリ秒の断片にしてaudio_inputイベントで送り、audio_outputイベントを再生します。ユーザーがエージェントの発話にかぶせて話し始めると、Cartesiaがaudio_output_clearを送るので、クライアントは再生を止めます。
エージェントのWebSocketは、ヘッダーなしのモノラル音声をpcm_16000、pcm_24000、pcm_44100、mulaw_8000のいずれかで受け取り、同じ形式で音声を返します。
{
"type": "session_create",
"audio": {
"input_format": "pcm_16000",
"output_delivery": "speaking_pace"
}
}
ブラウザから使う場合、APIキーをクライアントのコードに入れてはいけません。ブラウザはWebSocketのヘッダーを設定できないため、サーバーで短期のアクセストークンを発行し、クライアントはそれをクエリパラメーターとして渡します。完全なセッションの例はWebSocket APIガイドにあります。
試すには、Cartesiaのplaygroundでエージェントを作成するか、APIキーを取得して音声合成のクイックスタートで最初の音声をストリーミングしてみてください。