Table of Contents

Class GuildConnection

Namespace
Nyra
Assembly
Nyra.dll

A player bound to a guild on a Node, playback, filters and Discord voice connection.

public sealed class GuildConnection
Inheritance
GuildConnection
Inherited Members

Properties

ChannelId

The voice channel id the bot is connected to, or null after the connection was disconnected.

public ulong? ChannelId { get; }

Property Value

ulong?

CurrentTrack

The track currently loaded, or null when nothing is playing.

public Track? CurrentTrack { get; }

Property Value

Track

Remarks

A server-side destroy by another actor (a co-client) only raises PlayerDestroyed, it does not clear this, the stale track lives on until the next play or a teardown resets it, and a later PlayAsync re-creates the player.

Effects

The fading, ducking, loudness and crossfade effects of the connection.

public GuildEffects Effects { get; }

Property Value

GuildEffects

Filters

The audio filters of the connection.

public GuildFilters Filters { get; }

Property Value

GuildFilters

GuildId

The guild the connection plays in.

public ulong GuildId { get; }

Property Value

ulong

IsConnected

Whether the bot is in a Discord voice channel on this connection, not the node websocket (see IsConnected).

public bool IsConnected { get; }

Property Value

bool

IsPaused

Whether playback is paused, as last confirmed by the server.

public bool IsPaused { get; }

Property Value

bool

Lyrics

The lyrics subscription of the connection.

public GuildLyrics Lyrics { get; }

Property Value

GuildLyrics

Mix

The mix layers of the connection.

public GuildMix Mix { get; }

Property Value

GuildMix

Node

The node this connection plays through.

public Node Node { get; }

Property Value

Node

Position

Estimated position, the last server report advanced by elapsed wall time while playing, scaled by the applied timescale until the next report lands.

public TimeSpan? Position { get; }

Property Value

TimeSpan?

Remarks

The sustained pace follows the raw reports, which differ per server kind. NodeLink reports already carry the timescale, Lavalink reports advance at wall time under one, so a timescale speed other than one leaves the Lavalink estimate at wall pace. Reports arrive on the server's player update interval.

Null before the first report and after a disconnect, freezes at the final position after a natural end.

SponsorBlock

The SponsorBlock settings of the connection.

public GuildSponsorBlock SponsorBlock { get; }

Property Value

GuildSponsorBlock

State

The last player state reported by the server, or null when none arrived yet.

public PlayerState? State { get; }

Property Value

PlayerState

VoiceEndpoint

Discord voice server endpoint captured at join, updated when Discord re-targets the voice server.

public string VoiceEndpoint { get; }

Property Value

string

VoiceSessionId

Discord voice session id captured at join, updated when Discord rotates it on a channel move.

public string VoiceSessionId { get; }

Property Value

string

VoiceToken

Discord voice token captured at join, updated when Discord re-targets the voice server.

public string VoiceToken { get; }

Property Value

string

Volume

The player volume (0-1000), as last confirmed by the server, 100 is the default. The server enforces the range, the read does not clamp.

public int Volume { get; }

Property Value

int

Methods

DisconnectAsync(CancellationToken)

Disconnects the bot from the voice channel and destroys the player on the server.

public Task DisconnectAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

A token to cancel the operation.

Returns

Task

A task that completes when the player was destroyed.

Remarks

A cancellation during the teardown leaves the connection marked as tearing down. The registry removal runs inside the destroy, so a cancellation before it leaves the connection registered, one after it leaves it removed but unwiped. Either way it accepts no operations until another disconnect completes the cleanup or a new connect takes the guild over.

The state wipe only runs when the destroy settled. The event pump retires with the teardown attempt either way, since a dying connection has no reader left for events.

A destroy the server failed is not swallowed and throws to the caller. The connection stays unwiped and accepts no operations until a retry or a takeover cleans it up.

A connect right after disconnecting a bot that was already out of voice can fail with a VoiceHandshakeException until VoiceHandshakeTimeout passes. The library ignores the guild's voice state updates while it waits for the leave echo, and none comes if the bot was not in voice.

Exceptions

RestException

The server refused the player destroy.

PauseAsync(CancellationToken)

Pauses playback.

public Task PauseAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

A token to cancel the operation.

Returns

Task

A task that completes when the player was paused.

Remarks

