更新记录

1.0.0(2026-02-12)

首个正式完善发布版本 实现实时PCM音频流回调,支持边录边获取原始音频数据 支持实时分贝监测,帧回调中直接返回当前音量值 提供完整的录音控制:开始、停止、暂停、恢复、取消 Android/iOS双端适配,统一API,纯UTS实现无需原生代码


平台兼容性

uni-app(4.0)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android Android插件版本 iOS 鸿蒙
- - - - - - 5.0 1.0.0 12 -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

其他

多语言 暗黑模式 宽屏模式

Android iOS录音管理器 - 实时PCM音频流录音插件

uni-app Platform

支持实时PCM帧回调的uni-app录音插件,提供流式音频数据处理能力,适用于语音识别、实时转写、波形显示等场景。纯UTS实现,Android/iOS双端适配。

✨ 核心特性

  • 实时PCM音频流 - 边录边获取原始PCM数据,延迟低至40ms
  • 实时分贝监测 - RMS算法计算,实时返回音量分贝值
  • 流式数据处理 - 支持边录边传、边录边识别等流式场景
  • WAV文件保存 - 自动保存为标准WAV格式,支持file://直接上传
  • Android/iOS - 双端适配,统一API,透明处理平台差异
  • 暂停/恢复 - 支持录音过程中暂停和恢复
  • 纯UTS实现 - 无需原生代码,开箱即用

📦 安装

将插件目录复制到项目的 uni_modules 目录下即可。

your-project/
  └── uni_modules/
      └── dh-recorder/

🔐 权限说明

Android

自动声明录音权限:android.permission.RECORD_AUDIO

iOS

需要在 Info.plist 中添加麦克风权限说明(插件已自动配置):

<key>NSMicrophoneUsageDescription</key>
<string>需要使用麦克风进行录音</string>

🚀 快速开始

基本使用

import { getRecorderManager } from '@/uni_modules/dh-recorder';

// 获取录音管理器实例(单例)
const recorderManager = getRecorderManager();

// 监听录音开始
recorderManager.onStart(() => {
  console.log('🎙️ 录音开始');
});

// 监听录音帧数据(核心功能)
recorderManager.onFrameRecorded((res) => {
  const { frameBuffer, base64, isLastFrame, decibel } = res;

  // Android: res.frameBuffer 通过base64解码得到
  // iOS: res.frameBuffer 直接传输
  const arrayBuffer = frameBuffer || (base64 ? uni.base64ToArrayBuffer(base64) : undefined);

  if (arrayBuffer) {
    console.log('帧数据大小:', arrayBuffer.byteLength); // 如: 1280字节
    console.log('当前分贝:', decibel); // 如: -35.2 dB
    console.log('是否最后一帧:', isLastFrame); // false
  }
  // 可以在这里实时处理音频数据
  // 例如:发送到语音识别服务、实时显示波形等
});

// 监听录音停止
recorderManager.onStop((res) => {
  console.log('📁 录音文件:', res.tempFilePath); // file://格式路径
  console.log('⏱️  录音时长:', res.duration, 'ms');
  console.log('📦 文件大小:', res.fileSize, 'bytes');
});

// 监听错误
recorderManager.onError((err) => {
  console.error('❌ 录音错误:', err.errCode, err.errMsg);
});

// 开始录音
recorderManager.start({
  sampleRate: 16000, // 采样率:16kHz(推荐语音场景)
  numberOfChannels: 1, // 声道数:单声道
  bitsPerSample: 16, // 位深:16位
  frameSize: 640, // 帧大小:640样本 ≈ 40ms @ 16kHz
  format: 'wav', // 格式:WAV
});

// 停止录音
recorderManager.stop();

上传录音文件

录音完成后,返回的 tempFilePathfile:// 格式,可直接用于上传:

recorderManager.onStop((res) => {
  if (res.success && res.tempFilePath) {
    uni.uploadFile({
      url: 'https://your-server.com/upload',
      filePath: res.tempFilePath, // file://格式,可直接上传
      name: 'audioFile',
      formData: {
        duration: res.duration,
        fileSize: res.fileSize,
      },
      success: (uploadRes) => {
        console.log('✅ 上传成功:', uploadRes.data);
      },
      fail: (err) => {
        console.error('❌ 上传失败:', err);
      },
    });
  }
});

