Please describe the problem you are having in as much detail as possible:
When ending a dispatcher and immediately attempting to start another one, the first dispatcher ends properly, but the new dispatcher ends immediately with no reason (ie. the reason is undefined). This behaviour may be the result of my code, but regardless the dispatcher should not end with an undefined reason.
Include a reproducible code sample here, if possible:
function endListener(reason) {
dispatcher = null;
}
// for sake of brevity, dispatcher is currently playing at this point
dispatcher.end('temp');
dispatcher = voiceConnection.playStream(stream, { volume: 0.2 });
dispatcher.once('end', endListener);
Further details:
Probably my crappy code, I made a quick commit a few days ago to clean up internal dispatchers and streams, will take a look later today!
I'm closing this issue because it only occurs when streaming audio from ytdl-core and therefore is likely not an issue with this library.
This problem is apparently related to the stream that is being terminated: it only appears when the dispatcher that is being terminated is streaming through ytdl. I'm unsure how the previous stream could cause the new stream to immediately terminate without a reason, but that appears to be the case.
As a side note, I have seen others with this problem as well: my initial assumption that it was related to a local issue seems to be incorrect.
@appellation This happens even when using youtube-dl lib.
I did some testing and found that the AudioPlayer emits two error events after terminating the dispatcher, both of which are ECONNRESET errors.
Did you find out what could be causing the other side to abruptly close its end of the connection?
And does this commit d85695ee980e2d552d76d019f1cbde0492c31827 fix that?
No I haven't made any progress on this issue.
However, I am hearing from several people that this issue is appearing with other stream types and I can confirm that that is the case. As such, this appears to be a D.js issue.
From what I can tell, this appears to be a race condition as the issue does not appear on slower systems.
Can confirm. Discord.js is raceconditing. When I create a new stream instantly after closing one with Dispatcher#end, it ends the new one, causing a 'double skip'. Doesn't happen when the next stream starts a bit later (timeout of ~100ms).
Alright, time for a bit more investigation into this issue. First of all, here's a more detailed reproducible code sample.
const conn = message.guild.voiceConnection || await message.member.voiceChannel.join();
if (conn.dispatcher) conn.dispatcher.end();
const dispatcher = conn.playStream(ytdl('some yt link', { filter: 'audioonly', quality: 'lowest' }));
dispatcher.once('end', console.trace);
dispatcher.player.once('error', console.trace);
When running this code the second time, the following is output:

I can say that this is not the result of a ytdl error, as the exact same output is produced when replacing line 3 of the above code with the following: const dispatcher = conn.playStream(request('some audio stream'));
Note: does not appear to happen with playFile.
This, as of 4292134647608206e2b3b379485a5494854c648e running in a Ubuntu 16.04 Docker container.
I thought I was going crazy until I saw this thread. This happens to me every other 'skip', aka, when I call the dispatcher end method, the end event fires twice - two completely different events. E.g.
been fired: user skipped
been fired: undefined <-- skipped
been fired: user skipped <--fine here
been fired: user skipped
been fired: undefined <--another skip, etc
been fired: user skipped
been fired: user skipped
been fired: undefined
Can provide a condensed snippet of code upon request, but enough has been previously given already. Not sure if it is race conditioning, since it occurs every other skip (edit: I'd like to add that this has consistently occurred for more than 100 attempts - yes, I should've given up sooner). Could it be some missed case during error handling/not clearing properly?
Not sure how relevant it is, but when I force skip, the next song that plays seems to take far longer than usual, I'm afraid I don't know D.js well enough to speculate on that.
Further details:
-discord.js version: master
-node.js version: 7.7.4
-Operating system: Ubuntu 16.10, 17.04; OSx Sierra
-Using it with ytdl (I'm 99% sure this is not the issue)
The issue is with destroy function in src/client/voice/dispatcher/StreamDispatcher. The structure of AudioPlayer.js is passing itself with the same properties. Here is the line const dispatcher = new StreamDispatcher(this, stream, options);. When a new dispatcher was immediately added after the previous dispatcher, the emitter in the destroy function hasn't completed. Once the emitter finished emitting, it caused the re-initialized dispatcher to end instead. Hence, a race condition occurred.
Stream Dispatcher
destroy(type, reason) {
if (this.destroyed) return;
this.destroyed = true;
this.setSpeaking(false);
this.emit(type, reason);
/**
* Emitted once the dispatcher ends.
* @param {string} [reason] the reason the dispatcher ended
* @event StreamDispatcher#end
*/
if (type !== 'end') this.emit('end', `destroyed due to ${type} - ${reason}`);
}
Why when adding a delay to play another stream it doesn't work :
Skip:
function playerSkip(message: Message) {
const dontPlayMusic = ":x: **Le bot ne joue actuellement pas de musique.**";
const player = Player.getInstance();
if (!player.isConnected)
message.channel.send(dontPlayMusic);
else {
player.dispatcher.end("skip")
}
}
PlayCore:
async function playCore(message: Message, playlist: Playlist) {
const musicPlaying = (m) => ":musical_note: Now playing : `" + m.name + " - [" + m.length + "s]` :musical_note:";
const player: Player = Player.getInstance();
player.playlist = playlist;
player.voiceChan = message.member.voiceChannel;
player.connection = message.guild.voiceConnection || await message.member.voiceChannel.join();
const music: Music = player.nextMusic();
message.channel.sendMessage(musicPlaying(music));
player.dispatcher = player.connection.playStream(YTDL("http://www.youtube.com/v/" + music.id, {filter: "audioonly"}));
player.dispatcher.once("end", reason => {
console.log("end ?? " + music.name + " reason " + reason);
if (player.isConnected)
setTimeout(() => playCore(message, player.playlist), 500);
else
player.disconnect();
});
player.dispatcher.on('error', e => {
console.log(e)
});
player.dispatcher.player.on('warn', console.warn);
player.dispatcher.on('warn', console.warn)
}
Once I could skip and hear each time the music came in. But now it does not work, the music does not play and there is always this error: prism transcoder error - Error: read ECONNRESET
After some moment, the dispatcher end with this reason : reason Stream is not generating quickly enough.
Anyone has a solution ?
The core of this issue is over 2 months old and seems to have vanished.
This issue have not vanished,
The bug is currently upstream in https://github.com/hydrabolt/prism-media, because after kill it send error for stdin read fail and this cause the dispatcher's end https://github.com/hydrabolt/discord.js/blob/master/src/client/voice/player/AudioPlayer.js#L110
I am also still having this issue at 11.2.1 via npm
Running dispatcher.end() will end the current dispatcher and then the next one created after that.
@MarleyPlant prism-media has not been yet upgraded on npm, can you try to use the version on github ?
npm install --save hydrabolt/prism-media
I'm using discord.js and yt-dl.
is prism-media a requirement for discord.js or am I missing something?
yes, prism-media is a dependency of discord.js
Might be a bit late, but trying the upgraded version of prism-media fixed the issue for me.
As of this date the bug is still happening. This is indeed a race condition, and can be circumvented by using a delay before your next call.
dispatcher.on('end', () => {
setTimeout(() => yourcode, 200)
})
@vmarchesin can you try to do a npm update on your project and check if the bug is still happening ?
It's been months and I don't see this bug being fixed. I'm still getting this issue.
There's a brand new voice rewrite, if you want to test it out early you can test the voice-rewrite branch
I have not encountered this bug since like June. Please ensure that you've updated to the latest release of Discord.js. Also, as hydra mentioned, voice is getting rewritten for v12.
I tried with the latest version of all dependencies, and I still get the issue. I'm running off an AWS EC2 machine, which is quite fast, so the race condition is likely to appear. As I said adding a delay solves the issue. For now it's easier to have this workaround than to wait for a fix. I did not try the voice-rewrite branch but since everything is working for me now I won't use it until the next stable release.
Adding a delay is just a workaround, not a fix.
And voice-rewrite branch fixes the issue. Thanks hydrabolt. But since I can't use that on production, will have to wait until v12 is released.
I also noticed that this bug happened to me when I restart the bot without it fully go offline. Even with this delay walkaround. Maybe that will help someone.
voice-rewrite has landed on master for those looking for a fix
This is actually removed behaviour in master now, if no error event is emitted you can assume the stream has ended gracefully.
Most helpful comment
voice-rewrite has landed on master for those looking for a fix