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:
88
frontend/react/src/audio/audiomanager.ts
Normal file
88
frontend/react/src/audio/audiomanager.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { AudioRadioSetting } from "../interfaces";
|
||||
import { getApp } from "../olympusapp";
|
||||
import { Buffer } from "buffer";
|
||||
import { MicrophoneHandler } from "./microphonehandler";
|
||||
|
||||
enum MessageType {
|
||||
audio,
|
||||
settings,
|
||||
}
|
||||
|
||||
export class AudioManager {
|
||||
#radioSettings: AudioRadioSetting[] = [
|
||||
{
|
||||
frequency: 124000000,
|
||||
modulation: 0,
|
||||
ptt: false,
|
||||
tuned: false,
|
||||
volume: 0.5,
|
||||
},
|
||||
];
|
||||
|
||||
#microphoneHandlers: (MicrophoneHandler | null)[] =[];
|
||||
|
||||
#address: string = "localhost";
|
||||
#port: number = 4000;
|
||||
#socket: WebSocket | null = null;
|
||||
|
||||
constructor() {
|
||||
document.addEventListener("configLoaded", () => {
|
||||
let config = getApp().getConfig();
|
||||
if (config["WSPort"]) {
|
||||
this.setPort(config["WSPort"]);
|
||||
this.start();
|
||||
}
|
||||
});
|
||||
|
||||
this.#microphoneHandlers = this.#radioSettings.map(() => null);
|
||||
}
|
||||
|
||||
start() {
|
||||
let res = this.#address.match(/(?:http|https):\/\/(.+):/);
|
||||
let wsAddress = res ? res[1] : this.#address;
|
||||
|
||||
this.#socket = new WebSocket(`ws://${wsAddress}:${this.#port}`);
|
||||
|
||||
this.#socket.addEventListener("open", (event) => {
|
||||
console.log("Connection to audio websocket successfull");
|
||||
});
|
||||
|
||||
this.#socket.addEventListener("error", (event) => {
|
||||
console.log(event);
|
||||
});
|
||||
|
||||
this.#socket.addEventListener("message", (event) => {
|
||||
console.log("Message from server ", event.data);
|
||||
});
|
||||
}
|
||||
|
||||
setAddress(address) {
|
||||
this.#address = address;
|
||||
}
|
||||
|
||||
setPort(port) {
|
||||
this.#port = port;
|
||||
}
|
||||
|
||||
getRadioSettings() {
|
||||
return JSON.parse(JSON.stringify(this.#radioSettings));
|
||||
}
|
||||
|
||||
setRadioSettings(radioSettings: AudioRadioSetting[]) {
|
||||
this.#radioSettings = radioSettings;
|
||||
|
||||
let message = {
|
||||
type: "Settings update",
|
||||
settings: this.#radioSettings,
|
||||
};
|
||||
|
||||
this.#radioSettings.forEach((setting, idx) => {
|
||||
if (setting.ptt && !this.#microphoneHandlers[idx]) {
|
||||
this.#microphoneHandlers[idx] = new MicrophoneHandler(this.#socket, setting);
|
||||
}
|
||||
})
|
||||
|
||||
if (this.#socket?.readyState == 1)
|
||||
this.#socket?.send(new Uint8Array([MessageType.settings, ...Buffer.from(JSON.stringify(message), "utf-8")]));
|
||||
}
|
||||
}
|
||||
70
frontend/react/src/audio/audiopacket.ts
Normal file
70
frontend/react/src/audio/audiopacket.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { Buffer } from "buffer";
|
||||
|
||||
function getBytes(value, length) {
|
||||
let res: number[] = [];
|
||||
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));
|
||||
}
|
||||
|
||||
var packetID = 0;
|
||||
|
||||
export class AudioPacket {
|
||||
#packet: Uint8Array;
|
||||
|
||||
constructor(data, settings) {
|
||||
let header: number[] = [0, 0, 0, 0, 0, 0];
|
||||
|
||||
let encFrequency: number[] = [...doubleToByteArray(settings.frequency)];
|
||||
let encModulation: number[] = [settings.modulation];
|
||||
let encEncryption: number[] = [0];
|
||||
|
||||
let encUnitID: number[] = getBytes(100000001, 4);
|
||||
let encPacketID: number[] = getBytes(packetID, 8);
|
||||
packetID++;
|
||||
let encHops: number[] = [0];
|
||||
|
||||
let packet: number[] = ([] as number[]).concat(
|
||||
header,
|
||||
[...data],
|
||||
encFrequency,
|
||||
encModulation,
|
||||
encEncryption,
|
||||
encUnitID,
|
||||
encPacketID,
|
||||
encHops,
|
||||
[...Buffer.from("ImF72dh9EYcIDyYRGaF9S9", "utf-8")],
|
||||
[...Buffer.from("ImF72dh9EYcIDyYRGaF9S9", "utf-8")]
|
||||
);
|
||||
|
||||
let encPacketLen = getBytes(packet.length, 2);
|
||||
packet[0] = encPacketLen[0];
|
||||
packet[1] = encPacketLen[1];
|
||||
|
||||
let encAudioLen = getBytes(data.length, 2);
|
||||
packet[2] = encAudioLen[0];
|
||||
packet[3] = encAudioLen[1];
|
||||
|
||||
let frequencyAudioLen = getBytes(10, 2);
|
||||
packet[4] = frequencyAudioLen[0];
|
||||
packet[5] = frequencyAudioLen[1];
|
||||
|
||||
|
||||
this.#packet = new Uint8Array([0].concat(packet));
|
||||
}
|
||||
|
||||
getArray() {
|
||||
return this.#packet;
|
||||
}
|
||||
}
|
||||
52
frontend/react/src/audio/microphonehandler.ts
Normal file
52
frontend/react/src/audio/microphonehandler.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { AudioRadioSetting } from "../interfaces";
|
||||
import { AudioPacket } from "./audiopacket";
|
||||
|
||||
export class MicrophoneHandler {
|
||||
#socket: WebSocket;
|
||||
#setting: AudioRadioSetting;
|
||||
|
||||
constructor(socket, setting) {
|
||||
this.#socket = socket;
|
||||
this.#setting = setting;
|
||||
|
||||
console.log("Starting microphone handler");
|
||||
|
||||
//@ts-ignore
|
||||
let getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
|
||||
|
||||
if (getUserMedia) {
|
||||
//@ts-ignore
|
||||
navigator.getUserMedia(
|
||||
{ audio: {
|
||||
sampleRate: 16000,
|
||||
channelCount: 1,
|
||||
volume: 1.0
|
||||
} },
|
||||
(stream) => {
|
||||
this.start_microphone(stream);
|
||||
},
|
||||
(e) => {
|
||||
alert("Error capturing audio.");
|
||||
}
|
||||
);
|
||||
} else {
|
||||
alert("getUserMedia not supported in this browser.");
|
||||
}
|
||||
}
|
||||
|
||||
start_microphone(stream) {
|
||||
const recorder = new MediaRecorder(stream);
|
||||
|
||||
// fires every one second and passes an BlobEvent
|
||||
recorder.ondataavailable = async (event) => {
|
||||
// get the Blob from the event
|
||||
const blob = event.data;
|
||||
|
||||
let rawData = await blob.arrayBuffer();
|
||||
let packet = new AudioPacket(new Uint8Array(rawData), this.#setting);
|
||||
this.#socket.send(packet.getArray());
|
||||
};
|
||||
|
||||
recorder.start(200);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user