1
0
Fork 0
mirror of https://github.com/diamondburned/arikawa.git synced 2024-11-27 09:12:53 +00:00
arikawa/voice
diamondburned 54cadd2f45 gateway: Refactor for a better concurrent API
This commit refactors the whole package gateway as well as utils/ws
(formerly utils/wsutil) and voice/voicegateway. The new refactor
utilizes a design pattern involving a concurrent loop and an arriving
event channel.

An additional change was made to the way gateway events are typed.
Before, pretty much any type will satisfy a gateway event type, since
the actual type was just interface{}. The new refactor defines a
concrete interface that events can implement:

    type Event interface {
        Op() OpCode
        EventType() EventType
    }

Using this interface, the user can easily add custom gateway events
independently of the library without relying on string maps. This adds a
lot of type safety into the library and makes type-switching on Event
types much more reasonable.

Gateway error callbacks are also almost entirely removed in favor of
custom gateway events. A catch-all can easily be added like this:

    s.AddHandler(func(err error) {
        log.Println("gateway error:, err")
    })
2021-12-14 13:49:34 -08:00
..
testdata Voice: Added an integration test 2020-04-23 20:52:12 -07:00
udp gateway: Refactor for a better concurrent API 2021-12-14 13:49:34 -08:00
voicegateway gateway: Refactor for a better concurrent API 2021-12-14 13:49:34 -08:00
README.md *: Linting and typo fixes (#134) 2020-07-29 16:58:33 -07:00
session.go gateway: Refactor for a better concurrent API 2021-12-14 13:49:34 -08:00
session_example_test.go gateway: Refactor for a better concurrent API 2021-12-14 13:49:34 -08:00
session_test.go gateway: Refactor for a better concurrent API 2021-12-14 13:49:34 -08:00
voice.go gateway: Refactor for a better concurrent API 2021-12-14 13:49:34 -08:00

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.