voice.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. // Discordgo - Discord bindings for Go
  2. // Available at https://github.com/bwmarrin/discordgo
  3. // Copyright 2015-2016 Bruce Marriner <bruce@sqls.net>. All rights reserved.
  4. // Use of this source code is governed by a BSD-style
  5. // license that can be found in the LICENSE file.
  6. // This file contains code related to Discord voice suppport
  7. package discordgo
  8. import (
  9. "encoding/binary"
  10. "encoding/json"
  11. "fmt"
  12. "net"
  13. "strings"
  14. "sync"
  15. "time"
  16. "github.com/gorilla/websocket"
  17. "golang.org/x/crypto/nacl/secretbox"
  18. )
  19. // ------------------------------------------------------------------------------------------------
  20. // Code related to both VoiceConnection Websocket and UDP connections.
  21. // ------------------------------------------------------------------------------------------------
  22. // A VoiceConnection struct holds all the data and functions related to a Discord Voice Connection.
  23. type VoiceConnection struct {
  24. sync.RWMutex
  25. Debug bool // If true, print extra logging -- DEPRECATED
  26. LogLevel int
  27. Ready bool // If true, voice is ready to send/receive audio
  28. UserID string
  29. GuildID string
  30. ChannelID string
  31. deaf bool
  32. mute bool
  33. speaking bool
  34. reconnecting bool // If true, voice connection is trying to reconnect
  35. OpusSend chan []byte // Chan for sending opus audio
  36. OpusRecv chan *Packet // Chan for receiving opus audio
  37. wsConn *websocket.Conn
  38. wsMutex sync.Mutex
  39. udpConn *net.UDPConn
  40. session *Session
  41. sessionID string
  42. token string
  43. endpoint string
  44. // Used to send a close signal to goroutines
  45. close chan struct{}
  46. // Used to allow blocking until connected
  47. connected chan bool
  48. // Used to pass the sessionid from onVoiceStateUpdate
  49. // sessionRecv chan string UNUSED ATM
  50. op4 voiceOP4
  51. op2 voiceOP2
  52. voiceSpeakingUpdateHandlers []VoiceSpeakingUpdateHandler
  53. }
  54. // VoiceSpeakingUpdateHandler type provides a function definition for the
  55. // VoiceSpeakingUpdate event
  56. type VoiceSpeakingUpdateHandler func(vc *VoiceConnection, vs *VoiceSpeakingUpdate)
  57. // Speaking sends a speaking notification to Discord over the voice websocket.
  58. // This must be sent as true prior to sending audio and should be set to false
  59. // once finished sending audio.
  60. // b : Send true if speaking, false if not.
  61. func (v *VoiceConnection) Speaking(b bool) (err error) {
  62. v.log(LogDebug, "called (%t)", b)
  63. type voiceSpeakingData struct {
  64. Speaking bool `json:"speaking"`
  65. Delay int `json:"delay"`
  66. }
  67. type voiceSpeakingOp struct {
  68. Op int `json:"op"` // Always 5
  69. Data voiceSpeakingData `json:"d"`
  70. }
  71. if v.wsConn == nil {
  72. return fmt.Errorf("no VoiceConnection websocket")
  73. }
  74. data := voiceSpeakingOp{5, voiceSpeakingData{b, 0}}
  75. v.wsMutex.Lock()
  76. err = v.wsConn.WriteJSON(data)
  77. v.wsMutex.Unlock()
  78. v.Lock()
  79. defer v.Unlock()
  80. if err != nil {
  81. v.speaking = false
  82. v.log(LogError, "Speaking() write json error:", err)
  83. return
  84. }
  85. v.speaking = b
  86. return
  87. }
  88. // ChangeChannel sends Discord a request to change channels within a Guild
  89. // !!! NOTE !!! This function may be removed in favour of just using ChannelVoiceJoin
  90. func (v *VoiceConnection) ChangeChannel(channelID string, mute, deaf bool) (err error) {
  91. v.log(LogInformational, "called")
  92. data := voiceChannelJoinOp{4, voiceChannelJoinData{&v.GuildID, &channelID, mute, deaf}}
  93. v.wsMutex.Lock()
  94. err = v.session.wsConn.WriteJSON(data)
  95. v.wsMutex.Unlock()
  96. if err != nil {
  97. return
  98. }
  99. v.ChannelID = channelID
  100. v.deaf = deaf
  101. v.mute = mute
  102. v.speaking = false
  103. return
  104. }
  105. // Disconnect disconnects from this voice channel and closes the websocket
  106. // and udp connections to Discord.
  107. func (v *VoiceConnection) Disconnect() (err error) {
  108. // Send a OP4 with a nil channel to disconnect
  109. if v.sessionID != "" {
  110. data := voiceChannelJoinOp{4, voiceChannelJoinData{&v.GuildID, nil, true, true}}
  111. v.session.wsMutex.Lock()
  112. err = v.session.wsConn.WriteJSON(data)
  113. v.session.wsMutex.Unlock()
  114. v.sessionID = ""
  115. }
  116. // Close websocket and udp connections
  117. v.Close()
  118. v.log(LogInformational, "Deleting VoiceConnection %s", v.GuildID)
  119. v.session.Lock()
  120. delete(v.session.VoiceConnections, v.GuildID)
  121. v.session.Unlock()
  122. return
  123. }
  124. // Close closes the voice ws and udp connections
  125. func (v *VoiceConnection) Close() {
  126. v.log(LogInformational, "called")
  127. v.Lock()
  128. defer v.Unlock()
  129. v.Ready = false
  130. v.speaking = false
  131. if v.close != nil {
  132. v.log(LogInformational, "closing v.close")
  133. close(v.close)
  134. v.close = nil
  135. }
  136. if v.udpConn != nil {
  137. v.log(LogInformational, "closing udp")
  138. err := v.udpConn.Close()
  139. if err != nil {
  140. v.log(LogError, "error closing udp connection: ", err)
  141. }
  142. v.udpConn = nil
  143. }
  144. if v.wsConn != nil {
  145. v.log(LogInformational, "sending close frame")
  146. // To cleanly close a connection, a client should send a close
  147. // frame and wait for the server to close the connection.
  148. v.wsMutex.Lock()
  149. err := v.wsConn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
  150. v.wsMutex.Unlock()
  151. if err != nil {
  152. v.log(LogError, "error closing websocket, %s", err)
  153. }
  154. // TODO: Wait for Discord to actually close the connection.
  155. time.Sleep(1 * time.Second)
  156. v.log(LogInformational, "closing websocket")
  157. err = v.wsConn.Close()
  158. if err != nil {
  159. v.log(LogError, "error closing websocket, %s", err)
  160. }
  161. v.wsConn = nil
  162. }
  163. }
  164. // AddHandler adds a Handler for VoiceSpeakingUpdate events.
  165. func (v *VoiceConnection) AddHandler(h VoiceSpeakingUpdateHandler) {
  166. v.Lock()
  167. defer v.Unlock()
  168. v.voiceSpeakingUpdateHandlers = append(v.voiceSpeakingUpdateHandlers, h)
  169. }
  170. // VoiceSpeakingUpdate is a struct for a VoiceSpeakingUpdate event.
  171. type VoiceSpeakingUpdate struct {
  172. UserID string `json:"user_id"`
  173. SSRC int `json:"ssrc"`
  174. Speaking bool `json:"speaking"`
  175. }
  176. // ------------------------------------------------------------------------------------------------
  177. // Unexported Internal Functions Below.
  178. // ------------------------------------------------------------------------------------------------
  179. // A voiceOP4 stores the data for the voice operation 4 websocket event
  180. // which provides us with the NaCl SecretBox encryption key
  181. type voiceOP4 struct {
  182. SecretKey [32]byte `json:"secret_key"`
  183. Mode string `json:"mode"`
  184. }
  185. // A voiceOP2 stores the data for the voice operation 2 websocket event
  186. // which is sort of like the voice READY packet
  187. type voiceOP2 struct {
  188. SSRC uint32 `json:"ssrc"`
  189. Port int `json:"port"`
  190. Modes []string `json:"modes"`
  191. HeartbeatInterval time.Duration `json:"heartbeat_interval"`
  192. }
  193. // WaitUntilConnected waits for the Voice Connection to
  194. // become ready, if it does not become ready it returns an err
  195. func (v *VoiceConnection) waitUntilConnected() error {
  196. v.log(LogInformational, "called")
  197. i := 0
  198. for {
  199. v.RLock()
  200. ready := v.Ready
  201. v.RUnlock()
  202. if ready {
  203. return nil
  204. }
  205. if i > 10 {
  206. return fmt.Errorf("timeout waiting for voice")
  207. }
  208. time.Sleep(1 * time.Second)
  209. i++
  210. }
  211. }
  212. // Open opens a voice connection. This should be called
  213. // after VoiceChannelJoin is used and the data VOICE websocket events
  214. // are captured.
  215. func (v *VoiceConnection) open() (err error) {
  216. v.log(LogInformational, "called")
  217. v.Lock()
  218. defer v.Unlock()
  219. // Don't open a websocket if one is already open
  220. if v.wsConn != nil {
  221. v.log(LogWarning, "refusing to overwrite non-nil websocket")
  222. return
  223. }
  224. // TODO temp? loop to wait for the SessionID
  225. i := 0
  226. for {
  227. if v.sessionID != "" {
  228. break
  229. }
  230. if i > 20 { // only loop for up to 1 second total
  231. return fmt.Errorf("did not receive voice Session ID in time")
  232. }
  233. time.Sleep(50 * time.Millisecond)
  234. i++
  235. }
  236. // Connect to VoiceConnection Websocket
  237. vg := fmt.Sprintf("wss://%s", strings.TrimSuffix(v.endpoint, ":80"))
  238. v.log(LogInformational, "connecting to voice endpoint %s", vg)
  239. v.wsConn, _, err = websocket.DefaultDialer.Dial(vg, nil)
  240. if err != nil {
  241. v.log(LogWarning, "error connecting to voice endpoint %s, %s", vg, err)
  242. v.log(LogDebug, "voice struct: %#v\n", v)
  243. return
  244. }
  245. type voiceHandshakeData struct {
  246. ServerID string `json:"server_id"`
  247. UserID string `json:"user_id"`
  248. SessionID string `json:"session_id"`
  249. Token string `json:"token"`
  250. }
  251. type voiceHandshakeOp struct {
  252. Op int `json:"op"` // Always 0
  253. Data voiceHandshakeData `json:"d"`
  254. }
  255. data := voiceHandshakeOp{0, voiceHandshakeData{v.GuildID, v.UserID, v.sessionID, v.token}}
  256. err = v.wsConn.WriteJSON(data)
  257. if err != nil {
  258. v.log(LogWarning, "error sending init packet, %s", err)
  259. return
  260. }
  261. v.close = make(chan struct{})
  262. go v.wsListen(v.wsConn, v.close)
  263. // add loop/check for Ready bool here?
  264. // then return false if not ready?
  265. // but then wsListen will also err.
  266. return
  267. }
  268. // wsListen listens on the voice websocket for messages and passes them
  269. // to the voice event handler. This is automatically called by the Open func
  270. func (v *VoiceConnection) wsListen(wsConn *websocket.Conn, close <-chan struct{}) {
  271. v.log(LogInformational, "called")
  272. for {
  273. _, message, err := v.wsConn.ReadMessage()
  274. if err != nil {
  275. // Detect if we have been closed manually. If a Close() has already
  276. // happened, the websocket we are listening on will be different to the
  277. // current session.
  278. v.RLock()
  279. sameConnection := v.wsConn == wsConn
  280. v.RUnlock()
  281. if sameConnection {
  282. v.log(LogError, "voice endpoint %s websocket closed unexpectantly, %s", v.endpoint, err)
  283. // Start reconnect goroutine then exit.
  284. go v.reconnect()
  285. }
  286. return
  287. }
  288. // Pass received message to voice event handler
  289. select {
  290. case <-close:
  291. return
  292. default:
  293. go v.onEvent(message)
  294. }
  295. }
  296. }
  297. // wsEvent handles any voice websocket events. This is only called by the
  298. // wsListen() function.
  299. func (v *VoiceConnection) onEvent(message []byte) {
  300. v.log(LogDebug, "received: %s", string(message))
  301. var e Event
  302. if err := json.Unmarshal(message, &e); err != nil {
  303. v.log(LogError, "unmarshall error, %s", err)
  304. return
  305. }
  306. switch e.Operation {
  307. case 2: // READY
  308. if err := json.Unmarshal(e.RawData, &v.op2); err != nil {
  309. v.log(LogError, "OP2 unmarshall error, %s, %s", err, string(e.RawData))
  310. return
  311. }
  312. // Start the voice websocket heartbeat to keep the connection alive
  313. go v.wsHeartbeat(v.wsConn, v.close, v.op2.HeartbeatInterval)
  314. // TODO monitor a chan/bool to verify this was successful
  315. // Start the UDP connection
  316. err := v.udpOpen()
  317. if err != nil {
  318. v.log(LogError, "error opening udp connection, %s", err)
  319. return
  320. }
  321. // Start the opusSender.
  322. // TODO: Should we allow 48000/960 values to be user defined?
  323. if v.OpusSend == nil {
  324. v.OpusSend = make(chan []byte, 2)
  325. }
  326. go v.opusSender(v.udpConn, v.close, v.OpusSend, 48000, 960)
  327. // Start the opusReceiver
  328. if !v.deaf {
  329. if v.OpusRecv == nil {
  330. v.OpusRecv = make(chan *Packet, 2)
  331. }
  332. go v.opusReceiver(v.udpConn, v.close, v.OpusRecv)
  333. }
  334. return
  335. case 3: // HEARTBEAT response
  336. // add code to use this to track latency?
  337. return
  338. case 4: // udp encryption secret key
  339. v.Lock()
  340. defer v.Unlock()
  341. v.op4 = voiceOP4{}
  342. if err := json.Unmarshal(e.RawData, &v.op4); err != nil {
  343. v.log(LogError, "OP4 unmarshall error, %s, %s", err, string(e.RawData))
  344. return
  345. }
  346. return
  347. case 5:
  348. if len(v.voiceSpeakingUpdateHandlers) == 0 {
  349. return
  350. }
  351. voiceSpeakingUpdate := &VoiceSpeakingUpdate{}
  352. if err := json.Unmarshal(e.RawData, voiceSpeakingUpdate); err != nil {
  353. v.log(LogError, "OP5 unmarshall error, %s, %s", err, string(e.RawData))
  354. return
  355. }
  356. for _, h := range v.voiceSpeakingUpdateHandlers {
  357. h(v, voiceSpeakingUpdate)
  358. }
  359. default:
  360. v.log(LogDebug, "unknown voice operation, %d, %s", e.Operation, string(e.RawData))
  361. }
  362. return
  363. }
  364. type voiceHeartbeatOp struct {
  365. Op int `json:"op"` // Always 3
  366. Data int `json:"d"`
  367. }
  368. // NOTE :: When a guild voice server changes how do we shut this down
  369. // properly, so a new connection can be setup without fuss?
  370. //
  371. // wsHeartbeat sends regular heartbeats to voice Discord so it knows the client
  372. // is still connected. If you do not send these heartbeats Discord will
  373. // disconnect the websocket connection after a few seconds.
  374. func (v *VoiceConnection) wsHeartbeat(wsConn *websocket.Conn, close <-chan struct{}, i time.Duration) {
  375. if close == nil || wsConn == nil {
  376. return
  377. }
  378. var err error
  379. ticker := time.NewTicker(i * time.Millisecond)
  380. defer ticker.Stop()
  381. for {
  382. v.log(LogDebug, "sending heartbeat packet")
  383. v.wsMutex.Lock()
  384. err = wsConn.WriteJSON(voiceHeartbeatOp{3, int(time.Now().Unix())})
  385. v.wsMutex.Unlock()
  386. if err != nil {
  387. v.log(LogError, "error sending heartbeat to voice endpoint %s, %s", v.endpoint, err)
  388. return
  389. }
  390. select {
  391. case <-ticker.C:
  392. // continue loop and send heartbeat
  393. case <-close:
  394. return
  395. }
  396. }
  397. }
  398. // ------------------------------------------------------------------------------------------------
  399. // Code related to the VoiceConnection UDP connection
  400. // ------------------------------------------------------------------------------------------------
  401. type voiceUDPData struct {
  402. Address string `json:"address"` // Public IP of machine running this code
  403. Port uint16 `json:"port"` // UDP Port of machine running this code
  404. Mode string `json:"mode"` // always "xsalsa20_poly1305"
  405. }
  406. type voiceUDPD struct {
  407. Protocol string `json:"protocol"` // Always "udp" ?
  408. Data voiceUDPData `json:"data"`
  409. }
  410. type voiceUDPOp struct {
  411. Op int `json:"op"` // Always 1
  412. Data voiceUDPD `json:"d"`
  413. }
  414. // udpOpen opens a UDP connection to the voice server and completes the
  415. // initial required handshake. This connection is left open in the session
  416. // and can be used to send or receive audio. This should only be called
  417. // from voice.wsEvent OP2
  418. func (v *VoiceConnection) udpOpen() (err error) {
  419. v.Lock()
  420. defer v.Unlock()
  421. if v.wsConn == nil {
  422. return fmt.Errorf("nil voice websocket")
  423. }
  424. if v.udpConn != nil {
  425. return fmt.Errorf("udp connection already open")
  426. }
  427. if v.close == nil {
  428. return fmt.Errorf("nil close channel")
  429. }
  430. if v.endpoint == "" {
  431. return fmt.Errorf("empty endpoint")
  432. }
  433. host := fmt.Sprintf("%s:%d", strings.TrimSuffix(v.endpoint, ":80"), v.op2.Port)
  434. addr, err := net.ResolveUDPAddr("udp", host)
  435. if err != nil {
  436. v.log(LogWarning, "error resolving udp host %s, %s", host, err)
  437. return
  438. }
  439. v.log(LogInformational, "connecting to udp addr %s", addr.String())
  440. v.udpConn, err = net.DialUDP("udp", nil, addr)
  441. if err != nil {
  442. v.log(LogWarning, "error connecting to udp addr %s, %s", addr.String(), err)
  443. return
  444. }
  445. // Create a 70 byte array and put the SSRC code from the Op 2 VoiceConnection event
  446. // into it. Then send that over the UDP connection to Discord
  447. sb := make([]byte, 70)
  448. binary.BigEndian.PutUint32(sb, v.op2.SSRC)
  449. _, err = v.udpConn.Write(sb)
  450. if err != nil {
  451. v.log(LogWarning, "udp write error to %s, %s", addr.String(), err)
  452. return
  453. }
  454. // Create a 70 byte array and listen for the initial handshake response
  455. // from Discord. Once we get it parse the IP and PORT information out
  456. // of the response. This should be our public IP and PORT as Discord
  457. // saw us.
  458. rb := make([]byte, 70)
  459. rlen, _, err := v.udpConn.ReadFromUDP(rb)
  460. if err != nil {
  461. v.log(LogWarning, "udp read error, %s, %s", addr.String(), err)
  462. return
  463. }
  464. if rlen < 70 {
  465. v.log(LogWarning, "received udp packet too small")
  466. return fmt.Errorf("received udp packet too small")
  467. }
  468. // Loop over position 4 through 20 to grab the IP address
  469. // Should never be beyond position 20.
  470. var ip string
  471. for i := 4; i < 20; i++ {
  472. if rb[i] == 0 {
  473. break
  474. }
  475. ip += string(rb[i])
  476. }
  477. // Grab port from position 68 and 69
  478. port := binary.LittleEndian.Uint16(rb[68:70])
  479. // Take the data from above and send it back to Discord to finalize
  480. // the UDP connection handshake.
  481. data := voiceUDPOp{1, voiceUDPD{"udp", voiceUDPData{ip, port, "xsalsa20_poly1305"}}}
  482. v.wsMutex.Lock()
  483. err = v.wsConn.WriteJSON(data)
  484. v.wsMutex.Unlock()
  485. if err != nil {
  486. v.log(LogWarning, "udp write error, %#v, %s", data, err)
  487. return
  488. }
  489. // start udpKeepAlive
  490. go v.udpKeepAlive(v.udpConn, v.close, 5*time.Second)
  491. // TODO: find a way to check that it fired off okay
  492. return
  493. }
  494. // udpKeepAlive sends a udp packet to keep the udp connection open
  495. // This is still a bit of a "proof of concept"
  496. func (v *VoiceConnection) udpKeepAlive(udpConn *net.UDPConn, close <-chan struct{}, i time.Duration) {
  497. if udpConn == nil || close == nil {
  498. return
  499. }
  500. var err error
  501. var sequence uint64
  502. packet := make([]byte, 8)
  503. ticker := time.NewTicker(i)
  504. defer ticker.Stop()
  505. for {
  506. binary.LittleEndian.PutUint64(packet, sequence)
  507. sequence++
  508. _, err = udpConn.Write(packet)
  509. if err != nil {
  510. v.log(LogError, "write error, %s", err)
  511. return
  512. }
  513. select {
  514. case <-ticker.C:
  515. // continue loop and send keepalive
  516. case <-close:
  517. return
  518. }
  519. }
  520. }
  521. // opusSender will listen on the given channel and send any
  522. // pre-encoded opus audio to Discord. Supposedly.
  523. func (v *VoiceConnection) opusSender(udpConn *net.UDPConn, close <-chan struct{}, opus <-chan []byte, rate, size int) {
  524. if udpConn == nil || close == nil {
  525. return
  526. }
  527. // VoiceConnection is now ready to receive audio packets
  528. // TODO: this needs reviewed as I think there must be a better way.
  529. v.Lock()
  530. v.Ready = true
  531. v.Unlock()
  532. defer func() {
  533. v.Lock()
  534. v.Ready = false
  535. v.Unlock()
  536. }()
  537. var sequence uint16
  538. var timestamp uint32
  539. var recvbuf []byte
  540. var ok bool
  541. udpHeader := make([]byte, 12)
  542. var nonce [24]byte
  543. // build the parts that don't change in the udpHeader
  544. udpHeader[0] = 0x80
  545. udpHeader[1] = 0x78
  546. binary.BigEndian.PutUint32(udpHeader[8:], v.op2.SSRC)
  547. // start a send loop that loops until buf chan is closed
  548. ticker := time.NewTicker(time.Millisecond * time.Duration(size/(rate/1000)))
  549. defer ticker.Stop()
  550. for {
  551. // Get data from chan. If chan is closed, return.
  552. select {
  553. case <-close:
  554. return
  555. case recvbuf, ok = <-opus:
  556. if !ok {
  557. return
  558. }
  559. // else, continue loop
  560. }
  561. v.RLock()
  562. speaking := v.speaking
  563. v.RUnlock()
  564. if !speaking {
  565. err := v.Speaking(true)
  566. if err != nil {
  567. v.log(LogError, "error sending speaking packet, %s", err)
  568. }
  569. }
  570. // Add sequence and timestamp to udpPacket
  571. binary.BigEndian.PutUint16(udpHeader[2:], sequence)
  572. binary.BigEndian.PutUint32(udpHeader[4:], timestamp)
  573. // encrypt the opus data
  574. copy(nonce[:], udpHeader)
  575. v.RLock()
  576. sendbuf := secretbox.Seal(udpHeader, recvbuf, &nonce, &v.op4.SecretKey)
  577. v.RUnlock()
  578. // block here until we're exactly at the right time :)
  579. // Then send rtp audio packet to Discord over UDP
  580. select {
  581. case <-close:
  582. return
  583. case <-ticker.C:
  584. // continue
  585. }
  586. _, err := udpConn.Write(sendbuf)
  587. if err != nil {
  588. v.log(LogError, "udp write error, %s", err)
  589. v.log(LogDebug, "voice struct: %#v\n", v)
  590. return
  591. }
  592. if (sequence) == 0xFFFF {
  593. sequence = 0
  594. } else {
  595. sequence++
  596. }
  597. if (timestamp + uint32(size)) >= 0xFFFFFFFF {
  598. timestamp = 0
  599. } else {
  600. timestamp += uint32(size)
  601. }
  602. }
  603. }
  604. // A Packet contains the headers and content of a received voice packet.
  605. type Packet struct {
  606. SSRC uint32
  607. Sequence uint16
  608. Timestamp uint32
  609. Type []byte
  610. Opus []byte
  611. PCM []int16
  612. }
  613. // opusReceiver listens on the UDP socket for incoming packets
  614. // and sends them across the given channel
  615. // NOTE :: This function may change names later.
  616. func (v *VoiceConnection) opusReceiver(udpConn *net.UDPConn, close <-chan struct{}, c chan *Packet) {
  617. if udpConn == nil || close == nil {
  618. return
  619. }
  620. recvbuf := make([]byte, 1024)
  621. var nonce [24]byte
  622. for {
  623. rlen, err := udpConn.Read(recvbuf)
  624. if err != nil {
  625. // Detect if we have been closed manually. If a Close() has already
  626. // happened, the udp connection we are listening on will be different
  627. // to the current session.
  628. v.RLock()
  629. sameConnection := v.udpConn == udpConn
  630. v.RUnlock()
  631. if sameConnection {
  632. v.log(LogError, "udp read error, %s, %s", v.endpoint, err)
  633. v.log(LogDebug, "voice struct: %#v\n", v)
  634. go v.reconnect()
  635. }
  636. return
  637. }
  638. select {
  639. case <-close:
  640. return
  641. default:
  642. // continue loop
  643. }
  644. // For now, skip anything except audio.
  645. if rlen < 12 || (recvbuf[0] != 0x80 && recvbuf[0] != 0x90) {
  646. continue
  647. }
  648. // build a audio packet struct
  649. p := Packet{}
  650. p.Type = recvbuf[0:2]
  651. p.Sequence = binary.BigEndian.Uint16(recvbuf[2:4])
  652. p.Timestamp = binary.BigEndian.Uint32(recvbuf[4:8])
  653. p.SSRC = binary.BigEndian.Uint32(recvbuf[8:12])
  654. // decrypt opus data
  655. copy(nonce[:], recvbuf[0:12])
  656. p.Opus, _ = secretbox.Open(nil, recvbuf[12:rlen], &nonce, &v.op4.SecretKey)
  657. if len(p.Opus) > 8 && recvbuf[0] == 0x90 {
  658. // Extension bit is set, first 8 bytes is the extended header
  659. p.Opus = p.Opus[8:]
  660. }
  661. if c != nil {
  662. select {
  663. case c <- &p:
  664. case <-close:
  665. return
  666. }
  667. }
  668. }
  669. }
  670. // Reconnect will close down a voice connection then immediately try to
  671. // reconnect to that session.
  672. // NOTE : This func is messy and a WIP while I find what works.
  673. // It will be cleaned up once a proven stable option is flushed out.
  674. // aka: this is ugly shit code, please don't judge too harshly.
  675. func (v *VoiceConnection) reconnect() {
  676. v.log(LogInformational, "called")
  677. v.Lock()
  678. if v.reconnecting {
  679. v.log(LogInformational, "already reconnecting to channel %s, exiting", v.ChannelID)
  680. v.Unlock()
  681. return
  682. }
  683. v.reconnecting = true
  684. v.Unlock()
  685. defer func() { v.reconnecting = false }()
  686. // Close any currently open connections
  687. v.Close()
  688. wait := time.Duration(1)
  689. for {
  690. <-time.After(wait * time.Second)
  691. wait *= 2
  692. if wait > 600 {
  693. wait = 600
  694. }
  695. if v.session.DataReady == false || v.session.wsConn == nil {
  696. v.log(LogInformational, "cannot reconnect to channel %s with unready session", v.ChannelID)
  697. continue
  698. }
  699. v.log(LogInformational, "trying to reconnect to channel %s", v.ChannelID)
  700. _, err := v.session.ChannelVoiceJoin(v.GuildID, v.ChannelID, v.mute, v.deaf)
  701. if err == nil {
  702. v.log(LogInformational, "successfully reconnected to channel %s", v.ChannelID)
  703. return
  704. }
  705. v.log(LogInformational, "error reconnecting to channel %s, %s", v.ChannelID, err)
  706. // if the reconnect above didn't work lets just send a disconnect
  707. // packet to reset things.
  708. // Send a OP4 with a nil channel to disconnect
  709. data := voiceChannelJoinOp{4, voiceChannelJoinData{&v.GuildID, nil, true, true}}
  710. v.session.wsMutex.Lock()
  711. err = v.session.wsConn.WriteJSON(data)
  712. v.session.wsMutex.Unlock()
  713. if err != nil {
  714. v.log(LogError, "error sending disconnect packet, %s", err)
  715. }
  716. }
  717. }