Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't play audio because of WS_NOT_OPEN #5443

Closed
knt2nd opened this issue Mar 28, 2021 · 1 comment · Fixed by #5402
Closed

Can't play audio because of WS_NOT_OPEN #5443

knt2nd opened this issue Mar 28, 2021 · 1 comment · Fixed by #5402

Comments

@knt2nd
Copy link

knt2nd commented Mar 28, 2021

Please describe the problem you are having in as much detail as possible:

Can't play audio when a bot stays in a voice channel for a long time, days or weeks, and the error can't be handled without the debug event. Here is the error log.

Error [WS_NOT_OPEN]: Websocket not open to send ...
at /home/kanata/projects/knt2-dbot/node_modules/discord.js/src/client/voice/networking/VoiceWebSocket.js:93:68
at new Promise (<anonymous>)
at VoiceWebSocket.send (/home/kanata/projects/knt2-dbot/node_modules/discord.js/src/client/voice/networking/VoiceWebSocket.js:92:12)
at VoiceWebSocket.sendPacket (/home/kanata/projects/knt2-dbot/node_modules/discord.js/src/client/voice/networking/VoiceWebSocket.js:112:17)
at VoiceConnection.setSpeaking (/home/kanata/projects/knt2-dbot/node_modules/discord.js/src/client/voice/VoiceConnection.js:153:8)
at StreamDispatcher._setSpeaking (/home/kanata/projects/knt2-dbot/node_modules/discord.js/src/client/voice/dispatcher/StreamDispatcher.js:303:35)
at StreamDispatcher._sendPacket (/home/kanata/projects/knt2-dbot/node_modules/discord.js/src/client/voice/dispatcher/StreamDispatcher.js:290:10)
at StreamDispatcher._playChunk (/home/kanata/projects/knt2-dbot/node_modules/discord.js/src/client/voice/dispatcher/StreamDispatcher.js:253:10)
at StreamDispatcher._write (/home/kanata/projects/knt2-dbot/node_modules/discord.js/src/client/voice/dispatcher/StreamDispatcher.js:107:10)
at writeOrBuffer (internal/streams/writable.js:358:12) {
[Symbol(code)]: 'WS_NOT_OPEN'
}

Once the error happens, it always happens when a bot plays audio. The connection is never playable.

I found the following logs before the WS_NOT_OPEN error.

[WS] closed
[WS] connect requested
[WS] reset requested
[WS] connecting, 5 attempts, wss://japan4233.discord.media/?v=4&encoding=json
[WS] opened at gateway japan4233.discord.media
...
[WS] closed
[WS] connect requested
[WS] reset requested
Error [VOICE_CONNECTION_ATTEMPTS_EXCEEDED]: Too many connection attempts (5).
at VoiceWebSocket.connect (/home/kanata/projects/knt2-dbot/node_modules/discord.js/src/client/voice/networking/VoiceWebSocket.js:67:26)
at Timeout._onTimeout (/home/kanata/projects/knt2-dbot/node_modules/discord.js/src/client/BaseClient.js:83:7)
at listOnTimeout (internal/timers.js:554:17)
at processTimers (internal/timers.js:497:7) {
[Symbol(code)]: 'VOICE_CONNECTION_ATTEMPTS_EXCEEDED'
}

In short, a VoiceConnection has no WebSocket connection after it hits the retry limit, then never playable, and we have no way to handle it. That's the problem.

Include a reproducible code sample here, if possible:

Note: Prepare a short audio file as sample.mp3

const Discord = require('discord.js');
const client = new Discord.Client();
client.login('__TOKEN__');
client.on('message', async message => {
  if (!message.guild || !message.member.voice.channel) return;
  const connection = await message.member.voice.channel.join();
  connection.on('debug', console.log);
  for (let i = 1; i < 20; ++i) {
    let delay = 10;
    if (connection.sockets.ws.ws) {
      connection.sockets.ws.ws.close();
      delay = i + 1;
    }
    console.log(i, delay);
    await new Promise(resolve => setTimeout(resolve, delay * 1000));
    const dispatcher = connection.play('sample.mp3');
    await new Promise(resolve => dispatcher.on('finish', resolve));
  }
});

It should reproduce the situation. VOICE_CONNECTION_ATTEMPTS_EXCEEDED happens at 5, after that, WS_NOT_OPEN always happens, and audio doesn't stream after 10 or so because of the heartbeat failure.

You might think the situation is very rare but I'd say it's not. My guild members are always in a voice channel, literally 24/7, then sometimes my bot encounters the retry limit, even my server has a good network. To leave and rejoin would simply fix it, but I assume that Discord.js itself should have a workaround.

Here are my proposals.

  1. To handle/prevent WS_NOT_OPEN
    1. Emit failed event from StreamDispatcher
      • dispatcher.on('failed', /* leave and rejoin or something */)
      • Note: WS_NOT_OPEN doesn't only happen after the retry limit but also happen while retrying because there is no connection between close and connect
        • It's playable though
        • The problem here is whether or not it's playable, then the failed event should happen after the heartbeat dead
    2. Emit retryLimit event from VoiceConnection and leave from a voice channel automatically when it hits the retry limit
      • connection.on('retryLimit', /* rejoin or something */)
      • In this case, no need failed event on StreamDispatcher, nor need to think about the heartbeat
      • But I don't know how to compromise with the existing disconnect event (the next proposal might solve this)
    3. Leave from a voice channel automatically with an error when it hits the retry limit
      • connection.on('disconnect', error => { if (error) /* rejoin or something */ })
      • error === undefined means that it disconnected normally (same as the current version)
      • error !== undefined means that something went wrong and automatically disconnected by Discord.js itself
      • In this case, we don't have to add new event but change a bit the disconnect event interface that affects almost nothing to the current version
      • I admit that it certainly affects a bit something because there's no such auto-disconnection before, but think about it, even in the current version, a VoiceConnection with no WebSocket connection is completely useless, there's no reason to hold, then we should've disconnected it in the first place
      • I think this is the best option, what do you think?
  2. To prevent/reduce VOICE_CONNECTION_ATTEMPTS_EXCEEDED
    1. Reset the retry counter after confirmed proper WebSocket connection
      • I understand that the retry limit is for safety but if a WebSocket connection is stable for 10 mins or so, then you can assume that it's running properly, not retrying/looping anymore
      • Again, the situation is not so rare, when your bot stays in a voice channel for a week, it hits the retry limit easily, that's why the retry counter should be reset at some point
      • There might be a better solution though

knt2nd/knt2-dbot#1 is my current workaround by the way. After this, the WS_NOT_OPEN error never happens at all.

Further details:

  • discord.js version: 12.5.1
  • Node.js version: 14.15.4
  • Operating system: Ubuntu 20.04.2
  • Priority this issue should have – please be realistic and elaborate if possible: Low

Relevant client options:

  • partials: none
  • gateway intents: none
  • other: none
@amishshah
Copy link
Member

Hi there,

We're working on a new implementation of Discord's Voice API that has better playback quality and is more reliable than what we currently support in Discord.js v12 - check it out at https://github.com/discordjs/voice!

The new library solves many of the issues that users are facing, and as part of this, we're dropping built-in support for voice in our next major release. We have a PR (#5402) that adds native support for our new voice library - once this PR is merged, this issue will be closed.

You can still use our new voice library before that PR lands - just take a look at our music bot example to see how to get started upgrading your voice code. By using the boilerplate music player in the example, you can make it even easier to upgrade your code.

Note that the PR above only reduces some of the boilerplate code you'd otherwise have to write - you do not have to wait for the PR to be merged to start using the new voice library.


If you have any questions about this, feel free to:

  • Make an issue if you have found a bug in the new voice library
  • Use GitHub Discussions or join our Discord server (we have a new channel, #djs-new-voice, specifically for this!) to ask general questions about the library, give feedback on the library, and get support with upgrading to it

@amishshah amishshah linked a pull request Jun 9, 2021 that will close this issue
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 2, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants