From 58025d303f0bb91e6122465e770db7902ce65ed9 Mon Sep 17 00:00:00 2001 From: Khionu Date: Mon, 11 Apr 2016 22:08:59 -0400 Subject: [PATCH] Removed hack; code now assumes client is logged in as Bot Account, without 1 voice channel limit --- src/Discord.Net.Audio/AudioClient.cs | 91 ++++------------- src/Discord.Net.Audio/AudioService.cs | 183 ++++++++++------------------------ 2 files changed, 73 insertions(+), 201 deletions(-) diff --git a/src/Discord.Net.Audio/AudioClient.cs b/src/Discord.Net.Audio/AudioClient.cs index 8fab4bd9f..ed5d4fed5 100644 --- a/src/Discord.Net.Audio/AudioClient.cs +++ b/src/Discord.Net.Audio/AudioClient.cs @@ -1,5 +1,4 @@ using Discord.API.Client.GatewaySocket; -using Discord.API.Client.Rest; using Discord.Logging; using Discord.Net.Rest; using Discord.Net.WebSockets; @@ -13,7 +12,7 @@ using System.Threading.Tasks; namespace Discord.Audio { - internal class AudioClient : IAudioClient + internal class AudioClient : IAudioClient { private class OutStream : Stream { @@ -50,7 +49,7 @@ namespace Discord.Audio private ConnectionState _gatewayState; internal Logger Logger { get; } - + public int Id { get; } public AudioService Service { get; } public AudioServiceConfig Config { get; } @@ -59,7 +58,7 @@ namespace Discord.Audio public VoiceSocket VoiceSocket { get; } public JsonSerializer Serializer { get; } public Stream OutputStream { get; } - + public CancellationToken CancelToken { get; private set; } public string SessionId => GatewaySocket.SessionId; @@ -68,7 +67,7 @@ namespace Discord.Audio public Channel Channel => VoiceSocket.Channel; public AudioClient(DiscordClient client, Server server, int id) - { + { Id = id; Service = client.GetService(); Config = Service.Config; @@ -84,40 +83,8 @@ namespace Discord.Audio CancelToken = new CancellationToken(true); //Networking - if (Config.EnableMultiserver) - { - //TODO: We can remove this hack when official API launches - var baseConfig = client.Config; - var builder = new DiscordConfigBuilder - { - AppName = baseConfig.AppName, - AppUrl = baseConfig.AppUrl, - AppVersion = baseConfig.AppVersion, - CacheToken = baseConfig.CacheDir != null, - ConnectionTimeout = baseConfig.ConnectionTimeout, - EnablePreUpdateEvents = false, - FailedReconnectDelay = baseConfig.FailedReconnectDelay, - LargeThreshold = 1, - LogLevel = baseConfig.LogLevel, - MessageCacheSize = 0, - ReconnectDelay = baseConfig.ReconnectDelay, - UsePermissionsCache = false - }; - _config = builder.Build(); - - ClientAPI = new JsonRestClient(_config, DiscordConfig.ClientAPIUrl, client.Log.CreateLogger($"ClientAPI #{id}")); - GatewaySocket = new GatewaySocket(_config, client.Serializer, client.Log.CreateLogger($"Gateway #{id}")); - GatewaySocket.Connected += (s, e) => - { - if (_gatewayState == ConnectionState.Connecting) - EndGatewayConnect(); - }; - } - else - { - _config = client.Config; - GatewaySocket = client.GatewaySocket; - } + _config = client.Config; + GatewaySocket = client.GatewaySocket; GatewaySocket.ReceivedDispatch += (s, e) => OnReceivedEvent(e); VoiceSocket = new VoiceSocket(_config, Config, client.Serializer, client.Log.CreateLogger($"Voice #{id}")); VoiceSocket.Server = server; @@ -126,14 +93,9 @@ namespace Discord.Audio public async Task Connect() { - if (Config.EnableMultiserver) - await BeginGatewayConnect().ConfigureAwait(false); - else - { - var cancelSource = new CancellationTokenSource(); - CancelToken = cancelSource.Token; - await _taskManager.Start(new Task[0], cancelSource).ConfigureAwait(false); - } + var cancelSource = new CancellationTokenSource(); + CancelToken = cancelSource.Token; + await _taskManager.Start(new Task[0], cancelSource).ConfigureAwait(false); } private async Task BeginGatewayConnect() { @@ -154,7 +116,7 @@ namespace Discord.Audio var cancelSource = new CancellationTokenSource(); CancelToken = cancelSource.Token; ClientAPI.CancelToken = CancelToken; - + await GatewaySocket.Connect(ClientAPI, CancelToken).ConfigureAwait(false); await _taskManager.Start(new Task[0], cancelSource).ConfigureAwait(false); @@ -178,7 +140,7 @@ namespace Discord.Audio { _gatewayState = ConnectionState.Connected; } - + public async Task Disconnect() { await _taskManager.Stop(true).ConfigureAwait(false); @@ -188,28 +150,13 @@ namespace Discord.Audio var oldState = _gatewayState; _gatewayState = ConnectionState.Disconnecting; - if (Config.EnableMultiserver) - { - if (oldState == ConnectionState.Connected) - { - try { await ClientAPI.Send(new LogoutRequest()).ConfigureAwait(false); } - catch (OperationCanceledException) { } - } - - await GatewaySocket.Disconnect().ConfigureAwait(false); - ClientAPI.Token = null; - } - var server = VoiceSocket.Server; VoiceSocket.Server = null; VoiceSocket.Channel = null; - if (Config.EnableMultiserver) - await Service.RemoveClient(server, this).ConfigureAwait(false); + await Service.RemoveClient(server, this).ConfigureAwait(false); SendVoiceUpdate(server.Id, null); await VoiceSocket.Disconnect().ConfigureAwait(false); - if (Config.EnableMultiserver) - await GatewaySocket.Disconnect().ConfigureAwait(false); _gatewayState = (int)ConnectionState.Disconnected; } @@ -222,7 +169,7 @@ namespace Discord.Audio if (channel == VoiceSocket.Channel) return; var server = channel.Server; if (server != VoiceSocket.Server) - throw new ArgumentException("This is channel is not part of the current server.", nameof(channel)); + throw new ArgumentException("This channel is not part of the current server.", nameof(channel)); if (VoiceSocket.Server == null) throw new InvalidOperationException("This client has been closed."); @@ -282,26 +229,26 @@ namespace Discord.Audio } public void Send(byte[] data, int offset, int count) - { + { if (data == null) throw new ArgumentException(nameof(data)); if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset)); if (VoiceSocket.Server == null) return; //Has been closed if (count == 0) return; - VoiceSocket.SendPCMFrames(data, offset, count); - } + VoiceSocket.SendPCMFrames(data, offset, count); + } public void Clear() { if (VoiceSocket.Server == null) return; //Has been closed VoiceSocket.ClearPCMFrames(); } - public void Wait() + public void Wait() { if (VoiceSocket.Server == null) return; //Has been closed VoiceSocket.WaitForQueue(); - } + } public void SendVoiceUpdate(ulong? serverId, ulong? channelId) { @@ -309,5 +256,5 @@ namespace Discord.Audio (Service.Config.Mode | AudioMode.Outgoing) == 0, (Service.Config.Mode | AudioMode.Incoming) == 0); } - } + } } diff --git a/src/Discord.Net.Audio/AudioService.cs b/src/Discord.Net.Audio/AudioService.cs index 3de3531ae..3584b2075 100644 --- a/src/Discord.Net.Audio/AudioService.cs +++ b/src/Discord.Net.Audio/AudioService.cs @@ -1,22 +1,19 @@ using Nito.AsyncEx; using System; using System.Collections.Concurrent; -using System.Linq; using System.Threading.Tasks; namespace Discord.Audio { - public class AudioService : IService + public class AudioService : IService { private readonly AsyncLock _asyncLock; - private AudioClient _defaultClient; //Only used for single server - private VirtualClient _currentClient; //Only used for single server private ConcurrentDictionary _voiceClients; - private ConcurrentDictionary _talkingUsers; - private int _nextClientId; + private ConcurrentDictionary _talkingUsers; + private int _nextClientId; public DiscordClient Client { get; private set; } - public AudioServiceConfig Config { get; } + public AudioServiceConfig Config { get; } public event EventHandler Connected = delegate { }; public event EventHandler Disconnected = delegate { }; @@ -24,9 +21,9 @@ namespace Discord.Audio private void OnConnected() => Connected(this, EventArgs.Empty); - private void OnDisconnected(ulong serverId, bool wasUnexpected, Exception ex) + private void OnDisconnected(ulong serverId, bool wasUnexpected, Exception ex) => Disconnected(this, new VoiceDisconnectedEventArgs(serverId, wasUnexpected, ex)); - private void OnUserIsSpeakingUpdated(User user, bool isSpeaking) + private void OnUserIsSpeakingUpdated(User user, bool isSpeaking) => UserIsSpeakingUpdated(this, new UserIsSpeakingEventArgs(user, isSpeaking)); public AudioService() @@ -38,72 +35,41 @@ namespace Discord.Audio { } public AudioService(AudioServiceConfig config) - { + { Config = config; _asyncLock = new AsyncLock(); } - void IService.Install(DiscordClient client) - { - Client = client; - - if (Config.EnableMultiserver) - _voiceClients = new ConcurrentDictionary(); - else - { - var logger = Client.Log.CreateLogger("Voice"); - _defaultClient = new AudioClient(Client, null, 0); - } - _talkingUsers = new ConcurrentDictionary(); - - client.GatewaySocket.Disconnected += async (s, e) => - { - if (Config.EnableMultiserver) - { - var tasks = _voiceClients - .Select(x => - { - var val = x.Value; - if (val != null) - return x.Value.Disconnect(); - else - return TaskHelper.CompletedTask; - }) - .ToArray(); - await Task.WhenAll(tasks).ConfigureAwait(false); - _voiceClients.Clear(); - } - foreach (var member in _talkingUsers) - { - bool ignored; - if (_talkingUsers.TryRemove(member.Key, out ignored)) - OnUserIsSpeakingUpdated(member.Key, false); - } - }; - } - - public IAudioClient GetClient(Server server) - { - if (server == null) throw new ArgumentNullException(nameof(server)); - - if (Config.EnableMultiserver) + void IService.Install(DiscordClient client) + { + Client = client; + + _voiceClients = new ConcurrentDictionary(); + + _talkingUsers = new ConcurrentDictionary(); + + client.GatewaySocket.Disconnected += (s, e) => { - AudioClient client; - if (_voiceClients.TryGetValue(server.Id, out client)) - return client; - else - return null; - } + foreach (var member in _talkingUsers) + { + bool ignored; + if (_talkingUsers.TryRemove(member.Key, out ignored)) + OnUserIsSpeakingUpdated(member.Key, false); + } + }; + } + + public IAudioClient GetClient(Server server) + { + if (server == null) throw new ArgumentNullException(nameof(server)); + AudioClient client; + if (_voiceClients.TryGetValue(server.Id, out client)) + return client; else - { - if (server == _currentClient.Server) - return _currentClient; - else - return null; - } - } - - //Called from AudioClient.Disconnect + return null; + } + + //Called from AudioClient.Cleanup internal async Task RemoveClient(Server server, AudioClient client) { using (await _asyncLock.LockAsync().ConfigureAwait(false)) @@ -113,81 +79,40 @@ namespace Discord.Audio } } - public async Task Join(Channel channel) - { - if (channel == null) throw new ArgumentNullException(nameof(channel)); - + public async Task Join(Channel channel) + { + if (channel == null) throw new ArgumentNullException(nameof(channel)); + var server = channel.Server; using (await _asyncLock.LockAsync().ConfigureAwait(false)) { - if (Config.EnableMultiserver) - { - AudioClient client; - if (!_voiceClients.TryGetValue(server.Id, out client)) - { - client = new AudioClient(Client, server, unchecked(++_nextClientId)); - _voiceClients[server.Id] = client; - - await client.Connect().ConfigureAwait(false); - - /*voiceClient.VoiceSocket.FrameReceived += (s, e) => - { - OnFrameReceieved(e); - }; - voiceClient.VoiceSocket.UserIsSpeaking += (s, e) => - { - var user = server.GetUser(e.UserId); - OnUserIsSpeakingUpdated(user, e.IsSpeaking); - };*/ - } - - await client.Join(channel).ConfigureAwait(false); - return client; - } - else + AudioClient client; + if (!_voiceClients.TryGetValue(server.Id, out client)) { - if (_defaultClient.Server != server) - { - await _defaultClient.Disconnect().ConfigureAwait(false); - _defaultClient.VoiceSocket.Server = server; - await _defaultClient.Connect().ConfigureAwait(false); - } - var client = new VirtualClient(_defaultClient, server); - _currentClient = client; - - await client.Join(channel).ConfigureAwait(false); - return client; + client = new AudioClient(Client, server, unchecked(++_nextClientId)); + _voiceClients[server.Id] = client; + + await client.Connect().ConfigureAwait(false); } + await client.Join(channel).ConfigureAwait(false); + return client; } - } + } - public Task Leave(Server server) => Leave(server, null); + public Task Leave(Server server) => Leave(server, null); public Task Leave(Channel channel) => Leave(channel.Server, channel); private async Task Leave(Server server, Channel channel) { if (server == null) throw new ArgumentNullException(nameof(server)); - if (Config.EnableMultiserver) + AudioClient client; + //Potential race condition if changing channels during this call, but that's acceptable + if (channel == null || (_voiceClients.TryGetValue(server.Id, out client) && client.Channel == channel)) { - AudioClient client; - //Potential race condition if changing channels during this call, but that's acceptable - if (channel == null || (_voiceClients.TryGetValue(server.Id, out client) && client.Channel == channel)) - { - if (_voiceClients.TryRemove(server.Id, out client)) - await client.Disconnect().ConfigureAwait(false); - } - } - else - { - using (await _asyncLock.LockAsync().ConfigureAwait(false)) - { - var client = GetClient(server) as VirtualClient; - if (client != null && client.Channel == channel) - await _defaultClient.Disconnect().ConfigureAwait(false); - } + if (_voiceClients.TryRemove(server.Id, out client)) + await client.Disconnect().ConfigureAwait(false); } - } } }