/// <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));
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 11
0
        /// <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));
            }
        }
Ejemplo n.º 14
0
 /// <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;
 }
Ejemplo n.º 15
0
 /// <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.
 }
Ejemplo n.º 16
0
 public LavalinkPlayerEx(LavalinkSocket lavalinkSocket, IDiscordClientWrapper client, ulong guildId, bool disconnectOnStop) : base(lavalinkSocket, client, guildId, false)
 {
 }
Ejemplo n.º 17
0
 /// <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>();