Vonage Video API: Real-Time Video in iOS
Get started with the Vonage Video API and add real-time video streaming to your iOS apps. By Yusuf Tör.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Vonage Video API: Real-Time Video in iOS
20 mins
Connecting to the Session
Before you can start livestreaming, you need to connect to the session.
To do this, head to StreamingViewController.swift. Below the token
property, add the following:
private var session: OTSession?
OpenTok uses an OTSession to represent your session. Here, you’re keeping a strong reference to your session object.
Now, to connect to a session add the following code below leave()
:
private func connectToSession() {
// 1
session = OTSession(
apiKey: apiKey,
sessionId: sessionId,
delegate: self
)
// 2
var error: OTError?
session?.connect(withToken: token, error: &error)
// 3
if let error = error {
print("An error occurred connecting to the session", error)
}
}
Here’s what’s happening:
- Initialize
OTSession
with yourapiKey
andsessionId
. Set the delegate toStreamingViewController
. Setting the delegate will cause a compiler error as you have not yet madeStreamingViewController
conform toOTSessionDelegate
. - Connect to the session using your token and pass in a reference to an
OTError
to catch any synchronous errors.OTError
defines errors specific to the OpenTok iOS SDK. - If a synchronous error did occur, print it to the console.
Since you set the delegate of OTSession
to self
, you’ll need to implement the OTSessionDelegate
protocol. Add the following extension at the bottom of StreamingViewController.swift:
// MARK: - OTSessionDelegate
extension StreamingViewController: OTSessionDelegate {
// 1
func sessionDidConnect(_ session: OTSession) {
print("The client connected to the session.")
}
// 2
func sessionDidDisconnect(_ session: OTSession) {
print("The client disconnected from the session.")
}
// 3
func session(_ session: OTSession, didFailWithError error: OTError) {
print("The client failed to connect to the session: \(error).")
}
// 4
func session(_ session: OTSession, streamCreated stream: OTStream) {
print("A stream was created in the session.")
}
// 5
func session(_ session: OTSession, streamDestroyed stream: OTStream) {
print("A stream was destroyed in the session.")
}
}
This code handles events relating to the session. Specifically, when:
- You successfully connect to the session.
- You successfully disconnect from the session.
- An asynchronous error occurs while trying to connect to the session.
- Someone else publishes their video stream to the session. This provides an
OTStream
, which represents their stream. - Someone else stops publishing their video stream to the session.
You’re almost ready to try out your app, but you still need to actually connect to the session.
To do this, add the following at the bottom of viewDidLoad()
:
connectToSession()
Build and run, then enter the lounge. The screen will still be black, but you’ll notice in the console that you’ve successfully connected to the session:
Publishing the Camera
Now that you can connect to the session, it’s time to publish your camera and microphone.
Add the following below connectToSession()
:
private func publishCamera() {
// 1
guard let publisher = OTPublisher(delegate: nil) else {
return
}
// 2
var error: OTError?
session?.publish(publisher, error: &error)
// 3
if let error = error {
print("An error occurred when trying to publish", error)
return
}
// 4
guard let publisherView = publisher.view else {
return
}
// 5
let screenBounds = UIScreen.main.bounds
let viewWidth: CGFloat = 150
let viewHeight: CGFloat = 267
let margin: CGFloat = 20
publisherView.frame = CGRect(
x: screenBounds.width - viewWidth - margin,
y: screenBounds.height - viewHeight - margin,
width: viewWidth,
height: viewHeight
)
view.addSubview(publisherView)
}
Here’s what this code does:
- Initialize an
OTPublisher
object. This object can capture an audio-video stream from the device’s microphone and camera. - Publish an audio-video stream to the session and pass in a reference to
OTError
to catch any synchronous errors. - If a synchronous error did occur, print it to the console.
- Get the view from the publisher, which contains the video captured from the device’s camera. Since the simulator doesn’t have a camera, it substitutes in a default video.
- Add the view as a subview in the corner of
StreamingViewController
.
OTPublisher
‘s delegate to nil
here, but you could implement OTPublisherDelegate
to handle events related to the publisher, such as asynchronous errors. You could also use it to pass settings to OTPublisher
to adjust the camera resolution, audio fallback settings, video scaling behavior and more.
Next, to publish the camera when a connection has been established, inside sessionDidConnect(_:)
, add the following after print
:
publishCamera()
Build and run and you’ll see the simulator’s default video of a spinning teapot in the bottom-right. How apt! You’re now livestreaming in the session. If you were to run this code on a device, you’d see your camera’s video instead. Congratulations, you now have half a tea party! :]
Subscribing to an Incoming Stream
Before you can see a video stream from another client who’s publishing to the session, you need to subscribe to it.
Below the token
property add the following:
private var subscriberView: UIView?
This will keep a strong reference to the view that holds the video stream of the other client.
Now, add the following code below publishCamera()
:
private func subscribe(to stream: OTStream) {
// 1
guard let subscriber = OTSubscriber(stream: stream, delegate: nil) else {
return
}
// 2
var error: OTError?
session?.subscribe(subscriber, error: &error)
// 3
if let error = error {
print("An error occurred when subscribing to the stream", error)
return
}
// 4
guard let subscriberView = subscriber.view else {
return
}
// 5
self.subscriberView = subscriberView
subscriberView.frame = UIScreen.main.bounds
view.insertSubview(subscriberView, at: 0)
}
Here’s what’s going on in this code:
- Create
OTSubscriber
usingOTStream
, which represents the video stream of another device. - Subscribe to this stream and pass in a reference to
OTError
to catch any synchronous errors. - If a synchronous error did occur, print it to the console.
- Get the view from the subscriber. This view contains the stream’s video.
- Keep a reference to the view and insert that view below the subviews of
StreamingViewController
. This view is the same size as the screen’s bounds and will fill the screen.
OTSubscriber
‘s delegate to nil
here. Implementing the OTSubscriberDelegate
protocol enables you to handle events related to the subscriber.
Finally, at the bottom of session(_:streamCreated:)
, add:
subscribe(to: stream)
This makes you subscribe to a stream whenever it’s created.
To have a two-way livestream in your app, you either need a friend with another device or another iOS simulator. In this case, build and run using the iPhone 12 Pro simulator. Then, stop running the app, select the iPhone 12 simulator and build and run again.
Now, on the iPhone 12 Pro simulator, tap the TeaParty app to open it again and you’ll have two simulators running the app at the same time. Enter the lounge on both simulators and you’ll see two spinning teapots on each device:
The two simulators are having a virtual tea party — they’re both publishing their video to the session and subscribing to each other’s video stream!