iOS | Zoom Video SDK + Twilio migration
This guide walks you through how to migrate your existing project from the Twilio Video SDK to the Zoom Video SDK. If you're starting a new project from scratch, see the Video SDK for iOS documentation as it contains more details about the usage and features of the Video SDK.
Create a developer account
Create a Video SDK developer account to access your credentials. Choose a plan to get started. Learn about the Video SDK here.
Authorize
Both Zoom and Twilio use JSON Web Tokens (JWT) to authorize the use of the SDK and to generate a token for users to join. On your auth server, replace your Twilio Video JWT generation logic with the Zoom Video SDK JWT generation logic.
Install and set up the SDK
Install the Zoom Video SDK from Cocoapods, Swift Package Manager, or a direct download from the Zoom Developer Portal.
- Cocoapods installation
- Swift Package Manager installation (branch: swift-package-manager)
Add credentials
Copy the Video SDK and Video API credentials from the Marketplace page and save them to controllers and other classes in your app as necessary.
Set up the SDK
Remove the listing for TwilioVideo in the Podfile and run pod install as necessary to remove the Twilio Video SDK.
Copy the ZoomVideoSDK.xcframework folder from the SDK directory under Sample-Libs/lib. Add the ScreenShare framework folder as well if you want to add screen sharing functionality.
Because the iOS Video SDK is a dynamic library, ensure that it is embedded in your Xcode project. Navigate to your app's project file > app target > General tab > Frameworks, Libraries, and Embedded Content section and ensure it's set to an Embedded option.
Make sure that the Camera, Microphone, Bluetooth, and Photo Library (optional) permissions are added to the info.plist.
Set Build Settings > Build Options > Enable Bitcode to No. The Zoom Video SDK does not support the Bitcode builds.
See Integrate for more details.
Code Changes
The Twilio Video SDK uses several delegate classes in the Cocoa delegation pattern, which contain callback methods that respond to video events. The Zoom Video SDK uses the singleton pattern, centering around the ZoomVideoSDKInitParams class.
In any classes where you had previously imported TwilioVideo, make sure you instead import ZoomVideoSDK.
The code snippets below illustrate the mappings between the Zoom and Twilio SDKs. Low-level functionality may differ between the two platforms, so the mappings may not be perfectly accurate for all use cases.
Initialize the SDK
In order to use The Zoom Video SDK, you must first initialize the main SDK singleton. This is usually done when your app starts, but you can substitute in the Video SDK wherever it is appropriate for your implementation.
There is no equivalent of this in the Twilio Video SDK, so it is important to find the correct place in your app to add initialization logic.
let initParams = ZoomVideoSDKInitParams()
initParams.domain = "zoom.us"
initParams.enableLog = true
let sdkInitReturnStatus = ZoomVideoSDK.shareInstance()?.initialize(initParams)
switch sdkInitReturnStatus {
case .Errors_Success:
print("SDK initialized successfully")
default:
if let error = sdkInitReturnStatus {
print("SDK failed to initialize: (error)")
}
}
ZoomVideoSDKInitParams *initParams = [[ZoomVideoSDKInitParams alloc] init];
initParams.domain = @"zoom.us";
initParams.enableLog = YES;
ZoomVideoSDKERROR ret = [[ZoomVideoSDK shareInstance] initialize:initParams];
switch (ret) {
case Errors_Success:
NSLog(@"SDK initialized successfully");
break;
default:
NSLog(@"SDK failed to initialize with error code: %lu", (unsigned long)ret);
break;
}
SDK callbacks
Both SDKs use delegates/listeners to detect and stay in sync with state changes. Replace your Twilio listeners with Zoom Video SDK for iOS delegates.
class YourClass: TVIRoomDelegate {
// Add any of the callback functions here as needed.
}
let room = TwilioVideo.connect(with: connectOptions, delegate: self)
class YourClass: ZoomVideoSDKDelegate {
// Add any of the callback functions here as needed.
}
@interface YourClass : NSObject <ZoomVideoSDKDelegate>
// Add any of the callback functions here as needed.
[ZoomVideoSDK shareInstance].delegate = self;
The callbacks in these delegates can reflect a number of different changes including connection to the session/channel, status of other users, errors, and changes in state related to specific features. To take advantage of this capability, simply have your class conform to the delegate protocol.
In most use cases, the ZoomVideoSDKDelegate contains all of the callbacks you need. In Twilio there are multiple listeners depending on the area of functionality you're using. So it may require some refactoring to consolidate everything into one place in the Video SDK.
Join session/room
The Video SDK uses sessions, which are similar to Twilio's concept of a room. Replace Twilio's code with Zoom's.
let connectOptions = ConnectOptions(token: accessToken) { (builder) in
builder.roomName = "existing-room"
}
let room = TwilioVideoSDK.connect(options: connectOptions, delegate: self)
let sessionContext = ZoomVideoSDKSessionContext()
// Ensure that you do not hard code JWT or any other confidential credentials in your production app.
sessionContext.token = "Your jwt"
sessionContext.sessionName = "Your session name"
sessionContext.userName = "Your name"
sessionContext.sessionPassword = "Your session password"
// Join the session
if let session = ZoomVideoSDK.shareInstance()?.joinSession(sessionContext) {
// Session joined successfully.
}
ZoomVideoSDKSessionContext *sessionContext = [[ZoomVideoSDKSessionContext alloc] init];
// Ensure that you do not hard code JWT or any other confidential credentials in your production app.
sessionContext.token = @"Your jwt";
sessionContext.sessionName = @"Your session name";
sessionContext.userName = @"Your name";
sessionContext.sessionPassword = @"Your session password";
// Join the session
ZoomVideoSDKSession *session = [[ZoomVideoSDK shareInstance] joinSession:sessionContext];
if (session) {
// Session joined successfully.
}
Both SDKs use a token for authentication, but the Zoom SDK JWT requires information specific to the session you are trying to join, so it's important to use the correct payload as specified in Generate a Video SDK JWT.
Because you previously conformed your class to the ZoomVideoSDKDelegate protocol, you should be able to monitor events related to the session.
See sessions for more details.
Video
The Zoom Video SDK provides an easy way to control a user's video stream and to check their state. Use the ZoomVideoSDKVideoHelper to check a user's video status and start or stop their video.
// start camera
var cameraSource = CameraSource(delegate: self),
let captureDevice = CameraSource.captureDevice(position: .front)
cameraSource.startCapture(device: captureDevice, completion: nil)
// stop camera
cameraSource?.stopCapture()
cameraSource = nil
// Get the ZoomVideoSDKVideoHelper to perform video actions.
if let videoHelper = ZoomVideoSDK.shareInstance()?.getVideoHelper() {
// START local User's video.
videoHelper.startVideo()
// STOP local User's video.
videoHelper.stopVideo()
}
// Get the ZoomVideoSDKVideoHelper to perform video actions.
ZoomVideoSDKVideoHelper *videoHelper = [[ZoomVideoSDK shareInstance] getVideoHelper];
if (videoHelper) {
// START local User's video.
[videoHelper startVideo];
// STOP local User's video.
[videoHelper stopVideo];
}
Set up local video preview
Additionally, setting up a local video preview is similar between the two SDKs.
// Use CameraSource to produce video from the device's front camera.
if let camera = CameraSource(delegate: self),
let videoTrack = LocalVideoTrack(source: camera) {
// VideoView is a VideoRenderer and can be added to any VideoTrack.
let renderer = VideoView(frame: view.bounds)
}
if let camera = TVICameraCapturer(source: .frontCamera),
let videoTrack = TVILocalVideoTrack(capturer: camera) {
// TVIVideoView is a TVIVideoRenderer and can be added to any TVIVideoTrack.
let renderer = TVIVideoView(frame: view.bounds)
// Add renderer to the video track
videoTrack.addRenderer(renderer)
self.localVideoTrack = videoTrack
self.camera = camera
self.view.addSubview(renderer)
}
// Get local user's video canvas.
if let localUserVideoCanvas = ZoomVideoSDK.shareInstance()?.getSession()?.getMySelf().getVideoCanvas() {
// Set video aspect.
let videoAspect = ZoomVideoSDKVideoAspect.panAndScan
// Pass a UIView to the canvas in order to subscribe to User's videoCanvas
localUserVideoCanvas.subscribe(with: view, andAspectMode: videoAspect)
}
// Get local user's video canvas.
ZoomVideoSDKVideoCanvas *localUserVideoCanvas = [[[[ZoomVideoSDK shareInstance] getSession] getMySelf] getVideoCanvas];
// Set video aspect.
ZoomVideoSDKVideoAspect videoAspect = ZoomVideoSDKVideoAspect_PanAndScan;
// Pass a UIView to the canvas in order to subscribe to User's videoCanvas
[localUserVideoCanvas subscribeWithView:view
andAspectMode:videoAspect];
See Video for more details about video configuration and Render a user's video canvas for a list of video aspect options.
Display other user videos
In order to enable your end users to see the video feeds of other users in a session/channel, you can use an approach similar to that used when setting up local video preview. But instead of getting local video, get the ZoomVideoSDKVideoCanvas associated with another user.
// MARK: RemoteParticipantDelegate
/*
* In the Participant Delegate, we can respond when the Participant adds a Video
* Track by rendering it on screen.
*/
func didSubscribeToVideoTrack(videoTrack: RemoteVideoTrack,
publication: RemoteVideoTrackPublication,
participant: RemoteParticipant) {
if let remoteView = VideoView.init(frame: self.view.bounds,
delegate:self) {
videoTrack.addRenderer(remoteView)
self.view.addSubview(remoteView)
self.remoteView = remoteView
}
}
// MARK: VideoViewDelegate
// Lastly, we can subscribe to important events on the VideoView
func videoViewDimensionsDidChange(view: VideoView, dimensions: CMVideoDimensions) {
self.view.setNeedsLayout()
}
// Get all users who are not the local user.
let remoteUsers = ZoomVideoSDK.shareInstance()?.getSession()?.getRemoteUsers()
// Get user's video canvas from the list of remote users.
user.getVideoCanvas()
// Get all users who are not the local user.
NSArray *remoteUsers = [[[ZoomVideoSDK shareInstance] getSession] getRemoteUsers];
// Get user's video canvas from the list of remote users.
[user getVideoCanvas];
Leave a session
Users can either leave the session, or the host can end the session for all users. To leave a session, call the leaveSession function and confirm whether the session should be ended for all users if you are the host.
room?.disconnect()
// A value of true will end the session if you are the host
ZoomVideoSDK.shareInstance()?.leaveSession(shouldEndSession)
// A value of true will end the session if you are the host
[[ZoomVideoSDK shareInstance] leaveSession:shouldEndSession];
Audio controls
Similarly to video controls, both SDKs offer a relatively simple approach to controlling audio.
// For instance, this is how to unpublish the microphone track in the Twilio SDK
var room: Room? // Set when connected to a video room
var micTrack: LocalAudioTrack?
var isLocalMicOn = false {
didSet {
guard oldValue != isLocalMicOn else {
return
}
if isLocalMicOn {
guard let micTrack = LocalAudioTrack(options: nil, enabled: true, name: "mic") else {
return
}
self.micTrack = micTrack
room?.localParticipant?.publishAudioTrack(micTrack)
} else {
guard let micTrack = micTrack else {
return
}
room?.localParticipant?.unpublishAudioTrack(micTrack)
self.micTrack = nil
}
}
}
// Get the user's audioStatus.
if let audioStatus = user.audioStatus() {
// Get the user's audioType.
let audioType = audioStatus.audioType
if audioType == .none {
// User's audio is not connected.
// Get the ZoomVideoSDKAudioHelper to perform audio actions.
if let audioHelper = ZoomVideoSDK.shareInstance()?.getAudioHelper() {
// Connect User's audio.
audioHelper.startAudio()
}
} else {
// User is already connected to audio.
}
// Muting or Unmuting a user
// Get the ZoomVideoSDKAudioHelper to perform audio actions.
if let audioHelper = ZoomVideoSDK.shareInstance()?.getAudioHelper() {
// Mute user.
audioHelper.muteAudio(user)
// Unmute user.
audioHelper.unmuteAudio(user)
}
}
// Get the user's audioStatus.
ZoomVideoSDKAudioStatus *audioStatus = [user audioStatus];
// Get the user's audioType.
ZoomVideoSDKAudioType audioType = [audioStatus audioType];
if (audioType == ZoomVideoSDKAudioType_None) {
// User's audio is not connected.
// Get the ZoomVideoSDKAudioHelper to perform audio actions.
ZoomVideoSDKAudioHelper *audioHelper = [[ZoomVideoSDK shareInstance] getAudioHelper];
if (audioHelper) {
// Connect User's audio.
[audioHelper startAudio];
}
} else {
// User is already connected to audio.
}
// Get the ZoomVideoSDKAudioHelper to perform audio actions.
ZoomVideoSDKAudioHelper *audioHelper = [[ZoomVideoSDK shareInstance] getAudioHelper];
if (audioHelper) {
// Mute user.
[audioHelper muteAudio:user];
// Unmute user.
[audioHelper unmuteAudio:user];
}
See Audio for more details.
Clean up Video SDK
When you are no longer using Zoom Video SDK in your app, you can call a simple method to clean up the Zoom Video SDK.
ZoomVideoSDK.shareInstance()?.cleanup()
[[ZoomVideoSDK shareInstance] cleanup];
REST APIs and Webhooks
Zoom Video SDK has a full suite of REST APIs and webhooks.
Learn how to use the Zoom APIs and webhooks.
For reference, here's the Twilio REST API documentation.
Video SDK features and support
Zoom has a number of additional features including live transcription and translation, cloud recording, Public Switched Telephone Network (PSTN) call out and call in to join sessions by phone, chat, screen sharing, and command channel to send data to other users in a session. Zoom also supports additional Video SDK platforms including Android, iOS, Linux, macOS, Windows, and wrappers such as Flutter and React Native. See the Zoom Video SDK documentation to learn more.
For the complete feature map of Twilio Video to Zoom Video SDK, by platform, see the feature map.
Start building with the Video SDK now. For questions, contact us!
Contact Us
See Video SDK Plans & Pricing for Developer for pricing.