This tutorial will walk you through the steps of setting up a basic iOS client that uses the Vonage Video API.
All applications that use the Vonage Video API require both a client and a server component. The client-side code is what loads in an end-user's iOS device and handles the majority of OpenTok functionality, including connecting to the session, publishing audio-video streams to the session, and subscribing to other clients’ streams. For more information on clients, servers, and sessions, see Video API Basics.
In this tutorial, you will be utilizing the OpenTok iOS SDK, OpenTok's client-side library for iOS devices, to quickly and easily build a real-time interactive video application.
Note: The code in this tutorial is written in Objective-C. There is also a tutorial with the code written in Swift.
Estimated completion time: 25 mins
Want to skip this tutorial? You can jump to the completed iOS Objective-C client code in the Basic-Video-Chat folder of our iOS sample app repo on GitHub. The repo includes a README with documentation for running and exploring the code.
To complete this tutorial, you'll need:
A supported version of Xcode
Open Xcode and create a new project.
Select Single View Application as the template.
Select Objective-C as the language for the app code.
Follow the steps below to use CocoaPods to add the OpenTok library and its dependencies to your app. If you would prefer not to use CocoaPods, follow these instructions for using the SDK.
In the Terminal, navigate to the root directory of your project and enter the following:
pod init
This creates a Podfile at the root of your project directory.
Edit the Podfile and add the following line after the comment that says
# Pods for [YourProjectName]
(The podfile will not be visible in your XCode project, so you will need to open it from the project folder directly):
pod 'OpenTok'
Save changes to the Podfile.
In the Terminal, in your project root directory type:
pod install
Close your project in Xcode. Then reopen your project by double-clicking the new .xcworkspace file in the Finder (in the root directory of your project).
For camera and microphone access you need to modify the Info.plist file:
In the lefthand navigator panel in Xcode, click the project file (with the name of your project) to open the center project panel.
To the left of the General tab in the project panel, you should see your project name. If the name is something different from your project (such as [YourProjectName]Tests), click on it and set the target to your project name.
Inside the panel, switch to the Info tab.
Expand the Custom iOS Target Properties section if it’s collapsed
Mouse over any key and click the + button to add a new key. Add a
Privacy - Camera Usage Description
key and assign it the following string:
$(PRODUCT_NAME) uses the camera.
Then click the + button to add a new Privacy - Microphone Usage Description
key and
assign it the following string:
$(PRODUCT_NAME) uses the microphone.
The app displays these strings when the application first accesses the camera and microphone.
(These security features were added in iOS 10.)
Add the OpenTok library to the view controller.
In Xcode, open the ViewController.m file and, at the beginning of the file, add a line to import the OpenTok library:
#import "ViewController.h"
#import <OpenTok/OpenTok.h>
In order to connect to an OpenTok session, the client will need access to some authentication credentials — an API key, session ID, and token. In a production application, these credentials should be generated by a server, but to speed things up we will just hard code the values for now:
Start by copying the following code block and adding it to your ViewController.m file:
// Replace with your OpenTok API key
static NSString* kApiKey = @"";
// Replace with your generated session ID
static NSString* kSessionId = @"";
// Replace with your generated token
static NSString* kToken = @"";
Add these lines before the @interface
declaration.
Adjust the code by hard coding the values for the kApiKey
, kSessionId
and kToken
(inside the empty quotation marks).
To do this, log into your Video API account, either create a new OpenTok API project or use an existing OpenTok API project, then go to your project page and scroll down to the Project Tools section. From there, you can generate a session ID and token manually. Use the project's API key along with the session ID and token you generated.
Important: You can continue to get the session ID and token values from your Account during testing and development, but before you go into production you must set up a server. We will discuss this in Next steps at the end of this tutorial.
For more information on sessions, tokens, and servers, check out Video API Basics.
Next, we will connect to the OpenTok session. You must do this before you can publish your audio-video stream to the session or view other participants streams.
Add a session
property to the ViewController class:
@interface ViewController()
@property (nonatomic) OTSession *session;
@end
The OTSession class is defined in the OpenTok iOS SDK. It represents an OpenTok session and includes methods for interacting with the session.
Add a method to instantiate the OTSession object and
call its [OTSession connectWithToken: error:]
method. Then you can call it in viewDidLoad
:
- (void)viewDidLoad {
[super viewDidLoad];
[self connectToAnOpenTokSession];
}
- (void)connectToAnOpenTokSession {
_session = [[OTSession alloc] initWithApiKey:kApiKey sessionId:kSessionId delegate:self];
NSError *error;
[_session connectWithToken:kToken error:&error];
if (error) {
NSLog(@"%@", error);
}
}
The [OTSession initWithApiKey:sessionId:delegate:]
method takes three parameters:
The [OTSession connectWithToken: error:]
method connects the client application to the OpenTok
session. You must connect before sending or receiving audio-video streams in the session (or
before interacting with the session in any way). The method takes two parameters:
token
is the authentication token for this client to connect to the OpenTok session.
error
is set to an OTError object if an error occurs synchronously when calling the method.
Change the ViewController interface declaration to indicate that the class implements
the OTSessionDelegate
protocol:
@interface ViewController() <OTSessionDelegate>
Next we will implement methods of the OTSessionDelegate protocol. Add the following code to the
end of the ViewController class (before the class's @end
statement):
# pragma mark - OTSession delegate callbacks
- (void)sessionDidConnect:(OTSession*)session
{
NSLog(@"The client connected to the OpenTok session.");
}
- (void)sessionDidDisconnect:(OTSession*)session
{
NSLog(@"The client disconnected from the OpenTok session.");
}
- (void) session:(OTSession*)session
didFailWithError:(OTError*)error
{
NSLog(@"The client failed to connect to the OpenTok session: (%@)", error);
}
- (void)session:(OTSession*)session
streamCreated:(OTStream *)stream
{
NSLog(@"A stream was created in the session.");
}
- (void)session:(OTSession*)session
streamDestroyed:(OTStream *)stream
{
NSLog(@"A stream was destroyed in the session.");
}
This protocol includes methods for handling events related to the session:
When the client connects to the OpenTok session, the [OTSessionDelegate sessionDidConnect:]
message is sent.
If the client fails to connect to the OpenTok session, the
[OTSessionDelegate session:didFailWithError:]
message is sent.
When the client disconnects from the OpenTok session, the
[OTSessionDelegate sessionDidDisconnect:]
message is sent.
When another client publishes a stream to the OpenTok session the
[OTSessionDelegate session:streamCreated:]
message is sent.
When another client stops publishing a stream to the OpenTok session the
[OTSessionDelegate session:streamDestroyed:]
message is sent.
For now, the app prints to the debugger console when any of these events occur.
Debug your application. If the app successfully connects to the OpenTok session, the
the [OTSessionDelegate sessionDidConnect:]
method should print to the debug console.
When the app connects to the OpenTok session, we want it to publish an audio-video stream to the session, using the device's camera and microphone:
Add a publisher
property to the ViewController class:
@interface ViewController() <OTSessionDelegate>
@property (nonatomic) OTSession *session;
@property (nonatomic) OTPublisher *publisher;
@end
The OTPublisher class is defined in the OpenTok iOS SDK. It uses the device's camera and microphone, to publish a stream OpenTok session.
Modify the implementation of the sessionDidConnect(_:)
method to include
code to publish a stream to the session:
- (void)sessionDidConnect:(OTSession*)session
{
OTPublisherSettings *settings = [[OTPublisherSettings alloc] init];
_publisher = [[OTPublisher alloc]
initWithDelegate:self
settings:settings];
OTError *error = nil;
[_session publish:_publisher error:&error];
if (error)
{
NSLog(@"Unable to publish (%@)", error.localizedDescription);
return;
}
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGRect rect = CGRectMake(screenSize.width - 150 - 20, screenSize.height - 150 - 20, 150, 150);
[_publisher.view setFrame:rect];
[self.view addSubview:_publisher.view];
}
When the app connects to a session, it initializes an instance of the OTPublisher,
defined in the OpenTok iOS SDK. The [OTPublisher initWithDelegate:]
method takes
two parameters: the object that implements the OTPublisherDelegate protocol
and a settings
object.
The code then passes the OTPublisher object in as a parameter of the
[OTSession publish:]
method. This method publishes an audio-video stream to the
OpenTok session, using the camera and microphone of the iOS device. (Note that
in the Xcode simulator, the OpenTok iOS SDK uses a test video when publishing a
stream.)
The OTPublisher object has a view
property, which is a UIView object.
This view displays the video captured from the device's camera. The code
adds this view as a subview of the main ViewController's view.
Change the ViewController interface declaration to indicate that the class implements
the OTPublisherDelegate
protocol:
@interface ViewController() <OTSessionDelegate, OTPublisherDelegate>
Next we will implement methods of the OTSessionDelegate protocol. Add the following code to the
end of the ViewController class (before the class's @end
statement):
# pragma mark - OTPublisher delegate callbacks
- (void)publisher:(OTPublisherKit*)publisher
didFailWithError:(OTError*) error
{
NSLog(@"The publisher failed: %@", error);
}
If the client fails to publish to the OpenTok session, an OTError object is passed into the
[OTPublisherDelegate publisher:didFailWithError:]
method.
Debug your application. If the app successfully connects to the OpenTok session, it will publish a stream to the session, and you will see the publisher's video in the app.
Finally, we want clients to be able to subscribe to (or view) other clients' streams in the session:
Add a subscriber
property to the ViewController class:
@interface ViewController() <OTSessionDelegate, OTPublisherDelegate>
@property (nonatomic) OTSession *session;
@property (nonatomic) OTPublisher *publisher;
@property (nonatomic) OTSubscriber *subscriber;
@end
The OTSubscriber class is defined in the OpenTok iOS SDK. It uses the device's camera and microphone, to subscribe a stream OpenTok session.
Modify the implementation of the [OTSessionDelegate session: streamCreated]
method (one of the
OTSessionDelegate callbacks) to include code to subscribe to other clients' streams the session:
- (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(@"Unable to subscribe (%@)", error.localizedDescription);
return;
}
[_subscriber.view setFrame:[UIScreen mainScreen].bounds];
[self.view insertSubview:_subscriber.view atIndex:0];
}
When another client publishes a stream to a session, this method is called, and an
OTStream object is passed in. The OTStream class is defined in the OpenTok iOS SDK,
and it represents an audio-video stream in the OpenTok session. The code
initializes an instance of the OTSubscriber class, defined in the OpenTok iOS SDK.
The OTSubscriber()
constructor takes two parameters: The OTStream object (for the
stream you want to view) and the object that implements the OTSubscriberDelegate protocol.
Change the ViewController interface declaration to indicate that the class implements
the OTSubscriberDelegate
protocol:
@interface ViewController() <OTSessionDelegate, OTPublisherDelegate,OTSubscriberDelegate>
Next we will implement methods of the OTSessionDelegate protocol. Add the following code to the
end of the ViewController class (before the class's @end
statement):
# pragma mark - OTSubscriber delegate callbacks
- (void)subscriberDidConnectToStream:(OTSubscriberKit *)subscriber {
NSLog(@"The subscirber: %@ did connect to the stream", subscriber);
}
- (void)subscriber:(OTSubscriberKit*)subscriber
didFailWithError:(OTError*)error
{
NSLog(@"subscriber %@ didFailWithError %@",
subscriber.stream.streamId,
error);
}
subscriber(_: didFailWithError:)
method.Now that your code is complete, you can run the app in the XCode emulator. This will create a simulated publisher video — since the emulator cannot access your webcam, the publisher video will display a spinning teapot graphic instead of your camera feed.
To add a second publisher (which will display as a subscriber in your emulator), either run the app a second time in a connected iOS device or use the OpenTok Playground to connect to the session in a supported web browser by following the steps below:
Go to OpenTok Playground (must be logged into your Account)
Select the Join existing session tab
Copy the session ID you used in your ViewController.m file and paste it in Session ID input field
Click Join Session
On the next screen, click Connect, then click Publish Stream
You can adjust the Publisher options (not required), then click Continue to connect and begin publishing and subscribing
At this point you should see the stream being published from your webcam as well as the stream being published by the emulator. Returning to the emulator, you should also see the new publisher displayed on the emulated screen.
Congratulations! You've finished the 'Set up a Basic iOS Client (Objective-C)' tutorial.
You can continue to play with and adjust the code you've developed here for the client-side of your application, but keep in mind that you'll need to implement the server component of your application before going to production (see Setting up your server below).
You can view a completed version of this sample app in the Basic-Video-Chat folder of the opentok-ios-sdk-samples repo on GitHub. This completed version adds code to load the session ID, token, and API key from a web service (instead of using hard coded values).
When you're finished here, continue building and enhancing your OpenTok application with these helpful resources:
In the tutorial above, we had you hard code your authentication credentials. However, for a production application, the sessionId
and token
values in your code must be generated by your app server and passed to the client. Here are a couple of reasons why you don't want hard coded credentials in your production app:
You can continue testing your application with hard coded values, but when you're ready to set up a server there are a number of ways to do so:
This is probably the fastest way to get a server up and running, but it has limited functionality. Simply click the Heroku button below, at which point you'll be sent to Heroku's website and prompted for your OpenTok API Key and API Secret — you can get these values on your project page in your Video API account. If you don't have a Heroku account, you'll need to sign up (it's free).
Want to explore the code? The button above launches server code from the learning-opentok-php GitHub repo. Visit the repo to review the code as well as additional documentation — you can even fork the repo and make changes before deploying.
Prefer Node.js? Visit the learning-opentok-node repo for the same functionality using Node.js (including Heroku deploy button.)
Once the server is deployed on Heroku, you'll need to add a few lines to your client-side code. Instead of calling connectToAnOpenTokSession
directly, you'll need to make a networking call to the path /session
on your server to fetch valid OpenTok credentials first.
Copy the following code and use it to replace viewDidLoad
in your ViewController.m file:
- (void)viewDidLoad {
[super viewDidLoad];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSURL *url = [NSURL URLWithString:<#https://YOURAPPNAME.herokuapp.com/session#>];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
kApiKey = dict[@"apiKey"];
kSessionId = dict[@"sessionId"];
kToken = dict[@"token"];
[self connectToAnOpenTokSession];
}
else {
NSLog(@"%@", error);
}
}];
[dataTask resume];
[session finishTasksAndInvalidate];
}
You'll need to replace https://YOURAPPNAME.herokuapp.com
with your actual Heroku app url — you can find this on your app page on the Heroku website.
The code above makes a request to the /session endpoint (https://YOURAPPNAME.herokuapp.com/session), which should return an HTTP response that includes the session ID, the token, and API key formatted as JSON data, which is then assigned to the corresponding variables.
This /session
endpoint will always return the same session ID, but will produce a new token each time it's called — this results in each client receiving a unique token.
Option 1 uses REST endpoints for transmitting credentials to the client, but that's only one of many ways to implement a server with OpenTok. If you want a greater level of customization, you can review OpenTok's Server SDK documentation for the server-side language of your choice (available for PHP, Node.js, Java, .NET, Python and Ruby). The documentation goes over the setup process and the various methods you'll need to generate sessions and tokens, as well as other server-side functionality.