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

View 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")]));
}
}

View 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;
}
}

View 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);
}
}