Video Call
  • iOS : Swift
  • Android
  • Web
  • Flutter
  • React Native
  • Electron
  • Unity3D
  • Cocos Creator
  • Windows
  • macOS
  • Linux
  • Overview
  • Develop your app
    • Quick start
    • Enhance basic feature
      • Use Tokens for authentication
      • Config your video based on scenes
      • Check the room connection status
  • Best practices
    • Implement call invitation
    • Implement a live audio room
  • Upgrade using advanced features
    • Advanced features
      • Message signaling
        • Convey extra information using SEI
    • Distincitve features
      • Customize the video and audio
  • Upgrade using Add-on
  • Resources & Reference
    • SDK
    • Sample codes
    • API reference
      • Client APIs
      • Server APIs
    • Debugging
      • Error codes
    • FAQs
    • Key concepts
  • Documentation
  • Video Call
  • Develop your app
  • Quick start

Quick start

Last updated:2024-01-02 11:48

This guide describes how to integrate the SDK and implement a basic one-on-one video call using ZEGOCLOUD's Video Call SDK.

Prerequisites

Before you begin, make sure you complete the following:

  • Xcode 13.0 or later.
  • A device running on iOS 9.0 or later.
  • Sign up and create a project in Admin Console.

Create an iOS project

Skip this step if a project already exists.

Create a new project
  1. Open Xcode, select File > New > Project. In the dialog that appears, select the iOS tab, then select App in the Application section.

  1. Fill in items or choose options for the new project, click Next after the configuration is completed.

    Product Name and Organization Identifier are required, which will be used for creating the App Bundle Identifier.

    set_project_name

  2. Choose a directory to store the project, and click Create to create a project.

Import the SDK

Choose either of the following methods to integrate the Video Call SDK into your project.

Method 1: Use Swift Package Manager (Recommended)
  1. Open Xcode and select File > Add Packages..., and enter the following URL in the search box of Search or Enter Package URL:

    https://github.com/zegolibrary/express-video-ios
  2. Specify the SDK version you want to integrate into Dependency Rule (Recommended: use the default rule "Up to Next Major Version"), and then click Add Package to import the SDK. For more, refer to Apple Documentation.

Method 2: Use CocoaPods
  1. Install CocoaPods. For more details, see CocoaPods Installation Guide .

  2. Open the Terminal, enter the root directory of the project, and execute the command pod init to create a Podfile.

  3. Open Podfile, add pod 'ZegoExpressEngine', and change MyProject to your target name.

    target 'MyProject' do
        use_frameworks!
        pod 'ZegoExpressEngine'
    end

    Because the SDK is XCFramwork, therefore, you will need to use CocoaPods 1.10.0 or later to integrate the Video Call SDK.

    Since version v3.2.0, the Pod name of the Video Call SDK is changed from ZegoExpressEngine/Video to ZegoExpressEngine; the Pod name of the Voice Call SDK is changed from ZegoExpressEngine/Audio to ZegoExpressAudio.

  1. Execute pod repo update to update the local index to make sure the latest version of SDK can be installed. For the latest version number, see ZEGOCLOUD Express-Video iOS SDK Release History .

  2. Execute pod install to install the SDK.

Method 3: Manually add the SDK to the project
  1. Download the latest version of SDK from SDK downloads . We recommend you use XCFramework, and then extract files from the downloaded SDK package.

  2. Copy the SDK dynamic library file ZegoExpressEngine.xcframework to the project directory.

    • ios-arm64_armv7: A real device that supports the arm64 or armv7 architectures of the iOS platform.
    • ios-arm64_x86_64-maccatalyst: supports the arm64, x86_64 architecture of Mac Catalyst mode.
    • ios-arm64_x86_64-simulator: A simulator that supports the arm64 and x86_64 architectures of the iOS platform.
  3. Open Xcode and select File > Add Files to "xxx" (xxx is the project name) to add the SDK dynamic library files to the project.

  4. Do the following to add the framework file to the project target.

    a) Select the project target.

    b) Click General, then under Frameworks, Libraries, and Embedded Content, click the Add button (+) below the table.

    c) Add ZegoExpressEngine.framework to the target, and set the Embed field to Embed & Sign.

    Dylibembed

Add device permissions

Permissions can be set as needed.

  1. Open Xcode, select the target object, and then click Info > Custom iOS Target Properties.

    AddPrivacy

  2. Click the Add button (+) to add camera and microphone permissions.

    • Privacy - Camera Usage Description

    • Privacy - Microphone Usage Description

      AddPrivacy Done

Implement video call functions

Sample code

The following is the sample code for implementing video call functions. Feel free to refer to it when developing.

Code for implementing a video call
//
//  ViewController.swift
//

import UIKit
import ZegoExpressEngine


