All Products
Search
Document Center

ApsaraVideo Live:Play and publish external audio (sound effects and accompaniment)

Last Updated:Mar 26, 2026

This topic explains how to mix external audio—such as background music, sound effects, or a PCM audio stream—into the ARTC SDK audio stream for local playback and remote sharing during a real-time session.

Overview

The ARTC SDK lets you play and publish external audio. It supports various file formats such as MP4, WAV, and AAC, as well as PCM audio streams. You can integrate pre-recorded files or real-time data streams, depending on your use case.

Use cases

  • Publishing audio files: Insert sound effects, background music, or spoken content into live streams. For example, you can trigger product alerts in e-commerce streams or add ambient sound effects in game streams.

  • Publishing PCM streams: Ideal for real-time interactive voice services, such as publishing a text-to-speech (TTS) generated PCM audio stream in an intelligent customer service system.

Sample code

Android: Android/ARTCExample/BasicUsage/src/main/java/com/aliyun/artc/api/basicusage/PlayAudioFiles/PlayAudioFilesActivity.java

iOS: iOS/ARTCExample/BasicUsage/PlayAudioFiles/PlayAudioFilesVC.swift

Harmony: Harmony/ARTCExample/entry/src/main/ets/pages/basicusage/PlayAudioFilesPage.ets

Before you begin

Before implementing the features in this topic, ensure you meet the following requirements:

Play or publish audio files

How it works

This feature lets you play or publish audio files during a real-time session. It provides two sets of APIs for different use cases:

  • Accompaniment APIs: For playing longer audio files, such as background music or musical accompaniment. You can play only one music file at a time.

  • Sound effect APIs: Optimized for playing short, transient audio clips, such as applause or laughter. You can play multiple sound effects simultaneously.

Note

Before playing or publishing external audio, you must join a channel and publish your local audio stream. Wait for the onAudioPublishStateChanged callback, which confirms that the audio stream is published.

The related APIs are as follows:

Feature

Accompaniment APIs

Sound effect APIs

Control playback

  • startAudioAccompany

  • stopAudioAccompany

  • pauseAudioAccompany

  • resumeAudioAccompany

  • preloadAudioEffect

  • unloadAudioEffect

  • playAudioEffect

  • stopAudioEffect

  • stopAllAudioEffects

  • pauseAudioEffect

  • pauseAllAudioEffects

  • resumeAudioEffect

  • resumeAllAudioEffects

Manage playback progress

  • getAudioAccompanyDuration

  • getAudioAccompanyCurrentPosition

  • setAudioAccompanyPosition


Manage playback volume

  • setAudioAccompanyVolume

  • setAudioAccompanyPublishVolume

  • getAudioAccompanyPublishVolume

  • setAudioAccompanyPlayoutVolume

  • getAudioAccompanyPlayoutVolume

  • setAudioEffectPublishVolume

  • getAudioEffectPublishVolume

  • setAudioEffectPlayoutVolume

  • getAudioEffectPlayoutVolume

  • setAllAudioEffectsPublishVolume

  • setAllAudioEffectsPlayoutVolume

Playback status callbacks

Local:

  • onAudioAccompanyStateChanged

Remote:

  • onRemoteAudioAccompanyStarted

  • onRemoteAudioAccompanyFinished

Local:

  • onAudioEffectFinished

Get audio file information

  • getAudioFileInfo

  • onAudioFileInfo

Play an accompaniment

When using the accompaniment APIs, you can play only one audio file at a time.

  1. Join a channel and publish the audio stream. This is enabled by default in the SDK.

    Android

    // To play an accompaniment or sound effect, you must publish the audio stream. This is enabled by default in the SDK.
    mAliRtcEngine.publishLocalAudioStream(true);

    iOS

    // To play an accompaniment or sound effect, you must publish the audio stream. This is enabled by default in the SDK.
    engine.publishLocalAudioStream(true)

    Harmony

    // Publish the local audio stream. This is enabled by default.
    this.rtcEngine.publishLocalAudioStream(true);

    Mac

    // To play an accompaniment or sound effect, you must publish the audio stream. This is enabled by default in the SDK.
    [self.engine publishLocalAudioStream:TRUE];

    Windows

    mAliRtcEngine->publishLocalAudioStream(true)
  2. Control playback

