/// <summary> /// Updates the player volume asynchronously. /// </summary> /// <param name="volume">the player volume (0f - 10f)</param> /// <param name="normalize"> /// a value indicating whether if the <paramref name="volume"/> is out of range (0f - /// 10f) it should be normalized in its range. For example 11f will be mapped to 10f and /// -20f to 0f. /// </param> /// <returns>a task that represents the asynchronous operation</returns> /// <exception cref="InvalidOperationException"> /// thrown if the player is not connected to a voice channel /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// thrown if the specified <paramref name="volume"/> is out of range (0f - 10f) /// </exception> /// <exception cref="InvalidOperationException">thrown if the player is destroyed</exception> public virtual async Task SetVolumeAsync(float volume = 1f, bool normalize = false) { EnsureNotDestroyed(); EnsureConnected(); if (volume > 10f || volume < 0f) { if (!normalize) { throw new ArgumentOutOfRangeException(nameof(volume), volume, "Volume is out of range (0f - 10f)"); } // bring the values into range (0f - 10f) volume = Math.Max(0f, volume); volume = Math.Min(10f, volume); } // check if the volume is already the same as wanted if (Volume == volume) { return; } var payload = new PlayerVolumePayload(GuildId, (int)(volume * 100)); await LavalinkSocket.SendPayloadAsync(payload); Volume = volume; }
/// <summary> /// Destroys the player asynchronously. /// </summary> /// <returns>a task that represents the asynchronous operation</returns> public async Task DestroyAsync() { EnsureNotDestroyed(); // destroy player State = PlayerState.Destroyed; // send destroy payload await LavalinkSocket.SendPayloadAsync(new PlayerDestroyPayload(GuildId)); }
/// <summary> /// Initializes a new instance of the <see cref="LavalinkPlayer"/> class. /// </summary> /// <param name="lavalinkSocket">the lavalink socket</param> /// <param name="client">the discord client</param> /// <param name="guildId">the identifier of the guild that is controlled by the player</param> /// <param name="disconnectOnStop"> /// a value indicating whether the player should stop after the track finished playing /// </param> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="lavalinkSocket"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="client"/> is <see langword="null"/>. /// </exception> public LavalinkPlayer(LavalinkSocket lavalinkSocket, IDiscordClientWrapper client, ulong guildId, bool disconnectOnStop) { GuildId = guildId; LavalinkSocket = lavalinkSocket ?? throw new ArgumentNullException(nameof(lavalinkSocket)); Client = client ?? throw new ArgumentNullException(nameof(client)); _disconnectOnStop = disconnectOnStop; _lastPositionUpdate = DateTimeOffset.UtcNow; _position = TimeSpan.Zero; }
/// <summary> /// Updates the player equalizer asynchronously. /// </summary> /// <param name="bands">the bands</param> /// <param name="reset"> /// a value indicating whether the equalizer bands should be overridden ( <see /// langword="false"/>) or replaced ( <see langword="true"/>). /// </param> /// <returns>a task that represents the asynchronous operation</returns> /// <exception cref="InvalidOperationException">thrown if the player is destroyed</exception> public virtual Task UpdateEqualizerAsync(IEnumerable <EqualizerBand> bands, bool reset = true) { EnsureNotDestroyed(); if (reset) { bands = bands.Union(DefaultEqualizer, new EqualizerBandComparer()); } return(LavalinkSocket.SendPayloadAsync(new PlayerEqualizerPayload(GuildId, bands.ToArray()))); }
/// <summary> /// Stops playing the current track asynchronously. /// </summary> /// <param name="disconnect"> /// a value indicating whether the connection to the voice server should be closed /// </param> /// <returns>a task that represents the asynchronous operation</returns> /// <exception cref="InvalidOperationException"> /// thrown if the player is not connected to a voice channel /// </exception> /// <exception cref="InvalidOperationException">thrown if the player is destroyed</exception> public virtual async Task StopAsync(bool disconnect = false) { EnsureNotDestroyed(); EnsureConnected(); await LavalinkSocket.SendPayloadAsync(new PlayerStopPayload(GuildId)); if (disconnect) { await DisconnectAsync(PlayerDisconnectCause.Stop); } }
/// <summary> /// Seeks the current playing track asynchronously. /// </summary> /// <returns>a task that represents the asynchronous operation</returns> /// <exception cref="InvalidOperationException"> /// thrown if the player is not connected to a voice channel /// </exception> /// <exception cref="NotSupportedException"> /// thrown if the current playing track does not support seeking. /// </exception> /// <exception cref="InvalidOperationException">thrown if the player is destroyed</exception> public virtual Task SeekPositionAsync(TimeSpan position) { EnsureNotDestroyed(); EnsureConnected(); if (State != PlayerState.Paused && State != PlayerState.Playing) { throw new InvalidOperationException("There is no track paused or playing."); } return(LavalinkSocket.SendPayloadAsync(new PlayerSeekPayload(GuildId, position))); }
/// <summary> /// Plays the specified <paramref name="track"/> asynchronously. /// </summary> /// <param name="track">the track to play</param> /// <param name="startTime">the track start position</param> /// <param name="endTime">the track end position</param> /// <param name="noReplace"> /// a value indicating whether the track play should be ignored if the same track is /// currently playing /// </param> /// <returns>a task that represents the asynchronous operation</returns> /// <exception cref="InvalidOperationException"> /// thrown if the player is not connected to a voice channel /// </exception> /// <exception cref="InvalidOperationException">thrown if the player is destroyed</exception> public virtual async Task PlayAsync(LavalinkTrack track, TimeSpan?startTime = null, TimeSpan?endTime = null, bool noReplace = false) { EnsureNotDestroyed(); EnsureConnected(); CurrentTrack = track ?? throw new ArgumentNullException(nameof(track)); startTime = startTime ?? track.Position; await LavalinkSocket.SendPayloadAsync(new PlayerPlayPayload(GuildId, track.Identifier, startTime, endTime, noReplace)); State = PlayerState.Playing; }
/// <summary> /// Pauses the current playing track asynchronously. /// </summary> /// <returns>a task that represents the asynchronous operation</returns> /// <exception cref="InvalidOperationException"> /// thrown if the current playing track is already paused. /// </exception> /// <exception cref="InvalidOperationException"> /// thrown if the player is not connected to a voice channel /// </exception> /// <exception cref="InvalidOperationException">thrown if the player is destroyed</exception> public virtual async Task PauseAsync() { EnsureNotDestroyed(); EnsureConnected(); if (State != PlayerState.Playing) { throw new InvalidOperationException("The current playing track is not playing."); } await LavalinkSocket.SendPayloadAsync(new PlayerPausePayload(GuildId, true)); State = PlayerState.Paused; }
/// <summary> /// Resumes the current playing track asynchronously. /// </summary> /// <returns>a task that represents the asynchronous operation</returns> /// <exception cref="InvalidOperationException"> /// thrown if the player is not connected to a voice channel /// </exception> /// <exception cref="InvalidOperationException"> /// thrown if the current playing track is not paused /// </exception> /// <exception cref="InvalidOperationException">thrown if the player is destroyed</exception> public virtual async Task ResumeAsync() { EnsureNotDestroyed(); EnsureConnected(); if (State != PlayerState.Paused) { throw new InvalidOperationException("There is no track paused."); } await LavalinkSocket.SendPayloadAsync(new PlayerPausePayload(GuildId, false)); State = PlayerState.Playing; }
/// <summary> /// Initializes a new instance of a player. /// </summary> /// <param name="playerFactory">the player factory</param> /// <param name="socket">the lavalink socket</param> /// <param name="client">the discord client</param> /// <param name="guildId">the identifier of the guild that is controlled by the player</param> /// <param name="disconnectOnStop"> /// a value indicating whether the player should stop after the track finished playing /// </param> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="playerFactory"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="socket"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="client"/> is <see langword="null"/>. /// </exception> internal static T CreatePlayer <T>( PlayerFactory <T> playerFactory, LavalinkSocket socket, IDiscordClientWrapper client, ulong guildId, bool disconnectOnStop) where T : LavalinkPlayer { if (playerFactory is null) { throw new ArgumentNullException(nameof(playerFactory)); } var player = playerFactory(); player.LavalinkSocket = socket ?? throw new ArgumentNullException(nameof(socket)); player.Client = client ?? throw new ArgumentNullException(nameof(client)); player.GuildId = guildId; player.DisconnectOnStop = disconnectOnStop; return(player); }
/// <summary> /// Updates the player equalizer asynchronously. /// </summary> /// <param name="bands">the bands</param> /// <param name="reset"> /// a value indicating whether the equalizer bands should be overridden ( <see /// langword="false"/>) or replaced ( <see langword="true"/>). /// </param> /// <param name="force"> /// a value indicating whether to send the update regardless of whether the current /// equalizer bands ( <see cref="Bands"/>) are configured the same as the specified /// <paramref name="bands"/>. /// </param> /// <returns>a task that represents the asynchronous operation</returns> /// <exception cref="InvalidOperationException">thrown if the player is destroyed</exception> public virtual Task UpdateEqualizerAsync(IEnumerable <EqualizerBand> bands, bool reset = true, bool force = false) { EnsureNotDestroyed(); if (reset) { bands = bands.Union(DefaultEqualizer, EqualizerBandComparer.Instance); } if (!force && Bands.SequenceEqual(bands, EqualizerBandComparer.Instance)) { // equalizer bands are the same return(Task.CompletedTask); } Bands = bands.ToArray(); var payload = new PlayerEqualizerPayload(GuildId, Bands); return(LavalinkSocket.SendPayloadAsync(payload)); }
/// <summary> /// Sends the voice state and server data to the Lavalink Node if both is provided. /// </summary> /// <returns>a task that represents the asynchronous operation</returns> internal async Task UpdateAsync() { if (_voiceServer is null || _voiceState is null) { // voice state or server is missing return; } // send voice update payload await LavalinkSocket.SendPayloadAsync(new VoiceUpdatePayload(_voiceState.GuildId, _voiceState.VoiceSessionId, new VoiceServerUpdateEvent(_voiceServer))); if (State == PlayerState.NotConnected || State == PlayerState.Destroyed) { // set initial player state to connected, if player was not connected or destroyed, // see: https://github.com/angelobreuer/Lavalink4NET/issues/28 State = PlayerState.NotPlaying; } // trigger event await OnConnectedAsync(_voiceServer, _voiceState); }
/// <summary> /// Disconnects the player asynchronously. /// </summary> /// <returns>a task that represents the asynchronous operation</returns> internal async Task DisconnectAsync(PlayerDisconnectCause disconnectCause) { if (State == PlayerState.NotConnected) { return; } // keep old channel in memory var channel = VoiceChannelId; // disconnect from channel await Client.SendVoiceUpdateAsync(GuildId, null); VoiceChannelId = null; State = PlayerState.NotConnected; // only trigger event if disconnected from a channel if (channel.HasValue) { // notify disconnect await LavalinkSocket.NotifyDisconnectAsync( new PlayerDisconnectedEventArgs(this, channel.Value, disconnectCause)); } }
/// <summary> /// Initializes a new instance of the <see cref="QueuedLavalinkPlayer"/> class. /// </summary> /// <param name="lavalinkSocket">the lavalink socket</param> /// <param name="client">the discord client</param> /// <param name="guildId">the identifier of the guild that is controlled by the player</param> /// <param name="disconnectOnStop"> /// a value indicating whether the player should stop after the track finished playing /// </param> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="lavalinkSocket"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="client"/> is <see langword="null"/>. /// </exception> public QueuedLavalinkPlayer(LavalinkSocket lavalinkSocket, IDiscordClientWrapper client, ulong guildId, bool disconnectOnStop) : base(lavalinkSocket, client, guildId, false /* this player handles this on itself */) { Queue = new LavalinkQueue(); _disconnectOnStop = disconnectOnStop; }
/// <summary> /// Initializes a new instance of the <see cref="LavalinkPlayer"/> class. /// </summary> /// <param name="lavalinkSocket">the lavalink socket</param> /// <param name="client">the discord client</param> /// <param name="guildId">the identifier of the guild that is controlled by the player</param> public MyCustomPlayer(LavalinkSocket lavalinkSocket, IDiscordClientWrapper client, ulong guildId) : base(lavalinkSocket, client, guildId) { // This constructor pattern must be always used for a custom player. You can not add nor // remove any constructor parameters. The player class will be instantiated using System.Activator. }
public LavalinkPlayerEx(LavalinkSocket lavalinkSocket, IDiscordClientWrapper client, ulong guildId, bool disconnectOnStop) : base(lavalinkSocket, client, guildId, false) { }
/// <summary> /// Initializes a new instance of the <see cref="VoteLavalinkPlayer"/> class. /// </summary> /// <param name="lavalinkSocket">the lavalink socket</param> /// <param name="client">the discord client</param> /// <param name="guildId">the identifier of the guild that is controlled by the player</param> /// <param name="disconnectOnStop"> /// a value indicating whether the player should stop after the track finished playing /// </param> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="lavalinkSocket"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="client"/> is <see langword="null"/>. /// </exception> public VoteLavalinkPlayer(LavalinkSocket lavalinkSocket, IDiscordClientWrapper client, ulong guildId, bool disconnectOnStop) : base(lavalinkSocket, client, guildId, disconnectOnStop) => _skipVotes = new List <ulong>();