149 lines
3.8 KiB
JavaScript
149 lines
3.8 KiB
JavaScript
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();
|
||
}
|
||
}
|