arikawa/voice
diamondburned f5ae68c781
voice: Refactor and fix up
This commit refactors a lot of voice's internals to be more stable and
handle more edge cases from Discord's voice servers. It should result in
an overall more stable voice connection.

A few helper functions have been added into voice.Session. Some fields
will have been broken and changed to accomodate for the refactor, as
well.

Below are some commits that have been squashed in:

    voice: Fix Speaking() panic on closed
    voice: StopSpeaking should not error out
        The rationale is added as a comment into the Speaking() method.
    voice: Add TestKickedOut
    voice: Fix region change disconnecting
2022-01-18 21:31:46 -08:00
..
testdata voice: Refactor and fix up 2022-01-18 21:31:46 -08:00
udp voice: Refactor and fix up 2022-01-18 21:31:46 -08:00
voicegateway voice: Refactor and fix up 2022-01-18 21:31:46 -08:00
README.md *: Linting and typo fixes (#134) 2020-07-29 16:58:33 -07:00
session.go voice: Refactor and fix up 2022-01-18 21:31:46 -08:00
session_example_test.go voice: Refactor and fix up 2022-01-18 21:31:46 -08:00
session_test.go voice: Refactor and fix up 2022-01-18 21:31:46 -08:00
voice.go voice: Refactor and fix up 2022-01-18 21:31:46 -08:00

README.md

Voice

Terminology

  • Discord Gateway - The standard Discord Gateway users connect to and receive update events from
  • Discord Voice Gateway - The Discord Voice gateway that allows voice connections to be configured
  • Voice Server - What the Discord Voice Gateway allows connection to for sending of Opus voice packets over UDP
  • Voice Packet - Opus encoded UDP packet that contains audio
  • Application - Could be a custom Discord Client or Bot (nothing that is within this package)
  • Library - Code within this package

Connection Flow

  • The application would get a new *Voice instance by calling NewVoice()
  • When the application wants to connect to a voice channel they would call JoinChannel() on the stored *Voice instance

  • The library sends a Voice State Update to the Discord Gateway.
  • The library waits until it receives a Voice Server Update from the Discord Gateway.
  • Once a Voice Server Update event is received, a new connection is opened to the Discord Voice Gateway.

  • The Discord Voice Gateway will first send a Hello Event which will be used to create a new *heart.PacemakerLoop and start sending heartbeats to the Discord Voice Gateway.
  • Afterwards, an Identify Command or Resume Command is sent to the Discord Voice Gateway depending on whether the library is reconnecting.

  • The Discord Voice Gateway should then respond with a Ready Event once the connection is opened, providing the required information to connect to a Voice Server.
  • Using the information provided in the Ready Event, a new UDP connection is opened to the Voice Server and IP Discovery occurs.
  • After IP Discovery returns the Application's external ip and port it connected to the Voice Server with, the library sends a Select Protocol Event to the Discord Voice Gateway.
  • The library waits until it receives a Session Description Event from the Discord Voice Gateway.
  • Once the Session Description Event is received, Speaking Events and Voice Packets can begin to be sent to the Discord Voice Gateway and Voice Server respectively.

Usage

  • The application would get a new *Voice instance by calling NewVoice() and keep it stored for when it needs to open voice connections.
  • When the application wants to connect to a voice channel they would call JoinChannel() on the stored *Voice instance.
  • JoinChannel() will block as it follows the Connection Flow, returning an error if one occurs and a *voice.Session if it was successful.
  • The application should now call (*voice.Session).Speaking() with the wanted voice flag (voicegateway.Microphone, voicegateway.Soundshare, or voicegateway.Priority).
  • The application can now send Voice Packets using the (*voice.Session).Write() method which will be sent to the Voice Server. (*voice.Session) also implements io.Writer.
  • When the application wants to stop sending Voice Packets they should call (*voice.Session).StopSpeaking(), then any required voice cleanup (closing streams, etc.), then (*voice.Session).Disconnect()

Examples

Check the integration tests at voice/integration_test.go.