Browse Source

Better voice error handling, moved several properties into DiscordVoiceSocket

tags/docs-0.9
Brandon Smith 9 years ago
parent
commit
52590e4153
6 changed files with 77 additions and 41 deletions
  1. +2
    -1
      src/Discord.Net.Commands/DiscordBotClient.cs
  2. +9
    -12
      src/Discord.Net/DiscordClient.cs
  3. +3
    -5
      src/Discord.Net/DiscordClientConfig.cs
  4. +5
    -0
      src/Discord.Net/DiscordDataSocket.cs
  5. +52
    -20
      src/Discord.Net/DiscordVoiceSocket.cs
  6. +6
    -3
      src/Discord.Net/DiscordWebSocket.cs

+ 2
- 1
src/Discord.Net.Commands/DiscordBotClient.cs View File

@@ -22,6 +22,7 @@ namespace Discord
_commands = new List<Command>(); _commands = new List<Command>();


CommandChar = '~'; CommandChar = '~';
UseCommandChar = true;
RequireCommandCharInPublic = true; RequireCommandCharInPublic = true;
RequireCommandCharInPrivate = true; RequireCommandCharInPrivate = true;


@@ -32,7 +33,7 @@ namespace Discord
return; return;


//Ignore messages from ourselves //Ignore messages from ourselves
if (e.Message.UserId == _myId)
if (e.Message.UserId == _myId)
return; return;


//Check for the command character //Check for the command character


+ 9
- 12
src/Discord.Net/DiscordClient.cs View File

@@ -49,8 +49,7 @@ namespace Discord
private bool _isDebugMode; private bool _isDebugMode;


#if !DNXCORE50 #if !DNXCORE50
public Server CurrentVoiceServer => _currentVoiceToken != null ? _servers[_currentVoiceServerId] : null;
private string _currentVoiceServerId, _currentVoiceToken;
public Server CurrentVoiceServer => GetServer(_voiceWebSocket.CurrentVoiceServerId);
#endif #endif


//Constructor //Constructor
@@ -142,13 +141,12 @@ namespace Discord
//Reconnect if we didn't cause the disconnect //Reconnect if we didn't cause the disconnect
if (e.WasUnexpected) if (e.WasUnexpected)
{ {
await Task.Delay(_config.ReconnectDelay);
while (!_disconnectToken.IsCancellationRequested) while (!_disconnectToken.IsCancellationRequested)
{ {
try try
{ {
await Task.Delay(_config.ReconnectDelay);
await _voiceWebSocket.ReconnectAsync(); await _voiceWebSocket.ReconnectAsync();
await _voiceWebSocket.Login(_currentVoiceServerId, _myId, _sessionId, _currentVoiceToken);
break; break;
} }
catch (Exception ex) catch (Exception ex)
@@ -425,11 +423,10 @@ namespace Discord
try { RaiseVoiceServerUpdated(server, data.Endpoint); } catch { } try { RaiseVoiceServerUpdated(server, data.Endpoint); } catch { }


#if !DNXCORE50 #if !DNXCORE50
if (_config.EnableVoice && data.ServerId == _currentVoiceServerId)
if (_config.EnableVoice)
{ {
_currentVoiceToken = data.Token;
_voiceWebSocket.SetSessionData(data.ServerId, _myId, _sessionId, data.Token);
await _voiceWebSocket.ConnectAsync("wss://" + data.Endpoint.Split(':')[0]); await _voiceWebSocket.ConnectAsync("wss://" + data.Endpoint.Split(':')[0]);
await _voiceWebSocket.Login(_currentVoiceServerId, _myId, _sessionId, data.Token);
} }
#endif #endif
} }
@@ -627,19 +624,19 @@ namespace Discord
if (channel == null) throw new ArgumentNullException(nameof(channel)); if (channel == null) throw new ArgumentNullException(nameof(channel));


await LeaveVoiceServer(); await LeaveVoiceServer();
_currentVoiceServerId = channel.ServerId;
//_currentVoiceServerId = channel.ServerId;
_webSocket.JoinVoice(channel); _webSocket.JoinVoice(channel);
await _voiceWebSocket.BeginConnect();
} }


public async Task LeaveVoiceServer() public async Task LeaveVoiceServer()
{ {
CheckReady();
if (!_config.EnableVoice) throw new InvalidOperationException("Voice is not enabled for this client."); if (!_config.EnableVoice) throw new InvalidOperationException("Voice is not enabled for this client.");


await _voiceWebSocket.DisconnectAsync(); await _voiceWebSocket.DisconnectAsync();
if (_currentVoiceServerId != null)
_webSocket.LeaveVoice();
_currentVoiceServerId = null;
_currentVoiceToken = null;
//if (_voiceWebSocket.CurrentVoiceServerId != null)
_webSocket.LeaveVoice();
} }


/// <summary> Sends a PCM frame to the voice server. </summary> /// <summary> Sends a PCM frame to the voice server. </summary>


+ 3
- 5
src/Discord.Net/DiscordClientConfig.cs View File

@@ -3,8 +3,7 @@
public class DiscordClientConfig public class DiscordClientConfig
{ {
#if !DNXCORE50 #if !DNXCORE50
/// <summary> Enables the voice websocket and UDP client (Experimental!). </summary>
/// <remarks> This option requires the opus .dll or .so be in the local lib/ folder. </remarks>
/// <summary> Enables the voice websocket and UDP client (Experimental!). This option requires the opus .dll or .so be in the local lib/ folder. </remarks>
public bool EnableVoice { get; set; } = false; public bool EnableVoice { get; set; } = false;
#endif #endif
/// <summary> Enables the verbose DebugMessage event handler. May hinder performance but should help debug any issues. </summary> /// <summary> Enables the verbose DebugMessage event handler. May hinder performance but should help debug any issues. </summary>
@@ -24,9 +23,8 @@
public bool UseMessageQueue { get; set; } = false; public bool UseMessageQueue { get; set; } = false;
/// <summary> Gets or sets the time (in milliseconds) to wait when the message queue is empty before checking again. </summary> /// <summary> Gets or sets the time (in milliseconds) to wait when the message queue is empty before checking again. </summary>
public int MessageQueueInterval { get; set; } = 100; public int MessageQueueInterval { get; set; } = 100;
/// <summary> Gets or sets the max buffer length (in milliseconds) for outgoing voice packets. </summary>
/// <remarks> This value is the target maximum but is not guaranteed. The buffer will often go a bit above this value. </remarks>
public int VoiceBufferLength { get; set; } = 1000;
/// <summary> Gets or sets the max buffer length (in milliseconds) for outgoing voice packets. This value is the target maximum but is not guaranteed, the buffer will often go slightly above this value. </remarks>
public int VoiceBufferLength { get; set; } = 3000;


public DiscordClientConfig() { } public DiscordClientConfig() { }
} }


+ 5
- 0
src/Discord.Net/DiscordDataSocket.cs View File

@@ -20,6 +20,11 @@ namespace Discord
_connectWaitOnLogin2 = new ManualResetEventSlim(false); _connectWaitOnLogin2 = new ManualResetEventSlim(false);
} }


