1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-11-06 06:54:28 +00:00
arikawa/voice/op.go
2020-04-21 16:37:22 -06:00

111 lines
2.6 KiB
Go

package voice
import (
"fmt"
"github.com/diamondburned/arikawa/utils/json"
"github.com/diamondburned/arikawa/utils/wsutil"
"github.com/pkg/errors"
)
// OPCode represents a Discord Voice Gateway operation code.
type OPCode uint8
const (
IdentifyOP OPCode = 0 // send
SelectProtocolOP OPCode = 1 // send
ReadyOP OPCode = 2 // receive
HeartbeatOP OPCode = 3 // send
SessionDescriptionOP OPCode = 4 // receive
SpeakingOP OPCode = 5 // send/receive
HeartbeatAckOP OPCode = 6 // receive
ResumeOP OPCode = 7 // send
HelloOP OPCode = 8 // receive
ResumedOP OPCode = 9 // receive
// ClientDisconnectOP OPCode = 13 // receive
)
// OP represents a Discord Voice Gateway operation.
type OP struct {
Code OPCode `json:"op"`
Data json.Raw `json:"d,omitempty"`
}
func HandleEvent(c *Connection, ev wsutil.Event) error {
o, err := DecodeOP(c.Driver, ev)
if err != nil {
return err
}
return HandleOP(c, o)
}
func DecodeOP(driver json.Driver, ev wsutil.Event) (*OP, error) {
if ev.Error != nil {
return nil, ev.Error
}
if len(ev.Data) == 0 {
return nil, errors.New("Empty payload")
}
var op *OP
if err := driver.Unmarshal(ev.Data, &op); err != nil {
return nil, errors.Wrap(err, "OP error: "+string(ev.Data))
}
return op, nil
}
func HandleOP(c *Connection, op *OP) error {
switch op.Code {
// Gives information required to make a UDP connection
case ReadyOP:
if err := c.Driver.Unmarshal(op.Data, &c.ready); err != nil {
return errors.Wrap(err, "Failed to parse READY event")
}
if err := c.udpOpen(); err != nil {
return errors.Wrap(err, "Failed to open UDP connection")
}
if c.OpusSend == nil {
c.OpusSend = make(chan []byte)
}
go c.opusSendLoop()
// Gives information about the encryption mode and secret key for sending voice packets
case SessionDescriptionOP:
if err := c.Driver.Unmarshal(op.Data, &c.sessionDescription); err != nil {
c.ErrorLog(errors.Wrap(err, "Failed to parse SESSION_DESCRIPTION"))
}
// Someone started or stopped speaking.
case SpeakingOP:
// ?
return nil
// Heartbeat response from the server
case HeartbeatAckOP:
c.Pacemaker.Echo()
// Hello server, we hear you! :)
case HelloOP:
// Decode the data.
if err := c.Driver.Unmarshal(op.Data, &c.hello); err != nil {
c.ErrorLog(errors.Wrap(err, "Failed to parse SESSION_DESCRIPTION"))
}
return nil
// Server is saying the connection was resumed, no data here.
case ResumedOP:
WSDebug("Voice connection has been resumed")
default:
return fmt.Errorf("unknown OP code %d", op.Code)
}
return nil
}