From 50cc4df965efe7b9a3c6b5bd221e85e4d23c2da9 Mon Sep 17 00:00:00 2001 From: Bruce Marriner Date: Fri, 11 Mar 2016 23:19:35 -0600 Subject: [PATCH] Some, slightly messy, fixes to get voice -working-. --- voice.go | 21 ++++++++++------ wsapi.go | 77 ++++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 63 insertions(+), 35 deletions(-) diff --git a/voice.go b/voice.go index c080813..a9ff4fe 100644 --- a/voice.go +++ b/voice.go @@ -12,7 +12,6 @@ package discordgo import ( "encoding/binary" "encoding/json" - "errors" "fmt" "net" "runtime" @@ -131,16 +130,22 @@ func (v *VoiceConnection) Open() (err error) { return } +// WaitUntilConnected is a TEMP FUNCTION +// And this is going to be removed to changed entirely. +// I know it looks hacky, but I needed to get it working quickly. func (v *VoiceConnection) WaitUntilConnected() error { - if v.Ready { - return nil - } - value, ok := <-v.connected + i := 0 + for { + if i > 10 { + return fmt.Errorf("Timeout waiting for voice.") + } - if (!value && !v.Ready) || !ok { - delete(v.session.VoiceConnections, v.GuildID) - return errors.New("Timed out connecting to voice") + if v.Ready { + return nil + } + time.Sleep(1 * time.Second) + i++ } return nil diff --git a/wsapi.go b/wsapi.go index 7bfbc39..b4dd701 100644 --- a/wsapi.go +++ b/wsapi.go @@ -336,52 +336,64 @@ type voiceChannelJoinOp struct { // cID : Channel ID of the channel to join. // mute : If true, you will be set to muted upon joining. // deaf : If true, you will be set to deafened upon joining. -// timeout : If greater than zero, the timeout in milliseconds after which connecting will fail +// timeout : If timeout > 0 then func will wait up to timeout for voice +// connection to be ready. If it does not become ready in that +// time frame then it will return an error and close out the voice +// connection entirely. func (s *Session) ChannelVoiceJoin(gID, cID string, mute, deaf bool, timeout int) (voice *VoiceConnection, err error) { - // If a voice connection for the guild exists, return that - if _, exists := s.VoiceConnections[gID]; exists { - return s.VoiceConnections[gID], err - } - // Send the request to Discord that we want to join the voice channel - data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}} - err = s.wsConn.WriteJSON(data) - if err != nil { - return nil, err + // If a voice connection alreadyy exists for this guild then + // return that connection. If the channel differs, also change channels. + // TODO: check if the voice connection is really valid or just a shell + // because we might want to allow setting variables prior to getting here + // like debug, and other things. + if voice, ok := s.VoiceConnections[gID]; ok { + if voice.ChannelID != cID { + err = voice.ChangeChannel(cID) + } + return voice, err + // TODO: ugh, ugly.. } // Create a new voice session + // TODO review what all these things are for.... voice = &VoiceConnection{ Receive: true, session: s, connected: make(chan bool), sessionRecv: make(chan string), + GuildID: gID, + ChannelID: cID, } - // Store this in the waiting map so it can get a session/token + // Store voice in VoiceConnections map for thils GuildID s.VoiceConnections[gID] = voice - // Store gID and cID for later use - voice.GuildID = gID - voice.ChannelID = cID - - // Queue the timeout in case we fail to connect - if timeout > 0 { - go func() { - time.Sleep(time.Millisecond * time.Duration(timeout)) - if !voice.Ready { - voice.connected <- false - } - }() + // Send the request to Discord that we want to join the voice channel + data := voiceChannelJoinOp{4, voiceChannelJoinData{&gID, &cID, mute, deaf}} + err = s.wsConn.WriteJSON(data) + if err != nil { + return } - return voice, err + // doesn't exactly work perfect yet.. TODO + if timeout > 0 { + err = voice.WaitUntilConnected() + if err != nil { + voice.Close() + delete(s.VoiceConnections, gID) + return + } + } + + return } // onVoiceStateUpdate handles Voice State Update events on the data // websocket. This comes immediately after the call to VoiceChannelJoin // for the session user. func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) { + // If we don't have a connection for the channel, don't bother if st.ChannelID == "" { return @@ -409,7 +421,10 @@ func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) { // Store the SessionID for later use. voice.UserID = self.ID // TODO: Review - voice.sessionRecv <- st.SessionID + voice.sessionID = st.SessionID + + // TODO: Consider this... + // voice.sessionRecv <- st.SessionID } // onVoiceServerUpdate handles the Voice Server Update data websocket event. @@ -420,10 +435,12 @@ func (s *Session) onVoiceStateUpdate(se *Session, st *VoiceStateUpdate) { // to a voice channel. In that case, need to re-establish connection to // the new region endpoint. func (s *Session) onVoiceServerUpdate(se *Session, st *VoiceServerUpdate) { + voice, exists := s.VoiceConnections[st.GuildID] // If no VoiceConnection exists, just skip this if !exists { + fmt.Println("doesn't exist! Oh noooo bail out.. emergency..") return } @@ -434,10 +451,16 @@ func (s *Session) onVoiceServerUpdate(se *Session, st *VoiceServerUpdate) { // If currently connected to voice ws/udp, then disconnect. // Has no effect if not connected. - voice.Close() + // voice.Close() // Wait for the sessionID from onVoiceStateUpdate - voice.sessionID = <-voice.sessionRecv + // voice.sessionID = <-voice.sessionRecv + // TODO review above + // wouldn't this cause a huge problem, if it's just a guild server + // update.. ? + // I could add a timeout loop of some sort and also check if the + // sessionID doesn't or does exist already... + // something.. a bit smarter. // We now have enough information to open a voice websocket conenction // so, that's what the next call does.