public override Task ConnectAsync(string url)
{
BeginConnect();
return base.ConnectAsync(url);
}
public async Task Login(string token) public async Task Login(string token)
{ {
var cancelToken = _disconnectToken.Token; var cancelToken = _disconnectToken.Token;


+ 52
- 20
src/Discord.Net/DiscordVoiceSocket.cs View File

@@ -1,4 +1,4 @@
//#define USE_THREAD
#define USE_THREAD
#if !DNXCORE50 #if !DNXCORE50
using Discord.API.Models; using Discord.API.Models;
using Discord.Opus; using Discord.Opus;
@@ -35,10 +35,14 @@ namespace Discord
private ushort _sequence; private ushort _sequence;
private string _mode; private string _mode;
private byte[] _encodingBuffer; private byte[] _encodingBuffer;
private string _serverId, _userId, _sessionId, _token;

#if USE_THREAD #if USE_THREAD
private Thread _sendThread; private Thread _sendThread;
#endif #endif


public string CurrentVoiceServerId => _serverId;

public DiscordVoiceSocket(DiscordClient client, int timeout, int interval, int audioBufferLength, bool isDebug) public DiscordVoiceSocket(DiscordClient client, int timeout, int interval, int audioBufferLength, bool isDebug)
: base(client, timeout, interval, isDebug) : base(client, timeout, interval, isDebug)
{ {
@@ -54,25 +58,54 @@ namespace Discord
protected override void OnConnect() protected override void OnConnect()
{ {
_udp = new UdpClient(new IPEndPoint(IPAddress.Any, 0)); _udp = new UdpClient(new IPEndPoint(IPAddress.Any, 0));
#if !DNX451 && !MONO
#if !DNX451
_udp.AllowNatTraversal(true); _udp.AllowNatTraversal(true);
#endif #endif
_isReady = false; _isReady = false;
_isClearing = false; _isClearing = false;
}

var cancelToken = _disconnectToken.Token;
Task.Factory.StartNew(async () =>
{
_connectWaitOnLogin.Reset();

VoiceWebSocketCommands.Login msg = new VoiceWebSocketCommands.Login();
msg.Payload.ServerId = _serverId;
msg.Payload.SessionId = _sessionId;
msg.Payload.Token = _token;
msg.Payload.UserId = _userId;
await SendMessage(msg, cancelToken);

try
{
if (!_connectWaitOnLogin.Wait(_timeout, cancelToken))
return;
}
catch (OperationCanceledException)
{
return;
}

SetConnected();
});
}
protected override void OnDisconnect() protected override void OnDisconnect()
{ {
_udp = null; _udp = null;
_serverId = null;
_userId = null;
_sessionId = null;
_token = null;
#if USE_THREAD #if USE_THREAD
_sendThread.Join(); _sendThread.Join();
_sendThread = null; _sendThread = null;
#endif #endif
}
}


protected override Task[] CreateTasks() protected override Task[] CreateTasks()
{ {
#if USE_THREAD #if USE_THREAD
_sendThread = new Thread(new ThreadStart(() => SendAsync(_disconnectToken)));
_sendThread = new Thread(new ThreadStart(() => SendVoiceAsync(_disconnectToken)));
_sendThread.Start(); _sendThread.Start();
#endif #endif
return new Task[] return new Task[]
@@ -85,19 +118,20 @@ namespace Discord
}.Concat(base.CreateTasks()).ToArray(); }.Concat(base.CreateTasks()).ToArray();
} }


public async Task Login(string serverId, string userId, string sessionId, string token)
public void SetSessionData(string serverId, string userId, string sessionId, string token)
{ {
var cancelToken = _disconnectToken.Token;

_connectWaitOnLogin.Reset();
_serverId = serverId;
_userId = userId;
_sessionId = sessionId;
_token = token;
}


VoiceWebSocketCommands.Login msg = new VoiceWebSocketCommands.Login();
msg.Payload.ServerId = serverId;
msg.Payload.SessionId = sessionId;
msg.Payload.Token = token;
msg.Payload.UserId = userId;
await SendMessage(msg, cancelToken);
public new async Task BeginConnect()
{
base.BeginConnect();
var cancelToken = _disconnectToken.Token;


await Task.Yield();
try try
{ {
if (!_connectWaitOnLogin.Wait(_timeout, cancelToken)) //Waiting on JoinServer message if (!_connectWaitOnLogin.Wait(_timeout, cancelToken)) //Waiting on JoinServer message
@@ -110,8 +144,6 @@ namespace Discord
else else
_disconnectReason.Throw(); _disconnectReason.Throw();
} }

SetConnected();
} }
private async Task ReceiveVoiceAsync() private async Task ReceiveVoiceAsync()
@@ -143,6 +175,7 @@ namespace Discord
var cancelSource = _disconnectToken; var cancelSource = _disconnectToken;
var cancelToken = cancelSource.Token; var cancelToken = cancelSource.Token;
await Task.Yield(); await Task.Yield();
#endif


byte[] packet; byte[] packet;
try try
@@ -189,7 +222,7 @@ namespace Discord
rtpPacket[7] = (byte)((timestamp >> 0) & 0xFF); rtpPacket[7] = (byte)((timestamp >> 0) & 0xFF);
Buffer.BlockCopy(packet, 0, rtpPacket, 12, packet.Length); Buffer.BlockCopy(packet, 0, rtpPacket, 12, packet.Length);
#if USE_THREAD #if USE_THREAD
_udp.Send(rtpPacket, packet.Count + 12);
_udp.Send(rtpPacket, packet.Length + 12);
#else #else
await _udp.SendAsync(rtpPacket, packet.Length + 12); await _udp.SendAsync(rtpPacket, packet.Length + 12);
#endif #endif
@@ -222,8 +255,7 @@ namespace Discord
catch (ObjectDisposedException) { } catch (ObjectDisposedException) { }
catch (Exception ex) { DisconnectInternal(ex); } catch (Exception ex) { DisconnectInternal(ex); }
} }
#endif
//Closes the UDP socket when _disconnectToken is triggered, since UDPClient doesn't allow passing a canceltoken
//Closes the UDP socket when _disconnectToken is triggered, since UDPClient doesn't allow passing a canceltoken
private async Task WatcherAsync() private async Task WatcherAsync()
{ {
var cancelToken = _disconnectToken.Token; var cancelToken = _disconnectToken.Token;


+ 6
- 3
src/Discord.Net/DiscordWebSocket.cs View File

@@ -40,12 +40,15 @@ namespace Discord
_sendQueue = new ConcurrentQueue<byte[]>(); _sendQueue = new ConcurrentQueue<byte[]>();
} }


public async Task ConnectAsync(string url)
protected void BeginConnect()
{ {
await DisconnectAsync();

_disconnectToken = new CancellationTokenSource(); _disconnectToken = new CancellationTokenSource();
_disconnectReason = null; _disconnectReason = null;
}
public virtual async Task ConnectAsync(string url)
{
await DisconnectAsync();

var cancelToken = _disconnectToken.Token; var cancelToken = _disconnectToken.Token;


_webSocket = new ClientWebSocket(); _webSocket = new ClientWebSocket();


Loading…
Cancel
Save