diff --git a/src/http.ts b/src/http.ts
index 4f41483..2428586 100644
--- a/src/http.ts
+++ b/src/http.ts
@@ -8,7 +8,7 @@ export default class HttpServer {
private httpServer: http.Server;
private port: number;
private root: string;
- public constructor(port: number, root: string, tune: (ch: string, adp?: number) => void, getChannels: ()=>string[], getSignal: (adapter:number)=>object) {
+ public constructor(port: number, root: string, tune: (ch: string, adp?: number) => void, getChannels: ()=>string[]) {
this.port = port;
this.root = root;
this.httpServer = http.createServer((req, res) => {
@@ -27,11 +27,6 @@ export default class HttpServer {
body = JSON.stringify(getChannels());
status = 200;
break;
- case "signal":
- const adapter = parseInt(url.searchParams.get('adapter'));
- body = JSON.stringify(getSignal(adapter));
- status = 200;
- break;
}
break;
diff --git a/src/server.ts b/src/server.ts
index 17cecfc..9ab196a 100644
--- a/src/server.ts
+++ b/src/server.ts
@@ -20,16 +20,17 @@ const tune = (reqChannel: string, reqAdapter?: number) => {
});
}
-const getChannels = () =>
- zap.getChannels();
+const getChannels = zap.getChannels.bind(zap)
+const getMetaData0 = zap.getMetaData.bind(zap,0)
+const getMetaData1 = zap.getMetaData.bind(zap,1)
-const getSignal = (adapter: number) =>
- zap.getSignal(adapter)
-const httpServer = new HttpServer(HTTP_PORT, STATIC_ROOT, tune, getChannels, getSignal);
-const tvWebSocket0 = new TVWebSocket(WS_PORT, TV_DEV_0);
-const tvWebSocket1 = new TVWebSocket(WS_PORT + 1, TV_DEV_1);
+const httpServer = new HttpServer(HTTP_PORT, STATIC_ROOT, tune, getChannels);
+const tvWebSocket0 = new TVWebSocket(WS_PORT, TV_DEV_0, getMetaData0);
+const tvWebSocket1 = new TVWebSocket(WS_PORT + 1, TV_DEV_1, getMetaData1);
httpServer.start();
+tune('ION',0);
+tune("KGW",1);
process.stdin.setEncoding("utf8");
diff --git a/src/static/index.html b/src/static/index.html
index 6675c38..26cd3cb 100644
--- a/src/static/index.html
+++ b/src/static/index.html
@@ -2,7 +2,7 @@
- WebRTC Stream
+ PDX Airwave TV
@@ -11,24 +11,23 @@
- Video streams
- WebRTC
+ Portland Airwave Television
+
-
+
N/A
+
-
N/A
-
+
-
+
N/A
+
-
N/A
-
-
+
diff --git a/src/static/js/video.ts b/src/static/js/video.ts
index c6fc4ba..6abd54f 100644
--- a/src/static/js/video.ts
+++ b/src/static/js/video.ts
@@ -13,10 +13,40 @@ const config = {
}
]
};
+
+
+interface IData {
+ channel: string,
+ signal: number,
+ cn: number
+}
+
const pc0 = new RTCPeerConnection(config);
const pc1 = new RTCPeerConnection(config);
-const video0 = document.getElementById('video0') as HTMLVideoElement;
-const video1 = document.getElementById('video1') as HTMLVideoElement;
+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) => {
@@ -49,6 +79,24 @@ ws0.onmessage = async (message) => {
};
// 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];
diff --git a/src/ws.ts b/src/ws.ts
index 95afcab..db3d4b7 100644
--- a/src/ws.ts
+++ b/src/ws.ts
@@ -9,7 +9,7 @@ const FRAME_SIZE = WIDTH * HEIGHT * 1.5; // YUV420p frame size (460800 bytes)
export default class TVWebSocket {
videoDevice: string;
- public constructor(port: number, videoDevice) {
+ public constructor(port: number, videoDevice, getMetaData: ()=>any) {
this.videoDevice = videoDevice
const ffmpegProcess = this.startFFmpeg();
const videoTrack = this.createVideoTrack(ffmpegProcess);
@@ -25,7 +25,29 @@ export default class TVWebSocket {
wss.on('connection', async (ws: ws.WebSocket) => {
const peerConnection: RTCPeerConnection = this.createPeerConnection(videoTrack, audioTrack);
+ peerConnection.ondatachannel = (event) => {
+ const dataChannel = event.channel; // This is the data channel created by the client
+ dataChannel.onopen = () => {
+ console.log('📬 Server: Data channel opened');
+ // Now you can send data through the channel
+ setInterval(() => {
+ if (dataChannel.readyState === 'open') {
+ const metaData = getMetaData(); // Example function to fetch data
+ dataChannel.send(JSON.stringify(metaData)); // Send data to the client
+ }
+
+ }, 1000);
+ };
+
+ dataChannel.onmessage = (event) => {
+ console.log("📦 Server received message:", event.data);
+ };
+
+ dataChannel.onclose = () => {
+ console.log("📴 Server: Data channel closed");
+ };
+ }
ws.on('message', async (message: Buffer) => {
const { type, data } = JSON.parse(message.toString());
@@ -71,10 +93,12 @@ export default class TVWebSocket {
// Video
'-map', '0:v:0',
- '-vf', `scale=${WIDTH}:${HEIGHT}`,
+ '-framerate', '24',
+ '-vf', `scale=${WIDTH}:${HEIGHT}:flags=fast_bilinear`,
'-vcodec', 'rawvideo',
'-pix_fmt', 'yuv420p',
'-f', 'rawvideo',
+ '-threads', '1',
//quality
'-fflags', '+discardcorrupt',
diff --git a/src/zap.ts b/src/zap.ts
index 11397b0..dc9f251 100644
--- a/src/zap.ts
+++ b/src/zap.ts
@@ -5,10 +5,10 @@ export interface IZap {
process: ChildProcessWithoutNullStreams | null,
channel: string,
adapter: 0 | 1
- strength: {
- signal: string;
- cn: string;
- },
+
+ signal: string;
+ cn: string;
+
}
export default class Zap {
@@ -17,27 +17,27 @@ export default class Zap {
private channelNameList: string[];
private fileName: string;
- private regex = /Signal=\s*(-?\d+(\.\d+)?dBm)\s+C\/N=\s*(\d+(\.\d+)?dB)/;
+ private regex = /Signal=\s*(-?\d+(\.\d+)?dBm)\s+C\/N=\s*(\d+(\.\d+)?dB)/;
public constructor(fileName = "dvb_channel.conf", channel = "ION") {
const zap0: IZap = {
process: null,
- channel,
+ channel: "None",
adapter: 0,
- strength: {
- signal: "None",
- cn: "None"
- }
+
+ signal: "None",
+ cn: "None"
+
}
const zap1: IZap = {
process: null,
- channel,
+ channel: "None",
adapter: 1,
- strength: {
- signal: "None",
- cn: "None"
- }
+
+ signal: "None",
+ cn: "None"
+
}
this.zap0 = zap0;
this.zap1 = zap1;
@@ -53,19 +53,12 @@ export default class Zap {
return this.channelNameList;
}
- public getSignal(adapter: number) {
- if(adapter == 0){
- return this.zap0.strength;
- }
- else if (adapter == 1){
- return this.zap1.strength;
- }
- else {
- return {signal: 'N/A', cn: 'N/A'}
- }
+ public getMetaData(adapter: 0 | 1) {
+ const { channel, signal, cn } = adapter === 0 ? this.zap0 : this.zap1
+ return { channel, signal, cn }
}
- private nextChannel(channel: string) :string {
+ private nextChannel(channel: string): string {
const size = this.channelNameList.length;
const currentIndex = this.channelNameList.indexOf(channel);
if (currentIndex >= 0) {
@@ -76,11 +69,11 @@ export default class Zap {
}
}
- private mod(n: number, m: number) :number{
+ private mod(n: number, m: number): number {
return ((n % m) + m) % m;
}
- private previousChannel(channel: string):string {
+ private previousChannel(channel: string): string {
const size = this.channelNameList.length;
const currentIndex = this.channelNameList.indexOf(channel);
if (currentIndex >= 0) {
@@ -138,10 +131,8 @@ export default class Zap {
clearTimeout(lockTimer);
const match = output.match(this.regex);
zap.channel = verifiedChannel;
- zap.strength = {
- signal: match[1],
- cn: match[3]
- }
+ zap.signal = match[1],
+ zap.cn = match[3]
resolve(zap);
}