After you join a channel and push an audio stream, call startAudioAccompany to play the accompaniment. A successful call triggers the onAudioAccompanyStateChanged callback locally, and the onRemoteAudioAccompanyStarted callback remotely.

You can also use the following APIs to control playback:

  • stopAudioAccompany: Stop playback.

  • pauseAudioAccompany: Pause playback.

  • resumeAudioAccompany: Resume playback.

  • getAudioAccompanyDuration, getAudioAccompanyCurrentPosition, setAudioAccompanyPosition: Get the file duration and control playback progress.

  • setAudioAccompanyVolume: Set both the local playback and remote publishing volume of the accompaniment.

  • getAudioAccompanyPublishVolume, setAudioAccompanyPublishVolume: Get or adjust the publishing volume of the accompaniment for remote clients.

  • getAudioAccompanyPlayoutVolume, setAudioAccompanyPlayoutVolume: Get or adjust the local playback volume of the accompaniment.

Android

// Path to the accompaniment file.
private String mMixingMusicFilepath = "/assets/music.wav";

// Configure accompaniment playback.
AliRtcEngine.AliRtcAudioAccompanyConfig config = new AliRtcEngine.AliRtcAudioAccompanyConfig();
config.loopCycles = -1; // Number of loops. -1 indicates infinite looping.
config.publishVolume = publishVolume; // Publishing volume. Range: [0, 100].
config.playoutVolume = playbackVolume; // Local playback volume. Range: [0, 100].
config.startPosMs = 0; // Playback starting position.
// Start playback.
mAliRtcEngine.startAudioAccompany(mMixingMusicFilepath, config);

// Pause/Resume the accompaniment.
mAliRtcEngine.pauseAudioAccompany();
mAliRtcEngine.resumeAudioAccompany();

// Stop playback.
mAliRtcEngine.stopAudioAccompany();

// Get the duration of the accompaniment file in ms. Call this method after startAudioAccompany, otherwise it returns -1.
int duration = mAliRtcEngine.getAudioAccompanyDuration();
// To get the duration of a specific file, call getAudioFileInfo. You can call this after creating the engine. The result is returned in the onAudioFileInfo callback.
mAliRtcEngine.getAudioFileInfo(filePath);
@Override
public void onAudioFileInfo(AliRtcEngine.AliRtcAudioFileInfo info, AliRtcEngine.AliRtcAudioAccompanyErrorCode errorCode) {

    handler.post(() -> {
        String msg = "onAudioFileInfo.file:" + info.filePath + "duration:" + info.durationMs + "audioPlayingErrorCode=" + errorCode;
        ToastHelper.showToast(PlayAudioFilesActivity.this, msg, Toast.LENGTH_SHORT);
    });
}

// Get/Set the volume.
mAliRtcEngine.setAudioAccompanyVolume(50); // Range: [0, 100].
int publishVolume = mAliRtcEngine.getAudioAccompanyPublishVolume();
mAliRtcEngine.setAudioAccompanyPublishVolume(50);
int playoutVolume = mAliRtcEngine.getAudioAccompanyPlayoutVolume();
mAliRtcEngine.setAudioAccompanyPlayoutVolume(50);

// Get/Set playback progress.
int currPosition = mAliRtcEngine.getAudioAccompanyCurrentPosition(); // Unit: ms.
int targetPosition = 1000; // Example: start playing from the 1000 ms mark.
mAliRtcEngine.setAudioAccompanyPosition(targetPosition);

iOS

// Path to the accompaniment file.
let filePath = Bundle.main.path(forResource: "music", ofType: "wav")

// Configure accompaniment playback.
let config = AliRtcAudioAccompanyConfig()
config.loopCycles = loopCount
config.publishVolume = publishVolume
config.playoutVolume = playoutVolume
config.startPosMs = 0
// Start playback.
let result = rtcEngine.startAudioAccompany(withFile: filePath, config: config)

// Pause/Resume playback.
rtcEngine.pauseAudioAccompany()
rtcEngine.resumeAudioAccompany()

// Stop playback.
rtcEngine.stopAudioAccompany()

// Get the duration of the accompaniment file in ms. Call this method after startAudioAccompany, otherwise it returns -1.
let duration = rtcEngine.getAudioAccompanyDuration()
// To get the duration of a specific file, call getAudioFileInfo. You can call this after creating the engine. The result is returned in the onAudioFileInfo callback.
rtcEngine.getAudioFileInfo(filePath)
func onAudioFileInfo(_ info: AliRtcAudioFileInfo, errorCode: AliRtcAudioAccompanyErrorCode) {
    "onAudioFileInfo, filePath: \(info.filePath), durationMs: \(info.durationMs), errorCode: \(errorCode)".printLog()
}

// Get/Set the volume.
rtcEngine.setAudioAccompanyVolume(50) // Set both the publishing and playback volume of the accompaniment. Range: [0-100].
let audioPublishVolume = rtcEngine.getAudioAccompanyPublishVolume() // Get the current publishing volume of the accompaniment.
rtcEngine.setAudioAccompanyPublishVolume(50) // Set the publishing volume of the accompaniment. Range: [0-100].
let audioPlayoutVolume = rtcEngine.getAudioAccompanyPlayoutVolume() // Get the current local playback volume of the accompaniment.
rtcEngine.setAudioAccompanyPlayoutVolume(50) // Set the local playback volume of the accompaniment. Range: [0-100].

// Get/Set playback progress.
let currentPosition = rtcEngine.getAudioAccompanyCurrentPosition() // Unit: ms.
let targetPosition:Int32 = 1000; // Example: start playing from the 1000 ms mark.
rtcEngine.setAudioAccompanyPosition(targetPosition)

Harmony

// Path to the accompaniment file.
private accompanimentFile: string = 'music.wav';
// Start the accompaniment.
private async startAudioAccompany(): Promise<void> {
  if (!this.rtcEngine) {
    prompt.showToast({ message: 'RTC engine not initialized', duration: 2000 });
    return;
  }
  if (!this.hasJoined) {
    prompt.showToast({ message: 'Join a channel first', duration: 2000 });
    return;
  }
  try {
    // Get the loop count.
    const loopCount = this.loopCount.trim() === '' ? -1 : parseInt(this.loopCount);
    const publishVolume = this.pushVolume;  // Publishing volume.
    const playbackVolume = this.playVolume; // Local playback volume.
    // Create an accompaniment configuration.
    const config: AliRtcAudioAccompanyConfig = new AliRtcAudioAccompanyConfig();
    config.loopCycles = loopCount;      // Number of loops. -1 indicates infinite looping.
    config.publishVolume = publishVolume; // Publishing volume. Range: [0, 100].
    config.playoutVolume = playbackVolume; // Local playback volume. Range: [0, 100].
    config.startPosMs = 0;              // Playback starting position.
    // Use the sandbox file path.
    const audioPath = this.sandboxManager.getSandboxFilePath(this.accompanimentFile);
    // Start playback.
    this.rtcEngine.startAudioAccompany(audioPath, config);
    // Get the audio duration and update the progress bar.
    const audioDuration = this.rtcEngine.getAudioAccompanyDuration(); // Unit: ms.
    if (audioDuration > 0) {
      this.audioDuration = audioDuration;
    }
    console.info('Start playing accompaniment');
  } catch (error) {
    console.error('Error playing accompaniment:', error);
    prompt.showToast({ message: 'Error playing accompaniment', duration: 2000 });
  }
}
// Pause the accompaniment.
private pauseAudioAccompany(): void {
  if (!this.rtcEngine) {
    prompt.showToast({ message: 'RTC engine not initialized', duration: 2000 });
    return;
  }
  this.rtcEngine.pauseAudioAccompany();
  console.info('Pause accompaniment playback');
}
// Resume the accompaniment.
private resumeAudioAccompany(): void {
  if (!this.rtcEngine) {
    prompt.showToast({ message: 'RTC engine not initialized', duration: 2000 });
    return;
  }
  this.rtcEngine.resumeAudioAccompany();
  console.info('Resume accompaniment playback');
}
// Stop the accompaniment.
private stopAudioAccompany(): void {
  if (!this.rtcEngine) {
    prompt.showToast({ message: 'RTC engine not initialized', duration: 2000 });
    return;
  }
  this.rtcEngine.stopAudioAccompany();
  console.info('Stop accompaniment playback');
}
// Set the accompaniment volume.
private setAudioAccompanyVolume(volume: number): void {
  if (this.rtcEngine && this.hasJoined) {
    this.rtcEngine.setAudioAccompanyVolume(volume); // Range: [0, 100].
  }
}
// Set the publishing volume.
private setAudioAccompanyPublishVolume(volume: number): void {
  if (this.rtcEngine && this.hasJoined) {
    this.rtcEngine.setAudioAccompanyPublishVolume(volume); // Range: [0, 100].
  }
}
// Set the playback volume.
private setAudioAccompanyPlayoutVolume(volume: number): void {
  if (this.rtcEngine && this.hasJoined) {
    this.rtcEngine.setAudioAccompanyPlayOutVolume(volume); // Range: [0, 100].
  }
}
// Get the publishing volume.
private getAudioAccompanyPublishVolume(): number {
  if (this.rtcEngine) {
    return this.rtcEngine.getAudioAccompanyPublishVolume();
  }
  return 0;
}
// Get the playback volume.
private getAudioAccompanyPlayoutVolume(): number {
  if (this.rtcEngine) {
    return this.rtcEngine.getAudioAccompanyPlayoutVolume();
  }
  return 0;
}
// Set the playback position.
private setAudioAccompanyPosition(position: number): void {
  if (this.rtcEngine && this.hasJoined) {
    if (position >= 0 && position <= this.audioDuration) {
      this.rtcEngine.setAudioAccompanyPosition(position); // Unit: ms.
    }
  }
}
// Get the current playback position.
private getAudioAccompanyCurrentPosition(): number {
  if (this.rtcEngine && this.hasJoined) {
    return this.rtcEngine.getAudioAccompanyCurrentPosition(); // Unit: ms.
  }
  return 0;
}
// Example of a timer to update playback progress.
private updatePlayProgress(): void {
  if (this.rtcEngine && this.hasJoined) {
    const currentPosition = this.rtcEngine.getAudioAccompanyCurrentPosition();
    this.playProgress = currentPosition;
  }
}

