All Products
Search
Document Center

ApsaraVideo Live:Get started with ARTC

Last Updated:Oct 30, 2024

This topic describes how to use Alibaba Cloud resources to create your own application that is based on ApsaraVideo Real-time Communication (ARTC).

Procedure

Step

Description

Step 1: Create an application

Create an ARTC application in the ApsaraVideo Live console. Then, obtain the application ID and AppKey.

Note
  • The application name can contain Chinese and English characters.

  • By default, no fees are incurred when you create an application. You are charged based on your actual usage in the cloud.

Step 2: Integrate authentication code into the server

After you obtain the application ID and AppKey, use them and other parameters to generate authentication code. The code is provided by Alibaba Cloud based on your programming language. Then, integrate the code into the server.

Step 3: Integrate the SDK

After you complete the server-side configurations, use CocoaPods (for iOS) or Maven (for Android) to integrate the SDK.

  • iOS

    pod 'AliVCSDK_ARTC', 'x.x.x'

  • Android

    com.aliyun.aio:AliVCSDK_ARTC:x.x.x

  • Windows

    For information about how to download the Windows SDK, see SDK download.

  • Web

    For information about the Web SDK, see Get started with ARTC SDK for Web.

Step 1: Create an application

  1. Log on to the ApsaraVideo Live console.

  2. In the left-side navigation pane, choose Live + > ApsaraVideo Real-time Communication > Applications.

  3. Click Create Application.

  4. Enter a custom name in the Instance Name field, select Terms of Service, and then click Buy Now.

  5. After the application is created, refresh the Applications page to view the application.

    Note

    By default, no fees are incurred when you create an application. You are charged based on your actual usage in the cloud. For more information, see Billing of ARTC.

Step 2: Integrate authentication code into the server

  1. Integrate the authentication code provided by Alibaba Cloud into your server environment. For more information, see Token-based authentication.

  2. The server provides API operations to facilitate calls on the mobile client.

Step 3: Integrate the SDK

ARTC provides the interactive mode that is suitable for interactive entertainment scenarios and the communication mode that is suitable for one-to-one or one-to-many communication scenarios. By choosing the right mode, you can ensure a smooth user experience and use the network resources in an efficient manner. We recommend that you choose a mode based on your business requirements.

Mode

Stream ingest

Stream pulling

Description

Interactive mode

  • Role restrictions are imposed. Only users who are assigned the streamer role can perform stream ingest.

  • Users have the flexibility to switch roles throughout the process.

No role restrictions are imposed. All users have the permissions to perform stream pulling.

  • In interactive mode, the viewers are notified of when the streamer joins or leaves the channel and when the streamer starts to ingest the stream. This ensures that the viewers can keep abreast of the streamer's activities. On the contrary, the streamer is not notified of any events of the viewers, which allows the streamer to stream without interference.

  • In interactive mode, the streamer is responsible for providing live streaming content and initiating interaction with other streamers, while the viewers receive the content and usually do not participate in the interaction process. If business requirements are likely to change in the future, resulting in uncertainty about whether to support the interactive engagement of the viewers, we recommend that you use the interactive mode by default. This mode is highly flexible and can adapt to different interaction needs if you adjust the user roles.

Communication mode

No role restrictions are imposed. All users have the permissions to perform stream ingest.

No role restrictions are imposed. All users have the permissions to perform stream pulling.

  • In communication mode, all users can perceive the presence of one another.

  • Although this mode does not distinguish between user roles, all users are actually considered streamers. This simplifies operations and reduces API calls that are made to implement the required capabilities.

1. Project configuration

Android

We recommend that you use a Maven repository to integrate the required dependency libraries.

  1. Add the URL of the Maven repository to the project-level build.gradle file.

    allprojects {
        repositories {
            google()
            jcenter()
            // Add the URL of the Maven repository that is required by ARTC.
            maven {
                url "https://maven.aliyun.com/nexus/content/repositories/releases"
            }
        }
    }
  2. In the application-level build.gradle file, add the following line of code.

    // Add ARTC SDK as a dependency. 
    implementation 'com.aliyun.aio:AliVCSDK_ARTC:${latest version}'
  3. Add the following code to the app/src/main/AndroidManifest.xml file to obtain the required device permissions.

        <uses-permission android:name="android.permission.CAMERA" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <!-- Request legacy Bluetooth permissions on older devices. -->
        <uses-permission
            android:name="android.permission.BLUETOOTH"
            android:maxSdkVersion="30" />
        <uses-permission
            android:name="android.permission.BLUETOOTH_ADMIN"
            android:maxSdkVersion="30" />
    
        <!-- Needed only if your app communicates with already-paired Bluetooth devices. -->
        <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
        <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.WRITE_SETTINGS"
            tools:ignore="ProtectedPermissions" />
        <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    Note

    The following permissions are requested at runtime:

    • Manifest.permission.CAMERA

    • Manifest.permission.WRITE_EXTERNAL_STORAGE

    • Manifest.permission.RECORD_AUDIO

    • Manifest.permission.READ_EXTERNAL_STORAGE

    If the operating system is Android 12 or later (API level 31 or higher), the following permission is also requested at runtime:

    • Manifest.permission.BLUETOOTH_CONNECT

  4. (Optional) Add obfuscation rules.

    -keep class com.aliyun.allinone.** {
    *;
    }
    
    -keep class com.aliyun.rts.network.AliHttpTool {
    *;
    }
    
    -keep class com.aliyun.common.AlivcBase {
    *;
    }
    
    -keep class com.huawei.multimedia.alivc.** {
    *;
    }
    
    -keep class com.alivc.rtc.** {
    *;
    }
    
    -keep class com.alivc.component.** {
    *;
    }
    
    -keep class org.webrtc.** {
    *;
    }
  5. Verify that the configurations are complete.

iOS

We recommend that you use CocoaPods.

  1. Open Terminal and run the following command to install CocoaPods.

    Important

    Before you start using CocoaPods, make sure that a Ruby environment is set up on your Mac.

    sudo gem install cocoapods
  2. In Terminal, run the following command to create a Podfile in the project path:

    pod init
  3. Edit the Podfile to add ARTC SDK as a dependency.

    pod 'AliVCSDK_ARTC', '~> ${latest version}'
  4. In Terminal, run the following command to update the CocoaPods dependency library in your project. A project file that is suffixed with .xcworkspace is generated. Double-click the file to install the SDK.

    pod update
  5. Grant permissions.

    Important

    Make sure that permissions on your microphone and camera are granted.

    1. Add the following configurations for permissions on the microphone and camera to the Info.plist file: Privacy - Camera Usage Description and Privacy - Microphone Usage Description.

      image.png

    2. Enable audio recording in the background by selecting Audio, AirPlay, and Picture in Picture, as shown in the following figure.

      image.png

  6. Find the Enable Bitcode option and set the value to No to disable Bitcode.

    image.png

Windows

We recommend that you use Visual Studio 2015.

  1. Add the directory of the runtime library to the include path.imageimage

  2. Specify the path of the runtime library.image

HarmonyOS

  1. Prerequisites

    Before integrating the SDK, make sure that the following requirements are met:

    • Contact the Huawei sales team to obtain necessary permissions for DevEco Studio 5.0.3.900 Release or later.

    • Obtain HarmonyOS NEXT SDK that supports API 12 or later.

    • Obtain HarmonyOS NEXT 5.0.0.102 that supports API 12 or later. Enable Allow Debugging on the HarmonyOS device that supports audio and video services.

    • For information about how to set up on-device debugging, see the HarmonyOS documentation.

    • Connect to the Internet on the HarmonyOS device.

    • Register a HUAWEI ID and complete identity verification.

  2. Configure the project
    1. Manual integration

      Download the AliVCSDK_ARTC-6.11.0-Beta.har file. Add it to the libs directory in the project. Then, configure dependencies in the project. Sample code:

      "dependencies": {
          "@aliyun_video_cloud/alivcsdk_artc":"file:./libs/AliVCSDK_ARTC-6.11.0-beta.har",
        }

      image

    2. OHPM integration

      Configure dependencies in the project. Sample code:

      "dependencies": {
          "@aliyun_video_cloud/alivcsdk_artc":"6.11.0-beta",
      }

      Run the following command:

      ohpm install @aliyun_video_cloud/alivcsdk_artc

2. SDK integration

1. Initialize the ARTC engine and register callbacks

Important

When an exception occurs in the SDK, the SDK is designed to preferentially perform retries to restore the normal state. For exceptions that the SDK cannot handle, the SDK sends explicit callback notifications.

Exception

Callback

Solution

Remarks

Failed authentication

onJoinChannelResult (AliRtcErrJoinBadToken returned)

When this exception occurs, check whether the token is valid in the app.

If authentication fails when the user proactively calls a method, the system returns an error message that indicates authentication failure in the callback.

Authentication about to expire

onWillAuthInfoExpire

When this exception occurs, obtain the latest authentication information and then call refreshAuthInfo to refresh authentication.

The authentication exception occurs when the user proactively calls a method or when the program is running. The exception is returned in the callback corresponding to the method or an independent error callback.

Expired authentication

onAuthInfoExpired

When this exception occurs, the user needs to use the app to re-join the channel.

The authentication exception occurs when the user proactively calls a method or when the program is running. The exception is returned in the callback corresponding to the method or an independent error callback.

Network failure

onConnectionStatusChange (AliRtcConnectionStatusFailed returned)

When this exception occurs, the user needs to use the app to re-join the channel.

The SDK can automatically recover from network disconnection in a certain period of time. If the network is not recovered after the preset threshold time, a timeout is triggered and the SDK is interrupted. In this case, the user needs to check the network status of the app and join the channel again.

Being kicked out

onBye

  • If AliRtcOnByeUserReplaced is returned in the callback, check whether a user that has the same user ID exists.

  • If AliRtcOnByeBeKickedOut is returned in the callback, the user is kicked out of the channel and needs to join the channel again.

  • If AliRtcOnByeChannelTerminated is returned in the callback, the channel is destroyed and the user needs to join a new channel.

ARTC provides the capability that kicks users out of a channel.

Local device exception

onLocalDeviceException

When this exception occurs, check the app permissions and check whether the device hardware is normal.

ARTC supports the device detection and exception diagnosis capabilities. When a local device exception that the SDK cannot handle occurs, the SDK sends callback notifications. In this case, the SDK cannot be recovered. Make sure that the device is normal so that the app can run normally.

Android

private void createEngine() {
    mAliRtcEngine = AliRtcEngine.getInstance(getApplicationContext());
    mAliRtcEngine.setRtcEngineEventListener(new AliRtcEngineEventListener() {

        /* The notification about the SDK connection to the server. You must handle connection failures. */
        @Override
        public void onConnectionStatusChange(AliRtcEngine.AliRtcConnectionStatus aliRtcConnectionStatus, AliRtcEngine.AliRtcConnectionStatusChangeReason aliRtcConnectionStatusChangeReason) {
            super.onConnectionStatusChange(aliRtcConnectionStatus, aliRtcConnectionStatusChangeReason);
            if (aliRtcConnectionStatus == AliRtcEngine.AliRtcConnectionStatus.AliRtcConnectionStatusFailed) {
                /* TODO: Be sure to handle the exception. The SDK has tried various recovery policies but still cannot recover. */
            } else {
                /* TODO: Handle the exception as needed. Business code is added, usually for data statistics and UI changes. */
            }
        }

        /* The SDK attempts to fix the local device exception. */
        @Override
        public void OnLocalDeviceException(AliRtcEngine.AliRtcEngineLocalDeviceType aliRtcEngineLocalDeviceType, AliRtcEngine.AliRtcEngineLocalDeviceExceptionType aliRtcEngineLocalDeviceExceptionType, String s) {
            super.OnLocalDeviceException(aliRtcEngineLocalDeviceType, aliRtcEngineLocalDeviceExceptionType, s);
            /* TODO: Be sure to handle the exception. The SDK has tried various recovery policies but still cannot recover. */
        }

        @Override
        public void onJoinChannelResult(int result, String channel, String userId, int elapsed) {
            super.onJoinChannelResult(result, channel, userId, elapsed);
            /* TODO: Handle the exception as needed. Business code is added, usually for data statistics and UI changes. */
            Log.i(TAG, "onJoinChannelResult result=" + result + ",channel=" + channel + ",userId=" + userId + ",elapsed=" + elapsed);
        }

        @Override
        public void onLeaveChannelResult(int result, AliRtcEngine.AliRtcStats stats) {
            super.onLeaveChannelResult(result, stats);
            Log.i(TAG, "onLeaveChannelResult result=" + result);
        }
    });
    mAliRtcEngine.setRtcEngineNotify(new AliRtcEngineNotify() {

        /* The callback is returned when authentication is about to expire in 30 seconds. You must refresh authentication. */
        @Override
        public void onAuthInfoWillExpire() {
            super.onAuthInfoWillExpire();
            /* TODO: Be sure to handle the exception. Obtain the authentication information of the channel and users, and then call refreshAuthInfo. */
        }

        /* The kicking-out operation may be triggered. You must handle the exception. */
        @Override
        public void onBye(int code) {
            super.onBye(code);
            /* TODO: We recommend that you perform handling operations based on your actual scenario. */
        }

        @Override
        public void onRemoteUserOnLineNotify(String uid, int elapsed) {
            super.onRemoteUserOnLineNotify(uid, elapsed);
            Log.i(TAG, "onRemoteUserOnLineNotify uid=" + uid + ",elapsed=" + elapsed);
        }

        @Override
        public void onRemoteUserOffLineNotify(String uid, AliRtcEngine.AliRtcUserOfflineReason aliRtcUserOfflineReason) {
            super.onRemoteUserOffLineNotify(uid, aliRtcUserOfflineReason);
            Log.i(TAG, "onRemoteUserOnLineNotify uid=" + uid + ",aliRtcUserOfflineReason=" + aliRtcUserOfflineReason);
        }

        @Override
        public void onRemoteTrackAvailableNotify(String uid, AliRtcEngine.AliRtcAudioTrack aliRtcAudioTrack, AliRtcEngine.AliRtcVideoTrack aliRtcVideoTrack) {
            super.onRemoteTrackAvailableNotify(uid, aliRtcAudioTrack, aliRtcVideoTrack);
            Log.i(TAG, "onRemoteUserOnLineNotify uid=" + uid + ",aliRtcAudioTrack=" + aliRtcAudioTrack + ",aliRtcVideoTrack=" + aliRtcVideoTrack);
            mMainHandler.post(new Runnable() {
                @Override
                public void run() {
                    if (aliRtcVideoTrack == AliRtcEngine.AliRtcVideoTrack.AliRtcVideoTrackCamera
                            || aliRtcVideoTrack == AliRtcEngine.AliRtcVideoTrack.AliRtcVideoTrackBoth) {
                        AliRtcEngine.AliRtcVideoCanvas remote_canvas = new AliRtcEngine.AliRtcVideoCanvas();
                        SurfaceView remoteView = mAliRtcEngine.createRenderSurfaceView(mContext);
                        if (remoteView != null) {
                            remoteView.setZOrderOnTop(true);
                            remoteView.setZOrderMediaOverlay(true);
                        }
                        remote_canvas.view = remoteView;
                        mLocalSurfaceContainer.addView(remote_canvas.view, new FrameLayout.LayoutParams(
                                findViewById(R.id.local_surface_container).getWidth()/4,
                                findViewById(R.id.local_surface_container).getHeight()/4));
                        mAliRtcEngine.setRemoteViewConfig(remote_canvas,uid,AliRtcEngine.AliRtcVideoTrack.AliRtcVideoTrackCamera);
                    } else {
                        mAliRtcEngine.setRemoteViewConfig(null, uid, AliRtcEngine.AliRtcVideoTrack.AliRtcVideoTrackCamera);
                    }
                }
            });
        }
    });
}

iOS

- (AliRtcEngine *)engine{
    if (!_engine) {
        NSString *extras = @"";
        /* Construct the engine and pass in delegate. */
        _engine = [AliRtcEngine sharedInstance:self extras:extras];
    }
    return _engine;
}

#pragma mark - "Delegates of engine"
/* The callback is returned when authentication is about to expire in 30 seconds. You must refresh authentication. */
- (void)onAuthInfoWillExpire{
    /* TODO: Be sure to handle the exception. Obtain the authentication information of the channel and users, and then call refreshAuthInfo. */
}

/* The notification about the SDK connection to the server. You must handle connection failures. */
- (void)onConnectionStatusChange:(AliRtcConnectionStatus)status reason:(AliRtcConnectionStatusChangeReason)reason {
    if (status == AliRtcConnectionStatusFailed) {
        /* TODO: Be sure to handle the exception. The SDK has tried various recovery policies but still cannot recover. */
    } else {
        /* TODO: Handle the exception as needed. Business code is added, usually for data statistics and UI changes. */
    }
}

/* The SDK attempts to fix the local device exception. */
- (void)onLocalDeviceException:(AliRtcLocalDeviceType)deviceType exceptionType:(AliRtcLocalDeviceExceptionType)exceptionType message:(NSString *_Nullable)msg {
    /* TODO: Be sure to handle the exception. The SDK has tried various recovery policies but still cannot recover. */
}

/* The kicking-out operation may be triggered. You must handle the exception. */
/* The kicking-out operation may be triggered. You must handle the exception. */
- (void)onBye:(int)code {
    /* TODO: We recommend that you perform handling operations based on your actual scenario. */
}

/* The notification about remote stream ingest. If automatic subscription is enabled, you can configure the black screen time and time to first frame for adaption. */
- (void)onRemoteTrackAvailableNotify:(NSString *_Nonnull)uid audioTrack:(AliRtcAudioTrack)audioTrack videoTrack:(AliRtcVideoTrack)videoTrack {
    /* TODO: Be sure to handle the exception. Set a video rendering window for the SDK. */
    dispatch_async(dispatch_get_main_queue(), ^{
        if (videoTrack & AliRtcVideoTrackCamera) {
            AliVideoCanvas *canvas = [[AliVideoCanvas alloc] init];
            canvas.view = self.remoteRenderView;
            canvas.renderMode = AliRtcRenderModeAuto;
            [self.engine setRemoteViewConfig:canvas uid:uid forTrack:AliRtcVideoTrackCamera];
        } else {
            /* Clear the rendering window of the remote user. However, the remote user may directly leave the channel. */
            [self.engine setRemoteViewConfig:nil uid:uid forTrack:AliRtcVideoTrackCamera];
        }
    });
}

- (void)onRemoteUserOffLineNotify:(NSString *)uid offlineReason:(AliRtcUserOfflineReason)reason {
    dispatch_async(dispatch_get_main_queue(), ^{
        /* Clear the rendering window of the remote user. */
        [self.engine setRemoteViewConfig:nil uid:uid forTrack:AliRtcVideoTrackBoth];
    });
}

- (void)onJoinChannelResult:(int)result channel:(NSString *)channel userId:(NSString *)userId elapsed:(int)elapsed {
    /* TODO: Handle the exception as needed. Business code is added, usually for data statistics and UI changes. */
}

- (void)onLeaveChannelResult:(int)result stats:(AliRtcStats)stats {
    /* TODO: Handle the exception as needed. Business code is added, usually for data statistics and UI changes. */
}

Windows

class AliEngineEventListenerImpl : public AliEngineEventListener {
public:
    AliEngineEventListenerImpl(AliEngine* engine, HWND hWnd) {
        mAliRtcEngine = engine;
        mHWnd = hWnd;
    };
    virtual AliEngineEventListenerImpl() {};

