Documentation
Private_Migration Migration
Documentation
Demo APP
SDK Center
API Center
FAQ
Code Market
Console
Sign Up
Log In
中文站 English
  • Documentation
  • Migration
  • Migrating from Agora to ZEGOCLOUD

Migrating from Agora to ZEGOCLOUD

Last updated:2024-06-17 10:33

This doc will guide you on how to migrate from Agora to ZEGOCLOUD.

Before getting started, you will first gain a technical understanding of the key differences between Agora and ZEGOCLOUD. Afterwards, this doc will compare the code of the main features of the SDK, helping you to understand how to migrate and modify your code.

Understanding the differences in SDKs

Agora ZEGOCLOUD
Channel/Room
Agora uses the concept of Channel, and the joinChannel method is called to create and join a channel. Users who pass the same channel name will join the same channel,provided that the AppID is consistent.
ZEGOCLOUD uses the concept of Room, and the loginRoom API is called to log in to a room. Users who pass the same roomID will join the same room, provided that the AppID is consistent.
How to manage streams - using Role/Stream
Agora manages streams through user roles, and the SDK auto publishes or subscribes to streams based on the current role: the host sends streams in the channel and receives audio and video streams published by other hosts in the channel; the audience can only receive audio and video streams published by the host in the channel; you can call setClientRole to switch the user role from audience to host.
ZEGOCLOUD SDK does not distinguish roles, and you need to use startPublishingStream, stopPublishingStream, startPlayingStream, and stopPlayingStream to control the start and end of streaming.
Authentication: using Token & AppSign
When joining a channel via the app client, users need to be authenticated using a Token.  
Similarly, when joining a room, Token authentication is required. In addition, ZEGOCLOUD also supports authentication using the "AppSign" method, which is a fixed key corresponding to each AppID and is only recommended for use during the testing phase.

For a better understanding, you can check the key concepts of ZEGOCLOUD SDK.

Click me to see how to integrate the ZEGOCLOUD SDK to your project.
  1. If your Android Gradle Plugin is v7.1.0 or later: go to the root directory of your project, open the settings.gradle file, and add the following line to the dependencyResolutionManagement:

    ...
    dependencyResolutionManagement {
        repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
        repositories {
            maven { url 'https://maven.zego.im' }
            google()
            mavenCentral()
        }
    }

    If you can't find the above fields in settings.gradle, it's probably because your Android Gradle Plugin version is lower than v7.1.0.

    For more details, see Android Gradle Plugin Release Note v7.1.0.

    If your Android Gradle Plugin is earlier than 7.1.0: go to the root directory of your project, open the build.gradle file, and add the following line to the allprojects:

    ...
    allprojects {
        repositories {
            maven { url 'https://maven.zego.im' }
            google()
            mavenCentral()
        }
    }
  2. Go to the app directory, open the build.gradle file, and add the following line to the dependencies. (x.y.z is the SDK version number, to obtain the latest version number, see ZEGO Express-Video Android SDK Release History)

    ...
    dependencies {
        ...
        implementation 'im.zego:express-video:x.y.z'
    }
  3. Add device permissions

    Open the file app/src/main/AndroidManifest.xml, and add the following code:

    <!-- Permissions required by the SDK -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    
    <!-- Permissions required by the App -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />
    
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
  4. Prevent class name obfuscation

    To prevent the ZEGO SDK public class names from being obfuscated, you can add the following code in the file proguard-rules.pro.

    -keep class **.zego.**{*;}

Comparing the implementation

Create the SDK instance

Firstly, both SDKs require you to create an SDK instance, which is typically done when the app starts.

Agora

void createEngine() {
  RtcEngineConfig config = new RtcEngineConfig();
  config.mContext = getBaseContext();
  config.mAppId = appId;
  config.mEventHandler = mRtcEventHandler;
  mRtcEngine = RtcEngine.create(config);
}


private void destroyEngine() {
    RtcEngine.destroy();
}

ZEGOCLOUD

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.

