You've already forked fm-dx-webserver
mirror of
https://github.com/KubaPro010/fm-dx-webserver.git
synced 2026-02-26 22:13:53 +01:00
bugfixes / PCM removal
This commit is contained in:
@@ -200,7 +200,6 @@ const decode_errors = function(string) {
|
||||
};
|
||||
|
||||
const updateInterval = 75;
|
||||
const clientUpdateIntervals = new Map(); // Store update intervals for each client
|
||||
|
||||
// Initialize the data object
|
||||
var dataToSend = {
|
||||
@@ -247,13 +246,13 @@ const filterMappings = {
|
||||
|
||||
|
||||
var legacyRdsPiBuffer = null;
|
||||
var lastUpdateTime = Date.now();
|
||||
const initialData = { ...dataToSend };
|
||||
const resetToDefault = dataToSend => Object.assign(dataToSend, initialData);
|
||||
|
||||
|
||||
function handleData(ws, receivedData) {
|
||||
function handleData(wss, receivedData) {
|
||||
// Retrieve the last update time for this client
|
||||
let lastUpdateTime = clientUpdateIntervals.get(ws) || 0;
|
||||
const currentTime = Date.now();
|
||||
|
||||
let modifiedData, parsedValue;
|
||||
@@ -374,8 +373,10 @@ function handleData(ws, receivedData) {
|
||||
// Send the updated data to the client
|
||||
const dataToSendJSON = JSON.stringify(dataToSend);
|
||||
if (currentTime - lastUpdateTime >= updateInterval) {
|
||||
clientUpdateIntervals.set(ws, currentTime); // Update the last update time for this client
|
||||
ws.send(dataToSendJSON);
|
||||
wss.clients.forEach((client) => {
|
||||
client.send(dataToSendJSON);
|
||||
});
|
||||
lastUpdateTime = Date.now();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ var pjson = require('../package.json');
|
||||
let timeoutID = null;
|
||||
|
||||
function send(request) {
|
||||
const url = "https://list.fmdx.pl/api/";
|
||||
const url = "https://servers.fmdx.org/api/";
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
@@ -53,7 +53,7 @@ function sendKeepalive() {
|
||||
|
||||
const request = {
|
||||
token: serverConfig.identification.token,
|
||||
status: (serverConfig.lockToAdmin ? 2 : 1)
|
||||
status: ((serverConfig.lockToAdmin || !serverConfig.publicTuner) ? 2 : 1)
|
||||
};
|
||||
|
||||
send(request);
|
||||
|
||||
@@ -73,12 +73,8 @@ function resolveDataBuffer(data, wss) {
|
||||
}
|
||||
|
||||
if (receivedData.length) {
|
||||
wss.clients.forEach((client) => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
dataHandler.handleData(client, receivedData);
|
||||
}
|
||||
});
|
||||
}
|
||||
dataHandler.handleData(wss, receivedData);
|
||||
};
|
||||
}
|
||||
|
||||
function kickClient(ipAddress) {
|
||||
|
||||
@@ -64,6 +64,7 @@ connectToSerial();
|
||||
|
||||
// Serial Connection
|
||||
function connectToSerial() {
|
||||
let okReceived = false;
|
||||
if (serverConfig.xdrd.wirelessConnection === false) {
|
||||
|
||||
serialport = new SerialPort({path: serverConfig.xdrd.comPort, baudRate: 115200 });
|
||||
@@ -71,27 +72,34 @@ function connectToSerial() {
|
||||
serialport.on('open', () => {
|
||||
logInfo('Using COM device: ' + serverConfig.xdrd.comPort);
|
||||
serialport.write('x\n');
|
||||
serialport.write('Q0\n');
|
||||
serialport.write('M0\n');
|
||||
serialport.write('Z0\n');
|
||||
|
||||
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);
|
||||
} else {
|
||||
serialport.write('T87500\n');
|
||||
}
|
||||
|
||||
serialport.write('A0\n');
|
||||
serialport.write('F-1\n');
|
||||
serialport.write('W0\n');
|
||||
serialport.write('D0\n');
|
||||
serialport.write('G00\n');
|
||||
serverConfig.audio.startupVolume ? serialport.write('Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n') : serialport.write('Y100\n');
|
||||
|
||||
serialport.on('data', (data) => {
|
||||
helpers.resolveDataBuffer(data, wss);
|
||||
if (receivedData.startsWith('OK')) {
|
||||
okReceived = true;
|
||||
|
||||
// Send the remaining commands
|
||||
serialport.write('Q0\n');
|
||||
serialport.write('M0\n');
|
||||
serialport.write('Z0\n');
|
||||
|
||||
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);
|
||||
} else {
|
||||
serialport.write('T87500\n');
|
||||
}
|
||||
|
||||
serialport.write('A0\n');
|
||||
serialport.write('F-1\n');
|
||||
serialport.write('W0\n');
|
||||
serialport.write('D0\n');
|
||||
serialport.write('G00\n');
|
||||
serverConfig.audio.startupVolume ? serialport.write('Y' + (serverConfig.audio.startupVolume * 100).toFixed(0) + '\n') : serialport.write('Y100\n');
|
||||
} else {
|
||||
// Continue handling data normally if it's not the "OK" message
|
||||
helpers.resolveDataBuffer(data, wss);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -273,8 +281,8 @@ wss.on('connection', (ws, request) => {
|
||||
const command = message.toString();
|
||||
logDebug(`Command received from \x1b[90m${clientIp}\x1b[0m: ${command}`);
|
||||
|
||||
if (command.startsWith('X')) {
|
||||
logWarn(`Remote tuner shutdown attempted by \x1b[90m${clientIp}\x1b[0m. You may consider blocking this user.`);
|
||||
if ((command.startsWith('X') || command.startsWith('Y')) && !request.session.isAdminAuthenticated) {
|
||||
logWarn(`User \x1b[90m${clientIp}\x1b[0m attempted to send a potentially dangerous command. You may consider blocking this user.`);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const consoleCmd = require('./console');
|
||||
const { serverConfig } = require('./server_config');
|
||||
|
||||
// Function to read all .js files in a directory
|
||||
@@ -31,7 +32,9 @@ function parsePluginConfig(filePath) {
|
||||
// Copy the file to the destination directory
|
||||
const destinationFile = path.join(destinationDir, path.basename(sourcePath));
|
||||
fs.copyFileSync(sourcePath, destinationFile);
|
||||
console.log(`File copied from ${sourcePath} to ${destinationFile}`);
|
||||
setTimeout(function() {
|
||||
consoleCmd.logInfo(`Plugin ${pluginConfig.name} ${pluginConfig.version} initialized successfully.`);
|
||||
}, 500)
|
||||
} else {
|
||||
console.error(`Error: frontEndPath is not defined in ${filePath}`);
|
||||
}
|
||||
|
||||
@@ -1,46 +1,11 @@
|
||||
"use strict";
|
||||
var fs = require('fs');
|
||||
const ffmpegStaticPath = require('ffmpeg-static');
|
||||
const {serverConfig} = require('../server_config')
|
||||
const fs = require('fs');
|
||||
const ws = require('ws');
|
||||
const { serverConfig } = require('../server_config');
|
||||
|
||||
// Load settings from config
|
||||
const Settings = JSON.parse(fs.readFileSync('server/stream/settings.json', 'utf-8'));
|
||||
|
||||
/*
|
||||
Stdin streamer is part of 3LAS (Low Latency Live Audio Streaming)
|
||||
https://github.com/JoJoBond/3LAS
|
||||
*/
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = require("fs");
|
||||
const child_process_1 = require("child_process");
|
||||
const ws = __importStar(require("ws"));
|
||||
const Settings = JSON.parse((0, fs_1.readFileSync)('server/stream/settings.json', 'utf-8'));
|
||||
const FFmpeg_command = ffmpegStaticPath;
|
||||
class StreamClient {
|
||||
constructor(server, socket) {
|
||||
this.Server = server;
|
||||
@@ -51,155 +16,127 @@ class StreamClient {
|
||||
};
|
||||
this.Socket.on('error', this.OnError.bind(this));
|
||||
this.Socket.on('message', this.OnMessage.bind(this));
|
||||
this.Socket.on('close', this.OnClose.bind(this));
|
||||
}
|
||||
OnMessage(message, isBinary) {
|
||||
|
||||
OnMessage(message) {
|
||||
try {
|
||||
let request = JSON.parse(message.toString());
|
||||
if (request.type == "answer") {
|
||||
|
||||
}
|
||||
else if (request.type == "fallback") {
|
||||
this.Server.SetFallback(this, request.data);
|
||||
}
|
||||
else if (request.type == "stats") {
|
||||
if (Settings.AdminKey && request.data == Settings.AdminKey) {
|
||||
if (request.type === "answer") {
|
||||
// Handle answer type messages if needed
|
||||
} else if (request.type === "fallback") {
|
||||
// Assuming SetFallback is not needed or replace with the correct method
|
||||
console.warn('SetFallback method not defined. Fallback request ignored.');
|
||||
} else if (request.type === "stats") {
|
||||
if (Settings.AdminKey && request.data === Settings.AdminKey) {
|
||||
this.SendText(JSON.stringify({
|
||||
"type": "stats",
|
||||
"data": this.Server.GetStats(),
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
this.OnError(new Error("Invalid message type"));
|
||||
}
|
||||
else {
|
||||
this.OnError(null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (_a) {
|
||||
this.OnError(null);
|
||||
return;
|
||||
} catch (error) {
|
||||
this.OnError(error);
|
||||
}
|
||||
}
|
||||
OnError(_err) {
|
||||
|
||||
OnError(error) {
|
||||
console.error('WebSocket error:', error);
|
||||
this.Server.DestroyClient(this);
|
||||
}
|
||||
|
||||
OnClose() {
|
||||
console.log('WebSocket connection closed');
|
||||
this.Server.DestroyClient(this);
|
||||
}
|
||||
|
||||
Destroy() {
|
||||
try {
|
||||
this.Socket.close();
|
||||
}
|
||||
catch (ex) {
|
||||
if (this.Socket.readyState === ws.OPEN) {
|
||||
try {
|
||||
this.Socket.close();
|
||||
} catch (ex) {
|
||||
console.error('Error while closing socket:', ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SendBinary(buffer) {
|
||||
if (this.Socket.readyState != ws.OPEN) {
|
||||
this.OnError(null);
|
||||
if (this.Socket.readyState !== ws.OPEN) {
|
||||
this.OnError(new Error('Socket is not open'));
|
||||
return;
|
||||
}
|
||||
this.Socket.send(buffer, this.BinaryOptions);
|
||||
}
|
||||
|
||||
SendText(text) {
|
||||
if (this.Socket.readyState != ws.OPEN) {
|
||||
this.OnError(null);
|
||||
if (this.Socket.readyState !== ws.OPEN) {
|
||||
this.OnError(new Error('Socket is not open'));
|
||||
return;
|
||||
}
|
||||
this.Socket.send(text);
|
||||
}
|
||||
OnIceCandidate(e) {
|
||||
if (e.candidate) {
|
||||
this.SendText(JSON.stringify({
|
||||
"type": "candidate",
|
||||
"data": e.candidate
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class StreamServer {
|
||||
constructor(port, channels, sampleRate) {
|
||||
this.Port = port;
|
||||
this.Channels = channels;
|
||||
this.SampleRate = sampleRate;
|
||||
this.Clients = new Set();
|
||||
this.FallbackClients = {
|
||||
"wav": new Set(),
|
||||
"mp3": new Set()
|
||||
};
|
||||
this.FallbackProvider = {};
|
||||
if (Settings.FallbackUseMp3) {
|
||||
this.FallbackProvider["mp3"] = AFallbackProvider.Create(this, "mp3");
|
||||
}
|
||||
if (Settings.FallbackUseWav) {
|
||||
this.FallbackProvider["wav"] = AFallbackProvider.Create(this, "wav");
|
||||
}
|
||||
this.StdIn = process.stdin;
|
||||
this.SamplesCount = this.SampleRate / 100;
|
||||
this.Samples = new Int16Array(this.Channels * this.SamplesCount);
|
||||
this.SamplesPosition = 0;
|
||||
this.Buffer = Buffer.alloc(0);
|
||||
}
|
||||
|
||||
Run() {
|
||||
this.Server = new ws.Server({
|
||||
"host": ["127.0.0.1", "::1"],
|
||||
"port": this.Port,
|
||||
"clientTracking": true,
|
||||
"perMessageDeflate": false
|
||||
host: ["127.0.0.1", "::1"],
|
||||
port: this.Port,
|
||||
clientTracking: true,
|
||||
perMessageDeflate: false
|
||||
});
|
||||
this.Server.on('connection', this.OnServerConnection.bind(this));
|
||||
this.StdIn.on('data', this.OnStdInData.bind(this));
|
||||
this.StdIn.resume();
|
||||
}
|
||||
BroadcastBinary(format, buffer) {
|
||||
this.FallbackClients[format].forEach((function each(client) {
|
||||
client.SendBinary(buffer);
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
OnStdInData(buffer) {
|
||||
for (let i = 0; i < buffer.length; i += 2) {
|
||||
this.Samples[this.SamplesPosition] = buffer.readInt16LE(i);
|
||||
this.SamplesPosition++;
|
||||
if (this.SamplesPosition >= this.Samples.length) {
|
||||
let data = {
|
||||
"samples": this.Samples,
|
||||
"sampleRate": this.SampleRate,
|
||||
"bitsPerSample": 16,
|
||||
"channelCount": this.Channels,
|
||||
"numberOfFrames": this.SamplesCount,
|
||||
};
|
||||
this.Samples = new Int16Array(this.Channels * this.SamplesCount);
|
||||
this.SamplesPosition = 0;
|
||||
this.Buffer = Buffer.concat([this.Buffer, buffer]);
|
||||
if (this.Buffer.length >= 8192) { // Adjust the buffer size as needed
|
||||
this.SendAudioData(this.Buffer);
|
||||
this.Buffer = Buffer.alloc(0);
|
||||
}
|
||||
}
|
||||
|
||||
SendAudioData(buffer) {
|
||||
this.Clients.forEach(client => {
|
||||
try {
|
||||
client.SendBinary(buffer);
|
||||
} catch (error) {
|
||||
console.error('Error sending data to client:', error);
|
||||
}
|
||||
}
|
||||
for (let format in this.FallbackProvider) {
|
||||
this.FallbackProvider[format].InsertData(buffer);
|
||||
}
|
||||
});
|
||||
}
|
||||
OnServerConnection(socket, _request) {
|
||||
this.Clients.add(new StreamClient(this, socket));
|
||||
}
|
||||
SetFallback(client, format) {
|
||||
if (format != "mp3" && format != "wav") {
|
||||
this.DestroyClient(client);
|
||||
return;
|
||||
}
|
||||
this.FallbackClients[format].add(client);
|
||||
this.FallbackProvider[format].PrimeClient(client);
|
||||
|
||||
OnServerConnection(socket) {
|
||||
const client = new StreamClient(this, socket);
|
||||
this.Clients.add(client);
|
||||
console.log('New client connected');
|
||||
}
|
||||
|
||||
DestroyClient(client) {
|
||||
this.FallbackClients["mp3"].delete(client);
|
||||
this.FallbackClients["wav"].delete(client);
|
||||
this.Clients.delete(client);
|
||||
client.Destroy();
|
||||
console.log('Client connection destroyed');
|
||||
}
|
||||
|
||||
GetStats() {
|
||||
let fallback = {
|
||||
"wav": (this.FallbackClients["wav"] ? this.FallbackClients["wav"].size : 0),
|
||||
"mp3": (this.FallbackClients["mp3"] ? this.FallbackClients["mp3"].size : 0),
|
||||
};
|
||||
for (let format in fallback) {
|
||||
total += fallback[format];
|
||||
}
|
||||
return {
|
||||
"Total": total,
|
||||
"Fallback": fallback,
|
||||
"Total": this.Clients.size,
|
||||
};
|
||||
}
|
||||
|
||||
static Create(options) {
|
||||
if (!options["-port"])
|
||||
throw new Error("Port undefined. Please use -port to define the port.");
|
||||
@@ -208,7 +145,7 @@ class StreamServer {
|
||||
if (!options["-channels"])
|
||||
throw new Error("Channels undefined. Please use -channels to define the number of channels.");
|
||||
if (typeof options["-channels"] !== "number" || options["-channels"] !== Math.floor(options["-channels"]) ||
|
||||
!(options["-channels"] == 1 || options["-channels"] == 2))
|
||||
!(options["-channels"] === 1 || options["-channels"] === 2))
|
||||
throw new Error("Invalid channels. Must be either 1 or 2.");
|
||||
if (!options["-samplerate"])
|
||||
throw new Error("Sample rate undefined. Please use -samplerate to define the sample rate.");
|
||||
@@ -217,114 +154,21 @@ class StreamServer {
|
||||
return new StreamServer(options["-port"], options["-channels"], options["-samplerate"]);
|
||||
}
|
||||
}
|
||||
class AFallbackProvider {
|
||||
constructor(server) {
|
||||
this.Server = server;
|
||||
this.Process = (0, child_process_1.spawn)(FFmpeg_command, this.GetFFmpegArguments(), { shell: false, detached: false, stdio: ['pipe', 'pipe', 'ignore'] });
|
||||
this.Process.stdout.addListener('data', this.OnData.bind(this));
|
||||
}
|
||||
InsertData(buffer) {
|
||||
this.Process.stdin.write(buffer);
|
||||
}
|
||||
static Create(server, format) {
|
||||
if (format == "mp3") {
|
||||
return new FallbackProviderMp3(server);
|
||||
}
|
||||
else if (format == "wav") {
|
||||
return new FallbackProviderWav(server, 384);
|
||||
}
|
||||
}
|
||||
}
|
||||
class FallbackProviderMp3 extends AFallbackProvider {
|
||||
constructor(server) {
|
||||
super(server);
|
||||
}
|
||||
GetFFmpegArguments() {
|
||||
return [
|
||||
"-fflags", "+nobuffer+flush_packets", "-flags", "low_delay", "-rtbufsize", "32", "-probesize", "32",
|
||||
"-f", "s16le",
|
||||
"-ar", this.Server.SampleRate.toString(),
|
||||
"-ac", this.Server.Channels.toString(),
|
||||
"-i", "pipe:0",
|
||||
"-c:a", "libmp3lame",
|
||||
"-b:a", serverConfig.audio.audioBitrate,
|
||||
"-ac", this.Server.Channels.toString(),
|
||||
"-reservoir", "0",
|
||||
"-f", "mp3", "-write_xing", "0", "-id3v2_version", "0",
|
||||
"-fflags", "+nobuffer", "-flush_packets", "1",
|
||||
"pipe:1"
|
||||
];
|
||||
}
|
||||
OnData(chunk) {
|
||||
this.Server.BroadcastBinary("mp3", chunk);
|
||||
}
|
||||
PrimeClient(_) {
|
||||
}
|
||||
}
|
||||
class FallbackProviderWav extends AFallbackProvider {
|
||||
constructor(server, chunkSize) {
|
||||
super(server);
|
||||
if (typeof chunkSize !== "number" || chunkSize !== Math.floor(chunkSize) || chunkSize < 1)
|
||||
throw new Error("Invalid ChunkSize. Must be natural number greater than or equal to 1.");
|
||||
this.ChunkSize = chunkSize;
|
||||
this.ChunkBuffer = Buffer.alloc(0);
|
||||
this.HeaderBuffer = new Array();
|
||||
}
|
||||
GetFFmpegArguments() {
|
||||
return [
|
||||
"-fflags", "+nobuffer+flush_packets", "-flags", "low_delay", "-rtbufsize", "32", "-probesize", "32",
|
||||
"-f", "s16le",
|
||||
"-ar", this.Server.SampleRate.toString(),
|
||||
"-ac", this.Server.Channels.toString(),
|
||||
"-i", "pipe:0",
|
||||
"-c:a", "pcm_s16le",
|
||||
"-ar", Settings.FallbackWavSampleRate.toString(),
|
||||
"-ac", "1",
|
||||
"-f", "wav",
|
||||
"-flush_packets", "1", "-fflags", "+nobuffer", "-chunk_size", "384", "-packetsize", "384",
|
||||
"pipe:1"
|
||||
];
|
||||
}
|
||||
OnData(chunk) {
|
||||
// Check if riff for wav
|
||||
if (this.HeaderBuffer.length == 0) {
|
||||
// Check if chunk is a header page
|
||||
let isHeader = (chunk[0] == 0x52 && chunk[1] == 0x49 && chunk[2] == 0x46 && chunk[3] == 0x46);
|
||||
if (isHeader) {
|
||||
this.HeaderBuffer.push(chunk);
|
||||
this.Server.BroadcastBinary("wav", chunk);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.ChunkBuffer = Buffer.concat(new Array(this.ChunkBuffer, chunk), this.ChunkBuffer.length + chunk.length);
|
||||
if (this.ChunkBuffer.length >= this.ChunkSize) {
|
||||
let chunkBuffer = this.ChunkBuffer;
|
||||
this.ChunkBuffer = Buffer.alloc(0);
|
||||
this.Server.BroadcastBinary("wav", chunkBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
PrimeClient(client) {
|
||||
let headerBuffer = this.HeaderBuffer;
|
||||
for (let i = 0; i < headerBuffer.length; i++) {
|
||||
client.SendBinary(headerBuffer[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const OptionParser = {
|
||||
"-port": function (txt) { return parseInt(txt, 10); },
|
||||
"-channels": function (txt) { return parseInt(txt, 10); },
|
||||
"-samplerate": function (txt) { return parseInt(txt, 10); }
|
||||
"-port": txt => parseInt(txt, 10),
|
||||
"-channels": txt => parseInt(txt, 10),
|
||||
"-samplerate": txt => parseInt(txt, 10)
|
||||
};
|
||||
|
||||
const Options = {};
|
||||
// Parse parameters
|
||||
for (let i = 2; i < (process.argv.length - 1); i += 2) {
|
||||
for (let i = 2; i < process.argv.length; i += 2) {
|
||||
if (!OptionParser[process.argv[i]])
|
||||
throw new Error("Invalid argument: '" + process.argv[i] + "'.");
|
||||
if (Options[process.argv[i]])
|
||||
throw new Error("Redefined argument: '" + process.argv[i] + "'. Please use '" + process.argv[i] + "' only ONCE");
|
||||
Options[process.argv[i]] = OptionParser[process.argv[i]](process.argv[i + 1]);
|
||||
}
|
||||
|
||||
const Server = StreamServer.Create(Options);
|
||||
Server.Run();
|
||||
//# sourceMappingURL=3las.server.js.map
|
||||
@@ -8,17 +8,17 @@ function enableAudioStream() {
|
||||
serverConfig.webserver.webserverPort = Number(serverConfig.webserver.webserverPort);
|
||||
|
||||
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`;
|
||||
const codec = `-acodec libmp3lame -ar 48000 -ac ${serverConfig.audio.audioChannels} -b:a ${serverConfig.audio.audioBitrate}`;
|
||||
const output = `-f mp3 -fflags +nobuffer+flush_packets -flush_packets 1 -bufsize 960`;
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
// Windows
|
||||
ffmpegCommand = "\"" + ffmpeg.replace(/\\/g, '\\\\') + "\"";
|
||||
ffmpegParams = `${flags} -f dshow -audio_buffer_size 200 -i audio="${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node server/stream/3las.server.js -port ${serverConfig.webserver.webserverPort + 10} -samplerate 48000 -channels ${serverConfig.audio.audioChannels}`;
|
||||
} else {
|
||||
ffmpegParams = `${flags} -f dshow -audio_buffer_size 200 -i audio="${serverConfig.audio.audioDevice}" ${codec} ${output} pipe:1 | node server/stream/3las.server.js -port ${serverConfig.webserver.webserverPort + 10} -samplerate 44100 -channels ${serverConfig.audio.audioChannels}`;
|
||||
} else {
|
||||
// Linux
|
||||
ffmpegCommand = 'ffmpeg';
|
||||
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}`;
|
||||
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 44100 -channels ${serverConfig.audio.audioChannels}`;
|
||||
}
|
||||
|
||||
logInfo("Trying to start audio stream on device: \x1b[35m" + serverConfig.audio.audioDevice);
|
||||
|
||||
Reference in New Issue
Block a user