logo
Video Call
On this page

Implementing Video Call

2025-01-21

Introduction

This article will introduce how to quickly implement a simple real-time audio and video call.

Explanation of related concepts:

  • ZEGO Express SDK: A real-time audio and video SDK provided by ZEGO, which can provide developers with convenient access, high definition and smoothness, multi-platform interoperability, low latency, and high concurrency audio and video services.
  • Stream: Refers to a group of audio and video data that are continuously being sent, packaged according to a specified encoding format. A user can simultaneously publish multiple streams (for example, one for camera data and one for screen sharing data) and can also play multiple streams. Each stream is identified by a stream ID (streamID).
  • Publish stream: The process of pushing packaged audio and video data streams to the ZEGOCLOUD.
  • Play stream: The process of pulling and playing existing audio and video data streams from the ZEGOCLOUD.
  • Room: An audio and video space service provided by ZEGO, used to organize user groups. Users in the same room can send and receive real-time audio and video and messages to each other.
    1. Users need to log in to a room first before they can publish and play streams.
    2. Users can only receive relevant messages in the room they are in (user entries/exits, audio and video stream changes, etc.).
    3. Each room is identified by a unique roomID within an AppID. All users who log in to the room using the same roomID belong to the same room.

For more related concepts, please refer to Terminology Explanation.

Prerequisites

Before implementing basic real-time audio and video functions, ensure that:

  • ZEGO Express SDK has been integrated into the project and basic real-time audio and video functions have been implemented. For details, please refer to Quick Start - Integration.
  • A project has been created in the ZEGOCLOUD Console, and valid AppID and AppSign have been obtained.
Warning

The SDK also supports Token authentication. If you have higher requirements for project security, it is recommended that you upgrade the authentication method. For details, please refer to How to upgrade from AppSign authentication to Token authentication.

Implementation Process

The basic process for users to make video calls through ZEGO Express SDK is as follows:

Users A and B join the room. User B previews and pushes the audio and video stream to the ZEGO cloud service (publish stream). After user A receives the notification of user B's pushed audio and video stream, user A plays user B's audio and video stream in the notification (play stream).

1 Create Engine

1. Create Interface

According to scenario needs, create a user interface for video calls for your project. We recommend that you add the following elements to your project:

  • Local video window
  • Remote video window
  • End call button

2. Import Header File

Import the ZegoExpressEngine header file in your project.

// Import ZegoExpressEngine.h header file
#include "ZegoExpressSDK.h"

3. Create Engine

Call the createEngine interface and pass the applied AppID and AppSign into the parameters "appID" and "appSign".

Select an appropriate scenario according to the actual audio and video business of the App. Please refer to the Scenario-based Audio and Video Configuration document and pass the selected scenario enumeration into the parameter "scenario".

Warning

The SDK also supports Token authentication. If you have higher requirements for project security, it is recommended that you upgrade the authentication method. For details, please refer to How to upgrade from AppSign authentication to Token authentication.

ZegoEngineProfile profile;
// AppID and AppSign are assigned to each App by ZEGO; for security reasons, it is recommended to store AppSign in the App's business backend and obtain it from the backend when needed
profile.appID = appID;
profile.appSign = appSign;
// Specify using the live streaming scenario (please fill in the scenario suitable for your business according to the actual situation)
profile.scenario = ZegoScenario::ZEGO_SCENARIO_BROADCAST;
// Create engine instance
auto engine = ZegoExpressSDK::createEngine(profile, nullptr);

4. Set Callbacks

You can instantiate a class that implements the IZegoEventHandler interface and implement the required callback methods to listen to and handle event callbacks you care about, and then pass the instantiated object as an eventHandler parameter to the createEngine method or pass it to setEventHandler to register callbacks.

Warning

It is recommended to register callbacks when creating the engine or immediately after creating the engine, to avoid delaying registration and missing event notifications.

My connection status change notification in the room

onRoomStateChanged: When the local user calls loginRoom to join the room, you can monitor your connection status in the room in real time by listening to the onRoomStateChanged callback.

You can handle business logic based on different states in the callback.

virtual void onRoomStateChanged(const std::string& roomID, ZegoRoomStateChangedReason reason, int errorCode, const std::string& extendedData) {

}

The meanings of ZegoRoomStateChangedReason states are as follows:

StateEnumeration ValueMeaning
ZEGO_ROOM_STATE_CHANGED_REASON_LOGINING0Logging in to the room. When calling [loginRoom] to log in to the room or [switchRoom] to switch to the target room, enter this state, indicating that a request is being made to connect to the server. Usually, this state is used to display the application interface.
ZEGO_ROOM_STATE_CHANGED_REASON_LOGINED1Successfully logged in to the room. After successfully logging in to or switching rooms, enter this state, indicating that logging in to the room has been successful, and users can normally receive callback notifications for additions and deletions of all other users and all stream information in the room.
ZEGO_ROOM_STATE_CHANGED_REASON_LOGIN_FAILED2Failed to log in to the room. After failing to log in to or switch rooms, enter this state, indicating that logging in to the room or switching rooms has failed, such as incorrect AppID or Token, etc.
ZEGO_ROOM_STATE_CHANGED_REASON_RECONNECTING3Room connection temporarily interrupted. If the interruption is caused by poor network quality, the SDK will perform internal retry.
ZEGO_ROOM_STATE_CHANGED_REASON_RECONNECTED4Room reconnection successful. If the interruption is caused by poor network quality, the SDK will perform internal retry. After successful reconnection, enter this state.
ZEGO_ROOM_STATE_CHANGED_REASON_RECONNECT_FAILED5Room reconnection failed. If the interruption is caused by poor network quality, the SDK will perform internal retry. After failed reconnection, enter this state.
ZEGO_ROOM_STATE_CHANGED_REASON_KICK_OUT6Kicked out of the room by the server. For example, when a user with the same username logs in to the room elsewhere, causing the local end to be kicked out of the room, this state will be entered.
ZEGO_ROOM_STATE_CHANGED_REASON_LOGOUT7Successfully logged out of the room. This is the default state before logging in to the room. After successfully calling [logoutRoom] to log out of the room or [switchRoom] internally logging out of the current room successfully, enter this state.
ZEGO_ROOM_STATE_CHANGED_REASON_LOGOUT_FAILED8Failed to log out of the room. After failing to call [logoutRoom] to log out of the room or [switchRoom] internally failing to log out of the current room, enter this state.

Notifications of other users entering or leaving the room

onRoomUserUpdate: When other users in the same room enter or leave the room, you can receive notifications through this callback.

Warning
  • Only when the isUserStatusNotify parameter in the configuration ZegoRoomConfig passed when logging in to the room loginRoom is true, can users receive callbacks of other users in the room.

  • When the parameter ZegoUpdateType in the callback is ZEGO_UPDATE_TYPE_ADD, it indicates that a user has entered the room; when ZegoUpdateType is ZEGO_UPDATE_TYPE_DELETE, it indicates that a user has left the room.

void VideoTalk::onRoomUserUpdate(const std::string &roomID, ZegoUpdateType updateType, const std::vector<ZegoUser> &userList) {
    // You can handle corresponding business logic in the callback based on user entry/exit situations
    if (updateType == ZEGO_UPDATE_TYPE_ADD) {

    } else if (updateType == ZEGO_UPDATE_TYPE_DELETE) {

    }
}

Status notification of user publishing audio and video streams

onPublisherStateUpdate: According to actual application needs, after a user publishes audio and video streams, when the status of the published video stream changes (such as network interruption causing publishing stream abnormalities, etc.), you will receive this callback, and the SDK will automatically retry.

void VideoTalk::onPublisherStateUpdate(const std::string &streamID, ZegoPublisherState state, int errorCode, const std::string &extendData) {
    if (errorCode != 0) {
        // Publishing stream status error
    } else {
        switch (state) {
            case ZEGO_PUBLISHER_STATE_PUBLISHING:
                // Publishing stream
                break;
            case ZEGO_PUBLISHER_STATE_PUBLISH_REQUESTING:
                // Requesting to publish stream
                break;
            case ZEGO_PUBLISHER_STATE_NO_PUBLISH:
                // Not publishing stream
                break;
        }
    }
}

Status notification of user playing audio and video streams

onPlayerStateUpdate: According to actual application needs, after a user plays audio and video streams, when the status of the played video stream changes (such as network interruption causing playing stream abnormalities, etc.), you will receive this callback, and the SDK will automatically retry.

