github.com/diamondburned/arikawa@v1.3.14/voice/voicegateway/commands.go (about) 1 package voicegateway 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/diamondburned/arikawa/discord" 8 "github.com/pkg/errors" 9 ) 10 11 var ( 12 // ErrMissingForIdentify is an error when we are missing information to identify. 13 ErrMissingForIdentify = errors.New("missing GuildID, UserID, SessionID, or Token for identify") 14 15 // ErrMissingForResume is an error when we are missing information to resume. 16 ErrMissingForResume = errors.New("missing GuildID, SessionID, or Token for resuming") 17 ) 18 19 // OPCode 0 20 // https://discordapp.com/developers/docs/topics/voice-connections#establishing-a-voice-websocket-connection-example-voice-identify-payload 21 type IdentifyData struct { 22 GuildID discord.GuildID `json:"server_id"` // yes, this should be "server_id" 23 UserID discord.UserID `json:"user_id"` 24 SessionID string `json:"session_id"` 25 Token string `json:"token"` 26 } 27 28 // Identify sends an Identify operation (opcode 0) to the Gateway Gateway. 29 func (c *Gateway) Identify() error { 30 ctx, cancel := context.WithTimeout(context.Background(), c.Timeout) 31 defer cancel() 32 33 return c.IdentifyCtx(ctx) 34 } 35 36 // IdentifyCtx sends an Identify operation (opcode 0) to the Gateway Gateway. 37 func (c *Gateway) IdentifyCtx(ctx context.Context) error { 38 guildID := c.state.GuildID 39 userID := c.state.UserID 40 sessionID := c.state.SessionID 41 token := c.state.Token 42 43 if guildID == 0 || userID == 0 || sessionID == "" || token == "" { 44 return ErrMissingForIdentify 45 } 46 47 return c.SendCtx(ctx, IdentifyOP, IdentifyData{ 48 GuildID: guildID, 49 UserID: userID, 50 SessionID: sessionID, 51 Token: token, 52 }) 53 } 54 55 // OPCode 1 56 // https://discordapp.com/developers/docs/topics/voice-connections#establishing-a-voice-udp-connection-example-select-protocol-payload 57 type SelectProtocol struct { 58 Protocol string `json:"protocol"` 59 Data SelectProtocolData `json:"data"` 60 } 61 62 type SelectProtocolData struct { 63 Address string `json:"address"` 64 Port uint16 `json:"port"` 65 Mode string `json:"mode"` 66 } 67 68 // SelectProtocol sends a Select Protocol operation (opcode 1) to the Gateway Gateway. 69 func (c *Gateway) SelectProtocol(data SelectProtocol) error { 70 ctx, cancel := context.WithTimeout(context.Background(), c.Timeout) 71 defer cancel() 72 73 return c.SelectProtocolCtx(ctx, data) 74 } 75 76 // SelectProtocolCtx sends a Select Protocol operation (opcode 1) to the Gateway Gateway. 77 func (c *Gateway) SelectProtocolCtx(ctx context.Context, data SelectProtocol) error { 78 return c.SendCtx(ctx, SelectProtocolOP, data) 79 } 80 81 // OPCode 3 82 // https://discordapp.com/developers/docs/topics/voice-connections#heartbeating-example-heartbeat-payload 83 // type Heartbeat uint64 84 85 // Heartbeat sends a Heartbeat operation (opcode 3) to the Gateway Gateway. 86 func (c *Gateway) Heartbeat() error { 87 ctx, cancel := context.WithTimeout(context.Background(), c.Timeout) 88 defer cancel() 89 90 return c.HeartbeatCtx(ctx) 91 } 92 93 // HeartbeatCtx sends a Heartbeat operation (opcode 3) to the Gateway Gateway. 94 func (c *Gateway) HeartbeatCtx(ctx context.Context) error { 95 return c.SendCtx(ctx, HeartbeatOP, time.Now().UnixNano()) 96 } 97 98 // https://discordapp.com/developers/docs/topics/voice-connections#speaking 99 type SpeakingFlag uint64 100 101 const ( 102 Microphone SpeakingFlag = 1 << iota 103 Soundshare 104 Priority 105 ) 106 107 // OPCode 5 108 // https://discordapp.com/developers/docs/topics/voice-connections#speaking-example-speaking-payload 109 type SpeakingData struct { 110 Speaking SpeakingFlag `json:"speaking"` 111 Delay int `json:"delay"` 112 SSRC uint32 `json:"ssrc"` 113 } 114 115 // Speaking sends a Speaking operation (opcode 5) to the Gateway Gateway. 116 func (c *Gateway) Speaking(flag SpeakingFlag) error { 117 ctx, cancel := context.WithTimeout(context.Background(), c.Timeout) 118 defer cancel() 119 120 return c.SpeakingCtx(ctx, flag) 121 } 122 123 // SpeakingCtx sends a Speaking operation (opcode 5) to the Gateway Gateway. 124 func (c *Gateway) SpeakingCtx(ctx context.Context, flag SpeakingFlag) error { 125 // How do we allow a user to stop speaking? 126 // Also: https://discordapp.com/developers/docs/topics/voice-connections#voice-data-interpolation 127 128 return c.SendCtx(ctx, SpeakingOP, SpeakingData{ 129 Speaking: flag, 130 Delay: 0, 131 SSRC: c.ready.SSRC, 132 }) 133 } 134 135 // OPCode 7 136 // https://discordapp.com/developers/docs/topics/voice-connections#resuming-voice-connection-example-resume-connection-payload 137 type ResumeData struct { 138 GuildID discord.GuildID `json:"server_id"` // yes, this should be "server_id" 139 SessionID string `json:"session_id"` 140 Token string `json:"token"` 141 } 142 143 // Resume sends a Resume operation (opcode 7) to the Gateway Gateway. 144 func (c *Gateway) Resume() error { 145 ctx, cancel := context.WithTimeout(context.Background(), c.Timeout) 146 defer cancel() 147 return c.ResumeCtx(ctx) 148 } 149 150 // ResumeCtx sends a Resume operation (opcode 7) to the Gateway Gateway. 151 func (c *Gateway) ResumeCtx(ctx context.Context) error { 152 guildID := c.state.GuildID 153 sessionID := c.state.SessionID 154 token := c.state.Token 155 156 if !guildID.IsValid() || sessionID == "" || token == "" { 157 return ErrMissingForResume 158 } 159 160 return c.SendCtx(ctx, ResumeOP, ResumeData{ 161 GuildID: guildID, 162 SessionID: sessionID, 163 Token: token, 164 }) 165 }