暂停和恢复

// 监听暂停事件
recorderManager.onPause(() => {
  console.log('⏸️ 录音已暂停');
});

// 监听恢复事件
recorderManager.onResume(() => {
  console.log('▶️ 录音已恢复');
});

// 暂停录音
recorderManager.pause();

// 恢复录音
recorderManager.resume();

// 取消录音(不保存文件)
recorderManager.cancel();

📖 API文档

getRecorderManager()

获取录音管理器单例。

返回值: IRecorderManager

RecorderManager 实例方法

start(options)

开始录音。

参数:

参数名 类型 必填 默认值 说明
sampleRate number 16000 采样率(Hz),常用值:8000/16000/44100/48000
numberOfChannels number 1 声道数:1=单声道,2=立体声
bitsPerSample number 16 位深,支持:8/16/24/32
frameSize number 640 帧大小(样本数)。16位时:640样本=1280字节≈40ms@16kHz
format string 'wav' 录音格式:'wav' 或 'pcm'

帧大小(frameSize)说明:

  • 样本数,不是字节数
  • 16位PCM:1样本 = 2字节
  • 例如:640样本 = 1280字节 ≈ 40ms @ 16kHz
  • 值越小回调频率越高,实时性越好,但CPU占用也越高

stop()

停止录音。停止后会触发 onStop 回调,返回录音文件路径。

pause()

暂停录音。暂停后会触发 onPause 回调。

resume()

恢复录音。恢复后会触发 onResume 回调。

cancel()

取消录音。取消后不保存文件,不触发 onStop 回调。

onStart(callback)

监听录音开始事件。

回调参数:

onStop(callback)

监听录音停止事件。

回调参数:

{
  success: boolean; // 是否成功
  tempFilePath: string; // 录音文件路径(file://格式,可直接用于上传)
  duration: number; // 录音总时长(毫秒)
  fileSize: number; // 文件大小(字节)
}

路径格式示例:

  • Android: file:///data/user/0/com.xxx.xxx/cache/dh_record_1234567890.wav
  • iOS: file:///var/mobile/Containers/Data/Application/.../tmp/dh_record_1234567890.wav

onFrameRecorded(callback)

监听录音帧数据事件。这是本插件的核心功能,可实时获取音频数据。

回调参数:

{
  frameBuffer: ArrayBuffer; // 音频帧数据(PCM格式,Int16小端序)
  isLastFrame: boolean; // 是否为最后一帧
  decibel: number; // 当前帧的分贝值(约-96dB到0dB)
}

跨平台差异说明:

  • iOS:frameBuffer是标准的ArrayBuffer,可直接使用DataView等API
  • Android:内部通过base64传输,前端自动解码为ArrayBuffer

onError(callback)

监听录音错误事件。

回调参数:

{
  errCode: number; // 错误码
  errSubject: string; // 错误主题
  errMsg: string; // 错误信息
}

错误码说明:

错误码 说明
8010001 录音权限被拒绝
8010002 录音初始化失败
8010003 录音启动失败
8010004 录音停止失败
8010005 录音过程中发生错误
8010006 参数错误

onPause(callback)

监听录音暂停事件。

回调参数:

onResume(callback)

监听录音恢复事件。

回调参数:

🎯 高级用法

实时语音识别

const recorderManager = getRecorderManager();
const recognitionWS = new WebSocket('wss://asr-api.example.com');

recorderManager.onFrameRecorded((res) => {
  // 实时发送PCM数据到语音识别服务
  if (recognitionWS.readyState === WebSocket.OPEN) {
    recognitionWS.send(res.frameBuffer);
  }
});

recognitionWS.onmessage = (event) => {
  const result = JSON.parse(event.data);
  console.log('识别结果:', result.text);
};

recorderManager.start({
  sampleRate: 16000, // 语音识别通常使用16kHz
  numberOfChannels: 1,
  format: 'pcm', // PCM格式,无WAV头,适合实时传输
});

实时音量显示

const recorderManager = getRecorderManager();
const volumeBar = ref(0); // 音量条

