Clean up AudioPlayer internals, remove the concept of multiple "temporary" streams

This commit is contained in:
Amish Shah
2017-04-12 20:12:51 +01:00
parent d0c2b84659
commit 9eaf1456b2

View File

@@ -36,6 +36,7 @@ class AudioPlayer extends EventEmitter {
*/ */
this.opusEncoder = OpusEncoders.fetch(); this.opusEncoder = OpusEncoders.fetch();
this.streams = new Collection(); this.streams = new Collection();
this.currentStream = {};
this.streamingData = { this.streamingData = {
channels: 2, channels: 2,
count: 0, count: 0,
@@ -47,7 +48,7 @@ class AudioPlayer extends EventEmitter {
} }
get currentTranscoder() { get currentTranscoder() {
return (this.streams.last() || {}).transcoder; return this.currentStream.transcoder;
} }
/** /**
@@ -56,29 +57,19 @@ class AudioPlayer extends EventEmitter {
* @readonly * @readonly
*/ */
get currentDispatcher() { get currentDispatcher() {
return this.streams.size > 0 ? this.streams.last().dispatcher || null : null; return this.currentStream.dispatcher;
} }
destroy() { destroy() {
if (this.opusEncoder) this.opusEncoder.destroy(); if (this.opusEncoder) this.opusEncoder.destroy();
} }
destroyStream(stream) { destroyCurrentStream() {
const data = this.streams.get(stream); const transcoder = this.currentTranscoder;
if (!data) return; const dispatcher = this.currentDispatcher;
const transcoder = data.transcoder;
const dispatcher = data.dispatcher;
if (transcoder) transcoder.kill(); if (transcoder) transcoder.kill();
if (dispatcher) dispatcher.destroy('end'); if (dispatcher) dispatcher.destroy('end');
this.streams.delete(stream); this.currentStream = {};
}
destroyAllStreams(except) {
for (const stream of this.streams.keys()) {
if (except === stream) continue;
if (except === true && this.streams.get(stream) === this.streams.last()) continue;
this.destroyStream(stream);
}
} }
playUnknownStream(stream, { seek = 0, volume = 1, passes = 1 } = {}) { playUnknownStream(stream, { seek = 0, volume = 1, passes = 1 } = {}) {
@@ -89,30 +80,46 @@ class AudioPlayer extends EventEmitter {
media: stream, media: stream,
ffmpegArguments: ffmpegArguments.concat(['-ss', String(seek)]), ffmpegArguments: ffmpegArguments.concat(['-ss', String(seek)]),
}); });
this.streams.set(transcoder.output, { transcoder, input: stream }); this.destroyCurrentStream();
this.currentStream = {
transcoder: transcoder,
output: transcoder.output,
input: stream,
};
transcoder.on('error', e => { transcoder.on('error', e => {
this.destroyStream(stream); this.destroyCurrentStream();
if (this.listenerCount('error') > 0) this.emit('error', e); if (this.listenerCount('error') > 0) this.emit('error', e);
this.emit('warn', `prism transcoder error - ${e}`); this.emit('warn', `prism transcoder error - ${e}`);
}); });
return this.playPCMStream(transcoder.output, options); return this.playPCMStream(transcoder.output, options, true);
} }
playPCMStream(stream, { seek = 0, volume = 1, passes = 1 } = {}) { playPCMStream(stream, { seek = 0, volume = 1, passes = 1 } = {}, fromUnknown = false) {
OpusEncoders.guaranteeOpusEngine(); OpusEncoders.guaranteeOpusEngine();
const options = { seek, volume, passes }; const options = { seek, volume, passes };
this.destroyAllStreams(stream);
const dispatcher = this.createDispatcher(stream, options); const dispatcher = this.createDispatcher(stream, options);
if (!this.streams.has(stream)) this.streams.set(stream, { dispatcher, input: stream }); if (fromUnknown) {
this.streams.get(stream).dispatcher = dispatcher; this.currentStream.dispatcher = dispatcher;
} else {
this.destroyCurrentStream();
this.currentStream = {
dispatcher,
input: stream,
output: stream,
};
}
return dispatcher; return dispatcher;
} }
playOpusStream(stream, { seek = 0, passes = 1 } = {}) { playOpusStream(stream, { seek = 0, passes = 1 } = {}) {
const options = { seek, passes, opus: true }; const options = { seek, passes, opus: true };
this.destroyAllStreams(stream); this.destroyCurrentStream();
const dispatcher = this.createDispatcher(stream, options); const dispatcher = this.createDispatcher(stream, options);
this.streams.set(stream, { dispatcher, input: stream }); this.currentStream = {
dispatcher,
input: stream,
output: stream,
};
return dispatcher; return dispatcher;
} }
@@ -120,15 +127,20 @@ class AudioPlayer extends EventEmitter {
const options = { volume, passes }; const options = { volume, passes };
this.destroyAllStreams(); this.destroyAllStreams();
const dispatcher = this.createDispatcher(broadcast, options); const dispatcher = this.createDispatcher(broadcast, options);
this.streams.set(broadcast, { dispatcher, input: broadcast }); this.currentStream = {
dispatcher,
broadcast,
input: broadcast,
output: broadcast,
};
broadcast.registerDispatcher(dispatcher); broadcast.registerDispatcher(dispatcher);
return dispatcher; return dispatcher;
} }
createDispatcher(stream, options) { createDispatcher(stream, options) {
const dispatcher = new StreamDispatcher(this, stream, options); const dispatcher = new StreamDispatcher(this, stream, options);
dispatcher.on('end', () => this.destroyStream(stream)); dispatcher.on('end', () => this.destroyCurrentStream());
dispatcher.on('error', () => this.destroyStream(stream)); dispatcher.on('error', () => this.destroyCurrentStream());
dispatcher.on('speaking', value => this.voiceConnection.setSpeaking(value)); dispatcher.on('speaking', value => this.voiceConnection.setSpeaking(value));
return dispatcher; return dispatcher;
} }