原始音频数据

更新时间: 2024/03/15 17:25:03

NERTC SDK 的音频模块会严格控制声音设备的采集和播放逻辑,同时支持对采集到的音视频原始数据进行自定义的前处理和后处理,获取想要的播放效果。适用于非标设备接入、自定义音频效果、语音处理、语音识别等场景。

  • 前处理:在音频数据发送到编码器前获取原始的音频数据进行修改,主要针对本地麦克风采集到的音频数据或自定义外部音频流。
  • 后处理:即在音频数据发送给解码器后获取原始的音频数据进行修改,主要针对接收到的远端用户音频数据。

NERTC SDK 通过提供 NERtcAudioFrameObserver 类,实现采集、修改原始音频数据功能。

前提条件

在使用原始数据处理功能前,请确保您已在项目中实现基本的实时音视频功能。

注意事项

技术原理

rawdata.png

实现方法

API 调用时序

以实现修改采集音频的音频数据为例,API 调用时序如下图所示。

sequenceDiagram
    participant 应用层
    participant NERtcSDK
    应用层->>NERtcSDK: setRecordingAudioFrameParameters
    应用层->>NERtcSDK: setAudioFrameObserver
    NERtcSDK-->>应用层: onRecordFrame
    Note over 应用层, NERtcSDK: 自行处理音频数据
    应用层->>NERtcSDK: onRecordFrame

配置步骤

  1. 设置回调的音频采样率。

  2. 调用 setAudioFrameObserver 方法注册语音观测器,并在该方法中实现一个 NERtcEngineAudioFrameObserver 类。

  3. SDK 返回回调。

  4. 用户拿到音频数据后,需要根据场景自行进行处理。

  5. 完成音频数据处理后,您可以直接进行自播放,或根据场景需求再通过 onRecordFrameonPlaybackFrame 回调发送给 SDK。

示例项目源码

网易云信提供原始音频数据的示例项目源码 RawAudioCallback ,您可以参考该源码实现采集和修改原始音频数据。

示例代码

///设置音频回调参数
NERtcAudioFrameRequestFormat formatMix = new NERtcAudioFrameRequestFormat();
    formatMix.setChannels(channel);
    formatMix.setSampleRate(sampleRate);
    formatMix.setOpMode(readOnly.isChecked() ? NERtcAudioFrameOpMode.kNERtcAudioFrameOpModeReadOnly : NERtcAudioFrameOpMode.kNERtcAudioFrameOpModeReadWrite);
    Log.i(TAG, "AudioCallback ,channel: "+formatMix.getChannels()+ " Mixed Sample:" + formatMix.getSampleRate() + " ReadWrite:" + formatMix.getOpMode());
NERtcEx.getInstance().setMixedAudioFrameParameters(formatMix);
NERtcEx.getInstance().setPlaybackAudioFrameParameters(formatMix);
NERtcEx.getInstance().setRecordingAudioFrameParameters(formatMix);
NERtcEx.getInstance().setAudioFrameObserver(observer);

///音频数据回调处理
observer = new NERtcAudioFrameObserver() {
            @Override
            public void onRecordFrame(NERtcAudioFrame audioFrame) {
                try {
                    if(!isAudioCallbackDump){
                        return;
                    }
                    if (pcmCallbackRecordDump == null) {
                        pcmCallbackRecordDump = createPCMDump("Record_" +audioFrame.getFormat().getChannels()
                                +"_"+ audioFrame.getFormat().getSampleRate());

                        if(pcmCallbackMixDump == null) {
                            Log.e(TAG, "create dump file failed!");
                            return;
                        }
                    }

                    byte[] remaining = new byte[audioFrame.getData().remaining()];
                    audioFrame.getData().get(remaining);
                    pcmCallbackRecordDump.write(remaining);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onPlaybackFrame(NERtcAudioFrame audioFrame) {
                if(!isAudioCallbackDump){
                    return;
                }
                try {

                    if (pcmCallbackPlaybackDump == null) {
                        pcmCallbackPlaybackDump = createPCMDump("PlayBack_" +audioFrame.getFormat().getChannels()
                                +"_"+ audioFrame.getFormat().getSampleRate());
                        if(pcmCallbackMixDump == null) {
                            Log.e(TAG, "create dump file failed!");
                            return;
                        }
                    }

                    byte[] remaining = new byte[audioFrame.getData().remaining()];
                    audioFrame.getData().get(remaining);
                    pcmCallbackPlaybackDump.write(remaining);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onPlaybackAudioFrameBeforeMixingWithUserID(long userID, NERtcAudioFrame audioFrame) {
                if(!isAudioCallbackDump){
                    return;
                }
                try {
                    if(mRemoteUserMap.get(userID) != null){

                        if(mRemoteUserMap.get(userID).audioPCMDump == null){

                            mRemoteUserMap.get(userID).audioPCMDump = createPCMDump("PlayBackUid_"+ userID +"_"+ audioFrame.getFormat().getChannels()
                                    +"_"+ audioFrame.getFormat().getSampleRate());
                            if(mRemoteUserMap.get(userID).audioPCMDump == null){
                                Log.e(TAG, "create dump file failed!");
                                return;
                            }
                        }

                        byte[] remaining = new byte[audioFrame.getData().remaining()];
                        audioFrame.getData().get(remaining);
                        mRemoteUserMap.get(userID).audioPCMDump.write(remaining);

                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onMixedAudioFrame(NERtcAudioFrame audioFrame) {
                if(!isAudioCallbackDump){
                    return;
                }
                try {
                    if (pcmCallbackMixDump == null) {
                        pcmCallbackMixDump = createPCMDump("Mix_" +audioFrame.getFormat().getChannels()
                                +"_"+ audioFrame.getFormat().getSampleRate());
                        if(pcmCallbackMixDump == null) {
                            Log.e(TAG, "create dump file failed!");
                            return;
                        }
                    }

                    byte[] remaining = new byte[audioFrame.getData().remaining()];
                    audioFrame.getData().get(remaining);
                    pcmCallbackMixDump.write(remaining);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

API 参考

方法 功能描述
setRecordingAudioFrameParameters 设置回调的采集音频采样率
setPlaybackAudioFrameParameters 设置回调的播放音频采样率
setMixedAudioFrameParameters 设置回调的混音音频采样率
setAudioFrameObserver 注册语音观测器
onRecordFrame 接收本端输入的采集音频数据回调
onPlaybackFrame 接收本端输入的播放音频数据播放回调
onMixedAudioFrame 接收采集与播放音频混合数据帧回调
onPlaybackAudioFrameBeforeMixingWithUserID 接收远端播放的音频数据帧回调
此文档是否对你有帮助?
有帮助
去反馈
  • 前提条件
  • 注意事项
  • 技术原理
  • 实现方法
  • API 调用时序
  • 配置步骤
  • 示例项目源码
  • 示例代码
  • API 参考