Video Call
  • iOS : Objective-C
  • Android
  • Web
  • Flutter
  • React Native
  • Electron
  • Unity3D
  • Cocos Creator
  • Windows
  • macOS
  • Linux
  • Overview
  • Develop your app
    • Integrate the SDK
    • Implement a basic video call
    • Enhance basic feature
      • Use Tokens for authentication
      • Config your video based on scenes
      • Check the room connection status
      • Set up common video config
      • Set up common audio config
  • Best practices
    • Implement a video call for multiple users
  • Upgrade using advanced features
    • Advanced features
      • Configure the video
        • Watermark the video/Take snapshots
        • Improve your appearance in the video
        • Beautify & Change the voice
        • Configure video codec
        • Output the video in H.265
      • Improve video quality
        • Configure bandwidth management
        • Test network and devices in advance
        • Visualize the sound level
        • Monitor streaming quality
      • Message signaling
        • Convey extra information using SEI
        • Broadcast real-time messages to a room
        • Quotas and limits
      • Play media files
        • Play media files
        • Play sound effects
      • Share the screen
      • Mix the video streams
      • Publish multiple video streams
      • Encrypt the video streams
      • Record video media data
    • Distincitve features
      • Join multiple rooms
      • Customize the video and audio
      • Set the voice hearing range
      • Use the bit mask
      • Play streams via URL
      • Play a transparent gift special effect
  • Upgrade using Add-on
  • Resources & Reference
    • SDK
    • Sample codes
    • API reference
      • Client APIs
      • Server APIs
    • Debugging
      • Error codes
      • Logging/Version number
    • FAQs
    • Key concepts
  • Documentation
  • Video Call
  • Develop your app
  • Implement a basic video call

Implement a basic video call

Last updated:2023-05-29 11:31

Introduction

This guide describes how to implement basic audio and video functions with the ZEGO Express SDK.

Basic concepts:

  • ZEGO Express SDK: The real-time audio and video SDK developed by ZEGO to help you quickly build high-quality, low-latency, and smooth real-time audio and video communications into your apps across different platforms, with support for massive concurrency.

  • Stream publishing: The process of the client app capturing and transmitting audio and video streams to the ZEGO Real-Time Audio and Video Cloud.

  • Stream playing: The process of the client app receiving and playing audio and video streams from the ZEGO Real-Time Audio and Video Cloud.

  • Room: The service for organizing groups of users, allowing users in the same room to send and receive real-time audio, video, and messages to each other.

    1. Logging in to a room is required to perform stream publishing and playing.
    2. Users can only receive notifications about changes in the room they are in (such as new users joining the room, existing users leaving the room, new audio and video streams being published, etc.).

For more basic concepts, refer to the Glossary.

Prerequisites

Before you begin, make sure you complete the following steps:

  • Create a project in ZEGOCLOUD Console, and get the AppID and AppSign of your project.
  • The ZEGO Express SDK has been integrated into the project. For details, see Integration.

If the version of the ZEGO Express SDK you are using is under 2.17.0, to get the AppSign, contact the ZEGOCLOUD Technical Support. To upgrade the authentication mode from using the AppSign to Token, see Upgrade guide.

Sample code

The following is sample code for a basic video call and can be used for reference during development.

Code for implementing a video call
//
//  ViewController.m
//  ZegoExpressExample
//
//  Copyright © 2022 Zego. All rights reserved.
//

#import "ViewController.h"
#import <ZegoExpressEngine/ZegoExpressEngine.h>

@interface ViewController ()<ZegoEventHandler>
// View for playing the audio and video streams of other users.
@property (strong, nonatomic) UIView *remoteUserView;
// Button for starting a video call.
@property (strong, nonatomic) UIButton *startVideoTalkButton;
// Button for stopping a video call.
@property (strong, nonatomic) UIButton *stopVideoTalkButton;


@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupUI];
}

- (void)setupUI {
    self.remoteUserView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 180, 250)];
    self.remoteUserView.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:self.remoteUserView];

    self.startVideoTalkButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.view addSubview:self.startVideoTalkButton];
    self.startVideoTalkButton.frame = CGRectMake(100, self.view.bounds.size.height - 280, 150, 50);
    [self.startVideoTalkButton.titleLabel setFont:[UIFont systemFontOfSize:32]];
    [self.startVideoTalkButton setTitle:@"Start" forState:UIControlStateNormal];
    [self.startVideoTalkButton addTarget:self action:@selector(startVideoTalk:) forControlEvents:UIControlEventTouchUpInside];

    self.stopVideoTalkButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.view addSubview:self.stopVideoTalkButton];
    self.stopVideoTalkButton.frame = CGRectMake(100, self.view.bounds.size.height - 200, 150, 50);
    [self.stopVideoTalkButton.titleLabel setFont:[UIFont systemFontOfSize:32]];
    [self.stopVideoTalkButton setTitle:@"Stop" forState:UIControlStateNormal];
    [self.stopVideoTalkButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [self.stopVideoTalkButton addTarget:self action:@selector(stopVideoTalk:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)startVideoTalk:(UIButton *)button {
    [self createEngine];
    [self loginRoom];
    [self startPublish];
}

- (void)stopVideoTalk:(UIButton *)button {
    [[ZegoExpressEngine sharedEngine] logoutRoom];
    [ZegoExpressEngine destroyEngine:^{

    }];
}

- (void)createEngine {
    ZegoEngineProfile *profile = [[ZegoEngineProfile alloc] init];
    // Register with the official website and obtain the data in the format similar to 1234567890.
    profile.appID = <#appID#>;
    // Register with the official website and obtain a string of 64 characters in the format similar to @"0123456789012345678901234567890123456789012345678901234567890123".
    profile.appSign = @"<#appSign#>"; 
    // General scenario. Select a scenario based on your service requirements.
    profile.scenario = ZegoScenarioDefault;
    // Create an engine and set `eventHandler` to `self`. If callback registration is not needed, `eventHandler` can be set to `nil`, and you can call the `-setEventHandler:` method to set the callback later on.
    [ZegoExpressEngine createEngineWithProfile:profile eventHandler:self];
}

- (void)loginRoom {
    // The value of `roomID` is generated locally and must be globally unique. Users must log in to the same room to call each other.
    NSString *roomID = @"room1";

    // Create a user object. The `ZegoUser` constructor `userWithUserID` will set `userName` to the value of `userID`. The `userID` and `userName` parameters cannot be set to `nil`. Otherwise, logging in to a room will fail.
    // The value of `userID` is generated locally and must be globally unique.
    ZegoUser *user = [ZegoUser userWithUserID:@"user1"];

    // The `onRoomUserUpdate` callback can be received only when `ZegoRoomConfig` in which the `isUserStatusNotify` parameter is set to `true` is passed.
    ZegoRoomConfig *roomConfig = [[ZegoRoomConfig alloc] init];
    // If you use the AppSign for authentication, you do not need to set the `token` parameter. If you want to use the Token for authentication, which is securer, see [Guide for upgrading the authentication mode from using the AppSign to Token](https://docs.zegocloud.com/faq/token_upgrade).

    // roomConfig.token = @"<#token#>";

    roomConfig.isUserStatusNotify = YES;
    // Log in to a room.
    [[ZegoExpressEngine sharedEngine] loginRoom:roomID user:user config:roomConfig callback:^(int errorCode, NSDictionary * _Nullable extendedData) {
        // (Optional callback) Room login result. This callback is sufficient if you only need to check the login result.
        if (errorCode == 0) {
            NSLog(@"Room login successful.");
        } else {
            // Login failed. For details, see [Error codes\|_blank](/404).
            NSLog(@"Room login failed.");
        }
    }];
}

- (void)startPublish {
    // Set the local preview view and start the preview. The default view mode of the SDK is used and the entire view is filled through proportional scaling.
    [[ZegoExpressEngine sharedEngine] startPreview:[ZegoCanvas canvasWithView:self.view]];

    // After calling the `loginRoom` method, call this method to publish streams.
    // Ensure that the value of `streamID` is globally unique under the same AppID. If different streams are published with the same `streamID`, the ones that are published after the first one will fail.
    [[ZegoExpressEngine sharedEngine] startPublishingStream:@"stream1"];
}

// After the `loginRoom` method is called, you can use the `onRoomStateChanged` callback to listen for the room connection status in real time.
// For details, see https://docs.zegocloud.com/article/13398.
-(void)onRoomStateChanged:(ZegoRoomStateChangedReason)reason errorCode:(int)errorCode extendedData:(NSDictionary *)extendedData roomID:(NSString *)roomID {
    if(reason == ZegoRoomStateChangedReasonLogining) {
        // Logging in to a room. When `loginRoom` is called to log in to a room or `switchRoom` is called to switch to another room, the room enters this status, indicating that it is requesting a connection to the server. On the app UI, the status of logging in to the room is displayed.
    } else if(reason == ZegoRoomStateChangedReasonLogined) {
        // Logging in to a room succeeds. When a user successfully logs in to a room or switches the room, the room enters this status. In this case, the user can receive notifications of addition or deletion of other users and their streams in the room.
        // Only after a user successfully logs in to a room or switches the room, `startPublishingStream` and `startPlayingStream` can be called to publish and play streams properly.
    } else if(reason == ZegoRoomStateChangedReasonLoginFailed) {
        // Logging in to a room fails. When a user fails to log in to a room or switch the room due to a reason such as incorrect AppID or Token, the room enters this status.
    } else if(reason == ZegoRoomStateChangedReasonReconnecting) {
        // The room connection is temporarily interrupted. The SDK will retry internally if the interruption is caused by poor network quality.
    } else if(reason == ZegoRoomStateChangedReasonReconnected) {
        // Reconnecting a room succeeds. The SDK will retry internally if the interruption is caused by poor network quality. If the reconnection is successful, the room enters this status.
    } else if(reason == ZegoRoomStateChangedReasonReconnectFailed) {
        // Reconnecting a room fails. The SDK will retry internally if the interruption is caused by poor network quality. If the reconnection fails, the room enters this status.
    } else if(reason == ZegoRoomStateChangedReasonKickOut) {
        // The server forces a user to log out of a room. If a user who has logged in to room A tries to log in to room B, the server forces the user to log out of room A and room A enters this status.
    } else if(reason == ZegoRoomStateChangedReasonLogout) {
        // Logging out of a room succeeds. This is the default status of a room before login. If a user successfully logs out of a room by calling `logoutRoom` or `switchRoom`, the room enters this status.
    } else if(reason == ZegoRoomStateChangedReasonLogoutFailed) {
        // Logging out of a room fails. If a user fails to log out of a room by calling `logoutRoom` or `switchRoom`, the room enters this status.
    }
}

// When another user in the same room publishes or stops publishing streams, you will receive a notification of stream increase or decrease of the user.
- (void)onRoomStreamUpdate:(ZegoUpdateType)updateType streamList:(NSArray<ZegoStream *> *)streamList extendedData:(NSDictionary *)extendedData roomID:(NSString *)roomID {
    // When `updateType` is set to `ZegoUpdateTypeAdd`, an audio and video stream is added, and you can call the `startPlayingStream` method to play the stream.
    if (updateType == ZegoUpdateTypeAdd) {
        // Start to play streams. Set the view for rendering the remote streams. The default view mode of the SDK is used and the entire view is filled through proportional scaling.
        // In the following code, the value of `remoteUserView` is the same as that of `View` of the UI. For conciseness of the sample code, only the first stream in the list of newly added audio and video streams is played here. In a real service, it is recommended that you traverse the stream list to play each stream.
        NSString *streamID = streamList[0].streamID;
        [[ZegoExpressEngine sharedEngine] startPlayingStream:streamID canvas:[ZegoCanvas canvasWithView:self.remoteUserView]];
    }
}

// You will receive this callback when another user logs in to or out of the room. If the value of `ZegoUpdateType` in the callback is `ZegoUpdateTypeAdd`, a user has logged in to the room. If the value of `ZegoUpdateType` in the callback is `ZegoUpdateTypeDelete`, a user has logged out of the room.
// This callback can be received only when `ZegoRoomConfig` in which the `isUserStatusNotify` parameter is set to `YES` is passed in the `loginRoom` method.
// The `onRoomUserUpdate` callback may be invalid for rooms with more than 500 users. If such rooms need to be supported in your service, contact ZEGOCLOUD technical support.
- (void)onRoomUserUpdate:(ZegoUpdateType)updateType userList:(NSArray<ZegoUser *> *)userList roomID:(NSString *)roomID {
    if (updateType == ZegoUpdateTypeAdd) {
        for (ZegoUser *user in userList) {
            NSLog(@"User %@ logged in to room %@.", user.userName, roomID);
        }
    } else if (updateType == ZegoUpdateTypeDelete) {
        for (ZegoUser *user in userList) {
            NSLog(@"User %@ logged out of room %@.", user.userName, roomID);
        }
    }
}

// Status notification of audio and video stream publishing.
// This callback is received when the status of audio and video stream publishing of a user changes. If an exception occurs during stream publishing due to a network interruption, the SDK retries to publish the streams and triggers this status change notification.
- (void)onPublisherStateUpdate:(ZegoPublisherState)state errorCode:(int)errorCode extendedData:(NSDictionary *)extendedData streamID:(NSString *)streamID {
    if (errorCode != 0) {
        NSLog(@"Stream publishing exception. errorCode: %d", errorCode);
    } else {
        switch (state) {
            case ZegoPublisherStatePublishing:
                NSLog(@"Publishing streams.");
                break;
            case ZegoPublisherStatePublishRequesting:
                NSLog(@"Requesting stream publishing.");
                break;
            case ZegoPublisherStateNoPublish:
                NSLog(@"Streams not published.");
                break;
        }
    }
}

// Status notifications of audio and video stream playing.
// This callback is received when the status of audio and video stream playing of a user changes. If an exception occurs during stream playing due to a network interruption, the SDK automatically retries to play the streams.
- (void)onPlayerStateUpdate:(ZegoPlayerState)state errorCode:(int)errorCode extendedData:(NSDictionary *)extendedData streamID:(NSString *)streamID {
    if (errorCode != 0) {
        NSLog(@"Stream playing exception. streamID: %@, errorCode: %d", streamID, errorCode);
    } else {
        switch (state) {
            case ZegoPlayerStatePlaying:
                NSLog(@"Playing streams.");
                break;
            case ZegoPlayerStatePlayRequesting:
                NSLog(@"Requesting stream playing.");
                break;
            case ZegoPlayerStateNoPlay:
                NSLog(@"Streams not played.");
                break;
        }
    }
}

// You can use the `onNetworkQuality` callback to listen for the upstream and downstream network quality of users (including yourself) in a room. This callback will be received every two seconds. For details about network quality levels, see `ZegoStreamQualityLevel`.
- (void)onNetworkQuality:(NSString *)userID upstreamQuality:(ZegoStreamQualityLevel)upstreamQuality downstreamQuality:(ZegoStreamQualityLevel)downstreamQuality {
    if (userID == nil) {
        // Network quality of the local user.
//        NSLog(@"My upstream network quality is %lu.", (unsigned long)upstreamQuality);
//        NSLog(@"My downstream network quality is %lu.", (unsigned long)downstreamQuality);
    } else {
        // Network quality of other users in a room.
//        NSLog(@"The upstream network quality of user %@ is %lu.", userID, (unsigned long)upstreamQuality);
//        NSLog(@"The downstream network quality of user %@ is %lu.", userID, (unsigned long)downstreamQuality);
    }

    /*
     ZegoStreamQualityLevelExcellent: The network quality is excellent.
     ZegoStreamQualityLevelGood: The network quality is good.
     ZegoStreamQualityLevelMedium: The network quality is medium.
     ZegoStreamQualityLevelBad: The network quality is bad.
     ZegoStreamQualityLevelDie: The network is abnormal.
     ZegoStreamQualityLevelUnknown: The network quality is unknown.
     */
}


@end

Implementation process

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

Initialize the SDK

Create 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

Import the header file

// Import the `ZegoExpressEngine.h` header file.
#import <ZegoExpressEngine/ZegoExpressEngine.h>

@interface ViewController ()<ZegoEventHandler>
// View for playing the audio and video streams of other users.
@property (strong, nonatomic) UIView *remoteUserView;
// Button for starting a video call.
@property (strong, nonatomic) UIButton *startVideoTalkButton;
// Button for stopping a video call.
@property (strong, nonatomic) UIButton *stopVideoTalkButton;

@end
- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupUI];
}

