discordjs / voice

Implementation of the Discord Voice API for discord.js and other JS/TS libraries
Apache License 2.0
328 stars 112 forks source link

fix: fixed type bundling for real #151

Closed favna closed 3 years ago

favna commented 3 years ago

Please describe the changes this PR makes and why it should be merged:

Heck did I know I had to call bundle.write() after creating the rollup bundle

I guess I should've read rollup docs more carefully, lol.

Click here to view the dist/index.d.ts after npm publish --dry-run! ```ts /// import { Readable, ReadableOptions } from 'stream'; import { VolumeTransformer, opus } from 'prism-media'; import { TypedEmitter } from 'tiny-typed-emitter'; import { GatewayVoiceServerUpdateDispatchData, GatewayVoiceStateUpdateDispatchData } from 'discord-api-types/v8'; import WebSocket, { MessageEvent } from 'ws'; declare type Awaited = T | Promise; /** * The different types of stream that can exist within the pipeline * * @remarks * - `Arbitrary` - the type of the stream at this point is unknown. * * - `Raw` - the stream at this point is s16le PCM. * * - `OggOpus` - the stream at this point is Opus audio encoded in an Ogg wrapper. * * - `WebmOpus` - the stream at this point is Opus audio encoded in a WebM wrapper. * * - `Opus` - the stream at this point is Opus audio, and the stream is in object-mode. This is ready to play. */ declare enum StreamType { Arbitrary = "arbitrary", Raw = "raw", OggOpus = "ogg/opus", WebmOpus = "webm/opus", Opus = "opus" } /** * The different types of transformers that can exist within the pipeline */ declare enum TransformerType { FFmpegPCM = "ffmpeg pcm", FFmpegOgg = "ffmpeg ogg", OpusEncoder = "opus encoder", OpusDecoder = "opus decoder", OggOpusDemuxer = "ogg/opus demuxer", WebmOpusDemuxer = "webm/opus demuxer", InlineVolume = "volume transformer" } /** * Represents a pathway from one stream type to another using a transformer */ interface Edge { from: Node; to: Node; cost: number; transformer: (input: string | Readable) => Readable; type: TransformerType; } /** * Represents a type of stream within the graph, e.g. an Opus stream, or a stream of raw audio. */ declare class Node { /** * The outbound edges from this node */ readonly edges: Edge[]; /** * The type of stream for this node */ readonly type: StreamType; constructor(type: StreamType); /** * Creates an outbound edge from this node * * @param edge - The edge to create */ addEdge(edge: Omit): void; } /** * Options that are set when creating a new audio resource. * * @template T - the type for the metadata (if any) of the audio resource. */ interface CreateAudioResourceOptions { /** * The type of the input stream. Defaults to `StreamType.Arbitrary`. */ inputType?: StreamType; /** * Optional metadata that can be attached to the resource (e.g. track title, random ID). * This is useful for identification purposes when the resource is passed around in events. * See {@link AudioResource.metadata} */ metadata?: T; /** * Whether or not inline volume should be enabled. If enabled, you will be able to change the volume * of the stream on-the-fly. However, this also increases the performance cost of playback. Defaults to `false`. */ inlineVolume?: boolean; /** * The number of silence frames to append to the end of the resource's audio stream, to prevent interpolation glitches. * Defaults to 5. */ silencePaddingFrames?: number; } /** * Represents an audio resource that can be played by an audio player. * * @template T - the type for the metadata (if any) of the audio resource. */ declare class AudioResource { /** * An object-mode Readable stream that emits Opus packets. This is what is played by audio players. */ readonly playStream: Readable; /** * The pipeline used to convert the input stream into a playable format. For example, this may * contain an FFmpeg component for arbitrary inputs, and it may contain a VolumeTransformer component * for resources with inline volume transformation enabled. */ readonly edges: readonly Edge[]; /** * Optional metadata that can be used to identify the resource. */ metadata: T; /** * If the resource was created with inline volume transformation enabled, then this will be a * prism-media VolumeTransformer. You can use this to alter the volume of the stream. */ readonly volume?: VolumeTransformer; /** * If using an Opus encoder to create this audio resource, then this will be a prism-media opus.Encoder. * You can use this to control settings such as bitrate, FEC, PLP. */ readonly encoder?: opus.Encoder; /** * The audio player that the resource is subscribed to, if any. */ audioPlayer?: AudioPlayer; /** * The playback duration of this audio resource, given in milliseconds. */ playbackDuration: number; /** * Whether or not the stream for this resource has started (data has become readable) */ started: boolean; /** * The number of silence frames to append to the end of the resource's audio stream, to prevent interpolation glitches. */ readonly silencePaddingFrames: number; /** * The number of remaining silence frames to play. If -1, the frames have not yet started playing. */ silenceRemaining: number; constructor(edges: readonly Edge[], streams: readonly Readable[], metadata: T, silencePaddingFrames: number); /** * Whether this resource is readable. If the underlying resource is no longer readable, this will still return true * while there are silence padding frames left to play. */ get readable(): boolean; /** * Whether this resource has ended or not. */ get ended(): boolean; /** * Attempts to read an Opus packet from the audio resource. If a packet is available, the playbackDuration * is incremented. * @internal * @remarks * It is advisable to check that the playStream is readable before calling this method. While no runtime * errors will be thrown, you should check that the resource is still available before attempting to * read from it. */ read(): Buffer | null; } declare function createAudioResource(input: string | Readable, options: CreateAudioResourceOptions & Pick : Required>, 'metadata'>): AudioResource; declare function createAudioResource(input: string | Readable, options?: Omit, 'metadata'>): AudioResource; /** * An error emitted by an AudioPlayer. Contains an attached resource to aid with * debugging and identifying where the error came from. */ declare class AudioPlayerError extends Error { /** * The resource associated with the audio player at the time the error was thrown. */ readonly resource: AudioResource; constructor(error: Error, resource: AudioResource); } /** * Represents a subscription of a voice connection to an audio player, allowing * the audio player to play audio on the voice connection. */ declare class PlayerSubscription { /** * The voice connection of this subscription */ readonly connection: VoiceConnection; /** * The audio player of this subscription */ readonly player: AudioPlayer; constructor(connection: VoiceConnection, player: AudioPlayer); /** * Unsubscribes the connection from the audio player, meaning that the * audio player cannot stream audio to it until a new subscription is made. */ unsubscribe(): void; } /** * Describes the behavior of the player when an audio packet is played but there are no available * voice connections to play to. */ declare enum NoSubscriberBehavior { /** * Pauses playing the stream until a voice connection becomes available */ Pause = "pause", /** * Continues to play through the resource regardless */ Play = "play", /** * The player stops and enters the Idle state */ Stop = "stop" } declare enum AudioPlayerStatus { /** * When there is currently no resource for the player to be playing */ Idle = "idle", /** * When the player is waiting for an audio resource to become readable before transitioning to Playing */ Buffering = "buffering", /** * When the player has been manually paused */ Paused = "paused", /** * When the player is actively playing an audio resource */ Playing = "playing", /** * When the player has paused itself. Only possible with the "pause" no subscriber behavior. */ AutoPaused = "autopaused" } /** * Options that can be passed when creating an audio player, used to specify its behavior. */ interface CreateAudioPlayerOptions { debug?: boolean; behaviors?: { noSubscriber?: NoSubscriberBehavior; maxMissedFrames?: number; }; } /** * The state that an AudioPlayer is in when it has no resource to play. This is the starting state. */ interface AudioPlayerIdleState { status: AudioPlayerStatus.Idle; } /** * The state that an AudioPlayer is in when it is waiting for a resource to become readable. Once this * happens, the AudioPlayer will enter the Playing state. If the resource ends/errors before this, then * it will re-enter the Idle state. */ interface AudioPlayerBufferingState { status: AudioPlayerStatus.Buffering; /** * The resource that the AudioPlayer is waiting for */ resource: AudioResource; onReadableCallback: () => void; onFailureCallback: () => void; onStreamError: (error: Error) => void; } /** * The state that an AudioPlayer is in when it is actively playing an AudioResource. When playback ends, * it will enter the Idle state. */ interface AudioPlayerPlayingState { status: AudioPlayerStatus.Playing; /** * The number of consecutive times that the audio resource has been unable to provide an Opus frame. */ missedFrames: number; /** * The playback duration in milliseconds of the current audio resource. This includes filler silence packets * that have been played when the resource was buffering. */ playbackDuration: number; /** * The resource that is being played */ resource: AudioResource; onStreamError: (error: Error) => void; } /** * The state that an AudioPlayer is in when it has either been explicitly paused by the user, or done * automatically by the AudioPlayer itself if there are no available subscribers. */ interface AudioPlayerPausedState { status: AudioPlayerStatus.Paused | AudioPlayerStatus.AutoPaused; /** * How many silence packets still need to be played to avoid audio interpolation due to the stream suddenly pausing */ silencePacketsRemaining: number; /** * The playback duration in milliseconds of the current audio resource. This includes filler silence packets * that have been played when the resource was buffering. */ playbackDuration: number; /** * The current resource of the audio player */ resource: AudioResource; onStreamError: (error: Error) => void; } /** * The various states that the player can be in. */ declare type AudioPlayerState = AudioPlayerIdleState | AudioPlayerBufferingState | AudioPlayerPlayingState | AudioPlayerPausedState; declare type AudioPlayerEvents = { error: (error: AudioPlayerError) => Awaited; debug: (message: string) => Awaited; stateChange: (oldState: AudioPlayerState, newState: AudioPlayerState) => Awaited; subscribe: (subscription: PlayerSubscription) => Awaited; unsubscribe: (subscription: PlayerSubscription) => Awaited; } & { [status in AudioPlayerStatus]: (oldState: AudioPlayerState, newState: AudioPlayerState & { status: status; }) => Awaited; }; /** * Used to play audio resources (i.e. tracks, streams) to voice connections. * * @remarks * Audio players are designed to be re-used - even if a resource has finished playing, the player itself * can still be used. * * The AudioPlayer drives the timing of playback, and therefore is unaffected by voice connections * becoming unavailable. Its behavior in these scenarios can be configured. */ declare class AudioPlayer extends TypedEmitter { /** * The state that the AudioPlayer is in */ private _state; /** * A list of VoiceConnections that are registered to this AudioPlayer. The player will attempt to play audio * to the streams in this list. */ private readonly subscribers; /** * The behavior that the player should follow when it enters certain situations. */ private readonly behaviors; /** * The debug logger function, if debugging is enabled. */ private readonly debug; /** * Creates a new AudioPlayer */ constructor(options?: CreateAudioPlayerOptions); /** * A list of subscribed voice connections that can currently receive audio to play */ get playable(): VoiceConnection[]; /** * Subscribes a VoiceConnection to the audio player's play list. If the VoiceConnection is already subscribed, * then the existing subscription is used. * * @remarks * This method should not be directly called. Instead, use VoiceConnection#subscribe. * * @param connection - The connection to subscribe * @returns The new subscription if the voice connection is not yet subscribed, otherwise the existing subscription. */ private subscribe; /** * Unsubscribes a subscription - i.e. removes a voice connection from the play list of the audio player. * * @remarks * This method should not be directly called. Instead, use PlayerSubscription#unsubscribe. * * @param subscription - The subscription to remove * @returns Whether or not the subscription existed on the player and was removed. */ private unsubscribe; /** * The state that the player is in. */ get state(): AudioPlayerState; /** * Sets a new state for the player, performing clean-up operations where necessary. */ set state(newState: AudioPlayerState); /** * Plays a new resource on the player. If the player is already playing a resource, the existing resource is destroyed * (it cannot be reused, even in another player) and is replaced with the new resource. * * @remarks * The player will transition to the Playing state once playback begins, and will return to the Idle state once * playback is ended. * * If the player was previously playing a resource and this method is called, the player will not transition to the * Idle state during the swap over. * * @param resource - The resource to play * @throws Will throw if attempting to play an audio resource that has already ended, or is being played by another player. */ play(resource: AudioResource): void; /** * Pauses playback of the current resource, if any. * * @param interpolateSilence - If true, the player will play 5 packets of silence after pausing to prevent audio glitches. * @returns true if the player was successfully paused, otherwise false. */ pause(interpolateSilence?: boolean): boolean; /** * Unpauses playback of the current resource, if any. * * @returns true if the player was successfully unpaused, otherwise false. */ unpause(): boolean; /** * Stops playback of the current resource and destroys the resource. The player will either transition to the Idle state, * or remain in its current state until the silence padding frames of the resource have been played. * * @param force - If true, will force the player to enter the Idle state even if the resource has silence padding frames. * @returns true if the player will come to a stop, otherwise false. */ stop(force?: boolean): boolean; /** * Checks whether the underlying resource (if any) is playable (readable). * * @returns true if the resource is playable, false otherwise. */ checkPlayable(): boolean; /** * Called roughly every 20ms by the global audio player timer. Dispatches any audio packets that are buffered * by the active connections of this audio player. */ private _stepDispatch; /** * Called roughly every 20ms by the global audio player timer. Attempts to read an audio packet from the * underlying resource of the stream, and then has all the active connections of the audio player prepare it * (encrypt it, append header data) so that it is ready to play at the start of the next cycle. */ private _stepPrepare; /** * Signals to all the subscribed connections that they should send a packet to Discord indicating * they are no longer speaking. Called once playback of a resource ends. */ private _signalStopSpeaking; /** * Instructs the given connections to each prepare this packet to be played at the start of the * next cycle. * * @param packet - The Opus packet to be prepared by each receiver * @param receivers - The connections that should play this packet */ private _preparePacket; } /** * Creates a new AudioPlayer to be used */ declare function createAudioPlayer(options?: CreateAudioPlayerOptions): AudioPlayer; interface JoinConfig { guildId: string; channelId: string | null; selfDeaf: boolean; selfMute: boolean; } declare function getVoiceConnection(guildId: string): VoiceConnection | undefined; /** * Methods that are provided by the @discordjs/voice library to implementations of * Discord gateway DiscordGatewayAdapters. */ interface DiscordGatewayAdapterLibraryMethods { /** * Call this when you receive a VOICE_SERVER_UPDATE payload that is relevant to the adapter. * * @param data - The inner data of the VOICE_SERVER_UPDATE payload */ onVoiceServerUpdate(data: GatewayVoiceServerUpdateDispatchData): void; /** * Call this when you receive a VOICE_STATE_UPDATE payload that is relevant to the adapter. * * @param data - The inner data of the VOICE_STATE_UPDATE payload */ onVoiceStateUpdate(data: GatewayVoiceStateUpdateDispatchData): void; /** * Call this when the adapter can no longer be used (e.g. due to a disconnect from the main gateway) */ destroy(): void; } /** * Methods that are provided by the implementer of a Discord gateway DiscordGatewayAdapter. */ interface DiscordGatewayAdapterImplementerMethods { /** * Implement this method such that the given payload is sent to the main Discord gateway connection. * * @param payload - The payload to send to the main Discord gateway connection * @returns false if the payload definitely failed to send - in this case, the voice connection disconnects. */ sendPayload(payload: any): boolean; /** * This will be called by @discordjs/voice when the adapter can safely be destroyed as it will no * longer be used. */ destroy(): void; } /** * A function used to build adapters. It accepts a methods parameter that contains functions that * can be called by the implementer when new data is received on its gateway connection. In return, * the implementer will return some methods that the library can call - e.g. to send messages on * the gateway, or to signal that the adapter can be removed. */ declare type DiscordGatewayAdapterCreator = (methods: DiscordGatewayAdapterLibraryMethods) => DiscordGatewayAdapterImplementerMethods; /** * Stores an IP address and port. Used to store socket details for the local client as well as * for Discord. */ interface SocketConfig { ip: string; port: number; } interface VoiceUDPSocketEvents { error: (error: Error) => Awaited; close: () => Awaited; debug: (message: string) => Awaited; message: (message: Buffer) => Awaited; } /** * Manages the UDP networking for a voice connection. */ declare class VoiceUDPSocket extends TypedEmitter { /** * The underlying network Socket for the VoiceUDPSocket. */ private readonly socket; /** * The socket details for Discord (remote). */ private readonly remote; /** * A list of keep alives that are waiting to be acknowledged. */ private readonly keepAlives; /** * The counter used in the keep alive mechanism */ private keepAliveCounter; /** * The buffer used to write the keep alive counter into */ private readonly keepAliveBuffer; /** * The Node.js interval for the keep-alive mechanism */ private readonly keepAliveInterval; /** * The time taken to receive a response to keep alive messages */ ping?: number; /** * The debug logger function, if debugging is enabled. */ private readonly debug; /** * Creates a new VoiceUDPSocket. * * @param remote - Details of the remote socket */ constructor(remote: SocketConfig, debug?: boolean); /** * Called when a message is received on the UDP socket * @param buffer The received buffer */ private onMessage; /** * Called at a regular interval to check whether we are still able to send datagrams to Discord */ private keepAlive; /** * Sends a buffer to Discord. * * @param buffer - The buffer to send */ send(buffer: Buffer): void; /** * Closes the socket, the instance will not be able to be reused. */ destroy(): void; /** * Performs IP discovery to discover the local address and port to be used for the voice connection. * * @param ssrc - The SSRC received from Discord */ performIPDiscovery(ssrc: number): Promise; } /** * Debug event for VoiceWebSocket. * * @event VoiceWebSocket#debug * @type {string} */ interface VoiceWebSocketEvents { error: (error: Error) => Awaited; open: (event: WebSocket.OpenEvent) => Awaited; close: (event: WebSocket.CloseEvent) => Awaited; debug: (message: string) => Awaited; packet: (packet: any) => Awaited; } /** * An extension of the WebSocket class to provide helper functionality when interacting * with the Discord Voice gateway. */ declare class VoiceWebSocket extends TypedEmitter { /** * The current heartbeat interval, if any */ private heartbeatInterval?; /** * The time (milliseconds since UNIX epoch) that the last heartbeat acknowledgement packet was received. * This is set to 0 if an acknowledgement packet hasn't been received yet. */ private lastHeartbeatAck; /** * The time (milliseconds since UNIX epoch) that the last heartbeat was sent. This is set to 0 if a heartbeat * hasn't been sent yet. */ private lastHeatbeatSend; /** * The number of consecutively missed heartbeats. */ private missedHeartbeats; /** * The last recorded ping. */ ping?: number; /** * The debug logger function, if debugging is enabled. */ private readonly debug; /** * The underlying WebSocket of this wrapper */ private readonly ws; /** * Creates a new VoiceWebSocket * * @param address - The address to connect to */ constructor(address: string, debug: boolean); /** * Destroys the VoiceWebSocket. The heartbeat interval is cleared, and the connection is closed. */ destroy(): void; /** * Handles message events on the WebSocket. Attempts to JSON parse the messages and emit them * as packets. * * @param event - The message event */ onMessage(event: MessageEvent): void; /** * Sends a JSON-stringifiable packet over the WebSocket * * @param packet - The packet to send */ sendPacket(packet: any): void; /** * Sends a heartbeat over the WebSocket */ private sendHeartbeat; /** * Sets/clears an interval to send heartbeats over the WebSocket * * @param ms - The interval in milliseconds. If negative, the interval will be unset. */ setHeartbeatInterval(ms: number): void; } /** * The different statuses that a networking instance can hold. The order * of the states between OpeningWs and Ready is chronological (first the * instance enters OpeningWs, then it enters Identifying etc.) */ declare enum NetworkingStatusCode { OpeningWs = 0, Identifying = 1, UdpHandshaking = 2, SelectingProtocol = 3, Ready = 4, Resuming = 5, Closed = 6 } /** * The initial Networking state. Instances will be in this state when a WebSocket connection to a Discord * voice gateway is being opened. */ interface NetworkingOpeningWsState { code: NetworkingStatusCode.OpeningWs; ws: VoiceWebSocket; connectionOptions: ConnectionOptions; } /** * The state that a Networking instance will be in when it is attempting to authorize itself. */ interface NetworkingIdentifyingState { code: NetworkingStatusCode.Identifying; ws: VoiceWebSocket; connectionOptions: ConnectionOptions; } /** * The state that a Networking instance will be in when opening a UDP connection to the IP and port provided * by Discord, as well as performing IP discovery. */ interface NetworkingUdpHandshakingState { code: NetworkingStatusCode.UdpHandshaking; ws: VoiceWebSocket; udp: VoiceUDPSocket; connectionOptions: ConnectionOptions; connectionData: Pick; } /** * The state that a Networking instance will be in when selecting an encryption protocol for audio packets. */ interface NetworkingSelectingProtocolState { code: NetworkingStatusCode.SelectingProtocol; ws: VoiceWebSocket; udp: VoiceUDPSocket; connectionOptions: ConnectionOptions; connectionData: Pick; } /** * The state that a Networking instance will be in when it has a fully established connection to a Discord * voice server. */ interface NetworkingReadyState { code: NetworkingStatusCode.Ready; ws: VoiceWebSocket; udp: VoiceUDPSocket; connectionOptions: ConnectionOptions; connectionData: ConnectionData; preparedPacket?: Buffer; } /** * The state that a Networking instance will be in when its connection has been dropped unexpectedly, and it * is attempting to resume an existing session. */ interface NetworkingResumingState { code: NetworkingStatusCode.Resuming; ws: VoiceWebSocket; udp: VoiceUDPSocket; connectionOptions: ConnectionOptions; connectionData: ConnectionData; preparedPacket?: Buffer; } /** * The state that a Networking instance will be in when it has been destroyed. It cannot be recovered from this * state. */ interface NetworkingClosedState { code: NetworkingStatusCode.Closed; } /** * The various states that a networking instance can be in. */ declare type NetworkingState = NetworkingOpeningWsState | NetworkingIdentifyingState | NetworkingUdpHandshakingState | NetworkingSelectingProtocolState | NetworkingReadyState | NetworkingResumingState | NetworkingClosedState; /** * Details required to connect to the Discord voice gateway. These details * are first received on the main bot gateway, in the form of VOICE_SERVER_UPDATE * and VOICE_STATE_UPDATE packets. */ interface ConnectionOptions { serverID: string; userID: string; sessionID: string; token: string; endpoint: string; } /** * Information about the current connection, e.g. which encryption mode is to be used on * the connection, timing information for playback of streams. */ interface ConnectionData { ssrc: number; encryptionMode: string; secretKey: Uint8Array; sequence: number; timestamp: number; packetsPlayed: number; nonce: number; nonceBuffer: Buffer; speaking: boolean; } interface NetworkingEvents { debug: (message: string) => Awaited; error: (error: Error) => Awaited; stateChange: (oldState: NetworkingState, newState: NetworkingState) => Awaited; close: (code: number) => Awaited; } /** * Manages the networking required to maintain a voice connection and dispatch audio packets */ declare class Networking extends TypedEmitter { private _state; /** * The debug logger function, if debugging is enabled. */ private readonly debug; /** * Creates a new Networking instance. */ constructor(options: ConnectionOptions, debug: boolean); /** * Destroys the Networking instance, transitioning it into the Closed state. */ destroy(): void; /** * The current state of the networking instance. */ get state(): NetworkingState; /** * Sets a new state for the networking instance, performing clean-up operations where necessary. */ set state(newState: NetworkingState); /** * Creates a new WebSocket to a Discord Voice gateway. * * @param endpoint - The endpoint to connect to * @param debug - Whether to enable debug logging */ private createWebSocket; /** * Propagates errors from the children VoiceWebSocket and VoiceUDPSocket. * * @param error - The error that was emitted by a child */ private onChildError; /** * Called when the WebSocket opens. Depending on the state that the instance is in, * it will either identify with a new session, or it will attempt to resume an existing session. */ private onWsOpen; /** * Called when the WebSocket closes. Based on the reason for closing (given by the code parameter), * the instance will either attempt to resume, or enter the closed state and emit a 'close' event * with the close code, allowing the user to decide whether or not they would like to reconnect. * * @param code - The close code */ private onWsClose; /** * Called when the UDP socket has closed itself if it has stopped receiving replies from Discord */ private onUdpClose; /** * Called when a packet is received on the connection's WebSocket * @param packet - The received packet */ private onWsPacket; /** * Propagates debug messages from the child WebSocket. * * @param message - The emitted debug message */ private onWsDebug; /** * Propagates debug messages from the child UDPSocket. * * @param message - The emitted debug message */ private onUdpDebug; /** * Prepares an Opus packet for playback. This includes attaching metadata to it and encrypting it. * It will be stored within the instance, and can be played by dispatchAudio(). * * @remarks * Calling this method while there is already a prepared audio packet that has not yet been dispatched * will overwrite the existing audio packet. This should be avoided. * * @param opusPacket - The Opus packet to encrypt * * @returns The audio packet that was prepared. */ prepareAudioPacket(opusPacket: Buffer): Buffer | undefined; /** * Dispatches the audio packet previously prepared by prepareAudioPacket(opusPacket). The audio packet * is consumed and cannot be dispatched again. */ dispatchAudio(): boolean; /** * Plays an audio packet, updating timing metadata used for playback. * * @param audioPacket - The audio packet to play */ private playAudioPacket; /** * Sends a packet to the voice gateway indicating that the client has start/stopped sending * audio. * * @param speaking - Whether or not the client should be shown as speaking */ setSpeaking(speaking: boolean): void; /** * Creates a new audio packet from an Opus packet. This involves encrypting the packet, * then prepending a header that includes metadata. * * @param opusPacket - The Opus packet to prepare * @param connectionData - The current connection data of the instance */ private createAudioPacket; /** * Encrypts an Opus packet using the format agreed upon by the instance and Discord. * * @param opusPacket - The Opus packet to encrypt * @param connectionData - The current connection data of the instance */ private encryptOpusPacket; } /** * The various status codes a voice connection can hold at any one time. */ declare enum VoiceConnectionStatus { /** * Sending a packet to the main Discord gateway to indicate we want to change our voice state. */ Signalling = "signalling", /** * The `VOICE_SERVER_UPDATE` and `VOICE_STATE_UPDATE` packets have been received, now attempting to establish a voice connection. */ Connecting = "connecting", /** * A voice connection has been established, and is ready to be used */ Ready = "ready", /** * The voice connection has either been severed or not established. */ Disconnected = "disconnected", /** * The voice connection has been destroyed and untracked, it cannot be reused. */ Destroyed = "destroyed" } /** * The state that a VoiceConnection will be in when it is waiting to receive a VOICE_SERVER_UPDATE and * VOICE_STATE_UPDATE packet from Discord, provided by the adapter. */ interface VoiceConnectionSignallingState { status: VoiceConnectionStatus.Signalling; subscription?: PlayerSubscription; adapter: DiscordGatewayAdapterImplementerMethods; } /** * The reasons a voice connection can be in the disconnected state. */ declare enum VoiceConnectionDisconnectReason { /** * When the WebSocket connection has been closed. */ WebSocketClose = 0, /** * When the adapter was unable to send a message requested by the VoiceConnection. */ AdapterUnavailable = 1, /** * When a VOICE_SERVER_UPDATE packet is received with a null endpoint, causing the connection to be severed. */ EndpointRemoved = 2, /** * When a manual disconnect was requested. */ Manual = 3 } /** * The state that a VoiceConnection will be in when it is not connected to a Discord voice server nor is * it attempting to connect. You can manually attempt to reconnect using VoiceConnection#reconnect. */ interface VoiceConnectionDisconnectedBaseState { status: VoiceConnectionStatus.Disconnected; subscription?: PlayerSubscription; adapter: DiscordGatewayAdapterImplementerMethods; } /** * The state that a VoiceConnection will be in when it is not connected to a Discord voice server nor is * it attempting to connect. You can manually attempt to reconnect using VoiceConnection#reconnect. */ interface VoiceConnectionDisconnectedOtherState extends VoiceConnectionDisconnectedBaseState { reason: Exclude; } /** * The state that a VoiceConnection will be in when its WebSocket connection was closed. * You can manually attempt to reconnect using VoiceConnection#reconnect. */ interface VoiceConnectionDisconnectedWebSocketState extends VoiceConnectionDisconnectedBaseState { reason: VoiceConnectionDisconnectReason.WebSocketClose; /** * The close code of the WebSocket connection to the Discord voice server. */ closeCode: number; } /** * The states that a VoiceConnection can be in when it is not connected to a Discord voice server nor is * it attempting to connect. You can manually attempt to connect using VoiceConnection#reconnect. */ declare type VoiceConnectionDisconnectedState = VoiceConnectionDisconnectedOtherState | VoiceConnectionDisconnectedWebSocketState; /** * The state that a VoiceConnection will be in when it is establishing a connection to a Discord * voice server. */ interface VoiceConnectionConnectingState { status: VoiceConnectionStatus.Connecting; networking: Networking; subscription?: PlayerSubscription; adapter: DiscordGatewayAdapterImplementerMethods; } /** * The state that a VoiceConnection will be in when it has an active connection to a Discord * voice server. */ interface VoiceConnectionReadyState { status: VoiceConnectionStatus.Ready; networking: Networking; subscription?: PlayerSubscription; adapter: DiscordGatewayAdapterImplementerMethods; } /** * The state that a VoiceConnection will be in when it has been permanently been destroyed by the * user and untracked by the library. It cannot be reconnected, instead, a new VoiceConnection * needs to be established. */ interface VoiceConnectionDestroyedState { status: VoiceConnectionStatus.Destroyed; } /** * The various states that a voice connection can be in. */ declare type VoiceConnectionState = VoiceConnectionSignallingState | VoiceConnectionDisconnectedState | VoiceConnectionConnectingState | VoiceConnectionReadyState | VoiceConnectionDestroyedState; declare type VoiceConnectionEvents = { error: (error: Error) => Awaited; debug: (message: string) => Awaited; stateChange: (oldState: VoiceConnectionState, newState: VoiceConnectionState) => Awaited; } & { [status in VoiceConnectionStatus]: (oldState: VoiceConnectionState, newState: VoiceConnectionState & { status: status; }) => Awaited; }; /** * A connection to the voice server of a Guild, can be used to play audio in voice channels. */ declare class VoiceConnection extends TypedEmitter { /** * The number of consecutive rejoin attempts. Initially 0, and increments for each rejoin. * When a connection is successfully established, it resets to 0. */ rejoinAttempts: number; /** * The state of the voice connection */ private _state; /** * A configuration storing all the data needed to reconnect to a Guild's voice server. * @internal */ readonly joinConfig: JoinConfig; /** * The two packets needed to successfully establish a voice connection. They are received * from the main Discord gateway after signalling to change the voice state. */ private readonly packets; /** * The debug logger function, if debugging is enabled. */ private readonly debug; /** * Creates a new voice connection. * * @param joinConfig - The data required to establish the voice connection * @param options - The options used to create this voice connection */ constructor(joinConfig: JoinConfig, { debug, adapterCreator }: CreateVoiceConnectionOptions); /** * The current state of the voice connection */ get state(): VoiceConnectionState; /** * Updates the state of the voice connection, performing clean-up operations where necessary. */ set state(newState: VoiceConnectionState); /** * Registers a `VOICE_SERVER_UPDATE` packet to the voice connection. This will cause it to reconnect using the * new data provided in the packet. * * @param packet - The received `VOICE_SERVER_UPDATE` packet */ private addServerPacket; /** * Registers a `VOICE_STATE_UPDATE` packet to the voice connection. Most importantly, it stores the ID of the * channel that the client is connected to. * * @param packet - The received `VOICE_STATE_UPDATE` packet */ private addStatePacket; /** * Attempts to configure a networking instance for this voice connection using the received packets. * Both packets are required, and any existing networking instance will be destroyed. * * @remarks * This is called when the voice server of the connection changes, e.g. if the bot is moved into a * different channel in the same guild but has a different voice server. In this instance, the connection * needs to be re-established to the new voice server. * * The connection will transition to the Connecting state when this is called. */ configureNetworking(): void; /** * Called when the networking instance for this connection closes. If the close code is 4014 (do not reconnect), * the voice connection will transition to the Disconnected state which will store the close code. You can * decide whether or not to reconnect when this occurs by listening for the state change and calling reconnect(). * * @remarks * If the close code was anything other than 4014, it is likely that the closing was not intended, and so the * VoiceConnection will signal to Discord that it would like to rejoin the channel. This automatically attempts * to re-establish the connection. This would be seen as a transition from the Ready state to the Signalling state. * * @param code - The close code */ private onNetworkingClose; /** * Called when the state of the networking instance changes. This is used to derive the state of the voice connection. * * @param oldState - The previous state * @param newState - The new state */ private onNetworkingStateChange; /** * Propagates errors from the underlying network instance. * * @param error - The error to propagate */ private onNetworkingError; /** * Propagates debug messages from the underlying network instance. * * @param message - The debug message to propagate */ private onNetworkingDebug; /** * Prepares an audio packet for dispatch * * @param buffer - The Opus packet to prepare */ prepareAudioPacket(buffer: Buffer): Buffer | undefined; /** * Dispatches the previously prepared audio packet (if any) */ dispatchAudio(): boolean | undefined; /** * Prepares an audio packet and dispatches it immediately * * @param buffer - The Opus packet to play */ playOpusPacket(buffer: Buffer): boolean | undefined; /** * Destroys the VoiceConnection, preventing it from connecting to voice again. * This method should be called when you no longer require the VoiceConnection to * prevent memory leaks. * @param adapterAvailable - Whether the adapter can be used */ destroy(adapterAvailable?: boolean): void; /** * Disconnects the VoiceConnection, allowing the possibility of rejoining later on. * @returns - true if the connection was successfully disconnected. */ disconnect(): boolean; /** * Attempts to rejoin (better explanation soon:tm:) * * @remarks * Calling this method successfully will automatically increment the `rejoinAttempts` counter, * which you can use to inform whether or not you'd like to keep attempting to reconnect your * voice connection. * * A state transition from Disconnected to Signalling will be observed when this is called. */ rejoin(joinConfig?: Omit): boolean; /** * Updates the speaking status of the voice connection. This is used when audio players are done playing audio, * and need to signal that the connection is no longer playing audio. * * @param enabled - Whether or not to show as speaking */ setSpeaking(enabled: boolean): false | undefined; /** * Subscribes to an audio player, allowing the player to play audio on this voice connection. * * @param player - The audio player to subscribe to * @returns The created subscription */ subscribe(player: AudioPlayer): PlayerSubscription | undefined; /** * The latest ping (in milliseconds) for the WebSocket connection and audio playback for this voice * connection, if this data is available. * * @remarks * For this data to be available, the VoiceConnection must be in the Ready state, and its underlying * WebSocket connection and UDP socket must have had at least one ping-pong exchange. */ get ping(): { ws: number | undefined; udp: number | undefined; }; /** * Called when a subscription of this voice connection to an audio player is removed. * * @param subscription - The removed subscription */ private onSubscriptionRemoved; } /** * The options that can be given when creating a voice connection. */ interface CreateVoiceConnectionOptions { /** * If true, debug messages will be enabled for the voice connection and its * related components. Defaults to false. */ debug?: boolean; adapterCreator: DiscordGatewayAdapterCreator; } /** * The options that can be given when joining a voice channel. */ interface JoinVoiceChannelOptions { /** * The ID of the Discord voice channel to join */ channelId: string; /** * The ID of the guild that the voice channel belongs to */ guildId: string; /** * Whether to join the channel deafened (defaults to true) */ selfDeaf?: boolean; /** * Whether to join the channel muted (defaults to true) */ selfMute?: boolean; } /** * Creates a VoiceConnection to a Discord voice channel. * * @param voiceChannel - the voice channel to connect to * @param options - the options for joining the voice channel */ declare function joinVoiceChannel(options: JoinVoiceChannelOptions & CreateVoiceConnectionOptions): VoiceConnection; /** * Generates a report of the dependencies used by the \@discordjs/voice module. * Useful for debugging. */ declare function generateDependencyReport(): string; /** * Allows a voice connection a specified amount of time to enter a given state, otherwise rejects with an error. * * @param target - The voice connection that we want to observe the state change for * @param status - The status that the voice connection should be in * @param maxTime - The maximum time we are allowing for this to occur */ declare function entersState(target: VoiceConnection, status: VoiceConnectionStatus, maxTime: number): Promise; /** * Allows an audio player a specified amount of time to enter a given state, otherwise rejects with an error. * * @param target - The audio player that we want to observe the state change for * @param status - The status that the audio player should be in * @param maxTime - The maximum time we are allowing for this to occur */ declare function entersState(target: AudioPlayer, status: AudioPlayerStatus, maxTime: number): Promise; /** * Takes an Opus Head, and verifies whether the associated Opus audio is suitable to play in a Discord voice channel. * @param opusHead The Opus Head to validate * @returns true if suitable to play in a Discord voice channel, false otherwise */ declare function validateDiscordOpusHead(opusHead: Buffer): boolean; /** * The resulting information after probing an audio stream */ interface ProbeInfo { /** * The readable audio stream to use. You should use this rather than the input stream, as the probing * function can sometimes read the input stream to its end and cause the stream to close. */ stream: Readable; /** * The recommended stream type for this audio stream */ type: StreamType; } /** * Attempt to probe a readable stream to figure out whether it can be demuxed using an Ogg or WebM Opus demuxer. * @param stream The readable stream to probe * @param probeSize The number of bytes to attempt to read before giving up on the probe * @param validator The Opus Head validator function * @experimental */ declare function demuxProbe(stream: Readable, probeSize?: number, validator?: typeof validateDiscordOpusHead): Promise; /** * A readable stream of Opus packets received from a specific entity * in a Discord voice connection. */ declare class AudioReceiveStream extends Readable { constructor(options?: ReadableOptions); _read(): void; } /** * The known data for a user in a Discord voice connection */ interface VoiceUserData { /** * The SSRC of the user's audio stream */ audioSSRC: number; /** * The SSRC of the user's video stream (if one exists). * Cannot be 0. If undefined, the user has no video stream. */ videoSSRC?: number; /** * The Discord user ID of the user */ userId: string; } /** * The events that an SSRCMap may emit. */ interface SSRCMapEvents { update: (oldData: VoiceUserData | undefined, newData: VoiceUserData) => Awaited; delete: (deletedData: VoiceUserData) => Awaited; } /** * Maps audio SSRCs to data of users in voice connections. */ declare class SSRCMap extends TypedEmitter { /** * The underlying map */ private readonly map; constructor(); /** * Updates the map with new user data * * @param data The data to update with */ update(data: VoiceUserData): void; /** * Gets the stored voice data of a user. * * @param target The target, either their user ID or audio SSRC */ get(target: number | string): VoiceUserData | undefined; /** * Deletes the stored voice data about a user. * * @param target The target of the delete operation, either their audio SSRC or user ID * @returns The data that was deleted, if any */ delete(target: number | string): VoiceUserData | undefined; } /** * Attaches to a VoiceConnection, allowing you to receive audio packets from other * users that are speaking. * * @beta */ declare class VoiceReceiver { /** * The attached connection of this receiver. */ readonly voiceConnection: VoiceConnection; /** * Maps SSRCs to Discord user IDs. */ readonly ssrcMap: SSRCMap; /** * The current audio subscriptions of this receiver. */ readonly subscriptions: Map; /** * The connection information for this receiver. Used to decrypt incoming packets. */ private connectionData; constructor(voiceConnection: VoiceConnection); /** * Called when a packet is received on the attached connection's WebSocket. * * @param packet The received packet */ private onWsPacket; private decrypt; /** * Parses an audio packet, decrypting it to yield an Opus packet. * * @param buffer The buffer to parse * @param mode The encryption mode * @param nonce The nonce buffer used by the connection for encryption * @param secretKey The secret key used by the connection for encryption * @returns The parsed Opus packet */ private parsePacket; /** * Called when the UDP socket of the attached connection receives a message. * * @param msg The received message */ private onUdpMessage; /** * Creates a subscription for the given target, specified either by their SSRC or user ID. * * @param target The audio SSRC or user ID to subscribe to * @returns A readable stream of Opus packets received from the target */ subscribe(target: string | number): AudioReceiveStream; } /** * Creates a new voice receiver for the given voice connection. * * @param voiceConnection The voice connection to attach to * @beta * @remarks * Voice receive is an undocumented part of the Discord API - voice receive is not guaranteed * to be stable and may break without notice. */ declare function createVoiceReceiver(voiceConnection: VoiceConnection): VoiceReceiver; export { AudioPlayer, AudioPlayerBufferingState, AudioPlayerError, AudioPlayerEvents, AudioPlayerIdleState, AudioPlayerPausedState, AudioPlayerPlayingState, AudioPlayerState, AudioPlayerStatus, AudioReceiveStream, AudioResource, CreateAudioPlayerOptions, CreateVoiceConnectionOptions, DiscordGatewayAdapterCreator, DiscordGatewayAdapterImplementerMethods, DiscordGatewayAdapterLibraryMethods, JoinVoiceChannelOptions, NoSubscriberBehavior, PlayerSubscription, ProbeInfo, SSRCMap, SSRCMapEvents, StreamType, VoiceConnection, VoiceConnectionConnectingState, VoiceConnectionDestroyedState, VoiceConnectionDisconnectReason, VoiceConnectionDisconnectedBaseState, VoiceConnectionDisconnectedOtherState, VoiceConnectionDisconnectedState, VoiceConnectionDisconnectedWebSocketState, VoiceConnectionEvents, VoiceConnectionReadyState, VoiceConnectionSignallingState, VoiceConnectionState, VoiceConnectionStatus, VoiceReceiver, VoiceUserData, createAudioPlayer, createAudioResource, createVoiceReceiver, demuxProbe, entersState, generateDependencyReport, getVoiceConnection, joinVoiceChannel, validateDiscordOpusHead }; ```

Status and versioning classification:

codecov[bot] commented 3 years ago

Codecov Report

Merging #151 (06f04d7) into main (43c32b9) will not change coverage. The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #151   +/-   ##
=======================================
  Coverage   67.74%   67.74%           
=======================================
  Files          19       19           
  Lines         896      896           
  Branches      220      220           
=======================================
  Hits          607      607           
  Misses        287      287           
  Partials        2        2           

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update 43c32b9...06f04d7. Read the comment docs.