void createEngine() {
    ZegoEngineProfile profile = new ZegoEngineProfile();

    // Get your AppID and AppSign from ZEGOCLOUD Console
    //[My Projects -> AppID] : https://console.zegocloud.com/project
    profile.appID = appID;
    profile.appSign = appSign;
    profile.scenario = ZegoScenario.DEFAULT; // General scenario.
    profile.application = getApplication();
    ZegoExpressEngine.createEngine(profile, null);
}


private void destroyEngine() {
    ZegoExpressEngine.destroyEngine(null);
}

Set up an event handler

To receive event notifications thrown by the SDK, both Agora and ZEGOCLOUD require setting an object as the event handler.

Agora

Common callback explanations:

  • onJoinChannelSuccess: Callback for a successful channel joined by the local user.
  • onUserJoined: Callback for a remote user (communication scenario) / host (live scenario) joining the current channel.
  • onUserOffline: Callback for a remote user (communication scenario) / host (live scenario) leaving the current channel, including the case where the remote host switches roles to become an audience (such as cohost going offstage).

Usually, remote rendering starts with onUserJoined and ends with onUserOffline.

void startListenEvent() {
    private final IRtcEngineEventHandler mRtcEventHandler = new IRtcEngineEventHandler() {
        @Override
        // Listen for the remote host joining the channel to get the uid of the host.
        public void onUserJoined(int uid, int elapsed) {
            showMessage("Remote user joined " + uid);
                if (!audienceRole.isChecked()) return;
                // Set the remote video view
                runOnUiThread(() -> setupRemoteVideo(uid));
        }

        @Override
        public void onJoinChannelSuccess(String channel, int uid, int elapsed) {
            isJoined = true;
            showMessage("Joined Channel " + channel);
        }

        @Override
        public void onUserOffline(int uid, int reason) {
            showMessage("Remote user offline " + uid + " " + reason);
            runOnUiThread(() -> remoteSurfaceView.setVisibility(View.GONE));
        }
    };
    mRtcEngine.addEventHandler(mRtcEventHandler);
}

void stopListenEvent() {
    mRtcEngine.removeHandler(mRtcEventHandler);
}

ZEGOCLOUD

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.

When using Agora, remote rendering usually starts in onUserJoined and ends in onUserOffline.

As there is no concept of "role" in ZEGOCLOUD, onRoomUserUpdate differs greatly from Agora's onUserJoined and onUserOffline. This means that both audience and host joining the room will trigger the onRoomUserUpdate callback.

Therefore, during migration, you need to modify the rendering timing to start or end remote rendering based on updateType received in onRoomStreamUpdate.