NodeLink rate-limits requests per guild and answers 429, which surfaces as an RestException with status 429. The limits are set on the server and cover any request for the guild. Lavalink applies no such limit.

PlayAsync(Track, PlayOptions?, CancellationToken)

Plays a track, replacing whatever plays unless NoReplace is set, falls back to StartPosition without an explicit start, consumed after the first accepted play.

public Task PlayAsync(Track track, PlayOptions? options = null, CancellationToken cancellationToken = default)

Parameters

track Track

The track to play.

options PlayOptions

How to start the track, null starts it plain.

cancellationToken CancellationToken

A token to cancel the operation.

Returns

Task

A task that completes when the server accepted the play.

Remarks

The consumption is best-effort on the echo, a play the server ignored (NodeLink drops a re-sent identical track) can consume the offset without a restart, the next accepted play then starts from zero.

Exceptions

NotSupportedException

AudioTrackId was given and the node is not NodeLink.

PlayIdentifierAsync(string, PlayOptions?, CancellationToken)

Plays a raw identifier and lets the server load it, search queries and playlists are rejected by both servers.

public Task<Track> PlayIdentifierAsync(string identifier, PlayOptions? options = null, CancellationToken cancellationToken = default)

Parameters

identifier string

What to load, a raw identifier (a source URL or a video id).

options PlayOptions

How to start the loaded track, null starts it plain.

cancellationToken CancellationToken

A token to cancel the operation.

Returns

Task<Track>

The loaded track, as the player reports it.

Remarks

Lavalink only.

Exceptions

NotSupportedException

The node is a NodeLink server.

RefreshAsync(CancellationToken)

Fetches the player as the server sees it, takes its state in and returns it, useful to re-sync after a resumed reconnect or an out-of-band change.

public Task<Player> RefreshAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

A token to cancel the operation.

Returns

Task<Player>

The fetched player, now the connection's state.

Remarks

After a session loss the player is gone, reconnect.

ResumeAsync(CancellationToken)

Resumes playback.

public Task ResumeAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

A token to cancel the operation.

Returns

Task

A task that completes when the player was resumed.

Remarks

NodeLink rate-limits requests per guild, see the remarks on PauseAsync(CancellationToken).

SeekAsync(TimeSpan, CancellationToken)

Seeks the current track to a position.

public Task SeekAsync(TimeSpan position, CancellationToken cancellationToken = default)

Parameters

position TimeSpan

Where to seek to.

cancellationToken CancellationToken

A token to cancel the operation.

Returns

Task

A task that completes when the seek was accepted.

Remarks

NodeLink rate-limits requests per guild, see the remarks on PauseAsync(CancellationToken).

SetEndTimeAsync(TimeSpan?, CancellationToken)

Moves the end time marker mid-track, honored by Lavalink, accepted but not applied by NodeLink, set it through EndTime there.

public Task SetEndTimeAsync(TimeSpan? endTime, CancellationToken cancellationToken = default)

Parameters

endTime TimeSpan?

The marker to stop the track at. On NodeLink a null value is sent as-is, on Lavalink it is a no-op (the marker stays armed, see remarks).

cancellationToken CancellationToken

A token to cancel the operation.

Returns

Task

A task that completes when the end time was updated.

Remarks

On Lavalink the marker fires and the end reports as a natural finish. A null endTime does not clear it, the server skips the marker block for a null value, play the track again without an end time to clear it.

On NodeLink an end time that travels with a play works on every source, but a marker moved mid-track only applies on the native seek paths (SABR sources like YouTube and the legacy path), plain http sources drop the value on the re-seek. A replay without an end time clears an applied marker, and the update is silently dropped while the position still reads zero (voice startup, the first second or so).

SetVolumeAsync(int, CancellationToken)

Sets the volume of the player.

public Task SetVolumeAsync(int volume, CancellationToken cancellationToken = default)

Parameters

volume int

The volume to set, 100 is the default.

cancellationToken CancellationToken

A token to cancel the operation.

Returns

Task

A task that completes when the volume was set.

Remarks

NodeLink rate-limits requests per guild, see the remarks on PauseAsync(CancellationToken).

StopAsync(CancellationToken)

Stops the player, clearing the current track.

public Task StopAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

A token to cancel the operation.

Returns

Task

A task that completes when the player was stopped.

ToString()

Returns the connection as its guild and node.

public override string ToString()

