Video Call
  • iOS
  • Android
  • Web : JavaScript
  • 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
      • 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
        • Improve your appearance in the video
        • Configure video codec
      • Improve video quality
        • Visualize the sound level
        • Monitor streaming quality
      • Message signaling
        • Broadcast real-time messages to a room
        • Quotas and limits
      • Share the screen
      • Mix the video streams
      • Publish multiple video streams
      • Replace the audio/video track
    • Distincitve features
      • Join multiple rooms
      • Customize the video and audio
      • Set the voice hearing range
      • Render the audio and video
      • Autoplay policy
      • Restrictions on playing multiple videos simultaneously in Safari
      • Play streams via URL
      • Browser compatibility
      • Audio mixing
      • Vitrual Background and Blur
    • Implement a video call using frameworks
      • Implement a video call using Vue
      • Implement a video call using Angular
      • Implement a video call using React
  • 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-12-14 15:24

Introduction

This topic describes how to quickly implement a basic real-time video call.

Before you begin, learn about the following basic concepts about audio and video:

  • Stream: a group of audio and video data encapsulated in a specified encoding format. A stream can contain several video and audio tracks.
  • Stream publishing: the process of publishing the audio and video data streams that are captured and packaged to ZEGOCLOUD real-time audio and video cloud.
  • Stream playing: the process of receiving and playing audio and video data streams from ZEGOCLOUD real-time audio and video cloud.
  • Room: the service provided by ZEGOCLOUD for organizing user groups and allowing users in the same room to receive and send real-time audio, video, and messages to each other.
    1. Users can publish or play streams only after logging in to a room.
    2. Users can receive notifications about changes (such as users joining or leaving a room, and audio and video stream changes) in the room where they are in.

For more concepts, see Glossary.

Prerequisites

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

Sample code

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

Complete HTML sample code
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>Zego Express Video Call</title>
    <!-- Enter the correct SDK version number. -->
    <script src="ZegoExpressWebRTC-x.x.x.js"></script>

    <style type="text/css">
        h1,
        h4 {
            text-align: center;
        }

        .video-wrapper {
            width: 610px;
            margin: 0 auto;
        }

        .video-wrapper h4 {
            width: 300px;
            display: inline-block;
            position: relative;
        }
        #remote-video, #local-video {
            width: 300px;
            height: 270px;
            display: inline-block;
            position: relative;
        }

        .video-wrapper video {
            height: auto;
        }
    </style>
</head>

<body>
    <h1>
        Zego RTC Video Call
    </h1>
    <div class="video-wrapper">
        <h4>Local video</h4>
        <h4>Remote video</h4>
        <div id="local-video"></div>
        <div id="remote-video"></div>
    </div>
    <script>
        // Unique AppID of a project, which is of the Number type. You can obtain it in ZEGOCLOUD Admin Console.
        let appID = 0
        // Access server address, which is of the String type. You can obtain it in ZEGOCLOUD Admin Console. (For more information about how to obtain it, see Prerequisites.)
        let server = ""

        // Instance initialization
        const zg = new ZegoExpressEngine(appID, server);
        zg.setDebugVerbose(false)
        // Room status update callback
        // In the sample code, streams are published immediately after you successfully log in to a room. When implementing your service, you can choose to publish streams at any time when the room is connected status.
        // Room status update callback
        zg.on('roomStateChanged', async (roomID, reason, errorCode, extendedData) => {
            if (reason == 'LOGINED') {
                console.log ("Connected to the room successfully. You can perform operations such as stream publishing and playing only after the room is successfully connected.")
            }
        })

        zg.on('roomUserUpdate', (roomID, updateType, userList) => {
            // Notification of users joining or leaving a room
        });

        zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
            // Notification of audio or video stream updates of other users in a room
            if (updateType == 'ADD') {
                // When streams are added, play them.
                // In the sample code, the audio and video of the first stream in the stream addition list are played.
                const streamID = streamList[0].streamID;
                // The stream list specified by `streamList` contains the ID of the corresponding stream.
                const remoteStream = await zg.startPlayingStream(streamID);
                // Create a media stream player.
                const remoteView = zg.createRemoteStreamView(remoteStream);
                remoteView.play("remote-video", {enableAutoplayDialog:true});

            } else if (updateType == 'DELETE') {
                // When streams are deleted, stop playing them based on `streamID` of the streams in the stream deletion list specified by `streamList`.
                const streamID = streamList[0].streamID;
                zg.stopPlayingStream(streamID)
            }
        });

        // Log in to a room. If the login succeeds, `true` is returned.
        // The `roomUserUpdate` callback can be received only when `userUpdate` is set to `true`.
        let userID = "user1"; // You can set `userID` based on your service requirements but ensure that it is globally unique.
        let userName = "user1";// You can set `userName` based on your service requirements, which is not necessarily to be unique.
        let roomID = "123"; // You can set `roomID` based on your service requirements but ensure that it is globally unique.
        // The value of `token` is generated by your server. To quickly perform debugging, you can apply for a temporary audio and video token of the String type in ZEGOCLOUD Admin Console (https://console.zego.im/).
        let token = ``;

        zg.loginRoom(roomID, token, { userID, userName: userID }, { userUpdate: true }).then(async result => {
            if (result == true) {
                console.log("login success");
                // Connected to the room successfully. You can perform operations such as stream publishing and playing only after the room is successfully connected.
                // Create a stream and start the preview.
                // After calling the createZegoStream method, you need to wait for the ZEGO server to return the local stream object before any further operation.
                const localStream = await zg.createZegoStream();
                // Play preview of the stream
                localStream.playVideo(document.querySelector("#local-video"), {enableAutoplayDialog:true});
                // Publish a stream to ZEGOCLOUD audio and video cloud. You can set `streamID` based on your service requirements but ensure that it is globally unique.
                let streamID = new Date().getTime().toString();
                zg.startPublishingStream(streamID, localStream)
            }
        });
        // // Alternative code for room login
        // (async function main(){
        //     await zg.loginRoom(roomID, token, { userID, userName: userID }, { userUpdate: true })
        // })()
    </script>