Mac

AliRtcAudioAccompanyConfig *config = [[AliRtcAudioAccompanyConfig alloc] init];
    
config.onlyLocalPlay = localPlay;
config.replaceMic = replaceMic;
config.loopCycles = self.loopLabel.intValue;
config.startPosMs = startPosMs;
config.publishVolume = publishVolume;
config.playoutVolume = playVolume;
NSString *string;

int ret = [self.engine startAudioAccompanyWithFile:self.playURLString config:config];
if (ret) {
    string = [NSString stringWithFormat:@"Playback failed. Check the parameter configuration: %d",ret];
} else {
        
    [self.isChangeMicBtn setEnabled:FALSE] ;
        
    if (startPos > 0 && startPosMs == 0) {
        string = @"Playback started successfully (music duration not available, start position parameter ignored)";
    } else {
        string = @"Playback started successfully";
    }
}

// Pause/Resume playback.
[self.engine pauseAudioAccompany];
[self.engine resumeAudioAccompany];

// Stop playback.
[self.engine stopAudioAccompany];

// Get the duration of the accompaniment file in ms. Call this method after startAudioAccompany, otherwise it returns -1.
int duration = [self.engine getAudioAccompanyDuration];

// To get the duration of a specific file, call getAudioFileInfo. You can call this after creating the engine. The result is returned in the onAudioFileInfo callback.
 [self.engine getAudioFileInfo:filePath];

- (void)onAudioFileInfo:(AliRtcAudioFileInfo* _Nonnull)info errorCode:(AliRtcAudioAccompanyErrorCode)errorCode {
   /* Update UI status */
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.accompanyVC) {
            [self.accompanyVC updateAudioFileInfo:info errorCode:errorCode];
        }
        if (self.effectVC) {
            [self.effectVC updateAudioFileInfo:info errorCode:errorCode];
        }
    });
    
}


// Get/Set volume.
[self.engine setAudioAccompanyVolume:sender.integerValue];

// Set both the publishing and playback volume of the accompaniment. Range: [0, 100].
int volume = [self.engine getAudioAccompanyPublishVolume];
sender.title = [NSString stringWithFormat:@"Get publishing volume: %d",volume];

[self.engine setAudioAccompanyPublishVolume:50]; // Set the publishing volume of the accompaniment. Range: [0, 100].

int audioPlayoutVolume = [self.engine getAudioAccompanyPlayoutVolume]; // Get the current local playback volume of the accompaniment.
[self.engine setAudioAccompanyPlayoutVolume:50]; // Set the local playback volume of the accompaniment. Range: [0, 100].

// Get/Set playback progress.
int duration = [self.engine getAudioAccompanyDuration];
long position = duration * sender.integerValue/100;
[self.engine setAudioAccompanyPosition:(int)position];

Windows

AliEngineAudioAccompanyConfig config;
config.onlyLocalPlay = (0 == mbCheckPubAcc);
config.loopCycles = miEditCycleNum;
config.replaceMic = (0 != mbCheckAccReplaceMic);
config.startPosMs = startPosMs;
config.playoutVolume = mbCheckAccMixVol ? miStaticAccMixVol : miStaticAccPlayoutVol;
config.publishVolume = mbCheckAccMixVol ? miStaticAccMixVol : miStaticAccPubVol;

if (0 != mAliRtcEngine->StartAudioAccompany(strPath.c_str(), config))
{
    AfxMessageBox(_T("Failed to start accompaniment!"));
    return;
}

// Pause/Resume the accompaniment.
mAliRtcEngine->PauseAudioAccompany();
mAliRtcEngine->ResumeAudioAccompany();

// Stop playback.
mAliRtcEngine->StopAudioAccompany();

// Get the duration of the accompaniment file in ms. Call this method after startAudioAccompany, otherwise it returns -1.
int duration = mAliRtcEngine->GetAudioAccompanyDuration();
// To get the duration of a specific file, call getAudioFileInfo. You can call this after creating the engine. The result is returned in the onAudioFileInfo callback.
mAliRtcEngine->GetAudioFileInfo(filePath);


void CTutorialDlg::OnAudioFileInfo(AliEngineAudioFileInfo info,
	AliEngineAudioAccompanyErrorCode errorCode) {

    /* Notify the UI to refresh. */
	CAudioAccompanyDlg::AudioFileInfo *audioInfo = new CAudioAccompanyDlg::AudioFileInfo();
	
    audioInfo->filePath = AliStringToCString(info.filePath);
	audioInfo->durationMs = info.durationMs;
	::PostMessage(cshell_dlg.GetAudioAccompanyHwnd(), MM_AUDIO_ACCOMPANY_AUDIO_FILE_INFO, (WPARAM)audioInfo, (LPARAM)errorCode);

	CAudioEffectDlg::AudioFileInfo *effectInfo = new CAudioEffectDlg::AudioFileInfo();
	effectInfo->filePath = AliStringToCString(info.filePath);
	effectInfo->durationMs = info.durationMs;
	::PostMessage(cshell_dlg.GetAudioEffectHwnd(), MM_AUDIO_EFFECT_AUDIO_FILE_INFO, (WPARAM)effectInfo, (LPARAM)errorCode);
}

/* Get/Set the volume. */
mAliRtcEngine->SetAudioAccompanyVolume(50); // Range: [0, 100].
int publishVolume = mAliRtcEngine->GetAudioAccompanyPublishVolume();
mAliRtcEngine->SetAudioAccompanyPublishVolume(50);
int playoutVolume = mAliRtcEngine->GetAudioAccompanyPlayoutVolume();
mAliRtcEngine->SetAudioAccompanyPlayoutVolume(50);

/* Get/Set playback progress. */
int currPosition = mAliRtcEngine->GetAudioAccompanyCurrentPosition(); // Unit: ms.
int targetPosition = 1000; // Example: start playing from the 1000 ms mark.
mAliRtcEngine->SetAudioAccompanyPosition(targetPosition);

Play sound effects

To play multiple sound effects simultaneously (for example, applause and laughter), use APIs such as preloadAudioEffect and playAudioEffect.

Note

You must assign a unique ID to each sound effect. Your application is responsible for managing these IDs.

  1. Join a channel and publish the audio stream. This is enabled by default in the SDK.

    Android

    // To play an accompaniment or sound effect, you must publish the audio stream. This is enabled by default in the SDK.
    mAliRtcEngine.publishLocalAudioStream(true);

    iOS

    // To play an accompaniment or sound effect, you must publish the audio stream. This is enabled by default in the SDK.
    engine.publishLocalAudioStream(true)

    Harmony

    // Publish the local audio stream. This is enabled by default.
    this.rtcEngine.publishLocalAudioStream(true);

    Mac

    // To play an accompaniment or sound effect, you must publish the audio stream. This is enabled by default in the SDK.
    [self.engine publishLocalAudioStream:TRUE];

    Windows

    mAliRtcEngine->PublishLocalAudioStream(true);
  2. (Optional) Preload resources

To improve performance when playing a sound effect repeatedly, we recommend preloading the audio file into memory by calling preloadAudioEffect.

  • preloadAudioEffect: Loads the specified sound effect file. It supports both local files and network file URLs. We recommend using local files.

  • When a sound effect is no longer needed, call unloadAudioEffect to unload it and release resources.

Android

// Load the sound effect file with the specified ID and filePath. You must define the ID.
mAliRtcEngine.preloadAudioEffect(mCurrSoundID, filePath);
// Unload the sound effect file with the specified ID.
mAliRtcEngine.unloadAudioEffect(mCurrSoundID);

iOS

// Load the sound effect file with the specified ID and filePath. You must define the ID.
rtcEngine.preloadAudioEffect(withSoundId: self.soundId, filePath: filePath)
// Unload the sound effect file with the specified ID.
rtcEngine.unloadAudioEffect(withSoundId: self.currentEffectIndex)

Harmony

// Load the sound effect file with the specified ID and filePath. You must define the ID.
this.rtcEngine.preloadAudioEffect(1, audioPath);
// Unload the sound effect file with the specified ID.
this.rtcEngine.unloadAudioEffect(this.currSoundID);

Mac

// Load the sound effect file with the specified ID and filePath. You must define the ID.
[self.engine preloadAudioEffectWithSoundId:weakSelf.currentIndex filePath:chooseFileString];

// Unload the sound effect file with the specified ID.
[self.engine unloadAudioEffectWithSoundId:info.effectId];

Windows

// Load the sound effect file with the specified ID and filePath. You must define the ID.
mAliRtcEngine->PreloadAudioEffect(mCurrSoundID, filePath);
// Unload the sound effect file with the specified ID.
mAliRtcEngine->UnloadAudioEffect(mCurrSoundID);
  1. Control playback

After you join a channel and publish the audio stream, call playAudioEffect to play the sound effect. When playback is complete, the onAudioEffectFinished callback is triggered on the local client.

You can also use the following APIs to control playback:

  • stopAudioEffect/stopAllAudioEffects: Stop playback of a specific or all sound effects.

  • pauseAudioEffect/pauseAllAudioEffects: Pause playback of a specific or all sound effects.

  • resumeAudioEffect/resumeAllAudioEffects: Resume playback of a specific or all sound effects.

  • getAudioEffectPublishVolume, setAudioEffectPublishVolume, setAllAudioEffectsPublishVolume: Get or adjust the publishing volume of sound effects for remote clients.

  • getAudioEffectPlayoutVolume, setAudioEffectPlayoutVolume, setAllAudioEffectsPlayoutVolume: Get or adjust the local playback volume of sound effects.

Android

// Play the sound effect.
AliRtcEngine.AliRtcAudioEffectConfig config = new AliRtcEngine.AliRtcAudioEffectConfig();
config.loopCycles = -1;			// Number of loops. -1 indicates infinite looping.
config.startPosMs = 0;			// Playback starting position.
config.publishVolume = 50;		// Publishing volume. Range: [0, 100].
config.playoutVolume = 50;		// Local playback volume. Range: [0, 100].
mAliRtcEngine.playAudioEffect(mCurrSoundID, filePath, config);

// Stop playback.
mAliRtcEngine.stopAudioEffect(soundId);
mAliRtcEngine.stopAllAudioEffects();

// Pause playback.
mAliRtcEngine.pauseAudioEffect(soundId);
mAliRtcEngine.pauseAllAudioEffects();

// Resume playback.
mAliRtcEngine.resumeAudioEffect(soundId);
mAliRtcEngine.resumeAllAudioEffects();

