本文介绍如何通过ARTC SDK 使用外部音频源,实现播放 PCM 音频裸数据或本地音频文件。
功能介绍
ARTC SDK支持通过两种方式使用外部音频源:注入 PCM 格式的音频裸数据,或播放本地音频文件(如 MP3、WAV、AAC 等)。您可以根据业务场景选择合适的方案。
音频源 | 主要接口 | 适用场景 |
PCM音频裸数据 |
| 适用于需要实时注入和处理原始音频数据(如 TTS、自定义音频效果器)的场景。此方案灵活性高,但需要您自行管理数据缓存和推送时序。 |
本地音频文件 |
| 用于播放本地音频文件(如 MP3、WAV、AAC),SDK 自动处理解码和播放控制,适合伴奏、音效等文件类音频播放。 |
前提条件
在实现相关功能前,请确保满足以下条件:
功能实现
播放音频裸数据
1. (可选)提前启动播放器
如果您需要在加入频道前播放,请调用startAudioPlayer()提前启动播放器,否则不需要调用。
Android
mAliRtcEngine.startAudioPlayer();iOS
self.rtcEngine?.startAudioPlayer()2. 添加外部音频流(仅播放)
调用addExternalAudioStream接口向 AliRtcEngine 对象中添加外部音频流,添加成功后会返回改音频流的唯一标识 audioStreamID。
如果只需要播放而不需要推流,需要设置推流音量为 0。
Android
/* 根据自己的业务设置对应的参数 */
AliRtcEngine.AliRtcExternalAudioStreamConfig config = new AliRtcEngine.AliRtcExternalAudioStreamConfig();
/* 设置播放音量为0 ,意味着不进行本地播放 */
config.playoutVolume = 100;
/* 设置推流音量为0, 意味着不进行推流 */
config.publishVolume = 0;
config.channels = 1;
config.sampleRate = 48000;
// 返回值为外部输入流ID,后续通过该ID将数据送入SDK
audioStreamID = mAliRtcEngine.addExternalAudioStream(config);iOS
/* 根据自己的业务设置对应的参数 */
AliRtcExternalAudioStreamConfig *config = [AliRtcExternalAudioStreamConfig new];
config.channels = _pcmChannels;
config.sampleRate = _pcmSampleRate;
/* 设置播放音量为0 ,意味着不进行本地播放 */
config.playoutVolume = 0;
/* 设置推流音量为0, 意味着不进行推流 */
config.publishVolume = 100;
// 返回值为外部输入流ID,后续通过该ID将数据送入SDK
_externalPlayoutStreamId = [self.engine addExternalAudioStream:config];3. 向音频流内送入PCM数据
将您获取到的音频流通过 pushExternalAudioStreamRawData 送入 SDK 进行播放。
Android
int duration = 30; // 单次送入SDK音频数据的时长,建议20~50ms
// 从缓存里获取接下来要播放的pcm数据(pcm播放时长不超过duration)
byte[] dataToSend = ...
// 检查dataToSend:如果未停止播放且数据太少可以sleep一下并返回等待更多缓存数据
// 计算dataToSend的采样点数
int numOfSamples = dataToSend的字节长度 / (2 * frameInfo.audio_channels);
// 构造AliRtcAudioFrame对象
AliRtcEngine.AliRtcAudioFrame rawData = new AliRtcEngine.AliRtcAudioFrame();
rawData.data = dataToSend;
rawData.numSamples = numOfSamples;
rawData.bytesPerSample = 2;
rawData.numChannels = mPcmChannels;
rawData.samplesPerSec = mPcmSampleRate;
// 向SDK送入数据
int ret = mAliRtcEngine.pushExternalAudioStreamRawData(audioStreamID, rawData);
if(ret == 0x01070101) {
/* rtc buffer已经满,出现此错误时数据送入SDK失败需要重新送入 */
}
else if(ret < 0) {
/* 异常, 检查参数和推流状态 */
}
// 根据送入数据的固定时长睡眠
sleep(duration - 10);iOS
guard let rtc = self.rtcEngine, self.streamId > 0 else {
return
}
// 单次送给SDK的播放时长,建议为20~50ms
let duration = 30
// 从缓存里获取接下来要播放的pcm数据(pcm播放时长不超过duration)
let dataToSend = ...
// 检查dataToSend:如果未停止播放且数据太少可以sleep一下并返回等待更多缓存数据
// 计算dataToSend的采样点数
let numOfSamples = dataToSend的字节长度 / (2 * frameInfo.audio_channels)
let pushFrame = AliRtcAudioFrame()
pushFrame.dataPtr = dataToSend
pushFrame.numOfSamples = numOfSamples // 采样点数
pushFrame.bytesPerSample = 2
pushFrame.samplesPerSec = self.pcmSampleRate
pushFrame.numOfChannels = self.pcmChannels
let result = rtc.pushExternalAudioStream(self.pushStreamId, rawData: pushFrame)
if result == 0x01070101 {
/* rtc buffer已经满,出现此错误时数据送入SDK失败需要重新送入 */
}
else if result < 0 {
/* 异常, 检查参数和推流状态 */
}
// 根据送入数据的固定时长睡眠
Thread.sleep(forTimeInterval: Double(duration - 10) / 1000.0)4. 移除外部音频流
当播放结束的时候,通过removeExternalAudioStream接口移除对应的外部音频流。
Android
mAliRtcEngine.removeExternalAudioStream(audioStreamID);
audioStreamID = -1;iOS
self.rtcEngine?.removeExternalAudioStream(self.streamId)
self.streamId = -1播放本地文件
如果您的音频源为本地音频文件,可以通过伴奏的相关接口进行播放,同样可以无缝集成 RTC 的音频 3A 能力。
1. 开始播放
调用startAudioAccompany接口开始播放指定的音频文件。
如果不需要推流,需要配置推流音量为 0。
Android
// 音频文件路径
private String mFilepath = "/assets/music.wav";
// 播放配置
AliRtcEngine.AliRtcAudioAccompanyConfig config = new AliRtcEngine.AliRtcAudioAccompanyConfig();
config.loopCycles = 1; // 循环次数
config.publishVolume = 0; // 只播放,不推流
config.playoutVolume = 100;
config.startPosMs = 0; // 起始播放位置
// 开始播放
mRtcEngine.startAudioAccompany(mFilepath, config);iOS
// 音频文件路径
let filePath = Bundle.main.path(forResource: "music", ofType: "wav")
// 播放配置
let config = AliRtcAudioAccompanyConfig()
config.loopCycles = 1 // 循环次数, -1表示无限循环
config.publishVolume = 0 // 只播放,不推流
config.playoutVolume = 100
config.startPosMs = 0
// 开始播放
let result = rtcEngine.startAudioAccompany(withFile: filePath, config: config)
开始播放后可以通过下面的接口进行播放控制:
pauseAudioAccompany:暂停播放
resumeAudioAccompany: 恢复播放
stopAudioAccompany:停止播放
2. 本地监听播放状态
启动播放后,本地会通过onAudioAccompanyStateChanged回调播放状态的变化。
Android
@Override
public void onAudioAccompanyStateChanged(ARTCAICallEngine.ARTCAICallAudioAccompanyStateCode
playState, ARTCAICallEngine.ARTCAICallAudioAccompanyErrorCode
errorCode) {
if (playState == ARTCAICallEngine.ARTCAICallAudioAccompanyStateCode.ARTCAICallAudioAccompanyEnded) {
// 处理播放结束
}
}iOS
func onAudioAccompanyStateChanged(state: ARTCAICallAudioAccompanyState, errorCode: ARTCAICallAudioAccompanyErrorCode) {
if state == .ARTCAICallAudioAccompanyEnded {
// 处理播放结束
}
}相关文档
将音频裸数据推送到远端:自定义音频采集。
播放和推流伴奏/音效文件:播放与推流外部输入音频(包括音效、伴奏)。
常见问题
startAudioAccompany支持播放多个文件吗?伴奏相关接口仅支持同一时间播放一个音频文件,如果需要播放多个文件可以使用音效相关接口,详细请参见播放与推流外部输入音频(包括音效、伴奏)。
为什么调用
pushExternalAudioStreamRawData返回0x01070101?返回值
0x01070101表示 RTC 内部音频缓冲区已满,无法接收更多数据。建议适当降低送入数据的频率;增加 sleep 时间(如示例中的 duration - 10ms);检查是否送入数据过快或缓存管理不当。