void startListenEvent() {
    ZegoExpressEngine.getEngine().setEventHandler(new IZegoEventHandler() {
        @Override
        // Callback for updates on the status of the streams in the room.
        public void onRoomStreamUpdate(String roomID, ZegoUpdateType updateType, ArrayList<ZegoStream> streamList, JSONObject extendedData) {
            super.onRoomStreamUpdate(roomID, updateType, streamList, extendedData);
            // When `updateType` is set to `ZegoUpdateType.ADD`, an audio and video
            // stream is added, and you can call the `startPlayingStream` method to
            // play the stream.
            if (updateType == ZegoUpdateType.ADD) {
                startPlayStream(streamList.get(0).streamID);
            } else {
                stopPlayStream(streamList.get(0).streamID);
            }
        }

        @Override
        // 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).
        public void onRoomUserUpdate(String roomID, ZegoUpdateType updateType, ArrayList<ZegoUser> userList) {
            super.onRoomUserUpdate(roomID, updateType, userList);
            // You can implement service logic in the callback based on the login
            // and logout status of users.
            if (updateType == ZegoUpdateType.ADD) {
                for (ZegoUser user : userList) {
                    String text = user.userID + "logged in to the room.";
                    Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG).show();
                }
            } else if (updateType == ZegoUpdateType.DELETE) {
                for (ZegoUser user : userList) {
                    String text = user.userID + "logged out of the room.";
                    Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG).show();
                }
            }
        }

        @Override
        // Callback for updates on the current user's room connection status.
        public void onRoomStateChanged(String roomID, ZegoRoomStateChangedReason reason, int i, JSONObject jsonObject) {
            super.onRoomStateChanged(roomID, reason, i, jsonObject);
            if (reason == ZegoRoomStateChangedReason.LOGIN_FAILED) {
                Toast.makeText(getApplicationContext(), "ZegoRoomStateChangedReason.LOGIN_FAILED", Toast.LENGTH_LONG).show();
            }
        }

        // Status notification of audio and video stream publishing.
        @Override
        public void onPublisherStateUpdate(String streamID, ZegoPublisherState state, int errorCode, JSONObject extendedData) {
            super.onPublisherStateUpdate(streamID, state, errorCode, extendedData);
            if (errorCode != 0) {
                // Stream publishing exception.
            }
            if (state == ZegoPublisherState.PUBLISHING) {
                // Publishing streams.
            } else if (state == ZegoPublisherState.NO_PUBLISH) {
                // Streams not published.
                Toast.makeText(getApplicationContext(), "ZegoPublisherState.NO_PUBLISH", Toast.LENGTH_LONG).show();
            } else if (state == ZegoPublisherState.PUBLISH_REQUESTING) {
                // Requesting stream publishing.
            }
        }

        // Status notifications of audio and video stream playing.
        @Override
        public void onPlayerStateUpdate(String streamID, ZegoPlayerState state, int errorCode, JSONObject extendedData) {
            super.onPlayerStateUpdate(streamID, state, errorCode, extendedData);
            if (errorCode != 0) {
                // Stream playing exception.
                Toast.makeText(getApplicationContext(), "onPlayerStateUpdate, state:" + state + "errorCode:" + errorCode, Toast.LENGTH_LONG).show();
            }
            if (state == ZegoPlayerState.PLAYING) {
                // Playing streams.
            } else if (state == ZegoPlayerState.NO_PLAY) {
                // Streams not played.
                Toast.makeText(getApplicationContext(), "ZegoPlayerState.NO_PLAY", Toast.LENGTH_LONG).show();
            } else if (state == ZegoPlayerState.PLAY_REQUESTING) {
                // Requesting stream playing.
            }
        }
    });
}

void stopListenEvent() {
    ZegoExpressEngine.getEngine().setEventHandler(null);
}

Log in & log out room

Agora

public void joinChannel(View view) {
    if (checkSelfPermission()) {
        ChannelMediaOptions options = new ChannelMediaOptions();
        // For Live Streaming, set the channel profile as LIVE_BROADCASTING.
        options.channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING;
        // Set the client role as BROADCASTER or AUDIENCE according to the scenario.
        if (audienceRole.isChecked()) { //Audience
          options.clientRoleType = Constants.CLIENT_ROLE_AUDIENCE;
        } else { //Host
            options.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
            // Display LocalSurfaceView.
            setupLocalVideo();
            localSurfaceView.setVisibility(View.VISIBLE);
            // Start local preview.
            mRtcEngine.startPreview();
        }
        audienceRole.setEnabled(false); // Disable the switch
        // Join the channel with a temp token.
        // You need to specify the user ID yourself, and ensure that it is unique in the channel.
        mRtcEngine.joinChannel(token, channelName, uid, options);
    } else {
        Toast.makeText(getApplicationContext(), "Permissions was not granted", Toast.LENGTH_SHORT).show();
    }
}

public void leaveChannel() {
    mRtcEngine.leaveChannel()
}

ZEGOCLOUD

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

To log out, you can call the logoutRoom method.

Token authentication and AppSign authentication are mutually exclusive. Do not use them together:

  • If appSign is used when creating the engine, there is no need to pass a token when calling loginRoom.
  • Otherwise, if appSign is not used when creating the engine, a token is required for authentication when logging into the room: when calling loginRoom method, the token needs to be set in the token parameter of ZegoRoomConfig.

For details, see Use Tokens for authentication.

ZegoRoomConfig roomConfig = new ZegoRoomConfig();
roomConfig.token = "....";
ZegoExpressEngine.getEngine().loginRoom(roomID, user, roomConfig, ...)
void loginRoom() {
    ZegoUser user = new ZegoUser(userID, userName);
    ZegoRoomConfig roomConfig = new ZegoRoomConfig();
    // The `onRoomUserUpdate` callback can be received only when
    // `ZegoRoomConfig` in which the `isUserStatusNotify` parameter is set to
    // `true` is passed.
    roomConfig.isUserStatusNotify = true;
    ZegoExpressEngine.getEngine().loginRoom(roomID, user, roomConfig, (int error, JSONObject extendedData) -> {
        // Room login result. This callback is sufficient if you only need to
        // check the login result.
        if (error == 0) {
            // Login successful.
            // Start the preview and stream publishing.
            Toast.makeText(this, "Login successful.", Toast.LENGTH_LONG).show();
            startPreview();
            startPublish();
        } else {
            // Login failed. For details, see [Error codes\|_blank](/404).
            Toast.makeText(this, "Login failed. error = " + error, Toast.LENGTH_LONG).show();
        }
    });
}

void logoutRoom() {
    ZegoExpressEngine.getEngine().logoutRoom();
}

Start & stop the local video preview

Agora

private void setupLocalVideo() {
    FrameLayout container = findViewById(R.id.local_video_view_container);
    // Create a SurfaceView object and add it as a child to the FrameLayout.
    localSurfaceView = new SurfaceView(getBaseContext());
    container.addView(localSurfaceView);
    // Call setupLocalVideo with a VideoCanvas having uid set to 0.
    mRtcEngine.setupLocalVideo(new VideoCanvas(localSurfaceView, VideoCanvas.RENDER_MODE_HIDDEN, 0));
    // Display LocalSurfaceView.
    localSurfaceView.setVisibility(View.VISIBLE);
    // Start local preview.
    mRtcEngine.startPreview();
}

private void setupLocalVideo() {
   mRtcEngine.stopPreview();
}

ZEGOCLOUD

Similar to Agora's video rendering method, on the Android platform, you can use SurfaceView or TextureView to render the video.

We recommended using TextureView for better performance.

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

And you call the stopPreview method to stop the rendering.

void startPreview(){
    ZegoCanvas previewCanvas = new ZegoCanvas(findViewById(R.id.preview));
    ZegoExpressEngine.getEngine().startPreview(previewCanvas);
}

void stopPreview(){
    ZegoExpressEngine.getEngine().stopPreview();
}

Publishing and playing streams

There is a significant difference between the two:

  • Agora manages streams based on user roles, which are divided into "host" and "audience". Hosts can publish their own audio and video streams and receive audio and video streams published by other hosts in the channel. Audiences can only receive audio and video streams published by the hosts. You can call setClientRole to switch the user role from the audience to the host.
  • ZEGOCLOUD does not differentiate between roles. You can freely control the start and end of stream publishing and playing by calling startPublishingStream, stopPublishingStream, startPlayingStream, and stopPlayingStream.

During the migration process, note that "code logic related to user roles" also needs to be migrated, meaning that instead of "managing roles through Agora SDK", it should be changed to "managing roles through your app's code".

Agora

ChannelMediaOptions options;
options.channelProfile = CHANNEL_PROFILE_LIVE_BROADCASTING;
options.clientRoleType = CLIENT_ROLE_BROADCASTER;
options.autoSubscribeAudio = true;
options.autoSubscribeVideo = true;
options.publishCameraTrack = true;
mRtcEngine.joinChannel(APP_TOKEN, szChannelId, 0, options);

ZEGOCLOUD

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.

void startPublish() {
    // After calling the `loginRoom` method, call this method to publish streams.
    // The StreamID must be unique in the room.
    ZegoCanvas previewCanvas = new ZegoCanvas(findViewById(R.id.preview));
    ZegoExpressEngine.getEngine().startPreview(previewCanvas);
    String streamID = roomID + "_" + userID + "_call";
    ZegoExpressEngine.getEngine().startPublishingStream(streamID);
}


void stopPublish() {
    ZegoExpressEngine.getEngine().stopPublishingStream();
}
Start & stop playing streams

To start playing a remote video stream, call the startPlayingStream method.

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

When a new stream is added in the Room where the user is located, the ZegoEventHandler will receive the onRoomStreamUpdate event notification. You can obtain detailed information about the stream, such as userID and streamID, from this callback.

