mirror of
https://github.com/diamondburned/arikawa.git
synced 2024-11-06 06:54:28 +00:00
111 lines
2.6 KiB
Go
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
|
|
}
|