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

Voice websocket closed unexpectedly at random times #829

Closed
yms2772 opened this issue Oct 31, 2020 · 8 comments · Fixed by #1408
Closed

Voice websocket closed unexpectedly at random times #829

yms2772 opened this issue Oct 31, 2020 · 8 comments · Fixed by #1408

Comments

@yms2772
Copy link

yms2772 commented Oct 31, 2020

I'm making a bot which is playing songs using github.com/jonas747/dca.
However it always leave the voice channel at random times (about after 1 hour) with below log and join the channel again.
My internet is stable and I even used Amazon AWS but it showed same problem.

2020/10/31 15:14:36 [DG0] voice.go:376:wsListen() voice endpoint south-korea889.discord.media:443 websocket closed unexpectantly, websocket: close 1001 (going away)
2020/10/31 15:14:36 [DG0] voice.go:197:Close() error closing websocket, websocket: close sent
2020/10/31 15:14:37 [DG0] voice.go:206:Close() error closing websocket, write tcp 172.17.0.8:60728->162.159.128.235:443: i/o timeout
2020/10/31 15:14:49 [DG1] wsapi.go:648:ChannelVoiceJoin() error waiting for voice to connect, timeout waiting for voice
@colecrouter
Copy link

I've been getting this and it's a real pain. No way to catch it or anything. For me at least, it doesn't always crash from it; only about half the time. Really hoping someone will give us an update. Even a basic recover() would be a godsend at this point

@colecrouter
Copy link

I have an update on this one. Thanks to the @FlameInTheDark on this issue here, it appears that using this:

vc, err := discord.ChannelVoiceJoin(guildID, channelID, properties.Muted, properties.Deafened)
	if err != nil {
		if _, ok := discord.VoiceConnections[guildID]; ok {
			vc = discord.VoiceConnections[guildID]
		} else {
			return nil, err
		}
	}

—will fix your issue.

It almost looks like (Session*) ChannelVoiceJoin() just doesn't return properly sometimes. Not sure if this is a discordgo issue, or a Discord issue.

@yms2772
Copy link
Author

yms2772 commented Nov 18, 2020

I have an update on this one. Thanks to the @FlameInTheDark on this issue here, it appears that using this:

vc, err := discord.ChannelVoiceJoin(guildID, channelID, properties.Muted, properties.Deafened)
	if err != nil {
		if _, ok := discord.VoiceConnections[guildID]; ok {
			vc = discord.VoiceConnections[guildID]
		} else {
			return nil, err
		}
	}

—will fix your issue.

It almost looks like (Session*) ChannelVoiceJoin() just doesn't return properly sometimes. Not sure if this is a discordgo issue, or a Discord issue.

I'm trying using that code and it does not timeout even after an hour has passed.
Thank you for your reply.

Mroik added a commit to Mroik/go-Covid-chan that referenced this issue Nov 18, 2020
@colecrouter
Copy link

colecrouter commented Nov 24, 2020

This doesn't seem to be working for me anymore. I haven't had a chance to double check and make sure I didn't screw something up, but I will as soon as I can.
EDIT:
it appears that the uppermost err is still getting returned. I'm going to try adding another:

if err != nil {
	log.Fatalln("error connecting:", err)
	return // Emphasis on the return
}

—at the end. This doesn't look like it'll fix the issue, but it might stop the crashing? We'll see.

@yms2772
Copy link
Author

yms2772 commented Dec 6, 2020

This doesn't seem to be working for me anymore. I haven't had a chance to double check and make sure I didn't screw something up, but I will as soon as I can.
EDIT:
it appears that the uppermost err is still getting returned. I'm going to try adding another:

if err != nil {
	log.Fatalln("error connecting:", err)
	return // Emphasis on the return
}

—at the end. This doesn't look like it'll fix the issue, but it might stop the crashing? We'll see.

I've been thinking about this a lot, I think I should give the websocket a keepalive signal like below code.

func DiscordVoicePing(guildID string) {
	voiceConnection[guildID].StreamSession.SetPaused(true)
	done := make(chan error)

	encodingSession, _ := dca.EncodeFile("./bin/ping.mp3", options)
	dca.NewStream(encodingSession, voiceConnection[guildID].VC, done)

	err := <-done
	if err != nil && err != io.EOF {
		log.Printf("Ping Error: %s", err.Error())
	}

	voiceConnection[guildID].StreamSession.SetPaused(false)
}

ping.mp3 is a 0.3 second silent file.
Since that function is executed once every 10 minutes with a ticker, the voice does not stop.

@colecrouter
Copy link

Idiot me didn't realize that we were using log.Fatalln() and not log.Println() so that's definitely contributing to the exiting. Like I said, this won't solve the crashing outright, but "failing to function consistently" is miles better than crashing. Here's what I have now:

vc, err = s.ChannelVoiceJoin(e.GuildID, e.ChannelID, false, false)
if err != nil {
	if err, ok := s.VoiceConnections[e.GuildID]; ok {
		vc = s.VoiceConnections[e.GuildID]
		if err != nil {
			log.Println("error connecting:", err)
			return
		}
	} else {
		log.Println("error connecting:", err)
		return
	}
}

Will report back later. For anyone else who's interested, this is the line with the function that throws the error. Looks like just a simple loop waiting for it to Ready. Either Ready isn't being set properly, or it's an issue on Discord's end. That's my naïve take at least.

@colecrouter
Copy link

Looks like the snippet I posted above does the trick. However, the error is still happening. This is what I've found:

i := 0
for {
	if v.sessionID != "" {
		break
	}
	if i > 20 { // only loop for up to 1 second total
		return fmt.Errorf("did not receive voice Session ID in time")
	}
	time.Sleep(50 * time.Millisecond)
	i++
}

The whole error down the chain being:

[DG0] wsapi.go:744:onVoiceServerUpdate() onVoiceServerUpdate voice.open, did not receive voice Session ID in time

This is what I've found from the Discord docs:

f our request succeeded, the gateway will respond with two events—a Voice State Update event and a Voice Server Update event—meaning your library must properly wait for both events before continuing. The first will contain a new key, session_id, and the second will provide voice server information we can use to establish a new voice connection:

So the bot is waiting on two packets, and it kinda looks like they're not arriving. Granted, it is only waiting 1 second. While the waitUntilConnected() function tries for 10 seconds, it won't happen because open() has already returned an error and is no longer listening (if I understand it correctly). I think this here might be our problem.

I'll try to fork it, make the change, and test it when I get the chance. In the mean time, anyone is welcome to try increasing the timeout from the line I mentioned above and reporting back.

@denverquane
Copy link
Contributor

I'll try to fork it, make the change, and test it when I get the chance. In the mean time, anyone is welcome to try increasing the timeout from the line I mentioned above and reporting back.

I had the same bug, but increasing the timeout had no effect. I realized it's a deadlock; wsapi.go locks before populating the sessionID we need, but the open() function holds the lock for the entire function, meaning the sessionID can never be updated in that sleep loop.

See my PR mentioned above for the fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants