Subscribe: Basics
This guide shows how to detect available streams in a session, subscribe to them, and unsubscribe when done. You’ll listen for new streams, attach them to your UI, and clean up correctly.
Detect streams
Listen for new streams in a session so you can subscribe as they appear.
The Session object dispatches a streamCreated event when a new stream (other than your own) is created in a session. A stream is created when a client publishes a stream to the session. The streamCreated event is also dispatched for each existing stream in the session when you first connect. This event is defined by the StreamEvent, which has a stream property, representing stream that was created:
You can subscribe to any stream. See the next section.
The onStreamReceived(Session session, Stream stream) method of the Session.SessionListener object is called when a stream published by another client is created in a session. (A stream is created when a client publishes a stream to the session or if the stream exists when you connect to the session.)
@Override
public void onStreamReceived(Session session, Stream stream) {
// There is a new stream.
// You may want to subscribe to it.
}
Add a listener object for this event by calling the setSessionListener(Session.SessionListener listener) method of the Session object:
mSession.setSessionListener(this);
The OTSessionDelegate session(_ 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:
func session(_ session: OTSession, streamCreated stream: OTStream) {
print("Session streamCreated: \(stream.streamId)")
// See the declaration of subscribeToSelf above.
if stream.connection.connectionId == session.connection.connectionId {
// This is my own stream
} else {
// This is a stream from another client.
}
}
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.
- (void)session:(OTSession*)session streamDestroyed:(OTStream *)stream
{
NSLog(@"session streamDestroyed (%@)", stream.streamId);
if ([subscriber.stream.streamId isEqualToString:stream.streamId])
{
[_subscriber.view removeFromSuperview];
_subscriber = nil;
}
}
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:
- (void)subscriberVideoDisabled:(OTSubscriber *)subscriber
reason:(OTSubscriberVideoEventReason)reason
{
NSLog(@"subscriber video 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 the[OTSubscriberKit 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'sOTSubscriberKit.subscribeToVideoproperty.
If the video stream resumes, the [OTSubscriberKit 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 NO.
The Session object sends an StreamReceived event when a stream published by another client is created in a session. (A stream is created when a client publishes a stream to the session or if the stream exists when you connect to the session.)
The on_stream_received callback function of the otc_session_callbacks struct is called when a stream published by another client is created in a session. (A stream is created when a client publishes a stream to the session or if the stream exists when you connect to the session.) See Instantiating an otc_session instance and session-related callbacks.
Subscribe to a stream
Use the session to subscribe to a remote stream and render it in your UI.
To subscribe to all streams in the session, add an OTSubscriber object as a chile of the OTSession object:
After the client connects to the session, the OTSubscriber object adds views for subscriber videos when other clients streams become available in the session.
The OTSubscriber object dispatches a connected event when a subscriber successfully starts streaming. It dispatches an error event if there is an error subscribing. Set an eventHandlers prop of the OTSubscriber component, and set the connected and error properties of that object to callback functions:
To subscribe to a stream, pass the Stream object into the subscribe method of the Session object:
The subscribe() method takes the following parameters:
stream—The Stream object.targetElement— (Optional) Defines the DOM element that the Subscriber video replaces.properties— (Optional) A set of properties that customize the appearance of the Subscriber view in the HTML page and select whether to subscribe to audio and video
see Adjusting audio and video.
completionHandler— (Optional) A function that is called asynchronously when the call to thesubscribe()method completes successfully or fails. If the call to thesubscribe()method fails, the completion handler is passed an error object. This object has acodeandmessageproperty that describe the error.
The following code subscribes to all streams, other than those published by your client:
The insertMode property of the properties parameter of the Session.subscribe() method specifies how the Publisher object will be inserted in the HTML DOM, in relation to the targetElement parameter. You can set this parameter to one of the following values:
"replace"— The Subscriber object replaces contents of the targetElement. This is the default."after"— The Subscriber object is a new element inserted after the targetElement in the HTML DOM. (Both the Subscriber and targetElement have the same parent element.)"before"— The Subscriber object is a new element inserted before the targetElement in the HTML DOM. (Both the Subscriber and targetElement have the same parent element.)"append"— The Subscriber object is a new element added as a child of the targetElement. If there are other child elements, the Publisher is appended as the last child element of the targetElement.
For example, the following code adds a new Subscriber object as a child of a subscriberContainer DOM element:
The Subscriber object has an element property, which is set to the HTML DOM element containing it.
To subscribe to a stream, first instantiate a Subscriber.Builder object by calling the Subscriber.Builder(Context context, Stream stream) constructor. Pass in the Android application context for the Subscriber and the Stream object. Call the build() method to create the Subscriber object. Then call the subscribe() method of the Session object to start subscribing to the stream:
mSubscriber = new Subscriber.Builder(context, stream)
.build();
mSession.subscribe(mSubscriber);
The SubscriberKit.SubscriberListener.onConnected(SubscriberKit subscriber) method is called when the app starts receiving the subscriber's stream. At this point, you can add the subscriber's view (returned by the getView() method of the Subscriber object) as a subview of an android.view.ViewGroup object to display it in the app:
@Override
public void onConnected(subscriber) {
// mViewContainer is an Android View
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(
getResources().getDisplayMetrics().widthPixels, getResources()
.getDisplayMetrics().heightPixels);
mViewContainer.addView(mSubscriber.getView(), layoutParams);
}
Unsubscribing from a stream
To stop playing a stream you are subscribed to, call the Session.unsubscribe(Subscriber subscriber) method:
mSession.unsubscribe(mSubscriber);
The Subscriber is disconnected, and its view is removed from its superview.
To subscribe to a stream, call the OTSubscriber init(stream:delegate:) method, passing in an OTStream object and a delegate object to receive subscriber-related messages. Then call theOTSession subscribe(_:error:) method to start subscribing to the stream:
func session(_ session: OTSession, streamCreated stream: OTStream) {
subscriber = OTSubscriber(stream: stream, delegate: self)
var error: OTError?
session.subscribe(subscriber!, error: &error)
if error {
print("subscribe failed with error: \(error)")
}
}
The OTSubscriberDelegate subscriberDidConnect(toStream:) message is sent when the app starts receiving the subscriber's stream. At this point, you can add the subscriber's view (represented by the OTSubscriber view property) to the app:
func subscriberDidConnect(toStream subscriber: OTSubscriberKit) {
if let subscriberView = self.subscriber?.view {
subscriberView.frame = CGRect(x: 0, y: 300, width: 400, height: 300)
self.view.addSubview(subscriberView)
}
}
Unsubscribing from a stream
To stop playing a stream you are subscribed to, call the OTSession unsubscribe(_:error:) method:
var error: OTError?
session.unsubscribe(subscriber, error: &error)
if (error) {
print("unsubscribe failed with error: \(error)")
}
The Subscriber is disconnected. Next, remove its view from its superview:
subscriber.view?.removeFromSuperview()
To subscribe to a stream, call the [OTSubscriber initWithStream:] method, passing in an OTStream object and a delegate object to receive subscriber-related messages. Then call the[OTSession subscribe:error] method to start subscribing to the stream:
- (void)session:(OTSession*)session streamCreated:(OTStream*)stream
{
subscriber = [[OTSubscriber alloc] initWithStream:stream delegate:self];
OTError* error = nil;
[session subscribe:subscriber error:&error]
if (error) {
NSLog(@"subscribe failed with error: (%@)", error);
}
}
The [OTSubscriberDelegate subscriberDidConnectToStream:] message is sent when the app starts receiving the subscriber's stream. At this point, you can add the subscriber's view (represented by the OTSubscriber.view property) to the app:
- (void)subscriberDidConnectToStream:(OTSubscriber*)subscriber
{
[subscriber.view setFrame:CGRectMake(0, 300, 400, 300)];
[self.view addSubview:subscriber.view];
}
Unsubscribing from a stream
To stop playing a stream you are subscribed to, call the [OTSession unsubscribe:error:] method:
OTError* error = nil;
[session unsubscribe:_subscriber error:&error]
if (error) {
NSLog(@"unsubscribe failed with error: (%@)", error);
}
The Subscriber is disconnected. Next, remove its view from its superview:
[subscriber.view removeFromSuperview:];
To subscribe to a stream, first instantiate a Subscriber object by calling the Subscriber(context, stream, renderer) constructor. Pass in the Windows application context for the Subscriber, the Stream object, and a video renderer.
The OpenTok.IVideoRenderer interface defines the video renderer. The OpenTok.VideoRenderer class, included in Vonage Video Windows SDK, renders video to an Windows Presentation Framework control. The VideoRenderer object is a subclass of System.Windows.Controls.Control.
You can add this element to your view hierarchy. Or you can create your own custom video renderer that implements the OpenTok.IVideoRenderer interface.
Call the subscribe() method of the Session object to start subscribing to the stream:
The Subscriber object sends an Error event if there is an error in subscribing to the stream. Check the ErrorCode property of the arguments passed into the event to see details on why subscribing failed. (The OpenTok.ErrorCode enum defines ErrorCode values.)
The Subscriber object sends a Connected event when the app starts receiving the subscriber's stream.
Note: The OpenTok.Subscriber class implements the System.IDisposable interface. Be sure to call the Dispose() method of the Subscriber object to release its resources when you no longer need the object (for example, when the Subscriber stops streaming video or when the app or window is closing).
You can create a custom audio driver to be used by all publishers and subscribers.
Unsubscribing from a stream
To stop playing a stream you are subscribed to, call the Session.Unsubscribe(subscriber) method:
The Subscriber is disconnected, and its view is removed from its superview.
The on_stream_received callback function (see the previous section) includes a stream parameter, which is a pointer to an otc_stream struct representing the new stream. To subscribe to the stream, instantiate a otc_subscriber_callbacks instance, set some callback functions for subscriber-related events, and then call the otc_subscriber_new() function passing in the otc_stream and otc_subscriber_callbacks instances
char *user_data = strdup("Session user data");
static void on_subscriber_connected(otc_subscriber *subscriber,
void *user_data,
const otc_stream *stream) {
// Called when the subscriber connects to the stream.
}
static void on_render_frame(otc_subscriber *subscriber,
void *user_data,
const otc_video_frame *frame) {
// Called when the subscriber is ready to render a new video frame
}
static void on_error(otc_subscriber *subscriber,
void *user_data) {
// Called when there is an error.
}
struct otc_subscriber_callbacks subscriber_callbacks = {0};
subscriber_callbacks.user_data = user_data;
subscriber_callbacks.on_connected = on_subscriber_connected;
subscriber_callbacks.on_render_frame = on_subscriber_render_frame;
subscriber_callbacks.on_error = on_subscriber_error;
otc_subscriber *subscriber = otc_subscriber_new(stream,
&subscriber_callbacks);
if (subscriber == NULL) {
printf("Could not create OpenTok subscriber successfully");
return;
}
if (otc_session_subscribe(session, subscriber) != OTC_SUCCESS) {
printf("Could not subscribe successfully.");
}
Use the user_data member of the otc_subscriber_callbacks structure to set data you may want to reference in the callback functions. In this example, we set it to a pointer to a string object. But it could be a pointer to an instance of some other type that contains meaningful information.
The other members of the otc_subscriber_callbacks structure are each callback functions that are invoked when events related to the subscriber occur:
on_connected— Called when the subscriber connects to the audio-video stream.on_render_frame— Called each time the subscriber is ready to render a new video frame.on_error— Called when a subscriber error occurs.
All callbacks will not be made on the application or main thread but on an internal thread. The application should return the callback as quickly as possible to avoid blocking the internal thread.
See otc_subscriber_callbacks in the Vonage Video Linux SDK reference for details on each of the callback functions.
Unsubscribing from a stream
To stop playing a stream you are subscribed to, call the otc_session_unsubscribe() function, passing in the otc_session and otc_subscriber instances:
if (session.unsubscribe(session, subscriber) == OTC_SUCCESS) {
printf("Unsubscribed from the stream successfully.");
otc_subscriber_delete(subscriber);
} else {
printf("Could not unsubscribe successfully.");
};
Call the otc_subscriber_delete() function to release the subscriber instance, including all hardware and UI resources bound to it.
Unsubscribe (JavaScript)
To stop playing a stream you are subscribed to:
The Subscriber object is destroyed, and the stream display is removed from the HTML DOM.