Implement a voice chat room on HarmonyOS

Updated at:

This document describes how to integrate the Alibaba Real-Time Communication (ARTC) software development kit (SDK) into your HarmonyOS project. Using the ARTC SDK, you can quickly build a simple audio-only interactive application for scenarios such as voice calls and voice chat rooms.

Function introduction

Before you begin, understand the following basic concepts of real-time audio and video interaction:

  • ARTC SDK: The software development kit for ApsaraVideo Real-time Communication. It is an Alibaba Cloud product that helps developers quickly implement real-time audio and video interactions.

  • Channel: A concept similar to a room. Users in the same channel can interact in real time.

  • Streamer: A user who can publish audio and video streams in a channel and subscribe to streams published by other streamers.

  • Viewer: A user who can subscribe to audio and video streams in a channel but cannot publish them.

The following figure shows the basic flow for implementing a voice call or a voice chat room:

image
  1. Users must call joinChannel to join a channel before they can ingest or pull streams:

    • Audio-only call scenario: All users are streamers and can ingest and pull streams.

    • Voice chat room scenario: Users who need to ingest streams in the channel must have the streamer role. If a user only needs to pull streams, you can set their role to viewer.

    • You can use setClientRole to set different roles for users.

  2. After joining a channel, the stream ingest and pulling behaviors vary based on the user's role:

    • All users in a channel can receive audio and video streams from other users in the same channel.

    • Streamers can ingest audio and video streams into the channel.

    • If a viewer needs to ingest a stream, they must call the setClientRole method to switch their role to streamer before they can ingest the stream.

Prerequisites

Before you run the sample project, make sure your development environment meets the following requirements:

  • Development tool: DevEco Studio 5.0.3.900 Release or later. Obtain the HarmonyOS NEXT SDK for API Version 12 or later.

  • Test device: A HarmonyOS device that supports audio and video, running HarmonyOS NEXT 5.0.0.102 (for API Version 12) or later. The "Allow debugging" option must be enabled.

  • Network: A stable network connection is required.

  • Application: An AppID and AppKey for your ApsaraVideo Real-time Communication application. For more information, see Create an application.

Sample project

The Alibaba Cloud ARTC SDK provides an open source sample project for your reference. You can download the project or view the sample source code.

Implementation steps

The following section uses a voice chat room scenario as an example. The process is as follows:

image

The main features of a voice chat room scenario are as follows:

  • Audio-only: The channel contains only audio, not video.

  • Streamer and viewer roles: The roles in the channel are divided into streamer and viewer. Streamers can ingest and pull audio streams. Viewers can only pull audio streams that are ingested by streamers. Viewers can switch their role to streamer.

Implement audio-only interaction

1. Handle permission requests

Before you start the audio interaction, ensure that you have requested audio and network permissions.

2. Get an authentication token

When you call joinChannel to join an ARTC channel, you must pass an authentication token to authenticate the user's identity. For more information about how to generate tokens, see Token-based authentication.

Production phase:

Generating a token requires an AppKey. To avoid security risks associated with hardcoding the AppKey on the client, we strongly recommend that you generate tokens on your business server and send them to the client for your online service.

Development and testing phase:

During development and testing, if your business server is not yet configured to generate tokens, you can temporarily use the token generation logic in the sample project to create a temporary token.

3. Create and initialize the engine

  • Create the RTC engine

    Call getInstance to create an RTC engine object.

    private rtcEngine: AliRtcEngine | null | undefined;
    
    this.rtcEngine = AliRtcEngine.getInstance('', this.context);
  • Initialize the engine

    • Call the setChannelProfile method to set the channel to interactive mode.

    • Based on the user's role in the scenario, call the setClientRole method to set the user as a streamer or viewer.

    • Call the setAudioProfile method to set the audio quality and scenario mode.

// Set the channel profile to interactive streaming mode.
this.rtcEngine.setChannelProfile(AliRtcChannelProfile.AliRtcInteractiveLive);

// Set the user role.
if (this.isAnchor) {
  // Streamer role: needs to publish streams.
  this.rtcEngine.setClientRole(AliRtcClientRole.AliRtcClientRoleInteractive);
} else {
  // Viewer role: only pulls streams.
  this.rtcEngine.setClientRole(AliRtcClientRole.AliRtcClientRoleLive);
}

// Set the audio profile (high-quality mode + music scenario).
this.rtcEngine.setAudioProfile(
  AliRtcAudioProfile.AliRtcHighQualityMode,
  AliRtcAudioScenario.AliRtcSceneMusicMode
);
  • Implement common callbacks

    If an exception occurs during runtime, the SDK first tries to recover automatically using its internal retry mechanism. For errors that the SDK cannot resolve on its own, it notifies your application through predefined callbacks.

    The following table describes key callbacks for events that the SDK cannot handle on its own. Your application layer must listen for and respond to these callbacks.

    Causes of the abnormal behavior

    Callback and parameter

    Solutions

    Description

    Authentication failed

    The result in the onJoinChannel callback returns AliRtcErrJoinBadToken.

    When this error occurs, your application must verify that the token is correct.

    If authentication fails when a user calls an API, the system returns an authentication failure error message in the API callback.

    Authentication token is about to expire

    onWillAuthInfoExpire

    When this exception occurs, the app must retrieve the latest authentication information and then call refreshAuthInfo.

    An authentication expiration error occurs in two scenarios: during an API call or program execution. Therefore, the error feedback is returned through an API callback or a separate error callback.

    Authentication token expired

    onAuthInfoExpired

    When this exception occurs, the app must rejoin the meeting.

    This event can occur when a user calls an API or during program execution. The feedback is sent through an API callback or a separate error callback.

    Network connectivity issue

    The onConnectionStatusChange callback returns AliRtcConnectionStatusFailed.

    When this status is returned, your application must rejoin the channel.

    The SDK can automatically recover from network disconnections for a certain period. However, if the disconnection time exceeds a preset threshold, the connection times out. In this case, your application should check the network status and guide the user to rejoin the channel.

    Kicked offline

    onBye

    • AliRtcOnByeUserReplaced: When this event occurs, check if the user userid is the same.

    • AliRtcOnByeBeKickedOut: This event indicates that the user was removed by the business service. The user must rejoin the channel.

    • AliRtcOnByeChannelTerminated: This event indicates that the channel was destroyed. The user must rejoin the channel.

    The RTC service allows an administrator to remove participants.

    Local device exception

    onLocalDeviceException

    When this exception occurs, the app should check whether the permissions and device hardware are functioning as expected.

    The RTC service supports device detection and exception diagnosis. When a local device exception occurs, the RTC service notifies the client through a callback. If the SDK cannot resolve the issue, your application must intervene and check whether the device is working correctly.

const listener = new AliRtcEngineEventListener()
  .onJoinChannel((resultCode: number, channel: string, elapsed: string) => {
    console.info(`Join channel result: result=${resultCode}, channel=${channel}, userId=${this.UserId}, elapsed=${elapsed}`);
    this.handleJoinResult(resultCode, channel);
  })
  .onLeaveChannel((resultCode: number) => {
    console.info(`Leave channel result: result=${resultCode}`);
  })
  .onConnectionStatusChange((status: number, reason: number) => {
    console.info(`Connection status changed: status=${status}, reason=${reason}`);

  })
this.rtcEngine.setRtcEngineEventListener(listener);

4. Set stream publishing and pulling properties

By default, the SDK automatically publishes and pulls audio and video streams within the channel.

  • After you set the role to viewer, you can only pull streams. The publishLocalAudioStream method is invalid for viewers.

  • The following configuration can be set for both streamers and viewers.

this.rtcEngine.publishLocalAudioStream(true);
// Publishing video is not needed in a voice chat scenario.
this.rtcEngine.publishLocalVideoStream(false);

// Set the default to subscribe to all remote audio streams.
this.rtcEngine.setDefaultSubscribeAllRemoteAudioStreams(true);
this.rtcEngine.subscribeAllRemoteAudioStreams(true);

5. Join a channel to start the audio-only interaction

Call joinChannel to join the channel. If the token was generated with a single-parameter rule, call the single-parameter AliRtcEngine method. If it was generated with a multi-parameter rule, call the multi-parameter AliRtcEngine method. After you call the method to join the channel, you can obtain the result from the onJoinChannelResult callback. If the result is 0, the user successfully joined the channel. Otherwise, check whether the provided token is invalid.

// Join the channel.
const result = this.rtcEngine.joinChannelWithToken(this.Token, '', '', 'Voice Chat User');
console.info('Join channel call result:', result);

6. End the audio-only interaction

When the audio interaction is over, you must leave the channel and destroy the engine. Follow these steps to end the audio interaction:

  1. Call leaveChannel to leave the channel.

  2. Call destroy to destroy the engine and release related resources.

this.rtcEngine.leaveChannel();
this.hasJoined = false;
AliRtcEngine.destroyInstance();

this.rtcEngine = null;

7. (Optional) Let a viewer become a streamer

In your scenario, if a user with the viewer role needs to publish a stream, you can call setClientRole to switch their role to streamer.

// Switch to the streamer role
this.rtcEngine.setClientRole(AliRtcClientRole.AliRtcClientRoleInteractive);

// Switch to the viewer role
this.rtcEngine.setClientRole(AliRtcClientRole.AliRtcClientRoleLive);

References