// Get or set the volume.
// Publishing volume
mAliRtcEngine.getAudioEffectPublishVolume(soundId);
mAliRtcEngine.setAudioEffectPublishVolume(soundId, 50);
mAliRtcEngine.setAllAudioEffectsPublishVolume(50);
// Playback volume
mAliRtcEngine.getAudioEffectPlayoutVolume(soundId);
mAliRtcEngine.setAudioEffectPlayoutVolume(soundId, 50);
mAliRtcEngine.setAllAudioEffectsPlayoutVolume(50);

iOS

// Play
let config = AliRtcAudioEffectConfig()
config.loopCycles = -1
config.startPosMs = 0
config.publishVolume = 50
config.playoutVolume = 50
let result = rtcEngine.playAudioEffect(withSoundId: self.soundId, filePath: filePath, config: config)
if result != 0 {
    UIAlertController.showAlertWithMainThread(msg: "Failed to play sound effect. Error code: \(result)", vc: self)
}

// Stop playback.
rtcEngine.stopAudioEffect(withSoundId: soundId)
rtcEngine.stopAllAudioEffects()

// Pause playback.
rtcEngine.pauseAudioEffect(withSoundId: soundId)
rtcEngine.pauseAllAudioEffects()

// Resume playback.
rtcEngine.resumeAudioEffect(withSoundId: soundId)
rtcEngine.resumeAllAudioEffects()

// Get or set the volume.
rtcEngine.getAudioEffectPublishVolume(withSoundId: soundId)
rtcEngine.setAudioEffectPublishVolumeWithSoundId(soundId, volume: 50)
rtcEngine.setAllAudioEffectsPublishVolume(50)
rtcEngine.resumeAudioEffect(withSoundId: soundId)    
rtcEngine.getAudioEffectPlayoutVolume(withSoundId: soundId)
rtcEngine.setAudioEffectPlayoutVolumeWithSoundId(soundId, volume: 50)

Harmony

// Play
const config: AliRtcAudioEffectConfig = new AliRtcAudioEffectConfig();
config.loopCycles = loopCount;
config.startPosMs = 0;
config.publishVolume = this.soundEffectVolume;
config.playoutVolume = this.soundEffectVolume;
const audioPath = this.sandboxManager.getSandboxFilePath(filePath);
this.rtcEngine.playAudioEffect(this.currSoundID, audioPath, config);

// Stop playback.
this.rtcEngine.stopAudioEffect(soundId);
this.rtcEngine.stopAllAudioEffects();

// Pause playback.
this.rtcEngine.pauseAudioEffect(soundId);
this.rtcEngine.pauseAllAudioEffects();

// Resume playback.
this.rtcEngine.resumeAudioEffect(soundId);
this.rtcEngine.resumeAllAudioEffects();

Mac

// Play
AliRtcAudioEffectConfig *config = [AliRtcAudioEffectConfig new];
config.loopCycles = self.circleCountLabel.intValue;
config.needPublish = publish;
config.playoutVolume = info.playoutVolume;
config.publishVolume = info.publishVolume;
config.startPosMs = startPosMs;
    
int ret = [self.engine playAudioEffectWithSoundId:info.effectId filePath:self.playURLString config:config];


// Stop playback.
[self.engine stopAudioEffectWithSoundId:effectId];

[self.engine stopAllAudioEffects];

// Pause playback.
[self.engine pauseAudioEffectWithSoundId:effectId];
[self.engine pauseAllAudioEffects];

// Resume playback.
[self.engine resumeAudioEffectwithSoundId:soundId];
[self.engine resumeAllAudioEffects];

// Get or set the volume.
int volume = [self.engine getAudioEffectPublishVolumeWithSoundId:soundId];
[self.engine setAudioEffectPublishVolumeWithSoundId:soundId volume: 50];

[self.engine setAllAudioEffectsPublishVolume:50];
[self.engine resumeAudioEffectwithSoundId: soundId];    
[self.engine getAudioEffectPlayoutVolumewithSoundId: soundId];
[self.engine setAudioEffectPlayoutVolumeWithSoundId:soundId volume: 50];

Windows

// Play the sound effect.
AliEngineAudioEffectConfig config ;
config.loopCycles = -1;			// Number of loops. -1 indicates infinite looping.
config.startPosMs = 0;			// Playback starting position.
config.publishVolume = 50;		// Publishing volume. Range: [0, 100].
config.playoutVolume = 50;		// Local playback volume. Range: [0, 100].

