discordjs / voice

Implementation of the Discord Voice API for discord.js and other JS/TS libraries
Apache License 2.0
327 stars 110 forks source link

Adapter destroying voiceConnection when client reconnects #153

Closed MatteZ02 closed 3 years ago

MatteZ02 commented 3 years ago

Please describe the problem you are having in as much detail as possible: VoiceConnection changes state to destroyed from ready in the middle of playback. Sometimes this occurs after 10 minutes of listening, Sometimes after hours. Yet to find a proper way of reproducing this issue. image

Include a reproducible code sample here, if possible:

    public async join(
        channel: Discord.VoiceChannel | Discord.StageChannel
    ): Promise<VoiceConnection | null> {
        try {
            this.voiceChannel = channel;
            const connection: VoiceConnection =
                getVoiceConnection(this.guild.id) ??
                joinVoiceChannel({
                    channelId: channel.id,
                    guildId: this.guild.id,
                    //@ts-ignore
                    adapterCreator: createDiscordJSAdapter(channel),
                    debug: this.client.config.debug.voiceConnection
                });
            this.connection = connection;
            this.connection
                .once("error", err => {
                    this.connection = null;
                    this.emit("error", err);
                })
                .on("stateChange", async (oldState, newState) => 
                    console.log(`oldStatus: ${oldState.status}, newStatus: ${newState.status}`)
                )
                .on("debug", console.log);
            return (
                (await entersState(connection, VoiceConnectionStatus.Ready, 15e3).catch(e => {
                    console.error(e);
                    if (connection.state.status !== "destroyed") connection.destroy();
                    if (this.exists) this._timeout();
                })) || null
            );
        } catch (error) {
            this.client.player.delete(channel.guild?.id as string);
            console.log("failed to obtain a voiceConnection");
            console.error(error);
            this.textChannel?.send(this.client.messages.error + error.toString());
            return null;
        }
    }

Further details:

Relevant client options:

SpaceEEC commented 3 years ago

Can you try getting a stacktrace in the statusUpdate event? Something like new Error().stack should do the trick.

MatteZ02 commented 3 years ago

Will do. Might take up to a few days for me to catch the error again.

MatteZ02 commented 3 years ago

image Alright got the stack trace after 2 hours of continuous listening (on the same connection)

amishshah commented 3 years ago

Can you share your Player.js file?

MatteZ02 commented 3 years ago

the uncompiled ts file of the player is 930 lines. I can send the entire thing if needed but is there any part you'd like to see in particular?

MatteZ02 commented 3 years ago

image Alright got the stack trace after 2 hours of continuous listening (on the same connection)

Unfortunately i didn't take a proper look at the chain of errors that occurred around this stack.

Anyhow i just ran into a different one. Seems like the ws shard closed which resulted in the voiceConnection being destroyed by the adapter. image

Don't mind the different line numbers. This is a wip bot and the code is continuously changing (which at times makes debugging a mess)

MatteZ02 commented 3 years ago

after 5 hours of debugging last night i got the error again. This time with debugging enabled for my djs client. image so what happened was that the ws reconnected which caused the adapter to destroy the voiceConnection.

MatteZ02 commented 3 years ago

Alright i got it. So the reason the voiceConnection is destroyed is due to the adapter function cleanupGuilds which will delete the existing voiceConnections. Just by commenting out adapters.get(guildID)?.destroy(); the problem went away.

amishshah commented 3 years ago

This is odd, the intended behaviour of the adapter provided by discord.js is to only destroy once the main WebSocket shard has disconnected and will not attempt to reconnect.

I will take a look at fixing this adapter.