forked from pothtonswer/discordmuffin
All sent JSON data now using structs
This commit is contained in:
parent
0fbfc66554
commit
b87add9152
1 changed files with 61 additions and 22 deletions
83
voice.go
83
voice.go
|
@ -23,7 +23,7 @@ import (
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A VEvent is the inital structure for voice websocket events. I think
|
// A VEvent is the initial structure for voice websocket events. I think
|
||||||
// I can reuse the data websocket structure here.
|
// I can reuse the data websocket structure here.
|
||||||
type VEvent struct {
|
type VEvent struct {
|
||||||
Type string `json:"t"`
|
Type string `json:"t"`
|
||||||
|
@ -41,15 +41,32 @@ type VoiceOP2 struct {
|
||||||
HeartbeatInterval time.Duration `json:"heartbeat_interval"`
|
HeartbeatInterval time.Duration `json:"heartbeat_interval"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type voiceHandshakeData struct {
|
||||||
|
ServerID string `json:"server_id"`
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
SessionID string `json:"session_id"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type voiceHandshakeOp struct {
|
||||||
|
Op int `json:"op"` // Always 0
|
||||||
|
Data voiceHandshakeData `json:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
// VoiceOpenWS opens a voice websocket connection. This should be called
|
// VoiceOpenWS opens a voice websocket connection. This should be called
|
||||||
// after VoiceChannelJoin is used and the data VOICE websocket events
|
// after VoiceChannelJoin is used and the data VOICE websocket events
|
||||||
// are captured.
|
// are captured.
|
||||||
func (s *Session) VoiceOpenWS() {
|
func (s *Session) VoiceOpenWS() {
|
||||||
|
|
||||||
|
// Don't open a socket if one is already open
|
||||||
|
if s.VwsConn != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var self User
|
var self User
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
self, err = s.User("@me") // AGAIN, Move to @ login and store in session
|
self, err = s.User("@me") // TODO: Move to @ login and store in session
|
||||||
|
|
||||||
// Connect to Voice Websocket
|
// Connect to Voice Websocket
|
||||||
vg := fmt.Sprintf("wss://%s", strings.TrimSuffix(s.VEndpoint, ":80"))
|
vg := fmt.Sprintf("wss://%s", strings.TrimSuffix(s.VEndpoint, ":80"))
|
||||||
|
@ -58,16 +75,7 @@ func (s *Session) VoiceOpenWS() {
|
||||||
fmt.Println("VOICE cannot open websocket:", err)
|
fmt.Println("VOICE cannot open websocket:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send initial handshake data to voice websocket. This is required.
|
json := voiceHandshakeOp{0, voiceHandshakeData{s.VGuildID, self.ID, s.VSessionID, s.VToken}}
|
||||||
json := map[string]interface{}{
|
|
||||||
"op": 0,
|
|
||||||
"d": map[string]interface{}{
|
|
||||||
"server_id": s.VGuildID,
|
|
||||||
"user_id": self.ID,
|
|
||||||
"session_id": s.VSessionID,
|
|
||||||
"token": s.VToken,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.VwsConn.WriteJSON(json)
|
err = s.VwsConn.WriteJSON(json)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -147,13 +155,29 @@ func (s *Session) VoiceEvent(messageType int, message []byte) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type voiceUDPData struct {
|
||||||
|
Address string `json:"address"` // Public IP of machine running this code
|
||||||
|
Port uint16 `json:"port"` // UDP Port of machine running this code
|
||||||
|
Mode string `json:"mode"` // plain or ? (plain or encrypted)
|
||||||
|
}
|
||||||
|
|
||||||
|
type voiceUDPD struct {
|
||||||
|
Protocol string `json:"protocol"` // Always "udp" ?
|
||||||
|
Data voiceUDPData `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type voiceUDPOp struct {
|
||||||
|
Op int `json:"op"` // Always 1
|
||||||
|
Data voiceUDPD `json:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
// VoiceOpenUDP opens a UDP connect to the voice server and completes the
|
// VoiceOpenUDP opens a UDP connect to the voice server and completes the
|
||||||
// initial required handshake. This connect is left open in the session
|
// initial required handshake. This connect is left open in the session
|
||||||
// and can be used to send or receive audio.
|
// and can be used to send or receive audio.
|
||||||
func (s *Session) VoiceOpenUDP() {
|
func (s *Session) VoiceOpenUDP() {
|
||||||
|
|
||||||
// TODO: add code to convert hostname into an IP address to avoid problems
|
// TODO: add code to convert hostname into an IP address to avoid problems
|
||||||
// with frequent DNS lookups.
|
// with frequent DNS lookups. ??
|
||||||
|
|
||||||
udpHost := fmt.Sprintf("%s:%d", strings.TrimSuffix(s.VEndpoint, ":80"), s.Vop2.Port)
|
udpHost := fmt.Sprintf("%s:%d", strings.TrimSuffix(s.VEndpoint, ":80"), s.Vop2.Port)
|
||||||
serverAddr, err := net.ResolveUDPAddr("udp", udpHost)
|
serverAddr, err := net.ResolveUDPAddr("udp", udpHost)
|
||||||
|
@ -182,6 +206,7 @@ func (s *Session) VoiceOpenUDP() {
|
||||||
fmt.Println("Voice RLEN should be 70 but isn't")
|
fmt.Println("Voice RLEN should be 70 but isn't")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO need serious changes, this will likely not work on all IPs!
|
||||||
ip := string(rb[4:16]) // must be a better way. TODO: NEEDS TESTING
|
ip := string(rb[4:16]) // must be a better way. TODO: NEEDS TESTING
|
||||||
port := make([]byte, 2)
|
port := make([]byte, 2)
|
||||||
port[0] = rb[68]
|
port[0] = rb[68]
|
||||||
|
@ -190,10 +215,9 @@ func (s *Session) VoiceOpenUDP() {
|
||||||
|
|
||||||
// Take the parsed data from above and send it back to Discord
|
// Take the parsed data from above and send it back to Discord
|
||||||
// to finalize the UDP handshake.
|
// to finalize the UDP handshake.
|
||||||
json := fmt.Sprintf(`{"op":1,"d":{"protocol":"udp","data":{"address":"%s","port":%d,"mode":"plain"}}}`, ip, p)
|
jsondata := voiceUDPOp{1, voiceUDPD{"udp", voiceUDPData{ip, p, "plain"}}}
|
||||||
jsonb := []byte(json)
|
|
||||||
|
|
||||||
err = s.VwsConn.WriteMessage(websocket.TextMessage, jsonb)
|
err = s.VwsConn.WriteJSON(jsondata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("error:", err)
|
fmt.Println("error:", err)
|
||||||
return
|
return
|
||||||
|
@ -209,6 +233,16 @@ func (s *Session) VoiceCloseUDP() {
|
||||||
s.UDPConn.Close()
|
s.UDPConn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type voiceSpeakingData struct {
|
||||||
|
Speaking bool `json:"speaking"`
|
||||||
|
Delay int `json:"delay"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type voiceSpeakingOp struct {
|
||||||
|
Op int `json:"op"` // Always 5
|
||||||
|
Data voiceSpeakingData `json:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Session) VoiceSpeaking() {
|
func (s *Session) VoiceSpeaking() {
|
||||||
|
|
||||||
if s.VwsConn == nil {
|
if s.VwsConn == nil {
|
||||||
|
@ -217,8 +251,8 @@ func (s *Session) VoiceSpeaking() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonb := []byte(`{"op":5,"d":{"speaking":true,"delay":0}}`)
|
json := voiceSpeakingOp{5, voiceSpeakingData{true, 0}}
|
||||||
err := s.VwsConn.WriteMessage(websocket.TextMessage, jsonb)
|
err := s.VwsConn.WriteJSON(json)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("error:", err)
|
fmt.Println("error:", err)
|
||||||
return
|
return
|
||||||
|
@ -284,6 +318,11 @@ func (s *Session) VoiceUDPKeepalive(i time.Duration) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type voiceHeartbeatOp struct {
|
||||||
|
Op int `json:"op"` // Always 3
|
||||||
|
Data int `json:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
// VoiceHeartbeat sends regular heartbeats to voice Discord so it knows the client
|
// VoiceHeartbeat sends regular heartbeats to voice Discord so it knows the client
|
||||||
// is still connected. If you do not send these heartbeats Discord will
|
// is still connected. If you do not send these heartbeats Discord will
|
||||||
// disconnect the websocket connection after a few seconds.
|
// disconnect the websocket connection after a few seconds.
|
||||||
|
@ -292,15 +331,15 @@ func (s *Session) VoiceHeartbeat(i time.Duration) {
|
||||||
ticker := time.NewTicker(i * time.Millisecond)
|
ticker := time.NewTicker(i * time.Millisecond)
|
||||||
for {
|
for {
|
||||||
timestamp := int(time.Now().Unix())
|
timestamp := int(time.Now().Unix())
|
||||||
err := s.VwsConn.WriteJSON(map[string]int{
|
json := voiceHeartbeatOp{3, timestamp}
|
||||||
"op": 3,
|
|
||||||
"d": timestamp,
|
err := s.VwsConn.WriteJSON(json)
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.VoiceReady = false
|
s.VoiceReady = false
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return // log error?
|
return // log error?
|
||||||
}
|
}
|
||||||
|
|
||||||
s.VoiceReady = true
|
s.VoiceReady = true
|
||||||
<-ticker.C
|
<-ticker.C
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue