菊风已发布实时音视频2.0升级版(2.0版本说明),当前您正在访问1.0旧版本,点击此处可进入2.0升级版

# 自定义音频采集和渲染

# 简介

实时音频传输过程中,JCSDK 会启动默认的音频模块进行采集和渲染。当遇到不支持系统标准 API 的音频设备的时候,或者希望使用自己已经拥有的音频模块进行音频采集和渲染的时候,您可以选择在音频被采集前自定义音频采集,也可以选择在音频播放前自定义音频渲染

# 前提条件

在自定义音频采集和渲染前,确保已经初始化了 JCMediaDevice 模块。

# 自定义音频采集

参照下述步骤,在音频输入前,修改音频输入源和采样率等参数:

  1. 发起通话前,将 JCMediaDevice (opens new window)audioParam (opens new window)autoStartAudioInputDevice 设置为 false。这种情况下才可以获取音频输入数据。
  2. 调用 inputCustomAudioData (opens new window) 自定义音频采集。 建议在一对一通话状态为连接中时或者加入频道成功后,在工作线程中不断调用此方法传入音频数据。
  3. 在结束通话的时候,停止工作线程,结束音频采集。
import { JCMediaDevice, JCCall, JCMediaChannel } from "@juphoon/jcsdk";
import { ByteBuffer } from "@ohos/util";

// 在开启前将 autoStartAudioInputDevice 属性设为 false
function turnOffAutoStartAudioInputDevice(mediaDevice: JCMediaDevice): void {
  mediaDevice.audioParam.autoStartAudioInputDevice = false;
}

// 自定义音频采集任务
class CustomAudioInputTask {
  private isRunning: boolean = false;
  private mediaDevice: JCMediaDevice;
  private call: JCCall | null;
  private mediaChannel: JCMediaChannel | null;

  constructor(
    mediaDevice: JCMediaDevice,
    call: JCCall | null = null,
    mediaChannel: JCMediaChannel | null = null
  ) {
    this.mediaDevice = mediaDevice;
    this.call = call;
    this.mediaChannel = mediaChannel;
  }

  // 开始自定义音频采集
  public start(): void {
    if (this.isRunning) {
      return;
    }

    this.isRunning = true;
    this.runAudioInputTask();
  }

  // 停止自定义音频采集
  public stop(): void {
    this.isRunning = false;
  }

  // 执行自定义音频采集
  private async runAudioInputTask(): Promise<void> {
    const sampleRateHz = 8000;
    const channels = 1;

    // 示例:创建自定义音频数据
    const text = "自定义音频数据示例";
    const encoder = new TextEncoder();
    const value = encoder.encode(text);

    // 创建直接缓冲区
    const buffer = new ByteBuffer(value.length);
    buffer.writeBytes(value);
    buffer.flip();

    // 循环输入音频数据
    while (
      this.isRunning &&
      ((this.call && this.call.getActiveCallItem() !== null) ||
        (this.mediaChannel &&
          this.mediaChannel.getState() === JCMediaChannel.STATE_JOINED))
    ) {
      this.mediaDevice.inputCustomAudioData(
        sampleRateHz,
        channels,
        buffer,
        0,
        0,
        0
      );

      // 等待10ms
      await new Promise<void>((resolve) => {
        setTimeout(resolve, 10);
      });
    }

    this.isRunning = false;
  }
}

# 自定义音频渲染

参照下述步骤,在音频播放前,修改音频输出参数:

  1. 发起通话前,将 JCMediaDevice (opens new window)audioParam (opens new window)autoStartAudioOutputDevice 设置为 false。这种情况下才可以获取音频输出数据。
  2. 调用 getAudioOutputData (opens new window) 自定义音频渲染。建议在一对一通话状态为连接中时或者加入频道成功后,在工作线程中不断调用此方法渲染音频数据。
  3. 在结束通话的时候,停止工作线程,结束音频渲染。
import { JCMediaDevice, JCCall, JCMediaChannel } from "@juphoon/jcsdk";
import { ByteBuffer } from "@ohos/util";

// 在开启前将 autoStartAudioOutputDevice 属性设为 false
function turnOffAutoStartAudioOutputDevice(mediaDevice: JCMediaDevice): void {
  mediaDevice.audioParam.autoStartAudioOutputDevice = false;
}

// 自定义音频渲染任务
class CustomAudioOutputTask {
  private isRunning: boolean = false;
  private mediaDevice: JCMediaDevice;
  private call: JCCall | null;
  private mediaChannel: JCMediaChannel | null;

  constructor(
    mediaDevice: JCMediaDevice,
    call: JCCall | null = null,
    mediaChannel: JCMediaChannel | null = null
  ) {
    this.mediaDevice = mediaDevice;
    this.call = call;
    this.mediaChannel = mediaChannel;
  }

  // 开始自定义音频渲染
  public start(): void {
    if (this.isRunning) {
      return;
    }

    this.isRunning = true;
    this.runAudioOutputTask();
  }

  // 停止自定义音频渲染
  public stop(): void {
    this.isRunning = false;
  }

  // 执行自定义音频渲染
  private async runAudioOutputTask(): Promise<void> {
    const sampleRateHz = 8000;
    const channels = 1;

    // 创建用于获取音频输出数据的缓冲区
    // 计算每10ms的数据大小: 采样率 * 每个样本字节数(短整型2字节) * 通道数 / 100
    const bufferSize = Math.floor((sampleRateHz / 100) * 2 * channels);
    const buffer = new ByteBuffer(bufferSize);

    // 循环获取并处理音频数据
    while (
      this.isRunning &&
      ((this.call && this.call.getActiveCallItem() !== null) ||
        (this.mediaChannel &&
          this.mediaChannel.getState() === JCMediaChannel.STATE_JOINED))
    ) {
      // 获取音频输出数据
      this.mediaDevice.getAudioOutputData(sampleRateHz, channels, buffer);

      // 在这里对buffer中的音频数据进行处理和渲染
      // 例如:播放到扬声器、进行音频处理等

      // 等待10ms,与音频帧率匹配
      await new Promise<void>((resolve) => {
        setTimeout(resolve, 10);
      });
    }

    this.isRunning = false;
  }
}
最后更新时间: 2025-5-13 6:06:58 ├F10: PM┤