internal async Task OnVoiceStateUpdated(DiscordVoiceState voiceState) { if (isValid) { this.voiceState = voiceState; if (!isConnected && !isConnecting && token != null && endPoint != null) { // Either the token or session ID can be received first, // so we must check if we are ready to start in both cases. await DoFullConnect(); } } }
/// <summary> /// Initiates this voice connection. /// <para> /// Note: An <see cref="OperationCanceledException"/> will be thrown if the Gateway /// connection is closed while initiating. /// </para> /// </summary> /// <param name="startMute">Whether the current bot should connect self-muted.</param> /// <param name="startDeaf">Whether the current bot should connect self-deafened.</param> /// <exception cref="DiscordPermissionException"> /// Thrown if the current bot does not have permission to connect to the voice channel. /// </exception> /// <exception cref="InvalidOperationException"> /// Thrown if connect is called more than once, /// if the voice channel is full and the current bot is not an admin, /// or if the shard behind this connection isn't running. /// </exception> /// <exception cref="OperationCanceledException"> /// Thrown if the give cancellation token is cancelled or the Gateway connection is closed while initiating the voice connection. /// </exception> public async Task ConnectAsync(Snowflake voiceChannelId, bool startMute = false, bool startDeaf = false, CancellationToken?cancellationToken = null) { if (isValid) { if (!isConnecting && !IsConnected) { // We need to guarantee that the shard user ID is available, // so double-check that the shard is running. if (!Shard.IsRunning) { throw new InvalidOperationException("Voice connection cannot be started while the parent shard is not running!"); } // Ensure the API user has permission to connect (this is to avoid the 10s timeout (if possible) otherwise). AssertUserCanJoin(guildId, voiceChannelId); // Set state voiceState = new DiscordVoiceState(guildId, Shard.UserId.Value, voiceChannelId); // Create the logger log = new DiscoreLogger($"VoiceConnection:{guildId}"); // Initiate the connection isConnecting = true; connectingCancellationSource = new CancellationTokenSource(); await gateway.SendVoiceStateUpdatePayload(guildId, voiceChannelId, startMute, startDeaf, cancellationToken ?? CancellationToken.None).ConfigureAwait(false); await ConnectionTimeout().ConfigureAwait(false); } else { throw new InvalidOperationException("Voice connection is already connecting or is currently connected."); } } }