https://xiangyuecn.gitee.io/recorder/
引入 recorder-core
npm install recorder-core -S
在渲染进程模块的main.js
中加入recorder-core
组件
//加载必须要的core,demo简化起见采用的直接加载类库,实际使用时应当采用异步按需加载
import Recorder from 'recorder-core'
//需要使用到的音频格式编码引擎的js文件统统加载进来,这些引擎文件会比较大
import 'recorder-core/src/engine/mp3'
import 'recorder-core/src/engine/mp3-engine'
module.exports = {
data(){
return {
Rec:Recorder
,type:"mp3"
,bitRate:16
,sampleRate:16000
,rec:0
,duration:0
,powerLevel:0
,recOpenDialogShow:0
,logs:[]
}
}
,methods:{
recOpen:function(){
var This=this;
var rec=this.rec=Recorder({
type:This.type
,bitRate:This.bitRate
,sampleRate:This.sampleRate
,onProcess:function(buffers,powerLevel,duration,sampleRate){
This.duration=duration;
This.powerLevel=powerLevel;
This.wave.input(buffers[buffers.length-1],powerLevel,sampleRate);
}
});
This.dialogInt=setTimeout(function(){//定时8秒后打开弹窗,用于监测浏览器没有发起权限请求的情况
This.showDialog();
},8000);
rec.open(function(){
This.dialogCancel();
This.reclog("已打开:"+This.type+" "+This.sampleRate+"hz "+This.bitRate+"kbps",2);
This.wave=Recorder.WaveView({elem:".ctrlProcessWave"});
},function(msg,isUserNotAllow){
This.dialogCancel();
This.reclog((isUserNotAllow?"UserNotAllow,":"")+"打开失败:"+msg,1);
});
This.waitDialogClickFn=function(){
This.dialogCancel();
This.reclog("打开失败:权限请求被忽略,用户主动点击的弹窗",1);
};
}
,recClose:function(){
var rec=this.rec;
this.rec=null;
if(rec){
rec.close();
this.reclog("已关闭");
}else{
this.reclog("未打开录音",1);
};
}
,recStart:function(){
if(!this.rec||!Recorder.IsOpen()){
this.reclog("未打开录音",1);
return;
}
this.rec.start();
var set=this.rec.set;
this.reclog("录制中:"+set.type+" "+set.sampleRate+"hz "+set.bitRate+"kbps");
}
,recPause:function(){
if(this.rec&&Recorder.IsOpen()){
this.rec.pause();
}else{
this.reclog("未打开录音",1);
};
}
,recResume:function(){
if(this.rec&&Recorder.IsOpen()){
this.rec.resume();
}else{
this.reclog("未打开录音",1);
};
}
,recStop:function(){
if(!(this.rec&&Recorder.IsOpen())){
This.reclog("未打开录音",1);
return;
}
var This=this;
var rec=This.rec;
rec.stop(function(blob,duration){
This.reclog("已录制:","",{
blob:blob
,duration:duration
,rec:rec
});
},function(s){
This.reclog("录音失败:"+s,1);
});
}
,recPlayLast:function(){
if(!this.recLogLast){
this.reclog("请先录音,然后停止后再播放",1);
return;
};
this.recplay(this.recLogLast.idx);
}
,recUploadLast:function(){
if(!this.recLogLast){
this.reclog("请先录音,然后停止后再上传",1);
return;
};
var This=this;
var blob=this.recLogLast.res.blob;
//本例子假设使用原始XMLHttpRequest请求方式,实际使用中自行调整为自己的请求方式
//录音结束时拿到了blob文件对象,可以用FileReader读取出内容,或者用FormData上传
var api="https://xx.xx/test_request";
var onreadystatechange=function(title){
return function(){
if(xhr.readyState==4){
if(xhr.status==200){
This.reclog(title+"上传成功",2);
}else{
This.reclog(title+"没有完成上传,演示上传地址无需关注上传结果,只要浏览器控制台内Network面板内看到的请求数据结构是预期的就ok了。", "#d8c1a0");
console.error(title+"上传失败",xhr.status,xhr.responseText);
};
};
};
};
This.reclog("开始上传到"+api+",请求稍后...","#f60");
/***方式一:将blob文件转成base64纯文本编码,使用普通application/x-www-form-urlencoded表单上传***/
var reader=new FileReader();
reader.onloadend=function(){
var postData="";
postData+="mime="+encodeURIComponent(blob.type);//告诉后端,这个录音是什么格式的,可能前后端都固定的mp3可以不用写
postData+="&upfile_b64="+encodeURIComponent((/.+;\s*base64\s*,\s*(.+)$/i.exec(reader.result)||[])[1]) //录音文件内容,后端进行base64解码成二进制
//...其他表单参数
var xhr=new XMLHttpRequest();
xhr.open("POST", api);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhr.onreadystatechange=onreadystatechange("上传方式一【Base64】");
xhr.send(postData);
};
reader.readAsDataURL(blob);
/***方式二:使用FormData用multipart/form-data表单上传文件***/
var form=new FormData();
form.append("upfile",blob,"recorder.mp3"); //和普通form表单并无二致,后端接收到upfile参数的文件,文件名为recorder.mp3
//...其他表单参数
var xhr=new XMLHttpRequest();
xhr.open("POST", api);
xhr.onreadystatechange=onreadystatechange("上传方式二【FormData】");
xhr.send(form);
}
,reclog:function(msg,color,res){
var obj={
idx:this.logs.length
,msg:msg
,color:color
,res:res
,playMsg:""
,down:0
,down64Val:""
};
if(res&&res.blob){
this.recLogLast=obj;
};
this.logs.splice(0,0,obj);
}
,recplay:function(idx){
var This=this;
var o=this.logs[this.logs.length-idx-1];
o.play=(o.play||0)+1;
var logmsg=function(msg){
o.playMsg='<span style="color:green">'+o.play+'</span> '+This.getTime()+" "+msg;
};
logmsg("");
var audio=this.$refs.LogAudioPlayer;
audio.controls=true;
if(!(audio.ended || audio.paused)){
audio.pause();
};
audio.onerror=function(e){
logmsg('<span style="color:red">播放失败['+audio.error.code+']'+audio.error.message+'</span>');
};
audio.src=(window.URL||webkitURL).createObjectURL(o.res.blob);
audio.play();
}
,recdown:function(idx){
var This=this;
var o=this.logs[this.logs.length-idx-1];
o.down=(o.down||0)+1;
o=o.res;
var name="rec-"+o.duration+"ms-"+(o.rec.set.bitRate||"-")+"kbps-"+(o.rec.set.sampleRate||"-")+"hz."+(o.rec.set.type||(/\w+$/.exec(o.blob.type)||[])[0]||"unknown");
var downA=document.createElement("A");
downA.href=(window.URL||webkitURL).createObjectURL(o.blob);
downA.download=name;
downA.click();
}
,recdown64:function(idx){
var This=this;
var o=this.logs[this.logs.length-idx-1];
var reader = new FileReader();
reader.onloadend = function() {
o.down64Val=reader.result;
};
reader.readAsDataURL(o.res.blob);
}
,getTime:function(){
var now=new Date();
var t=("0"+now.getHours()).substr(-2)
+":"+("0"+now.getMinutes()).substr(-2)
+":"+("0"+now.getSeconds()).substr(-2);
return t;
}
,intp:function(s,len){
s=s==null?"-":s+"";
if(s.length>=len)return s;
return ("_______"+s).substr(-len);
}
,showDialog:function(){
//我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调
if(!/mobile/i.test(navigator.userAgent)){
return;//只在移动端开启没有权限请求的检测
};
this.recOpenDialogShow=1;
}
,dialogCancel:function(){
clearTimeout(this.dialogInt);
this.recOpenDialogShow=0;
}
,waitDialogClick:function(){
this.dialogCancel();
this.waitDialogClickFn();
}
}
}
作者:Jeebiz 创建时间:2023-07-07 20:38
最后编辑:Jeebiz 更新时间:2024-10-29 20:36
最后编辑:Jeebiz 更新时间:2024-10-29 20:36