changed internal buffering of audio files to hopefully prevent memory problems

This commit is contained in:
Daniel Sommer 2022-04-20 17:43:38 +02:00
parent 424f9c4d82
commit c0ffcbebb6
2 changed files with 49 additions and 18 deletions

View file

@ -14,12 +14,14 @@ class AudioServer {
this.listen = config?.server?.listen || '0.0.0.0'; this.listen = config?.server?.listen || '0.0.0.0';
this.port = 0; this.port = 0;
this.buffer = { this.buffer = {
file: file file: file,
stream: fs.createReadStream(file),
limit: (config?.audio.bufferlimit || 256) * 1048576
}; };
this.clients = []; this.clients = [];
this.sockets = []; this.sockets = [];
this.playback = { this.playback = {
position: 0 position: undefined
}; };
this.server = net.createServer(); this.server = net.createServer();
this.#prepare(); this.#prepare();
@ -49,10 +51,9 @@ class AudioServer {
this.buffer.size = stats.size; this.buffer.size = stats.size;
this.buffer.threshold = (this.buffer.size / 100) / (!isNaN(config.audio?.threshold) || 30); this.buffer.threshold = (this.buffer.size / 100) / (!isNaN(config.audio?.threshold) || 30);
this.#announceAudioServer(); this.#announceAudioServer();
this.#bufferFile();
} }
#handleEvents(socket) { #handleEvents() {
eventparser.on('audio:register', (data) => { eventparser.on('audio:register', (data) => {
if (data?.clientId === undefined || data?.socket === undefined) { if (data?.clientId === undefined || data?.socket === undefined) {
return; return;
@ -150,11 +151,32 @@ class AudioServer {
async #sendData(client) { async #sendData(client) {
const timestamp = Date.now(); const timestamp = Date.now();
const buffer = await this.#waitForBuffer(); const buffer = await this.#bufferFile();
return new Promise((resolve, reject) => { return new Promise(async (resolve, reject) => {
client.audiosocket.end(buffer, () => { this.buffer.written = 0;
logger.debug(client.getTag() + ' sent audio file \'' + this.buffer.file + '\' after ' + (Date.now() - timestamp) + 'ms...'); while (true) {
}); if (this.buffer.stream.bytesRead === this.buffer.size && buffer.length === 0) {
client.audiosocket.end(() => {
logger.debug(client.getTag() + ' sent audio file \'' + this.buffer.file + '\' after ' + (Date.now() - timestamp) + 'ms...');
});
break;
}
if (buffer.length === 0) {
this.buffer.stream.resume();
await sleep(1);
continue;
}
if (!this.buffer.stream.isPaused()) {
this.buffer.stream.pause();
}
const tmp = buffer[0];
buffer.shift();
client.audiosocket.write(tmp);
}
// client.audiosocket.end(() => {
// logger.debug(client.getTag() + ' sent audio file \'' + this.buffer.file + '\' after ' + (Date.now() - timestamp) + 'ms...');
// });
client.audiosocket.on('error', (error) => { client.audiosocket.on('error', (error) => {
logger.error(client.getTag() + ' encountered an error: ' + error); logger.error(client.getTag() + ' encountered an error: ' + error);
}); });
@ -182,23 +204,31 @@ class AudioServer {
} }
async #bufferFile() { async #bufferFile() {
return new Promise((resolve, reject) => { // const stream = fs.createReadStream(this.buffer.file);
const buffer = await new Promise((resolve, reject) => {
const timestamp = Date.now(); const timestamp = Date.now();
const buffer = []; const buffer = [];
const stream = fs.createReadStream(this.buffer.file); let resolved = false;
stream.on('data', (data) => { this.buffer.stream.on('data', (data) => {
buffer.push(data); buffer.push(data);
if (resolved !== true && this.buffer.stream.bytesRead >= this.buffer.threshold) {
resolved = true;
logger.debug('buffering threshold of ' + this.buffer.threshold + ' bytes for file \'' + this.buffer.file + '\' took ' + (Date.now() - timestamp) + 'ms');
resolve(buffer);
}
}); });
stream.on('close', () => { this.buffer.stream.on('close', () => {
this.buffer.data = Buffer.concat(buffer); // this.buffer.data = Buffer.concat(buffer);
logger.debug('buffering file \'' + this.buffer.file + '\' took ' + (Date.now() - timestamp) + 'ms (size: ' + this.buffer.data.length + ' bytes)'); logger.debug('buffering file \'' + this.buffer.file + '\' took ' + (Date.now() - timestamp) + 'ms (size: ' + this.buffer.stream.bytesRead + ' bytes)');
resolve(); // resolve();
}); });
stream.on('error', (error) => { this.buffer.stream.on('error', (error) => {
// TODO: handle with try/catch // TODO: handle with try/catch
reject(error); reject(error);
}); });
}); });
return buffer;
} }
#getClientById(clientId) { #getClientById(clientId) {

View file

@ -22,6 +22,7 @@
"password": "kannon" "password": "kannon"
}, },
"audio": { "audio": {
"threshold": 10 "threshold": 10,
"bufferlimit": 128
} }
} }