| @@ -3,6 +3,6 @@ | |||||
| public static class AudioExtensions | public static class AudioExtensions | ||||
| { | { | ||||
| public static AudioService Audio(this DiscordClient client, bool required = true) | public static AudioService Audio(this DiscordClient client, bool required = true) | ||||
| => client.GetService<AudioService>(required); | |||||
| => client.Services.Get<AudioService>(required); | |||||
| } | } | ||||
| } | } | ||||
| @@ -11,7 +11,7 @@ namespace Discord.Audio | |||||
| public readonly ulong ServerId; | public readonly ulong ServerId; | ||||
| public VoiceDisconnectedEventArgs(ulong serverId, DisconnectedEventArgs e) | public VoiceDisconnectedEventArgs(ulong serverId, DisconnectedEventArgs e) | ||||
| : base(e.WasUnexpected, e.Error) | |||||
| : base(e.WasUnexpected, e.Exception) | |||||
| { | { | ||||
| ServerId = serverId; | ServerId = serverId; | ||||
| } | } | ||||
| @@ -45,8 +45,8 @@ namespace Discord.Audio | |||||
| } | } | ||||
| public class AudioService : IService | public class AudioService : IService | ||||
| { | |||||
| private DiscordAudioClient _defaultClient; | |||||
| { | |||||
| private DiscordAudioClient _defaultClient; | |||||
| private ConcurrentDictionary<ulong, DiscordAudioClient> _voiceClients; | private ConcurrentDictionary<ulong, DiscordAudioClient> _voiceClients; | ||||
| private ConcurrentDictionary<User, bool> _talkingUsers; | private ConcurrentDictionary<User, bool> _talkingUsers; | ||||
| private int _nextClientId; | private int _nextClientId; | ||||
| @@ -94,8 +94,8 @@ namespace Discord.Audio | |||||
| _voiceClients = new ConcurrentDictionary<ulong, DiscordAudioClient>(); | _voiceClients = new ConcurrentDictionary<ulong, DiscordAudioClient>(); | ||||
| else | else | ||||
| { | { | ||||
| var logger = Client.Log().CreateLogger("Voice"); | |||||
| _defaultClient = new DiscordAudioClient(this, 0, logger, _client.WebSocket); | |||||
| var logger = Client.Log.CreateLogger("Voice"); | |||||
| _defaultClient = new DiscordAudioClient(this, 0, logger, _client.GatewaySocket); | |||||
| } | } | ||||
| _talkingUsers = new ConcurrentDictionary<User, bool>(); | _talkingUsers = new ConcurrentDictionary<User, bool>(); | ||||
| @@ -147,7 +147,7 @@ namespace Discord.Audio | |||||
| var client = _voiceClients.GetOrAdd(server.Id, _ => | var client = _voiceClients.GetOrAdd(server.Id, _ => | ||||
| { | { | ||||
| int id = unchecked(++_nextClientId); | int id = unchecked(++_nextClientId); | ||||
| var logger = Client.Log().CreateLogger($"Voice #{id}"); | |||||
| var logger = Client.Log.CreateLogger($"Voice #{id}"); | |||||
| GatewaySocket gatewaySocket = null; | GatewaySocket gatewaySocket = null; | ||||
| var voiceClient = new DiscordAudioClient(this, id, logger, gatewaySocket); | var voiceClient = new DiscordAudioClient(this, id, logger, gatewaySocket); | ||||
| voiceClient.SetServerId(server.Id); | voiceClient.SetServerId(server.Id); | ||||
| @@ -158,7 +158,7 @@ namespace Discord.Audio | |||||
| }; | }; | ||||
| voiceClient.VoiceSocket.IsSpeaking += (s, e) => | voiceClient.VoiceSocket.IsSpeaking += (s, e) => | ||||
| { | { | ||||
| var user = Client.GetUser(server, e.UserId); | |||||
| var user = server.GetUser(e.UserId); | |||||
| RaiseUserIsSpeakingUpdated(user, e.IsSpeaking); | RaiseUserIsSpeakingUpdated(user, e.IsSpeaking); | ||||
| }; | }; | ||||
| @@ -1,6 +1,8 @@ | |||||
| using Discord.API; | using Discord.API; | ||||
| using Discord.API.Client.GatewaySocket; | using Discord.API.Client.GatewaySocket; | ||||
| using Discord.Logging; | |||||
| using Discord.Net.WebSockets; | using Discord.Net.WebSockets; | ||||
| using Newtonsoft.Json; | |||||
| using System; | using System; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| @@ -8,31 +10,33 @@ namespace Discord.Audio | |||||
| { | { | ||||
| public partial class DiscordAudioClient | public partial class DiscordAudioClient | ||||
| { | { | ||||
| private readonly int _id; | |||||
| public int Id => _id; | |||||
| private JsonSerializer _serializer; | |||||
| private readonly AudioService _service; | |||||
| private readonly Logger _logger; | |||||
| internal AudioService Service { get; } | |||||
| internal Logger Logger { get; } | |||||
| public int Id { get; } | |||||
| public GatewaySocket GatewaySocket { get; } | |||||
| public VoiceWebSocket VoiceSocket { get; } | |||||
| public GatewaySocket GatewaySocket => _gatewaySocket; | |||||
| private readonly GatewaySocket _gatewaySocket; | |||||
| public VoiceWebSocket VoiceSocket => _voiceSocket; | |||||
| private readonly VoiceWebSocket _voiceSocket; | |||||
| public string Token => _token; | |||||
| private string _token; | |||||
| public ulong? ServerId => _voiceSocket.ServerId; | |||||
| public ulong? ChannelId => _voiceSocket.ChannelId; | |||||
| public ulong? ServerId => VoiceSocket.ServerId; | |||||
| public ulong? ChannelId => VoiceSocket.ChannelId; | |||||
| public DiscordAudioClient(AudioService service, int id, Logger logger, GatewaySocket gatewaySocket) | public DiscordAudioClient(AudioService service, int id, Logger logger, GatewaySocket gatewaySocket) | ||||
| { | { | ||||
| _service = service; | |||||
| _id = id; | |||||
| _logger = logger; | |||||
| _gatewaySocket = gatewaySocket; | |||||
| _voiceSocket = new VoiceWebSocket(service.Client, this, logger); | |||||
| Service = service; | |||||
| Id = id; | |||||
| Logger = logger; | |||||
| _serializer = new JsonSerializer(); | |||||
| _serializer.DateTimeZoneHandling = DateTimeZoneHandling.Utc; | |||||
| _serializer.Error += (s, e) => | |||||
| { | |||||
| e.ErrorContext.Handled = true; | |||||
| Logger.Error("Serialization Failed", e.ErrorContext.Error); | |||||
| }; | |||||
| GatewaySocket = gatewaySocket; | |||||
| VoiceSocket = new VoiceWebSocket(service.Client, this, _serializer, logger); | |||||
| /*_voiceSocket.Connected += (s, e) => RaiseVoiceConnected(); | /*_voiceSocket.Connected += (s, e) => RaiseVoiceConnected(); | ||||
| _voiceSocket.Disconnected += async (s, e) => | _voiceSocket.Disconnected += async (s, e) => | ||||
| @@ -68,7 +72,7 @@ namespace Discord.Audio | |||||
| _voiceSocket.ParentCancelToken = _cancelToken; | _voiceSocket.ParentCancelToken = _cancelToken; | ||||
| };*/ | };*/ | ||||
| _gatewaySocket.ReceivedDispatch += async (s, e) => | |||||
| GatewaySocket.ReceivedDispatch += async (s, e) => | |||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| @@ -76,15 +80,15 @@ namespace Discord.Audio | |||||
| { | { | ||||
| case "VOICE_SERVER_UPDATE": | case "VOICE_SERVER_UPDATE": | ||||
| { | { | ||||
| var data = e.Payload.ToObject<VoiceServerUpdateEvent>(_gatewaySocket.Serializer); | |||||
| var data = e.Payload.ToObject<VoiceServerUpdateEvent>(_serializer); | |||||
| var serverId = data.GuildId; | var serverId = data.GuildId; | ||||
| if (serverId == ServerId) | if (serverId == ServerId) | ||||
| { | { | ||||
| var client = _service.Client; | |||||
| _token = data.Token; | |||||
| _voiceSocket.Host = "wss://" + e.Payload.Value<string>("endpoint").Split(':')[0]; | |||||
| await _voiceSocket.Connect().ConfigureAwait(false); | |||||
| var client = Service.Client; | |||||
| VoiceSocket.Token = data.Token; | |||||
| VoiceSocket.Host = "wss://" + e.Payload.Value<string>("endpoint").Split(':')[0]; | |||||
| await VoiceSocket.Connect().ConfigureAwait(false); | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| @@ -92,7 +96,7 @@ namespace Discord.Audio | |||||
| } | } | ||||
| catch (Exception ex) | catch (Exception ex) | ||||
| { | { | ||||
| _gatewaySocket.Logger.Error($"Error handling {e.Type} event", ex); | |||||
| Logger.Error($"Error handling {e.Type} event", ex); | |||||
| } | } | ||||
| }; | }; | ||||
| } | } | ||||
| @@ -100,7 +104,7 @@ namespace Discord.Audio | |||||
| internal void SetServerId(ulong serverId) | internal void SetServerId(ulong serverId) | ||||
| { | { | ||||
| _voiceSocket.ServerId = serverId; | |||||
| VoiceSocket.ServerId = serverId; | |||||
| } | } | ||||
| public async Task Join(Channel channel) | public async Task Join(Channel channel) | ||||
| { | { | ||||
| @@ -110,14 +114,14 @@ namespace Discord.Audio | |||||
| throw new InvalidOperationException("Cannot join a channel on a different server than this voice client."); | throw new InvalidOperationException("Cannot join a channel on a different server than this voice client."); | ||||
| //CheckReady(checkVoice: true); | //CheckReady(checkVoice: true); | ||||
| await _voiceSocket.Disconnect().ConfigureAwait(false); | |||||
| _voiceSocket.ChannelId = channel.Id; | |||||
| _gatewaySocket.SendUpdateVoice(channel.Server.Id, channel.Id, | |||||
| (_service.Config.Mode | AudioMode.Outgoing) == 0, | |||||
| (_service.Config.Mode | AudioMode.Incoming) == 0); | |||||
| await _voiceSocket.WaitForConnection(_service.Config.ConnectionTimeout).ConfigureAwait(false); | |||||
| await VoiceSocket.Disconnect().ConfigureAwait(false); | |||||
| VoiceSocket.ChannelId = channel.Id; | |||||
| GatewaySocket.SendUpdateVoice(channel.Server.Id, channel.Id, | |||||
| (Service.Config.Mode | AudioMode.Outgoing) == 0, | |||||
| (Service.Config.Mode | AudioMode.Incoming) == 0); | |||||
| await VoiceSocket.WaitForConnection(Service.Config.ConnectionTimeout).ConfigureAwait(false); | |||||
| } | } | ||||
| public Task Disconnect() => _voiceSocket.Disconnect(); | |||||
| public Task Disconnect() => VoiceSocket.Disconnect(); | |||||
| /// <summary> Sends a PCM frame to the voice server. Will block until space frees up in the outgoing buffer. </summary> | /// <summary> Sends a PCM frame to the voice server. Will block until space frees up in the outgoing buffer. </summary> | ||||
| /// <param name="data">PCM frame to send. This must be a single or collection of uncompressed 48Kz monochannel 20ms PCM frames. </param> | /// <param name="data">PCM frame to send. This must be a single or collection of uncompressed 48Kz monochannel 20ms PCM frames. </param> | ||||
| @@ -129,7 +133,7 @@ namespace Discord.Audio | |||||
| //CheckReady(checkVoice: true); | //CheckReady(checkVoice: true); | ||||
| if (count != 0) | if (count != 0) | ||||
| _voiceSocket.SendPCMFrames(data, count); | |||||
| VoiceSocket.SendPCMFrames(data, count); | |||||
| } | } | ||||
| /// <summary> Clears the PCM buffer. </summary> | /// <summary> Clears the PCM buffer. </summary> | ||||
| @@ -137,7 +141,7 @@ namespace Discord.Audio | |||||
| { | { | ||||
| //CheckReady(checkVoice: true); | //CheckReady(checkVoice: true); | ||||
| _voiceSocket.ClearPCMFrames(); | |||||
| VoiceSocket.ClearPCMFrames(); | |||||
| } | } | ||||
| /// <summary> Returns a task that completes once the voice output buffer is empty. </summary> | /// <summary> Returns a task that completes once the voice output buffer is empty. </summary> | ||||
| @@ -145,7 +149,7 @@ namespace Discord.Audio | |||||
| { | { | ||||
| //CheckReady(checkVoice: true); | //CheckReady(checkVoice: true); | ||||
| _voiceSocket.WaitForQueue(); | |||||
| VoiceSocket.WaitForQueue(); | |||||
| return TaskHelper.CompletedTask; | return TaskHelper.CompletedTask; | ||||
| } | } | ||||
| } | } | ||||
| @@ -4,6 +4,7 @@ using Discord.API.Client.VoiceSocket; | |||||
| using Discord.Audio; | using Discord.Audio; | ||||
| using Discord.Audio.Opus; | using Discord.Audio.Opus; | ||||
| using Discord.Audio.Sodium; | using Discord.Audio.Sodium; | ||||
| using Discord.Logging; | |||||
| using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
| using Newtonsoft.Json.Linq; | using Newtonsoft.Json.Linq; | ||||
| using System; | using System; | ||||
| @@ -24,35 +25,33 @@ namespace Discord.Net.WebSockets | |||||
| private const int MaxOpusSize = 4000; | private const int MaxOpusSize = 4000; | ||||
| private const string EncryptedMode = "xsalsa20_poly1305"; | private const string EncryptedMode = "xsalsa20_poly1305"; | ||||
| private const string UnencryptedMode = "plain"; | private const string UnencryptedMode = "plain"; | ||||
| //private readonly Random _rand; | |||||
| private readonly int _targetAudioBufferLength; | private readonly int _targetAudioBufferLength; | ||||
| private readonly ConcurrentDictionary<uint, OpusDecoder> _decoders; | private readonly ConcurrentDictionary<uint, OpusDecoder> _decoders; | ||||
| private readonly DiscordAudioClient _audioClient; | private readonly DiscordAudioClient _audioClient; | ||||
| private readonly AudioServiceConfig _config; | private readonly AudioServiceConfig _config; | ||||
| private OpusEncoder _encoder; | |||||
| private Thread _sendThread, _receiveThread; | |||||
| private VoiceBuffer _sendBuffer; | |||||
| private OpusEncoder _encoder; | |||||
| private uint _ssrc; | private uint _ssrc; | ||||
| private ConcurrentDictionary<uint, ulong> _ssrcMapping; | private ConcurrentDictionary<uint, ulong> _ssrcMapping; | ||||
| private VoiceBuffer _sendBuffer; | |||||
| private UdpClient _udp; | private UdpClient _udp; | ||||
| private IPEndPoint _endpoint; | private IPEndPoint _endpoint; | ||||
| private bool _isEncrypted; | private bool _isEncrypted; | ||||
| private byte[] _secretKey, _encodingBuffer; | private byte[] _secretKey, _encodingBuffer; | ||||
| private ushort _sequence; | private ushort _sequence; | ||||
| private ulong? _serverId, _channelId; | |||||
| private string _encryptionMode; | private string _encryptionMode; | ||||
| private int _ping; | |||||
| private Thread _sendThread, _receiveThread; | |||||
| public ulong? ServerId { get { return _serverId; } internal set { _serverId = value; } } | |||||
| public ulong? ChannelId { get { return _channelId; } internal set { _channelId = value; } } | |||||
| public int Ping => _ping; | |||||
| private int _ping; | |||||
| public string Token { get; internal set; } | |||||
| public ulong? ServerId { get; internal set; } | |||||
| public ulong? ChannelId { get; internal set; } | |||||
| public int Ping => _ping; | |||||
| internal VoiceBuffer OutputBuffer => _sendBuffer; | internal VoiceBuffer OutputBuffer => _sendBuffer; | ||||
| public VoiceWebSocket(DiscordClient client, DiscordAudioClient audioClient, Logger logger) | |||||
| : base(client, logger) | |||||
| public VoiceWebSocket(DiscordClient client, DiscordAudioClient audioClient, JsonSerializer serializer, Logger logger) | |||||
| : base(client, serializer, logger) | |||||
| { | { | ||||
| _audioClient = audioClient; | _audioClient = audioClient; | ||||
| _config = client.Audio().Config; | _config = client.Audio().Config; | ||||
| @@ -84,7 +83,7 @@ namespace Discord.Net.WebSockets | |||||
| catch (OperationCanceledException) { throw; } | catch (OperationCanceledException) { throw; } | ||||
| catch (Exception ex) | catch (Exception ex) | ||||
| { | { | ||||
| _logger.Error("Reconnect failed", ex); | |||||
| Logger.Error("Reconnect failed", ex); | |||||
| //Net is down? We can keep trying to reconnect until the user runs Disconnect() | //Net is down? We can keep trying to reconnect until the user runs Disconnect() | ||||
| await Task.Delay(_client.Config.FailedReconnectDelay, cancelToken).ConfigureAwait(false); | await Task.Delay(_client.Config.FailedReconnectDelay, cancelToken).ConfigureAwait(false); | ||||
| } | } | ||||
| @@ -101,14 +100,14 @@ namespace Discord.Net.WebSockets | |||||
| List<Task> tasks = new List<Task>(); | List<Task> tasks = new List<Task>(); | ||||
| if ((_config.Mode & AudioMode.Outgoing) != 0) | if ((_config.Mode & AudioMode.Outgoing) != 0) | ||||
| { | { | ||||
| _sendThread = new Thread(new ThreadStart(() => SendVoiceAsync(_cancelToken))); | |||||
| _sendThread = new Thread(new ThreadStart(() => SendVoiceAsync(CancelToken))); | |||||
| _sendThread.IsBackground = true; | _sendThread.IsBackground = true; | ||||
| _sendThread.Start(); | _sendThread.Start(); | ||||
| } | } | ||||
| if ((_config.Mode & AudioMode.Incoming) != 0) | if ((_config.Mode & AudioMode.Incoming) != 0) | ||||
| { | { | ||||
| _receiveThread = new Thread(new ThreadStart(() => ReceiveVoiceAsync(_cancelToken))); | |||||
| _receiveThread.IsBackground = true; | |||||
| _receiveThread = new Thread(new ThreadStart(() => ReceiveVoiceAsync(CancelToken))); | |||||
| _receiveThread.IsBackground = true; | |||||
| _receiveThread.Start(); | _receiveThread.Start(); | ||||
| } | } | ||||
| @@ -117,8 +116,8 @@ namespace Discord.Net.WebSockets | |||||
| #if !DOTNET5_4 | #if !DOTNET5_4 | ||||
| tasks.Add(WatcherAsync()); | tasks.Add(WatcherAsync()); | ||||
| #endif | #endif | ||||
| tasks.AddRange(_engine.GetTasks(_cancelToken)); | |||||
| tasks.Add(HeartbeatAsync(_cancelToken)); | |||||
| tasks.AddRange(_engine.GetTasks(CancelToken)); | |||||
| tasks.Add(HeartbeatAsync(CancelToken)); | |||||
| await _taskManager.Start(tasks, _cancelTokenSource).ConfigureAwait(false); | await _taskManager.Start(tasks, _cancelTokenSource).ConfigureAwait(false); | ||||
| } | } | ||||
| protected override Task Cleanup() | protected override Task Cleanup() | ||||
| @@ -179,7 +178,7 @@ namespace Discord.Net.WebSockets | |||||
| if (packetLength > 0 && endpoint.Equals(_endpoint)) | if (packetLength > 0 && endpoint.Equals(_endpoint)) | ||||
| { | { | ||||
| if (_state != ConnectionState.Connected) | |||||
| if (State != ConnectionState.Connected) | |||||
| { | { | ||||
| if (packetLength != 70) | if (packetLength != 70) | ||||
| return; | return; | ||||
| @@ -235,7 +234,7 @@ namespace Discord.Net.WebSockets | |||||
| ulong userId; | ulong userId; | ||||
| if (_ssrcMapping.TryGetValue(ssrc, out userId)) | if (_ssrcMapping.TryGetValue(ssrc, out userId)) | ||||
| RaiseOnPacket(userId, _channelId.Value, result, resultOffset, resultLength); | |||||
| RaiseOnPacket(userId, ChannelId.Value, result, resultOffset, resultLength); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -249,7 +248,7 @@ namespace Discord.Net.WebSockets | |||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| while (!cancelToken.IsCancellationRequested && _state != ConnectionState.Connected) | |||||
| while (!cancelToken.IsCancellationRequested && State != ConnectionState.Connected) | |||||
| Thread.Sleep(1); | Thread.Sleep(1); | ||||
| if (cancelToken.IsCancellationRequested) | if (cancelToken.IsCancellationRequested) | ||||
| @@ -353,7 +352,7 @@ namespace Discord.Net.WebSockets | |||||
| } | } | ||||
| catch (SocketException ex) | catch (SocketException ex) | ||||
| { | { | ||||
| _logger.Error("Failed to send UDP packet.", ex); | |||||
| Logger.Error("Failed to send UDP packet.", ex); | |||||
| } | } | ||||
| hasFrame = false; | hasFrame = false; | ||||
| } | } | ||||
| @@ -385,11 +384,7 @@ namespace Discord.Net.WebSockets | |||||
| #if !DOTNET5_4 | #if !DOTNET5_4 | ||||
| //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 Task WatcherAsync() | private Task WatcherAsync() | ||||
| { | |||||
| var cancelToken = _cancelToken; | |||||
| return cancelToken.Wait() | |||||
| .ContinueWith(_ => _udp.Close()); | |||||
| } | |||||
| => CancelToken.Wait().ContinueWith(_ => _udp.Close()); | |||||
| #endif | #endif | ||||
| protected override async Task ProcessMessage(string json) | protected override async Task ProcessMessage(string json) | ||||
| @@ -401,7 +396,7 @@ namespace Discord.Net.WebSockets | |||||
| { | { | ||||
| case OpCodes.Ready: | case OpCodes.Ready: | ||||
| { | { | ||||
| if (_state != ConnectionState.Connected) | |||||
| if (State != ConnectionState.Connected) | |||||
| { | { | ||||
| var payload = (msg.Payload as JToken).ToObject<ReadyEvent>(_serializer); | var payload = (msg.Payload as JToken).ToObject<ReadyEvent>(_serializer); | ||||
| _heartbeatInterval = payload.HeartbeatInterval; | _heartbeatInterval = payload.HeartbeatInterval; | ||||
| @@ -460,24 +455,23 @@ namespace Discord.Net.WebSockets | |||||
| } | } | ||||
| break; | break; | ||||
| default: | default: | ||||
| if (_logger.Level >= LogSeverity.Warning) | |||||
| _logger.Warning($"Unknown Opcode: {opCode}"); | |||||
| Logger.Warning($"Unknown Opcode: {opCode}"); | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| public void SendPCMFrames(byte[] data, int bytes) | public void SendPCMFrames(byte[] data, int bytes) | ||||
| { | { | ||||
| _sendBuffer.Push(data, bytes, _cancelToken); | |||||
| _sendBuffer.Push(data, bytes, CancelToken); | |||||
| } | } | ||||
| public void ClearPCMFrames() | public void ClearPCMFrames() | ||||
| { | { | ||||
| _sendBuffer.Clear(_cancelToken); | |||||
| _sendBuffer.Clear(CancelToken); | |||||
| } | } | ||||
| public void WaitForQueue() | public void WaitForQueue() | ||||
| { | { | ||||
| _sendBuffer.Wait(_cancelToken); | |||||
| _sendBuffer.Wait(CancelToken); | |||||
| } | } | ||||
| public Task WaitForConnection(int timeout) | public Task WaitForConnection(int timeout) | ||||
| { | { | ||||
| @@ -485,7 +479,7 @@ namespace Discord.Net.WebSockets | |||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| if (!_connectedEvent.Wait(timeout, _cancelToken)) | |||||
| if (!_connectedEvent.Wait(timeout, CancelToken)) | |||||
| throw new TimeoutException(); | throw new TimeoutException(); | ||||
| } | } | ||||
| catch (OperationCanceledException) | catch (OperationCanceledException) | ||||
| @@ -498,9 +492,11 @@ namespace Discord.Net.WebSockets | |||||
| public override void SendHeartbeat() | public override void SendHeartbeat() | ||||
| => QueueMessage(new HeartbeatCommand()); | => QueueMessage(new HeartbeatCommand()); | ||||
| public void SendIdentify() | public void SendIdentify() | ||||
| => QueueMessage(new IdentifyCommand { GuildId = _serverId.Value, UserId = _client.UserId.Value, SessionId = _client.SessionId, Token = _audioClient.Token }); | |||||
| => QueueMessage(new IdentifyCommand { GuildId = ServerId.Value, UserId = _client.CurrentUser.Id, | |||||
| SessionId = _client.SessionId, Token = Token }); | |||||
| public void SendSelectProtocol(string externalAddress, int externalPort) | public void SendSelectProtocol(string externalAddress, int externalPort) | ||||
| => QueueMessage(new SelectProtocolCommand { Protocol = "udp", ExternalAddress = externalAddress, ExternalPort = externalPort, EncryptionMode = _encryptionMode }); | |||||
| => QueueMessage(new SelectProtocolCommand { Protocol = "udp", ExternalAddress = externalAddress, | |||||
| ExternalPort = externalPort, EncryptionMode = _encryptionMode }); | |||||
| public void SendSetSpeaking(bool value) | public void SendSetSpeaking(bool value) | ||||
| => QueueMessage(new SetSpeakingCommand { IsSpeaking = value, Delay = 0 }); | => QueueMessage(new SetSpeakingCommand { IsSpeaking = value, Delay = 0 }); | ||||
| @@ -56,6 +56,8 @@ namespace Discord | |||||
| internal User PrivateUser { get; private set; } | internal User PrivateUser { get; private set; } | ||||
| /// <summary> Gets information about the current logged-in account. </summary> | /// <summary> Gets information about the current logged-in account. </summary> | ||||
| public Profile CurrentUser { get; private set; } | public Profile CurrentUser { get; private set; } | ||||
| /// <summary> Gets the session id for the current connection. </summary> | |||||
| public string SessionId { get; private set; } | |||||
| /// <summary> Gets the status of the current user. </summary> | /// <summary> Gets the status of the current user. </summary> | ||||
| public UserStatus Status { get; private set; } | public UserStatus Status { get; private set; } | ||||
| /// <summary> Gets the game this current user is reported as playing. </summary> | /// <summary> Gets the game this current user is reported as playing. </summary> | ||||
| @@ -448,7 +450,7 @@ namespace Discord | |||||
| case "READY": //Resync | case "READY": //Resync | ||||
| { | { | ||||
| var data = e.Payload.ToObject<ReadyEvent>(_serializer); | var data = e.Payload.ToObject<ReadyEvent>(_serializer); | ||||
| //SessionId = data.SessionId; | |||||
| SessionId = data.SessionId; | |||||
| PrivateUser = new User(this, data.User.Id, null); | PrivateUser = new User(this, data.User.Id, null); | ||||
| PrivateUser.Update(data.User); | PrivateUser.Update(data.User); | ||||
| CurrentUser.Update(data.User); | CurrentUser.Update(data.User); | ||||
| @@ -22,7 +22,7 @@ namespace Discord.Net.WebSockets | |||||
| private DateTime _lastHeartbeat; | private DateTime _lastHeartbeat; | ||||
| /// <summary> Gets the logger used for this client. </summary> | /// <summary> Gets the logger used for this client. </summary> | ||||
| internal Logger Logger { get; } | |||||
| protected internal Logger Logger { get; } | |||||
| public CancellationToken CancelToken { get; private set; } | public CancellationToken CancelToken { get; private set; } | ||||