recorderManager.onFrameRecorded((res) => {
  // 分贝值约为 -96dB(静音)到 0dB(满刻度)
  // 映射到 0-100 的音量条
  const normalized = Math.max(0, Math.min(100, ((res.decibel + 96) / 96) * 100));
  volumeBar.value = normalized;
});

recorderManager.start({
  sampleRate: 16000,
  numberOfChannels: 1,
  frameSize: 320, // 更小的帧,更高的刷新率(约20ms)
});

录音波形可视化

const recorderManager = getRecorderManager();
const waveformData = ref<number[]>([]);

recorderManager.onFrameRecorded((res) => {
  // 将ArrayBuffer转换为Int16数组
  const int16Array = new Int16Array(res.frameBuffer);

  // 抽样显示(每10个样本取1个)
  const samples: number[] = [];
  for (let i = 0; i < int16Array.length; i += 10) {
    samples.push(int16Array[i] / 32768); // 归一化到[-1, 1]
  }

  // 更新波形数据(保留最近100个点)
  waveformData.value = [...waveformData.value, ...samples].slice(-100);
});

recorderManager.start({
  sampleRate: 16000,
  numberOfChannels: 1,
});

⚙️ 技术实现

架构说明

Android端

  • 使用 AudioRecord API 进行PCM录音
  • 独立线程读取音频数据,避免阻塞主线程
  • ArrayBuffer跨边界问题:Android UTS的ArrayBuffer无法直接传输到JS,采用base64编码传输
  • 数据流程:AudioRecord → ByteBuffer → ByteArray → Base64 → JS解码 → ArrayBuffer

iOS端

  • 使用 AVAudioEngine + installTap 实时获取音频
  • Float32 → Int16转换,兼容标准PCM格式
  • 采样率处理:iOS硬件实际采样率通常是48kHz,插件会自动处理:
    • 保存文件:使用实际采样率(48kHz),保证音质
    • 实时回调:自动降采样到配置采样率(如16kHz),减少传输量
  • 采用简单抽样法降采样(每N个样本取1个),性能高,适合语音场景
  • ArrayBuffer直接传输:iOS可以直接跨JS边界传输ArrayBuffer

分贝计算算法

基于RMS(均方根)算法:

  1. 将Int16样本归一化到 [-1, 1]
  2. 计算RMS:√(Σsample² / count)
  3. 转换为分贝:dB = 20 * log₁₀(RMS)

分贝范围约为 -96dB(静音)到 0dB(满刻度)。

数据格式

统一输出 16位PCM(小端序,Int16):

  • 采样值范围:-32768 到 32767
  • 字节序:Little Endian(小端)
  • 数据类型:ArrayBuffer(可转换为Int16Array使用)

📝 注意事项

  1. 权限管理

    • 首次使用需要用户授予录音权限
    • Android会自动请求权限,iOS需要在系统设置中手动开启
  2. 内存管理

    • onFrameRecorded 回调频率较高(默认约40ms一次)
    • 注意及时处理音频数据,避免内存累积
    • 不使用时及时调用 stop()cancel()
  3. 采样率选择

    • 语音场景:推荐8000Hz或16000Hz,占用空间小
    • 音乐场景:推荐44100Hz或48000Hz,音质更好
    • iOS实际录音采样率由硬件决定(通常48kHz),插件会自动处理
  4. 帧大小设置

    • 值越小,回调频率越高,实时性越好,但CPU占用也越高
    • 语音识别推荐:640样本(40ms @ 16kHz)
    • 实时显示推荐:320样本(20ms @ 16kHz)
  5. 格式选择

    • WAV格式:带文件头,可直接播放,文件较大
    • PCM格式:纯音频数据,适合实时传输,需要自行处理
  6. 平台差异

    • Android:通过base64传输音频帧(透明处理,无需关心)
    • iOS:直接传输ArrayBuffer
    • 前端API统一,无需区分平台

🔧 兼容性

平台 支持情况 最低版本 备注
Android API 21 (Android 5.0) 使用AudioRecord
iOS iOS 12.0 使用AVAudioEngine
Web - 不支持
小程序 - 不支持

💬 联系方式

如有问题或建议,欢迎通过以下方式反馈:

  • 提交 Issue
  • 发送邮件
  • DCloud论坛

隐私、权限声明

1. 本插件需要申请的系统权限列表:

麦克风权限

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件会访问麦克风进行录音

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。