Files
2025-05-30 14:26:36 +08:00

290 lines
12 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebRTC WHIP Audio Sender</title>
</head>
<body>
<label for="newUrl">808 url:</label>
<input type="text" id="newUrl" value="https://124.221.30.46:12000/api/v1/jt808/9101" style="width: 300px;">
<label for="ip">ip:</label>
<input type="text" id="ip" value="124.221.30.46">
<label for="port">port:</label>
<input type="text" id="port" value="12051">
<label for="simCard">sim:</label>
<input type="text" id="simCard" value="10088">
<button id="newSendButton">设备音视频指令</button>
<div id="newStatus"></div>
<label for="audioPort">音频端口:</label>
<input type="text" id="audioPort" value="12022">
<button id="intercomSendButton">设备对讲指令</button>
<div id="intercomStatus"></div>
<label for="url">url:</label>
<input type="text" id="url" value="https://124.221.30.46:12080/jt1078/api/v1/intercom" style="width: 300px;">
<label for="portsInput">音频端口组第一个:</label>
<input type="text" id="portsInput" value="12022" style="width: 100px;">
<label for="audioTextBox">音频类型文本框:</label>
<input type="text" id="audioTextBox" value="https://124.221.30.46:12000/api/v1/jt808/9003" style="width: 300px;">
<button id="startButton">webrtc对讲</button>
<button id="stopButton" disabled>关闭webrtc对讲</button>
<div id="status"></div>
<video id="videoElement" width="640" height="360" controls></video>
<!-- https://github.com/bilibili/flv.js/releases-->
<script src="flv.min.js"></script>
<script>
const startButton = document.getElementById('startButton');
const stopButton = document.getElementById('stopButton');
const statusDiv = document.getElementById('status');
let peerConnection;
let mediaStream;
async function startSendingAudio() {
try {
const simCard = document.getElementById('simCard').value;
const newUrl = document.getElementById('audioTextBox').value;
const newResponse = await fetch(newUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
key: simCard,
data:{}
})
});
if (!newResponse.ok) {
throw new Error(`HTTP error! status: ${newResponse.status}`);
}
const newData = await newResponse.json();
console.log(newData)
const audio = newData.data.details.enterAudioEncoding
console.log("音频类型 2-G722 6-G711A 7-G711U 当前值:"+audio)
console.log("输入音频采样位数 0-8位 1-16位 2-32位 当前值:"+newData.data.details.enterAudioSampleDigits)
console.log("输入音频采样率 0-8kHz 1-22.05 kHz 2-44.1 kHz 3-48 kHz 当前值:"+newData.data.details.enterAudioSampleRate)
console.log("音频帧长度 范围1-4294967295 当前值:"+newData.data.details.audioFrameLength)
statusDiv.textContent = `音频类型:` + audio;
// 获取音频流
mediaStream = await navigator.mediaDevices.getUserMedia({
audio: {
echoCancellation: true, // 启用回声消除
noiseSuppression: true, // 启用噪声抑制
autoGainControl: true, // 启用自动增益控制
channelCount: 1, // 使用单声道减少处理复杂度
sampleRate: 8000, // 设置合适的采样率
sampleSize: 16, // 位深度
}
});
// 创建 RTCPeerConnection 实例
peerConnection = new RTCPeerConnection();
// 将音频轨道添加到连接中
mediaStream.getTracks().forEach(track => {
peerConnection.addTrack(track, mediaStream);
});
peerConnection.addEventListener('icecandidate', handleConnection);
// 创建一个 offer
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);
const url = document.getElementById('url').value;
const audioPort = document.getElementById('portsInput').value;
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
sdp: offer.sdp,
group: [
{
sim: simCard,
channel: 1,
audioPort: parseInt(audioPort, 10)
}
],
// EnterAudioEncoding 音频类型参数 根据jt1078-2016表12 2-G722 6-G711A 7-G711U
enterAudioEncoding: parseInt(audio, 10)
})
});
console.log(response.ok)
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
const answer = new RTCSessionDescription({ type: data.type, sdp: data.sdp });
await peerConnection.setRemoteDescription(answer);
startButton.disabled = true;
stopButton.disabled = false;
statusDiv.textContent = '开始对讲';
} catch (error) {
console.error('Error starting audio sending:', error);
statusDiv.textContent = `Error: ${error.message}`;
}
}
async function stopSendingAudio() {
if (peerConnection) {
// 发送关闭请求到服务器
try {
const simCard = document.getElementById('simCard').value;
// 设备和jt1078之间的链接 手动关闭 或者设置超时自动关闭
const url = 'https://124.221.30.46:12000/api/v1/jt808/9102'
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
key: simCard,
data: {
channelNo: 1,
controlCmd: 4,
closeAudioVideoData: 0,
streamType: 0
}
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('关闭请求响应:', data);
statusDiv.textContent += ' (服务器已通知)';
} catch (error) {
console.error('Error sending stop request:', error);
statusDiv.textContent += ' (关闭请求失败)';
}
peerConnection.close();
peerConnection = null;
}
if (mediaStream) {
mediaStream.getTracks().forEach(track => track.stop());
mediaStream = null;
}
startButton.disabled = false;
stopButton.disabled = true;
statusDiv.textContent = '关闭对讲';
}
startButton.addEventListener('click', startSendingAudio);
stopButton.addEventListener('click', stopSendingAudio);
function handleConnection(event) {
const iceCandidate = event.candidate;
if (iceCandidate) {
const newIceCandidate = new RTCIceCandidate(iceCandidate);
console.log(newIceCandidate)
console.log(`ICE candidate:\n` +
`${event.candidate.candidate}.`)
}
}
const newSendButton = document.getElementById('newSendButton');
const newStatusDiv = document.getElementById('newStatus');
async function sendNewRequest() {
const newUrl = document.getElementById('newUrl').value;
const ip = document.getElementById('ip').value;
const port = parseInt(document.getElementById('port').value, 10);
const simCard = document.getElementById('simCard').value;
try {
const response = await fetch(newUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
key: simCard,
data: {
serverIPAddr: ip,
serverIPLen: ip.length,
tcpPort: port,
channelNo: 1, // 通道号
// 选择0音视频的情况 因为音频是g711a flv支持不了
dataType: 1, // 0-音视频 1-视频 2-双向对讲 3-监听 4-中心广播 5-透传
streamType: 0, // 0-主码流 1-子码流
}
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
// http://124.221.30.46:12080/mp4/live/jt1078-10088-1.mp4
// https://go-jt808.online:12080/flv/live/jt1078-10088-1.flv
data.playUrl = `https://${ip}:12080/flv/live/jt1078-${simCard}-1.flv`;
newStatusDiv.innerHTML = `<pre>请求成功: ${JSON.stringify(data, null, 2)}</pre>`; // 格式化显示JSON
setTimeout(() => {
console.log('等待设备推流 假设3秒内完成');
const videoElement = document.getElementById('videoElement');
const flvPlayer = flvjs.createPlayer({
type: 'flv',
url: data.playUrl
});
flvPlayer.attachMediaElement(videoElement);
flvPlayer.load();
flvPlayer.play();
}, 3000);
} catch (error) {
console.error('Error sending new request:', error);
newStatusDiv.innerHTML = `<pre>Error: ${error.message}</pre>`; // 格式化显示错误信息
}
}
newSendButton.addEventListener('click', sendNewRequest);
const intercomSendButton = document.getElementById('intercomSendButton');
const intercomStatusDiv = document.getElementById('intercomStatus');
async function sendIntercomRequest() {
const newUrl = document.getElementById('newUrl').value;
const ip = document.getElementById('ip').value;
const audioPort = parseInt(document.getElementById('audioPort').value, 10);
const simCard = document.getElementById('simCard').value;
try {
const response = await fetch(newUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
key: simCard,
data: {
serverIPAddr: ip,
serverIPLen: ip.length,
tcpPort: audioPort,
channelNo: 1, // 通道号
dataType: 2, // 0-音视频 1-视频 2-双向对讲 3-监听 4-中心广播 5-透传
streamType: 0, // 0-主码流 1-子码流
}
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
intercomStatusDiv.innerHTML = `<pre>请求成功: ${JSON.stringify(data, null, 2)}</pre>`; // 格式化显示JSON
} catch (error) {
console.error('Error sending intercom request:', error);
intercomStatusDiv.innerHTML = `<pre>Error: ${error.message}</pre>`; // 格式化显示错误信息
}
}
intercomSendButton.addEventListener('click', sendIntercomRequest);
</script>
</body>
</html>