Skip to content

Firefox WebRTC Realtime sessions disconnect mid-turn; likely ICE consent / USE-CANDIDATE interop #1353

Description

@crabbixOCE

Describe the bug

Firefox WebRTC sessions against OpenAI Realtime can connect successfully, exchange one or more turns, then disconnect mid-session/mid-turn. Chrome and Edge do not reproduce the issue in the same app/environment. Switching the same Firefox flow to the Realtime WebSocket transport prevents the connection from closing.

This appears to match Mozilla's active WebRTC bug report for OpenAI Realtime:

Mozilla's investigation in that thread points toward an ICE consent interop issue: Firefox consent checks do not include USE-CANDIDATE, and the OpenAI media server appears to stop responding to them. A local Firefox build that adds USE-CANDIDATE to consent checks reportedly makes the OpenAI Realtime repro work, but that is not something application JavaScript can control. If the root cause is in Realtime media infrastructure rather than this SDK, could this issue be used to track/escalate/document it from the SDK side?

Environment

  • Package: @openai/agents-realtime
  • Version observed locally: 0.10.1
  • Browser affected: Firefox
  • Browsers not affected in the same environment: Chrome, Edge
  • Transport affected: OpenAIRealtimeWebRTC
  • Workaround that works: Realtime WebSocket transport

Observed behavior

The session starts and audio/transcript events flow normally. After one or two turns, the peer connection transitions to disconnected/closed while the conversation is still active. In one case the assistant transcript continued to finalize text after audio went silent, but the WebRTC connection had already closed.

Example app-side logs:

[OpenaiRealtimeVoiceService] WebRTC peer connection state
{ reason: "iceconnectionstatechange", connectionState: "disconnected", iceConnectionState: "disconnected", iceGatheringState: "complete", signalingState: "stable" }

[OpenaiRealtimeVoiceService] WebRTC peer connection state
{ reason: "connectionstatechange", connectionState: "closed", iceConnectionState: "closed", iceGatheringState: "complete", signalingState: "closed" }

about:webrtc showed a selected/nominated candidate pair with bytes flowing before the failure. Mozilla's linked bug shows the more specific Firefox-side signature:

STUN-CLIENT(consent): Timed out

Things already tried / ruled out

  • Wake Lock / permissions-policy errors were present but unrelated; the call can start and run.
  • A Firefox getUserMedia default-device OverconstrainedError was fixed locally, but the WebRTC drop still reproduced.
  • Delaying the SDK close on connectionState === "disconnected" did not recover; the connection remained unhealthy after a grace period.
  • Forcing a TCP ICE path by removing UDP remote candidates still reproduced the drop.
  • The same application flow works in Chrome and Edge.
  • Using WebSocket for Firefox avoids the connection close.

SDK-specific note

The current WebRTC transport closes immediately on RTCPeerConnection.connectionState === "disconnected":

connection.onconnectionstatechange = () => {
  switch (connection.connectionState) {
    case 'disconnected':
    case 'failed':
    case 'closed':
      this.close();
      break;
  }
};

That may make transient disconnects worse, but in this specific Firefox/OpenAI case it does not look like the whole root cause: delaying this close locally still resulted in the peer connection remaining disconnected.

Expected behavior

Firefox WebRTC sessions should remain connected across turns, like Chrome/Edge, or the SDK/docs should provide a known Firefox workaround if this is currently a Realtime media-server/browser interop limitation.

Questions

  1. Is OpenAI already tracking the ICE consent / USE-CANDIDATE issue raised in the Mozilla thread?
  2. Is there any recommended client-side WebRTC workaround other than falling back to WebSocket for Firefox?
  3. Should OpenAIRealtimeWebRTC avoid immediately calling close() on connectionState === "disconnected", even if that is only a secondary robustness fix?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions