ota-tv-web/src/static/js/video.ts
david d1f26ede2f
All checks were successful
OTA TV / deploy (push) Successful in 4s
data in websocket
2025-04-21 15:55:53 -07:00

145 lines
4.0 KiB
TypeScript

const isSecure = window.location.protocol === 'https:';
const host = window.location.hostname;
const ws0builder = isSecure ? `wss://${host}/ws0` : `ws://${host}:3001`;
const ws1builder = isSecure ? `wss://${host}/ws1` : `ws://${host}:3002`;
const ws0 = new WebSocket(ws0builder);
const ws1 = new WebSocket(ws1builder);
const config = {
iceServers: [
{
urls: ['stun:dwestgate.us:3478','turn:dwestgate.us:3478?transport=udp'],
username: 'webrtcuser',
credential: 'webrtccred'
}
]
};
interface IData {
channel: string,
signal: number,
cn: number
}
const pc0 = new RTCPeerConnection(config);
const pc1 = new RTCPeerConnection(config);
const video0 = document.getElementById('video-0') as HTMLVideoElement;
const video1 = document.getElementById('video-1') as HTMLVideoElement;
const station0 = document.getElementById('station-0') as HTMLHeadElement;
const station1 = document.getElementById('station-1') as HTMLHeadElement;
const signal0 = document.getElementById('signal-0') as HTMLHeadElement;
const signal1 = document.getElementById('signal-1') as HTMLHeadElement;
// 0
const dataChannel0 = pc0.createDataChannel('meta');
console.log("📡 Data channel created by client");
dataChannel0.onopen = () => {
console.log('📬 Client: Data channel opened');
};
dataChannel0.onmessage = (event) => {
const json = JSON.parse(event.data) as IData;
station0.textContent = json.channel;
signal0.textContent = `Signal: ${json.signal}\tC/N: ${json.cn}`
};
dataChannel0.onclose = () => {
console.log("📴 Client: Data channel closed");
};
// 0
pc0.ontrack = (event) => {
console.log("Received track event", event.streams);
video0.srcObject = event.streams[0];
};
pc0.onicecandidate = ({ candidate }) => {
if (candidate) {
ws0.send(JSON.stringify({ type: 'ice-candidate', data: candidate }));
}
};
ws0.onopen = async () => {
pc0.addTransceiver('video', { direction: 'recvonly' });
pc0.addTransceiver('audio', { direction: 'recvonly' })
const offer = await pc0.createOffer();
await pc0.setLocalDescription(offer);
ws0.send(JSON.stringify({ type: 'offer', data: offer }));
}
ws0.onmessage = async (message) => {
const msg = JSON.parse(message.data);
if (msg.type === 'answer') {
await pc0.setRemoteDescription(msg.data);
}
else if (msg.type === 'ice-candidate') {
await pc0.addIceCandidate(msg.data);
}
};
// 1
const dataChannel1 = pc1.createDataChannel('meta');
console.log("📡 Data channel created by client");
dataChannel1.onopen = () => {
console.log('📬 Client: Data channel opened');
};
dataChannel1.onmessage = (event) => {
const json = JSON.parse(event.data) as IData;
station1.textContent = json.channel;
signal1.textContent = `Signal: ${json.signal}\tC/N: ${json.cn}`
};
dataChannel1.onclose = () => {
console.log("📴 Client: Data channel closed");
};
pc1.ontrack = (event) => {
console.log("Received track event", event.streams);
video1.srcObject = event.streams[0];
};
pc1.onicecandidate = ({ candidate }) => {
if (candidate) {
ws1.send(JSON.stringify({ type: 'ice-candidate', data: candidate }));
}
};
ws1.onopen = async () => {
pc1.addTransceiver('video', { direction: 'recvonly' });
pc1.addTransceiver('audio', { direction: 'recvonly' })
const offer = await pc1.createOffer();
await pc1.setLocalDescription(offer);
ws1.send(JSON.stringify({ type: 'offer', data: offer }));
}
ws1.onmessage = async (message) => {
const msg = JSON.parse(message.data);
if (msg.type === 'answer') {
await pc1.setRemoteDescription(msg.data);
}
else if (msg.type === 'ice-candidate') {
await pc1.addIceCandidate(msg.data);
}
};
// TODO: Not yet working
// const dc0 = pc0.createDataChannel("keepalive");
// dc0.onopen = () =>{
// console.log("Data channel 0 open");
// setInterval(()=>{
// dc0.send("ping");
// },10000)
// }
// const dc1 = pc1.createDataChannel("keepalive");
// dc1.onopen = () =>{
// console.log("Data channel 1 open");
// setInterval(()=>{
// dc1.send("ping");
// },10000)
// }