更新记录

1.0.0(2026-10-20)

2026年10月20日首次上传


平台兼容性

uni-app(3.91)

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

sidong-voice-stream

App 端实时音频帧采集(PCM) —— 解决 uni-app 在 App 端拿不到实时音频帧的痛点。

uni.getRecorderManager() 的 onFrameRecorded / frameSize 官方标注「App 暂不支持」,只能录完整段拿到文件。 本插件用原生 AudioRecord 采集 PCM,由 JS 定时 read() 取走小块数据,即可实现:

  • 流式语音识别(边说边出字 / 边录边传)
  • 实时音频上传(如自定义 ASR、实时字幕)
  • 实时音量/波形分析
  • 边录边存(自己拼接 PCM → wav)

平台支持

平台 支持 说明
App-Android ✅ 原生 AudioRecord,本插件主要实现
App-iOS ❌ 暂未实现(isSupported() 返回 false,可自行回退到整段录音)
App-HarmonyOS ❌ 暂未实现
H5 / 小程序 ❌ isSupported() 返回 false;H5 可用浏览器 getUserMedia,微信小程序可用 onFrameRecorded

未实现的平台不会报错:isSupported() 返回 false,请自行回退到「录音 → 上传」。

兼容性说明:本插件为 UTS 插件,在 uni-app(Vue2/Vue3) 已实测;uni-app x 未做验证 (接口本身是 UTS 标准写法,但请在 uni-app x 项目里自行验证后再用于生产)。

安装

  1. 插件市场安装,或把 uni_modules/sidong-voice-stream 放入项目。
  2. App 端需要麦克风权限:本插件已自带 app-android/AndroidManifest.xml(RECORD_AUDIO、MODIFY_AUDIO_SETTINGS), 运行时权限由插件内部用 UTSAndroid.requestSystemPermission 自动申请。
  3. 含原生代码,必须打自定义基座(标准基座不含插件原生实现)。

API

import { isSupported, start, read, stop, isRecording, dropped } from '@/uni_modules/sidong-voice-stream';
方法 说明
isSupported(): boolean 当前平台是否支持
start(options): void 申请麦克风权限并开始采集
read(): string 取走自上次调用后新采集的裸 PCM(Base64,16bit 小端);无新数据返回 ''(非阻塞)
stop(): void 停止并释放(可重复调用,不抛错)
isRecording(): boolean 是否正在采集
dropped(): string 因缓冲溢出被丢弃的字节数(诊断用)

start(options)

参数 类型 默认 说明
sampleRate number 16000 采样率,取值 8000/11025/16000/22050/32000/44100/48000
audioSource string 'recognition' 'recognition'=VOICE_RECOGNITION(适合识别,一般无 AGC);'mic'=MIC(通用麦克风)
maxBufferBytes number 4194304 内部缓冲上限(64KB~16MB);溢出会丢弃最旧的一半
readChunkBytes number 3200 原生每次读取块大小(320~64KB)
success function - 开始成功
fail function - { errCode, errMsg }
complete function - 成功/失败都会调用

错误码

errCode 含义
1001 麦克风权限被拒绝
1002 启动录音失败(设备不支持 / 被占用)
1003 参数不合法(sampleRate / audioSource / maxBufferBytes / readChunkBytes)

示例:定时取帧(推荐 40ms 一次)

import { isSupported, start, read, stop, dropped } from '@/uni_modules/sidong-voice-stream';

let timer = null;

function begin() {
  if (!isSupported()) {
    uni.showToast({ title: '当前平台不支持', icon: 'none' });
    return;
  }
  start({
    sampleRate: 16000,
    success() {
      timer = setInterval(() => {
        const base64 = read();          // 自上次以来新采集的 PCM(Base64)
        if (!base64) return;
        // TODO:把 base64 发出去(WebSocket 分帧 / 上传 / 自己拼接保存)
        console.log('新帧字节数≈', Math.floor(base64.length * 3 / 4));
      }, 40);
    },
    fail(e) {
      uni.showToast({ title: e.errMsg || '无法开始录音', icon: 'none' });
    }
  });
}

function end() {
  clearInterval(timer);
  timer = null;
  stop();
  console.log('丢弃字节数=', dropped());
}

你也可以在 setInterval 里直接对 read() 的结果做 base64 解码(小程序/App 可用 uni.base64ToArrayBuffer), 或按固定字节数切片后再分帧(切 base64 请按 4 的整数倍 字符切,保证每片可独立解码)。

隐私与权限声明(发布时可直接填入市场表单)

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

权限 用途 申请时机
android.permission.RECORD_AUDIO 麦克风录音:采集实时音频帧(PCM) 仅在调用 start() 时由插件弹出系统权限申请;用户拒绝则 fail 回调返回 errCode=1001
android.permission.MODIFY_AUDIO_SETTINGS 音频设置:录音相关音频参数调整 随录音能力一并申请

可选硬件特性声明(已在插件 AndroidManifest.xml 中声明,required="false"): android.hardware.microphone —— 无麦克风的设备也可安装,但本插件功能不可用。

除以上两项外不再申请任何权限(不申请存储、网络、位置、后台服务、通知等)。

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

本插件不采集、不存储、不上传任何数据。

  • 插件源码中不包含任何网络请求(无 http / WebSocket / Socket 代码),也没有内置任何服务器地址;
  • 音频数据仅存在于 App 内存缓冲区(默认上限 4MB,可配置),由调用方通过 read() 主动取走(Base64 字符串); 其后续用途(发送到调用方自有服务、本地保存、语音识别等)完全由调用方代码决定,与本插件无关;
  • 不包含任何第三方 SDK、统计、埋点或广告组件;
  • 调用 stop() 后立即释放录音资源并清空缓冲区。

3. 本插件是否包含广告

否。 无广告、无统计、无埋点。

合规注意事项(仅供接入方参考)

  1. 请先获得用户对隐私政策的同意,再调用 start():插件内直接用系统 API 申请麦克风权限, 建议调用方先通过 uni.getPrivacySetting / uni.requirePrivacyAuthorize(或自有隐私弹窗)确认用户已同意, 否则可能违反「同意隐私政策前不得申请敏感权限」的合规要求。
  2. 后台录音限制:插件不含前台服务/保活,Android 9+ 在后台长时间录音可能被系统限制(静音或停止)。 需要长时后台录音请自行申请前台服务及相应权限。
  3. 未实现的平台(iOS / HarmonyOS / H5 / 小程序)isSupported() 返回 false,不会申请任何权限、不会执行原生代码。
  4. 用户拒绝权限时请引导其到系统设置开启;插件不会反复弹窗骚扰。

使用注意

  • read() 是拉取式:请用定时器(建议 40~100ms)及时取走,否则内部缓冲填满后会丢弃最旧数据(可用 dropped() 观察)。 之所以设计成拉取而不是原生回调:Kotlin 反向回调 UTS 不被官方保证,容易被 HBuilderX 升级打断;拉取式只依赖「UTS 调 Kotlin」这一稳定方向。
  • 音频固定为单声道 16bit 小端;sampleRate 由你指定。
  • 采集线程在原生侧,stop() 会置停止标志并 join(最多 500ms)后释放,可安全重复调用。
  • 若需要 wav 文件:把每次 read() 的 PCM 依次写入文件,最后补 44 字节 wav 头即可。
  • 后台采集:Android 9+ 后台可能被系统限制(锁屏/切后台久了会静音),如需长时间后台录音请配合前台服务/保活。

常见问题

Q:为什么不用 uni.getRecorderManager().onFrameRecorded? A:该 API 与 frameSize 官方标注「App 暂不支持」(仅部分小程序支持,且只支持 mp3)。所以 App 端要拿实时音频只能走原生采集。

Q:为什么 read() 返回 Base64 而不是 ArrayBuffer? A:跨语言(Kotlin → UTS → JS)传二进制容易出现类型转换问题,Base64 字符串最稳;且 Base64 可直接作为文本帧发给 WebSocket 服务。

Q:iOS 什么时候支持? A:欢迎反馈需求;目前 iOS 请自行回退到整段录音方案。

许可

MIT(可自由用于商业项目)。插件内的原生实现不依赖任何第三方 SDK。

隐私、权限声明

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

android.permission.RECORD_AUDIO(麦克风录音):用于采集实时音频帧(PCM)。 仅在调用 start() 时由插件弹出系统权限申请;用户拒绝则 fail 回调返回 errCode=1001。 android.permission.MODIFY_AUDIO_SETTINGS(音频设置):用于录音相关音频参数调整。 另声明硬件特性 android.hardware.microphone(required=false): 无麦克风的设备也可安装,但本插件功能不可用。 除以上外不再申请任何权限(不申请存储、网络、位置、后台服务、通知等)。

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

本插件不采集、不存储、不上传任何数据,也没有内置任何服务器地址。 1) 音频数据仅存在于 App 内存缓冲区(默认上限 4MB,可配置),由调用方通过 read() 主动取走(Base64 字符串); 其后续用途(发送到调用方自有服务、本地保存、语音识别等)完全由调用方代码决定,与本插件无关。 2) 插件源码中不包含任何网络请求(无 http / WebSocket / Socket 代码),无第三方 SDK、统计、埋点或广告组件。 3) 调用 stop() 后立即释放录音资源并清空缓冲区。 4) 未实现的平台(iOS / HarmonyOS / H5 / 小程序)为安全空实现:isSupported() 返回 false,不申请任何权限、不执行原生代码。

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

无

暂无用户评论。