Haikang SDK / Ehomeプロトコル/ RTSPプロトコル/ GB28181セキュリティビデオクラウドサービスEasyCVRは、GB28181プロトコルを介してカスケード接続できます。カメラまたはデバイスがオーディオをサポートしている場合、EasyCVRはオーディオキャプチャも実行できます。
EasyCVRビデオプラットフォームのフロントエンドjsは、webapiを使用してデバイスオーディオを収集します。非localhostおよび127の場合はgetUserMediaに特に注意し、httpsをオンにする必要があります。
基本的な手順
1. webrtcのgetUserMediaメソッドを使用してデバイスのオーディオ入力を取得し、audioprocessを使用してオーディオストリーム(pcmストリーム、範囲-1〜1)を取得します。
2.再サンプリング、フロントエンドサンプリングレートは48000、バックエンドサンプリングレートは8000、すべてを組み合わせて圧縮する必要があります。
3.値の変換:各チャンクで取得される入力データは、長さが4096のFloat32Array固定配列です。つまり、各サンプリングポイント情報は32ビット浮動小数点に格納されます。
32ビットの保存されたサンプリングフレーム値は、-1〜1を使用して、16ビットの保存範囲-32768〜32767をマップします。
以下は変換コードです:
function floatTo16BitPCM(output, offset, input) {
for (let i = 0; i < input.length; i++, offset += 2) {
//下面一行代码保证了采样帧的值在-1到1之间,因为有可能在多声道合并或其他状况下超出范围
let s = Math.max(-1, Math.min(1, input[i]));
//将32位浮点映射为16位整形表示的值
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}
説明:
s> 0が実際に01を032767にマップし、正数の最初の符号ビットが0の場合、32767は0111 1111 1111 1111、つまり0x7FFFに対応し、sを係数として乗算するだけです。負の数の場合、0-1から0-32768にマップする必要があるため、sの値を変換計算のスケール係数として直接使用することもできます。負の数がメモリに格納されている場合は、補数コードを使用する必要があります。補数コードは、符号ビットに加えて元のコードです。ビットが反転されてから+1が取得されるため、-32768の元のコードは1000 0000 0000 0000(オーバーフローしたビットは直接破棄されます)ですが、符号ビットはビットが反転されて1111 1111 1111 1111になり、最後に+1が計算されて1000 0000 0000になります。 0000(オーバーフローしたビットも直接破棄されます)。16進数で表すと0x8000です。ちなみに、補数は正と負の値の加算をバイナリ形式で0に等しくするために存在します。
4. Websocketはデータを送信するためのクライアントリンクを確立し、コレクションコールバックが約80msに1回トリガーされ、トリガーされたコールバック関数でデータが送信されることを監視します
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta name="apple-mobile-web-capable" content="yes">
<title>录音并传递给后台</title>
</head>
<body>
<button id="intercomBegin">开始对讲</button>
<button id="intercomEnd">关闭对讲</button>
</body>
<script type="text/javascript">
var begin = document.getElementById('intercomBegin');
var end = document.getElementById('intercomEnd');
var ws = null; //实现WebSocket
var record = null; //多媒体对象,用来处理音频
function init(rec) {
record = rec;
}
//录音对象
var Recorder = function(stream) {
var sampleBits = 16; //输出采样数位 8, 16
var sampleRate = 8000; //输出采样率
var context = new AudioContext();
var audioInput = context.createMediaStreamSource(stream);
var recorder = context.createScriptProcessor(4096, 1, 1);
var audioData = {
size: 0, //录音文件长度
buffer: [], //录音缓存
inputSampleRate: 48000, //输入采样率
inputSampleBits: 16, //输入采样数位 8, 16
outputSampleRate: sampleRate, //输出采样数位
oututSampleBits: sampleBits, //输出采样率
clear: function() {
this.buffer = [];
this.size = 0;
},
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;
},
encodePCM: function() { //这里不对采集到的数据进行其他格式处理,如有需要均交给服务器端处理。
var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);
var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);
var bytes = this.compress();
var dataLength = bytes.length * (sampleBits / 8);
var buffer = new ArrayBuffer(dataLength);
var data = new DataView(buffer);
var offset = 0;
for (var i = 0; i < bytes.length; i++, offset += 2) {
var s = Math.max(-1, Math.min(1, bytes[i]));
data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
return new Blob([data]);
}
};
var sendData = function() { //对以获取的数据进行处理(分包)
var reader = new FileReader();
reader.onload = e => {
var outbuffer = e.target.result;
var arr = new Int8Array(outbuffer);
if (arr.length > 0) {
var tmparr = new Int8Array(1024);
var j = 0;
for (var i = 0; i < arr.byteLength; i++) {
tmparr[j++] = arr[i];
if (((i + 1) % 1024) == 0) {
ws.send(tmparr);
if (arr.byteLength - i - 1 >= 1024) {
tmparr = new Int8Array(1024);
} else {
tmparr = new Int8Array(arr.byteLength - i - 1);
}
j = 0;
}
if ((i + 1 == arr.byteLength) && ((i + 1) % 1024) != 0) {
ws.send(tmparr);
}
}
}
};
reader.readAsArrayBuffer(audioData.encodePCM());
audioData.clear();//每次发送完成则清理掉旧数据
};
this.start = function() {
audioInput.connect(recorder);
recorder.connect(context.destination);
}
this.stop = function() {
recorder.disconnect();
}
this.getBlob = function() {
return audioData.encodePCM();
}
this.clear = function() {
audioData.clear();
}
recorder.onaudioprocess = function(e) {
var inputBuffer = e.inputBuffer.getChannelData(0);
audioData.input(inputBuffer);
sendData();
}
}
/*
* WebSocket
*/
function useWebSocket() {
ws = new WebSocket("ws://192.168.2.9:8080/websocket");
ws.binaryType = 'arraybuffer'; //传输的是 ArrayBuffer 类型的数据
ws.onopen = function() {
console.log('握手成功');
if (ws.readyState == 1) { //ws进入连接状态,则每隔500毫秒发送一包数据
record.start();
}
};
ws.onmessage = function(msg) {
console.info(msg)
}
ws.onerror = function(err) {
console.info(err)
}
}
/*
* 开始对讲
*/
begin.onclick = function() {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;
if (!navigator.getUserMedia) {
alert('浏览器不支持音频输入');
} else {
navigator.getUserMedia({
audio: true
},
function(mediaStream) {
init(new Recorder(mediaStream));
console.log('开始对讲');
useWebSocket();
},
function(error) {
console.log(error);
switch (error.message || error.name) {
case 'PERMISSION_DENIED':
case 'PermissionDeniedError':
console.info('用户拒绝提供信息。');
break;
case 'NOT_SUPPORTED_ERROR':
case 'NotSupportedError':
console.info('浏览器不支持硬件设备。');
break;
case 'MANDATORY_UNSATISFIED_ERROR':
case 'MandatoryUnsatisfiedError':
console.info('无法发现指定的硬件设备。');
break;
default:
console.info('无法打开麦克风。异常信息:' + (error.code || error.name));
break;
}
}
)
}
}
/*
* 关闭对讲
*/
end.onclick = function() {
if (ws) {
ws.close();
record.stop();
console.log('关闭对讲以及WebSocket');
}
}
</script>
</html>
EasyCVRビデオプラットフォームの詳細
EasyCVRセキュリティビデオクラウドサービスの主な機能は、デジタルネットワークカメラ、DVR、NVR、エンコーダーなどのデバイスビデオストリームを含むがこれらに限定されない、ローカルLANに接続されたRTSPビデオソースをプッシュし、RTMPプロトコルを介してそれらをAli、Tencent、およびその他のパブリッククラウドベンダーにプッシュすることです。ビデオサービスの中でも、優れたビデオトランスコーディング、再生、およびカスケード機能を備えています。同時に、新しいシステムはHaikang SDKもサポートし、Ehome契約、GB28181国家標準契約は真のビデオ統合プラットフォームです。
EasyCVRはすでに統合されたHaikang EHomeプロトコルをサポートしています。関心のあるユーザーは、「EasyCVR統合されたHaikang EHomeプロトコルシリーズの構成とプロトコルの概要」、「EasyCVR統合されたHaikang EHomeプロトコルシリーズ-Ehomeプロトコルの呼び出しプロセスの概要」およびその他の記事を読むことができます。。