Returns

string

The guild and node of the connection.

Events

EternalBoxInfoUpdated

Raised when the node reports EternalBox context for the playing track, whenever the server signals the track start.

public event AsyncEventHandler<EternalBoxInfoUpdatedEventArgs>? EternalBoxInfoUpdated

Event Type

AsyncEventHandler<EternalBoxInfoUpdatedEventArgs>

Remarks

NodeLink only.

EternalBoxJumped

Raised when the EternalBox engine jumps to a different beat of the playing track.

public event AsyncEventHandler<EternalBoxJumpedEventArgs>? EternalBoxJumped

Event Type

AsyncEventHandler<EternalBoxJumpedEventArgs>

Remarks

NodeLink only.

FiltersChanged

Raised when the server's applied filter chain changed.

public event AsyncEventHandler<FiltersChangedEventArgs>? FiltersChanged

Event Type

AsyncEventHandler<FiltersChangedEventArgs>

Remarks

NodeLink only.

GuildConnectionInvalidated

Raised when this guild's player is gone for good, the node session could not be resumed, or a NodeLink cluster worker crashed and took the player with it.

public event AsyncEventHandler<GuildConnectionInvalidatedEventArgs>? GuildConnectionInvalidated

Event Type

AsyncEventHandler<GuildConnectionInvalidatedEventArgs>

HandlerError

Raised when a handler of one of the other events of this connection threw.

public event AsyncEventHandler<HandlerErrorEventArgs>? HandlerError

Event Type

AsyncEventHandler<HandlerErrorEventArgs>

LyricsFound

Raised when the node loaded the lyrics of the current track through a lyrics subscription.

public event AsyncEventHandler<LyricsFoundEventArgs>? LyricsFound

Event Type

AsyncEventHandler<LyricsFoundEventArgs>

LyricsLine

Raised for every lyrics line that becomes current during playback.

public event AsyncEventHandler<LyricsLineEventArgs>? LyricsLine

Event Type

AsyncEventHandler<LyricsLineEventArgs>

Remarks

Lines are skipped while the connection's event queue is more than 512 events behind (a stuck or slow handler).

LyricsNotFound

Raised when no timed lyrics were found for the track, no provider had any, or the provider returned text-only lyrics (LavaLyrics).

public event AsyncEventHandler<LyricsNotFoundEventArgs>? LyricsNotFound

Event Type

AsyncEventHandler<LyricsNotFoundEventArgs>

Remarks

NodeLink answers it only when nothing was found.

MixEnded

Raised when a mix layer ended.

public event AsyncEventHandler<MixEndedEventArgs>? MixEnded

Event Type

AsyncEventHandler<MixEndedEventArgs>

Remarks

NodeLink only. The FINISHED and MAIN_ENDED reasons only arrive when the server's mix auto-cleanup is enabled, a layer that plays through with it off ends through the mixer's teardown instead.

MixStarted

Raised when a mix started playing on top of the main track.

public event AsyncEventHandler<MixStartedEventArgs>? MixStarted

Event Type

AsyncEventHandler<MixStartedEventArgs>

Remarks

NodeLink only.

PauseChanged

Raised on both pausing and resuming, IsPaused tells them apart.

public event AsyncEventHandler<PauseChangedEventArgs>? PauseChanged

Event Type

AsyncEventHandler<PauseChangedEventArgs>

Remarks

NodeLink only.

PlayerConnected

The voice connection became established.

public event AsyncEventHandler<PlayerConnectedEventArgs>? PlayerConnected

Event Type

AsyncEventHandler<PlayerConnectedEventArgs>

Remarks

NodeLink only. The establishment of the join itself can dispatch before a handler can attach (the connect's roundtrip races the voice websocket), the reliable signal for the first join is the connect completing, reconnect cycles raise this while subscribed.

PlayerCreated

Raised when the server created the player.

public event AsyncEventHandler<PlayerCreatedEventArgs>? PlayerCreated

Event Type

AsyncEventHandler<PlayerCreatedEventArgs>

Remarks

NodeLink only. The creation this connection's own join caused races the return of the connect and usually fires before any handler can subscribe, so treat the connect's completion as the creation signal. This event only reports creations by other actors (a co-client, a re-creation after a resume).

PlayerDestroyed

Raised when the player was destroyed by an actor outside this client on the same session, not by this connection's own REST teardown (DisconnectAsync).

public event AsyncEventHandler<PlayerDestroyedEventArgs>? PlayerDestroyed

Event Type

AsyncEventHandler<PlayerDestroyedEventArgs>

Remarks

A destroy frame queued by a kick or pass can still drain through this connection, and a successor connection of the same guild can observe a stale frame of a predecessor's teardown. The destroy is a notification only, the connection's playback half (track, position estimate, filters) keeps its last state until the next play or a teardown resets it. NodeLink only.

PlayerReconnecting

The voice connection dropped and is being re-established.

public event AsyncEventHandler<PlayerReconnectingEventArgs>? PlayerReconnecting

Event Type

AsyncEventHandler<PlayerReconnectingEventArgs>

Remarks

NodeLink only. The server dispatches this per re-establishment attempt, one reconnect with an intermediate failure can carry more than one raise.

PlayerUpdated

Raised on every position report of the player.

public event AsyncEventHandler<PlayerUpdateEventArgs>? PlayerUpdated

Event Type

AsyncEventHandler<PlayerUpdateEventArgs>

Remarks

Reports are skipped while the connection's event queue is more than 512 events behind (a stuck or slow handler), the latest state is always available through State and Position.

SponsorBlockSegmentSkipped

Raised when the node skipped a SponsorBlock segment of the current track.

public event AsyncEventHandler<SponsorBlockSegmentSkippedEventArgs>? SponsorBlockSegmentSkipped

Event Type

AsyncEventHandler<SponsorBlockSegmentSkippedEventArgs>

Remarks

NodeLink only.

SponsorBlockSegmentsLoaded

Raised when the node loaded the SponsorBlock segments of the current track.

public event AsyncEventHandler<SponsorBlockSegmentsLoadedEventArgs>? SponsorBlockSegmentsLoaded

Event Type

AsyncEventHandler<SponsorBlockSegmentsLoadedEventArgs>

Remarks

NodeLink only.

StreamMetadataUpdated

A live stream announced new station metadata while playing.

public event AsyncEventHandler<StreamMetadataUpdatedEventArgs>? StreamMetadataUpdated

Event Type

AsyncEventHandler<StreamMetadataUpdatedEventArgs>

Remarks

NodeLink only.

TrackException

Raised when the server failed to load or play the current track.

public event AsyncEventHandler<TrackExceptionEventArgs>? TrackException

Event Type

AsyncEventHandler<TrackExceptionEventArgs>

TrackFinished

Raised when the current track ended, EndReason says why, a null Track (NodeLink) may report a reset of an earlier playthrough, see the remarks of that property.

public event AsyncEventHandler<TrackFinishedEventArgs>? TrackFinished

Event Type

AsyncEventHandler<TrackFinishedEventArgs>

TrackSought

Raised when the playback position of the current track was sought.

public event AsyncEventHandler<TrackSoughtEventArgs>? TrackSought

Event Type

AsyncEventHandler<TrackSoughtEventArgs>

Remarks

NodeLink only.

TrackStarted

Raised when the server started playing the current track.

public event AsyncEventHandler<TrackStartedEventArgs>? TrackStarted

Event Type

AsyncEventHandler<TrackStartedEventArgs>

TrackStuck

Raised when playback of the current track stalled long enough to exceed the node's threshold.

public event AsyncEventHandler<TrackStuckEventArgs>? TrackStuck

Event Type

AsyncEventHandler<TrackStuckEventArgs>

VolumeChanged

Raised when the player's volume changed.

public event AsyncEventHandler<VolumeChangedEventArgs>? VolumeChanged

Event Type

AsyncEventHandler<VolumeChangedEventArgs>

Remarks

NodeLink only.

WebSocketClosed

Raised when the node's Discord voice websocket for this guild was closed.

public event AsyncEventHandler<WebSocketClosedEventArgs>? WebSocketClosed

Event Type

AsyncEventHandler<WebSocketClosedEventArgs>

Remarks

For NodeLink this also reports synthetic voice deaths (worker failure, UDP/IP-discovery loss) that never closed a Discord websocket (see Code). NodeLink also emits deaths that never came from Discord wearing Discord codes, for example 4015 when its voice library gives up reconnecting and 4014 when the voice server endpoint is null. Do not attribute 4xxx to Discord on NodeLink without checking the reason.