- (void)setupUI {
    self.remoteUserView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 180, 250)];
    self.remoteUserView.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:self.remoteUserView];

    self.startVideoTalkButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.view addSubview:self.startVideoTalkButton];
    self.startVideoTalkButton.frame = CGRectMake(100, self.view.bounds.size.height - 280, 150, 50);
    [self.startVideoTalkButton.titleLabel setFont:[UIFont systemFontOfSize:32]];
    [self.startVideoTalkButton setTitle:@"Start" forState:UIControlStateNormal];
    [self.startVideoTalkButton addTarget:self action:@selector(startVideoTalk:) forControlEvents:UIControlEventTouchUpInside];

    self.stopVideoTalkButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.view addSubview:self.stopVideoTalkButton];
    self.stopVideoTalkButton.frame = CGRectMake(100, self.view.bounds.size.height - 200, 150, 50);
    [self.stopVideoTalkButton.titleLabel setFont:[UIFont systemFontOfSize:32]];
    [self.stopVideoTalkButton setTitle:@"Stop" forState:UIControlStateNormal];
    [self.stopVideoTalkButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [self.stopVideoTalkButton addTarget:self action:@selector(stopVideoTalk:) forControlEvents:UIControlEventTouchUpInside];
}

- (void)startVideoTalk:(UIButton *)button {
    [self createEngine];
    [self loginRoom];
    [self startPublish];
}

Create a ZegoExpressEngine instance

Call the createEngineWithProfile method and set the appID and appSign parameters to the applied AppID and AppSign, respectively.

Use the scenario parameter to pass a room scenario matching the audio and video service of your app. For details, see Scenario-based audio and video configuration.

Register a callback. You can set eventHandler to an implemented object (for example, self) that conforms to the ZegoEventHandler protocol.

The SDK also supports Token-based authentication. If you want to upgrade the authentication mode, see Guide for upgrading the authentication mode from using the AppSign to Token.

- (void)createEngine {
    ZegoEngineProfile *profile = [[ZegoEngineProfile alloc] init];
    // Register with the official website and obtain the data in the format similar to 1234567890.
    profile.appID = <#appID#>;
    // Register on the official website and obtain a string of 64 characters in the format similar to @"0123456789012345678901234567890123456789012345678901234567890123".
    profile.appSign = <#appSign#>; 
    // Specify a scenario based on your service requirements.
    profile.scenario = ZegoScenarioBroadcast;
    // Create an engine and set `eventHandler` to `self`. If callback registration is not needed, `eventHandler` can be set to `nil`, and you can call the `-setEventHandler:` method to set the callback later on.
    [ZegoExpressEngine createEngineWithProfile:profile eventHandler:self];
}

Log in to a room

Call the loginRoom method to log in to a room. If the room does not exist, calling this method will create and log in to the room. The values of the roomID and user parameters are generated locally, but the following conditions must be met:

  • The value of roomID must be globally unique under the same AppID.
  • The value of userID must be globally unique under the same AppID. You are advised to associate userID with the account system of your service.
- (void)loginRoom {
    // The value of `roomID` is generated locally and must be globally unique. Users must log in to the same room to call each other.
    NSString *roomID = @"room1";

    // Create a user object. The `ZegoUser` constructor `userWithUserID` will set `userName` to the value of `userID`. The `userID` and `userName` parameters cannot be set to `nil`. Otherwise, logging in to a room will fail.
    // The value of `userID` is generated locally and must be globally unique.
    ZegoUser *user = [ZegoUser userWithUserID:@"user1"];

    // The `onRoomUserUpdate` callback can be received only when `ZegoRoomConfig` in which the `isUserStatusNotify` parameter is set to `true` is passed.
    ZegoRoomConfig *roomConfig = [[ZegoRoomConfig alloc] init];
    // If you use the AppSign for authentication, you do not need to set the `token` parameter. If you want to use the Token for authentication, which is securer, see [Guide for upgrading the authentication mode from using the AppSign to Token](https://docs.zegocloud.com/faq/token_upgrade).

    // roomConfig.token = @"<#token#>";

    roomConfig.isUserStatusNotify = YES;
    // Log in to a room.
    [[ZegoExpressEngine sharedEngine] loginRoom:roomID user:user config:roomConfig callback:^(int errorCode, NSDictionary * _Nullable extendedData) {
        // (Optional callback) Room login result. This callback is sufficient if you only need to check the login result.
        if (errorCode == 0) {
            NSLog(@"Room login successful.");
        } else {
            // Login failed. For details, see [Error codes\|_blank](/404).
            NSLog(@"Room login failed.");
        }
    }];
}

Listen for the login status (room connection status)

After the loginRoom method is called, you can use the onRoomStateChanged callback to listen for the room connection status in real time.

Start the local video preview and publish streams to ZEGOCLOUD audio and video cloud

Start the local video preview

To view the local videos, call the startPreview method to set the preview view and start the local preview.

Publish streams to ZEGOCLOUD audio and video cloud

After the loginRoom method is called, you can call the startPublishingStream method and pass streamID to publish the audio and video streams to ZEGOCLOUD audio and video cloud. You can use the onPublisherStateUpdate callback to listen for the publishing status.

The value of streamID is generated locally, but the following condition must be met:

The value of streamID must be globally unique under the same AppID. If different streams are published with the same streamID, the ones that are published after the first one will fail.

- (void)startPublish {
    // Set the local preview view and start the preview. The default view mode of the SDK is used and the entire view is filled through proportional scaling.
    [[ZegoExpressEngine sharedEngine] startPreview:[ZegoCanvas canvasWithView:self.view]];

    // After calling the `loginRoom` method, call this method to publish streams.
    // Ensure that the value of `streamID` is globally unique under the same AppID. If different streams are published with the same `streamID`, the ones that are published after the first one will fail.
    [[ZegoExpressEngine sharedEngine] startPublishingStream:@"stream1"];
}

@@@Warning_How_to_switch_devices@@@

Play streams

During a video call, audio and video streams of other users need to be played.

When another user in the same room publishes audio and video streams to ZEGOCLOUD audio and video cloud, you will receive a notification of new audio and video streams through the onRoomStreamUpdate callback and can obtain streamID of a certain stream through ZegoStream.

You can call startPlayingStream in the callback and pass the value of streamID to play the audio and video stream of the user. You can use the onPlayerStateUpdate callback to listen for the playing status.

// When another user in the same room publishes or stops publishing streams, you will receive a notification of stream increase or decrease of the user.
- (void)onRoomStreamUpdate:(ZegoUpdateType)updateType streamList:(NSArray<ZegoStream *> *)streamList extendedData:(NSDictionary *)extendedData roomID:(NSString *)roomID {
    // When `updateType` is set to `ZegoUpdateTypeAdd`, an audio and video stream is added, and you can call the `startPlayingStream` method to play the stream.
    if (updateType == ZegoUpdateTypeAdd) {
        // Start to play streams. Set the view for rendering the remote streams. The default view mode of the SDK is used and the entire view is filled through proportional scaling.
        // In the following code, the value of `remoteUserView` is the same as that of `View` of the UI. For the conciseness of the sample code, only the first stream in the list of newly added audio and video streams is played here. In a real service, it is recommended that you traverse the stream list to play each stream.
        NSString *streamID = streamList[0].streamID;
        [[ZegoExpressEngine sharedEngine] startPlayingStream:streamID canvas:[ZegoCanvas canvasWithView:self.remoteUserView]];
    }
}

Common features

Common callbacks

// After the `loginRoom` method is called, you can use the `onRoomStateChanged` callback to listen for the room connection status in real time.
// For details, see https://docs.zegocloud.com/article/13398.
-(void)onRoomStateChanged:(ZegoRoomStateChangedReason)reason errorCode:(int)errorCode extendedData:(NSDictionary *)extendedData roomID:(NSString *)roomID {
    if(reason == ZegoRoomStateChangedReasonLogining) {
        // Logging in to a room. When `loginRoom` is called to log in to a room or `switchRoom` is called to switch to another room, the room enters this status, indicating that it is requesting a connection to the server. On the app UI, the status of logging in to the room is displayed.
    } else if(reason == ZegoRoomStateChangedReasonLogined) {
        // Logging in to a room succeeds. When a user successfully logs in to a room or switches the room, the room enters this status. In this case, the user can receive notifications of addition or deletion of other users and their streams in the room.
        // Only after a user successfully logs in to a room or switches the room, can `startPublishingStream` and `startPlayingStream` be called to publish and play streams properly.
    } else if(reason == ZegoRoomStateChangedReasonLoginFailed) {
        // Logging in to a room fails. When a user fails to log in to a room or switch the room due to a reason such as incorrect AppID or AppSign, the room enters this status.
    } else if(reason == ZegoRoomStateChangedReasonReconnecting) {
        // The room connection is temporarily interrupted. The SDK will retry internally if the interruption is caused by poor network quality.
    } else if(reason == ZegoRoomStateChangedReasonReconnected) {
        // Reconnecting a room succeeds. The SDK will retry internally if the interruption is caused by poor network quality. If the reconnection is successful, the room enters this status.
    } else if(reason == ZegoRoomStateChangedReasonReconnectFailed) {
        // Reconnecting a room fails. The SDK will retry internally if the interruption is caused by poor network quality. If the reconnection fails, the room enters this status.
    } else if(reason == ZegoRoomStateChangedReasonKickOut) {
        // The server forces a user to log out of a room. If a user who has logged in to room A tries to log in to room B, the server forces the user to log out of room A and room A enters this status.
    } else if(reason == ZegoRoomStateChangedReasonLogout) {
        // Logging out of a room succeeds. This is the default status of a room before login. If a user successfully logs out of a room by calling `logoutRoom` or `switchRoom`, the room enters this status.
    } else if(reason == ZegoRoomStateChangedReasonLogoutFailed) {
        // Logging out of a room fails. If a user fails to log out of a room by calling `logoutRoom` or `switchRoom`, the room enters this status.
    }
}

// When another user in the same room publishes or stops publishing streams, you will receive a notification of stream increase or decrease of the user.
- (void)onRoomStreamUpdate:(ZegoUpdateType)updateType streamList:(NSArray<ZegoStream *> *)streamList extendedData:(NSDictionary *)extendedData roomID:(NSString *)roomID {
    // When `updateType` is set to `ZegoUpdateTypeAdd`, an audio and video stream is added, and you can call the `startPlayingStream` method to play the stream.
    if (updateType == ZegoUpdateTypeAdd) {
        NSString *streamID = streamList[0].streamID;
        //[[ZegoExpressEngine sharedEngine] startPlayingStream:streamID canvas:[ZegoCanvas canvasWithView:self.remoteUserView]];
    }
}

// You will receive this callback when another user logs in to or out of the room. If the value of `ZegoUpdateType` in the callback is `ZegoUpdateTypeAdd`, a user has logged in to the room. If the value of `ZegoUpdateType` in the callback is `ZegoUpdateTypeDelete`, a user has logged out of the room.
// This callback can be received only when `ZegoRoomConfig` in which the `isUserStatusNotify` parameter is set to `YES` is passed in the `loginRoom` method.
// The `onRoomUserUpdate` callback may be invalid for rooms with more than 500 users. If such rooms need to be supported in your service, contact ZEGOCLOUD technical support.
- (void)onRoomUserUpdate:(ZegoUpdateType)updateType userList:(NSArray<ZegoUser *> *)userList roomID:(NSString *)roomID {
    if (updateType == ZegoUpdateTypeAdd) {
        for (ZegoUser *user in userList) {
            NSLog(@"User %@ logged in to room %@.", user.userName, roomID);
        }
    } else if (updateType == ZegoUpdateTypeDelete) {
        for (ZegoUser *user in userList) {
            NSLog(@"User %@ logged out of room %@.", user.userName, roomID);
        }
    }
}

// Status notification of audio and video stream publishing.
// This callback is received when the status of audio and video stream publishing of a user changes. If an exception occurs during stream publishing due to a network interruption, the SDK retries to publish the streams and triggers this status change notification.
- (void)onPublisherStateUpdate:(ZegoPublisherState)state errorCode:(int)errorCode extendedData:(NSDictionary *)extendedData streamID:(NSString *)streamID {
    if (errorCode != 0) {
        NSLog(@"Stream publishing exception. errorCode: %d", errorCode);
    } else {
        switch (state) {
            case ZegoPublisherStatePublishing:
                NSLog(@"Publishing streams.");
                break;
            case ZegoPublisherStatePublishRequesting:
                NSLog(@"Requesting stream publishing.");
                break;
            case ZegoPublisherStateNoPublish:
                NSLog(@"Streams not published.");
                break;
        }
    }
}

// Status notifications of audio and video stream playing.
// This callback is received when the status of audio and video stream playing of a user changes. If an exception occurs during stream playing due to a network interruption, the SDK automatically retries to play the streams.
- (void)onPlayerStateUpdate:(ZegoPlayerState)state errorCode:(int)errorCode extendedData:(NSDictionary *)extendedData streamID:(NSString *)streamID {
    if (errorCode != 0) {
        NSLog(@"Stream playing exception. streamID: %@, errorCode: %d", streamID, errorCode);
    } else {
        switch (state) {
            case ZegoPlayerStatePlaying:
                NSLog(@"Playing streams.");
                break;
            case ZegoPlayerStatePlayRequesting:
                NSLog(@"Requesting stream playing.");
                break;
            case ZegoPlayerStateNoPlay:
                NSLog(@"Streams not played.");
                break;
        }
    }
}

// You can use the `onNetworkQuality` callback to listen for the upstream and downstream network quality of users (including yourself) in a room. This callback will be received every two seconds. For details about network quality levels, see `ZegoStreamQualityLevel`.
- (void)onNetworkQuality:(NSString *)userID upstreamQuality:(ZegoStreamQualityLevel)upstreamQuality downstreamQuality:(ZegoStreamQualityLevel)downstreamQuality {
    if (userID == nil) {
        // Network quality of the local user.
//        NSLog(@"My upstream network quality is %lu.", (unsigned long)upstreamQuality);
//        NSLog(@"My downstream network quality is %lu.", (unsigned long)downstreamQuality);
    } else {
        // Network quality of other users in a room.
//        NSLog(@"The upstream network quality of user %@ is %lu.", userID, (unsigned long)upstreamQuality);
//        NSLog(@"The downstream network quality of user %@ is %lu.", userID, (unsigned long)downstreamQuality);
    }

    /*
     ZegoStreamQualityLevelExcellent: The network quality is excellent.
     ZegoStreamQualityLevelGood: The network quality is good.
     ZegoStreamQualityLevelMedium: The network quality is medium.
     ZegoStreamQualityLevelBad: The network quality is bad.
     ZegoStreamQualityLevelDie: The network is abnormal.
     ZegoStreamQualityLevelUnknown: The network quality is unknown.
     */
}

Stop a video call

Stop publishing or playing audio and video streams

Stop the stream publishing and preview

Call the stopPublishingStream method to stop publishing local audio and video streams to remote users.

// Stop publishing streams.
[[ZegoExpressEngine sharedEngine] stopPublishingStream];

If the local preview is started, call the stopPreview method to stop it.

// Stop the local preview.
[[ZegoExpressEngine sharedEngine] stopPreview];

Stop playing streams

Call the stopPlayingStream method to stop playing audio and video streams published by remote users.

// Stop playing streams.
[[ZegoExpressEngine sharedEngine] stopPlayingStream:@"stream1"];

Log out of a room

Call the logoutRoom method to log out of a room.

// Log out of a room.
[[ZegoExpressEngine sharedEngine] logoutRoom];

Destroy a ZegoExpressEngine instance

If a user will not use the audio and video feature any longer, call the destroyEngine method to destroy the ZegoExpressEngine instance and release resources such as the microphone, camera, memory, and CPU.

  • If you need to receive a callback to ensure that hardware resources are released, pass callback when destroying the ZegoExpressEngine instance. This callback can only be used to send a notification when destruction of the engine is completed. You cannot use this callback method to release engine-related resources.
  • If you do not want to receive any callbacks, pass nil to destroyEngine instead.
[ZegoExpressEngine destroyEngine:nil];

Debug the video call feature

We recommend you run your project on a real device. If your app runs successfully, you should hear the sound and see the video captured locally from your device.

To test out the real-time audio and video features, visit the ZEGO Express Web Demo, and enter the same AppID, Server and RoomID to join the same room. If it runs successfully, you should be able to view the video from both the local side and the remote side, and hear the sound from both sides as well.

In audio-only scenarios, no video will be captured and displayed.

Page Directory