First tests and integration of radio panel

This commit is contained in:
Davide Passoni
2024-08-31 10:12:25 +02:00
parent ebfa7916c6
commit ba2c48dead
26 changed files with 844 additions and 69 deletions

BIN
frontend/server/Example.ogg Normal file

Binary file not shown.

View File

@@ -10,6 +10,7 @@
},
"private": true,
"dependencies": {
"@discordjs/opus": "^0.9.0",
"appjs": "^0.0.20",
"appjs-win32": "^0.0.19",
"body-parser": "^1.20.2",
@@ -21,6 +22,7 @@
"express-basic-auth": "^1.2.1",
"http-proxy-middleware": "^2.0.6",
"morgan": "~1.9.1",
"node-opus": "^0.3.3",
"open": "^10.0.0",
"regedit": "^5.1.2",
"save": "^2.9.0",
@@ -28,6 +30,7 @@
"srtm-elevation": "^2.1.2",
"tcp-ping-port": "^1.0.1",
"uuid": "^9.0.1",
"wavefile": "^11.0.0",
"ws": "^8.18.0",
"yargs": "^17.7.2"
},

BIN
frontend/server/sample1.WAV Normal file

Binary file not shown.

BIN
frontend/server/sample3.WAV Normal file

Binary file not shown.

View File

@@ -5,6 +5,7 @@ import logger = require("morgan");
import fs = require("fs");
import bodyParser = require("body-parser");
import cors = require("cors");
import { AudioBackend } from "./audio/audiobackend";
/* Load the proxy middleware plugin */
import httpProxyMiddleware = require("http-proxy-middleware");
@@ -83,5 +84,10 @@ module.exports = function (configLocation, viteProxy) {
});
}
if (config["audio"]) {
let audioBackend = new AudioBackend(config["audio"]["SRSPort"], config["audio"]["WSPort"]);
audioBackend.start();
}
return app;
};

View File

@@ -0,0 +1,27 @@
import { WebSocketServer } from "ws";
import { SRSHandler } from "./srshandler";
export class AudioBackend {
SRSPort: number = 5002;
WSPort: number = 4000;
handlers: SRSHandler[] = [];
constructor(SRSPort, WSPort) {
this.SRSPort = SRSPort ?? this.SRSPort;
this.WSPort = WSPort ?? this.WSPort;
}
start() {
const wss = new WebSocketServer({ port: this.WSPort });
wss.on("connection", (ws) => {
this.handlers.push(new SRSHandler(ws, this.SRSPort));
});
wss.on("disconnection", (ws) => {
this.handlers = this.handlers.filter((handler) => {
handler.ws != ws;
});
});
}
}

View File

@@ -0,0 +1,112 @@
export var defaultSRSData = {
ClientGuid: "",
Name: "",
Seat: 0,
Coalition: 0,
AllowRecord: false,
RadioInfo: {
radios: [
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
],
unit: "",
unitId: 0,
iff: {
control: 2,
mode1: -1,
mode2: -1,
mode3: -1,
mode4: false,
mic: -1,
status: 0,
},
ambient: { vol: 1.0, abType: "" },
},
LatLngPosition: { lat: 0.0, lng: 0.0, alt: 0.0 },
};

View File

@@ -0,0 +1,84 @@
import { defaultSRSData } from "./defaultdata";
var net = require("net");
const SRS_VERSION = "2.1.0.10";
var globalIndex = 1;
enum MessageType {
audio,
settings,
}
function makeID(length) {
let result = "";
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const charactersLength = characters.length;
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}
export class SRSHandler {
ws: any;
tcp = new net.Socket();
udp = require("dgram").createSocket("udp4");
data = JSON.parse(JSON.stringify(defaultSRSData));
syncInterval: any;
constructor(ws, SRSPort) {
this.data.ClientGuid = "ImF72dh9EYcIDyYRGaF9S9";
this.data.Name = `Olympus${globalIndex}`;
globalIndex += 1;
/* Websocket */
this.ws = ws;
this.ws.on("error", console.error);
this.ws.on("message", (data) => {
switch (data[0]) {
case MessageType.audio:
this.udp.send(data.slice(1), 5002, "localhost", function (error) {
if (error) {
console.log("Error!!!");
} else {
console.log("Data sent");
}
});
break;
case MessageType.settings:
let message = JSON.parse(data.slice(1));
message.settings.forEach((setting, idx) => {
this.data.RadioInfo.radios[idx].freq = setting.frequency;
this.data.RadioInfo.radios[idx].modulation = setting.modulation;
})
break;
default:
break;
}
});
this.ws.on("close", () => {
this.tcp.end();
});
/* TCP */
this.tcp.connect(SRSPort, "localhost", () => {
console.log("Connected");
this.syncInterval = setInterval(() => {
let SYNC = {
Client: this.data,
MsgType: 2,
Version: SRS_VERSION,
};
if (this.tcp.readyState == "open")
this.tcp.write(`${JSON.stringify(SYNC)}\n`);
else clearInterval(this.syncInterval);
}, 1000);
});
}
}

View File

@@ -7,7 +7,7 @@ module.exports = function (configLocation) {
if (fs.existsSync(configLocation)) {
let rawdata = fs.readFileSync(configLocation, "utf-8");
const config = JSON.parse(rawdata);
res.send(JSON.stringify(config.frontend));
res.send(JSON.stringify({...config.frontend, ...(config.audio ?? {}) }));
res.end()
} else {
res.sendStatus(404);

219
frontend/server/srs.js Normal file
View File

@@ -0,0 +1,219 @@
const WaveFile = require('wavefile').WaveFile;
var fs = require('fs');
let source = fs.readFileSync('sample3.WAV');
let wav = new WaveFile(source);
let wavBuffer = wav.toBuffer();
const { OpusEncoder } = require('@discordjs/opus');
const encoder = new OpusEncoder(16000, 1);
let fileIndex = 0;
let packetID = 0;
var udp = require("dgram");
var udpClient = udp.createSocket("udp4");
let clientData = {
ClientGuid: "AZi9CkptY0yW_C-3YmI7oQ",
Name: "Olympus",
Seat: 0,
Coalition: 0,
AllowRecord: false,
RadioInfo: {
radios: [
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
{
enc: false,
encKey: 0,
freq: 1.0,
modulation: 3,
secFreq: 1.0,
retransmit: false,
},
],
unit: "",
unitId: 0,
iff: {
control: 2,
mode1: -1,
mode2: -1,
mode3: -1,
mode4: false,
mic: -1,
status: 0,
},
ambient: { vol: 1.0, abType: "" },
},
LatLngPosition: { lat: 0.0, lng: 0.0, alt: 0.0 },
};
var net = require("net");
var tcpClient = new net.Socket();
tcpClient.on("data", function (data) {
console.log("Received: " + data);
});
tcpClient.on("close", function () {
console.log("Connection closed");
});
tcpClient.connect(5002, "localhost", function () {
console.log("Connected");
setTimeout(() => {
let SYNC = {
Client: clientData,
MsgType: 2,
Version: "2.1.0.10",
};
let string = JSON.stringify(SYNC);
tcpClient.write(string + "\n");
setInterval(() => {
let slice = [];
for (let i = 0; i < 16000 * 0.04; i++) {
slice.push(wavBuffer[Math.round(fileIndex) * 2], wavBuffer[Math.round(fileIndex) * 2 + 1]);
fileIndex += 44100 / 16000;
}
const encoded = encoder.encode(new Uint8Array(slice));
let header = [
0, 0,
0, 0,
0, 0
]
let encFrequency = [...doubleToByteArray(251000000)];
let encModulation = [2];
let encEncryption = [0];
let encUnitID = getBytes(100000001, 4);
let encPacketID = getBytes(packetID, 8);
packetID++;
let encHops = [0];
let packet = [].concat(header, [...encoded], encFrequency, encModulation, encEncryption, encUnitID, encPacketID, encHops, [...Buffer.from(clientData.ClientGuid, 'utf-8')], [...Buffer.from(clientData.ClientGuid, 'utf-8')]);
let encPacketLen = getBytes(packet.length, 2);
packet[0] = encPacketLen[0];
packet[1] = encPacketLen[1];
let encAudioLen = getBytes(encoded.length, 2);
packet[2] = encAudioLen[0];
packet[3] = encAudioLen[1];
let frequencyAudioLen = getBytes(10, 2);
packet[4] = frequencyAudioLen[0];
packet[5] = frequencyAudioLen[1];
let data = new Uint8Array(packet);
udpClient.send(data, 5002, "localhost", function (error) {
if (error) {
tcpClient.close();
} else {
console.log("Data sent !!!");
}
});
}, 40);
}, 1000);
});
function getBytes(value, length) {
let res = [];
for (let i = 0; i < length; i++) {
res.push(value & 255);
value = value >> 8;
}
return res;
}
function doubleToByteArray(number) {
var buffer = new ArrayBuffer(8); // JS numbers are 8 bytes long, or 64 bits
var longNum = new Float64Array(buffer); // so equivalent to Float64
longNum[0] = number;
return Array.from(new Uint8Array(buffer));
}