mAliRtcEngine->PlayAudioEffect(mCurrSoundID, filePath, config);

// Stop playback.
mAliRtcEngine->StopAudioEffect(soundId);
mAliRtcEngine->StopAllAudioEffects();

// Pause playback.
mAliRtcEngine->PauseAudioEffect(soundId);
mAliRtcEngine->PauseAllAudioEffects();

// Resume playback.
mAliRtcEngine->ResumeAudioEffect(soundId);
mAliRtcEngine->ResumeAllAudioEffects();

// Get or set the volume.
// Publishing volume
mAliRtcEngine->GetAudioEffectPublishVolume(soundId);
mAliRtcEngine->SetAudioEffectPublishVolume(soundId, 50);
mAliRtcEngine->SetAllAudioEffectsPublishVolume(50);
// Playback volume
mAliRtcEngine->GetAudioEffectPlayoutVolume(soundId);
mAliRtcEngine->SetAudioEffectPlayoutVolume(soundId, 50);
mAliRtcEngine->SetAllAudioEffectsPlayoutVolume(50);

Play or publish PCM audio data

To play or publish PCM audio data, see Custom audio capture.

How it works

image

Sample code

Add an external input stream

Android

/* Set the parameters based on your business needs. */
AliRtcEngine.AliRtcExternalAudioStreamConfig config = new AliRtcEngine.AliRtcExternalAudioStreamConfig();
/* Set the playout volume to 0 to disable local playback. */
config.playoutVolume = currentAudioPlayoutVolume;
/* Set the publishing volume to 0 to disable publishing. */
config.publishVolume = currentAudioPublishVolume;
config.channels = 1;
config.sampleRate = 48000;
// The method returns an external input stream ID. Use this ID to push data into the SDK.
audioStreamID = mAliRtcEngine.addExternalAudioStream(config);

iOS

/* Set the parameters based on your business needs. */
AliRtcExternalAudioStreamConfig *config = [AliRtcExternalAudioStreamConfig new];
config.channels = _pcmChannels;
config.sampleRate = _pcmSampleRate;
/* Set the playout volume to 0 to disable local playback. */
config.playoutVolume = 0;
/* Set the publishing volume to 100. This example uses 100, but you can set it to 0 to disable publishing. */
config.publishVolume = 100;
// The method returns an external input stream ID. Use this ID to push data into the SDK.
_externalPlayoutStreamId = [self.engine addExternalAudioStream:config];

Push PCM data to the stream

Android

AliRtcEngine.AliRtcAudioFrame rawData = new AliRtcEngine.AliRtcAudioFrame();
rawData.data = frameInfo.audio_data[0];
rawData.numSamples = (int) (frameInfo.audio_data[0].length / (2 * frameInfo.audio_channels));
rawData.bytesPerSample = 2;
rawData.numChannels = frameInfo.audio_channels;
rawData.samplesPerSec = frameInfo.audio_sample_rate;

int ret = mAliRtcEngine.pushExternalAudioStreamRawData(audioStreamID, rawData);
if(ret == 0x01070101) {
    // The buffer is full.
    sleep(20);
} else if(ret < 0) {
    /* An exception occurred. Check the parameters and publishing state. */
}

iOS

AliRtcAudioFrame *sample = [AliRtcAudioFrame new];
sample.dataPtr = _pcmLocalData;
sample.samplesPerSec = _pcmLocalSampleRate;
sample.bytesPerSample = sizeof(int16_t);
sample.numOfChannels = _pcmLocalChannels;
sample.numOfSamples = numOfSamples;
int rc = [self.engine pushExternalAudioStream:_externalPlayoutStreamId rawData:sample];

if(rc == 0x01070101) {
    // The buffer is full.
    sleep(20);
} else if(ret < 0) {
    /* An exception occurred. Check the parameters and publishing state. */
}

Remove the external audio stream

Android

mAliRtcEngine.removeExternalAudioStream(audioStreamID);

iOS

[self.engine removeExternalAudioStream:_externalPublishStreamId];

FAQ

  1. When playing an accompaniment with startAudioAccompany, how can I let only remote users hear the accompaniment, and not the voice from the local microphone?

    You can call the muteLocalMic method before or during accompaniment playback to mute the microphone. In this case, remote users can only hear the accompaniment.