more support for dual tuners
This commit is contained in:
parent
b98717201e
commit
d1ad73fbf0
@ -2,13 +2,11 @@ import HttpServer from './http';
|
||||
import TVWebSocket from './ws';
|
||||
import Zap, { IZap } from './zap';
|
||||
|
||||
import * as readline from 'readline';
|
||||
|
||||
const HTTP_PORT = process.env.HTTP_PORT ? parseInt(process.env.HTTP_PORT, 10) : 8080;
|
||||
const WS_PORT = process.env.WS_PORT ? parseInt(process.env.WS_PORT, 10) : 3001;
|
||||
const STATIC_ROOT = process.cwd() + "/dist/static";
|
||||
const TV_DEV_0 = process.env.TV_DEV_0 ?? '/dev/dvb/adapter0/dvr0'
|
||||
const TV_DEV_1 = process.env.TV_DEV_1 ? '/dev/dvb/adapter0/dvr1' : null;
|
||||
const TV_DEV_1 = process.env.TV_DEV_1 ?? '/dev/dvb/adapter0/dvr1';
|
||||
|
||||
const zap = new Zap();
|
||||
|
||||
@ -26,7 +24,8 @@ const getChannels = () =>
|
||||
zap.getChannels();
|
||||
|
||||
const httpServer = new HttpServer(HTTP_PORT, STATIC_ROOT, tune, getChannels);
|
||||
const tvWebSocket = new TVWebSocket(WS_PORT);
|
||||
const tvWebSocket0 = new TVWebSocket(WS_PORT, TV_DEV_0);
|
||||
// const tvWebSocket1 = new TVWebSocket(WS_PORT + 1, TV_DEV_1);
|
||||
httpServer.start();
|
||||
|
||||
|
||||
|
@ -1,50 +1,67 @@
|
||||
const host = window.location.hostname
|
||||
const ws = new WebSocket(`ws://${host}:3001`);
|
||||
const pc = new RTCPeerConnection({ iceServers: [] });
|
||||
const ws0 = new WebSocket(`ws://${host}:3001`);
|
||||
const ws1 = new WebSocket(`ws://${host}:3002`);
|
||||
const pc0 = new RTCPeerConnection({ iceServers: [] });
|
||||
const pc1 = new RTCPeerConnection({ iceServers: [] });
|
||||
const video0 = document.getElementById('video0') as HTMLVideoElement;
|
||||
const video1 = document.getElementById('video1') as HTMLVideoElement;
|
||||
|
||||
pc.onconnectionstatechange = (event) => {
|
||||
console.log("onconnectionstatechange ", event)
|
||||
}
|
||||
|
||||
pc.ondatachannel = (event) => {
|
||||
console.log("ondatachannel ", event)
|
||||
}
|
||||
|
||||
pc.ontrack = (event) => {
|
||||
// 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
|
||||
pc1.ontrack = (event) => {
|
||||
console.log("Received track event", event.streams);
|
||||
video1.srcObject = event.streams[0];
|
||||
};
|
||||
|
||||
pc.onicecandidate = ({ candidate }) => {
|
||||
pc1.onicecandidate = ({ candidate }) => {
|
||||
if (candidate) {
|
||||
ws.send(JSON.stringify({ type: 'ice-candidate', data: candidate })); // Use 'candidate' instead of 'ice-candidate'
|
||||
ws1.send(JSON.stringify({ type: 'ice-candidate', data: candidate }));
|
||||
}
|
||||
};
|
||||
pc.onicegatheringstatechange = () => {
|
||||
// console.log('ICE state:', pc.iceGatheringState);
|
||||
};
|
||||
|
||||
ws.onopen = async () => {
|
||||
pc.addTransceiver('video', { direction: 'recvonly' });
|
||||
pc.addTransceiver('audio', { direction: 'recvonly' })
|
||||
const offer = await pc.createOffer();
|
||||
await pc.setLocalDescription(offer);
|
||||
ws.send(JSON.stringify({ type: 'offer', data: offer }));
|
||||
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 }));
|
||||
}
|
||||
|
||||
ws.onmessage = async (message) => {
|
||||
ws1.onmessage = async (message) => {
|
||||
const msg = JSON.parse(message.data);
|
||||
|
||||
if (msg.type === 'answer') {
|
||||
await pc.setRemoteDescription(msg.data);
|
||||
await pc1.setRemoteDescription(msg.data);
|
||||
}
|
||||
|
||||
else if (msg.type === 'ice-candidate') {
|
||||
await pc.addIceCandidate(msg.data);
|
||||
await pc1.addIceCandidate(msg.data);
|
||||
}
|
||||
};
|
||||
|
||||
;
|
@ -3,14 +3,14 @@ import { ChildProcessWithoutNullStreams, spawn } from 'child_process';
|
||||
import * as ws from 'ws';
|
||||
|
||||
// Constants
|
||||
const VIDEO_DEVICE = '/dev/dvb/adapter0/dvr0'; // Video source device
|
||||
const WIDTH = 640; // Video width
|
||||
const HEIGHT = 480; // Video height
|
||||
const FRAME_SIZE = WIDTH * HEIGHT * 1.5; // YUV420p frame size (460800 bytes)
|
||||
|
||||
export default class TVWebSocket {
|
||||
|
||||
public constructor(port: number) {
|
||||
videoDevice: string;
|
||||
public constructor(port: number, videoDevice) {
|
||||
this.videoDevice = videoDevice
|
||||
const ffmpegProcess = this.startFFmpeg();
|
||||
const videoTrack = this.createVideoTrack(ffmpegProcess);
|
||||
const audioTrack = this.createAudioTrack(ffmpegProcess);
|
||||
@ -62,7 +62,7 @@ export default class TVWebSocket {
|
||||
startFFmpeg = (): ChildProcessWithoutNullStreams => {
|
||||
const p = spawn('ffmpeg', [
|
||||
'-loglevel', 'debug',
|
||||
'-i', VIDEO_DEVICE,
|
||||
'-i', this.videoDevice,
|
||||
|
||||
// Video
|
||||
'-map', '0:v:0',
|
||||
|
Loading…
Reference in New Issue
Block a user