From e0a8d2350e256bcc3cc15ee5ba2cf1ad8d14c02c Mon Sep 17 00:00:00 2001 From: velvettear Date: Tue, 3 May 2022 14:58:02 +0200 Subject: [PATCH] close/destroy streams when playback finished --- classes/AudioBuffer.js | 39 ++++++++++++++++++++++++++++----------- classes/Player.js | 2 +- libs/util.js | 20 +++++++++++++++++++- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/classes/AudioBuffer.js b/classes/AudioBuffer.js index 6d113eb..3fd5757 100644 --- a/classes/AudioBuffer.js +++ b/classes/AudioBuffer.js @@ -1,6 +1,9 @@ const NodeSpeaker = require('../libs/speaker/index.js'); const EventEmitter = require('events'); -const { Readable } = require('stream'); +const { Readable, Writable } = require('stream'); + +const { restart } = require('../libs/util.js'); +const { Socket } = require('net'); class StreamBuffer extends EventEmitter { @@ -35,7 +38,7 @@ class StreamBuffer extends EventEmitter { } getProgress() { - return this.streams.output?.bytesWritten || 0; + return this.streams?.output?.bytesWritten || 0; } getHiccups() { @@ -81,7 +84,7 @@ class StreamBuffer extends EventEmitter { #createOutputStream() { if (this.streams.output !== undefined) { this.streams.output.destroy(); - } + } this.streams.output = new NodeSpeaker({ channels: this.audiosettings?.channels || 2, bitDepth: this.audiosettings?.bitDepth || 16, @@ -169,6 +172,13 @@ class StreamBuffer extends EventEmitter { this.streams.buffer.on('error', (error) => { logger.error('buffer stream encountered an error: ' + error); }); + this.streams.buffer.on('close', () => { + if (this.streams.buffer.destroyed !== true) { + return this.streams.buffer.destroy(); + } + logger.debug('buffer stream closed'); + this.streams.buffer.removeAllListeners(); + }); } #handleInputStream() { @@ -182,8 +192,12 @@ class StreamBuffer extends EventEmitter { this.#fillBuffer(); }); this.streams.input.on('close', () => { + if (this.streams.input.destroyed !== true) { + return this.streams.input.destroy(); + } this.times.transmitted = Date.now(); logger.debug('input stream closed, transmitting file took ' + (this.times.transmitted - this.times.start) + 'ms'); + this.streams.input.removeAllListeners(); }); } @@ -193,7 +207,7 @@ class StreamBuffer extends EventEmitter { } this.streams.output.on('error', (error) => { logger.error('output stream encountered an error: ' + error); - this.#createOutputStream(); + restart(); }); this.streams.output.on('written', (bytes) => { this.#writeBufferedChunk(bytes); @@ -207,6 +221,13 @@ class StreamBuffer extends EventEmitter { } this.#destroy(); }); + this.streams.output.on('close', () => { + if (this.streams.output.destroyed !== true) { + return this.streams.output.destroy(); + } + logger.debug('output stream closed'); + this.streams.output.removeAllListeners(); + }); this.streams.output.on('hiccup', () => { this.playback.hiccups++; logger.warn('hiccup ' + this.playback.hiccups + ' detected...'); @@ -214,13 +235,9 @@ class StreamBuffer extends EventEmitter { } #destroy() { - for (const key in this.streams) { - const stream = this.streams[key]; - if (stream.destroyed === true) { - continue; - } - stream.destroy(); - } + this.streams.input.destroy(); + this.streams.buffer.destroy(); + this.streams.output.close(); this.times.stop = Date.now(); this.emit('close'); } diff --git a/classes/Player.js b/classes/Player.js index 75eb501..f922685 100644 --- a/classes/Player.js +++ b/classes/Player.js @@ -72,10 +72,10 @@ class Player extends EventEmitter { if (this.events.includes(state)) { return; } + this.events.push(state); logger.debug('emitting state \'' + state + '\' of audio player...'); this.emit(this.state, { data: data }); this.emit(constants.STATECHANGE, { state: this.state, progress: this.getProgress() }); - this.events.push(state); } } diff --git a/libs/util.js b/libs/util.js index 7132429..c59e879 100644 --- a/libs/util.js +++ b/libs/util.js @@ -1,3 +1,5 @@ +const { spawn } = require('child_process'); + function isEnabled(parameter) { return isSet(parameter?.enabled) && parameter.enabled === true; } @@ -23,10 +25,26 @@ async function sleep(ms) { }); } +function restart() { + const args = process.argv; + const cmd = args[0]; + args.shift(); + const newProcess = spawn(cmd, args, { detached: true, stdio: 'ignore' }); + newProcess.unref(); + newProcess.on('error', (error) => { + logger.error('ERROR RESTARTING: '+ error); + }); + newProcess.on('spawn', () => { + logger.warn('PROCESS RESTARTED WITH PID: ' + newProcess.pid); + process.exit(0); + }); +} + module.exports = { isEnabled, isDisabled, isSet, isUnset, - sleep + sleep, + restart } \ No newline at end of file