更新记录

1.0.0(2026-07-16)

自用,自用,自用,不做任何保障,慎重购买

仅支持安卓和H5 仅支持安卓和H5 仅支持安卓和H5


平台兼容性

uni-app(5.15)

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

tki-audio-recorder

音频录制插件,支持实时 PCM 帧数据回调、PCM 流播放、通话模式(AEC + NS + AGC)。

适用于:H5(AudioWorklet)、Android(AudioRecord)、iOS(AVAudioEngine,不确定)。


目录


安装

通过 uni_modules 安装(推荐)

在 HBuilderX 中右键项目目录 → 插件市场 → 搜索 tki-audio-recorder → 点击安装。

手动安装

uni_modules/tki-audio-recorder 目录复制到项目的 uni_modules/ 目录下。

配置

Android: 插件会自动处理录音权限。Android 6.0+ 需要运行时权限,插件内部已处理。

iOS: 项目 manifest.jsonApp模块配置 → 勾选 AVFoundation(音频录制和播放)。

如果需要配置隐私权限描述,可在 manifest.jsoniOS 节点下添加:

{
  "plist": {
    "NSMicrophoneUsageDescription": "需要麦克风权限以录制音频"
  }
}

快速开始

import {
  recordStart,
  recordStop,
  onRecordStop,
  onRecordError,
  onRecordTimer,
} from '@/uni_modules/tki-audio-recorder'

// 1. 开始录音
recordStart({
  sampleRate: 16000,
  enableCommunicationMode: true,
  format: 'wav',
})

// 2. 监听录音结束
onRecordStop((info) => {
  console.log('录音结束,时长:', info.duration, '秒')
  console.log('WAV 文件:', info.tempFilePath) // 可用于播放或上传
})

// 3. 停止录音
setTimeout(() => {
  recordStop()
}, 5000) // 5 秒后停止

// 4. 回放录音
onRecordStop((info) => {
  if (info.tempFilePath) {
    const audio = uni.createInnerAudioContext()
    audio.src = info.tempFilePath
    audio.play()
  }
})

API 文档

录音控制


recordStart(options?)

开始录音。需要提前获取麦克风权限(H5 浏览器会自动弹权限请求,App 端插件内部处理)。

recordStart({
  sampleRate: 16000,             // 采样率,默认 16000
  numberOfChannels: 1,           // 声道数,默认 1(单声道)
  format: 'wav',                 // 录音格式:'wav' 或 'pcm'
  duration: 0,                   // 录音时长限制(ms),0=不限时
  bufferSize: 4096,              // onRecordFrame 回调触发阈值
  enableCommunicationMode: true, // 通话模式(含 AEC+NS+AGC)
})

注意

  • format='wav':录音结束后生成 WAV 文件并通过 onRecordStop 返回文件路径
  • format='pcm':仅通过 onRecordFrame 回调原始 PCM 数据,不生成文件
  • 如果已处于录音状态,重复调用会被忽略

recordStop()

停止录音。

  • format='wav' 时,触发 onRecordStoptempFilePath 为 WAV 文件的完整路径
  • format='pcm' 时,tempFilePath 为空字符串

recordPause()

暂停录音。麦克风仍然占用,暂停数据采集和计时。


recordResume()

恢复录音。计时从中断处继续。


recordMute()

静音。停止 onRecordFrame / onRecordDecibel / onRecordWaveform 回调,但 PCM 数据继续写入文件(写入静音数据,时长正确)。

适用于:需要停止 UI 刷新但不想中断录音的场景(如暂时不想暴露频谱)。


recordUnmute()

取消静音,恢复所有回调。


录音事件监听


onRecordStop(callback)

监听录音结束。回调参数:

onRecordStop((info: RecordEndInfo) => {
  console.log(info.tempFilePath)  // WAV 文件路径(format='wav' 时)
  console.log(info.duration)      // 录音时长(秒)
  console.log(info.fileSize)      // 文件大小(字节)
  console.log(info.interrupted)   // 是否被外部中断
})

onRecordError(callback)

监听录音错误。

onRecordError((err: ErrorInfo) => {
  console.log(err.errCode)  // 错误码
  console.log(err.errMsg)   // 错误描述
})

错误码说明

错误码 说明
9010001 录音初始化失败
9010002 录音启动失败(权限被拒/麦克风被占用)
9010003 录音停止失败
9010004 录音被系统中断(如来电)
9010005 播放器初始化失败
9010006 播放数据无效

onRecordFrame(callback)

监听原始 PCM 帧数据。

回调时机:每次累积的样本数达到 bufferSize 阈值时触发一次。

onRecordFrame((data: ArrayBuffer) => {
  // data: Int16Array.buffer,16-bit 小端序 PCM 数据
  const pcmData = new Int16Array(data)
  console.log('收到帧,样本数:', pcmData.length)
})

注意:每帧样本数等于 bufferSize(默认 4096),约 256ms@16kHz。静音时不触发回调。


onRecordDecibel(callback)

监听实时分贝值(dBFS)。

onRecordDecibel((db: number) => {
  // db: 范围约 -96 ~ 0(-96 ≈ 静音,0 ≈ 最大声)
})

静音时不触发回调。


onRecordWaveform(callback)

监听实时波形数据(FFT 频域)。

onRecordWaveform((arr: number[]) => {
  // arr: 64 个归一化值,范围 [0, 1]
  // 索引 0…63 对应频率 0Hz…8000Hz(@16kHz 采样率)
  // 可用于绘制音频频谱可视化(类似均衡器)

  const bass    = arr.slice(0, 2).reduce((a, b) => a + b, 0) / 2     // ~0~250Hz
  const mid     = arr.slice(2, 32).reduce((a, b) => a + b, 0) / 30   // ~250~4000Hz
  const treble  = arr.slice(32).reduce((a, b) => a + b, 0) / 32      // ~4000~8000Hz
})

三端均为 FFT 频域算法,输出一致的 64 段频谱值。仅 enableCommunicationMode=false 时因采样率不同频率范围会有差异。


onRecordTimer(callback)

监听录音时长(每秒触发一次)。

onRecordTimer((sec: number) => {
  // sec: 已录制秒数(排除暂停时间)
})

录音状态查询

const isRec = isRecording()     // 是否正在录音
const isPau = isRecordPaused()   // 是否暂停中
const isMut = isRecordMuted()    // 是否静音

PCM 播放控制

pcmInit(config?)

初始化 PCM 播放器。重复调用会自动销毁旧实例。

pcmInit({
  inputSampleRate: 16000,  // PCM 数据的采样率
  numChannels: 1,          // 声道数
  bitDepth: 16,            // 位深度(16 或 32)
})

推荐用法:在页面加载时初始化一次,后续复用。


pcmPlay(data)

播放 PCM 音频数据。

// 播放单个 PCM 帧
pcmPlay(arrayBuffer)

// 批量播放
pcmPlay([arrayBuffer1, arrayBuffer2])

data 支持的类型

类型 说明
ArrayBuffer Int16Array.buffer,16-bit 小端序 PCM
string base64 编码的 PCM 数据
ArrayBuffer[] 多个 ArrayBuffer 批量播放
string[] 多个 base64 字符串批量播放

不支持 WAV 文件路径。如需播放 WAV 文件,请使用 uni.createInnerAudioContext()


pcmAppend(data, immediatePlay?)

向播放队列追加 PCM 数据。

pcmAppend(arrayBuffer)               // 入队但不播放
pcmAppend(arrayBuffer, true)         // 入队并立即播放

pcmPause() / pcmResume()

暂停/恢复 PCM 播放。


pcmStop()

停止 PCM 播放,清空播放队列。


pcmReplay()

使用历史数据重新播放(重播从首次 pcmPlay 到最近一次 pcmClear 之间的所有数据)。


pcmClear()

清空播放队列和所有历史数据。


pcmStatus()

获取播放器当前状态。

const status = pcmStatus()
if (status) {
  console.log(status.isPlaying)      // 是否正在播放
  console.log(status.isPaused)       // 是否暂停
  console.log(status.queueLength)    // 队列中待播数据块数
  console.log(status.contextState)   // 上下文状态:'running' | 'suspended' | 'closed'
}

播放事件监听

onPCMStatus((status) => {
  // status 同 pcmStatus() 返回值
})

onPCMError((err) => {
  console.log(err.errCode, err.errMsg)
})

资源销毁

import { recordDestroy, pcmDestroy } from '@/uni_modules/tki-audio-recorder'

// 销毁录音资源(不触发 onRecordStop 回调)
recordDestroy()

// 销毁 PCM 播放器
pcmDestroy()

// 推荐在页面卸载时调用
onUnload(() => {
  recordDestroy()
  pcmDestroy()
})