</body>

</html>

Implementation steps

The following diagram shows a basic real-time video call process of User A playing a stream published by User B.

  1. User A creates a ZegoExpressEngine instance and logs in to a room. (After the login succeeds, User A can preview and publish streams.)
  2. User B creates a ZegoExpressEngine instance and logs in to the same room. After the login succeeds, User B publishes a stream. At this time, the SDK triggers the roomStreamUpdate callback, indicating that there is a stream change in the room.
  3. User A can listen for the roomStreamUpdate callback event. When receiving the callback, indicating that there is a new stream, User A obtains the ID of the stream published by User B and plays the stream.

/Pics/QuickStart/implementation_process_web_latesten.png

Create the UI

The following provides a UI layout and sample code, helping you implement basic real-time audio and video features.

layout

Open or create the index.html file and copy the following code to the file.

<html>

<head>
    <meta charset="UTF-8">
    <title>Zego Express Video Call</title>
    <style type="text/css">
        * {
            font-family: sans-serif;
        }

        h1,
        h4 {
            text-align: center;
        }

        #local-video, #remote-video {
            width: 400px;
            height: 300px;
            border: 1px solid #dfdfdf;
        }

        #local-video {
            position: relative;
            margin: 0 auto;
            display: block;
        }

        #remote-video {
            display: flex;
            margin: auto;
            position: relative !important;
        }
    </style>
</head>

<body>
    <h1>
        Zego RTC Video Call
    </h1>
    <h4>Local video</h4>
    <div id="local-video"></div>
    <h4>Remote video</h4>
    <div id="remote-video"></div>
    <script>
    // Copy and paste the JavaScript sample code in the following part of this topic here.
    // const zg = new ZegoExpressEngine(appID, server);
    </script>
</body>

</html>

Create a ZegoExpressEngine instance and listen for event callbacks

  1. Create and initialize a ZegoExpressEngine instance. Set the appID and server parameters to the AppID and access server address of your project.

  2. Listen for callback events immediately to prevent yourself from missing any notifications. The SDK provides notification callbacks for room connection status updates, audio and video stream updates, and user login or logout.

// Unique AppID of a project, which is of the Number type. You can obtain it in ZEGOCLOUD Admin Console.
let appID = ; 
// Access server address, which is of the String type. You can obtain it in ZEGOCLOUD Admin Console. (For more information about how to obtain it, see Prerequisites.)
let server = "";

// Instance initialization
const zg = new ZegoExpressEngine(appID, server);

// Room status update callback
zg.on('roomStateChanged', (roomID, reason, errorCode, extendData) => {
        if (reason == 'LOGINING') {
            // Logging in.
        } else if (reason == 'LOGINED') {
            // Login successful.
            // 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.
            // Publish streams to ZEGOCLOUD audio and video cloud.
        } else if (reason == 'LOGIN_FAILED') {
            // Login failed.
        } else if (reason == 'RECONNECTING') {
            // Reconnecting.
        } else if (reason == 'RECONNECTED') {
            // Reconnection successful.
        } else if (reason == 'RECONNECT_FAILED') {
            // Reconnection failed.
        } else if (reason == 'KICKOUT') {
            // Forced to log out of a room.
        } else if (reason == 'LOGOUT') {
            // Logout successful.
        } else if (reason == 'LOGOUT_FAILED') {
            // Logout failed.
        }
});

// Notification of users joining or leaving a room
// The `roomUserUpdate` callback can be received only when `ZegoRoomConfig` in which the `userUpdate` parameter is set to `true` is passed in the `loginRoom` method.
zg.on('roomUserUpdate', (roomID, updateType, userList) => {
    if (updateType == 'ADD') {
        for (var i = 0; i < userList.length; i++) {
            console.log(userList[i]['userID'], 'joins the room:', roomID)
        }
    } else if (updateType == 'DELETE') {
        for (var i = 0; i < userList.length; i++) {
            console.log(userList[i]['userID'], 'leaves the room:', roomID)
        }
    }
});

zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
    // Notification of audio or video stream updates of other users in a room
});

Check your browser's compatibility with WebRTC

Some browsers do not support WebRTC. Therefore, you need to check whether your browser can properly run WebRTC before implementing the stream publishing and playing features.

You can call the checkSystemRequirements method to check your browser's compatibility with WebRTC. For details about the check results, see the parameter description of the ZegoCapabilityDetection API.

const result = await zg.checkSystemRequirements();
// The `result` parameter that is returned indicates the compatibility check result. WebRTC is supported if the value of `webRTC` is `true`. For other attributes of this API, see the API reference.
console.log(result);
// {
//   webRTC: true,
//   customCapture: true,
//   camera: true,
//   microphone: true,
//   videoCodec: { H264: true, H265: false, VP8: true, VP9: true },
//   screenSharing: true,
//   errInfo: {}
// }

Alternatively, you can open the Online detection tool provided by ZEGOCLOUD in your browser to check its compatibility with WebRTC. For details about compatible browser versions, see Browser compatibility.

Log in to a room

Generate a Token

A Token used for identity authentication is required for room login. You can apply for a temporary Token, which is valid for 24 hours, in ZEGOCLOUD Admin Console.

The temporary Token is available only for debugging. Before bringing your app into commercial use, generate a Token from your service server. For details, see Use Tokens for authentication.

Log in to a room

Call the loginRoom method and set roomID, token, user, and config 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 roomID, userID, and userName are user-defined.
  • The values of roomID and userID must be unique. You are advised to associate userID with the account system of your service to make the value meaningful.
  • The roomUserUpdate callback can be received only when ZegoRoomConfig in which the userUpdate parameter is set to true is passed in the loginRoom method.
// Log in to a room. If the login succeeds, `true` is returned.
// The `roomUserUpdate` callback can be received only when `userUpdate` is set to `true`.

let userID = Util.getBrow() + '_' + new Date().getTime();
let userName = "user0001";
let roomID = "0001";
let token = ;
// To prevent yourself from missing any notification, listen for callback events such as user login or logout, room connection status updates, and stream publishing status updates before logging in to a room.
zg.on('roomStateChanged', async (roomID, reason, errorCode, extendedData) => {

})
zg.loginRoom(roomID, token, { userID, userName: userID }, { userUpdate: true }).then(result => {
     if (result == true) {
        console.log("login success")
     }
});

You can use the roomStateChanged callback to listen for the room connection status in real time. You can perform operations such as stream publishing and playing only after the room is successfully connected. If you fail to log in to a room, perform troubleshooting by referring to Error codes.

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

  1. Create a stream and start the local video preview.

Create a local audio and video stream, and call the createZegoStream method to obtain the media stream object. By default, images and sounds will be captured from the camera and microphone.

Through the playVideo and playAudio interfaces of localStream, create a local media stream playback component to play audio and video that is waiting to be published or has already been successfully published. Alternatively, you can assign the localStream.stream object to the srcObject attribute of the video element to play the object.

  1. Publish your audio and video stream to ZEGOCLOUD audio and video cloud only after the createZegoStream method returns the ZegoLocalStream object.