    virtual void OnConnectionStatusChange(int status, int reason) override {
        if (status == AliEngineConnectionFailed) {
            /* TODO: Be sure to handle the exception. The SDK has tried various recovery policies but still cannot recover. */
        } else {
            /* TODO: Handle the exception as needed. Business code is added, usually for data statistics and UI changes. */
        }
    };

    virtual void OnLocalDeviceException(AliEngineLocalDeviceType deviceType, AliEngineLocalDeviceExceptionType exceptionType, const char* msg) override {
        /* TODO: Be sure to handle the exception. The SDK has tried various recovery policies but still cannot recover. */
    };

    virtual void OnJoinChannelResult(int result, const char *channel, const char *userId, int elapsed) override {
        /* TODO: Handle the exception as needed. Business code is added, usually for data statistics and UI changes. */
    };

    virtual void OnLeaveChannelResult(int result, AliEngineStats stats) override {
        
    };

    virtual void OnAuthInfoWillExpire() override {
        /* TODO: Be sure to handle the exception. Obtain the authentication information of the channel and users, and then call refreshAuthInfo. */
    };

    virtual void OnBye(int code) override {
        /* TODO: We recommend that you perform handling operations based on your actual scenario. */
    };

    virtual void OnRemoteUserOnLineNotify(const char *uid, int elapsed) override {
        
    };

    virtual void OnRemoteUserOffLineNotify(const char *uid, AliEngineUserOfflineReason reason) override {
        
    };

    virtual void OnRemoteTrackAvailableNotify(const char *uid,
                                                  AliEngineAudioTrack audioTrack,
                                                  AliEngineVideoTrack videoTrack) {
        AliEngineVideoCanvas remote_canvas;
        if (videoTrack == AliEngineVideoTrackCamera
                            || videoTrack == AliEngineVideoTrackBoth) {
            RECT rect;
            ::GetWindowRect(mHWnd, &rect);
            remote_canvas.displayView = remoteView;
            remote_canvas.renderMode = AliEngineRenderModeAuto;
            mAliRtcEngine->SetRemoteViewConfig(remote_canvas,uid,AliEngineVideoTrackCamera);
        } else {
            mAliRtcEngine->SetRemoteViewConfig(remote_canvas, uid, AliEngineVideoTrackCamera);
        }
    }

private:
    AliEngine* mAliRtcEngine = nullptr;
    /* The window handle. */
    HWND mHWnd;
};


private:
void createEngine() {
    mAliRtcEngine = AliRtcEngine.Create("");
    mLisenter = new AliEngineEventListenerImpl(mAliRtcEngine, mHWnd);
    mAliRtcEngine->SetEngineEventListener(mLisenter);
}

HarmonyOS

this.rtcSdk = AliRtcEngine.getInstance(NULL, getContext(this));
this.engineEventListener: AliRtcEngineEventListener = new AliRtcEngineEventListener();
this.engineEventListener
      .onRemoteUserOnline((uid: string, elapsed: boolean)=> {
        // Triggered when a remote user joins the channel
      })
      .onRemoteUserOffline((uid:string, reason: AliRtcUserOfflineReason)=> {
        // Triggered when a remote user leaves the channel
      })
      .onJoinChannel((result : number, channel : string, userId : string, elapsed : number)=> {
        // Triggered when you joins the channel
      })
      .onLeaveChannel((result : number, stat : AliRtcStats)=> {
        // Triggered when you leaves the channel
      })
      
      .onBye((code : AliRtcOnByeType)=> {
        // Triggered when you are kicked out of the server or the channel is closed
      })
      .onOccurError((error : number, msg : string)=> {
        // Triggered when an error occurs
      })
      
      .onConnectionStatusChange((status : number, reason : number)=> {
        // Triggered when the network connection status changes
      })
    ;

  this.rtcSdk?.setRtcEngineEventListener(this.engineEventListener);

2. Configure parameters before users join a channel

Important
  • By default, for a streamer in interactive mode, the SDK ingests local audio and video streams of the streamer and pulls audio and video streams of other streamers.

  • By default, for a viewer in interactive mode, the SDK does not ingest local audio and video streams of the viewer but pulls audio and video streams of streamers.

  • By default, the SDK performs automatic stream ingest and pulling. You can disable automatic stream ingest and pulling based on your business requirements.

Android

    private void initEngineBeforeJoin() {
        /* (Optional) Configure parameters before users join the channel. */
        mAliRtcEngine.setChannelProfile(AliRtcEngine.AliRTCSdkChannelProfile.AliRTCSdkInteractiveLive);
        mAliRtcEngine.setClientRole(AliRtcEngine.AliRTCSdkClientRole.AliRTCSdkInteractive);
        /* Set the audio properties. */
        mAliRtcEngine.setAudioProfile(AliRtcEngine.AliRtcAudioProfile.AliRtcEngineStereoHighQualityMode, AliRtcEngine.AliRtcAudioScenario.AliRtcSceneMusicMode);

        /* (Optional) Configure camera preview. If you do not configure camera preview, stream ingest is also performed. */
        AliRtcEngine.AliRtcVideoCanvas canvas = new AliRtcEngine.AliRtcVideoCanvas();
        canvas.view = mAliRtcEngine.createRenderSurfaceView(mContext);
        mLocalSurfaceContainer.removeAllViews();
        if (canvas.view != null) {
            mLocalSurfaceContainer.addView(canvas.view, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
        }
        mAliRtcEngine.setLocalViewConfig(canvas, AliRtcEngine.AliRtcVideoTrack.AliRtcVideoTrackCamera);
    }

iOS

- (void)initBeforeJoin {
    /* (Optional) Configure parameters before users join the channel. */
    [self.engine setChannelProfile:AliRtcInteractivelive];
    [self.engine setClientRole:AliRtcClientRoleInteractive];
    /* Set the audio properties. */
    [self.engine setAudioProfile:AliRtcEngineStereoHighQualityMode audio_scene:AliRtcSceneMusicMode];
    /* (Optional) Configure camera preview. If you do not configure camera preview, stream ingest is also performed. */
    AliVideoCanvas *canvas = [[AliVideoCanvas alloc] init];
    canvas.view = self.previewView;
    canvas.renderMode = AliRtcRenderModeAuto;
    [self.engine setLocalViewConfig:canvas forTrack:AliRtcVideoTrackCamera];
    return;
}

Windows

private:
void initEngineBeforeJoin() {
    /* (Optional) Configure parameters before users join the channel. */
    mAliRtcEngine->SetChannelProfile(AliEngineInteractiveLive);
    mAliRtcEngine->SetClientRole(AliEngineClientRoleInteractive);
    /* Set the audio properties. */
    mAliRtcEngine->SetAudioProfile(AliEngineBasicQualityMode, AliEngineSceneMusicMode);

    /* (Optional) Configure camera preview. If you do not configure camera preview, stream ingest is also performed. */
    AliEngineVideoCanvas canvas;
    /* The window handle. */
    canvas.view = mHWnd;
    mAliRtcEngine.setLocalViewConfig(canvas, AliEngineVideoTrackCamera);
}

HarmonyOS

initEngineBeforeJoin = (surfaceId: string) => {
 
  let encoderConfig : AliRtcVideoEncoderConfiguration = new AliRtcVideoEncoderConfiguration();
  encoderConfig.dimensions = new AliRtcVideoDimensions();
  encoderConfig.dimensions.width = 480
  encoderConfig.dimensions.height = 640
  encoderConfig.frameRate = AliRtcFrameRate.AliEngineFrameRateFps15
  this.rtcSdk?.setVideoEncoderConfiguration(encoderConfig)

  let profile : AliRtcChannelProfile = AliRtcChannelProfile.AliEngineInteractiveLive
  if (this.mainPageParams.interactive_mode == 0) {
    profile = AliRtcChannelProfile.AliEngineCommunication
  } else if (this.mainPageParams.interactive_mode == 2) {
    profile = AliRtcChannelProfile.AliEngineInteractiveWithLowLatencyLive
  }
  this.rtcSdk?.setChannelProfile(profile);
  this.rtcSdk?.setClientRole(this.mainPageParams.is_anchor ? AliRtcClientRole.AliEngineClientRoleInteractive : AliRtcClientRole.AliEngineClientRoleLive);


  this.localVideoCanvas.surfaceId = surfaceId;
  this.rtcSdk?.setLocalViewConfig(this.localVideoCanvas, this.componentController, AliRtcVideoTrack.AliEngineVideoTrackCamera);

}

3. Users joining the channel

Important
  • After users join the channel, stream ingest and pulling are performed based on the parameters that you configured.

  • By default, the SDK automatically ingests and pulls streams to reduce the number of required API calls.

Android

initEngineBeforeJoin();
mAliRtcEngine.joinChannel("Authentication information", null, null, "testUserName");

iOS

[self initBeforeJoin];
/* The channel ID and user ID are issued by the server. The app does not obtain the IDs. */
[self.engine joinChannel:@"Authentication information" channelId:nil userId:nil name:@"testUserName" onResultWithUserId:nil];

Windows

initEngineBeforeJoin();
mAliRtcEngine->joinChannel("Authentication information", null, null, "testUserName");

HarmonyOS

this.initEngineBeforeJoin();
this.rtcSdk?.joinChannel("Authentication information", null, null, "testUserName");

4. Role switching

Important
  • When a user switches from the streamer role to the viewer role (usually referred to as "get off the mic"), the system stops ingesting the local audio and video streams. The subscribed audio and video streams are not affected.

  • When a user switches from the viewer role to the streamer role (usually referred to as "get on the mic"), the system starts to ingest the local audio and video streams. The subscribed audio and video streams are not affected.

Android

/* TODO: Set the roles based on your business requirements. */
/* Set the streamer role. Users of this role participate in interaction. */
mAliRtcEngine.setClientRole(AliRtcEngine.AliRTCSdkClientRole.AliRTCSdkInteractive);
/* Set the viewer role. Users of this role can only watch the stream. */
mAliRtcEngine.setClientRole(AliRtcEngine.AliRTCSdkClientRole.AliRTCSdkLive);

iOS

/* TODO: Set the roles based on your business requirements. */
/* Set the streamer role. Users of this role participate in interaction. */
[self.engine setClientRole:AliRtcClientRoleInteractive];
/* Set the viewer role. Users of this role can only watch the stream. */
[self.engine setClientRole:AliRtcClientRolelive];

Windows

/* TODO: Set the roles based on your business requirements. */
/* Set the streamer role. Users of this role participate in interaction. */
mAliRtcEngine->SetClientRole(AliEngineClientRoleInteractive);
/* Set the viewer role. Users of this role can only watch the stream. */
mAliRtcEngine->SetClientRole(AliEngineClientRoleLive);

HarmonyOS

/* TODO: Set the roles based on your business requirements. */
/* Set the streamer role. Users of this role participate in interaction. */
this.rtcSdk?.setClientRole(AliRtcClientRole.AliEngineClientRoleInteractive);
/* Set the viewer role. Users of this role can only watch the stream. */
this.rtcSdk?.setClientRole(AliRtcClientRole.AliEngineClientRoleLive);

5. Users leaving the channel

Android

mAliRtcEngine.leaveChannel();

iOS

[self.engine leaveChannel];

Windows

mAliRtcEngine->LeaveChannel();

HarmonyOS

this.rtcSdk?.leaveChannel();

6. Destroy the engine

Android

mAliRtcEngine.destroy();
mAliRtcEngine = null;

iOS

[AliRtcEngine destroy];

Windows

mAliRtcEngine->Destroy();
mAliRtcEngine = nullptr;

HarmonyOS

AliRtcEngine.destroyInstance();
this.rtcSdk? = null;

Sample output

After the integration is complete based on the preceding code, the following output result is shown. You can adjust the code based on your business requirements.

Android

image.png

iOS

image.png

Windows

image

References

For more information about API calls, see Overview.