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