// Get your AppID and AppSign from ZEGOCLOUD Console
// [My Projects -> AppID] : https://console.zegocloud.com/project
let appID : UInt32 = <#YourAppID#>
let appSign: String = "<#YourAppSign#>"

class ViewController: UIViewController {

    // The video stream for the local user is displayed here
    var localView: UIView!
    // The video stream for the remote user is displayed here
    var remoteView: UIView!
    // Click to log in or log out a room
    var callButton: UIButton!

    var localUserID = "user_" + String(Int.random(in: 1...100))

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        createEngine()
        initViews()
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        destroyEngine()
    }

    private func createEngine() {
        let profile = ZegoEngineProfile()

        // Get your AppID and AppSign from ZEGOCLOUD Console
        //[My Projects -> AppID] : https://console.zegocloud.com/project
        profile.appID = appID
        profile.appSign = appSign
        // Use the default scenario.
        profile.scenario = .default
        // Create a ZegoExpressEngine instance and set eventHandler to [self].
        ZegoExpressEngine.createEngine(with: profile, eventHandler: self)
    }

    private func destroyEngine() {
        ZegoExpressEngine.destroy(nil)
    }

    private func initViews() {
        // Initializes the remote video view. This view displays video when a remote host joins the channel.
        remoteView = UIView()
        remoteView.frame = self.view.frame
        self.view.addSubview(remoteView)

        // Initializes the local video window. This view displays video when the local user is a host.
        localView = UIView()
        localView.frame = CGRect(x: 200, y: 80, width: 135, height: 240)
        self.view.addSubview(localView)

        //  Button to log in or log out a room
        callButton = UIButton(type: .system)
        callButton.frame = CGRect(x: (self.view.frame.width - 80) / 2.0, y: self.view.frame.height - 150, width: 80, height: 80)
        callButton.setBackgroundImage(UIImage(named: "call_icon"), for: .normal)
        callButton.setBackgroundImage(UIImage(named: "call_hand_up_icon"), for: .selected)

        callButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
        self.view.addSubview(callButton)
    }

    private func startPreview() {
        // Set up a view for the local video preview
        let canvas = ZegoCanvas(view: self.localView)
        ZegoExpressEngine.shared().startPreview(canvas)
    }

    private func stopPreview() {
        ZegoExpressEngine.shared().stopPreview()
    }

    private func startPublish() {
        // After calling the `loginRoom` method, call this method to publish streams.
        let streamID = "stream_" + localUserID
        ZegoExpressEngine.shared().startPublishingStream(streamID)
    }

    private func stopPublish() {
        ZegoExpressEngine.shared().stopPublishingStream()
    }

    private func startPlayStream(streamID: String) {
        // Start to play streams. Set the view for rendering the remote streams.
        let canvas = ZegoCanvas(view: self.remoteView)
        ZegoExpressEngine.shared().startPlayingStream(streamID, canvas: canvas)
    }

    private func stopPlayStream(streamID: String) {
        ZegoExpressEngine.shared().stopPlayingStream(streamID)
    }


    private func loginRoom() {
        // The value of `userID` is generated locally and must be globally unique.
        let user = ZegoUser(userID: localUserID)
        // The value of `roomID` is generated locally and must be globally unique.
        // Users must log in to the same room to call each other.
        let roomID = "room_1"
        let roomConfig = ZegoRoomConfig()
        // onRoomUserUpdate callback can be received when "isUserStatusNotify" parameter value is "true".
        roomConfig.isUserStatusNotify = true
        // log in to a room
        ZegoExpressEngine.shared().loginRoom(roomID, user: user, config: roomConfig) { errorCode, extendedData in
            if errorCode == 0 {
                // Login room successful
                self.startPreview()
                self.startPublish()
            } else {
                // Login room failed
            }
        }
    }

    private func logoutRoom() {
        ZegoExpressEngine.shared().logoutRoom()
    }


    @objc func buttonAction(sender: UIButton!) {
        sender.isSelected = !sender.isSelected;
        if sender.isSelected {
            loginRoom()
        } else {
            logoutRoom()
        }
    }
}

extension ViewController : ZegoEventHandler {

    // Callback for updates on the status of the streams in the room.
    func onRoomStreamUpdate(_ updateType: ZegoUpdateType, streamList: [ZegoStream], extendedData: [AnyHashable : Any]?, roomID: String) {
        // If users want to play the streams published by other users in the room, call the startPlayingStream method with the corresponding streamID obtained from the `streamList` parameter where ZegoUpdateType == ZegoUpdateTypeAdd.
        if updateType == .add {
            for stream in streamList {
                startPlayStream(streamID: stream.streamID)
            }
        } else {
            for stream in streamList {
                stopPlayStream(streamID: stream.streamID)
            }
        }
    }

    // Callback for updates on the current user's room connection status.
    func onRoomStateUpdate(_ state: ZegoRoomState, errorCode: Int32, extendedData: [AnyHashable : Any]?, roomID: String) {
     }

    // Callback for updates on the status of other users in the room.
    // Users can only receive callbacks when the isUserStatusNotify property of ZegoRoomConfig is set to `true` when logging in to the room (loginRoom).
    func onRoomUserUpdate(_ updateType: ZegoUpdateType, userList: [ZegoUser], roomID: String) {
    }

}

Implement the UI

Create a UI for video calls for your project based on your scenario requirements. We recommend you add the following UI elements to your project:

  • A view for local preview
  • A view for remote video
  • A Stop button
layout
//
//  ViewController.swift
//

import UIKit

class ViewController: UIViewController {

    // The video stream for the local user is displayed here
    var localView: UIView!
    // The video stream for the remote user is displayed here
    var remoteView: UIView!
    // Click to log in or log out of a room
    var callButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        initViews()
    }


    private func initViews() {
        // Initializes the remote video view. This view displays video when a remote host logins the room.
        remoteView = UIView()
        remoteView.frame = self.view.frame
        self.view.addSubview(remoteView)

        // Initializes the local video window. This view displays video when the local user is a host.
        localView = UIView()
        localView.frame = CGRect(x: 200, y: 80, width: 135, height: 240)
        self.view.addSubview(localView)

        //  Button to log in or log out of a room
        callButton = UIButton(type: .system)
        callButton.frame = CGRect(x: (self.view.frame.width - 80) / 2.0, y: self.view.frame.height - 150, width: 80, height: 80)
        callButton.setBackgroundImage(UIImage(named: "call_icon"), for: .normal)
        callButton.setBackgroundImage(UIImage(named: "call_hand_up_icon"), for: .selected)

        callButton.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
        self.view.addSubview(callButton)
    }
}

Implement the video calling logic

Understand the tech

The following diagram shows the basic process of User A playing a stream published by User B:

For a better understanding, you can check the key concepts of Video Call SDK:

1. Create & destroy the ZegoExpressEngine instance

First, run the following to import the header file.

// Import the header file ZegoExpressEngine
import ZegoExpressEngine

Then, call the createEngineWithProfile method to initialize the Video Call SDK. And config the following:

  • profile: the ZegoEngineProfile object, used to config the appID and appSign, as well as the scenario you are applying the SDK to.
  • eventHandler: an event handler object, used to listen for core event callbacks, such as the callback for updates on the room connection stats changes, updates on in-room participants log in or log out, and more. You can call the setEventHandler method to set up the event handler object.

To destroy the SDK and release the resources it occupies, call the destroy method.

private func createEngine() {
    let profile = ZegoEngineProfile()

    // Get your AppID and AppSign from ZEGOCLOUD Console
    //[My Projects -> AppID] : https://console.zegocloud.com/project
    profile.appID = appID
    profile.appSign = appSign
    // Use the default scenario.
    profile.scenario = .default
    // Create a ZegoExpressEngine instance and set eventHandler to [self].
    ZegoExpressEngine.createEngine(with: profile, eventHandler: self)
}

private func destroyEngine() {
    ZegoExpressEngine.destroy(nil)
}

2. Set up an event handler

Implement the ZegoEventHandler event handler to listen for event callbacks, such as the event callback on the updates when the in-room streams are added or deleted, the updates when in-room participants log in or log out, the updates when room connection state changes, and more.

  • onRoomStreamUpdate: Callback for updates on the status of the streams in the room. When new streams are published to the room or existing streams in the room stop, the SDK sends out the event notification through this callback. You can call startPlayStream() and stopPlayStream() methods in this callback.

  • onRoomStateUpdate: Callback for updates on current room connection status. When the current room connection status changes (for example, when the current user is disconnected from the room or login authentication fails), the SDK sends out the event notification through this callback.

  • onRoomUserUpdate: Callback for updates on the status of other users in the room. When other users log in or log out of the room, the SDK sends out the event notification through this callback.

extension ViewController : ZegoEventHandler {

    // Callback for updates on the status of the streams in the room.
    func onRoomStreamUpdate(_ updateType: ZegoUpdateType, streamList: [ZegoStream], extendedData: [AnyHashable : Any]?, roomID: String) {
        // If users want to play the streams published by other users in the room, call the startPlayingStream method with the corresponding streamID obtained from the `streamList` parameter where ZegoUpdateType == ZegoUpdateTypeAdd.
        if updateType == .add {
            for stream in streamList {
                startPlayStream(streamID: stream.streamID)
            }
        } else {
            for stream in streamList {
                stopPlayStream(streamID: stream.streamID)
            }
        }
    }

    // Callback for updates on the current user's room connection status.
    func onRoomStateUpdate(_ state: ZegoRoomState, errorCode: Int32, extendedData: [AnyHashable : Any]?, roomID: String) {
     }

    // Callback for updates on the status of other users in the room.
    // Users can only receive callbacks when the isUserStatusNotify property of ZegoRoomConfig is set to `true` when logging in to the room (loginRoom).
    func onRoomUserUpdate(_ updateType: ZegoUpdateType, userList: [ZegoUser], roomID: String) {
    }

}

3. Log in & log out

To log in to a room, you can call the loginRoom method.

To log out, you can call the logoutRoom method.

private func loginRoom() {
    // The value of `userID` is generated locally and must be globally unique.
    let user = ZegoUser(userID: localUserID)
    // The value of `roomID` is generated locally and must be globally unique.
    // Users must log in to the same room to call each other.
    let roomID = "room_1"
    let roomConfig = ZegoRoomConfig()
    // onRoomUserUpdate callback can be received when "isUserStatusNotify" parameter value is "true".
    roomConfig.isUserStatusNotify = true
    // log in to a room
    ZegoExpressEngine.shared().loginRoom(roomID, user: user, config: roomConfig) { errorCode, extendedData in
        if errorCode == 0 {
            // Login room successful
            self.startPreview()
            self.startPublish()
        } else {
            // Login room failed
        }
    }
}

private func logoutRoom() {
    ZegoExpressEngine.shared().logoutRoom()
}

4. Start & stop the local video preview

To start the local video preview and to render it, call the startPreview method.

And you call the stopPreview method to stop the rendering.

private func startPreview() {
    // Set up a view for the local video preview
    let canvas = ZegoCanvas(view: self.localView)
    ZegoExpressEngine.shared().startPreview(canvas)
}

private func stopPreview() {
    ZegoExpressEngine.shared().stopPreview()
}

5. Start & stop publishing streams

To start publishing a local audio or video stream to remote users, call the startPublishingStream method.

And you can call the stopPublishingStream method to stop the stream publishing.

private func startPublish() {
    // After calling the `loginRoom` method, call this method to publish streams.
    // The StreamID must be unique in the room.
    let streamID = "stream_" + localUserID
    ZegoExpressEngine.shared().startPublishingStream(streamID)
}

private func stopPublish() {
    ZegoExpressEngine.shared().stopPublishingStream()
}

6. Start & stop playing streams

You can call startPlayingStream method to start playing a remote video stream.

And to stop the stream playing, call the stopPlayingStream method to stop.

private func startPlayStream(streamID: String) {
    // Start to play streams. Set the view for rendering the remote streams.
    let canvas = ZegoCanvas(view: self.remoteView)
    ZegoExpressEngine.shared().startPlayingStream(streamID, canvas: canvas)
}

private func stopPlayStream(streamID: String) {
    ZegoExpressEngine.shared().stopPlayingStream(streamID)
}

Start and stop your app

When your app starts, you need to call the createEngine method to initialize the SDK. When your app is about to exit, you can call the destroyEngine to release SDK resources.

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    createEngine()
    initViews()
}

override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    destroyEngine()
}

Test your implementation

To test your implementation, run your app project on a real device. Upon successful running, you can view the local video.

For your convenience of testing experience, we got you a Web platform for debugging. On the debugging page, you can enter the AppID and room ID of the real device user, and a different user ID to log in to the same room for communicating with the real device user. After a video call starts successfully, you can hear the remote audio and view the remote video.

Resource

For a detailed demo source code, check it here.

FAQ

  1. When running the App, it prompts Building for iOS Simulator, but the linked and embedded framework'ZegoExpressEngine.framework' was built for iOS + iOS Simulator.

    After Xcode 12.3, the framework with iOS + iOS (Simulator) dual-platform architecture is prohibited by default. It is recommended to replace it with XCFramework recommended by Apple (you can choose to download XCFramework in the drop-down box in Download SDK Package). Or you can select "TARGETS > Build Settings > Validate Workspace" through Xcode and set the value of this parameter to YES to continue using the traditional framework.

Resolution And Pricing Attention!

Please pay close attention to the relationship between video resolution and price when implementing video call, live streaming, and other video scenarios.

When playing multiple video streams in the same room, the billing will be based on the sum of the resolutions, and different resolutions will correspond to different billing tiers.

The video streams that are included in the calculation of the final resolution are as follows:

  1. Live streaming video view (such as host view, co-host view, PKBattle view, etc.)
  2. Video call's video view for each person
  3. Screen sharing view
  4. Resolution of the cloud recording service
  5. Resolution of the Live stream creation

Before your app goes live, please make sure you have reviewed all configurations and confirmed the billing tiers for your business scenario to avoid unnecessary losses. For more details, please refer to Pricing.

Page Directory