All Products
Search
Document Center

ApsaraVideo Live:Custom audio playback

Last Updated:Mar 26, 2026

Custom audio playback gives skilled developers full control over the audio playback process to meet specific requirements. ARTC provides this feature for such use cases.

Overview

By default, ARTC includes a field-tested audio playback module that meets most playback requirements. However, if you have an existing custom audio playback module or need to post-process audio data before playback, ARTC provides the custom audio playback feature. This lets you disable the internal playback logic and manage receiving and playing audio data.

You can then pass this data to your playback device for processing and playback.

Sample code

Android: Android/ARTCExample/AdvancedUsage/src/main/java/com/aliyun/artc/api/advancedusage/CustomAudioCaptureAndRender/CustomAudioRenderActivity.java.

iOS: iOS/ARTCExample/AdvancedUsage/CustomAudioRender/CustomAudioRenderVC.swift.

Prerequisites

Before using custom audio playback, ensure you meet the following requirements:

  • You can develop a complete audio playback module or already have an established third-party or in-house audio player.

  • You understand the basic audio processing workflow, including concepts like PCM data format, sample rate, and number of channels.

  • You have integrated the ARTC SDK and implemented basic audio and video call features.

  • Your use case requires bypassing the ARTC internal playback module. Otherwise, we recommend using the default playback solution to ensure stability and compatibility.

Implementation

image

Implementation

1. Disable internal playback

To use the custom audio playback feature, you typically need to disable the SDK's internal playback. We recommend disabling it when creating the engine instance by calling getInstance and passing the extras parameter. The relevant parameter is as follows:

user_specified_use_external_audio_player: Specifies whether to use an external player.

  • "TRUE": Uses an external player and disables internal playback.

  • "FALSE": Uses the default internal playback.

Android

String extras = "{\"user_specified_use_external_audio_player\":\"TRUE\"}";
mAliRtcEngine = AliRtcEngine.getInstance(this, extras);

iOS

// Create and initialize the engine.
var customAudioPlayConfig: [String: String] = [:]
// Use an external player, which disables the SDK's internal playback.
customAudioPlayConfig["user_specified_use_external_audio_player"] = "TRUE"
// Serialize to JSON.
guard let jsonData = try? JSONSerialization.data(withJSONObject: customAudioPlayConfig, options: []),
let extras = String(data: jsonData, encoding: .utf8) else {
    print("JSON serialization failed")
    return
}
let engine = AliRtcEngine.sharedInstance(self, extras:extras)

Mac

NSString * extras = @"{\"user_specified_use_external_audio_player\":\"TRUE\"}";
self.engine = [AliRtcEngine sharedInstance:self extras:extras];

Windows

std::string extras = "{\"user_specified_use_external_audio_player\":\"TRUE\"}";
mAliRtcEngine = AliRtcEngine.getInstance(this, extras.c_str());

2. Register audio frame callback

Call enableAudioFrameObserverto register the audio frame callback. Pass the following parameters:

  • enable: A boolean that enables or disables the data callback.

  • audioSource: The type of data source for the callback. For custom audio playback, set this to AliRtcAudioSourcePlayback to receive data from the playback stage through the onPlaybackAudioFrame callback.

  • config: The desired audio parameters for the callback, including sample rate and number of channels.

Android

// Set the callback configuration.
AliRtcEngine.AliRtcAudioFrameObserverConfig config = new AliRtcEngine.AliRtcAudioFrameObserverConfig();
config.sampleRate = AliRtcAudioSampleRate_48000;
config.channels = 1;
// Register to enable the playback data callback.
mAliRtcEngine.enableAudioFrameObserver(true, AliRtcAudioSourcePlayback, config);

iOS

// Set the callback configuration.
var observerConfig: AliRtcAudioFrameObserverConfig = AliRtcAudioFrameObserverConfig()
observerConfig.sampleRate = ._Unknown
observerConfig.channels = .monoAudio
// Register to enable the playback data callback.
let audioSource: AliRtcAudioSource = .playback
engine.enableAudioFrameObserver(true, audioSource: audioSource, config: observerConfig)

Mac

AliRtcAudioFrameObserverConfig* config = [[AliRtcAudioFrameObserverConfig alloc] init];
config.channels = audioNumChannel;
config.sampleRate = AliRtcAudioSampleRate_48000;
config.mode = AliRtcAudioFrameObserverOperationModeReadOnly;
[self.engine enableAudioFrameObserver:TRUE audioSource:AliRtcAudioSourcePlayback config:config];

Windows

// Set the callback configuration.
AliEngineAudioFrameObserverConfig config ;
config.sampleRate = AliRtcAudioSampleRate_48000;
config.channels = AliEngineMonoAudio;
// Register to enable the playback data callback.
mAliRtcEngine->EnableAudioFrameObserver(true, AliEngineAudioSourcePlayback, config);

3. Process PCM data in the callback

In the callback, process the received PCM data and submit it to your playback device.

Android

@Override
public boolean onPlaybackAudioFrame(AliRtcEngine.AliRtcAudioFrame frame) {
    // Implement your custom logic to play the audio data received in the callback.

    return true;
}

iOS

func onPlaybackAudioFrame(_ frame: AliRtcAudioFrame) -> Bool {
    // Implement your custom logic to play the audio data received in the callback.
    
    return true
}

Mac

- (BOOL)onPlaybackAudioFrame:(AliRtcAudioFrame* _Nonnull)frame {
    // Implement your custom logic to play the audio data received in the callback.
    return true;
}

Windows

bool CTutorialDlg::OnPlaybackAudioFrame(AliEngineAudioRawData audioRawData) {
	// Implement your custom logic to play the audio data received in the callback.
	return true;
}

4. Disable the observer

Android

mAliRtcEngine.enableAudioFrameObserver(false, AliRtcAudioSourcePlayback, config)

iOS

engine.enableAudioFrameObserver(false, audioSource: audioSource, config: observerConfig)

Mac

[self.engine enableAudioFrameObserver:false audioSource:AliRtcAudioSourcePlayback config:config];

Windows

mAliRtcEngine->EnableAudioFrameObserver(false, AliEngineAudioSourcePlayback, config);

5. (Optional) Dynamically enable or disable internal playback

To dynamically enable or disable the SDK's internal playback during a call, call the setParameter method.

Android

/* Dynamically disable internal playback. */
String parameter = "{\"audio\":{\"enable_system_audio_device_play\":\"FALSE\"}}";
mAliRtcEngine.setParameter(parameter);

/* Dynamically enable internal playback. */
String parameter = "{\"audio\":{\"enable_system_audio_device_play\":\"TRUE\"}}"; 
mAliRtcEngine.setParameter(parameter);

iOS

// Dynamically disable internal playback.
engine.setParameter("{\"audio\":{\"enable_system_audio_device_play\":\"FALSE\"}}")
// Dynamically enable internal playback.
engine.setParameter("{\"audio\":{\"enable_system_audio_device_play\":\"TRUE\"}}")

Mac

// Dynamically disable internal playback.
[self.engine setParameter:"{\"audio\":{\"enable_system_audio_device_play\":\"FALSE\"}}"];
// Dynamically enable internal playback.
[self.engine setParameter:"{\"audio\":{\"enable_system_audio_device_play\":\"TRUE\"}}"];

Windows

/* Dynamically disable internal playback. */
std::string parameter = "{\"audio\":{\"enable_system_audio_device_play\":\"FALSE\"}}";
mAliRtcEngine->SetParameter(parameter.c_str());

/* Dynamically enable internal playback. */
std::string parameter = "{\"audio\":{\"enable_system_audio_device_play\":\"TRUE\"}}"; 
mAliRtcEngine->SetParameter(parameter.c_str());