The OpenTok Windows SDK provides calls to access real-time network and media statistics in a video session. These calls report detailed stream quality metrics—such as packet loss, data received, and bandwidth—and can be used on any publisher or subscribed stream.
The OpenTok Video SDK exposes detailed stream-quality metrics through a high-level statistics API—recommended for most use cases—which provides audio, video, network, and sender-side statistics in a unified, session-aware form that remains stable across peer-connection transitions. For advanced debugging, the SDK also offers access to the raw WebRTC stats report, which reflects unprocessed peer-connection data.
The SDK also exposes network condition metrics that provide a high-level assessment of connection health for both publishers and subscribers. These metrics include a network condition score, the reason driving that score, and—for subscribers—a degradation source indicating which side of the connection is responsible for any observed issues. See Network condition and degradation source for details.
This guide includes the following sections:
The OpenTok Windows SDK sends periodic audio, video, and media link statistics for both publishers and subscribers. These include packet counts, bitrates, frame rate data, pause/freeze metrics, codec information, and transport-level network metrics such as bandwidth estimation and network condition scoring.
Statistics are delivered through the following events:
Publisher.AudioStatsUpdated — publisher-side audio statsPublisher.VideoStatsUpdated — publisher-side video statsPublisher.MediaLinkStatsUpdated — publisher-side media link stats (transport metrics)Publisher.VideoQualityChanged — publisher video quality change notificationPublisher.NetworkConditionChanged — publisher network condition change notificationSubscriber.AudioStatsUpdated — subscriber-side audio statsSubscriber.VideoStatsUpdated — subscriber-side video statsSubscriber.MediaLinkStatsUpdated — subscriber-side media link stats (transport metrics)Subscriber.VideoQualityChanged — subscriber video quality change notificationSubscriber.NetworkConditionChanged — subscriber network condition change notificationTo receive them, set the appropriate event handler on the publisher or subscriber.
Set the corresponding event handlers for Publisher.AudioStatsUpdated and Publisher.VideoStatsUpdated:
publisher.AudioStatsUpdated += (sender, args) =>
{
foreach (var stat in args.Stats)
{
Console.WriteLine($"Audio bytes sent: {stat.BytesSent}");
}
};
publisher.VideoStatsUpdated += (sender, args) =>
{
foreach (var stat in args.Stats)
{
Console.WriteLine($"Video packets sent: {stat.PacketsSent}");
}
};
publisher.MediaLinkStatsUpdated += (sender, args) =>
{
foreach (var stat in args.MediaLinkStats)
{
Console.WriteLine($"Publisher uplink bandwidth: {stat.Transport.ConnectionEstimatedBandwidth} bps");
Console.WriteLine($"Network condition: {stat.Transport.Condition}");
Console.WriteLine($"Condition reason: {stat.Transport.NetworkConditionReason}");
}
};
These events are sent periodically to report audio and video statistics for the publisher.
The event handlers for these are passed in an array of
AudioNetworkStats
and VideoNetworkStats
Each method is passed in two objects: the publisher and an array of stats
objects. For a publisher in a routed session (one that uses the
OpenTok
Media Router), the array includes one object, defining the statistics for
the single audio or video media stream that is sent to the Vonage Video Media Router.
In a relayed session, the array includes an object for each subscriber to
the published stream.
If you are also interested in video quality events implement this handler:
publisher.VideoQualityChanged += (sender, args) =>
{
Console.WriteLine($"Publisher video quality changed: {args.Reason}");
};
To receive network condition change events for the publisher, subscribe to the Publisher.NetworkConditionChanged event:
publisher.NetworkConditionChanged += (sender, args) =>
{
Console.WriteLine($"Publisher network condition: {args.MediaLinkStats.Transport.Condition}");
Console.WriteLine($"Reason: {args.MediaLinkStats.Transport.NetworkConditionReason}");
};
This event is triggered when a significant change in network condition is detected for the publisher. It includes the current media link statistics with transport metrics.
Set the corresponding event handlers for Subscriber.AudioStatsUpdated and Subscriber.VideoStatsUpdated:
subscriber.VideoStatsUpdated += (sender, stats) =>
{
Console.WriteLine($"Video bytes received: {stats.BytesReceived}");
};
subscriber.AudioStatsUpdated += (sender, stats) =>
{
Console.WriteLine($"Audio packets received: {stats.PacketsReceived}");
};
subscriber.MediaLinkStatsUpdated += (sender, args) =>
{
Console.WriteLine($"Local downlink bandwidth: {args.MediaLinkStats.Transport.ConnectionEstimatedBandwidth} bps");
if (args.MediaLinkStats.RemotePublisherTransport != null)
{
Console.WriteLine($"Remote publisher uplink bandwidth: {args.MediaLinkStats.RemotePublisherTransport.ConnectionEstimatedBandwidth} bps");
}
Console.WriteLine($"Degradation source: {args.MediaLinkStats.NetworkDegradationSource}");
};
If you are also interested in video quality events implement this handler:
subscriber.VideoQualityChanged += (sender, args) =>
{
Console.WriteLine($"Subscriber video quality event: {args.Reason}");
};
To receive network condition change events for the subscriber, subscribe to the Subscriber.NetworkConditionChanged event:
subscriber.NetworkConditionChanged += (sender, args) =>
{
Console.WriteLine($"Local network condition: {args.MediaLinkStats.Transport.Condition}");
Console.WriteLine($"Remote publisher network condition: {args.MediaLinkStats.RemotePublisherTransport.Condition}");
Console.WriteLine($"Degradation source: {args.MediaLinkStats.NetworkDegradationSource}");
};
This event is triggered when a significant change in network condition is detected for the subscriber or the remote publisher. It includes the current media link statistics with local and remote transport metrics and degradation source.
This section outlines the structs and fields provided by the Windows Video SDK audio and video statistics API. While all Video SDK platforms expose the same set of statistics, there may be minor differences in how each platform structures or names individual fields. These variations reflect platform-specific SDK design conventions rather than differences in the underlying metrics.
For a platform-independent explanation of the available statistics and what they represent, refer to client observability overview.
TransportStatsRepresents transport-level metrics.
ConnectionEstimatedBandwidth — Estimated available connection bandwidth (bps)Condition — Current network condition score (NetworkCondition.Unknown, NetworkCondition.Critical, NetworkCondition.Warning, NetworkCondition.Fair, NetworkCondition.Good, or NetworkCondition.Excellent)NetworkConditionReason — Primary reason impacting the network condition (NetworkReason.None, NetworkReason.Unknown, NetworkReason.Bandwidth, or NetworkReason.PacketLoss)Publisher.AudioNetworkStatsProvides statistics about a publisher’s audio track.
ConnectionId — Subscriber connection ID (relayed only)SubscriberId — Subscriber ID (relayed only)PacketsLost — Total audio packets lostPacketsSent — Total audio packets sentBytesSent — Total audio bytes sentTimestamp — Timestamp when stats were gathered (ms)StartTime — Timestamp when cumulative totals began (ms)Publisher.VideoNetworkStatsProvides statistics about a publisher’s video track.
ConnectionId — Subscriber connection ID (relayed only)SubscriberId — Subscriber ID (relayed only)PacketsLost — Video packets lostPacketsSent — Video packets sentBytesSent — Video bytes sentTimestamp — Timestamp when stats were gatheredStartTime — Timestamp when cumulative totals beganVideoLayers — List of simulcast/SVC layers (VideoLayerStats)Publisher.VideoLayerStatsRepresents a single simulcast or SVC video layer.
Width — Encoded frame widthHeight — Encoded frame heightEncodedFrameRate — Encoded frames per secondBitrate — Layer bitrate (bps)TotalBitrate — Bitrate including RTP overhead (bps)ScalabilityMode — SVC/scalability description (e.g., "L3T3")QualityLimitationReason — Reason for quality reductionCodec — Codec used for this layerPublisher.PublisherMediaLinkStatsProvides transport-level statistics for a publisher's connection.
Transport — Transport statistics for this publisher (see TransportStats)Subscriber.AudioNetworkStatsEventArgsProvides statistics about a subscriber’s audio track.
PacketsLost — Estimated audio packets lostPacketsReceived — Audio packets receivedBytesReceived — Audio bytes receivedTimestamp — Timestamp when stats were gatheredSenderStats — Sender-side network estimation (optional)Subscriber.VideoNetworkStatsEventArgsProvides statistics about a subscriber’s video track.
PacketsLost — Video packets lostPacketsReceived — Video packets receivedBytesReceived — Video bytes receivedTimestamp — Timestamp when stats were gatheredSenderStats — Sender-side network estimation (optional)Width — Decoded frame widthHeight — Decoded frame heightDecodedFrameRate — Decoded frames per secondBitrate — Video bitrate (bps)TotalBitrate — Total bitrate including RTP overheadPauseCount — Number of video pauses (>5s without a frame)TotalPausesDuration — Total pause duration (ms)FreezeCount — Number of WebRTC-defined freezesTotalFreezesDuration — Total freeze duration (ms)Codec — Decoder codecSubscriber.SubscriberMediaLinkStatsProvides transport-level statistics for a subscriber's connections, including visibility into the remote publisher's network performance. This enables applications to diagnose whether connection issues originate from the subscriber's downlink or the publisher's uplink.
Transport — Transport statistics for this subscriber's downlink connection (see TransportStats)RemotePublisherTransport — Transport statistics for the remote publisher's uplink connection (see TransportStats). May be limited if sender-side statistics are not enabled.NetworkDegradationSource — Indicates the source of network degradation, if any (NetworkDegradationSource.None, NetworkDegradationSource.Local, NetworkDegradationSource.Remote, or NetworkDegradationSource.BothOrUnclear)See the sender-side statistics overview.
Sender-side statistics are received on the subscribers. To receive sender-side statistics, enable them for the stream’s publisher by setting the HasSenderStatsTrack property to true when building the publisher:
var publisherBuilder = new Publisher.Builder()
{
HasSenderStatsTrack = true
};
Publisher publisher = publisherBuilder.Build();
If HasSenderStatsTrack is not enabled, no sender statistics channel will be published for this publisher. The default value is false.
If the publisher has enabled sender-side statistics, subscribers receive them automatically via the VideoStatsUpdated and AudioStatsUpdated events described above. The SenderStats property on both VideoNetworkStatsEventArgs and AudioNetworkStatsEventArgs provides two metrics:
ConnectionMaxAllocatedBitrate — The maximum bitrate that can be estimated for the connectionConnectionEstimatedBandwidth — The current estimated bandwidth for the connectionThese metrics are calculated per audio-video bundle, so the same values appear in both video and audio statistics.
subscriber.VideoStatsUpdated += (sender, stats) =>
{
if (stats.SenderStats != null)
{
Console.WriteLine($"Connection max allocated bitrate: {stats.SenderStats.ConnectionMaxAllocatedBitrate}");
Console.WriteLine($"Connection current estimated bandwidth: {stats.SenderStats.ConnectionEstimatedBandwidth}");
}
};
The SDK provides real-time network condition metrics for both publishers and subscribers, including a condition score, the reason driving that score, and a degradation source for subscribers. For a full explanation of the network condition model, scores, reasons, and how to enable it, see the client observability overview.
Network condition data is available through two channels:
Condition and NetworkConditionReason. For subscribers, media link stats also include RemotePublisherTransport and NetworkDegradationSource.The following example shows how to use the subscriber network condition data to identify the source of degradation:
subscriber.NetworkConditionChanged += (sender, args) =>
{
var localCondition = args.MediaLinkStats.Transport.Condition;
var remoteCondition = args.MediaLinkStats.RemotePublisherTransport.Condition;
var source = args.MediaLinkStats.NetworkDegradationSource;
if (source == NetworkDegradationSource.Local)
{
Console.WriteLine($"Local network is degraded (condition: {localCondition})");
}
else if (source == NetworkDegradationSource.Remote)
{
Console.WriteLine($"Remote publisher network is degraded (condition: {remoteCondition})");
}
else if (source == NetworkDegradationSource.BothOrUnclear)
{
Console.WriteLine($"Degradation source unclear — local: {localCondition}, remote: {remoteCondition}");
}
};
Use the RTC stats API for WebRTC-level diagnostic data. To get a publisher low-level peer connection statistics, use the
Publisher.GetRtcStatsReport() method. This provides
RTC stats reports for the media stream. This is an asynchronous operation.
When the stats are available, the RtcStatsReport event is sent.
The RtcStatsReportArgs object includes an array of
PublisherRtcStats
objects, which includes a JsonArrayOfReports property. This is a
JSON array of RTC stats reports, which are similar to
the format the RtcStatsReport object implemented in web browsers (see
these Mozilla docs).
Also see this W3C documentation.
To get a subscriber low-level peer connection statistics, use the
Subscriber.GetRtcStatsReport() method. This provides an
RTC stats report for the media stream. This is an asynchronous operation.
When the stats are available, the RtcStatsReport event is sent.
The RtcStatsReportArgs
object includes a JsonArrayOfReports property. This is a
JSON array of RTC stats reports, which are similar to
the format the RtcStatsReport object implemented in web browsers (see
these Mozilla docs).
Also see this W3C documentation.
Requesting an RTC stats report for a publisher:
publisher.RtcStatsReport += (sender, args) =>
{
foreach (var stat in args.stats)
{
Console.WriteLine(stat.JsonArrayOfReports); // Raw RTC JSON
}
};
publisher.GetRtcStatsReport();