Added opusSender func

This commit is contained in:
Bruce Marriner 2016-01-26 20:22:01 -06:00
parent 94b6199051
commit 4b1baec757

View file

@ -14,6 +14,7 @@ import (
"encoding/json"
"fmt"
"net"
"runtime"
"strings"
"sync"
"time"
@ -30,11 +31,13 @@ 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.
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
UDPConn *net.UDPConn // this will become unexported soon.
sessionID string
token string
@ -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
@ -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
}
@ -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)
}
}
}