recordDestroy()pcmDestroy() 已分离,可根据业务场景单独调用。 recordDestroy() 不会触发任何回调(onRecordStop / onRecordError / onRecordFrame 等均被清空)。


RecordOptions 配置项

参数 类型 默认值 说明
sampleRate number 16000 采样率(Hz),常用:8000 / 16000 / 44100
numberOfChannels number 1 声道数:1=单声道,2=立体声
format 'wav' \| 'pcm' 'wav' 'wav'=生成 WAV 文件;'pcm'=仅帧回调
duration number 0 录音时长限制(ms),0=不限时,>=1000 生效
bufferSize number 4096 onRecordFrame 触发阈值(采样点数),默认约 256ms@16kHz
enableCommunicationMode boolean true true=开启 AEC+NS+AGC;false=全部关闭(原始录音)

enableCommunicationMode 各平台实现

平台 true false
H5 getUserMedia 约束全部开启 getUserMedia 约束全部关闭
Android AudioSource.VOICE_COMMUNICATION AudioSource.UNPROCESSED(API 26+)或 MIC
iOS AVAudioSessionModeVoiceChat AVAudioSessionModeDefault

Android 回声消除说明

Android 端启用 enableCommunicationMode: true 只是选择了 VOICE_COMMUNICATION 音频源,硬件 AEC 要真正生效,还需要满足以下条件:

  1. 使用 pcmPlay 播放音频(不能只用 uni.createInnerAudioContext
  2. recordStart() 之前调用 pcmInit(),确保 PCMPlayer 已创建
  3. 在录音进行中播放(停止录音后 sessionId 失效)
// ✅ AEC 生效的正确顺序
pcmInit({ inputSampleRate: 16000 })   // 1. 先创建 PCMPlayer
recordStart({                         // 2. AudioRecord 启动,sessionId=123
  enableCommunicationMode: true,      //    自动传到 PCMPlayer
})
// 录音中...
pcmPlay(data)                         // 3. AudioTrack 用 sessionId=123 创建 ✅ 硬件 AEC
// ❌ AEC 无效的典型错误
recordStart({})                       // 1. 录音启动,但 player==null,sessionId 无法传递
pcmInit({})                           // 2. 新建 player,sessionId=0
pcmPlay(data)                         // 3. AudioTrack 以 sessionId=0 创建 ❌ 无 AEC

原理:Android 硬件 AEC 要求 AudioRecordAudioTrack 使用同一个 audioSessionIdrecordStart 获取真实 sessionId,传给 PCMPlayerpcmPlay 第一次创建 AudioTrack 时使用该 sessionId,系统此时才能挂载硬件 AEC。


RecordEndInfo 回调信息

onRecordStop 回调的参数:

字段 类型 说明
tempFilePath string WAV 文件路径(format='wav' 时有效),可直接用于 uni.createInnerAudioContext
duration number 录音时长(秒),已扣除暂停时间
fileSize number 文件大小(字节)
interrupted boolean 是否被外部中断(如来电)

各平台文件路径格式

平台 示例路径
H5 blob:http://localhost:5173/xxxx-xxxx
Android file:///storage/emulated/0/Android/data/.../recording_2026_07_15_14_30_00_1234.wav
iOS /private/var/mobile/Containers/.../tmp/recording_2026_07_15_14_30_00_1234.wav

完整示例

录音 + 文件回放

import {
  recordStart, recordStop, recordPause, recordResume,
  recordMute, recordUnmute,
  onRecordStop, onRecordError, onRecordTimer,
  recordDestroy, pcmDestroy,
} from '@/uni_modules/tki-audio-recorder'

const state = reactive({
  isRec: false,
  isPaused: false,
  isMuted: false,
  duration: 0,
  filePath: '',
})

// 录音控制
function startRec() {
  state.filePath = ''
  state.duration = 0
  recordStart({
    sampleRate: 16000,
    enableCommunicationMode: true,
    format: 'wav',
    bufferSize: 4096,
  })
  state.isRec = true
}

function stopRec() { recordStop() }
function pauseRec() { recordPause(); state.isPaused = true }
function resumeRec() { recordResume(); state.isPaused = false }
function muteRec() { recordMute(); state.isMuted = true }
function unmuteRec() { recordUnmute(); state.isMuted = false }

// 事件监听
onRecordStop((info) => {
  state.isRec = false
  state.isPaused = false
  state.filePath = info.tempFilePath
  console.log(`录制 ${info.duration}秒, 文件: ${info.tempFilePath}`)
})

onRecordTimer((sec) => { state.duration = sec })

// 回放
function playWav() {
  if (!state.filePath) return
  const audio = uni.createInnerAudioContext()
  audio.src = state.filePath
  audio.onEnded(() => audio.destroy())
  audio.onError(() => audio.destroy())
  audio.play()
}

// 页面卸载
onUnload(() => {
  recordDestroy()
  pcmDestroy()
})

实时 PCM 回放(对讲机模式)

import {
  recordStart, recordStop, pcmInit, pcmPlay,
  onRecordFrame, onRecordStop,
  recordDestroy, pcmDestroy,
} from '@/uni_modules/tki-audio-recorder'

// 页面加载时初始化播放器
pcmInit({ inputSampleRate: 16000 })

// 录音时实时回放
onRecordFrame((data: ArrayBuffer) => {
  pcmPlay(data)
})

function start() {
  recordStart({
    sampleRate: 16000,
    enableCommunicationMode: true,
    format: 'pcm',
    bufferSize: 4096,
  })
}

onUnload(() => {
  recordDestroy()
  pcmDestroy()
})

format: 'pcm' 避免生成无用的 WAV 文件,减少开销。


平台差异说明

功能差异

功能 H5 Android iOS
录音引擎 AudioWorklet AudioRecord AVAudioEngine
播放引擎 AudioContext + BufferSource AudioTrack AVAudioPlayerNode
WAV 文件 ✅ Blob URL ✅ 文件路径 不确定(文件路径)
帧回调(bufferSize) ✅ 每 4096 样本 ✅ 每 4096 样本 不确定(每 4096 样本)
分贝/波形 不确定
pause/resume 不确定
mute/unmute ✅(写入零数据) ✅(写入零数据) 不确定(写入零数据)
AEC (enableCommunicationMode) getUserMedia 约束 VOICE_COMMUNICATION 不确定(.voiceChat 模式)
onRecordDecibel 频域能量 时域 RMS 不确定(时域 RMS)
onRecordWaveform 频域 FFT 128 点 → 64 段 FFT 128 点 → 64 段 不确定(FFT 128 点 → 64 段)

onRecordFrame 返回数据格式

平台 数据类型 字节序 格式
三端一致 ArrayBuffer 小端 Int16 PCM

onRecordFrame 返回的数据可以在 H5 和 Android 端互通消费,iOS 不确定。


常见问题

Q: 录音后无法播放 WAV 文件?

Android 端 WAV 文件保存在 externalCacheDir/sdcard/Android/data/.../cache/),uni.createInnerAudioContext 可以直接访问。 如果使用文件管理器找不到文件,请确认路径包含 Android/data/(外部存储)。

Q: 为什么静音后 WAV 文件还是原来的大小?

静音不改变文件时长和大小——只是 PCM 数据替换为零。这样保证 tempFilePath 指向的 WAV 文件时长总是正确的。

Q: pcmPlay 报 ArrayBuffer 被忽略?

Android 端 pcmPlay([arrayBuf1, arrayBuf2]) 数组中的 ArrayBuffer 元素也会正确处理。如果使用的是字符串数组,字符串按 base64 解码。

Q: H5 端录制时间长后页面卡顿?

H5 端的 PCM 数据采用分块存储(pcmChunks: Float32Array[]),避免每帧拷贝整个缓冲区。即使是长时间录音内存占用也有限。

Q: 录音时长不准?

Web 端使用 AudioContext.currentTime(暂停时自动冻结)。 Android/iOS 使用 elapsedPaused 累计暂停时间扣除。 如果发现时长偏差,请确认是否误调了 pause()/resume()

Q: 录音文件保存在哪里?

平台 目录 清理时机
H5 内存 Blob 页面刷新后失效
Android externalCacheDir App 缓存清理时
iOS NSTemporaryDirectory 系统定期清理

如需持久保存,请将文件复制到应用的其他目录。

Q: 支持后台录音吗?

  • H5: 不支持(浏览器限制,页面不可见时 getUserMedia 会暂停)
  • Android: 支持(Service 保活需额外配置)
  • iOS: 不确定(需配置 Background Modes → Audio, AirPlay, and Picture in Picture)

隐私、权限声明

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

<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

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

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

暂无用户评论。