Build a voice chat room on Android using the ApsaraVideo Live ARTC SDK. This guide covers channel creation, role-based access, audio controls, and background music.
Prerequisites
Before you begin, make sure you have:
An ARTC (ApsaraVideo Real-time Communication) application
The base SDK integrated on your Android client. For setup instructions, see Implement audio/video communications on Android
How it works
A voice chat room uses the ARTC SDK in audio-only mode with role-based access:
Streamer (interactive role): Creates the channel, publishes audio, and receives audio from all participants.
Viewer (live role): Joins an existing channel and receives audio. Can be promoted to co-streamer through role switching.
Implementation flow:
Configure the channel profile and client role.
Set the audio profile for high-quality music.
Build and encode the authentication token.
Join the channel.

Create a channel as a streamer
Initialize the SDK in interactive live mode, set the interactive role, and join the channel. The SDK subscribes to all remote audio streams automatically.
// Set channel profile to interactive live streaming
mAliRtcEngine.setChannelProfile(AliRTCSdkInteractiveLive);
// Set the role to interactive (streamer can publish and receive audio)
mAliRtcEngine.setClientRole(AliRTCSdkInteractive);
// Use high-quality music mode for voice chat scenarios
mAliRtcEngine.setAudioProfile(AliRtcEngineHighQualityMode, AliRtcSceneMusicMode);
// Set the listener for callbacks
mAliRtcEngine.setRtcEngineEventListener(this);
// Auto-publish local audio
mAliRtcEngine.publishLocalAudioStream(true);
// Auto-subscribe to all remote audio streams
mAliRtcEngine.setDefaultSubscribeAllRemoteAudioStreams(true);
mAliRtcEngine.subscribeAllRemoteAudioStreams(true);
// Enable audio-only mode (no video)
mAliRtcEngine.setAudioOnlyMode(true);
// Build the authentication token
JSONObject tokenv2 = new JSONObject();
tokenv2.put("appid", userInfo.appId);
tokenv2.put("channelid", userInfo.channelId);
tokenv2.put("userid", userInfo.userId);
tokenv2.put("nonce", userInfo.nonce);
tokenv2.put("timestamp", userInfo.timestamp);
tokenv2.put("gslb",userInfo.gslb);
tokenv2.put("token", userInfo.token);
String base64TokenV2 = Base64.encodeToString(JSON.toJSONBytes(tokenv2),Base64.NO_WRAP);
// Join the channel with the Base64-encoded token
mAliRtcEngine.joinChannel(base64TokenV2, null, null, mUsername);Join a channel as a viewer
The viewer uses the same initialization flow as the streamer, except the client role is set to AliRTCSdkLive instead of AliRTCSdkInteractive. This designates the user as an ordinary viewer.
To join as a co-streamer, set the role to AliRTCSdkInteractive.
mAliRtcEngine.setChannelProfile(AliRTCSdkInteractiveLive);
// Set the role to live (ordinary viewer)
mAliRtcEngine.setClientRole(AliRTCSdkLive);
// Use high-quality music mode for voice chat scenarios
mAliRtcEngine.setAudioProfile(AliRtcEngineHighQualityMode, AliRtcSceneMusicMode);
// Set the listener for callbacks
mAliRtcEngine.setRtcEngineEventListener(this);
// Auto-publish local audio
mAliRtcEngine.publishLocalAudioStream(true);
// Auto-subscribe to all remote audio streams
mAliRtcEngine.setDefaultSubscribeAllRemoteAudioStreams(true);
mAliRtcEngine.subscribeAllRemoteAudioStreams(true);
// Enable audio-only mode (no video)
mAliRtcEngine.setAudioOnlyMode(true);
// Build the authentication token
JSONObject tokenv2 = new JSONObject();
tokenv2.put("appid", userInfo.appId);
tokenv2.put("channelid", userInfo.channelId);
tokenv2.put("userid", userInfo.userId);
tokenv2.put("nonce", userInfo.nonce);
tokenv2.put("timestamp", userInfo.timestamp);
tokenv2.put("gslb",userInfo.gslb);
tokenv2.put("token", userInfo.token);
String base64TokenV2 = Base64.encodeToString(JSON.toJSONBytes(tokenv2),Base64.NO_WRAP);
// Join the channel with the Base64-encoded token
mAliRtcEngine.joinChannel(base64TokenV2, null, null, mUsername);Switch the viewer role
After a viewer joins the channel, switch the role dynamically:
// Switch the role to streamer for a user who has joined the channel
mAliRtcEngine.setClientRole(AliRTCSdkInteractive);Control volume, voice effects, and reverberation
Adjust volume
// Adjust the local recording volume
mAliRtcEngine.setRecordingVolume(volumeLevel);
// Adjust the volume of a specific remote user
mAliRtcEngine.setRemoteAudioVolume(uid, volume);
// Adjust the playback volume of all sounds
mAliRtcEngine.setPlayoutVolume(volume);Apply a voice changer
// Apply the "old man" voice changer effect
mAliRtcEngine.setAudioEffectVoiceChangerMode(AliRtcSdk_AudioEffect_Voice_Changer_Oldman);Apply reverberation
// Configure reverberation by setting room size
mAliRtcEngine.setAudioEffectReverbParamType(AliRtcEngine.AliRtcAudioEffectReverbParamType.AliRtcSdk_AudioEffect_Reverb_Room_Size, value);Play background music
Two methods are available: raw PCM data input and file-based input.
PCM data input
Create a music input stream, then push raw PCM frames.
Create the external audio stream:
AliRtcEngine.AliRtcExternalAudioStreamConfig config = new AliRtcEngine.AliRtcExternalAudioStreamConfig();
config.sampleRate = sampleRate;
config.channels = channels;
// Local playback volume of the accompaniment (used when the ARTC SDK handles playback)
config.playoutVolume = 60;
// Volume published to remote participants
config.publishVolume = 100;
int externalAudioStreamId = aliRtcEngine.addExternalAudioStream(config);AliRtcExternalAudioStreamConfig parameters:
| Parameter | Description |
|---|---|
sampleRate | Audio sample rate |
channels | Number of audio channels |
playoutVolume | Local playback volume of the accompaniment |
publishVolume | Volume published to remote participants |
Push PCM data:
// Build an audio frame with raw PCM data
AliRtcEngine.AliRtcAudioFrame sample = new AliRtcEngine.AliRtcAudioFrame();
sample.data = buffer;
sample.numSamples = numSamples;
sample.numChannels = channels;
sample.sampleRate = sampleRate;
sample.bytesPerSample = bytesPerSample;
// Push the PCM data to the external audio stream
int ret = aliRtcEngine.pushExternalAudioStreamRawData(externalAudioStreamId, sample);AliRtcAudioFrame fields:
| Field | Description |
|---|---|
data | Raw PCM audio buffer |
numSamples | Number of audio samples |
numChannels | Number of audio channels |
sampleRate | Audio sample rate |
bytesPerSample | Bytes per audio sample |
File-based input
Start accompaniment from a local audio file:
AliRtcEngine.AliRtcAudioAccompanyConfig config = new AliRtcEngine.AliRtcAudioAccompanyConfig();
config.onlyLocalPlay = localPlay; // Play locally only, without publishing
config.replaceMic = replaceMic; // Replace microphone input with the file
config.loopCycles = loopCycles; // Number of playback loops
config.startPosMs = startPosMs; // Start position in milliseconds
config.publishVolume = pubVolume; // Volume published to remote participants
config.playoutVolume = playVolume; // Local playback volume
return mAliRtcEngine.startAudioAccompany(audioFileName, config);AliRtcAudioAccompanyConfig parameters:
| Parameter | Description |
|---|---|
onlyLocalPlay | Play locally only, without publishing to remote participants |
replaceMic | Replace microphone input with the audio file |
loopCycles | Number of playback loops |
startPosMs | Start position in milliseconds |
publishVolume | Volume published to remote participants |
playoutVolume | Local playback volume |