# 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](https://www.zoom.com/en/video-sdk/). If you're starting a new project from scratch, see the [Video SDK for iOS documentation](/docs/video-sdk/ios/) 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](https://zoom.us/pricing/developer) to get started. [Learn about the Video SDK here.](https://explore.zoom.us/en/video-sdk/) ## 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](https://www.twilio.com/docs/video/tutorials/user-identity-access-tokens) generation logic with the [Zoom Video SDK JWT](/docs/video-sdk/auth/) 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](https://github.com/CocoaPods/Specs/tree/master/Specs/e/f/b/ZoomVideoSDK) - [Swift Package Manager installation](https://github.com/zoom/zoom-video-sdk-iOS.git) (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](/docs/video-sdk/ios/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. ```swift 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)") } } ``` ```objectivec 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. ```swift class YourClass: TVIRoomDelegate { // Add any of the callback functions here as needed. } let room = TwilioVideo.connect(with: connectOptions, delegate: self) ``` ```swift class YourClass: ZoomVideoSDKDelegate { // Add any of the callback functions here as needed. } ``` ```objectivec @interface YourClass : NSObject // 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](/docs/video-sdk/ios/sessions/), which are similar to Twilio's concept of a room. Replace Twilio's code with Zoom's. ```swift let connectOptions = ConnectOptions(token: accessToken) { (builder) in builder.roomName = "existing-room" } let room = TwilioVideoSDK.connect(options: connectOptions, delegate: self) ``` ```swift 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. } ``` ```objectivec 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](/docs/video-sdk/auth/#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](/docs/video-sdk/ios/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. ```swift // 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 ``` ```swift // 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() } ``` ```objectivec // 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. ```swift // 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) } ``` ```swift // 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) } ``` ```objectivec // 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](/docs/video-sdk/ios/video/) for more details about video configuration and [Render a user's video canvas](/docs/video-sdk/ios/video/#render-a-users-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. ```swift // 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() } ``` ```swift // 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() ``` ```objectivec // 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. ```swift room?.disconnect() ``` ```swift // A value of true will end the session if you are the host ZoomVideoSDK.shareInstance()?.leaveSession(shouldEndSession) ``` ```objectivec // 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. ```swift // 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 } } } ``` ```swift // 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) } } ``` ```objectivec // 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](/docs/video-sdk/ios/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. ```swift ZoomVideoSDK.shareInstance()?.cleanup() ``` ```objectivec [[ZoomVideoSDK shareInstance] cleanup]; ``` ## REST APIs and Webhooks Zoom Video SDK has a full suite of [REST APIs](/docs/api/video-sdk) and [webhooks](/docs/api/video-sdk/events/). Learn how to [use the Zoom APIs](/docs/api/using-zoom-apis/) and [webhooks](/docs/api/webhooks/). _For reference, here's the [Twilio REST API documentation](https://www.twilio.com/docs/video/api)._ ## Video SDK features and support Zoom has a number of additional features including [live transcription and translation](https://marketplacefront.zoom.us/sdk/custom/ios/interface_zoom_video_s_d_k_live_transcription_helper.html), [cloud recording](https://marketplacefront.zoom.us/sdk/custom/ios/interface_zoom_video_s_d_k_recording_helper.html), [Public Switched Telephone Network (PSTN) call out](https://marketplacefront.zoom.us/sdk/custom/ios/interface_zoom_video_s_d_k_phone_helper.html) and [call in](https://marketplacefront.zoom.us/sdk/custom/ios/interface_zoom_video_s_d_k_dial_in_number_info.html) to join sessions by phone, [chat](/docs/video-sdk/ios/chat/), [screen sharing](/docs/video-sdk/ios/share/), and [command channel](/docs/video-sdk/ios/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](/docs/video-sdk/) to learn more. For the complete feature map of Twilio Video to Zoom Video SDK, by platform, see the [feature map](/docs/video-sdk/twilio/map/). Start building with the Video SDK now. For questions, contact us! ## Contact Us - [Developer Sales](https://www.zoom.com/en/video-sdk/#contact-block-get-started-with-video-sdk-from-zoom) - [Developer Forum](https://devforum.zoom.us/c/video-sdk/) - [Developer Support](/support/) - [Developer Partner Services](https://explore.zoom.us/en/lp/developer-partner-services/) _See [Video SDK Plans & Pricing for Developer](https://zoom.us/pricing/developer) for pricing._