nxdt-uniapp/static/js/qx/utility/talk.js

355 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @Author: zhangtq 2452618307@qq.com
* @Date: 2024-11-18 13:33:30
* @LastEditors: zhangtq 2452618307@qq.com
* @LastEditTime: 2024-11-18 13:34:44
* @FilePath: static/js/qx/utility/talk.js
* @Description: 这是默认设置,可以在设置》工具》File Description中进行配置
*/
(function(window) {
//兼容
window.URL = window.URL || window.webkitURL;
//请求麦克风
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
var recorder = {};
var dtcWs = {};
var cb = {};
var Recorder = function(stream, config, name) {
config = config || {};
config.sampleBits = config.sampleBits || 16; //输出采样数位 8, 16
config.sampleRate = config.sampleRate || (8000); //输出采样率(1/6 48000)
// 音频上下文对象可创建不同的AudioNode
var context = new AudioContext();
//将声音输入这个对像
var audioInput = context.createMediaStreamSource(stream);
//设置音量节点
// var volume = context.createGain();
// audioInput.connect(volume);
var recorder = context.createScriptProcessor(4096, 1, 1);
var audioData = {
size: 0 //录音文件长度
,
buffer: [] //录音缓存
,
inputSampleRate: context.sampleRate //输入采样率
,
inputSampleBits: 16 //输入采样数位 8, 16
,
outputSampleRate: config.sampleRate,
oututSampleBits: config.sampleBits,
clear: function() {
this.buffer = [];
this.size = 0;
}
/**
* @param {!Float32Array} data
*/
,
input: function(data) {
this.buffer.push(new Float32Array(data));
this.size += data.length;
},
compress: function() { //合并压缩
//合并
var data = new Float32Array(this.size);
var offset = 0;
for (var i = 0; i < this.buffer.length; i++) {
data.set(this.buffer[i], offset);
offset += this.buffer[i].length;
}
//压缩
var compression = parseInt(this.inputSampleRate / this.outputSampleRate);
var length = data.length / compression;
var result = new Float32Array(length);
var index = 0,
j = 0;
while (index < length) {
result[index] = data[j];
j += compression;
index++;
}
return result;
},
floatTo16BitPCM: function(input, output) {
for (var i = 0; i < input.length; i++) {
var s = Math.max(-1, Math.min(1, input[i]));
output[i] = (s < 0 ? s * 0x8000 : s * 0x7FFF);
}
},
convertBuffer: function() {
var bytes = this.compress();
//console.log(bytes);
var data = new Float32Array(bytes);
var out = new Int16Array(bytes.length);
this.floatTo16BitPCM(data, out);
return out;
},
encodePCM: function() {
// PCM
var bytes = this.convertBuffer();
var data = new DataView(bytes.buffer);
return data;
},
encodeG711A: function() { //转G711A
// G711A
var smaples = this.convertBuffer();
var g7111aBuf = alawmulaw.alaw.encode(smaples);
return g7111aBuf;
},
encodeG711aBuffer: function() {
// DataView
var smaples = this.convertBuffer();
var g7111aBuf = alawmulaw.alaw.encode(smaples);
var data = new DataView(g7111aBuf.buffer);
return data;
}
};
//开始录音
this.start = function() {
audioInput.connect(recorder);
recorder.connect(context.destination);
};
//停止
this.stop = function() {
audioInput.disconnect();
recorder.disconnect();
};
this.getData = function() {
return audioData.encodeG711A();
};
//回放
this.play = function(audio) {
audio.src = window.URL.createObjectURL(this.getBlob());
};
//获取音频文件
this.getBuffer = function() {
//return audioData.encodePCM();
return audioData.encodeG711aBuffer();
};
//清空缓存
this.clear = function() {
audioData.clear();
};
//音频采集
var that = this;
recorder.onaudioprocess = function(e) {
audioData.input(e.inputBuffer.getChannelData(0));
var data = that.getData();
// getG711A(data);
if (dtcWs[name]) {
dtcWs[name].send(data);
};
that.clear();
};
};
//抛出异常
Recorder.throwError = function(message) {
throw new function() { this.toString = function() { console.log(message) }; };
};
//是否支持录音
Recorder.canRecording = (navigator.getUserMedia != null);
//获取录音机
Recorder.get = function(callback, config, name) {
if (callback) {
if (navigator.getUserMedia) {
navigator.getUserMedia({ audio: true } //只启用音频
,
function(stream) {
var rec = new Recorder(stream, config, name);
callback(rec);
},
function(error) {
switch (error.code || error.name) {
case 'PERMISSION_DENIED':
case 'PermissionDeniedError':
STRecorder.throwErr('用户拒绝提供信息。');
break;
case 'NOT_SUPPORTED_ERROR':
case 'NotSupportedError':
STRecorder.throwErr('浏览器不支持硬件设备。');
break;
case 'MANDATORY_UNSATISFIED_ERROR':
case 'MandatoryUnsatisfiedError':
STRecorder.throwErr('无法发现指定的硬件设备。');
break;
default:
console.log('无法打开麦克风。异常信息:', error);
STRecorder.throwErr('无法打开麦克风。异常信息:' + (error.code || error.name));
break;
}
}
);
return;
} else if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({
audio: true
})
.then(function(stream) {
var rec = new Recorder(stream, config, name);
callback(rec);
}).catch(function(error) {
switch (error.code || error.name) {
case 'PERMISSION_DENIED':
case 'PermissionDeniedError':
Recorder.throwError('用户拒绝提供信息。');
break;
case 'NOT_SUPPORTED_ERROR':
case 'NotSupportedError':
Recorder.throwError('浏览器不支持硬件设备。');
break;
case 'MANDATORY_UNSATISFIED_ERROR':
case 'MandatoryUnsatisfiedError':
Recorder.throwError('无法发现指定的硬件设备。');
break;
default:
Recorder.throwError('无法打开麦克风。异常信息:' + (error.code || error.name));
break;
}
});
return;
} else {
Recorder.throwError('当前浏览器不支持录音功能。');
return;
}
}
};
function dtcWebsocket(websocket_url, IP, Port, Token, queryToken, name) { // 连接websocket
var ws = new WebSocket(websocket_url + '?token=' + queryToken + '&IP=' + IP + '&Port=' + Port + '&Token=' + Token + '&dtc=true');
console.log(ws)
ws.onopen = function(evt) {
var message = {
type: "websocket_success",
msg: "dtc websocket连接成功"
};
if (cb[name]) {
cb[name](message)
};
Recorder.get(function(rec) {
recorder[name] = rec;
recorder[name].start();
}, {}, name);
};
ws.onmessage = function(data) {};
ws.onclose = function(evt) {
var message = {
type: "websocket_close",
msg: "dtc websocket连接断开"
};
if (cb[name]) {
cb[name](message)
};
recorder[name].stop(); //关闭采集数据
recorder[name].clear(); //清空采集数据缓存
recorder[name] = null;
dtcWs[name] = null; //清空websocket
cb[name] = null;
};
ws.onerror = function(evt) {
var message = {
type: "websocket_error",
msg: evt
};
if (cb[name]) {
cb[name](message)
};
recorder[name].stop();
recorder[name].clear();
recorder[name] = null;
dtcWs[name] = null; //清空websocket
cb[name] = null;
};
return ws;
}
window.Recorder = Recorder;
window.startCall = function(q2http_url, websocket_url, token, puid, idx, name, callback) { //开启对讲,每开启一个对讲就开启一个websocket,关闭对讲就要关闭websocket
if (callback) {
cb[name] = callback;
}
var params = {
puid: puid,
idx: idx
}
$.ajax({
type: 'post',
url: q2http_url + "audio/startCall?token=" + token,
data: params,
traditional: true,
dataType: 'json',
async: false,
complete: function(rv) {
console.log(rv)
var res = rv.responseJSON;
console.log(res)
if (res.hasOwnProperty('errcode')) {
var message = {
type: "startTalk_error",
msg: res.data.message
};
if (cb[name]) {
cb[name](message)
};
return;
} else {
console.log(name)
dtcWs[name] = dtcWebsocket(websocket_url, res.IP, res.Port, res.Token, token, name);
var message = {
type: "startTalk_success",
msg: "打开喊话成功"
};
if (cb[name]) {
cb[name](message)
};
return;
};
},
error: function(err) {
console.log(err);
}
})
};
window.stopCall = function(name) {
if (recorder[name]) {
dtcWs[name].close(); //关闭websocket
var message = {
type: "stopTalk_success",
msg: "关闭喊话成功"
};
if (cb[name]) {
cb[name](message)
};
return;
} else {
var message = {
type: "stopTalk_error",
msg: "未找到喊话无法停止喊话"
};
if (cb[name]) {
cb[name](message)
};
return;
};
};
})(window);