Skip to content

Commit

Permalink
Added opusSender func
Browse files Browse the repository at this point in the history
  • Loading branch information
bwmarrin committed Jan 27, 2016
1 parent 94b6199 commit 4b1baec
Showing 1 changed file with 78 additions and 10 deletions.
88 changes: 78 additions & 10 deletions voice.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"encoding/json"
"fmt"
"net"
"runtime"
"strings"
"sync"
"time"
Expand All @@ -27,14 +28,16 @@ import (

// A Voice struct holds all data and functions related to Discord Voice support.
type Voice struct {
sync.Mutex // future use
Ready bool // If true, voice is ready to send/receive audio
Debug bool // If true, print extra logging
Chan chan struct{} // future use
UDPConn *net.UDPConn // exported for dgvoice, may change.
OP2 *voiceOP2 // exported for dgvoice, may change.
sync.Mutex // future use
Ready bool // If true, voice is ready to send/receive audio
Debug bool // If true, print extra logging
OP2 *voiceOP2 // exported for dgvoice, may change.
Opus chan []byte // Chan for sending opus audio
// FrameRate int // This can be used to set the FrameRate of Opus data
// FrameSize int // This can be used to set the FrameSize of Opus data

wsConn *websocket.Conn
wsConn *websocket.Conn
UDPConn *net.UDPConn // this will become unexported soon.

sessionID string
token string
Expand Down Expand Up @@ -174,9 +177,10 @@ func (v *Voice) wsEvent(messageType int, message []byte) {
return
}

// start udpKeepAlive
go v.udpKeepAlive(5 * time.Second)
// TODO: find a way to check that it fired off okay
// Start the opusSender.
// TODO: Should we allow 48000/960 values to be user defined?
v.Opus = make(chan []byte, 2)
go v.opusSender(v.Opus, 48000, 960)

return

Expand Down Expand Up @@ -347,6 +351,10 @@ func (v *Voice) udpOpen() (err error) {
return
}

// start udpKeepAlive
go v.udpKeepAlive(5 * time.Second)
// TODO: find a way to check that it fired off okay

v.Ready = true
return
}
Expand Down Expand Up @@ -375,3 +383,63 @@ func (v *Voice) udpKeepAlive(i time.Duration) {
<-ticker.C
}
}

// opusSender will listen on the given channel and send any
// pre-encoded opus audio to Discord. Supposedly.
func (v *Voice) opusSender(opus <-chan []byte, rate, size int) {

// TODO: Better checking to prevent this from running more than
// one instance at a time.
v.Lock()
if opus == nil {
v.Unlock()
return
}
v.Unlock()

runtime.LockOSThread()

var sequence uint16 = 0
var timestamp uint32 = 0
udpHeader := make([]byte, 12)

// build the parts that don't change in the udpHeader
udpHeader[0] = 0x80
udpHeader[1] = 0x78
binary.BigEndian.PutUint32(udpHeader[8:], v.OP2.SSRC)

// start a send loop that loops until buf chan is closed
ticker := time.NewTicker(time.Millisecond * time.Duration(size/(rate/1000)))
for {

// Add sequence and timestamp to udpPacket
binary.BigEndian.PutUint16(udpHeader[2:], sequence)
binary.BigEndian.PutUint32(udpHeader[4:], timestamp)

// Get data from chan. If chan is closed, return.
recvbuf, ok := <-opus
if !ok {
return
}

// Combine the UDP Header and the opus data
sendbuf := append(udpHeader, recvbuf...)

// block here until we're exactly at the right time :)
// Then send rtp audio packet to Discord over UDP
<-ticker.C
v.UDPConn.Write(sendbuf)

if (sequence) == 0xFFFF {
sequence = 0
} else {
sequence += 1
}

if (timestamp + uint32(size)) >= 0xFFFFFFFF {
timestamp = 0
} else {
timestamp += uint32(size)
}
}
}

0 comments on commit 4b1baec

Please sign in to comment.