自定义音频采集和渲染

  • Android

更新时间不可用

了解实时互动 RTC 在不同平台上的自定义音频采集和渲染方式,包括接入流程、关键配置和平台差异。

声网默认的音频模块可以满足在 App 中使用基本音频功能的需求。声网 SDK 支持使用自定义的音频源和自定义的音频渲染模块为你的 App 添加特殊的音频功能。

技术原理

实时音频传输过程中,声网 SDK 通常会开启默认的音频模块。在以下场景中,你可能会发现默认的音频模块无法满足开发需求,需要自定义音频采集或自定义音频渲染。例如:

  • App 中已有自己的音频模块。
  • 需要使用前处理库处理采集到的音频。
  • 某些音频采集设备被系统独占。为避免与其他业务产生冲突,需要灵活的设备管理策略。

使用自定义音频源管理音频帧的采集、处理和播放时,需要使用声网 SDK 外部方法。

音频数据传输

下图展示在自定义音频采集、音频渲染时,音频数据的传输过程。

自定义音频采集

  • 你需要使用 SDK 外部方法自行实现采集模块。
  • 调用 pushExternalAudioFrame,将采集到的音频帧发送给 SDK。

自定义音频渲染

  • 你需要使用 SDK 外部方法自行实现渲染模块。
  • 调用 pullPlaybackAudioFrame 获取远端用户发送的音频数据。

前提条件

在进行操作之前,请确保你已经在项目中实现了基本的实时音视频功能。详见实现音视频互动。

实现方法

自定义音频采集

本节介绍如何实现自定义音频采集。

参考以下调用时序图,在你的 App 中实现自定义音频采集:

API 调用步骤

参考如下步骤,在你的项目中实现自定义音频采集功能:

  1. 创建自定义音频轨道

    初始化 RtcEngine 后,调用 createCustomAudioTrack 创建自定义音频轨道并获得音频轨道 ID。

    Java
    AudioTrackConfig config = new AudioTrackConfig();
    config.enableLocalPlayback = false;
    customAudioTrack = engine.createCustomAudioTrack(Constants.AudioTrackType.AUDIO_TRACK_MIXABLE, config);
  2. 加入频道并发布自定义音频轨道

    调用 joinChannel[2/2] 加入频道, 在 ChannelMediaOptions 中,将 publishCustomAudioTrackId 参数设置为步骤 1 中获得的音频轨道 ID,并将 publishCustomAudioTrack 设置为 true,即可在频道中发布指定的自定义音频轨道。

    注意

    如需调用 enableCustomAudioLocalPlayback 在本地播放外部音频源,或调用 adjustCustomAudioPlayoutVolume 调节自定义音频采集轨道在本地播放的音量,请将 ChannelMediaOptions 中的 enableAudioRecordingOrPlayout 设置为 true。

    Java
    ChannelMediaOptions option = new ChannelMediaOptions();
    option.clientRoleType = Constants.CLIENT_ROLE_BROADCASTER;
    option.autoSubscribeAudio = true;
    option.autoSubscribeVideo = true;
    // 音频自采集场景下,不发布麦克风采集的音频
    option.publishMicrophoneTrack = false;
    // 发布自采集音频流
    option.publishCustomAudioTrack = true;
    // 设置自定义音频轨道 ID
    option.publishCustomAudioTrackId = customAudioTrack;
    // 加入频道
    int res = engine.joinChannel(accessToken, channelId, 0, option);
  3. 实现自采集模块

    声网提供了 AudioFileReader.java 示例项目,演示从本地文件读取 PCM 格式的音频数据。在实际项目中,你需要结合业务创建自定义音频采集模块。

  4. 通过自定义音频轨道推送音频数据到 SDK

    调用 pushExternalAudioFrame 将采集到的音频帧通过自定义音频轨道推送至 SDK。其中,trackId 要与步骤 2 加入频道时指定的音频轨道 ID 一致,sampleRate、channels 和 bytesPerSample 用于设置外部音频帧的采样率、声道数和每个采样点的字节数。

    信息

    为确保音视频同步,声网建议你调用 getCurrentMonotonicTimeInMs 获取当前的 Monotonic Time,将 timestamp(时间戳)设置为系统 Monotonic Time。

    Java
    audioPushingHelper = new AudioFileReader(requireContext(), (buffer, timestamp) -> {
        if (joined && engine != null && customAudioTrack != -1) {
            // 推送外部音频帧至 SDK
            int ret = engine.pushExternalAudioFrame(buffer, timestamp,
                    AudioFileReader.SAMPLE_RATE,
                    AudioFileReader.SAMPLE_NUM_OF_CHANNEL,
                    Constants.BytesPerSample.TWO_BYTES_PER_SAMPLE,
                    customAudioTrack);
            Log.i(TAG, "pushExternalAudioFrame times:" + (++pushTimes) + ", ret=" + ret);
        }
    });
  5. 销毁自定义音频轨道

    如果你需要停止发布自定义采集的音频,调用 destroyCustomAudioTrack 销毁自定义音频轨道。

    Java
    engine.destroyCustomAudioTrack(customAudioTrack);

自定义音频渲染

本节介绍如何实现自定义音频渲染。你可以采用如下两种方式实现自定义音频渲染。

参考以下调用时序图,在你的 App 中实现自定义音频渲染:

  1. 调用 joinChannel 加入频道前,调用 setExternalAudioSink 开启和配置自定义音频渲染。

    Java
     rtcEngine.setExternalAudioSink(
         true,      // 开启自定义音频渲染
         44100,     // 采样率 (Hz)。你可以将该值设置为 16000、32000、44100 或者 48000
         1          // 自定义音频源的声道数。你可以将该值设置为 1 或 2
     );
  2. 加入频道后,调用 pullPlaybackAudioFrame 获取远端用户发送的音频数据。使用你自己的音频渲染器处理音频数据,然后播放已渲染的数据。

    Java
     private class FileThread implements Runnable {
    
         @Override
         public void run() {
             while (mPull) {
                 int lengthInByte = 48000 / 1000 * 2 * 1 * 10;
                 ByteBuffer frame = ByteBuffer.allocateDirect(lengthInByte);
                 int ret = engine.pullPlaybackAudioFrame(frame, lengthInByte);
                 byte[] data = new byte[frame.remaining()];
                 frame.get(data, 0, data.length);
                 // 写入本地文件或由播放器进行渲染
                 FileIOUtils.writeFileFromBytesByChannel("/sdcard/agora/pull_48k.pcm", data, true, true);
                 try {
                     Thread.sleep(10);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
    
             }
         }
     }

使用原始音频数据回调

开始前,请确保你的项目中已实现原始音频数据的采集和处理。详见原始音频数据。

参考如下步骤,在你的项目中调用原始音频数据 API 实现自定义音频渲染:

  1. 从 onRecordAudioFrame,onPlaybackAudioFrame,onMixedAudioFrame 或 onPlaybackAudioFrameBeforeMixing 获取待播放的音频数据。
  2. 自行渲染并播放音频数据。

参考信息

示例项目

声网提供了开源的音频自采集和音频自渲染的示例项目供你参考,你可以前往下载或查看其中的源代码。

API 参考