Call the startPublishingStream method and set the streamID and localStream parameter to publish your local audio and video stream to remote users, where localStream indicates the media stream object that is obtained during stream creation.

  • The value of streamID is generated locally and 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.
  • To implement cross-platform communication or the feature of publishing streams through CDN, set the video coding format to H.264. For more information, see Configure video codec.
// In the sample code, streams are published immediately after you successfully log in to a room. When implementing your service, you can choose to publish streams at any time when the room is connected status.

zg.loginRoom(roomID, token, { userID, userName: userID }, { userUpdate: true }).then(async result => {
     if (result == true) {
        console.log("login success")
        // Create a stream and start the preview.
           // After calling the `createZegoStream` method, you cannot perform subsequent operations until the ZEGOCLOUD server returns a streaming media object.
           const localStream = await zg.createZegoStream();

           // Preview the stream and mount the playback component to the page. "local-video" is the id of the <div> element that serves as the component container.
           localStream.playVideo(document.querySelector("#local-video"));

           // Start to publish an audio and video stream to the ZEGOCLOUD audio and video cloud.
           let streamID = new Date().getTime().toString();
           zg.startPublishingStream(streamID, localStream)
     }
});

Optional: Set audio and video capture parameters.

Set capture parameters based on method attributes

You can set audio and video capture parameters by using the following attributes of the createZegoStream method. For details, see Custom video capture.

  • camera:configurations for capturing streams from the camera and microphone

  • screen:configurations for capturing streams from the screen

  • custom:configurations for capturing third-party streams

Play streams

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

When another user joins a room, the SDK triggers the roomStreamUpdate callback to notify you of stream addition in the room. The callback will carry the streamID parameter of the user who joins the room. In this scenario, you can call the startPlayingStream method to play the audio and video stream that has been published to the ZEGOCLOUD server by the remote user based on the streamID parameter. To play streams from the CDN, see Live streaming through via CDN.

// Stream status update callback
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
    // When `updateType` is set to `ADD`, an audio and video stream is added, and you can call the `startPlayingStream` method to play the stream.
    if (updateType == 'ADD') {
        // When streams are added, play them.
        // 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. 
        const streamID = streamList[0].streamID;
        // The stream list specified by `streamList` contains the ID of the corresponding stream.
        const remoteStream = await zg.startPlayingStream(streamID);

        // Create a media stream player object to play remote media streams.
        const remoteView = zg.createRemoteStreamView(remoteStream);
        // Mount the player to a page. In the sample code, `remote-video` indicates the DOM element ID of the player.
        remoteView.play("remote-video");

    } else if (updateType == 'DELETE') {
        // When streams are deleted, stop playing them.
    }
});
  • Due to the autoplay policy, some browsers may be blocked from playing media streams by calling ZegoStreamView. By default, the SDK will display a pop-up window on the UI to ask whether to return the playing.
  • You can disable the pop-up window by setting the second parameter options.enableAutoplayDialog to false in the ZegoStreamView.play() method. In addition, you can design a resume button to be displayed on the UI when the autoplayFailed callback is triggered. Users can click this button to resume playing.

Now, you have implemented a basic real-time video call. You can open index.html in your browser to test out the real-time audio and video features.

Common features

Common callbacks

// Room connection status update callback
// After the `loginRoom` method is called, you can use the `roomStateChanged` callback to listen for the room connection status in real time.
zg.on('roomStateChanged', (roomID, reason, errorCode, extendData) => {
    if (reason == 'LOGINING') {
        // Logging in.
    } else if (reason == 'LOGINED') {
        // Login successful.
        // 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.
        // Publish streams to ZEGOCLOUD audio and video cloud
    } else if (reason == 'LOGIN_FAILED') {
        // Login failed.
    } else if (reason == 'RECONNECTING') {
        // Reconnecting.
    } else if (reason == 'RECONNECTED') {
        // Reconnection successful.
    } else if (reason == 'RECONNECT_FAILED') {
        // Reconnection failed.
    } else if (reason == 'KICKOUT') {
        // Forced to log out of a room.
    } else if (reason == 'LOGOUT') {
        // Logout successful.
    } else if (reason == 'LOGOUT_FAILED') {
        // Logout failed.
    }
});

// Notification of audio or video stream updates of other users in a room
// No notification will not be provided for streams published by yourself.
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
    if (updateType == 'ADD') {
        // A stream is added.
        for (var i = 0; i < streamList.length; i++) {
            console.log('Room',roomID,'has a stream added:', streamList[i]['streamID'])
        }
        const message = "Video stream ID of the user: " + streamID.toString();
    } else if (updateType == 'DELETE') {
        // A stream is deleted.
        for (var i = 0; i < streamList.length; i++) {
            console.log('Room',roomID,'has a stream deleted:', streamList[i]['streamID'])
        }
    }
});

