更新记录
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音频流录音插件
支持实时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();
上传录音文件
录音完成后,返回的 tempFilePath 是 file:// 格式,可直接用于上传:
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端:
- 使用
AudioRecordAPI 进行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(均方根)算法:
- 将Int16样本归一化到 [-1, 1]
- 计算RMS:
√(Σsample² / count) - 转换为分贝:
dB = 20 * log₁₀(RMS)
分贝范围约为 -96dB(静音)到 0dB(满刻度)。
数据格式
统一输出 16位PCM(小端序,Int16):
- 采样值范围:-32768 到 32767
- 字节序:Little Endian(小端)
- 数据类型:
ArrayBuffer(可转换为Int16Array使用)
📝 注意事项
-
权限管理
- 首次使用需要用户授予录音权限
- Android会自动请求权限,iOS需要在系统设置中手动开启
-
内存管理
onFrameRecorded回调频率较高(默认约40ms一次)- 注意及时处理音频数据,避免内存累积
- 不使用时及时调用
stop()或cancel()
-
采样率选择
- 语音场景:推荐8000Hz或16000Hz,占用空间小
- 音乐场景:推荐44100Hz或48000Hz,音质更好
- iOS实际录音采样率由硬件决定(通常48kHz),插件会自动处理
-
帧大小设置
- 值越小,回调频率越高,实时性越好,但CPU占用也越高
- 语音识别推荐:640样本(40ms @ 16kHz)
- 实时显示推荐:320样本(20ms @ 16kHz)
-
格式选择
- WAV格式:带文件头,可直接播放,文件较大
- PCM格式:纯音频数据,适合实时传输,需要自行处理
-
平台差异
- Android:通过base64传输音频帧(透明处理,无需关心)
- iOS:直接传输ArrayBuffer
- 前端API统一,无需区分平台
🔧 兼容性
| 平台 | 支持情况 | 最低版本 | 备注 |
|---|---|---|---|
| Android | ✅ | API 21 (Android 5.0) | 使用AudioRecord |
| iOS | ✅ | iOS 12.0 | 使用AVAudioEngine |
| Web | ❌ | - | 不支持 |
| 小程序 | ❌ | - | 不支持 |
💬 联系方式
如有问题或建议,欢迎通过以下方式反馈:
- 提交 Issue
- 发送邮件
- DCloud论坛

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 126
赞赏 0
下载 11228448
赞赏 1860
赞赏
京公网安备:11010802035340号