在游戏等互动娱乐场景中,播放音效可以烘托气氛、增添娱乐效果,本端和房间内的其他成员都能听见声音,需要使用音效播放器接口。
一般来说,时长小于 20 s 的音频为音效,使用音效播放器接口。例如,掌声、欢呼声、口哨声等。多个音效可以叠加播放。

对于时长较长的音频或 PCM 数据,应使用音乐播放器接口,参考播放音乐文件 。

前提条件

你已经集成 RTC SDK,实现了基本的音视频通话。
支持音效播放的 SDK 详见API 及回调。

功能实现

除了常规的音频控制功能外,RTC SDK 支持调整音频播放音量和声道,设置音乐播放进度等。

创建引擎

创建音视频引擎类后,你可以创建一个音效播放器类。

如果你需要将音效发送到远端,还需要加入房间并发布音频流,参考 构建 RTC 应用 获取详细步骤。

rtcVideo = RTCVideo.createRTCVideo(this, Constants.APP_ID, rtcVideoEventHandler, null, null);
rtcVideo.startAudioCapture();

// 创建播放器
effectPlayer = rtcVideo.getAudioEffectPlayer();
java
self.rtcVideo = ByteRTCVideo.createRTCVideo(kAppID, delegate: self, parameters: [:])
self.rtcVideo?.startAudioCapture()

// 创建播放器
self.effectPlayer = self.rtcVideo?.getAudioEffectPlayer()
swift
video = bytertc::createRTCVideo(appid, handler, nullptr);
video->startAudioCapture();

// 创建播放器
player = video->getAudioEffectPlayer();
cpp
设置回调

调用 setEventHandler 后会收到播放音效的状态回调。

effectPlayer.setEventHandler(effectPlayerEventHandler);
java
weak var weakSelf = self
self.effectPlayer?.setEventHandler(weakSelf)
swift
player->setEventHandler(handler);

void Handler::onAudioEffectPlayerStateChanged(int effect_id, PlayerState state, PlayerError error){
    //effect_id 为音效的 ID
    //state 为音效的播放状态
    //error 为错误码
}
cpp
预加载本地音效文件

推荐使用 preload 进行预加载,在需要多次播放同一个本地音效时,避免内存多次申请、释放。
如果不再需要播放后,可以调用 unload 清理内存空间。

不支持加载在线 URL 音频文件。

effectPlayer.preload(EFFECT_ID_1, path1)
java
self.effectPlayer?.preload(effectId, filePath: filePath)
swift
int ret = player->preload(id, "path");
cpp
开始播放音效

多次调用 start,分别传入不同的混音 ID 和 filepath 可以实现同时播放多个音效文件,达到音效叠加效果。如果已预加载文件,确保播放时传入的混音 ID 与预加载时的一致。

private void startEffect(int effectId, String path) {
    AudioEffectPlayerConfig playerConfig = new AudioEffectPlayerConfig();
    playerConfig.type = AudioMixingType.AUDIO_MIXING_TYPE_PLAYOUT_AND_PUBLISH;
    playerConfig.startPos = 0;
    playerConfig.playCount = 1; // 重复播放次数
    playerConfig.pitch = 0;
    effectPlayer.start(effectId, path, playerConfig);
}
java
let filePath = Bundle.main.path(forResource: "rtc_test", ofType: "aac")

let config = ByteRTCAudioEffectPlayerConfig.init()
config.type = .playoutAndPublish
config.playCount = 1 // 重复播放次数

let code = self.effectPlayer?.start(self.effectId, filePath: filePath, config: config)
print("start play effect code = (code!)")
swift
bytertc::AudioEffectPlayerConfig config;
config.pitch = 0;
config.play_count = 1; // 重复播放次数
config.start_pos = 0;
config.type = static_cast<bytertc::AudioMixingType>(type);
int ret = player->start(id, "path1", config);
cpp
停止播放音效

如果你需要在音效播放中主动终止播放,可以调用 stop 或 stopAll 方法。

//停止播放单个音效
effectPlayer.stop(EFFECT_ID_1)
//停止播放所有音效
effectPlayer.stopAll()
java
//停止播放单个音效
self.effectPlayer?.stop(self.effectId) 
//停止播放所有音效
self.effectPlayer?.stopAll()
swift
 //停止播放单个音效
int ret = player->stop(id);
 //停止播放所有音效
int ret = player->stopAll();
cpp
暂停/恢复播放音效
//暂停播放单个音效
effectPlayer.pause(EFFECT_ID_1)
//暂停播放所有音效
effectPlayer.resume(EFFECT_ID_1)

