import BarkDetector from './barkDetector'; export default class AudioRecorder { constructor(options = {}) { this.recorder = wx.getRecorderManager(); this.detector = new BarkDetector(options); this.isRecording = false; this.sampleRate = options.sampleRate || 16000; this.frameSize = options.frameSize || 8192; this.onUpdate = options.onUpdate || null; this.onError = options.onError || null; this._bindEvents(); } _bindEvents() { this.recorder.onStart(() => { this.isRecording = true; }); this.recorder.onStop(() => { this.isRecording = false; }); this.recorder.onError((err) => { this.isRecording = false; if (this.onError) this.onError(err); }); this.recorder.onFrameRecorded((res) => { if (!res.frameBuffer || res.frameBuffer.byteLength === 0) return; const pcm = new Int16Array(res.frameBuffer); this.detector.feed(pcm, this.sampleRate); const status = this.detector.getStatus(); if (this.onUpdate) { this.onUpdate(status); } }); } start() { if (this.isRecording) return; // 先检查并请求麦克风权限 this._checkAndRequestPermission() .then(() => this._doStart()) .catch((err) => { console.error('mic permission error', err); if (this.onError) this.onError(err); }); } _checkAndRequestPermission() { return new Promise((resolve, reject) => { wx.getSetting({ success: (res) => { const auth = res.authSetting['scope.record']; if (auth === true) { // 已授权 resolve(); return; } if (auth === false) { // 之前拒绝过,需要引导去设置页 this._showOpenSettings(reject); return; } // 未请求过权限,发起授权请求 wx.authorize({ scope: 'scope.record', success: () => resolve(), fail: (err) => { // 用户点击拒绝 if (err.errCode === 12001 || (err.errMsg && err.errMsg.includes('auth deny'))) { this._showOpenSettings(reject); } else { reject(err); } } }); }, fail: reject }); }); } _showOpenSettings(reject) { wx.showModal({ title: '需要麦克风权限', content: '汪汪大作战需要麦克风来检测你的狗叫声,请在设置中打开麦克风权限。', confirmText: '去设置', cancelText: '取消', success: (res) => { if (res.confirm) { wx.openSetting({ success: (settingRes) => { if (settingRes.authSetting['scope.record']) { this._doStart(); } else { reject(new Error('用户未在设置中开启麦克风权限')); } }, fail: reject }); } else { reject(new Error('用户取消授权')); } }, fail: reject }); } _doStart() { try { // 微信小游戏 onFrameRecorded 在部分环境(尤其是开发者工具模拟器)下不会实时触发, // 在真机上通常正常。这里用 1KB 帧大小(约 64ms)尝试获得较频繁的回调。 this.recorder.start({ duration: 600000, sampleRate: 16000, numberOfChannels: 1, format: 'PCM', frameSize: 1 }); // recorder started } catch (err) { console.error('[AudioRecorder] recorder.start() error', err); if (this.onError) this.onError(err); } } stop() { if (!this.isRecording) return; this.recorder.stop(); } reset() { this.detector.reset(); } getStatus() { return this.detector.getStatus(); } }