// Notification of users joining or leaving a room
// The `roomUserUpdate` callback can be received only when `ZegoRoomConfig` in which the `userUpdate` parameter is set to `true` is passed in the `loginRoom` method.
zg.on('roomUserUpdate', (roomID, updateType, userList) => {
    if (updateType == 'ADD') {
        for (var i = 0; i < userList.length; i++) {
            console.log(userList[i]['userID'], 'joins the room:', roomID)
        }
    } else if (updateType == 'DELETE') {
        for (var i = 0; i < userList.length; i++) {
            console.log(userList[i]['userID'], 'leaves the room:', 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.
zg.on('publisherStateUpdate', result => {
    // Stream publishing status update callback
    var state = result['state']
    var streamID = result['streamID']
    var errorCode = result['errorCode']
    var extendedData = result['extendedData']
    if (state == 'PUBLISHING') {
        console.log('Successfully published an audio and video stream:', streamID);
    } else if (state == 'NO_PUBLISH') {
        console.log('No audio and video stream published');
    } else if (state == 'PUBLISH_REQUESTING') {
        console.log('Requesting to publish an audio and video stream:', streamID);
    }
    console.log('Error code:', errorCode,' Extra info:', extendedData)
})

// Quality callback for published streams
// After successfully publishing streams, you will regularly receive callbacks showing the quality data (such as resolution, frame rate, and bitrate) of audio and video streams.
zg.on('publishQualityUpdate', (streamID, stats) => {
    // Quality callback for published streams
    console.log('Stream quality callback')
})

// 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.
zg.on('playerStateUpdate', result => {
    // Stream playing status update callback
    var state = result['state']
    var streamID = result['streamID']
    var errorCode = result['errorCode']
    var extendedData = result['extendedData']
    if (state == 'PLAYING') {
        console.log('Successfully played an audio and video stream:', streamID);
    } else if (state == 'NO_PLAY') {
        console.log('No audio and video stream played');
    } else if (state == 'PLAY_REQUESTING') {
        console.log('Requesting to play an audio and video stream:', streamID);
    }
    console.log('Error code:', errorCode,' Extra info:', extendedData)
})

// Quality callback for audio or video stream playing
// After successfully playing streams, you will regularly receive the notification of quality data (such as resolution, frame rate, and bitrate) during audio or video stream playing.
zg.on('playQualityUpdate', (streamID,stats) => {
    // Quality callback for played streams
})

// Notification of receiving a broadcast message
zg.on('IMRecvBroadcastMessage', (roomID, chatData) => {
    console.log('Broadcast message defined by using IMRecvBroadcastMessage', roomID, chatData[0].message);
    alert(chatData[0].message)
});

// Notification of receiving a pop-up message
zg.on('IMRecvBarrageMessage', (roomID, chatData) => {
    console.log('Pop-up message defined by using IMRecvBroadcastMessage', roomID, chatData[0].message);
    alert(chatData[0].message)
});

// Notification of receiving a custom signaling message
zg.on('IMRecvCustomCommand', (roomID, fromUser, command) => {
    console.log('Custom message defined by using IMRecvCustomCommand', roomID, fromUser, command);
    alert(command)
});

Stop a video call

Stop publishing a stream and destroy a stream

Call the stopPublishingStream method to stop publishing local audio and video streams to remote users. Call the destroyStream method to destroy created stream data. After stream data is destroyed, you need to destroy the video to stop capturing video data.

// Stop publishing a stream based on the local `streamID`.
zg.stopPublishingStream(streamID)
// The `localStream` parameter indicates the `MediaStream` object obtained when the `createZegoStream` method is called.
zg.destroyStream(localStream)

Stop playing streams

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

// Stream status update callback
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
    if (updateType == 'ADD') {
        // When streams are added, play them.
    } else if (updateType == 'DELETE') {
        // When streams are deleted, stop playing them based on `streamID` of the streams in the stream deletion list specified by `streamList`.
        const streamID = streamList[0].streamID;
        zg.stopPlayingStream(streamID)
    }
});

Log out of a room

Call the logoutRoom method to log out of a room.

zg.logoutRoom(roomID)

Destroy the ZegoExpressEngine instance

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

zg.destroyEngine();
zg = null;

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