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
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 toAliRtcAudioSourcePlaybackto receive data from the playback stage through theonPlaybackAudioFramecallback.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());