Twilio migration guide (iOS)

This guide walks you through migrating your existing Twilio video application to Vonage Video.

For the most flexibility and versatility in programming your video solution, the Vonage Video API iOS SDK has you covered.

If your requirements extend beyond simple video functions and include features like broadcasting, SIP integration, media processing, and customizable stream settings, you'll discover that the Vonage Video iOS SDK offers unmatched power and flexibility.

Overview

Twilio and Vonage Video APIs have very similar concepts. This starter guide aims to assist you in migrating your video application.

One key difference between Twilio and Vonage video implementation is the use of room SID, this is a session ID when it comes to Vonage. We will look at how to generate a sessionID in a later section.

You will also need an authentication token when connecting a client to an active session.

The diagram below illustrates the architectural differences between Twilio and Vonage video.

Vonage Twilio migraiton illustration 1 Vonage Twilio migraiton illustration 1

Twilio Vonage terminology mapping

Twilio Vonage
Room Session
Participants Subscriber(s) + Publisher(s)
Tracks Stream
RemoteTracks Subscribers(s).stream
LocalTracks Publisher(s).stream

Get Video SDK credentials

Create a developer Account to access the developer portal.

To get started with video you need to create an application. You can follow the create an application guide to obtain your application ID and private key.

Install the SDK

You can install the Vonage Video iOS SDK through the Swift Package Manager or Cocoapods:

Using Swift Package Manager

To add a package dependency to your Xcode project, select File > Swift Packages > Add Package Dependency and enter the repository URL:

https://github.com/vonage/vonage-video-client-sdk-swift.git

Using Cocoapods

When adding the SDK using CocoaPods edit the Podfile and add the following line:

pod 'OTXCFramework'

Save changes to the Podfile, open the root directory of the project in the terminal/command-line and run:

pod install

This should pull in the Vonage video SDK and its dependencies.

You can now add the SDK to your view controller. In Xcode, open your ViewController.swift file and, at the very top of the file, add the following lines to import the video library:

import UIKit
import OpenTok

Authentication

The Vonage Video SDK uses tokens to authenticate users. When generating a token you can set the user’s role (subscriber, publisher, or moderator). Optionally, you can also assign a string of metadata to the token (i.e. to identify the connected client).

Please refer to our Token Creation guide to learn how to generate tokens. Tokens are generated on the server-side and then used on the client-side. Visit the Server-side SDKs guides to learn more.

Create a video session

A session is like a room. All clients using the same session ID will be able to communicate with each other.

Like tokens, sessions are created on the server side. Please refer to our Creating a session guide to learn more.

To create a session and generate a token, use one of our server SDKs.

You can declare all your keys as property in your ViewController.swift file:

// Replace with your Application ID
var kApplicationId = ""
// Replace with your generated session ID
var kSessionId = ""
// Replace with your generated token
var kToken = ""

Connect to a video session

With all your keys set you can now connect to an active video session.

You must do this before you can publish your audio-video stream to the session or view other participants streams.

Twilio

let twimlParamTo = "to"
let connectOptions: TVOConnectOptions = TVOConnectOptions(accessToken: accessToken) { (builder) in
            builder.params = [twimlParamTo : “{to}”]
        }
TwilioVoice.connect(with: connectOptions, delegate: self)

Vonage

class ViewController: UIViewController
   var session: OTSession?

override func viewDidLoad() {
   super.viewDidLoad()
   connectToAnOpenTokSession()
}

func connectToAnOpenTokSession() {
    // Important: Please note that your Application ID is your API key.
    session = OTSession(apiKey: kApplicationId, sessionId: kSessionId, delegate: self)
    var error: OTError?
    session?.connect(withToken: kToken, error: &error)
    if error != nil {
        print(error!)
    }
}

Event Listeners

Vonage and Twilio have delegate protocols to help you maintain the state of a session/call for all participants connected to a session.

Session/Room connection changes

Twilio

