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
|
|||
|
}
|
|||
|
|