1 Star 0 Fork 110

五岁打死熊 / Recorder

forked from xiangyuecn / Recorder 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
QuickStart.html 14.35 KB
一键复制 编辑 原始数据 按行查看 历史
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="shortcut icon" type="image/png" href="https://cdn.jsdelivr.net/gh/xiangyuecn/Recorder@latest/assets/icon.png">
<title>Recorder QuickStart: 快速入门</title>
<script>
var Tips='你可以直接将 <a target="_blank" href="https://github.com/xiangyuecn/Recorder/blob/master/QuickStart.html">/QuickStart.html</a> 文件copy到你的(https)网站中,无需其他文件,就能正常开始测试了;相比 Recorder H5 (/index.html) 这个大而全(杂乱)的demo,本文件更适合入门学习'+unescape("%uD83D%uDE04");
console.log(Tips);
</script>
<!--
【1】引入框架文件,注意自己使用时应当自己把源码clone下来,然后通过src="/src/recorder-core.js"引入,这里为了方便copy文件测试起见,使用了JsDelivr CDN。
另外:[1.1]、[1.2]可以合并为使用"/recorder.mp3.min.js",这个文件为压缩版大幅减小文件体积,已经包含了这3个源码文件
-->
<!-- 【1.1】引入核心文件 -->
<script src="https://cdn.jsdelivr.net/gh/xiangyuecn/Recorder@latest/src/recorder-core.js"></script>
<!-- 【1.2】引入相应格式支持文件;如果需要多个格式支持,把这些格式的编码引擎js文件放到后面统统加载进来即可 -->
<script src="https://cdn.jsdelivr.net/gh/xiangyuecn/Recorder@latest/src/engine/mp3.js"></script>
<script src="https://cdn.jsdelivr.net/gh/xiangyuecn/Recorder@latest/src/engine/mp3-engine.js"></script>
<!-- 【1.3】引入可选的扩展支持项,如果不需要这些扩展功能可以不引入 -->
<script src="https://cdn.jsdelivr.net/gh/xiangyuecn/Recorder@latest/src/extensions/frequency.histogram.view.js"></script>
<script src="https://cdn.jsdelivr.net/gh/xiangyuecn/Recorder@latest/src/extensions/lib.fft.js"></script>
</head>
<body>
<!-- 【2】构建界面 -->
<div class="main">
<div class="mainBox">
<span style="font-size:32px;color:#f60;">Recorder QuickStart: 快速入门</span>
<a href="https://github.com/xiangyuecn/Recorder">GitHub >></a>
<div style="padding-top:10px;color:#666">
更多Demo:
<a class="lb" href="https://xiangyuecn.gitee.io/recorder/">Recorder H5</a>
<a class="lb" href="https://jiebian.life/web/h5/github/recordapp.aspx">RecordApp</a>
<a class="lb" href="https://jiebian.life/web/h5/github/recordapp.aspx?path=/app-support-sample/QuickStart.html">RecordApp QuickStart</a>
</div>
</div>
<div class="mainBox">
<!-- 按钮控制区域 -->
<div class="pd btns">
<div>
<button onclick="recOpen()" style="margin-right:10px">打开录音,请求权限</button>
<button onclick="recClose()" style="margin-right:0">关闭录音,释放资源</button>
</div>
<button onclick="recStart()">录制</button>
<button onclick="recStop()" style="margin-right:80px">停止</button>
<span style="display: inline-block;">
<button onclick="recPause()">暂停</button>
<button onclick="recResume()">继续</button>
</span>
<span style="display: inline-block;">
<button onclick="recPlay()">播放</button>
<button onclick="recUpload()">上传</button>
</span>
</div>
<!-- 波形绘制区域 -->
<div class="pd recpower">
<div style="height:40px;width:300px;background:#999;position:relative;">
<div class="recpowerx" style="height:40px;background:#0B1;position:absolute;"></div>
<div class="recpowert" style="padding-left:50px; line-height:40px; position: relative;"></div>
</div>
</div>
<div class="pd waveBox">
<div style="border:1px solid #ccc;display:inline-block"><div style="height:100px;width:300px;" class="recwave"></div></div>
</div>
</div>
<!-- 日志输出区域 -->
<div class="mainBox">
<div class="reclog"></div>
</div>
</div>
<!-- 【3】实现录音逻辑 -->
<script>
var rec,wave,recBlob;
/**调用open打开录音请求好录音权限**/
var recOpen=function(){//一般在显示出录音按钮或相关的录音界面时进行此方法调用,后面用户点击开始录音时就能畅通无阻了
rec=null;
wave=null;
recBlob=null;
var newRec=Recorder({
type:"mp3",sampleRate:16000,bitRate:16 //mp3格式,指定采样率hz、比特率kbps,其他参数使用默认配置;注意:是数字的参数必须提供数字,不要用字符串;需要使用的type类型,需提前把格式支持文件加载进来,比如使用wav格式需要提前加载wav.js编码引擎
,onProcess:function(buffers,powerLevel,bufferDuration,bufferSampleRate,newBufferIdx,asyncEnd){
//录音实时回调,大约1秒调用12次本回调
document.querySelector(".recpowerx").style.width=powerLevel+"%";
document.querySelector(".recpowert").innerText=bufferDuration+" / "+powerLevel;
//可视化图形绘制
wave.input(buffers[buffers.length-1],powerLevel,bufferSampleRate);
}
});
createDelayDialog(); //我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调,此处demo省略了弹窗的代码
newRec.open(function(){//打开麦克风授权获得相关资源
dialogCancel(); //如果开启了弹框,此处需要取消
rec=newRec;
//此处创建这些音频可视化图形绘制浏览器支持妥妥的
wave=Recorder.FrequencyHistogramView({elem:".recwave"});
reclog("已打开录音,可以点击录制开始录音了",2);
},function(msg,isUserNotAllow){//用户拒绝未授权或不支持
dialogCancel(); //如果开启了弹框,此处需要取消
reclog((isUserNotAllow?"UserNotAllow,":"")+"打开录音失败:"+msg,1);
});
window.waitDialogClick=function(){
dialogCancel();
reclog("打开失败:权限请求被忽略,<span style='color:#f00'>用户主动点击的弹窗</span>",1);
};
};
/**关闭录音,释放资源**/
function recClose(){
if(rec){
rec.close();
reclog("已关闭");
}else{
reclog("未打开录音",1);
};
};
/**开始录音**/
function recStart(){//打开了录音后才能进行start、stop调用
if(rec&&Recorder.IsOpen()){
recBlob=null;
rec.start();
reclog("已开始录音...");
}else{
reclog("未打开录音",1);
};
};
/**暂停录音**/
function recPause(){
if(rec&&Recorder.IsOpen()){
rec.pause();
}else{
reclog("未打开录音",1);
};
};
/**恢复录音**/
function recResume(){
if(rec&&Recorder.IsOpen()){
rec.resume();
}else{
reclog("未打开录音",1);
};
};
/**结束录音,得到音频文件**/
function recStop(){
if(!(rec&&Recorder.IsOpen())){
reclog("未打开录音",1);
return;
};
rec.stop(function(blob,duration){
console.log(blob,(window.URL||webkitURL).createObjectURL(blob),"时长:"+duration+"ms");
recBlob=blob;
reclog("已录制mp3:"+duration+"ms "+blob.size+"字节,可以点击播放、上传了",2);
},function(msg){
reclog("录音失败:"+msg,1);
});
};
/**播放**/
function recPlay(){
if(!recBlob){
reclog("请先录音,然后停止后再播放",1);
return;
};
var cls=("a"+Math.random()).replace(".","");
reclog('播放中: <span class="'+cls+'"></span>');
var audio=document.createElement("audio");
audio.controls=true;
document.querySelector("."+cls).appendChild(audio);
//简单利用URL生成播放地址,注意不用了时需要revokeObjectURL,否则霸占内存
audio.src=(window.URL||webkitURL).createObjectURL(recBlob);
audio.play();
setTimeout(function(){
(window.URL||webkitURL).revokeObjectURL(audio.src);
},5000);
};
/**上传**/
function recUpload(){
var blob=recBlob;
if(!blob){
reclog("请先录音,然后停止后再上传",1);
return;
};
//本例子假设使用原始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){
reclog(title+"上传成功",2);
}else{
reclog(title+"没有完成上传,演示上传地址无需关注上传结果,只要浏览器控制台内Network面板内看到的请求数据结构是预期的就ok了。", "#d8c1a0");
console.error(title+"上传失败",xhr.status,xhr.responseText);
};
};
};
};
reclog("开始上传到"+api+",请求稍后...");
/***方式一:将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);
};
//recOpen我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调
var showDialog=function(){
if(!/mobile/i.test(navigator.userAgent)){
return;//只在移动端开启没有权限请求的检测
};
dialogCancel();
//显示弹框,应该使用自己的弹框方式
var div=document.createElement("div");
document.body.appendChild(div);
div.innerHTML=(''
+'<div class="waitDialog" style="z-index:99999;width:100%;height:100%;top:0;left:0;position:fixed;background:rgba(0,0,0,0.3);">'
+'<div style="display:flex;height:100%;align-items:center;">'
+'<div style="flex:1;"></div>'
+'<div style="width:240px;background:#fff;padding:15px 20px;border-radius: 10px;">'
+'<div style="padding-bottom:10px;">录音功能需要麦克风权限,请允许;如果未看到任何请求,请点击忽略~</div>'
+'<div style="text-align:center;"><a onclick="waitDialogClick()" style="color:#0B1">忽略</a></div>'
+'</div>'
+'<div style="flex:1;"></div>'
+'</div>'
+'</div>');
};
var createDelayDialog=function(){
dialogInt=setTimeout(function(){//定时8秒后打开弹窗,用于监测浏览器没有发起权限请求的情况,在open前放置定时器利于收到了回调能及时取消(不管open是同步还是异步回调的)
showDialog();
},8000);
};
var dialogInt;
var dialogCancel=function(){
clearTimeout(dialogInt);
//关闭弹框,应该使用自己的弹框方式
var elems=document.querySelectorAll(".waitDialog");
for(var i=0;i<elems.length;i++){
elems[i].parentNode.removeChild(elems[i]);
};
};
//recOpen弹框End
</script>
<!--以下这坨可以忽略-->
<script>
function reclog(s,color){
var now=new Date();
var t=("0"+now.getHours()).substr(-2)
+":"+("0"+now.getMinutes()).substr(-2)
+":"+("0"+now.getSeconds()).substr(-2);
var div=document.createElement("div");
var elem=document.querySelector(".reclog");
elem.insertBefore(div,elem.firstChild);
div.innerHTML='<div style="color:'+(!color?"":color==1?"red":color==2?"#0b1":color)+'">['+t+']'+s+'</div>';
};
window.onerror=function(message, url, lineNo, columnNo, error){
//https://www.cnblogs.com/xianyulaodi/p/6201829.html
reclog('<span style="color:red">【Uncaught Error】'+message+'<pre>'+"at:"+lineNo+":"+columnNo+" url:"+url+"\n"+(error&&error.stack||"不能获得错误堆栈")+'</pre></span>');
};
reclog("RecordApp[即将废弃] 除Recorder支持的外,支持Hybrid App,低版本IOS上支持微信网页和小程序web-view"+unescape("%uD83C%uDF89"),"#f60;font-weight:bold;font-size:24px");
reclog("Recorder H5使用简单,功能丰富,支持PC、Android、IOS 14.3+"+unescape("%uD83D%uDCAA"),"#0b1;font-weight:bold;font-size:24px");
reclog(Tips);
</script>
<script>
if(/mobile/i.test(navigator.userAgent)){
//移动端加载控制台组件
var elem=document.createElement("script");
elem.setAttribute("type","text/javascript");
elem.setAttribute("src","https://cdn.bootcss.com/eruda/1.5.4/eruda.min.js");
document.body.appendChild(elem);
elem.onload=function(){
eruda.init();
};
};
</script>
<!-- 加载打赏挂件 -->
<script src="https://cdn.jsdelivr.net/gh/xiangyuecn/Recorder@latest/assets/zdemo.widget.donate.js"></script>
<script>
var donateView=document.createElement("div");
document.querySelector(".reclog").appendChild(donateView);
DonateWidget({
log:function(msg){reclog(msg)}
,mobElem:donateView
});
</script>
<style>
body{
word-wrap: break-word;
background:#f5f5f5 center top no-repeat;
background-size: auto 680px;
}
pre{
white-space:pre-wrap;
}
a{
text-decoration: none;
color:#06c;
}
a:hover{
color:#f00;
}
.main{
max-width:700px;
margin:0 auto;
padding-bottom:80px
}
.mainBox{
margin-top:12px;
padding: 12px;
border-radius: 6px;
background: #fff;
--border: 1px solid #f60;
box-shadow: 2px 2px 3px #aaa;
}
.btns button{
display: inline-block;
cursor: pointer;
border: none;
border-radius: 3px;
background: #f60;
color:#fff;
padding: 0 15px;
margin:3px 20px 3px 0;
line-height: 36px;
height: 36px;
overflow: hidden;
vertical-align: middle;
}
.btns button:active{
background: #f00;
}
.pd{
padding:0 0 6px 0;
}
.lb{
display:inline-block;
vertical-align: middle;
background:#00940e;
color:#fff;
font-size:14px;
padding:2px 8px;
border-radius: 99px;
}
</style>
</body>
</html>
JavaScript
1
https://gitee.com/stephen_tp/Recorder.git
git@gitee.com:stephen_tp/Recorder.git
stephen_tp
Recorder
Recorder
master

搜索帮助