// MARK: TVOCallDelegate
func callDidStartRinging(_ call: TVOCall) {
        NSLog("callDidStartRinging:")
}
func callDidConnect(_ call: TVOCall) {
        NSLog("callDidConnect:")
}
func call(_ call: TVOCall, isReconnectingWithError error: Error) {
        NSLog("call:isReconnectingWithError:")
}
func callDidReconnect(_ call: TVOCall) {
        NSLog("callDidReconnect:")
}
func call(_ call: TVOCall, didFailToConnectWithError error: Error) {
        NSLog("Call failed to connect: \(error.localizedDescription)")
}
func call(_ call: TVOCall, didDisconnectWithError error: Error?) {
        NSLog("Call disconnected")
}

Vonage

// MARK: - OTSessionDelegate callbacks
extension ViewController: OTSessionDelegate {
   func sessionDidConnect(_ session: OTSession) {
       print("The client connected to the Vonage Video API session.")
   }
   func sessionDidDisconnect(_ session: OTSession) {
       print("The client disconnected from the Vonage Video API session.")
   }
   func session(_ session: OTSession, didFailWithError error: OTError) {
       print("The client failed to connect to the Vonage Video API session: \(error).")
   }
   func session(_ session: OTSession, streamCreated stream: OTStream) {
       print("A stream was created in the session.")
   }
   func session(_ session: OTSession, streamDestroyed stream: OTStream) {
       print("A stream was destroyed in the session.")
   }
}

Publishing Video

When a user is connected to an active session, it can publish an audio-video stream to the session, using the device's camera and microphone:

This is achieved by adding a publisher property to the ViewController class:

class ViewController: UIViewController, OTSessionDelegate {
   var session: OTSession?
   var publisher: OTPublisher?

Modify the implementation of the OTSessionDelegate.sessionDidConnect(_:) method to include code to publish a stream to the session. Here is an example:

func sessionDidConnect(_ session: OTSession) {
    print("The client connected to the OpenTok session.")
    let settings = OTPublisherSettings()
    guard let publisher = OTPublisher(delegate: self, settings: settings) else {
        Return
    }
    var error: OTError?
    session.publish(publisher, error: &error)
    guard error == nil else {
        print(error!)
        Return
    }
    guard let publisherView = publisher.view else {
        Return
    }
    let screenBounds = UIScreen.main.bounds
    publisherView.frame = CGRect(x: screenBounds.width - 150 - 20, y: screenBounds.height - 150 - 20, width: 150, height: 150)
    view.addSubview(publisherView)
}

The Vonage Video SDK handles the video quality automatically, based on network conditions and device capabilities. That said, you can configure certain properties, such as resolution, frame rate, and audio fallback.

Next we will implement methods from the OTPublisherDelegate protocol. This protocol includes methods for handling events related to the publisher.

To do so you can add the following code to your ViewController.swift file:

// MARK: - OTPublisherDelegate callbacks
extension ViewController: OTPublisherDelegate {
   func publisher(_ publisher: OTPublisherKit, didFailWithError error: OTError) {
       print("The publisher failed: \(error)")
   }
}

Turn the camera on/off

The Vonage SDK offers simple methods to control the camera.

Twilio

participant?.unpublishVideoTrack(cameraManager.track)
self.cameraManager = nil

Vonage

// This will only stop publishing Video to the session. You can still see your local preview

    publisher.publishVideo = false
// This will only stop publishing all media (audio and video) to the session. You can still see your local preview
    var error: OTError?
    session.unpublish(publisher, error: &error)
    guard error == nil else {
        print(error!)
        Return
    }

Render a remote user video

Similar to Twilio's participantDidConnect and didSubscribeToVideoTrack event listeners, Vonage also triggers connectionCreated and streamCreated events when a remote participant connects to the session and starts sending video.

Twilio

func participantDidConnect(room: Room, participant: RemoteParticipant) {
    print ("Participant \(participant.identity) has joined Room \(room.name)")

    // Set the delegate of the remote participant to receive callbacks
    participant.delegate = self
}

func participantDidDisconnect(room: Room, participant: RemoteParticipant) {
    print ("Participant \(participant.identity) has left Room \(room.name)")
}

 func didSubscribeToVideoTrack(videoTrack: RemoteVideoTrack,
                              publication: RemoteVideoTrackPublication,
                              participant: RemoteParticipant) {

    print("Participant \(participant.identity) added a video track.")
    if let remoteView = VideoView.init(frame: self.view.bounds,
                                       delegate:self) {
        videoTrack.addRenderer(remoteView)
        self.view.addSubview(remoteView)
        self.remoteView = remoteView
    }
}

Vonage

class ViewController: UIViewController {
   var session: OTSession?
   var publisher: OTPublisher?
   var subscriber: OTSubscriber?

func session(_ session: OTSession, streamCreated stream: OTStream) {
    subscriber = OTSubscriber(stream: stream, delegate: self)
    guard let subscriber = subscriber else {
        return
    }


    var error: OTError?
    session.subscribe(subscriber, error: &error)
    guard error == nil else {
        print(error!)
        return
    }


    guard let subscriberView = subscriber.view else {
        return
    }
    subscriberView.frame = UIScreen.main.bounds
    view.insertSubview(subscriberView, at: 0)
}


// MARK: - OTSubscriberDelegate callbacks
extension ViewController: OTSubscriberDelegate {
   public func subscriberDidConnect(toStream subscriber: OTSubscriberKit) {
       print("The subscriber did connect to the stream.")
   }


   public func subscriber(_ subscriber: OTSubscriberKit, didFailWithError error: OTError) {
       print("The subscriber failed to connect to the stream.")
   }
}

Audio

Vonage manages both audio and video using a single Publisher object. When you start publishing with the default options, the SDK publishes both audio and video. However, if you would prefer to have an audio-only session, you may configure the publisher object to not publish Video.

Mute microphone

With Twilio, you must get the audio track to mute the microphone. Vonage simplifies this by providing a single invocable method.

Twilio

guard let micTrack = LocalAudioTrack(options: nil, enabled: true, name: TrackName.mic) else {
           return
}
participant?.unpublishAudioTrack(micTrack)

Vonage

publisher.publishAudio = false

Unmute microphone

Similarly, with Twilio Video, you must get the audio track to unmute the microphone. Vonage simplifies this by providing a single invocable method.

Twilio

guard let micTrack = LocalAudioTrack(options: nil, enabled: true, name: TrackName.mic) else {
           return
}
participant?.publishAudioTrack(micTrack)

Vonage

publisher.publishAudio = true

Text chat

You can exchange data (i.e. text chat messages or custom JSON messages) between individual participants in a session, as well as all participants in a session.

The following method sends a message to clients connected to the session. Each signal is defined by a string type identifying the type of message (in this case "chat") and a string containing the message:

func sendChatMessage(message: String) {
    var error: OTError?
    session.signal(withType: "chat", string: message, connection: nil, error: &error)
    if let error {
        print(error)
    }
}

When another client connected to the session sends a message, the implementation of a callback from OTSessionDelegate allows you to receive the message:

func session(_ session: OTSession, receivedSignalType type: String?, from connection: OTConnection?, with string: String?) {
        print("Received signal type \(type) with message \(string)")
    }

Leave and End sessions The code below shows how to end an active session (disconnect a user from a session).

Twilio

// To disconnect from a Room, we call:
room?.disconnect()

// This results in a callback to RoomDelegate#roomDidDisconnect(room: Room, error: Error?)

// MARK: RoomDelegate

func roomDidDisconnect(room: Room, error: Error?) {
    print("Disconnected from room \(room.name)")
}

Vonage

var error: OTError?
session?.disconnect(&error)
if error != nil {
    print(error!)
}

// MARK: OTSessionDelegate

func sessionDidDisconnect(_ session: OTSession) {
print("The client disconnected to the OpenTok session.")
}

More information: