mirror of
https://github.com/Pax1601/DCSOlympus.git
synced 2025-10-29 16:56:34 +00:00
First tests and integration of radio panel
This commit is contained in:
BIN
frontend/server/Example.ogg
Normal file
BIN
frontend/server/Example.ogg
Normal file
Binary file not shown.
@@ -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
BIN
frontend/server/sample1.WAV
Normal file
Binary file not shown.
BIN
frontend/server/sample3.WAV
Normal file
BIN
frontend/server/sample3.WAV
Normal file
Binary file not shown.
@@ -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;
|
||||
};
|
||||
|
||||
27
frontend/server/src/audio/audiobackend.ts
Normal file
27
frontend/server/src/audio/audiobackend.ts
Normal 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;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
112
frontend/server/src/audio/defaultdata.ts
Normal file
112
frontend/server/src/audio/defaultdata.ts
Normal 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 },
|
||||
};
|
||||
84
frontend/server/src/audio/srshandler.ts
Normal file
84
frontend/server/src/audio/srshandler.ts
Normal 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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
219
frontend/server/srs.js
Normal 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));
|
||||
}
|
||||
Reference in New Issue
Block a user