From 7f483770f229c061206ac0f8bbf70aa78a931faf Mon Sep 17 00:00:00 2001 From: NoobishSVK Date: Mon, 25 Mar 2024 23:23:14 +0100 Subject: [PATCH] bugfixes, refactor, code removal --- package-lock.json | 41 +--- package.json | 7 +- server/index.js | 8 +- server/stream/3las.server.js | 95 +------- server/stream/index.js | 14 +- web/css/buttons.css | 12 +- web/css/helpers.css | 2 +- web/{favicon2.png => favicon.png} | Bin web/index.ejs | 26 +-- web/js/3las/3las.js | 66 +----- web/js/3las/3las.webrtc.js | 177 --------------- web/js/3las/main.js | 51 ++--- web/js/chat.js | 155 ++++++------- web/js/dropdown.js | 2 - web/js/init.js | 7 + web/js/main.js | 1 - web/js/modal.js | 61 +++--- web/js/settings.js | 350 +++++++++++++++--------------- web/setup.ejs | 2 +- web/wizard.ejs | 2 +- 20 files changed, 342 insertions(+), 737 deletions(-) rename web/{favicon2.png => favicon.png} (100%) delete mode 100644 web/js/3las/3las.webrtc.js diff --git a/package-lock.json b/package-lock.json index 5cae562..c1be744 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "fm-dx-webserver", - "version": "1.1.7", + "version": "1.1.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "fm-dx-webserver", - "version": "1.1.7", + "version": "1.1.8", "license": "ISC", "dependencies": { "@mapbox/node-pre-gyp": "1.0.11", @@ -14,14 +14,13 @@ "ejs": "3.1.9", "express": "4.18.3", "express-session": "1.18.0", - "ffmpeg-static": "^5.2.0", + "ffmpeg-static": "5.2.0", "http": "0.0.1-security", "http-proxy": "1.18.1", "https": "1.0.0", "koffi": "2.7.2", "net": "1.0.2", "serialport": "12.0.0", - "wrtc": "0.4.7", "ws": "8.14.2" } }, @@ -659,16 +658,6 @@ "node": ">=8" } }, - "node_modules/domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "deprecated": "Use your platform's native DOMException instead", - "optional": true, - "dependencies": { - "webidl-conversions": "^4.0.2" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1893,12 +1882,6 @@ "node": ">= 0.8" } }, - "node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "optional": true - }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -1926,24 +1909,6 @@ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "node_modules/wrtc": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/wrtc/-/wrtc-0.4.7.tgz", - "integrity": "sha512-P6Hn7VT4lfSH49HxLHcHhDq+aFf/jd9dPY7lDHeFhZ22N3858EKuwm2jmnlPzpsRGEPaoF6XwkcxY5SYnt4f/g==", - "bundleDependencies": [ - "node-pre-gyp" - ], - "hasInstallScript": true, - "dependencies": { - "node-pre-gyp": "^0.13.0" - }, - "engines": { - "node": "^8.11.2 || >=10.0.0" - }, - "optionalDependencies": { - "domexception": "^1.0.1" - } - }, "node_modules/ws": { "version": "8.14.2", "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", diff --git a/package.json b/package.json index e76380a..662a11e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "fm-dx-webserver", - "version": "1.1.7", - "description": "", + "version": "1.1.8", + "description": "FM DX Webserver", "main": "index.js", "scripts": { "debug": "node index.js --debug", @@ -17,14 +17,13 @@ "ejs": "3.1.9", "express": "4.18.3", "express-session": "1.18.0", - "ffmpeg-static": "^5.2.0", + "ffmpeg-static": "5.2.0", "http": "0.0.1-security", "http-proxy": "1.18.1", "https": "1.0.0", "koffi": "2.7.2", "net": "1.0.2", "serialport": "12.0.0", - "wrtc": "0.4.7", "ws": "8.14.2" } } diff --git a/server/index.js b/server/index.js index 4b7740b..6b38518 100644 --- a/server/index.js +++ b/server/index.js @@ -34,7 +34,7 @@ console.log(`\x1b[32m |_| |_| |_| |____/_/\\_\\ \\_/\\_/ \\___|_.__/|___/\\___|_| \\_/ \\___|_| `); console.log('\x1b[0mFM-DX-Webserver', pjson.version); -console.log('\x1b[90m======================================================'); +console.log('\x1b[90m―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――'); // Start ffmpeg require('./stream/index'); @@ -83,7 +83,7 @@ function connectToSerial() { serialport.write('C0\n'); serialport.write('I0,0\n'); - if(serverConfig.defaultFreq) { + if(serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true) { serialport.write('T' + Math.round(serverConfig.defaultFreq * 1000) +'\n'); dataHandler.initialData.freq = Number(serverConfig.defaultFreq).toFixed(3); dataHandler.dataToSend.freq = Number(serverConfig.defaultFreq).toFixed(3); @@ -160,7 +160,9 @@ function connectToXdrd() { if (authFlags.authMsg && authFlags.firstClient) { client.write('x\n'); - client.write(serverConfig.defaultFreq ? 'T' + Math.round(serverConfig.defaultFreq * 1000) + '\n' : 'T87500\n'); + client.write(serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true ? 'T' + Math.round(serverConfig.defaultFreq * 1000) + '\n' : 'T87500\n'); + dataHandler.initialData.freq = serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true ? (serverConfig.defaultFreq).toFixed(3) : (87.5).toFixed(3); + dataHandler.dataToSend.freq = serverConfig.defaultFreq && serverConfig.enableDefaultFreq === true ? (serverConfig.defaultFreq).toFixed(3) : (87.5).toFixed(3); client.write('A0\n'); client.write(serverConfig.audio.startupVolume ? 'Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n' : 'Y100\n'); client.off('data', authDataHandler); diff --git a/server/stream/3las.server.js b/server/stream/3las.server.js index 5637ab2..e12bbef 100644 --- a/server/stream/3las.server.js +++ b/server/stream/3las.server.js @@ -39,54 +39,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = require("fs"); const child_process_1 = require("child_process"); const ws = __importStar(require("ws")); -const wrtc = require('wrtc'); const Settings = JSON.parse((0, fs_1.readFileSync)('server/stream/settings.json', 'utf-8')); const FFmpeg_command = ffmpegStaticPath; -class RtcProvider { - constructor() { - this.RtcDistributePeer = new wrtc.RTCPeerConnection(Settings.RtcConfig); - this.RtcDistributePeer.addTransceiver('audio'); - this.RtcDistributePeer.ontrack = this.OnTrack.bind(this); - this.RtcDistributePeer.onicecandidate = this.OnIceCandidate_Distribute.bind(this); - this.RtcSourcePeer = new wrtc.RTCPeerConnection(Settings.RtcConfig); - this.RtcSourceMediaSource = new wrtc.nonstandard.RTCAudioSource(); - this.RtcSourceTrack = this.RtcSourceMediaSource.createTrack(); - this.RtcSourcePeer.addTrack(this.RtcSourceTrack); - this.RtcSourcePeer.onicecandidate = this.OnIceCandidate_Source.bind(this); - this.Init(); - } - Init() { - return __awaiter(this, void 0, void 0, function* () { - let offer = yield this.RtcSourcePeer.createOffer(); - yield this.RtcSourcePeer.setLocalDescription(new wrtc.RTCSessionDescription(offer)); - yield this.RtcDistributePeer.setRemoteDescription(offer); - let answer = yield this.RtcDistributePeer.createAnswer(); - yield this.RtcDistributePeer.setLocalDescription(new wrtc.RTCSessionDescription(answer)); - yield this.RtcSourcePeer.setRemoteDescription(new wrtc.RTCSessionDescription(answer)); - }); - } - OnTrack(event) { - this.RtcDistributeTrack = event.track; - } - OnIceCandidate_Distribute(e) { - if (!e.candidate) - return; - (() => __awaiter(this, void 0, void 0, function* () { return yield this.RtcSourcePeer.addIceCandidate(e.candidate); }))(); - } - OnIceCandidate_Source(e) { - if (!e.candidate) - return; - (() => __awaiter(this, void 0, void 0, function* () { return yield this.RtcDistributePeer.addIceCandidate(e.candidate); }))(); - } - InsertMediaData(data) { - if (!this.RtcSourceMediaSource) - return; - this.RtcSourceMediaSource.onData(data); - } - GetTrack() { - return this.RtcDistributeTrack; - } -} class StreamClient { constructor(server, socket) { this.Server = server; @@ -102,10 +56,7 @@ class StreamClient { try { let request = JSON.parse(message.toString()); if (request.type == "answer") { - (() => __awaiter(this, void 0, void 0, function* () { return yield this.RtcPeer.setRemoteDescription(new wrtc.RTCSessionDescription(request.data)); }))(); - } - else if (request.type == "webrtc") { - this.Server.SetWebRtc(this); + } else if (request.type == "fallback") { this.Server.SetFallback(this, request.data); @@ -137,17 +88,6 @@ class StreamClient { } catch (ex) { } - if (this.RtcSender && this.RtcPeer) - this.RtcPeer.removeTrack(this.RtcSender); - if (this.RtcSender) - this.RtcSender = null; - if (this.RtcTrack) - this.RtcTrack = null; - if (this.RtcPeer) { - this.RtcPeer.close(); - delete this.RtcPeer; - this.RtcPeer = null; - } } SendBinary(buffer) { if (this.Socket.readyState != ws.OPEN) { @@ -163,28 +103,6 @@ class StreamClient { } this.Socket.send(text); } - StartRtc(track) { - return __awaiter(this, void 0, void 0, function* () { - this.RtcPeer = new wrtc.RTCPeerConnection(Settings.RtcConfig); - this.RtcTrack = track; - this.RtcSender = this.RtcPeer.addTrack(this.RtcTrack); - this.RtcPeer.onconnectionstatechange = this.OnConnectionStateChange.bind(this); - this.RtcPeer.onicecandidate = this.OnIceCandidate.bind(this); - let offer = yield this.RtcPeer.createOffer(); - yield this.RtcPeer.setLocalDescription(new wrtc.RTCSessionDescription(offer)); - this.SendText(JSON.stringify({ - "type": "offer", - "data": offer - })); - }); - } - OnConnectionStateChange(e) { - if (!this.RtcPeer) - return; - let state = this.RtcPeer.connectionState; - if (state != "new" && state != "connecting" && state != "connected") - this.OnError(null); - } OnIceCandidate(e) { if (e.candidate) { this.SendText(JSON.stringify({ @@ -199,9 +117,7 @@ class StreamServer { this.Port = port; this.Channels = channels; this.SampleRate = sampleRate; - this.RtcProvider = new RtcProvider(); this.Clients = new Set(); - this.RtcClients = new Set(); this.FallbackClients = { "wav": new Set(), "mp3": new Set() @@ -246,7 +162,6 @@ class StreamServer { "channelCount": this.Channels, "numberOfFrames": this.SamplesCount, }; - this.RtcProvider.InsertMediaData(data); this.Samples = new Int16Array(this.Channels * this.SamplesCount); this.SamplesPosition = 0; } @@ -266,30 +181,22 @@ class StreamServer { this.FallbackClients[format].add(client); this.FallbackProvider[format].PrimeClient(client); } - SetWebRtc(client) { - this.RtcClients.add(client); - client.StartRtc(this.RtcProvider.GetTrack()); - } DestroyClient(client) { this.FallbackClients["mp3"].delete(client); this.FallbackClients["wav"].delete(client); - this.RtcClients.delete(client); this.Clients.delete(client); client.Destroy(); } GetStats() { - let rtc = this.RtcClients.size; let fallback = { "wav": (this.FallbackClients["wav"] ? this.FallbackClients["wav"].size : 0), "mp3": (this.FallbackClients["mp3"] ? this.FallbackClients["mp3"].size : 0), }; - let total = rtc; for (let format in fallback) { total += fallback[format]; } return { "Total": total, - "Rtc": rtc, "Fallback": fallback, }; } diff --git a/server/stream/index.js b/server/stream/index.js index 6de5d4a..b5fbb64 100644 --- a/server/stream/index.js +++ b/server/stream/index.js @@ -8,7 +8,7 @@ function enableAudioStream() { var ffmpegParams; var ffmpegCommand; serverConfig.webserver.webserverPort = Number(serverConfig.webserver.webserverPort); -const ffmpegPath = "\"" + ffmpeg.replace(/\\/g, '\\\\') + "\""; + const flags = `-fflags +nobuffer+flush_packets -flags low_delay -rtbufsize 6192 -probesize 32`; const codec = `-acodec pcm_s16le -ar 48000 -ac ${serverConfig.audio.audioChannels}`; const output = `-f s16le -fflags +nobuffer+flush_packets -packetsize 384 -flush_packets 1 -bufsize 960`; @@ -23,11 +23,12 @@ const ffmpegPath = "\"" + ffmpeg.replace(/\\/g, '\\\\') + "\""; ffmpegParams = `${flags} -f alsa -i "${serverConfig.audio.softwareMode && serverConfig.audio.softwareMode == true ? 'plug' : ''}${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node server/stream/3las.server.js -port ${serverConfig.webserver.webserverPort + 10} -samplerate 48000 -channels ${serverConfig.audio.audioChannels}`; } - consoleCmd.logInfo("Using audio device: " + serverConfig.audio.audioDevice); - consoleCmd.logInfo(`Launching audio stream on internal port ${serverConfig.webserver.webserverPort + 10}.`); + logInfo("Trying to start audio stream on device: \x1b[35m" + serverConfig.audio.audioDevice); + logInfo(`Using internal audio network port ${serverConfig.webserver.webserverPort + 10}.`); // If an audio device is configured, start the stream if(serverConfig.audio.audioDevice.length > 2) { + let startupSuccess = false; const childProcess = spawn(ffmpegCommand, [ffmpegParams], { shell: true }); childProcess.stdout.on('data', (data) => { @@ -36,6 +37,13 @@ const ffmpegPath = "\"" + ffmpeg.replace(/\\/g, '\\\\') + "\""; childProcess.stderr.on('data', (data) => { logFfmpeg(`stderr: ${data}`); + if(data.includes('I/O error')) { + logError('Audio device \x1b[35m' + serverConfig.audio.audioDevice + '\x1b[0m failed to start. Start server with the command \x1b[33mnode . --ffmpegdebug \x1b[0mfor more info.') + } + if(data.includes('size=') && startupSuccess === false) { + logInfo('Audio stream started up successfully.'); + startupSuccess = true; + } }); childProcess.on('close', (code) => { diff --git a/web/css/buttons.css b/web/css/buttons.css index abbdacc..23a20e3 100644 --- a/web/css/buttons.css +++ b/web/css/buttons.css @@ -143,7 +143,6 @@ input[type="range"]::-moz-range-track { border: 0; } -/* Thumb: webkit */ input[type="range"]::-webkit-slider-thumb { /* removing default appearance */ -webkit-appearance: none; @@ -151,11 +150,14 @@ input[type="range"]::-webkit-slider-thumb { /* creating a custom design */ height: 48px; width: 48px; - background-color: var(--color-4); - border-radius: 10px; - border: 2px solid var(--color-4); + background: url('../images/speaker.svg') center no-repeat, var(--color-5); + background-position: center; + background-size: 20px; + border-radius: 30px; + outline: 4px solid var(--color-5); + outline-offset: -3px; /* slider progress trick */ - box-shadow: -407px 0 0 400px var(--color-4); + box-shadow: -420px 0 0 400px var(--color-4); } /* Thumb: Firefox */ diff --git a/web/css/helpers.css b/web/css/helpers.css index 3b62ea1..caa0ae3 100644 --- a/web/css/helpers.css +++ b/web/css/helpers.css @@ -217,7 +217,7 @@ .text-big { font-size: 40px; display: block; - margin-top: -25px; + margin-top: 0; } .text-big#data-ps { margin: 0; diff --git a/web/favicon2.png b/web/favicon.png similarity index 100% rename from web/favicon2.png rename to web/favicon.png diff --git a/web/index.ejs b/web/index.ejs index 22ab61f..cb2ad13 100644 --- a/web/index.ejs +++ b/web/index.ejs @@ -7,12 +7,12 @@ - + - + @@ -26,22 +26,9 @@ - -

<%= tunerName %> @@ -169,7 +155,7 @@ <% } else { %> - + <% } %> @@ -442,10 +428,10 @@