//恢复单个音效
effectPlayer.pauseAll()
//恢复所有音效
effectPlayer.resumeAll()
java
//暂停播放单个音效
self.effectPlayer?.pause(self.effectId)
//暂停播放所有音效
self.effectPlayer?.resume(self.effectId) 

//恢复单个音效
self.effectPlayer?.pauseAll()  
//恢复所有音效
self.effectPlayer?.resumeAll() 
swift
//暂停播放单个音效
int ret = player->pause(id); 
//暂停播放所有音效
int ret = player->pauseAll(); 

//恢复单个音效
int ret = player->resume(id); 
//恢复所有音效
int ret = player->resumeAll();
cpp
获取和设置音乐属性

所有的混音相关设置都必须在开始播放以后,停止播放之前进行,否则不生效,包括但不限于设置播放音量,设置播放起始位置等。
只有移动端有 setVolumeAll 接口,可以调节全部混音音量,PC 端只能通过 setVolume 接口调节指定混音音量

对同一个音频文件进行操作时,注意混音 ID 应保持一。

//设置播放位置
effectPlayer.setPosition(EFFECT_ID_1, position)
//获取播放位置
int pos = effectPlayer.getPosition(progress)

//获取音效时长
effectPlayer.getDuration(EFFECT_ID_1, progress)

//设置单个音效音量,音量取值范围 [0,400]
effectPlayer.setVolume(EFFECT_ID_1, progress)
//设置所有音效音量,音量取值范围 [0,400]
effectPlayer.setVolumeAll(progress)
//获取单个音效音量
int volume = effectPlayer.getVolume(EFFECT_ID_1)

java
//设置播放位置
self.effectPlayer?.setPosition(self.effectId1, position: position)
//获取播放位置
let position = self.effectPlayer?.getPosition(self.effectId)

//获取音效时长
let totalTime = self.effectPlayer?.getDuration(self.effectId)

//设置单个音效音量,音量取值范围 [0,400]
self.effectPlayer?.setVolume(self.effectId, volume: volume)
//设置所有音效音量,音量取值范围 [0,400]
let volume = self.effectPlayer?.getVolume(self.effectId)
//获取单个音效音量
let volume = self.effectPlayer?.getVolume(self.effectId)
        
swift
//设置播放位置
int ret = player->setPositon(id, position); 
//获取播放位置
int ret = player->getPosition(id); 

//获取音效时长
int ret = player->getDuration(id); 

//设置单个音效音量,音量取值范围 [0,400]
int ret= player->setVolume(id, volume);  
//设置所有音效音量,音量取值范围 [0,400]
int ret = player->setVolumeAll(volume);  
//获取单个音效音量
int ret = player->getVolume(id); 
cpp
示例项目

API 及回调

说明:表格中的 macOS API 接口为 Objective-C,而示例项目中的 macOS 项目使用的是 Windows SDK 中的 API 接口。

平台AndroidiOSmacOSWindowsLinuxElectronFlutterWeb
初始化音效管理类getAudioEffectPlayergetAudioEffectPlayergetAudioEffectPlayergetAudioEffectPlayergetAudioEffectPlayergetAudioEffectPlayergetAudioEffectPlayergetAudioMixingManager
音效混音管理类IAudioEffectPlayerByteRTCAudioEffectPlayerByteRTCAudioEffectPlayerIAudioEffectPlayerIAudioEffectPlayerRTCAudioEffectPlayerRTCAudioEffectPlayerAudioMixingManager
音效播放器回调onAudioEffectPlayerStateChangedonAudioEffectPlayerStateChanged:state:error:onAudioEffectPlayerStateChanged:state:error:onAudioEffectPlayerStateChangedonAudioEffectPlayerStateChangedonAudioEffectPlayerStateChangedonAudioEffectPlayerStateChanged
变更日志
  1. 自客户端 SDK 3.32 起,支持对音乐文件的声道进行设置。

  2. 自客户端 SDK 3.36 起,全平台支持在线音频文件混音。

  3. 自客户端 SDK 3.38 起,支持调整音视频通话中使用的音频文件的播放速度。

  4. 自客户端 SDK 3.45.4 起,支持获取混音音频文件的实际播放时长,即歌曲不受停止、跳转、倍速、卡顿影响的播放时长。

  5. 自客户端 SDK 3.52 起,支持混音播放 24kHz 的 mp3 文件。3.52 之前版本仅支持以下采样率的音频文件:8kHz、16kHz、22.05kHz、32kHz、44.1kHz、48kHz、64kHz、96kHz、192kHz。

  6. 自客户端 SDK 3.54 起,Native 平台废弃原有的混音类,分为音效混音和音乐混音,支持分别控制。