HarmonyOS 鸿蒙Next中AudioCapturer录音采集readData事件回调频率问题

HarmonyOS 鸿蒙Next中AudioCapturer录音采集readData事件回调频率问题

最近在做录音跟播放,两个功能都遇到问题,首先是录音,先贴代码:

private initAudio(){
    let audioStreamInfo: audio.AudioStreamInfo = {
      samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_8000, // 采样率。
      channels: audio.AudioChannel.CHANNEL_1, // 通道。
      sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式。
      encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式。
    };

    let audioCapturerInfo: audio.AudioCapturerInfo = {
      source: audio.SourceType.SOURCE_TYPE_MIC, // 音源类型:Mic音频源。根据业务场景配置,参考SourceType。
      capturerFlags: 0 // 音频采集器标志。
    };

    let audioCapturerOptions: audio.AudioCapturerOptions = {
      streamInfo: audioStreamInfo,
      capturerInfo: audioCapturerInfo
    };

    audio.createAudioCapturer(audioCapturerOptions, (err, data) => {
      if (err) {
        console.error(`AudioCapturer Created : Error: ${err}`);
      } else {
        console.info('AudioCapturer Created : Success : SUCCESS');
        this.audioCapturer = data;
        AudioManager.instance.initCapturerEvent();
      }
    });
  }

上面是初始化代码,我选择8K 16bit 单声道采样,然后在下面的方法获取采集的回调

private initCapturerEvent(){
    if (!this.audioCapturer) return;
    this.audioCapturer.on("readData", (buffer:ArrayBuffer)=>{
      console.log(buffer.byteLength.toString());
      if (buffer.byteLength > 0) {
           // 

      }
    })
  }

在readData 事件中,获取到录音数据回调,每一帧的长度是320byte,这个是对的,但是回调的频率不对,正常一帧是20ms,也就是说20ms要回调一次才能保证录音的连贯,但是实际是1秒回调一次,我不知道我哪里做错了,请大家帮忙看看,谢谢🙏


更多关于HarmonyOS 鸿蒙Next中AudioCapturer录音采集readData事件回调频率问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

12 回复

伙伴您好,在真机上验证没有问题,建议切换到真机验证。或者重启模拟器试下。

更多关于HarmonyOS 鸿蒙Next中AudioCapturer录音采集readData事件回调频率问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


20ms的数据量计算应为:8000Hz * 16bit * 1通道 * 0.02秒 = 320字节,而实际回调间隔1秒说明系统分配的缓冲区远大于该值

现在我从回调接口拿到的数据只有320字节,我试试你提供的办法看看,非常感谢!

AudioCapturerreadData回调频率由音频流参数和系统调度机制共同决定。看了下你的代码因为readData回调频率与bufferSize参数直接相关,如果没有显式设置缓冲区大小,系统可能会基于samplingRatesampleFormat自动计算默认值。当bufferSize设置过大时,会导致回调间隔变长。通过AudioCapturerOptions.streamInfo补充bufferSize参数:

let audioStreamInfo: audio.AudioStreamInfo = {
  samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_8000,
  channels: audio.AudioChannel.CHANNEL_1,
  sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
  encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW,
  bufferSize: 320 // 根据20ms数据量设置
};

在订阅readData回调后,必须调用start()方法激活音频采集:

private initCapturerEvent() {
  if (!this.audioCapturer) return;
  this.audioCapturer.on("readData", (buffer: ArrayBuffer) => {
    console.log(`Buffer size: ${buffer.byteLength}`);
    // 处理音频数据
  });

  // 启动音频采集
  this.audioCapturer.start((err: BusinessError) => {
    if (err) {
      console.error(`Capturer start failed: ${err.message}`);
    }
  });
}

不行,audio.AudioStreamInfo没有bufferSize的构造方法,无法编译。

请问你用的是哪个版本的API,如果可以,我也去试试看,

我是API20,

通过 on(‘readData’) 订阅音频数据回调时,系统会根据实际硬件性能和数据传输效率动态调整每次回调的数据块大小(即 ArrayBuffer 的 byteLength)。这个数据块大小一般与系统计算的缓冲区大小一致。

若需限制单次处理的数据量,可以通过以下方式间接实现:

在 readData 回调中,将接收到的 ArrayBuffer 按需分块处理,这个官方文档有示例代码:

let bufferSize: number = 0;
let readDataCallback = (buffer: ArrayBuffer) => {
    let options: Options = { offset: bufferSize, length: buffer.byteLength };
    fs.writeSync(file.fd, buffer, options);
    bufferSize += buffer.byteLength;
};
audioCapturer.on('readData', readDataCallback);

我出现的问题是,回调的总数据长度,很明显低于实际录音数据长度(1秒的录音,只有一帧的数据)。当固定采样率、编码等信息时,任何系统的录音输出数据长度应该都是一致的。我用模拟器试了不同采样率的录音,都是每秒回调一次,并且每次回调的数据大小都是对的(即每帧的数据大小是对的)。

补充一下,我现在的版本是API18,5.1.0。另外用的是模拟器测试,非真机

在鸿蒙Next中,AudioCapturerreadData事件回调频率由音频采样率、帧大小和缓冲区配置决定。回调触发条件为缓冲区数据填满时,计算公式为:

回调频率=采样率/(缓冲区大小/每帧字节数)

若采样率为48kHz,16位单声道,缓冲区设置为4800字节,则回调频率为100Hz(10ms一次)。可通过setBufferSizeInBytes()调整缓冲区大小来改变回调间隔。系统默认采用低延迟策略,实际频率可能因硬件性能微调。

根据您提供的代码和描述,问题可能出在AudioCapturer的缓冲区设置上。在HarmonyOS Next中,AudioCapturer的readData回调频率是由缓冲区大小和采样参数共同决定的。

对于8K采样率、16bit、单声道的配置,20ms的数据量确实是320字节(800020.02=320)。但默认情况下系统可能使用了较大的缓冲区,导致回调间隔变长。

建议您尝试以下修改:

  1. 在AudioCapturerOptions中添加bufferSizeInBytes参数:
let audioCapturerOptions: audio.AudioCapturerOptions = {
  streamInfo: audioStreamInfo,
  capturerInfo: audioCapturerInfo,
  bufferSizeInBytes: 320 // 设置为20ms的数据量
};
  1. 确保在开始采集前正确设置了回调:
this.audioCapturer.on("readData", callback);
this.audioCapturer.start();

如果问题仍然存在,可能需要检查系统音频服务的配置或设备硬件支持情况。

回到顶部