A Player manages audio playback for a single Discord guild. Each guild has its own player instance that maintains state, handles tracks, and controls playback.
Creating Players
Players are automatically created when first accessed:
// Get/create player on best node
player := client.Player(guildID)
// Get/create player on specific node
player := client.PlayerOnNode(specificNode, guildID)
// Check if player exists without creating
if player := client.ExistingPlayer(guildID); player != nil {
// Player already exists
}
Player
func(snowflake.ID) Player
Get or create a player for the guild, automatically selecting the best node
PlayerOnNode
func(Node, snowflake.ID) Player
Get or create a player on a specific node
ExistingPlayer
func(snowflake.ID) Player
Get existing player without creating a new one (returns nil if not found)
Players are created per guild. Creating multiple players for the same guild returns the same instance.
Player State
Basic Properties
Get the guild ID this player belongs to
Get the current voice channel ID (nil if not connected)
Get the currently playing track (nil if nothing is playing)
Check if playback is paused
Get current volume (0-1000, default: 100)
Get currently applied audio filters
fmt.Printf("Guild: %d\n", player.GuildID())
fmt.Printf("Channel: %v\n", player.ChannelID())
fmt.Printf("Volume: %d%%\n", player.Volume())
fmt.Printf("Paused: %v\n", player.Paused())
if track := player.Track(); track != nil {
fmt.Printf("Playing: %s by %s\n", track.Info.Title, track.Info.Author)
}
Playback Position
Get current playback position in milliseconds (automatically calculated based on elapsed time)
State
func() lavalink.PlayerState
Get the full player state including timestamp, position, connection status, and ping
position := player.Position()
fmt.Printf("Position: %dms\n", position)
state := player.State()
fmt.Printf("Ping: %dms, Connected: %v\n", state.Ping, state.Connected)
Position() calculates the current position based on the last update time. It accounts for paused state and clamps the value between 0 and track length.
Updating Players
Update player state with the Update() method:
Update
func(context.Context, ...lavalink.PlayerUpdateOpt) error
Apply one or more updates to the player atomically
Playing Tracks
// Play a track
err := player.Update(ctx, lavalink.WithTrack(track))
// Play with position
err := player.Update(ctx,
lavalink.WithTrack(track),
lavalink.WithPosition(30000), // Start at 30s
)
// Stop playback
err := player.Update(ctx, lavalink.WithNullTrack())
WithTrack
func(Track) PlayerUpdateOpt
Set the track to play (automatically sets encoded track and user data)
WithEncodedTrack
func(string) PlayerUpdateOpt
Set track by encoded string
Stop playback by setting track to null
WithTrackIdentifier
func(string) PlayerUpdateOpt
Set track by identifier (alternative to encoded track)
WithTrackUserData
func(any) PlayerUpdateOpt
Attach custom user data to the track
Playback Control
// Pause/resume
err := player.Update(ctx, lavalink.WithPaused(true))
err := player.Update(ctx, lavalink.WithPaused(false))
// Set volume (0-1000)
err := player.Update(ctx, lavalink.WithVolume(75))
// Seek to position
err := player.Update(ctx, lavalink.WithPosition(60000)) // 60 seconds
// Set end time
err := player.Update(ctx, lavalink.WithEndTime(180000)) // End at 3 minutes
WithPaused
func(bool) PlayerUpdateOpt
Pause or resume playback
WithVolume
func(int) PlayerUpdateOpt
Set volume (0-1000, where 100 is default)
WithPosition
func(Duration) PlayerUpdateOpt
Seek to a specific position in milliseconds
WithEndTime
func(Duration) PlayerUpdateOpt
Set when the track should stop playing (in milliseconds from start)
Volume values above 100 may cause audio distortion. Maximum value is 1000 (10x amplification).
Audio Filters
// Apply filters
err := player.Update(ctx, lavalink.WithFilters(lavalink.Filters{
Volume: Ptr(1.0),
Equalizer: []lavalink.Equalizer{
{Band: 0, Gain: 0.2},
{Band: 1, Gain: 0.15},
},
}))
// Clear filters
err := player.Update(ctx, lavalink.WithFilters(lavalink.Filters{}))
WithFilters
func(Filters) PlayerUpdateOpt
Apply audio filters (equalizer, karaoke, timescale, tremolo, vibrato, rotation, distortion, channel mix, low pass)
Advanced Options
WithNoReplace
func(bool) PlayerUpdateOpt
If true, only updates if no track is currently playing (prevents replacing current track)
WithVoice
func(VoiceState) PlayerUpdateOpt
Manually set voice connection state (typically handled automatically)
// Only start track if nothing is playing
err := player.Update(ctx,
lavalink.WithTrack(track),
lavalink.WithNoReplace(true),
)
Combining Options
Multiple options can be applied in a single update:
err := player.Update(ctx,
lavalink.WithTrack(track),
lavalink.WithVolume(80),
lavalink.WithPosition(15000),
lavalink.WithPaused(false),
)
All options in a single Update() call are applied atomically to Lavalink.
Destroying Players
Clean up player resources:
Destroy
func(context.Context) error
Destroy the player on the Lavalink node and remove it from the client’s cache
err := player.Destroy(ctx)
if err != nil {
log.Printf("Failed to destroy player: %v", err)
}
Always call Destroy() when leaving a voice channel to free resources on the Lavalink server.
Voice State Management
Players automatically handle voice state when using Client.OnVoiceServerUpdate() and Client.OnVoiceStateUpdate(), but you can also call them directly:
OnVoiceServerUpdate
func(context.Context, string, string)
Handle VOICE_SERVER_UPDATE event (token, endpoint)
OnVoiceStateUpdate
func(context.Context, *snowflake.ID, string)
Handle VOICE_STATE_UPDATE event (channelID, sessionID)
// Typically forwarded through the client
client.OnVoiceServerUpdate(ctx, guildID, token, endpoint)
client.OnVoiceStateUpdate(ctx, guildID, channelID, sessionID)
// Or directly on the player
player.OnVoiceServerUpdate(ctx, token, endpoint)
player.OnVoiceStateUpdate(ctx, channelID, sessionID)
When channelID is nil in OnVoiceStateUpdate, the player automatically destroys itself.
Node Access
Get the node this player is connected to
Get the parent client instance
node := player.Node()
fmt.Printf("Player is on node: %s\n", node.Config().Name)
client := player.Lavalink()
Internal Methods
These methods are used internally by DisGoLink and typically don’t need to be called directly:
Restore player state from a Lavalink player object (used during session resuming)
Handle events from Lavalink (called internally)
OnPlayerUpdate
func(lavalink.PlayerState)
Update player state from PlayerUpdate messages (called internally)
Error Handling
Returned when trying to update or destroy a player that has no assigned node
err := player.Update(ctx, lavalink.WithVolume(100))
if errors.Is(err, disgolink.ErrPlayerNoNode) {
// Player has no node - possibly disconnected
}
Example: Complete Player Lifecycle
// Create player
player := client.Player(guildID)
// Load and play a track
result, err := node.LoadTracks(ctx, "ytsearch:rick astley never gonna give you up")
if err != nil {
return err
}
var track lavalink.Track
if search, ok := result.Data.(lavalink.Search); ok && len(search) > 0 {
track = search[0]
}
// Start playback
err = player.Update(ctx,
lavalink.WithTrack(track),
lavalink.WithVolume(80),
)
if err != nil {
return err
}
// Later: pause
err = player.Update(ctx, lavalink.WithPaused(true))
// Later: resume
err = player.Update(ctx, lavalink.WithPaused(false))
// When done: cleanup
err = player.Destroy(ctx)