235 lines
8.1 KiB
JavaScript
235 lines
8.1 KiB
JavaScript
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 =
|
||
"" +
|
||
'<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
|
||
|
||
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("打开失败:权限请求被忽略,<span style='color:#f00'>用户主动点击的弹窗</span>", 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
|
||
}
|
||
|