void VideoTalk::onPlayerStateUpdate(const std::string &streamID, ZegoPlayerState state, int errorCode, const std::string &extendData) {
    if (errorCode != 0) {
        //Playing stream status error
    } else {
        switch (state) {
            case ZEGO_PLAYER_STATE_NO_PLAY:
                // Playing stream
                break;
            case ZEGO_PLAYER_STATE_PLAY_REQUESTING:
                // Requesting to play stream
                break;
            case ZEGO_PLAYER_STATE_NO_PLAY:
                // Not playing stream
                break;
        }
    }
}

2 Login Room

After creating a ZegoUser user object by passing in the user ID parameter "userID", call the loginRoom interface and pass in the room ID parameter "roomID" and user parameter "user" to log in to the room. If the room does not exist, calling this interface will create and log in to this room.

The parameters roomID and user are generated locally by you, but need to meet the following conditions:

  • Within the same AppID, ensure that "roomID" is globally unique.
  • Within the same AppID, ensure that "userID" is globally unique. It is recommended that developers set it to a meaningful value and associate "userID" with their own business account system.
Warning

ZegoUser cannot be the default value, otherwise it will cause login room failure.

// Create user object
ZegoUser user("user1", "user1");
// Only by passing in ZegoRoomConfig with the "isUserStatusNotify" parameter value of "true" can you receive the onRoomUserUpdate callback.
ZegoRoomConfig roomConfig;
//If you use appsign for authentication, you do not need to fill in the token parameter; if you need to use a more secure authentication method: token authentication, please refer to [How to upgrade from AppSign authentication to Token authentication](https://www.zegocloud.com/docs/faq/express-token-upgrade)
// roomConfig.token = "xxxx";
roomConfig.isUserStatusNotify = true;
// Login room
engine->loginRoom(roomID, user, roomConfig, [=](){
    // (Optional callback) Login room result. If you only care about the login result, just pay attention to this callback
});

After calling the login room interface, you can monitor your connection status in the room in real time by listening to the onRoomStateChanged callback.

Only when the room status is successful login or successful reconnection can publishing stream (startPublishingStream) and playing stream (startPlayingStream) normally send and receive audio and video.

void onRoomStateChanged(const std::string& roomID, ZegoRoomStateChangedReason reason, int errorCode, const std::string& extendedData) {
    if(reason == ZEGO_ROOM_STATE_CHANGED_REASON_LOGINING)
    {
        // Logging in
    }
    else if(reason == ZEGO_ROOM_STATE_CHANGED_REASON_LOGINED)
    {
        // Login successful
        //Only when the room status is successful login or successful reconnection can publishing stream (startPublishingStream) and playing stream (startPlayingStream) normally send and receive audio and video
        //Push your audio and video stream to the ZEGO audio and video cloud
    }
    else if(reason == ZEGO_ROOM_STATE_CHANGED_REASON_LOGIN_FAILED)
    {
        // Login failed
    }
    else if(reason == ZEGO_ROOM_STATE_CHANGED_REASON_RECONNECTING)
    {
        // Reconnecting
    }
    else if(reason == ZEGO_ROOM_STATE_CHANGED_REASON_RECONNECTED)
    {
        // Reconnection successful
    }
    else if(reason == ZEGO_ROOM_STATE_CHANGED_REASON_RECONNECT_FAILED)
    {
        // Reconnection failed
    }
    else if(reason == ZEGO_ROOM_STATE_CHANGED_REASON_KICK_OUT)
    {
        // Kicked out of the room
    }
    else if(reason == ZEGO_ROOM_STATE_CHANGED_REASON_LOGOUT)
    {
        // Logout successful
    }
    else if(reason == ZEGO_ROOM_STATE_CHANGED_REASON_LOGOUT_FAILED)
    {
        // Logout failed
    }
}

3 Preview your own screen and push to ZEGO audio and video cloud

1. (Optional) Preview your own screen

Note

Whether or not you call startPreview to preview, you can push your audio and video stream to the ZEGO audio and video cloud.

Set the preview view and start local preview.

If you want to see the local screen, you can call the startPreview interface to set the preview view and start local preview.

// Set local preview view and start preview. The view mode uses the SDK default mode, scaling proportionally to fill the entire View
ZegoCanvas canvas((void*)view);
engine->startPreview(&canvas);

2. Push your audio and video stream to the ZEGO audio and video cloud

After the user calls the loginRoom interface, they can directly call the startPublishingStream interface and pass in the streamID to push their audio and video stream to the ZEGO audio and video cloud. You can know whether the publishing stream is successful by listening to the onPublisherStateUpdate callback.

