Subscribe: Diagnostics
Use this guide to inspect stream details, detect when streams end, and resolve common subscriber issues. It also includes guidance for handling connectivity problems in the UI.
Stream information
Get diagnostic details for active streams to aid debugging and analysis.
To get audio and video statistics for subscribers, add event handlers for the audioNetworkStats and videoNetworkStats event dispatched by the OTSubscriber. These provide information about the subscriber's stream, including the following:
- The total number of audio and video packets lost.
- The total number of audio and video packets received.
- The total number of audio and video bytes received.
- The current average video frame rate.
<OTSubscriber
eventHandlers={{
audioNetworkStats: event => {
console.log('subscriber audioNetworkStats event', event);
},
videoNetworkStats: event => {
console.log('subscriber videoNetworkStats event', event);
},
}}
/>
To get more detailed stream statistics, use the Subscriber.getRtcStatsReport() method of the OTSubscriber object. It returns a promise that, on success, resolves with a JSON representation of an RtcStatsReport object for the subscribed stream:
<OTSubscriber
eventHandlers={{
connected: event => {
setTimeout(() => {
this.subscriber.getRtcStatsReport();
}, 4000);
},
rtcStatsReport: event => {
console.log('subscriber rtcStatsReport event', event);
},
}}
/>
The Stream object has the following properties that define the stream:
connection— The Connection object corresponding to the connection that is publishing the stream. You can compare this to the connection property of the Session object to see if the stream is being published by the local web page.creationTime— The timestamp (a number) for the creation of the stream. This value is calculated in milliseconds. You can convert this value to a Date object by callingnew Date(stream.creationTime).hasAudio— (Boolean) Whether the stream has audio. This property can change if the publisher turns on or off audio (by calling Publisher.publishAudio()). When this occurs, the Session object dispatches astreamPropertyChangedevent.hasVideo— (Boolean) Whether the stream has video. initials—(Boolean) The initials for the stream (if initials were set when the stream's publisher was initialized).name— (String) The name of the stream. This is, by default, displayed when the user mouses over the Subscriber in the HTML DOM. You can, however, customize the UI to hide the name or display it without mousing over.videoDimensions— This object has two properties:widthandheight. Both are numbers. Thewidthproperty is the width of the encoded stream; theheightproperty is the height of the encoded stream. (These are independent of the actual width of Publisher and Subscriber objects corresponding to the stream.) This property can change if a stream published from an iOS device resizes, based on a change in the device orientation.videoType— The type of video: either "camera", "screen", "custom", or undefined. A "screen" video uses screen sharing on the publisher as the video source; a "custom" video uses a VideoTrack element as the video source on the publisher. ThevideoTypeisundefinedwhen a stream is voice-only (see the Voice-only guide). This property can change if a stream published from a mobile device changes from a camera to a screen-sharing video type. For more information, see Screen sharing — Web.
The hasAudio, hasVideo, videoDimensions, and videoType properties can change (for example, when the publisher turns on or off video). When this occurs, the Session object dispatches a streamPropertyChanged event (see StreamPropertyChangedEvent).
The getStats() method of a Subscriber object provides you with information about the subscriber's stream, including the following:
- The total number of audio and video packets lost
- The total number of audio and video packets received
- The total number of audio and video bytes received
- The current average video frame rate
The following code logs the audio packet loss ratio, the audio bit rate, and the video packet loss ratio, and the video bit rate for a subscriber every second:
var prevStats;
window.setInterval(function() {
subscriber.getStats(function(error, stats) {
if (error) {
console.error('Error getting subscriber stats. ', error.message);
return;
}
if (prevStats) {
var videoPacketLossRatio = stats.video.packetsLost /
(stats.video.packetsLost + stats.video.packetsReceived);
console.log('video packet loss ratio: ', videoPacketLossRatio);
var videoBitRate = 8 * (stats.video.bytesReceived - prevStats.video.bytesReceived);
console.log('video bit rate: ', videoBitRate, 'bps');
var audioPacketLossRatio = stats.audio.packetsLost /
(stats.audio.packetsLost + stats.audio.packetsReceived);
console.log('audio packet loss ratio: ', audioPacketLossRatio);
var audioBitRate = 8 * (stats.audio.bytesReceived - prevStats.audio.bytesReceived);
console.log('audio bit rate: ', audioBitRate, 'bps');
}
prevStats = stats;
});
}, 1000);
To get statistics for a stream published by the local client, you must use a session that uses the OpenTok Media Router (sessions with the media mode set to routed), and you must set the testNetwork property to true in the options object you pass into the Session.subscribe() method:
var publisher = OT.initPublisher();
publisher.on('streamCreated', function(event)) {
var subscriberOptions = {testNetwork: true};
var subscriber = session.subscribe(event.stream, 'publisher-element', subscriberOptions);
}
To get more detailed stream statistics, use the Subscriber.getRtcStatsReport() method. It returns a promise that, on success, resolves with an RtcStatsReport object for the subscribed stream:
subscriber.getRtcStatsReport()
.then((stats) => stats.forEach(console.log))
.catch(console.log);
The Stream object has the following methods that return values that define the stream:
getConnection()— (Connection) Returns the Connection object corresponding to the connection that is publishing the stream. You can compare this to the value returned by thegetConnection()method of the Session object to see if the stream is being published by your client.getCreationTime()— (Date) The Date timestamp for the creation time of the stream.hasAudio()— (boolean) Whether the stream has audio.hasVideo()— (boolean) Whether the stream has video.getName()— (String) Returns the name of the stream. This is set when you initialize the Publisher of the stream (see Initializing a Publisher object).getStreamId()— (String) The unique ID for the stream.getVideoHeight()— (int) The height of the stream, in pixels.getVideoType()— (StreamVideoType) Whether the stream uses a camera video source (StreamVideoTypeCamera.StreamVideoTypeCamera), a screen-sharing video source (StreamVideoTypeScreen.StreamVideoTypeScreen), or a custom video source (StreamVideoTypeScreen.StreamVideoTypeScreen).
See Screen sharing.
getVideoWidth()— (int) The width of the stream, in pixels.
You can set listeners to monitor the following statistics for a subscriber's stream:
- The total number of audio and video packets lost
- The total number of audio and video packets received
- The total number of audio and video bytes received
See the SubscriberKit.setAudioStatsListener(AudioStatsListener listener) and SubscriberKit.setVideoStatsListener(VideoStatsListener listener) methods.
To get statistics for a stream published by the local client, you must use a session that uses the Vonage Video Media Router (sessions with the media mode set to routed).
To get more detailed stream statistics, use the SubscriberKit.getRtcStatsReport() method. This provides an RTC stats report for the media stream.
This is an asynchronous operation. Call the SubscriberKit.setRtcStatsReportListener(SubscriberKit.SubscriberRtcStatsReportListener listener) method, and then implement the SubscriberKit.SubscriberRtcStatsReportListener.onRtcStatsReport(SubscriberKit subscriber, java.lang.String jsonArrayOfReports) method prior to calling SubscriberKit.getRtcStatsReport().
When the stats are available, the implementation of the SubscriberKit.SubscriberRtcStatsReportListener.onRtcStatsReport(SubscriberKit subscriber, java.lang.String jsonArrayOfReports) method is called. The jsonArrayOfReports parameter is a JSON array of RTC stats reports, which are similar to the format of the RtcStatsReport object implemented in web browsers (see these Mozilla docs).
Also see this W3C documentation.
The OTStream object has the following properties that define the stream:
connection—The OTConnection object corresponding to the connection that is publishing the stream. You can compare this to theconnectionproperty of the OTSession object to see if the stream is being published by your client.creationTime—The Date timestamp for the creation time of the stream.hasAudio—(Bool) Whether the stream has audio.hasVideo—(Bool) Whether the stream has video.name—(String?) The name of the stream. This is set when you initialize the Publisher of the stream (see Initializing an OTPublisher object).session—(OTSession) The Vonage Video session to which the stream is bound.streamId—(String) The unique ID for the stream.videoDimensions—A CGSize object defining the current dimensions of the video media track on this stream.videoType—(OTStreamVideoType) Whether the stream uses a camera video source (OTStreamVideoTypeCamera), a screen-sharing video source (OTStreamVideoTypeScreen), or a custom video source (OTStreamVideoTypeCustom).
See Screen sharing.
You can set a OTSubscriberKitNetworkStatsDelegate object for the OTSubscriberKit object to monitor the following statistics for a subscriber's stream:
- The total number of audio and video packets lost
- The total number of audio and video packets received
- The total number of audio and video bytes received
See the SubscriberKit.networkStatsDelegate property.
To get statistics for a stream published by the local client, you must use a session that uses the Vonage Video Media Router (sessions with the media mode set to routed).
The OTStream object has the following properties that define the stream:
connection—The OTConnection object corresponding to the connection that is publishing the stream. You can compare this to theconnectionproperty of the OTSession object to see if the stream is being published by your client.creationTime—The NSDate timestamp for the creation time of the stream.hasAudio—(Boolean) Whether the stream has audio.hasVideo—(Boolean) Whether the stream has video.name—(NSString) The name of the stream. This is set when you initialize the Publisher of the stream (see Initializing an OTPublisher object).session—(OTSession) The Vonage Video session to which the stream is bound.streamId—(NSString) The unique ID for the stream.videoDimensions—A CGSize object defining the current dimensions of the video media track on this stream.videoType—(OTStreamVideoType) Whether the stream uses a camera video source (OTStreamVideoTypeCamera), a screen-sharing video source (OTStreamVideoTypeScreen), or a custom video source (OTStreamVideoTypeCustom).
See Screen sharing.
You can set a OTSubscriberKitNetworkStatsDelegate object for the OTSubscriberKit object to monitor the following statistics for a subscriber's stream:
- The total number of audio and video packets lost
- The total number of audio and video packets received
- The total number of audio and video bytes received
See the SubscriberKit.networkStatsDelegate property.
To get statistics for a stream published by the local client, you must use a session that uses the Vonage Video Media Router (sessions with the media mode set to routed).
To get more detailed stream statistics, use the [OTSubscriberKit getRtcStatsReport:] method. This provides an RTC stats report for the media stream.
This is an asynchronous operation. Set the [OTSubscriberKit rtcStatsReportDelegate]> property and implement the >[OTSubscriberKitRtcStatsReportDelegate subscriber:rtcStatsReport:]> method prior to calling [OTSubscriberKit getRtcStatsReport:].
When the stats are available, the implementation of the >[OTSubscriberKitRtcStatsReportDelegate subscriber:rtcStatsReport:]> message is sent. The message includes an a jsonArrayOfReports parameter.
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.
The Stream object has the following properties that define the stream:
Connection— (Connection) The Connection object corresponding to the connection that is publishing the stream. You can compare this to theConnectionproperty of the Session object to see if the stream is being published by your client.CreationTime— (DateTime) The DateTime timestamp for the creation time of the stream.HasAudio— (bool) Whether the stream has audio.HasVideo— (bool) Whether the stream has video.Name— (string) The name of the stream. This is set when you initialize the Publisher of the stream (see Initializing a Publisher object).Id— (string) The unique ID for the stream.Height— (int) The height of the stream, in pixels.VideoSourceType— (VideoSourceType) Whether the stream uses a camera video source (VideoSourceType.StreamVideoTypeCamera), a screen-sharing video source (VideoSourceType.StreamVideoTypeScreen), or a custom video source (VideoSourceType.StreamVideoTypeCustom).
See Screen sharing.
Width— (int) The width of the stream, in pixels.
You use the Subscriber.AudioStatsUpdated and Subscriber.VideoStatsUpdated events to monitor the following statistics for a subscriber's stream:
- The total number of audio and video packets lost
- The total number of audio and video packets received
- The total number of audio and video bytes received
To get more detailed stream 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.
Call the following functions to get information about a stream:
otc_stream_get_connection()— Returns theotc_connectioninstance corresponding to the connection that is publishing the stream. You can compare the connection ID for this to the connection ID for theotc_connectioninstance returned by theotc_session_get_connection()function to see if the stream is being published by your client.otc_stream_get_creation_time()— Returns the timestamp for the creation time of the stream.otc_stream_has_audio()— Whether the stream is currently publishing audio.otc_stream_has_video()— Whether the stream is currently publishing video.otc_stream_has_audio_track()— Whether the stream has an audio track.otc_stream_has_video_track()— Whether the stream has a video track.otc_stream_get_name()— Returns the name of the stream. This is set when you initialize the Publisher of the stream (see Initializing an otc_publisher struct and setting publisher callbacks).otc_stream_get_id()— Returns the unique ID for the stream.otc_stream_get_video_height()— The height of the stream, in pixels.otc_stream_get_video_type()— Whether the stream uses a camera video source (OTC_STREAM_VIDEO_TYPE_CAMERA) or a screen-sharing video source (OTC_STREAM_VIDEO_TYPE_SCREEN).otc_stream_get_video_width()— The width of the stream, in pixels.
Use the on_audio_stats() and on_video_stats() callback functions of the otc_subscriber_callbacks to monitor the following statistics for a subscriber's stream:
- The total number of audio and video packets lost
- The total number of audio and video packets received
- The total number of audio and video bytes received
To get more detailed stream statistics, use the otc_subscriber_get_rtc_stats_report() function. This provides an RTC stats report for the media stream.
This is an asynchronous operation. Create an otc_subscriber_rtc_stats_report_cb struct and pass it into the otc_subscriber_set_rtc_stats_report_cb function prior to calling otc_subscriber_get_rtc_stats_report(). When the stats are available, the otc_subscriber_rtc_stats_report_cb.on_rtc_stats_report callback function is called.
This callback function includes a json_array_of_reports parameter. 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.
Detect stream end and video disabled
Detect when a stream ends so you can perform cleanup and adjust the UI.
When a subscriber's video is disabled, the OTSubscriber object dispatches a videoDisabled event:
<OTSubscriber
eventHandlers={{
videoDisabled: (event) => {
console.log('stream video disabled -- stream ID:', event.streamId);
// Display a user interface notification.
},
}}/>
When the Media Router disables the video of a subscriber, you may want to adjust the user interface related to the subscriber.
The reason property of the videoDisabled event object defines the reason the video was disabled. This can be set to one of the following values:
"PublisherPropertyChanged"— The publisher stopped publishing video."QualityChanged"— The Media Router stopped sending video to the subscriber based on stream quality changes. This feature of the Media Router has a subscriber drop the video stream when connectivity degrades. (The subscriber continues to receive the audio stream, if there is one.)
Before sending this event, when the subscriber's stream quality deteriorates to a level that is low enough that the video stream is at risk of being disabled, the OTSubscriber objet dispatches a videoDisableWarning event.
If connectivity improves to support video again, the OTSubscriber object dispatches a videoEnabled event, and the subscriber resumes receiving video.
This feature is only available in sessions that use the Media Router (sessions with the media mode set to routed), not in sessions with the media mode set to relayed.
When you publish a stream, you can prevent it from having its video disabled due to stream quality. Set audioFallbackEnabled to false in the properties prop pass into the OTPublisher component.
"SubscriberPropertyChanged"— The subscriber started or stopped subscribing to video, by setting subscribeToVideo to false in the properties prop passed into theOTSubscribercomponent."CodecNotSupported"— The subscriber stopped subscribing to video due to an incompatible codec (see the Video codecs developer guide).
The OTSubscriber object dispatches videoEnabled event when video resumes:
The reason property of the videoEnabled event object defines the reason the video was enabled. This can be set to one of the following values:
"PublisherPropertyChanged"— The publisher resumed publishing video."QualityChanged"— The Media Router resumed sending video to the subscriber based on stream quality changes. This feature of the Media Router has a subscriber drop the video stream when connectivity degrades and then resume the video stream if the stream quality improves.
This feature is only available in sessions that use the Media Router (sessions with the media mode set to routed), not in sessions with the media mode set to relayed.
"SubscriberPropertyChanged"— The subscriber started or stopped subscribing to video, by settingsubscribeToVideoto false in the properties prop passed into the OTSubscriber component."CodecNotSupported"— The subscriber video was enabled after a codec change from an incompatible codec (see the Video codecs developer guide).
When a stream, other than your own, leaves a session the Session object dispatches a streamDestroyed event:
session.on("streamDestroyed", function (event) {
console.log("Stream stopped. Reason: " + event.reason);
});
When a stream you publish leaves a session the Publisher object dispatches a streamDestroyed event:
var publisher = OT.initPublisher();
publisher.on("streamDestroyed", function (event) {
console.log("Stream stopped. Reason: " + event.reason);
});
The streamDestroyed event is defined by the StreamEvent class. The event includes a reason property, which details why the stream ended. These reasons include "clientDisconnected", "forceDisconnected", "forceUnpublished", or "networkDisconnected". For details, see StreamEvent.
By default, when a streamDestroyed event is dispatched for a stream you are subscribed to, the corresponding Subscriber objects (there could be more than one) are destroyed and removed from the HTML DOM. You can prevent this default behavior by calling the preventDefault() method of the StreamEvent object:
session.on("streamDestroyed", function (event) {
event.preventDefault();
var subscribers = session.getSubscribersForStream(event.stream);
// Now you can adjust the DOM elements around each
// subscriber to the stream, and then delete it yourself.
});
Note that the getSubscribersForStream() method of a Session object returns all of the Subscriber objects for a Stream.
You may want to prevent the default behavior, and retain the Subscriber, if you want to adjust related DOM elements before deleting the Subscriber yourself. You can then delete the Subscriber object (and its DOM element) by calling the destroy() method of the Subscriber object.
A Subscriber object dispatches a destroyed event when the object has been removed from the HTML DOM. In response to this event, you may choose to adjust (or remove) DOM elements related to the subscriber that was removed.
When streams published by other clients leave a session, the onStreamDropped(Session session, Stream stream) method of the Session.SessionListener object is called. When a stream is dropped, the view for any Subscriber object for the stream is removed from its superview.
Detecting when a subscriber's video is disabled
The Vonage Video Media Router stops sending video to the subscriber when it detects that connectivity degrades. The subscriber continues to receive the audio stream, if there is one. The onVideoDisabled(subscriber, subscriber) method of the SubscriberKit.VideoListener object is called when the Vonage Video Media Router stops sending video:
The reason parameter identifies the reason the subscriber stopped streaming video.
When the Vonage Video Media Router disables the video of a subscriber, you may want to adjust the user interface related to the subscriber.
The onVideoEnabled(subscriber, reason) method of the SubscriberKit.VideoListener object is called when the video resumes:
The reason parameter identifies the reason the subscriber's video resumed.
When you publish a stream, you can prevent it from having its video disabled due to stream quality. Before calling the Session.publish(publisher) method, call the setAudioFallbackEnabled(boolean enabled) method of the Publisher object (or PublisherKit object) and pass in false.
When streams leave a session, the OTSession session(_:streamDestroyed:) message is sent. When a stream is dropped, the view for any OTSubscriber object for the stream is removed from its superview. Check if the stream is not published by your own client, and remove its view from its superview.
Detecting when a subscriber's video is disabled
The subscriber's delegate sends the OTSubscriberDelegate subscriberVideoDisabled(_:reason:) message when the subscriber's video is disabled:
The reason parameter can be set to one of the following constants defined in the OTSubscriberVideoEventReason enum:
OTSubscriberVideoEventPublisherPropertyChanged— The video event was caused by the stream's publisher stopping the video stream.OTSubscriberVideoEventQualityChanged— The video event was caused by a change to the video stream quality. Stream quality may change due to network conditions or CPU usage on either the subscriber or publisher. This reason is only used in sessions that have the media mode set to "routed". (See The Vonage Video Media Router and media modes.) This feature of the Vonage Video Media Router has a subscriber drop the video stream when the video stream quality degrades, and the message is sent. When conditions improve, the video stream resumes, and theOTSubscriberDelegate subscriberVideoEnabled(_:reason:)message is sent. When the video stream is dropped, the subscriber continues to receive the audio stream, if there is one.OTSubscriberVideoEventSubscriberPropertyChanged— The video event was caused by a change to this subscriber'sOTSubscriber subscribeToVideoproperty.
If the video stream resumes, the OTSubscriberDelegate subscriberVideoEnabled(_:reason:) message is sent.
When you publish a stream, you can prevent it from having its video disabled due to stream quality. Before calling the OTSession publish(_:error:) method, set the audioFallbackEnabled property of the Publisher object (or PublisherKit object) to false.
The [OTSessionDelegate session:streamCreated:] message is sent when a new stream is created in a session. (A stream is created when a client publishes a stream to the session.) The OTStream object has properties that define the stream. Compare the connection property of the OTStream object with the connection property of the OTSession object to determine whether the stream is one that your client published:
When streams published by other clients leave a session, the Session object sends a StreamDropped event:
The event arguments object passed into this are defined by the OpenTok.Session.StreamEventArgs class. This class includes a Stream property. Compare this Stream object to the Stream property of each Subscriber object to identify the subscriber for the stream.
Detecting when a subscriber's video is disabled
The Vonage Video Media Router stops sending video to the subscriber when it detects that connectivity degrades. The subscriber continues to receive the audio stream, if there is one. When the Vonage Video Media Router stops sending video, the Subscriber object sends a VideoDisabled event:
When the Vonage Video Media Router disables the video of a subscriber, you may want to adjust the user interface related to the subscriber.
The Subscriber object sends a VideoDisabled event when video resumes:
The on_stream_dropped callback function of the otc_session_callbacks struct is called when another client's stream is dropped from the Vonage Video session. The stream parameter passed into this function is a pointer to an otc_stream struct for the stream. Call the otc_stream_get_id() method, passing in the otc_stream struct, to get the stream ID.
Detecting when a stream's video is disabled
The on_stream_has_video_changed callback function of the otc_session_callbacks struct is called when another client's stream is dropped from the Vonage Video session. The stream parameter passed into this function is a pointer to an otc_stream struct for the stream. Call the otc_stream_get_id() method, passing in the otc_stream struct, to get the stream ID.
Troubleshooting (JavaScript)
Tips for handling subscribe errors and connectivity issues.
For general information on troubleshooting, see Debugging.
Handling Errors
There is only one way to subscribe—with Session.subscribe()—and most errors are network related. If the Subscriber fails to connect it will display its own error message, but it’s better to surface a clear message yourself:
session.subscribe(event.stream, 'subscriber', {insertMode: 'append'}, function (err) {
if (err) {
showMessage('Streaming connection failed. This could be due to a restrictive firewall.');
}
});
Losing Connectivity
A Subscriber can lose its connection after it has connected. Handle the streamDestroyed event on the Session when the reason is networkDisconnected and inform the user without removing the Subscriber immediately:
session.on({
streamDestroyed: function (event) {
if (event.reason === 'networkDisconnected') {
event.preventDefault();
var subscribers = session.getSubscribersForStream(event.stream);
if (subscribers.length > 0) {
var subscriber = document.getElementById(subscribers[0].id);
subscriber.innerHTML = 'Lost connection. This could be due to your internet connection or because the other party lost their connection.';
event.preventDefault();
}
}
}
});
For subscriber event handling and runtime adjustments (audio blocked, video disabled, stats), see Subscribe: Management & Events.