fix: 录音 - 移除 uni.authorize + 修复 encodeBitRate 越界

录音按住松手无效根因有两处:

1. encodeBitRate:128000 对 sampleRate:16000 越界(微信规定16000Hz
  下 encodeBitRate 必须在 24000~96000 之间),导致 recorder.start()
  立即触发 onError,修改为 encodeBitRate:48000

2. uni.authorize 异步回调延迟 recorder.start(),用户松手时
  stopRecord 已执行但 recorder 尚未开始录,且之前的 recordingStarted
  守卫跳过 stopRecord 后 authorize 回调又启动录音无法停止。
  解决方案: 直接调 recorder.start(),不再前置 uni.authorize。
  微信会在需要时自动弹录音权限窗。

format 从 wav 改为 mp3(mp3 在微信各平台兼容性更好),
后端 ffmpeg 会自动转码为 wav 后再送 whisper。
This commit is contained in:
yuzhiran
2026-07-05 14:14:45 +08:00
parent 07b81f57a6
commit b38b38d0c8
+3 -24
View File
@@ -147,7 +147,7 @@ const isSpeaking = ref(false)
const dhRef = ref(null) const dhRef = ref(null)
const isRecording = ref(false) const isRecording = ref(false)
let recorder = null let recorder = null
let recordingStarted = false // 标记 recorder.start() 是否已实际调用,避免 stopRecord 在 start 前触发
// 录音初始化(一次性创建 recorder 并设置事件) // 录音初始化(一次性创建 recorder 并设置事件)
function initRecorder() { function initRecorder() {
@@ -155,18 +155,15 @@ function initRecorder() {
if (recorder) return // 已初始化 if (recorder) return // 已初始化
recorder = uni.getRecorderManager() recorder = uni.getRecorderManager()
recorder.onStart(() => { recorder.onStart(() => {
recordingStarted = true
console.log('[Recorder] start recording') console.log('[Recorder] start recording')
}) })
recorder.onError((err) => { recorder.onError((err) => {
console.error('[Recorder] error:', err) console.error('[Recorder] error:', err)
isRecording.value = false isRecording.value = false
recordingStarted = false
uni.showToast({ title: '录音失败,请重试', icon: 'none' }) uni.showToast({ title: '录音失败,请重试', icon: 'none' })
}) })
recorder.onStop(async (res) => { recorder.onStop(async (res) => {
isRecording.value = false isRecording.value = false
recordingStarted = false
console.log('[Recorder] stop, tempFilePath:', res.tempFilePath) console.log('[Recorder] stop, tempFilePath:', res.tempFilePath)
if (!res.tempFilePath) { if (!res.tempFilePath) {
uni.showToast({ title: '录音文件为空', icon: 'none' }) uni.showToast({ title: '录音文件为空', icon: 'none' })
@@ -412,11 +409,7 @@ function startRecord() {
if (aiLoading.value || isComplete.value) return if (aiLoading.value || isComplete.value) return
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
if (isRecording.value) return if (isRecording.value) return
recordingStarted = false
isRecording.value = true isRecording.value = true
uni.authorize({
scope: 'scope.record',
success: () => {
if (!recorder) initRecorder() if (!recorder) initRecorder()
if (!recorder) { if (!recorder) {
isRecording.value = false isRecording.value = false
@@ -424,26 +417,14 @@ function startRecord() {
return return
} }
recorder.start({ recorder.start({
format: 'wav', format: 'mp3',
sampleRate: 16000, sampleRate: 16000,
numberOfChannels: 1, numberOfChannels: 1,
encodeBitRate: 128000, encodeBitRate: 48000,
}) })
uni.vibrateShort({ type: 'medium' }) uni.vibrateShort({ type: 'medium' })
},
fail: () => {
isRecording.value = false
uni.showModal({
title: '需要录音权限',
content: '请在「设置」中开启「麦克风」权限后再使用语音输入',
confirmText: '去设置',
success: (r) => { if (r.confirm) uni.openSetting({}) },
})
},
})
// #endif // #endif
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
isRecording.value = false
uni.showToast({ title: '语音输入仅支持小程序', icon: 'none' }) uni.showToast({ title: '语音输入仅支持小程序', icon: 'none' })
// #endif // #endif
} }
@@ -451,8 +432,6 @@ function startRecord() {
function stopRecord() { function stopRecord() {
if (!isRecording.value) return if (!isRecording.value) return
isRecording.value = false isRecording.value = false
// 松手太快,recorder.start() 还没实际执行(authorize 异步或录音尚未开始),直接跳过
if (!recordingStarted) return
if (!recorder) return if (!recorder) return
recorder.stop() recorder.stop()
} }