Fixed audio and a few ConnectionManager issues

This commit is contained in:
RogueException
2017-02-25 16:06:42 -04:00
parent 3190d7e26d
commit 06dcac6a9f
7 changed files with 43 additions and 23 deletions

View File

@@ -19,6 +19,9 @@
<Compile Include="..\Discord.Net.WebSocket\Net\DefaultWebSocketClient.cs"> <Compile Include="..\Discord.Net.WebSocket\Net\DefaultWebSocketClient.cs">
<Link>Net\DefaultWebSocketClient.cs</Link> <Link>Net\DefaultWebSocketClient.cs</Link>
</Compile> </Compile>
<Compile Include="..\Discord.Net.WebSocket\ConnectionManager.cs">
<Link>ConnectionManager.cs</Link>
</Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" /> <ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" />

View File

@@ -12,12 +12,12 @@ namespace Discord.Rpc
remove { _connectedEvent.Remove(value); } remove { _connectedEvent.Remove(value); }
} }
private readonly AsyncEvent<Func<Task>> _connectedEvent = new AsyncEvent<Func<Task>>(); private readonly AsyncEvent<Func<Task>> _connectedEvent = new AsyncEvent<Func<Task>>();
public event Func<Exception, bool, Task> Disconnected public event Func<Exception, Task> Disconnected
{ {
add { _disconnectedEvent.Add(value); } add { _disconnectedEvent.Add(value); }
remove { _disconnectedEvent.Remove(value); } remove { _disconnectedEvent.Remove(value); }
} }
private readonly AsyncEvent<Func<Exception, bool, Task>> _disconnectedEvent = new AsyncEvent<Func<Exception, bool, Task>>(); private readonly AsyncEvent<Func<Exception, Task>> _disconnectedEvent = new AsyncEvent<Func<Exception, Task>>();
public event Func<Task> Ready public event Func<Task> Ready
{ {
add { _readyEvent.Add(value); } add { _readyEvent.Add(value); }

View File

@@ -40,6 +40,8 @@ namespace Discord.Rpc
_rpcLogger = LogManager.CreateLogger("RPC"); _rpcLogger = LogManager.CreateLogger("RPC");
_connection = new ConnectionManager(_stateLock, _rpcLogger, config.ConnectionTimeout, _connection = new ConnectionManager(_stateLock, _rpcLogger, config.ConnectionTimeout,
OnConnectingAsync, OnDisconnectingAsync, x => ApiClient.Disconnected += x); OnConnectingAsync, OnDisconnectingAsync, x => ApiClient.Disconnected += x);
_connection.Connected += () => _connectedEvent.InvokeAsync();
_connection.Disconnected += (ex, recon) => _disconnectedEvent.InvokeAsync(ex);
_serializer = new JsonSerializer { ContractResolver = new DiscordContractResolver() }; _serializer = new JsonSerializer { ContractResolver = new DiscordContractResolver() };
_serializer.Error += (s, e) => _serializer.Error += (s, e) =>

View File

@@ -59,14 +59,22 @@ namespace Discord.Audio
internal AudioClient(SocketGuild guild, int id) internal AudioClient(SocketGuild guild, int id)
{ {
Guild = guild; Guild = guild;
_audioLogger = Discord.LogManager.CreateLogger($"Audio #{id}");
ApiClient = new DiscordVoiceAPIClient(guild.Id, Discord.WebSocketProvider, Discord.UdpSocketProvider);
ApiClient.SentGatewayMessage += async opCode => await _audioLogger.DebugAsync($"Sent {opCode}").ConfigureAwait(false);
ApiClient.SentDiscovery += async () => await _audioLogger.DebugAsync($"Sent Discovery").ConfigureAwait(false);
//ApiClient.SentData += async bytes => await _audioLogger.DebugAsync($"Sent {bytes} Bytes").ConfigureAwait(false);
ApiClient.ReceivedEvent += ProcessMessageAsync;
ApiClient.ReceivedPacket += ProcessPacketAsync;
_stateLock = new SemaphoreSlim(1, 1); _stateLock = new SemaphoreSlim(1, 1);
_connection = new ConnectionManager(_stateLock, _audioLogger, 30000, _connection = new ConnectionManager(_stateLock, _audioLogger, 30000,
OnConnectingAsync, OnDisconnectingAsync, x => ApiClient.Disconnected += x); OnConnectingAsync, OnDisconnectingAsync, x => ApiClient.Disconnected += x);
_connection.Connected += () => _connectedEvent.InvokeAsync();
_connection.Disconnected += (ex, recon) => _disconnectedEvent.InvokeAsync(ex);
_heartbeatTimes = new ConcurrentQueue<long>(); _heartbeatTimes = new ConcurrentQueue<long>();
_audioLogger = Discord.LogManager.CreateLogger($"Audio #{id}");
_serializer = new JsonSerializer { ContractResolver = new DiscordContractResolver() }; _serializer = new JsonSerializer { ContractResolver = new DiscordContractResolver() };
_serializer.Error += (s, e) => _serializer.Error += (s, e) =>
{ {
@@ -74,14 +82,6 @@ namespace Discord.Audio
e.ErrorContext.Handled = true; e.ErrorContext.Handled = true;
}; };
ApiClient = new DiscordVoiceAPIClient(guild.Id, Discord.WebSocketProvider, Discord.UdpSocketProvider);
ApiClient.SentGatewayMessage += async opCode => await _audioLogger.DebugAsync($"Sent {opCode}").ConfigureAwait(false);
ApiClient.SentDiscovery += async () => await _audioLogger.DebugAsync($"Sent Discovery").ConfigureAwait(false);
//ApiClient.SentData += async bytes => await _audioLogger.DebugAsync($"Sent {bytes} Bytes").ConfigureAwait(false);
ApiClient.ReceivedEvent += ProcessMessageAsync;
ApiClient.ReceivedPacket += ProcessPacketAsync;
LatencyUpdated += async (old, val) => await _audioLogger.VerboseAsync($"Latency = {val} ms").ConfigureAwait(false); LatencyUpdated += async (old, val) => await _audioLogger.VerboseAsync($"Latency = {val} ms").ConfigureAwait(false);
} }
@@ -98,25 +98,32 @@ namespace Discord.Audio
private async Task OnConnectingAsync() private async Task OnConnectingAsync()
{ {
await _audioLogger.DebugAsync("Connecting ApiClient").ConfigureAwait(false);
await ApiClient.ConnectAsync("wss://" + _url).ConfigureAwait(false); await ApiClient.ConnectAsync("wss://" + _url).ConfigureAwait(false);
await _audioLogger.DebugAsync("Sending Identity").ConfigureAwait(false);
await ApiClient.SendIdentityAsync(_userId, _sessionId, _token).ConfigureAwait(false); await ApiClient.SendIdentityAsync(_userId, _sessionId, _token).ConfigureAwait(false);
//Wait for READY
await _connection.WaitAsync().ConfigureAwait(false);
} }
private async Task OnDisconnectingAsync(Exception ex) private async Task OnDisconnectingAsync(Exception ex)
{ {
//Disconnect from server await _audioLogger.DebugAsync("Disconnecting ApiClient").ConfigureAwait(false);
await ApiClient.DisconnectAsync().ConfigureAwait(false); await ApiClient.DisconnectAsync().ConfigureAwait(false);
//Wait for tasks to complete //Wait for tasks to complete
await _audioLogger.DebugAsync("Waiting for heartbeater").ConfigureAwait(false);
var heartbeatTask = _heartbeatTask; var heartbeatTask = _heartbeatTask;
if (heartbeatTask != null) if (heartbeatTask != null)
await heartbeatTask.ConfigureAwait(false); await heartbeatTask.ConfigureAwait(false);
_heartbeatTask = null; _heartbeatTask = null;
await Discord.ApiClient.SendVoiceStateUpdateAsync(Guild.Id, null, false, false).ConfigureAwait(false);
long time; long time;
while (_heartbeatTimes.TryDequeue(out time)) { } while (_heartbeatTimes.TryDequeue(out time)) { }
_lastMessageTime = 0; _lastMessageTime = 0;
await _audioLogger.DebugAsync("Sending Voice State").ConfigureAwait(false);
await Discord.ApiClient.SendVoiceStateUpdateAsync(Guild.Id, null, false, false).ConfigureAwait(false);
} }
public AudioOutStream CreateOpusStream(int samplesPerFrame, int bufferMillis) public AudioOutStream CreateOpusStream(int samplesPerFrame, int bufferMillis)

View File

@@ -2,6 +2,7 @@ using Discord.Logging;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Discord.Net;
namespace Discord namespace Discord
{ {
@@ -39,7 +40,13 @@ namespace Discord
clientDisconnectHandler(ex => clientDisconnectHandler(ex =>
{ {
if (ex != null) if (ex != null)
Error(new Exception("WebSocket connection was closed", ex)); {
var ex2 = ex as WebSocketClosedException;
if (ex2?.CloseCode == 4006)
CriticalError(new Exception("WebSocket session expired", ex));
else
Error(new Exception("WebSocket connection was closed", ex));
}
else else
Error(new Exception("WebSocket connection was closed")); Error(new Exception("WebSocket connection was closed"));
return Task.Delay(0); return Task.Delay(0);
@@ -50,7 +57,7 @@ namespace Discord
{ {
await AcquireConnectionLock().ConfigureAwait(false); await AcquireConnectionLock().ConfigureAwait(false);
var reconnectCancelToken = new CancellationTokenSource(); var reconnectCancelToken = new CancellationTokenSource();
_reconnectCancelToken = new CancellationTokenSource(); _reconnectCancelToken = reconnectCancelToken;
_task = Task.Run(async () => _task = Task.Run(async () =>
{ {
try try

View File

@@ -95,6 +95,8 @@ namespace Discord.WebSocket
_gatewayLogger = LogManager.CreateLogger(ShardId == 0 && TotalShards == 1 ? "Gateway" : $"Shard #{ShardId}"); _gatewayLogger = LogManager.CreateLogger(ShardId == 0 && TotalShards == 1 ? "Gateway" : $"Shard #{ShardId}");
_connection = new ConnectionManager(_stateLock, _gatewayLogger, config.ConnectionTimeout, _connection = new ConnectionManager(_stateLock, _gatewayLogger, config.ConnectionTimeout,
OnConnectingAsync, OnDisconnectingAsync, x => ApiClient.Disconnected += x); OnConnectingAsync, OnDisconnectingAsync, x => ApiClient.Disconnected += x);
_connection.Connected += () => _connectedEvent.InvokeAsync();
_connection.Disconnected += (ex, recon) => _disconnectedEvent.InvokeAsync(ex);
_nextAudioId = 1; _nextAudioId = 1;
_connectionGroupLock = groupLock; _connectionGroupLock = groupLock;
@@ -173,8 +175,6 @@ namespace Discord.WebSocket
{ {
await _gatewayLogger.DebugAsync("Connecting ApiClient").ConfigureAwait(false); await _gatewayLogger.DebugAsync("Connecting ApiClient").ConfigureAwait(false);
await ApiClient.ConnectAsync().ConfigureAwait(false); await ApiClient.ConnectAsync().ConfigureAwait(false);
await _gatewayLogger.DebugAsync("Raising Event").ConfigureAwait(false);
await _connectedEvent.InvokeAsync().ConfigureAwait(false);
if (_sessionId != null) if (_sessionId != null)
{ {

View File

@@ -506,15 +506,16 @@ namespace Discord.WebSocket
} }
internal async Task FinishConnectAudio(int id, string url, string token) internal async Task FinishConnectAudio(int id, string url, string token)
{ {
//TODO: Mem Leak: Disconnected/Connected handlers arent cleaned up
var voiceState = GetVoiceState(Discord.CurrentUser.Id).Value; var voiceState = GetVoiceState(Discord.CurrentUser.Id).Value;
await _audioLock.WaitAsync().ConfigureAwait(false); await _audioLock.WaitAsync().ConfigureAwait(false);
try try
{ {
var promise = _audioConnectPromise;
if (_audioClient == null) if (_audioClient == null)
{ {
var audioClient = new AudioClient(this, id); var audioClient = new AudioClient(this, id);
var promise = _audioConnectPromise;
audioClient.Disconnected += async ex => audioClient.Disconnected += async ex =>
{ {
if (!promise.Task.IsCompleted) if (!promise.Task.IsCompleted)
@@ -532,7 +533,7 @@ namespace Discord.WebSocket
} }
_audioClient.Connected += () => _audioClient.Connected += () =>
{ {
var _ = _audioConnectPromise.TrySetResultAsync(_audioClient); var _ = promise.TrySetResultAsync(_audioClient);
return Task.Delay(0); return Task.Delay(0);
}; };
await _audioClient.StartAsync(url, Discord.CurrentUser.Id, voiceState.VoiceSessionId, token).ConfigureAwait(false); await _audioClient.StartAsync(url, Discord.CurrentUser.Id, voiceState.VoiceSessionId, token).ConfigureAwait(false);