功能描述
音视频传输过程中,我们可以对采集到的音视频数据进行前处理和后处理,获取想要的播放效果。
对于有自行处理音视频数据需求的场景,SDK 提供原始数据功能,你可以在将数据发送给编码器前进行前处理,对捕捉到的语音信号或视频帧进行修改;也可以在将数据发送给解码器后进行后处理,对接收到的语音信号或视频帧进行修改。
Native SDK 通过提供 IAudioFrameObserver
类,实现采集、修改原始音频数据功能。
实现方法
在使用原始数据功能前,请确保你已在项目中完成基本的实时音视频功能。
一 、调用 Java 接口获取原始音频数据
- 加入频道前调用
registerAudioFrameObserver
方法,在此之前,你需要先创建一个IAudioFrameObserver
实例。
示例
rtcEngine.registerAudioFrameObserver(new AudioObserver());
class AudioObserver implements IAudioFrameObserver{
@Override
public boolean onRecordFrame(byte[] samples, int numOfSamples, int bytesPerSample, int channels, int samplesPerSec) {
return true;
}
@Override
public boolean onPlaybackFrame(byte[] samples, int numOfSamples, int bytesPerSample, int channels, int samplesPerSec) {
return true;
}
}
二 、通过 JNI 接口获取原始音频数据
参考如下步骤,在你的项目中实现原始音频数据功能:
- 加入频道前调用
registerAudioFrameObserver
方法注册语音观测器,并在该方法中实现一个IAudioFrameObserver
类。 - 成功注册后,SDK 通过
onRecordAudioFrame
、onPlaybackAudioFrame
、onPlaybackAudioFrameBeforeMixing
或onMixedAudioFrame
回调发送采集到的原始音频数据。 - 用户拿到音频数据后,根据场景需要自行进行处理。完成音频数据处理后,你可以直接进行自播放,或根据场景需求再通过
onRecordAudioFrame
、onPlaybackAudioFrame
、onPlaybackAudioFrameBeforeMixing
或onMixedAudioFrame
回调发送给 SDK。
API 时序图
下图展示使用原始音频数据的 API 调用时序:
示例代码
你可以对照 API 时序图,参考下面的示例代码片段,在项目中实现音频原始数据功能:
#include <jni.h>
#include <android/log.h>
#include <cstring>
#include "IArRtcEngine.h"
#include "IArMediaEngine.h"
#include "video_preprocessing_plugin_jni.h"
class ARAudioFrameObserver : public ar::media::IAudioFrameObserver
{
public:
// 获取录制的音频帧
virtual bool onRecordAudioFrame(AudioFrame& audioFrame) override
{
return true;
}
// 获取播放的音频帧
virtual bool onPlaybackAudioFrame(AudioFrame& audioFrame) override
{
return true;
}
// 获取远端某个用户发送的音频帧
virtual bool onPlaybackAudioFrameBeforeMixing(unsigned int uid, AudioFrame& audioFrame) override
{
return true;
}
// 获取本地录制和播放混音后的音频帧
virtual bool onMixedAudioFrame(AudioFrame& audioFrame) override
{
return true;
}
};
class IAudioFrameObserver
{
public:
enum AUDIO_FRAME_TYPE {
FRAME_TYPE_PCM16 = 0, // 音频数据格式为 PCM 16
};
struct AudioFrame {
AUDIO_FRAME_TYPE type;
int samples; // 该音频帧的帧数
int bytesPerSample; // 每帧的字节数:2
int channels; // 声道数;双声道则音频数据重叠
int samplesPerSec; // 采样率
void* buffer; // 音频数据 Buffer
int64_t renderTimeMs; // 当前音频帧的时间戳
};
public:
virtual bool onRecordAudioFrame(AudioFrame& audioFrame) = 0;
virtual bool onPlaybackAudioFrame(AudioFrame& audioFrame) = 0;
virtual bool onPlaybackAudioFrameBeforeMixing(unsigned int uid, AudioFrame& audioFrame) = 0;
virtual bool onMixedAudioFrame(AudioFrame& audioFrame) = 0;
};
同时,我们在 GitHub 提供一个开源的 Advanced-Video 示例项目。你可以前往下载,或参考 IARMediaEngine.h 文件中的代码。
开发注意事项
本文中使用的原始数据接口为 C++ 接口。如果你在 Android 平台开发,请参考如下步骤
static ARAudioFrameObserver s_audioFrameObserver;
static ar::rtc::IRtcEngine* rtcEngine = NULL;
#ifdef __cplusplus
extern "C" {
#endif
int __attribute__((visibility("default"))) loadARRtcEnginePlugin(ar::rtc::IRtcEngine* engine)
{
rtcEngine = engine;
return 0;
}
void __attribute__((visibility("default"))) unloadARRtcEnginePlugin(ar::rtc::IRtcEngine* engine)
{
rtcEngine = NULL;
}
JNIEXPORT void JNICALL Java_io_ar_propeller_preprocessing_AudioPreProcessing_enablePreProcessing
(JNIEnv *env, jobject obj, jboolean enable)
{
if (!rtcEngine)
return;
ar::util::AutoPtr<ar::media::IMediaEngine> mediaEngine;
mediaEngine.queryInterface(rtcEngine, ar::ar_IID_MEDIA_ENGINE);
if (mediaEngine) {
if (enable) {
mediaEngine->registerAudioFrameObserver(&s_audioFrameObserver);
} else {
mediaEngine->registerAudioFrameObserver(NULL);
}
}
}
#ifdef __cplusplus
}
#endif