Skip to content

WebRTC Diagnostics Mode #499

Description

@muke1908

Goal

Add a WebRTC diagnostics mode that exposes periodic RTCPeerConnection.getStats() snapshots and emits a new SDK event named call-metrics during active calls.

This should help developers understand what is happening inside a WebRTC audio call instead of only seeing high-level states like connected, disconnected, or failed.

Why this matters

WebRTC can fail or degrade for many reasons: bad network conditions, TURN fallback, packet loss, jitter, weak audio input, or candidate-pair changes. Browser APIs already expose this information through getStats(), but raw RTCStatsReport data is large and hard to interpret.

The SDK should provide a useful, developer-friendly metrics layer.

Functional requirements

  • Add an opt-in diagnostics configuration option, for example:
    • enable/disable diagnostics mode
    • configure snapshot interval
  • Periodically call RTCPeerConnection.getStats() while a call is active.
  • Emit a call-metrics event with normalized, easy-to-consume data.
  • Provide an on-demand method to fetch the latest stats snapshot for the active call.
  • Stop diagnostics timers when the call ends or the peer connection is disposed.
  • Avoid leaking raw unnecessary browser/network details unless they are useful for debugging.

Metrics to expose

At minimum, expose useful audio-call health data:

Network/media quality

  • Estimated bitrate
  • Round-trip time / RTT
  • Packets sent and received
  • Packets lost
  • Packet loss ratio
  • Jitter
  • Available outgoing bitrate when available

Audio visibility

  • Local audio level
  • Remote audio level if available
  • Whether local audio appears muted/silent

ICE/candidate-pair visibility

  • Selected candidate pair id
  • Local candidate type: host, srflx, relay, etc.
  • Remote candidate type: host, srflx, relay, etc.
  • Local/remote candidate address metadata when safe and useful
  • ICE connection state
  • Peer connection state

Suggested event shape

chat.on('call-metrics', (metrics) => {
  console.log(metrics.bitrateKbps);
  console.log(metrics.rttMs);
  console.log(metrics.packetLossRatio);
});

Suggested normalized payload:

type CallMetrics = {
  timestamp: number;
  bitrateKbps?: number;
  availableOutgoingBitrateKbps?: number;
  rttMs?: number;
  packetsLost?: number;
  packetLossRatio?: number;
  jitterMs?: number;
  localAudioLevel?: number;
  remoteAudioLevel?: number;
  selectedCandidatePairId?: string;
  localCandidateType?: string;
  remoteCandidateType?: string;
  iceConnectionState?: RTCIceConnectionState;
  connectionState?: RTCPeerConnectionState;
};

Learning material

This issue is a hands-on way to learn how WebRTC reports call quality.

getStats() basics

RTCPeerConnection.getStats() returns an RTCStatsReport, which is a map of many different stats objects. Important types include:

  • inbound-rtp: media received from the remote peer
  • outbound-rtp: media sent to the remote peer
  • candidate-pair: ICE connectivity pair stats
  • local-candidate: local ICE candidate details
  • remote-candidate: remote ICE candidate details
  • transport: transport-level stats and selected candidate-pair reference
  • media-source / track: audio level and media-source details, depending on browser support

Bitrate

Bitrate is usually calculated by comparing byte counters across two snapshots:

  • read bytesSent / bytesReceived
  • store previous values and timestamp
  • calculate delta bytes over delta time
  • convert bytes to bits and seconds to kilobits per second

This teaches that many WebRTC stats are counters, not instant values.

RTT

Round-trip time often comes from selected candidate-pair stats, commonly currentRoundTripTime. It is usually reported in seconds, so the SDK should convert it to milliseconds for easier use.

Packet loss

Packet loss can be estimated from inbound RTP stats:

  • packetsLost
  • packetsReceived
  • packetLossRatio = packetsLost / (packetsLost + packetsReceived)

This teaches how loss impacts real-time media quality.

Jitter

Jitter measures packet timing variation. High jitter can cause choppy or robotic audio even when packet loss is low.

Audio level

Audio level can help answer questions like:

  • Is the microphone producing input?
  • Is the user muted?
  • Is remote audio arriving but not audible?

Browser support varies, so the SDK should treat audio level fields as optional.

Candidate-pair behavior

The selected candidate pair explains the network path used by the call:

  • host means direct local/private candidate
  • srflx means server-reflexive candidate discovered through STUN
  • relay means TURN relay is being used

This helps developers understand whether the call is peer-to-peer or TURN-dependent.

Implementation notes

  • Keep the raw WebRTC API hidden behind SDK-friendly types.
  • Do not emit enormous raw RTCStatsReport objects by default.
  • Make diagnostics opt-in to avoid unnecessary CPU/battery usage.
  • Ensure timers are cleaned up on call end.
  • Handle browser differences gracefully: not all stats exist in every browser.
  • Avoid crashing if getStats() fails or returns incomplete data.

Testing ideas

  • Mock RTCPeerConnection.getStats() and verify normalized metrics.
  • Verify periodic metrics are emitted only when diagnostics mode is enabled.
  • Verify diagnostics stop after call end/dispose.
  • Verify bitrate calculation across two snapshots.
  • Verify missing optional stats do not throw.
  • Verify selected candidate-pair information is included when available.

Acceptance criteria

  • SDK supports opt-in WebRTC diagnostics mode.
  • Active calls emit call-metrics periodically.
  • Metrics include bitrate, RTT, packet loss, jitter, audio level, and selected candidate-pair information when available.
  • Consumers can request an on-demand stats snapshot.
  • Diagnostics timers are cleaned up correctly.
  • Tests cover stats normalization and event emission.
  • README/API docs explain the feature and learning purpose.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions