自定义音频采集和渲染
声网默认的音频模块可以满足在 App 中使用基本音频功能的需求。声网 SDK 支持使用自定义的音频源和自定义的音频渲染模块为你的 App 添加特殊的音频功能。
技术原理
实时音频传输过程中,声网 SDK 通常会开启默认的音频模块。在以下场景中,你可能会发现默认的音频模块无法满足开发需求,需要自定义音频采集或自定义音频渲染。例如:
- App 中已有自己的音频模块。
- 需要使用前处理库处理采集到的音频。
- 某些音频采集设备被系统独占。为避免与其他业务产生冲突,需要灵活的设备管理策略。
使用自定义音频源管理音频帧的采集、处理和播放时,需要使用声网 SDK 外部方法。
音频数据传输
下图展示在自定义音频采集、音频渲染时,音频数据的传输过程。
自定义音频采集
- 你需要使用 SDK 外部方法自行实现采集模块。
- 调用
pushAudioFrame
,将采集到的音频帧发送给 SDK。
自定义音频渲染
- 你需要使用 SDK 外部方法自行实现渲染模块。
- 调用
pullPlaybackAudioFrame
获取远端用户发送的音频数据。
前提条件
在进行操作之前,请确保你已经在项目中实现了基本的实时音视频功能。详见实现音视频互动。
实现方法
自定义音频采集
本节介绍如何实现自定义音频采集。
参考以下调用时序图,在你的 App 中实现自定义音频采集:
API 调用步骤
本节介绍如何实现自定义音频采集。
参考如下步骤,在你的项目中实现自定义音频采集功能:
-
调用
joinChannel
加入频道前,调用setExternalAudioSource
开启和配置自定义音频采集。C++// 指定自定义音频源
m_rtcEngine->setExternalAudioSource(true, m_capAudioInfo.sampleRate, m_capAudioInfo.channels);
// 本地用户加入频道
ChannelMediaOptions option;
option.autoSubscribeAudio = true;
option.autoSubscribeVideo = true;
m_rtcEngine->joinChannel("Your token", szChannelId.c_str(), 0, option); -
使用 SDK 外部方法自行实现音频的采集和处理。
-
调用
pushAudioFrame
,将音频帧发送给 SDK,留作备用。C++mediaEngine->pushAudioFrame(AUDIO_RECORDING_SOURCE, &m_audioFrame);
自定义音频渲染
本节介绍如何实现自定义音频渲染。你可以采用如下两种方式实现自定义音频渲染。
参考以下调用时序图,在你的 App 中实现自定义音频渲染:
-
调用
joinChannel
加入频道前,调用setExternalAudioSink
开启和配置自定义音频渲染。C++// 开启自定义音频渲染
// 采样率 (Hz) 可以设置为 16000,32000,441000 或者 48000
// 声道数可以设置为 1 或 2
nRet = m_rtcEngine->setExternalAudioSink(m_renderAudioInfo.sampleRate, m_renderAudioInfo.channels); -
加入频道后,调用
pullAudioFrame
获取远端用户发送的音频数据。使用你自己的音频渲染器处理音频数据,然后播放已渲染的数据。C++void CAgoraCaptureAduioDlg::PullAudioFrameThread(CAgoraCaptureAduioDlg * self)
{
int nRet = 0;
agora::util::AutoPtr<agora::media::IMediaEngine> mediaEngine;
mediaEngine.queryInterface(self->m_rtcEngine, AGORA_IID_MEDIA_ENGINE);
IAudioFrameObserver::AudioFrame audioFrame;
audioFrame.avsync_type = 0; // 预留参数
audioFrame.bytesPerSample = TWO_BYTES_PER_SAMPLE;
audioFrame.type = agora::media::IAudioFrameObserver::FRAME_TYPE_PCM16;
audioFrame.channels = self->m_renderAudioInfo.channels;
audioFrame.samplesPerChannel = self->m_renderAudioInfo.sampleRate / 100 * self->m_renderAudioInfo.channels;
audioFrame.samplesPerSec = self->m_renderAudioInfo.sampleRate;
audioFrame.buffer = new BYTE[audioFrame.samplesPerChannel * audioFrame.bytesPerSample];
while (self->m_extenalRenderAudio )
{
// 拉取远端音频数据
nRet = mediaEngine->pullAudioFrame(&audioFrame);
if (nRet != 0)
{
Sleep(10);
continue;
}
SIZE_T nSize = audioFrame.samplesPerChannel * audioFrame.bytesPerSample;
self->m_audioRender.Render((BYTE*)audioFrame.buffer, nSize);
}
delete audioFrame.buffer;
}
使用原始音频数据回调
开始前,请确保你的项目中已实现原始音频数据的采集和处理。详见原始音频数据。
参考如下步骤,在你的项目中调用原始音频数据 API 实现自定义音频渲染:
- 从
onRecordAudioFrame
,onPlaybackAudioFrame
,onMixedAudioFrame
或者onPlaybackAudioFrameBeforeMixing
获取待播放的音频数据。 - 自行渲染并播放远端音频数据。
参考信息
示例项目
声网提供了开源的音频自采集和音频自渲染的示例项目供你参考,你可以前往下载或查看其中的源代码。