The streamID is generated locally by you, but needs to ensure that: Under the same AppID, "streamID" is globally unique. If under the same AppID, different users each publish a stream with the same "streamID", the user who publishes the stream later will fail to publish the stream.

The example here publishes stream immediately after calling the loginRoom interface. When implementing specific business, you can choose other timings to publish stream, as long as you ensure to call loginRoom first.

// User calls this interface to publish stream after calling loginRoom
// Under the same AppID, developers need to ensure that "streamID" is globally unique. If different users each publish a stream with the same "streamID", the user who publishes the stream later will fail to publish the stream.
engine->startPublishingStream("stream1");
Note
If you need to know about camera/video/microphone/audio/speaker related interfaces of ZEGO Express SDK, please refer to FAQ - How to implement switching camera/video screen/microphone/audio/speaker?.

4 Play other users' audio and video

When making video calls, we need to play other users' audio and video.

onRoomStreamUpdate: When other users in the same room push audio and video streams to the ZEGO audio and video cloud, we will receive notifications of audio and video stream additions in this callback.

We can call startPlayingStream in this callback and pass in "streamID" to play the user's audio and video.

Warning

If users encounter related errors during audio and video calls, they can query Error Codes.

// When other users in the room publish/stop publishing streams, we will receive corresponding stream addition/deletion notifications here
void VideoTalk::onRoomStreamUpdate(const std::string &roomID, ZegoUpdateType updateType, const std::vector<ZegoStream> &streamList, const std::string &extendData) {
    //When updateType is ZEGO_UPDATE_TYPE_ADD, it represents that audio and video streams have been added. At this time, we can call the startPlayingStream interface to play this audio and video stream
    if (updateType == ZEGO_UPDATE_TYPE_ADD) {
        // Start playing stream, set remote playing stream rendering view. The view mode uses the SDK default mode, scaling proportionally to fill the entire View
        // The following playView is the UI window handle
        std::string streamID = streamList[0].streamID;
        ZegoCanvas canvas((void*)playView);
        engine->startPlayingStream(streamID , &canvas);
    }
}

5 Online test of publishing and playing stream functions

Run the project on the real device. After successful operation, you can see the local video screen.

For convenience, ZEGO provides a Web platform for debugging. On this page, enter the same AppID and RoomID, enter different UserIDs and corresponding Token, and you can join the same room to communicate with the real device. When the audio and video call starts successfully, you can hear the remote audio and see the remote video screen.

6 Stop audio and video call

Stop pushing and playing audio and video streams

1. Stop publishing stream, stop preview

Call the stopPublishingStream interface to stop sending the local audio and video stream to remote users.

// Stop publishing stream
engine->stopPublishingStream();

If local preview is enabled, call the stopPreview interface to stop preview.

// Stop local preview
engine->stopPreview();

2. Stop playing stream

Call the stopPlayingStream interface to stop playing the audio and video stream pushed by remote users.

Warning

If the developer receives a notification of "decrease" in audio and video streams through the onRoomStreamUpdate callback, please call the stopPlayingStream interface in time to stop playing stream to avoid playing empty streams and generating additional costs; or, developers can choose appropriate timing according to their own business needs and actively call the stopPlayingStream interface to stop playing stream.

// Stop playing stream
engine->stopPlayingStream("stream1");

Leave room

Call the logoutRoom interface to leave the room.

// Leave room
engine->logoutRoom("room1");

Destroy Engine

If users completely no longer use audio and video functions, they can call the destroyEngine interface to destroy the engine and release resources such as microphones, cameras, memory, CPU, etc.

  • If you need to listen to callbacks to ensure that device hardware resources are released, you can pass in "callback" when destroying the engine. This callback is only used for sending notifications. Developers cannot release engine-related resources in the callback.

  • If you don't need to listen to callbacks, you can pass in "nullptr".

ZegoExpressSDK::destroyEngine(engine, nullptr);
engine = nullptr;

Video Call API Call Sequence

FAQ

Can I directly kill the process when calling logoutRoom to log out of the room?

After calling logoutRoom, directly killing the process has a certain probability of causing the logoutRoom signal not to be sent. Then the ZEGO server can only consider that this user has left the room after the heartbeat times out. To ensure that the logoutRoom signal is sent, it is recommended to call destroyEngine again and wait for the callback before killing the process.

Previous

Integrate SDK

Next

Scenario-based Audio and Video Configuration