Service quality
You can use service quality callbacks to notify users about video, audio, and sharing quality during a session and unstable network conditions. You can also use these to measure or show latency, FPS, and resolution. Zoom Video SDK optimizes the FPS and resolution to the current device and network capabilities to optimize a good, smooth experience.
Additionally, you can build network strength indicators for your users or a real-time statistics dashboard of video, audio, and share quality. This is similar to how Zoom Meetings shares diagnostic information.
If you want near real time analytics to quickly diagnose and resolve network disruptions, consider purchasing a Quality of Service Subscription (QSS) plan to use our QSS API and webhooks for Video SDK.
Network status
The ZoomVideoSDKNetworkStatus enum includes literals representing the network status.
ZoomVideoSDKNetwork_None,
ZoomVideoSDKNetwork_Bad,
ZoomVideoSDKNetwork_Normal,
ZoomVideoSDKNetwork_Good;
To get a network status change callback, there must be at least two users in the session with their video on. You can use the network status returned from the callback to create an icon to show the current network quality.
void onUserVideoNetworkStatusChanged(ZoomVideoSDKNetworkStatus status, IZoomVideoSDKUser* pUser) {
pUser->getUserID();
pUser->getUserName();
if (status == ZoomVideoSDKNetwork_None) {}
else if (status == ZoomVideoSDKNetwork_Bad) {}
else if (status == ZoomVideoSDKNetwork_Normal) {}
else if (status == ZoomVideoSDKNetwork_Good) {}
}
QOS statistics
The onQOSStatisticsReceived callback provides real-time quality-of-service metrics for audio, video, and sharing streams. It fires for both send and receive directions, identified by the direction field on the statistics object.
The base ZoomVideoSDKQOSStatistics reference contains fields common to all stream types and directions. Check statistics.direction and static_cast to ZoomVideoSDKQOSSendStatistics or ZoomVideoSDKQOSRecvStatistics to access direction-specific fields.
void onQOSStatisticsReceived(const ZoomVideoSDKQOSStatistics& statistics, IZoomVideoSDKUser* pUser) {
// Common fields available on all statistics
statistics.direction; // ZoomVideoSDKStatisticsDirection_Send or _Receive
statistics.statisticsType; // Audio, Video, or Share
statistics.codecName; // e.g. "h264", "av1", "opus"; valid only during this callback
statistics.timestamp;
statistics.rtt;
statistics.jitter;
statistics.width;
statistics.height;
statistics.fps;
statistics.bps;
statistics.packetsLost;
statistics.packetsSent;
statistics.networkLevel;
statistics.avg_loss; // per-thousand, e.g. 100 = 10%
statistics.max_loss; // per-thousand
statistics.bandwidth;
if (statistics.direction == ZoomVideoSDKStatisticsDirection_Send) {
const ZoomVideoSDKQOSSendStatistics& sendStats =
static_cast<const ZoomVideoSDKQOSSendStatistics&>(statistics);
sendStats.frameWidthInput;
sendStats.frameHeightInput;
sendStats.frameRateInput;
sendStats.bytesSent;
sendStats.headerBytesSent; // RTP header and padding bytes sent
sendStats.packetsSent;
sendStats.totalPacketSendDelay;
sendStats.totalEncodeTime;
sendStats.framesEncoded;
} else if (statistics.direction == ZoomVideoSDKStatisticsDirection_Receive) {
const ZoomVideoSDKQOSRecvStatistics& recvStats =
static_cast<const ZoomVideoSDKQOSRecvStatistics&>(statistics);
recvStats.bytesReceived;
recvStats.headerBytesReceived; // RTP header and padding bytes received
recvStats.packetsReceived;
recvStats.estimatedPlayoutTimestamp;
recvStats.totalDecodeTime;
recvStats.framesDecoded;
recvStats.jitterBufferDelay;
recvStats.jitterBufferEmittedCount;
}
}
Video quality
When statisticsType is ZoomVideoSDKDataType_Video, the callback provides video-specific metrics such as frame dimensions, frame rate, and bitrate. To receive video statistics, there must be at least two users in the session with their video on.
Audio quality
When statisticsType is ZoomVideoSDKDataType_Audio, the callback provides audio-specific metrics such as codec, jitter, and packet loss. The width, height, and fps fields are not applicable for audio. To receive audio statistics, there must be at least two users actively sending audio to the session.
On the receive side, ZoomVideoSDKQOSRecvStatistics exposes additional audio-only metrics from the NetEQ jitter buffer and concealment engine. These are valid only when statisticsType is ZoomVideoSDKDataType_Audio and direction is ZoomVideoSDKStatisticsDirection_Receive.
if (statistics.statisticsType == ZoomVideoSDKDataType_Audio &&
statistics.direction == ZoomVideoSDKStatisticsDirection_Receive) {
const ZoomVideoSDKQOSRecvStatistics& recvStats =
static_cast<const ZoomVideoSDKQOSRecvStatistics&>(statistics);
recvStats.packetsDiscarded; // non-FEC packets discarded by NetEQ
recvStats.fecPacketsReceived; // total FEC packets received
recvStats.fecPacketsDiscarded; // FEC packets discarded by NetEQ
recvStats.jitterBufferTargetDelay; // accumulated target delay, in seconds
recvStats.jitterBufferMinimumDelay; // accumulated minimum achievable delay, in seconds
recvStats.totalSamplesReceived; // total samples generated by NetEQ
recvStats.concealedSamples; // samples produced by concealment
recvStats.silentConcealedSamples; // subset of concealedSamples that are silent
recvStats.concealmentEvents; // number of concealment events
recvStats.insertedSamplesForDeceleration; // samples inserted to slow down playout
recvStats.removedSamplesForAcceleration; // samples removed to speed up playout
recvStats.totalSamplesDuration; // total duration of received samples, in seconds
recvStats.audioLevel; // most recent audio level, range [0.0, 1.0]
recvStats.totalAudioEnergy; // accumulated audio energy
}
Sharing quality
When statisticsType is ZoomVideoSDKDataType_Share, the callback provides sharing metrics such as frame dimensions, frame rate, and bitrate. To receive share statistics, there must be at least two users in the session with at least one sharing.