void startPlayStream(String streamID){
    findViewById(R.id.remoteUserView).setVisibility(View.VISIBLE);
    ZegoCanvas playCanvas = new ZegoCanvas(findViewById(R.id.remoteUserView));
    ZegoExpressEngine.getEngine().startPlayingStream(streamID, playCanvas);
}

void stopPlayStream(String streamID){
    ZegoExpressEngine.getEngine().stopPlayingStream(streamID);
    findViewById(R.id.remoteUserView).setVisibility(View.GONE);
}

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.

Demos

We recommend that you first review the Quick Start Basic Demo to gain a deeper understanding of the content of this doc and to learn the basic usage of the ZEGOCLOUD SDK. Then, based on your specific use case, you can select the Best Practices Demo for reference and begin the migration process.

  • Quick Start Basic Demo: Video Call, Live Streaming.

  • Best Practices Demo: Call Invitation, Co-Hosting.

Next steps

Implement Token authentication of ZEGOLCOUD
  • For details, see Use Tokens for authentication.
Migration Plan

SDK migration requires different migration plans to be selected based on the scenario and market conditions. Below will introduce three common migration plans.

  1. Call Negotiation - Suitable for 1v1 call scenario

/Pics/zegocloud/common/migration_call.jpg

As shown in the figure, there are four situations in call negotiation. Only when both parties use the new version application, the ZEGOCLOUD SDK is used for communication.

1.1 Logic introduction

Add an application version field in the call invitation and reply to the call invitation of the new version. The two parties determine whether to use the ZEGOCLOUD SDK for communication based on the version number during the negotiation process.

  • If both parties use the new version application, use the ZEGOCLOUD SDK for communication.
  • If one party uses the old version application, use the Agora SDK for communication.

The reason for adding the version number field here is for function extension and easy control of the use of new version functions.

  1. Not Available for Older Versions - Suitable for live streaming scenario

Not Available for Older Versions means that if a user uses an older version application, they can not join live streaming started with the new version. There are two ways to make older version users not available:

  • Intercept when joining the live streaming. Determine whether the user can join the live streaming room through the business server. If the user can not join, return an error and remind the user to upgrade the application with a pop-up window.
  • Intercept when getting the list of live-streaming rooms. Control the live streaming room list that the user pulls based on their application version. Older versions can only pull older version live streaming rooms, while new versions can pull all versions of live-streaming rooms.

The advantages and disadvantages of the two solutions are as follows:

Plan Advantages Disadvantages
Intercept when joining the live streaming Can guide customers to update the version Requires support for business server interception of old-version applications
Intercept when getting the list of live-streaming rooms No need for a pre-embedded entrance, the business server directly controls The number of live streaming rooms visible to old-version users will decrease, which may cause user churn

2.1. Logic introduction

The not available for older versions plan is divided into three stages:

  • SDK pre-embedding stage.
  • Dual-version SDK coexistence stage.
  • Forced update stage.

2.1.1. SDK pre-embedding stage

During the SDK pre-embedding stage, ZEGOCLOUD SDK needs to be integrated into the application but is temporarily not enabled. When the proportion of new version users reaches more than 50%, the new version users can use the ZEGOCLOUD SDK to start live streaming through business server control. At the beginning stage, the application configuration defaults to using the Agora SDK.

2.1.2. Dual-version SDK coexistence stage

When the proportion of new version users reaches more than 50%, the business server modifies the application configuration to allow new versions of the application to use the ZEGOCLOUD SDK to start live streaming. At this time, interception needs to be enabled, and old versions of the application can not join new version live streaming rooms.

2.1.3. Forced update stage

When the proportion of new version applications reaches more than 90%, forced updates can be launched. Forced updates can reduce the maintenance cost of the R&D team and facilitate the operation team to carry out activity operations.

  1. Forced Update - Suitable for small user base versions

Forced updates are suitable for use when the number of users is small. Generally, when the version retention rate is 10%, a forced update can be initiated. This can ensure that the user experience is improved and the maintenance cost for the development team.

If you have any suggestions or comments, feel free to share them with us via Discord. We value your feedback.

Page Directory
  • Free trial
  • 提交工单
    咨询集成、功能及报价等问题
    电话咨询
    400 1006 604
    Get Consulting
    Scan Wechat QR code