function CmsTalk() { this.wasmLoaded = false; this.logger = new Logger("CmsTalk"); this.urlBufferBuffer = null this.audioCache = null this.localAudioStream = null this.ws = null this.mediaRecorder = null this.audioBuffer = null this.rec = null // this.recBlob = null; /**调用open打开录音请求好录音权限**/ this.RecorderOpen() } CmsTalk.prototype.RecorderOpen = function () { //recOpen我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调 var showDialog = function () { if (!/mobile/i.test(navigator.userAgent)) { return //只在移动端开启没有权限请求的检测 } dialogCancel() //显示弹框,应该使用自己的弹框方式 var div = document.createElement("div") document.body.appendChild(div) div.innerHTML = "" + '
' + '
' + '
' + '
' + '
录音功能需要麦克风权限,请允许;如果未看到任何请求,请点击忽略~
' + '
忽略
' + "
" + '
' + "
" + "
" } 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 var formatMs = function (ms, all) { var f = Math.floor(ms / 60000), m = Math.floor(ms / 1000) % 60 var s = (all || f > 0 ? (f < 10 ? "0" : "") + f + ":" : "") + (all || f > 0 || m > 0 ? ("0" + m).substr(-2) + "″" : "") + ("00" + (ms % 1000)).substr(-3) return s } // var recOpen = function () {//一般在显示出录音按钮或相关的录音界面时进行此方法调用,后面用户点击开始录音时就能畅通无阻了 this.newRec = Recorder({ type: "pcm", sampleRate: 8000, bitRate: 16 //mp3格式,指定采样率hz、比特率kbps,其他参数使用默认配置;注意:是数字的参数必须提供数字,不要用字符串;需要使用的type类型,需提前把格式支持文件加载进来,比如使用wav格式需要提前加载wav.js编码引擎 , onProcess: function (buffers, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd) { newBufferIdx = 0 var newChunkInfo = Recorder.SampleData(buffers, 48000, 8000, this.prevChunkInfo); this.sendAudioData(newChunkInfo.data) this.prevChunkInfo = newChunkInfo for (let index = buffers.length - 1; index >= 0; index--) { buffers[index] = null; } }.bind(this) }); // createDelayDialog(); //我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调,此处demo省略了弹窗的代码 window.waitDialogClick = function () { dialogCancel(); console.log("打开失败:权限请求被忽略,用户主动点击的弹窗", 1); }; // }; } //打开麦克风授权获得相关资源 CmsTalk.prototype.open = function (callback) { // dialogCancel(); //如果开启了弹框,此处需要取消 if (this.rec){ console.log("已打开录音设备,可以点击录制开始录音了", 2); callback(null) return } this.newRec.open(function () { this.rec = this.newRec; console.log("已打开录音设备,可以点击录制开始录音了", 2); callback() }.bind(this), function (msg, isUserNotAllow) { //用户拒绝未授权或不支持 // dialogCancel(); //如果开启了弹框,此处需要取消 var log = (isUserNotAllow ? "UserNotAllow," : "") + "打开录音失败:" + msg; console.log(log); callback(log) }) } /**关闭录音,释放资源**/ CmsTalk.prototype.recClose = function () { if (this.rec) { this.rec.close(); this.rec = null console.log("已关闭"); } else { console.log("未打开录音", 1); }; }; /**开始录音**/ CmsTalk.prototype.recStart = function () {//打开了录音后才能进行start、stop调用 this.prevChunkInfo = null if (this.rec && Recorder.IsOpen()) { // this.recBlob = null; this.rec.start(); console.log("已开始录音..."); } else { console.log("未打开录音", 1); }; }; /**暂停录音**/ CmsTalk.prototype.recPause = function () { if (this.rec && Recorder.IsOpen()) { this.rec.pause(); } else { console.log("未打开录音", 1); }; }; /**恢复录音**/ CmsTalk.prototype.recResume = function () { if (this.rec && Recorder.IsOpen()) { this.rec.resume(); } else { console.log("未打开录音", 1); }; }; /**结束录音,得到音频文件**/ CmsTalk.prototype.recStop = function () { if (!(this.rec && Recorder.IsOpen())) { console.log("未打开录音", 1); return; }; this.rec.stop(null, null); }; CmsTalk.prototype.startTalk = function (url, callback) { this.open((err) => { if (err) { callback(err) } else { if (url.indexOf("http") != -1) { //方式1,可手动修改talk-server对应的地址 this.ws = new WebSocket("ws://192.168.0.215:3000"); this.ws.onmessage = function (msg) { console.log(msg); }; this.ws.onopen = (ev) => { console.log("open") this.ws.send(url) this.recStart() if (callback) callback(null) } } else { //方式2 this.ws = new WebSocket(url); this.ws.onmessage = function (msg) { console.log(msg); }; this.ws.onopen = (ev) => { console.log("open") this.recStart() if (callback) callback(null) } } } }) } CmsTalk.prototype.stopTalk = function () { if (this.ws) { this.ws.close(); this.ws = null } if (this.audioBuffer) { delete this.audioBuffer this.audioBuffer = null } this.recStop() // this.recClose() } CmsTalk.prototype.sendAudioData = function (samples) { var u8Data = alawmulaw.alaw.encode(samples); if (!this.audioBuffer) this.audioBuffer = new Uint8Array([]) var tmpBuffer = new Uint8Array(this.audioBuffer.byteLength + u8Data.byteLength) tmpBuffer.set(this.audioBuffer, 0) tmpBuffer.set(u8Data, this.audioBuffer.byteLength) while (tmpBuffer.byteLength >= 480) { var d480 = tmpBuffer.subarray(0, 480); tmpBuffer = tmpBuffer.subarray(480); console.log("reserve ", tmpBuffer.length) if (this.ws) this.ws.send(d480) } this.audioBuffer = tmpBuffer }