摘要: 其实也看了很多导出wav的例子,但实际上并不是很好用,知识点比较分散,实战还得自己封装组合,所以特意提炼了一个比较实用的类。实战可以直接拿取引用,省时省力。
前端录音
export class SoundRecording{ // 录音
mediaRecorder: MediaRecorder | null;
stream: MediaStream | null;
chunks: any[];
endCallback: any[];
constructor() {
this.mediaRecorder = null; // 录音对象
this.stream = null; // 当前轨道
this.chunks = []; // 录音缓存
this.endCallback = []; // 录音结束回调
}
create() { // 创建一个录音任务
return new Promise((resolve, reject) => {
this.resetState();
navigator.mediaDevices.getUserMedia({audio: true}).then((stream) => {
this.stream = stream;
this.mediaRecorder = new MediaRecorder(stream, { audioBitsPerSecond: 128000, mimeType: "audio/webm;codecs=opus" });
resolve({code: 1, message: '创建成功'});
}).catch((err) => {
reject(err);
});
});
}
start() { // 开始录音
return new Promise((resolve, reject) => {
this.judgeMediaRecorderIs().then((mediaRecorder: MediaRecorder) => {
// start(100); 每100毫秒生成一个数据可用事件
mediaRecorder.start();
// 完成一次录制片段后触发
mediaRecorder.addEventListener('dataavailable', (e) => {
this.chunks.push(e.data);
});
resolve({code: 1, message: '开始录制'});
}).catch((err) => {
reject(err);
});
});
}
stop() { // 结束录音
return new Promise((resolve, reject) => {
this.judgeMediaRecorderIs().then((mediaRecorder: MediaRecorder) => {
if (mediaRecorder.state === 'inactive') {
return reject({code: 0, message: '已结束'});
};
mediaRecorder.stop();
this.stream.getTracks().forEach((track) => { track.stop(); });
// 监听结束录制
mediaRecorder.addEventListener('stop', (e: any) => {
resolve({code: 1, message: '录制结束'});
// 如果录制结束的回调,就执行回到
this.endCallback.forEach((callback) => {
callback();
this.endCallback.shift();
});
});
}).catch((err) => {
reject(err);
});
});
}
download() { // 下载
return new Promise((resolve, reject) => {
this.handleChunksToBolb().then((blob: Blob) => {
let url = URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = url;
// 也可以是 'audio.ogg'
a.download = 'audio.wav';
a.click();
resolve(url);
}).catch((err) => {
reject(err);
});
});
}
viewRecording() { // 播放url
return new Promise((resolve, reject) => {
this.handleChunksToBolb().then((blob: Blob) => {
let url = URL.createObjectURL(blob);
resolve(url);
}).catch((err) => {
reject(err);
});
});
}
toFile() { // 转file对象
return new Promise((resolve, reject) => {
this.handleChunksToBolb().then((blob: Blob) => {
resolve(new File([blob], 'audio.wav', { type: 'audio/wav' }));
}).catch((err) => {
reject(err);
});
});
}
handleChunksToBolb() { // 转bolb
return new Promise((resolve, reject) => {
this.judgeChunksIs().then((chunks: any) => {
// 也可以是 'audio/ogg;codecs=opus'
let blob = new Blob(chunks, { type: 'audio/wav;codecs=opus' })
resolve(blob);
}).catch((err) => {
reject(err);
});
});
}
judgeChunksIs() { // 判断是否有录制缓存
return new Promise((resolve, reject) => {
let chunks = this.chunks;
if (chunks.length === 0) {
return reject({code: 0, message: '没有录制的缓冲'});
};
return resolve(chunks);
});
}
judgeMediaRecorderIs() { // 判断是否创建了录音任务
return new Promise((resolve, reject) => {
let mediaRecorder = this.mediaRecorder;
if (!mediaRecorder) { return reject({code: 0, message: '请先创建一个录制对象'}); };
resolve(mediaRecorder);
});
}
setEndCallback(callback) { // 存结束回调
this.endCallback.push(callback);
}
resetState() { // 重置状态
this.chunks = [];
this.mediaRecorder = null;
this.stream = null;
}
};
使用方法
let mySoundRecording = new SoundRecording();
mySoundRecording.create().then(() => {
// 开始录制
mySoundRecording.start();
// 可选择自己注册一个结束回调, 也可以调用stop()结束成功后执行下载、播放url、转file
let endRecording = () => {
// 下载到本地
mySoundRecording.download();
// 本地播放url
mySoundRecording.viewRecording().then((srcObject) => {});
// 转file可上传到后台服务器
mySoundRecording.toFile().then((file) => {});
};
// 存结束录音回调函数
mySoundRecording.setEndCallback(endRecording);
// 手动结束录屏,then后才可以下载、获取本地播放url、转file对象
mySoundRecording.stop().then(() => {
// 下载到本地
mySoundRecording.download();
// 本地播放url
mySoundRecording.viewRecording().then((srcObject) => {});
// 转file可上传到后台服务器
mySoundRecording.toFile().then((file) => {});
});
});