Upgrade to Pro — share decks privately, control downloads, hide ads and more …

OpenAI RealTime API WebRTCモード - シグナリングとDataCha...

OpenAI RealTime API WebRTCモード - シグナリングとDataChannelの使い道 -

WebRTC Meetup Tokyo #30で発表した資料です。
OpenAI RealTime API WebRTCモードにおけるシグナリングの方法と、DataChannelがどのように使われているかについて紹介します

Avatar for mganeko

mganeko

July 24, 2025
Tweet

More Decks by mganeko

Other Decks in Technology

Transcript

  1. OpenAI RealTime API WebRTCモード - シグナリングとDataChannelの使い道 - WebRTC Meetup Tokyo

    #30 がねこまさし / @massie_g 自己紹介 • WebRTC Meetup Tokyo スタッフ • WebRTCで好きなもの: シグナリング
  2. OpenAI Realtime APIとは • https://platform.openai.com/docs/guides/realtime • OpenAIのマルチモーダル LLMに、リアルタイムに音声入出力するためのAPI ◦ マルチモーダルLLM

    … テキストだけでなく、画像や音声も扱える LLM ◦ OpenAIでは「gpt-4o-realtime-preview」「gpt-4o-mini-realtime-preview」が該当
  3. 通常のLLMとマルチモーダルLLMの比較 LLM Text Token Token Token Token Token Token Text

    Transformer Token マルチモーダルLLM Token Token Audio Token Transformer Token Token Token Audio Token Audio Audio
  4. 通常のLLMとマルチモーダルLLMの、音声入出力の比較 Audio マルチモーダル LLM Audio Text Text Audio SpeechToText (STT)

    LLM TextToSpeech (TTS) Audio 余計なオーバーヘッド無しに、直接音声を扱うことができる
  5. 2つの音声の入出力方式 • WebSocketで送受信 + 自分でエンコード/デコード ◦ 初期からサポート:2024年10月~ ◦ 長所:さまざまな環境で利用できる ◦

    短所:自分で音声をハンドリングするのが大変 ◦ 前回(Meetup #29)、@_katsumiさんのLTで使っていた方式 ▪ https://www.docswell.com/s/mobilebiz/59V66J-2025-03-10-131148#p1 • WebRTCによるエンコード /デコード&送受信 ◦ 途中からサポート: 2024年12月~ ◦ 長所:音声ハンドリングが楽、 UDPが使える環境なら小レイテンシーが期待できる ◦ 短所:ブラウザ、ネイティブモバイルアプリ等、 WebRTCが使える環境が限定される ◦ ※MediaStreamだけでなく、イベント通知に DataChannelも利用
  6. Realtime API WebRTC利用時のシグナリング • シグナリング … 通信に必要な情報を事前に交換するステップ ◦ 交換する内容は規定されている ▪

    SDP … メディアの種類、コーデック等 ▪ ICE candidate … 通信経路(IPアドレス/ポート等) ◦ 交換する方法は定められていない • よくある交換方法 ◦ WebSocket で初期SDP交換、あとからICE candidateを追加交換 → Trickle ICE • Realtime APIでの交換方法 ◦ HTTPのPOSTを使用( 1往復) ◦ クライアントからOffer SDPを送信 ◦ サーバーがAnswer SDPを返信
  7. Realtime API クライアント OpenAI HTTP POSTリクエスト header Content-Type: "application/sdp" Authorization:

    "Bearer token" body offer SDP (テキスト) HTTPレスポンス status code: 201 header Content-Type: "application/sdp" body answer SDP (テキスト) URL: https://api.openai.com/v1/realtime?model=モデル名 token: API Key またはエフェメラルキー どこかで見たこと あるぞ?
  8. WHIP(WebRTC-HTTP Ingestion Protocol) • WebRTCの特定のシナリオおける、シグナリング方法を定めた仕様 ◦ https://datatracker.ietf.org/doc/html/rfc9725 • シナリオ:P2Pでなく、サーバーを介した一方向の配信で利用 ◦

    通話や会議のような双方向通信ではなく ◦ 映像/音声の配信側(サーバーへの打上げ: ingestion)で利用 ▪ 従来のRTMPの代替 ▪ 代表的な配信ソフトの OBSもWHIPに対応 ◦ ※視聴側はWebRTCに限らない、従来のHLS等でもOK • どんな仕組み? ◦ 最少1回のHTTP POSTリクエストの往復で必要な情報を交換 ▪ Bearer Tokenを使った認証あり ◦ ※切断には、DELETEメソッドを利用する 10
  9. WHIP クライアント WHIP サーバー HTTPリクエスト header Content-Type: "application/sdp" Authorization: "Bearer

    token" body offer SDP HTTPレスポンス status code: 201 header Content-Type: "application/sdp" Location: whip-resource-URL body answer SDP (candidate含む)
  10. WHIPとRealtime APIシグナリングの共通点、相違点 WHIP OpenAI Realtime API 共通点 ・クライアント - サーバー間の通信

    ・クライアントからのPOSTリクエスト/レスポンスの1往復でシグナリングを完了 ・bodyがSDPのテキスト ・リクエストヘッダーに bearer tokenを入れて認証に利用 ・サーバーがパブリック IPアドレスを持つ場合はクライアント側の ICE candidate不要(*1) 相違点 クライアントからサーバーへの一方向メディア 通信 レスポンスヘッダーで locationを返し、切断時 に利用 クライアント ↔ サーバー間の双方向通信 レスポンスヘッダーに locationなし(*2) 切断はPeerConnectionのcloseを利用 MediaStreamだけでなく、 DataChannelも 利用(*3) (*1) 今回は省略。ICE LITEとも呼ばれる
  11. (*1) ICE candidate不要のケース • WebRTCの通信を開始するためには ◦ どちらか一方から、有効な ICE Candidateを渡せればOK ◦

    受け取った側が、Candidateに向けて接続を開始する • 両方のICE Candidateが必要なケース ◦ NAT越しのP2P通信の場合は、(通常)Offer側/Answer側の両方でICE Candidateを送り合う • 片方のICE Candidateだけで十分なケース ◦ Offer/Answer側を問わず、片方が確実に使える Candidateを提示できる場合 ▪ (例)インターネット上のパブリック IPアドレスを持っている(=サーバー) • 動的なcandidate収集を待たず、事前に分かっている candidateが利用可能 ▪ → ICE Liteと呼ばれる (https://datatracker.ietf.org/doc/html/rfc8445#section-2.5) • WHIPや、OpenAI Realtime APIの場合は ICE Liteに該当する ◦ クライアントがOffer側、Answer側のサーバーがパブリック IPアドレスを持つ
  12. (*2) レスポンスヘッダーのlocation • WHIPでは、レスポンスヘッダーでlocation URLを返す仕様 ◦ 例) location: /whip-resource/id/xx • 切断時には、そのURLにDELETEメソッドを投げる

    ◦ const res = await fetch("/whip-resource/id/xx", { method: 'DELETE', headers: "bearer token",}); ◦ ※いきなりPeerConnectionのclose()を呼ばない • OpenAI Realtime APIでは、locationが返ってこない ◦ 切断時にはPeerConnectionのclose()を使う
  13. (*3) MediaStreamだけでなく、DataChannelも利用 • WHIP ◦ MediaStreamで、VideoTrackとAudioTrackの両方またはどちらかを利用 ◦ クライアントからサーバーへの 1方向 ◦

    DataChannelは使わない • OpenAI RealtimeAPI ◦ MediaStreamで、AudioTrackのみ利用 ◦ クライアントとサーバー間の双方向 ◦ DataChannelも使う(オプション)
  14. サーバーからのAnswer SDP (抜粋) m=audio 9 UDP/TLS/RTP/SAVPF 111 0 8 a=sendrecv

    a=rtpmap:111 opus/48000/2 a=rtpmap:0 PCMU/8000 a=rtpmap:8 PCMA/8000 m=application 9 UDP/DTLS/SCTP webrtc-datachannel 双方向 WebRTCではopus使える (WebSocketではPCM) DataChannelも利用
  15. DataChannelの利用方法 • DataChannelはイベント通知に利用 ◦ https://platform.openai.com/docs/guides/realtime-conversations#client-and-server-events-for-a udio-in-webrtc • 例) ◦ サーバーのオーディオ返答の完了通知

    ◦ 音声ではなくテキストでのやりとり ▪ https://platform.openai.com/docs/guides/realtime-conversations#text-inputs-and-outputs ◦ function calling ▪ https://platform.openai.com/docs/guides/realtime-conversations#function-calling ▪ クライアントから、function callingの定義を渡す ▪ サーバーから、function callingの要求を返す ▪ クライアントから、function callingの結果をサーバーに知らせる
  16. マルチモーダルLLMはテキストも音声も扱える マルチモーダルLLM Token Token Audio Token Token Token Token Audio

    Token Audio Audio Text Token Token Token Token Token Token Token Text (1)発話 (3)function calling の結果の通知 (4)function結果を 受けての応答 (2)function calling の要求 Transformer
  17. DataChannelの利用:function callingの定義を渡す const config = { "type": "session.update", "session": {

    "modalities": ["text", "audio"], "instructions": "You are a helpful assistant. Please Answer in Japanese.", "voice": "ash", "temperature": 0.6, "tools": [ { "type": "function", "name": "quit_conversation", "description": "Quit current conversation and disconnect", "parameters": { } }], "tool_choice": "auto", } } datachannel.send(JSON.stringify(config));
  18. DataChannelの利用:サーバーからfunction callingの要求の受け取り datachannel.addEventListener ("message", (e) => { const realtimeEvent =

    JSON.parse(e.data); if (realtimeEvent.type === "response.done") { if (realtimeEvent.response?.output[0]?.type === "function_call") { const func = realtimeEvent.response.output[0].name; const args = realtimeEvent.response.output[0].arguments; const call_id = realtimeEvent.response.output[0].call_id; if (func === "functionの種別") { // その処理を行う } } } });
  19. DataChannelの利用:function callingの実行結果をサーバーに通知 function sendResultOfFunctionCall (dc, id, result) { const message

    = { "type": "conversation.item.create", "item": { "type": "function_call_output", "call_id": id, "output": result } } dc.send(JSON.stringify(message)); dc.send(JSON.stringify({"type": "response.create"})); }
  20. まとめ • OpenAI Realtime APIでは、WebRTCを使うモードもある • シグナリングには、HTTP POSTを使う ◦ WHIPに似ているが、拡張されている

    • 双方向音声通信と、DataChannelをうまく組み合わせている ◦ マルチモーダルLLMの特性とマッチしている • →「AIのためのWebRTC」の良い具体例になっている