WARP를 사용한 WebRTC

WARP를 사용한 WebRTC (WebRTC with WARP)

출처: 문서

WebRTC Abridged Roundtrip Protocol(WARP)를 사용하면 Realtime API 음성 세션을 시작하는 데 걸리는 시간을 줄일 수 있어요. WARP는 DTLS 1.3, SPED, SNAP, 그리고 사전 협상된(pre-negotiated) 데이터 채널을 결합해 더 적은 네트워크 왕복(round trip)으로 연결을 설정해요.

WARP, SPED, SNAP은 IETF Internet-Draft이므로 사양과 클라이언트 지원이 변경될 수 있어요.

이 최적화들을 개별적으로도 사용할 수 있어요. 전체 WARP를 사용할 수 없더라도 클라이언트가 지원하는 기능을 활성화해 연결 지연 시간을 줄여요. 모든 기능을 함께 사용하면 완전한 WARP 핸드셰이크가 돼요.

네이티브 클라이언트에서 WARP 활성화하기

최신 libwebrtc 버전에는 WARP 최적화가 포함돼 있어요. 네이티브 클라이언트가 호환되는 libwebrtc 빌드를 사용하면 다음 field trials를 활성화해요:

WebRTC-ForceDtls13/Enabled/
WebRTC-Sctp-Snap/Enabled/
WebRTC-IceHandshakeDtls/Enabled/

일부 통합에서는 하나로 합쳐진 field-trial 문자열이 필요해요:

WebRTC-ForceDtls13/Enabled/WebRTC-Sctp-Snap/Enabled/WebRTC-IceHandshakeDtls/Enabled/

peer connection factory를 만들기 전에 field trials를 초기화해요. 예를 들어 Rust 통합은 세 가지 trial을 함께 활성화할 수 있어요:

const WARP_FIELD_TRIALS: &str = concat!(
    "WebRTC-ForceDtls13/Enabled/",
    "WebRTC-Sctp-Snap/Enabled/",
    "WebRTC-IceHandshakeDtls/Enabled/",
);

webrtc_sys::peer_connection_factory::ffi::initialize_field_trials(
    WARP_FIELD_TRIALS.to_string(),
);

libwebrtc를 감싸는 SDK(예: 네이티브 LiveKit SDK)를 사용한다면, WebRTC 구성 또는 초기화 옵션을 통해 동일한 field-trial 문자열을 전달해요. SDK가 field trials를 노출하지 않으면, SDK가 peer connection factory를 만들기 전에 기반 libwebrtc 인스턴스를 초기화하거나, 이 구성을 제공하는 래퍼로 업데이트해요.

Trials를 활성화한 후 사용 가능한 아무 ID로 협상된(negotiated) 데이터 채널을 만들어요. SDP offer를 /v1/realtime/calls로 보낼 때 dcid 쿼리 파라미터에 같은 ID를 포함해요.

브라우저에서 WARP 활성화하기

Chrome, Edge 등 Chromium 기반 브라우저는 libwebrtc를 번들하지만, 웹 페이지가 field trials를 구성할 수는 없어요. Origin trial은 등록된 웹사이트에 실험적 브라우저 기능을 활성화해 줘요. 각 WARP 기능의 가용성을 확인해요:

  • DTLS 1.3: Chrome은 origin trial 없이 DTLS 1.3을 지원해요.
  • SNAP: Chrome 151–156은 origin trial을 통해 SNAP을 지원해요. Edge에서는 사용 버전에 SNAP origin trial이 있는지 확인하고, Edge가 발급한 토큰을 등록해요.
  • SPED: 브라우저 origin trial이 없어요. SPED 지원은 나중에 다시 확인해 보세요. 완전한 WARP를 사용하려면 브라우저가 SPED를 기본적으로 활성화해야 하거나, 시작 플래그를 제어하고 필요한 field trials를 직접 활성화해야 해요.

SNAP origin trial을 활성화한다고 해서 SPED나 완전한 WARP가 활성화되지는 않아요. 브라우저가 SPED를 노출하지 않으면, DTLS 1.3과 SNAP origin trial만 사용해도 해당 개별 최적화의 이점을 얻을 수 있어요.

브라우저의 origin trials를 확인해요:

SNAP origin trial을 활성화하려면:

  1. 브라우저의 origin trials 페이지를 열고 WebRTC Data Channel: SCTP Negotiation Acceleration Protocol (SNAP) 을 찾아요.
  2. Register 를 선택하고 애플리케이션의 origin(예: https://example.com)을 입력해요.
  3. RTCPeerConnection을 만드는 스크립트 앞, 페이지의 <head>에 발급된 토큰을 추가해요:
   <meta http-equiv="origin-trial" content="YOUR_ORIGIN_TRIAL_TOKEN" />
  1. 페이지를 새로고침해요. Chrome에서 DevTools를 열고 Application 을 선택한 다음, Origin Trials 아래에 WebRtcSctpSnap이 나타나는지 확인해요.

토큰은 HTTP 응답 헤더로도 제공할 수 있어요:

Origin-Trial: YOUR_ORIGIN_TRIAL_TOKEN

Origin-trial 토큰은 해당 이름의 기능, 발급 브라우저, 등록된 origin에만 적용돼요. SNAP 토큰은 SPED를 활성화하지 않고, Chrome 토큰은 Edge에서 trial을 활성화하지 않아요. Firefox, Safari, iOS 브라우저, 그리고 오래된 Chromium 빌드는 완전한 WARP를 지원하지 않으면서도 표준 WebRTC를 지원할 수 있어요.

통합 인터페이스로 연결하기

통합 WebRTC 연결 흐름을 사용하면 Realtime API 연결이 더 빨라져요. 브라우저가 SDP offer와 협상된 데이터 채널 ID를 애플리케이션 서버로 보내요. 서버는 /v1/realtime/calls를 호출할 때 dcid 쿼리 파라미터에 같은 ID를 전달해요.

애플리케이션 서버 구성하기

이 애플리케이션 서버는 표준 WebRTC와 WARP를 모두 지원해요. WARP only로 표시된 주석은 WARP에 필요한 dcid 전달을 식별해 줘요:

import express from "express";

const app = express();

// Parse raw SDP payloads posted from the browser
app.use(express.text({ type: ["application/sdp", "text/plain"] }));

const sessionConfig = JSON.stringify({
  type: "realtime",
  model: "gpt-realtime-2.1",
  audio: { output: { voice: "marin" } },
});

// An endpoint which creates a Realtime API session.
app.post("/session", async (req, res) => {
  const fd = new FormData();
  fd.set("sdp", req.body);
  fd.set("session", sessionConfig);

  const endpoint = new URL("https://api.openai.com/v1/realtime/calls");

  // WARP only: forward the negotiated data-channel ID to the Realtime API.
  if (typeof req.query.dcid === "string") {
    endpoint.searchParams.set("dcid", req.query.dcid);
  }

  try {
    const r = await fetch(endpoint, {
      method: "POST",
      headers: {
        Authorization: *** ${process.env.OPENAI_API_KEY}`,
        "OpenAI-Safety-Identifier": "hashed-user-id",
      },
      body: fd,
    });
    // Send back the SDP we received from the OpenAI REST API
    const sdp = await r.text();
    res.send(sdp);
  } catch (error) {
    console.error("Token generation error:", error);
    res.status(500).json({ error: "Failed to generate token" });
  }
});

app.listen(3000);

브라우저에서 연결하기

브라우저에서 사용 가능한 최적화를 활성화한 후 useWarp를 true로 설정해요. 사용 가능한 데이터 채널 ID를 선택하고 같은 ID를 서버에 전달해요. WARP only로 표시된 주석은 표준 WebRTC에는 필요하지 않은 구성과 시그널링을 식별해 줘요:

// WARP only: set to true after enabling the supported WARP optimizations.
const useWarp = false;

// WARP only: choose any available data-channel ID.
const dataChannelId = 4;

// Create a peer connection
const pc = new RTCPeerConnection();

// Set up to play remote audio from the model
audioElement.current = document.createElement("audio");
audioElement.current.autoplay = true;
pc.ontrack = (e) => (audioElement.current.srcObject = e.streams[0]);

// Add local audio track for microphone input in the browser
const ms = await navigator.mediaDevices.getUserMedia({
  audio: true,
});
pc.addTrack(ms.getTracks()[0]);

// Set up the event channel using any channel label.
// WARP only: pre-negotiate the channel using the selected data-channel ID.
const dc = pc.createDataChannel(
  "events",
  useWarp ? { negotiated: true, id: dataChannelId } : undefined,
);

// Start the session using the Session Description Protocol (SDP)
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);

const endpoint = new URL("/session", window.location.origin);

// WARP only: include the matching data-channel ID in the session request.
if (useWarp) {
  endpoint.searchParams.set("dcid", String(dataChannelId));
}

const sdpResponse = await fetch(endpoint, {
  method: "POST",
  body: offer.sdp,
  headers: {
    "Content-Type": "application/sdp",
  },
});

const answer = {
  type: "answer",
  sdp: await sdpResponse.text(),
};
await pc.setRemoteDescription(answer);

WARP를 지원하지 않는 클라이언트 사용하기

WebRTC 클라이언트가 libwebrtc를 사용하지 않는다면, WARP 호환 전송 최적화를 WebRTC 스택에 추가하거나 해당 스택이 지원하는 다른 접근 방식을 사용해요. 관련 사양은 WARP, SPED, SNAP, DTLS 1.3, data channel establishment이에요.

이 최적화들을 사용할 수 없다면 통합 WebRTC 인터페이스를 사용해요.