diff --git a/src/Discord.Net.Audio/AudioConfig.cs b/src/Discord.Net.Audio/AudioConfig.cs
deleted file mode 100644
index 43db99020..000000000
--- a/src/Discord.Net.Audio/AudioConfig.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using Discord.Net.WebSockets;
-
-namespace Discord.Audio
-{
- public class AudioConfig
- {
- /// Gets or sets the time (in milliseconds) to wait for the websocket to connect and initialize.
- public int ConnectionTimeout { get; set; } = 30000;
- /// Gets or sets the time (in milliseconds) to wait after an unexpected disconnect before reconnecting.
- public int ReconnectDelay { get; set; } = 1000;
- /// Gets or sets the time (in milliseconds) to wait after an reconnect fails before retrying.
- public int FailedReconnectDelay { get; set; } = 15000;
-
- /// Gets or sets the provider used to generate new websocket connections.
- public WebSocketProvider WebSocketProvider { get; set; } = () => new DefaultWebSocketClient();
- }
-}
diff --git a/src/Discord.Net.Audio/Discord.Net.Audio.xproj b/src/Discord.Net.Audio/Discord.Net.Audio.xproj
deleted file mode 100644
index 7434ce9ff..000000000
--- a/src/Discord.Net.Audio/Discord.Net.Audio.xproj
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
- 14.0.25123
- $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
-
-
-
- ddfcc44f-934e-478a-978c-69cdda2a1c5b
- Discord.Audio
- .\obj
- .\bin\
-
-
- 2.0
-
-
-
\ No newline at end of file
diff --git a/src/Discord.Net.Audio/Logger.cs b/src/Discord.Net.Audio/Logger.cs
deleted file mode 100644
index cdb3b5fa6..000000000
--- a/src/Discord.Net.Audio/Logger.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Discord.Audio
-{
- internal class Logger
- {
- }
-}
\ No newline at end of file
diff --git a/src/Discord.Net.Audio/Utilities/AsyncEvent.cs b/src/Discord.Net.Audio/Utilities/AsyncEvent.cs
deleted file mode 100644
index e94b1d892..000000000
--- a/src/Discord.Net.Audio/Utilities/AsyncEvent.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Threading.Tasks;
-
-namespace Discord
-{
- public class AsyncEvent
- {
- private readonly object _subLock = new object();
- internal ImmutableArray _subscriptions;
-
- public IReadOnlyList Subscriptions => _subscriptions;
-
- public AsyncEvent()
- {
- _subscriptions = ImmutableArray.Create();
- }
-
- public void Add(T subscriber)
- {
- lock (_subLock)
- _subscriptions = _subscriptions.Add(subscriber);
- }
- public void Remove(T subscriber)
- {
- lock (_subLock)
- _subscriptions = _subscriptions.Remove(subscriber);
- }
- }
-
- public static class EventExtensions
- {
- public static async Task InvokeAsync(this AsyncEvent> eventHandler)
- {
- var subscribers = eventHandler.Subscriptions;
- if (subscribers.Count > 0)
- {
- for (int i = 0; i < subscribers.Count; i++)
- await subscribers[i].Invoke().ConfigureAwait(false);
- }
- }
- public static async Task InvokeAsync(this AsyncEvent> eventHandler, T arg)
- {
- var subscribers = eventHandler.Subscriptions;
- for (int i = 0; i < subscribers.Count; i++)
- await subscribers[i].Invoke(arg).ConfigureAwait(false);
- }
- public static async Task InvokeAsync(this AsyncEvent> eventHandler, T1 arg1, T2 arg2)
- {
- var subscribers = eventHandler.Subscriptions;
- for (int i = 0; i < subscribers.Count; i++)
- await subscribers[i].Invoke(arg1, arg2).ConfigureAwait(false);
- }
- public static async Task InvokeAsync(this AsyncEvent> eventHandler, T1 arg1, T2 arg2, T3 arg3)
- {
- var subscribers = eventHandler.Subscriptions;
- for (int i = 0; i < subscribers.Count; i++)
- await subscribers[i].Invoke(arg1, arg2, arg3).ConfigureAwait(false);
- }
- public static async Task InvokeAsync(this AsyncEvent> eventHandler, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
- {
- var subscribers = eventHandler.Subscriptions;
- for (int i = 0; i < subscribers.Count; i++)
- await subscribers[i].Invoke(arg1, arg2, arg3, arg4).ConfigureAwait(false);
- }
- public static async Task InvokeAsync(this AsyncEvent> eventHandler, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
- {
- var subscribers = eventHandler.Subscriptions;
- for (int i = 0; i < subscribers.Count; i++)
- await subscribers[i].Invoke(arg1, arg2, arg3, arg4, arg5).ConfigureAwait(false);
- }
- }
-}
diff --git a/src/Discord.Net.Audio/project.json b/src/Discord.Net.Audio/project.json
deleted file mode 100644
index c7788f942..000000000
--- a/src/Discord.Net.Audio/project.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "version": "1.0.0-dev",
- "description": "A Discord.Net extension adding audio support.",
- "authors": [ "RogueException" ],
-
- "packOptions": {
- "tags": [ "discord", "discordapp" ],
- "licenseUrl": "http://opensource.org/licenses/MIT",
- "projectUrl": "https://github.com/RogueException/Discord.Net",
- "repository": {
- "type": "git",
- "url": "git://github.com/RogueException/Discord.Net"
- }
- },
-
- "buildOptions": {
- "allowUnsafe": true,
- "warningsAsErrors": false
- },
-
- "dependencies": {
- "Discord.Net": "1.0.0-dev",
- "System.Runtime.InteropServices": "4.1.0"
- },
-
- "frameworks": {
- "netstandard1.3": {
- "imports": [
- "dotnet5.4",
- "dnxcore50",
- "portable-net45+win8"
- ]
- }
- }
-}
diff --git a/src/Discord.Net/API/DiscordAPIClient.cs b/src/Discord.Net/API/DiscordAPIClient.cs
index 2a0b4c02e..128c15474 100644
--- a/src/Discord.Net/API/DiscordAPIClient.cs
+++ b/src/Discord.Net/API/DiscordAPIClient.cs
@@ -398,6 +398,17 @@ namespace Discord.API
{
await SendGatewayAsync(GatewayOpCode.RequestGuildMembers, new RequestMembersParams { GuildIds = guildIds, Query = "", Limit = 0 }, options: options).ConfigureAwait(false);
}
+ public async Task SendVoiceStateUpdateAsync(ulong guildId, ulong? channelId, bool selfDeaf, bool selfMute, RequestOptions options = null)
+ {
+ var payload = new VoiceStateUpdateParams
+ {
+ GuildId = guildId,
+ ChannelId = channelId,
+ SelfDeaf = selfDeaf,
+ SelfMute = selfMute
+ };
+ await SendGatewayAsync(GatewayOpCode.VoiceStateUpdate, payload, options: options).ConfigureAwait(false);
+ }
//Channels
public async Task GetChannelAsync(ulong channelId, RequestOptions options = null)
diff --git a/src/Discord.Net.Audio/AudioAPIClient.cs b/src/Discord.Net/API/DiscordVoiceAPIClient.cs
similarity index 97%
rename from src/Discord.Net.Audio/AudioAPIClient.cs
rename to src/Discord.Net/API/DiscordVoiceAPIClient.cs
index db3418610..e64d74c10 100644
--- a/src/Discord.Net.Audio/AudioAPIClient.cs
+++ b/src/Discord.Net/API/DiscordVoiceAPIClient.cs
@@ -14,7 +14,7 @@ using System.Threading.Tasks;
namespace Discord.Audio
{
- public class AudioAPIClient
+ public class DiscordVoiceAPIClient
{
public const int MaxBitrate = 128;
private const string Mode = "xsalsa20_poly1305";
@@ -40,7 +40,7 @@ namespace Discord.Audio
public string SessionId { get; }
public ConnectionState ConnectionState { get; private set; }
- internal AudioAPIClient(ulong guildId, ulong userId, string sessionId, string token, WebSocketProvider webSocketProvider, JsonSerializer serializer = null)
+ internal DiscordVoiceAPIClient(ulong guildId, ulong userId, string sessionId, string token, WebSocketProvider webSocketProvider, JsonSerializer serializer = null)
{
GuildId = guildId;
_userId = userId;
diff --git a/src/Discord.Net/API/Gateway/GuildEmojiUpdateEvent.cs b/src/Discord.Net/API/Gateway/GuildEmojiUpdateEvent.cs
new file mode 100644
index 000000000..13f083d40
--- /dev/null
+++ b/src/Discord.Net/API/Gateway/GuildEmojiUpdateEvent.cs
@@ -0,0 +1,12 @@
+using Newtonsoft.Json;
+
+namespace Discord.API.Gateway
+{
+ public class GuildEmojiUpdateEvent
+ {
+ [JsonProperty("guild_id")]
+ public ulong GuildId;
+ [JsonProperty("emojis")]
+ public Emoji[] Emojis;
+ }
+}
diff --git a/src/Discord.Net/API/Gateway/RequestMembersParams.cs b/src/Discord.Net/API/Gateway/RequestMembersParams.cs
index f11be49b1..a0819c556 100644
--- a/src/Discord.Net/API/Gateway/RequestMembersParams.cs
+++ b/src/Discord.Net/API/Gateway/RequestMembersParams.cs
@@ -1,15 +1,19 @@
using Newtonsoft.Json;
using System.Collections.Generic;
+using System.Linq;
namespace Discord.API.Gateway
{
public class RequestMembersParams
{
- [JsonProperty("guild_id")]
- public IEnumerable GuildIds { get; set; }
[JsonProperty("query")]
public string Query { get; set; }
[JsonProperty("limit")]
public int Limit { get; set; }
+
+ [JsonProperty("guild_id")]
+ public IEnumerable GuildIds { get; set; }
+ [JsonIgnore]
+ public IEnumerable Guilds { set { GuildIds = value.Select(x => x.Id); } }
}
}
diff --git a/src/Discord.Net/API/Gateway/UpdateVoiceParams.cs b/src/Discord.Net/API/Gateway/UpdateVoiceParams.cs
deleted file mode 100644
index d72d63548..000000000
--- a/src/Discord.Net/API/Gateway/UpdateVoiceParams.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Newtonsoft.Json;
-
-namespace Discord.API.Gateway
-{
- public class UpdateVoiceParams
- {
- [JsonProperty("guild_id")]
- public ulong? GuildId { get; set; }
- [JsonProperty("channel_id")]
- public ulong? ChannelId { get; set; }
- [JsonProperty("self_mute")]
- public bool IsSelfMuted { get; set; }
- [JsonProperty("self_deaf")]
- public bool IsSelfDeafened { get; set; }
- }
-}
diff --git a/src/Discord.Net/API/Gateway/VoiceStateUpdateParams.cs b/src/Discord.Net/API/Gateway/VoiceStateUpdateParams.cs
new file mode 100644
index 000000000..6eb285cea
--- /dev/null
+++ b/src/Discord.Net/API/Gateway/VoiceStateUpdateParams.cs
@@ -0,0 +1,21 @@
+using Newtonsoft.Json;
+
+namespace Discord.API.Gateway
+{
+ public class VoiceStateUpdateParams
+ {
+ [JsonProperty("self_mute")]
+ public bool SelfMute { get; set; }
+ [JsonProperty("self_deaf")]
+ public bool SelfDeaf { get; set; }
+
+ [JsonProperty("guild_id")]
+ public ulong GuildId { get; set; }
+ [JsonIgnore]
+ public IGuild Guild { set { GuildId = value.Id; } }
+ [JsonProperty("channel_id")]
+ public ulong? ChannelId { get; set; }
+ [JsonIgnore]
+ public IChannel Channel { set { ChannelId = value?.Id; } }
+ }
+}
diff --git a/src/Discord.Net.Audio/AudioClient.cs b/src/Discord.Net/Audio/AudioClient.cs
similarity index 91%
rename from src/Discord.Net.Audio/AudioClient.cs
rename to src/Discord.Net/Audio/AudioClient.cs
index 7f9298ed0..854c3219b 100644
--- a/src/Discord.Net.Audio/AudioClient.cs
+++ b/src/Discord.Net/Audio/AudioClient.cs
@@ -1,15 +1,15 @@
using Discord.API.Voice;
using Discord.Logging;
using Discord.Net.Converters;
+using Discord.Net.WebSockets;
using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Discord.Audio
{
- public class AudioClient
+ internal class AudioClient : IAudioClient
{
public event Func Connected
{
@@ -30,12 +30,11 @@ namespace Discord.Audio
}
private readonly AsyncEvent> _latencyUpdatedEvent = new AsyncEvent>();
- private readonly ILogger _webSocketLogger;
+ private readonly ILogger _webSocketLogger, _udpLogger;
#if BENCHMARK
private readonly ILogger _benchmarkLogger;
#endif
private readonly JsonSerializer _serializer;
- private readonly int _connectionTimeout, _reconnectDelay, _failedReconnectDelay;
internal readonly SemaphoreSlim _connectionLock;
private TaskCompletionSource _connectTask;
@@ -45,20 +44,18 @@ namespace Discord.Audio
private bool _isReconnecting;
private string _url;
- public AudioAPIClient ApiClient { get; private set; }
- /// Gets the current connection state of this client.
+ private DiscordSocketClient Discord { get; }
+ public DiscordVoiceAPIClient ApiClient { get; private set; }
public ConnectionState ConnectionState { get; private set; }
- /// Gets the estimated round-trip latency, in milliseconds, to the gateway server.
public int Latency { get; private set; }
/// Creates a new REST/WebSocket discord client.
- internal AudioClient(ulong guildId, ulong userId, string sessionId, string token, AudioConfig config, ILogManager logManager)
+ internal AudioClient(DiscordSocketClient discord, ulong guildId, ulong userId, string sessionId, string token, WebSocketProvider webSocketProvider, ILogManager logManager)
{
- _connectionTimeout = config.ConnectionTimeout;
- _reconnectDelay = config.ReconnectDelay;
- _failedReconnectDelay = config.FailedReconnectDelay;
+ Discord = discord;
- _webSocketLogger = logManager.CreateLogger("AudioWS");
+ _webSocketLogger = logManager.CreateLogger("Audio");
+ _udpLogger = logManager.CreateLogger("AudioUDP");
#if BENCHMARK
_benchmarkLogger = logManager.CreateLogger("Benchmark");
#endif
@@ -72,8 +69,7 @@ namespace Discord.Audio
e.ErrorContext.Handled = true;
};
- var webSocketProvider = config.WebSocketProvider; //TODO: Clean this check
- ApiClient = new AudioAPIClient(guildId, userId, sessionId, token, config.WebSocketProvider);
+ ApiClient = new DiscordVoiceAPIClient(guildId, userId, sessionId, token, webSocketProvider);
ApiClient.SentGatewayMessage += async opCode => await _webSocketLogger.DebugAsync($"Sent {(VoiceOpCode)opCode}").ConfigureAwait(false);
ApiClient.ReceivedEvent += ProcessMessageAsync;
diff --git a/src/Discord.Net.Audio/AudioMode.cs b/src/Discord.Net/Audio/AudioMode.cs
similarity index 62%
rename from src/Discord.Net.Audio/AudioMode.cs
rename to src/Discord.Net/Audio/AudioMode.cs
index b9acdbf89..7cc5a08c1 100644
--- a/src/Discord.Net.Audio/AudioMode.cs
+++ b/src/Discord.Net/Audio/AudioMode.cs
@@ -1,7 +1,11 @@
-namespace Discord.Audio
+using System;
+
+namespace Discord.Audio
{
+ [Flags]
public enum AudioMode : byte
{
+ Disabled = 0,
Outgoing = 1,
Incoming = 2,
Both = Outgoing | Incoming
diff --git a/src/Discord.Net/Audio/IAudioClient.cs b/src/Discord.Net/Audio/IAudioClient.cs
new file mode 100644
index 000000000..5f59851ee
--- /dev/null
+++ b/src/Discord.Net/Audio/IAudioClient.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Discord.Audio
+{
+ public interface IAudioClient
+ {
+ event Func Connected;
+ event Func Disconnected;
+ event Func LatencyUpdated;
+
+ DiscordVoiceAPIClient ApiClient { get; }
+ /// Gets the current connection state of this client.
+ ConnectionState ConnectionState { get; }
+ /// Gets the estimated round-trip latency, in milliseconds, to the gateway server.
+ int Latency { get; }
+
+ Task DisconnectAsync();
+ }
+}
diff --git a/src/Discord.Net.Audio/Opus/Ctl.cs b/src/Discord.Net/Audio/Opus/Ctl.cs
similarity index 100%
rename from src/Discord.Net.Audio/Opus/Ctl.cs
rename to src/Discord.Net/Audio/Opus/Ctl.cs
diff --git a/src/Discord.Net.Audio/Opus/OpusApplication.cs b/src/Discord.Net/Audio/Opus/OpusApplication.cs
similarity index 100%
rename from src/Discord.Net.Audio/Opus/OpusApplication.cs
rename to src/Discord.Net/Audio/Opus/OpusApplication.cs
diff --git a/src/Discord.Net.Audio/Opus/OpusConverter.cs b/src/Discord.Net/Audio/Opus/OpusConverter.cs
similarity index 100%
rename from src/Discord.Net.Audio/Opus/OpusConverter.cs
rename to src/Discord.Net/Audio/Opus/OpusConverter.cs
diff --git a/src/Discord.Net.Audio/Opus/OpusDecoder.cs b/src/Discord.Net/Audio/Opus/OpusDecoder.cs
similarity index 100%
rename from src/Discord.Net.Audio/Opus/OpusDecoder.cs
rename to src/Discord.Net/Audio/Opus/OpusDecoder.cs
diff --git a/src/Discord.Net.Audio/Opus/OpusEncoder.cs b/src/Discord.Net/Audio/Opus/OpusEncoder.cs
similarity index 97%
rename from src/Discord.Net.Audio/Opus/OpusEncoder.cs
rename to src/Discord.Net/Audio/Opus/OpusEncoder.cs
index 2e1d4d861..e17487f43 100644
--- a/src/Discord.Net.Audio/Opus/OpusEncoder.cs
+++ b/src/Discord.Net/Audio/Opus/OpusEncoder.cs
@@ -36,7 +36,7 @@ namespace Discord.Audio.Opus
{
if (channels != 1 && channels != 2)
throw new ArgumentOutOfRangeException(nameof(channels));
- if (bitrate != null && (bitrate < 1 || bitrate > AudioAPIClient.MaxBitrate))
+ if (bitrate != null && (bitrate < 1 || bitrate > DiscordVoiceAPIClient.MaxBitrate))
throw new ArgumentOutOfRangeException(nameof(bitrate));
OpusError error;
diff --git a/src/Discord.Net.Audio/Opus/OpusError.cs b/src/Discord.Net/Audio/Opus/OpusError.cs
similarity index 100%
rename from src/Discord.Net.Audio/Opus/OpusError.cs
rename to src/Discord.Net/Audio/Opus/OpusError.cs
diff --git a/src/Discord.Net.Audio/LibSodium.cs b/src/Discord.Net/Audio/Sodium/SecretBox.cs
similarity index 93%
rename from src/Discord.Net.Audio/LibSodium.cs
rename to src/Discord.Net/Audio/Sodium/SecretBox.cs
index 3b4129165..727db2711 100644
--- a/src/Discord.Net.Audio/LibSodium.cs
+++ b/src/Discord.Net/Audio/Sodium/SecretBox.cs
@@ -1,8 +1,8 @@
using System.Runtime.InteropServices;
-namespace Discord.Net.Audio
+namespace Discord.Net.Audio.Sodium
{
- public unsafe static class LibSodium
+ public unsafe static class SecretBox
{
[DllImport("libsodium", EntryPoint = "crypto_secretbox_easy", CallingConvention = CallingConvention.Cdecl)]
private static extern int SecretBoxEasy(byte* output, byte[] input, long inputLength, byte[] nonce, byte[] secret);
diff --git a/src/Discord.Net/DiscordSocketClient.Events.cs b/src/Discord.Net/DiscordSocketClient.Events.cs
index b4d4db47d..545f3a4fb 100644
--- a/src/Discord.Net/DiscordSocketClient.Events.cs
+++ b/src/Discord.Net/DiscordSocketClient.Events.cs
@@ -3,6 +3,7 @@ using System.Threading.Tasks;
namespace Discord
{
+ //TODO: Add event docstrings
public partial class DiscordSocketClient
{
//General
diff --git a/src/Discord.Net/DiscordSocketClient.cs b/src/Discord.Net/DiscordSocketClient.cs
index 01a9ae88c..d09675e18 100644
--- a/src/Discord.Net/DiscordSocketClient.cs
+++ b/src/Discord.Net/DiscordSocketClient.cs
@@ -1,7 +1,9 @@
using Discord.API.Gateway;
+using Discord.Audio;
using Discord.Extensions;
using Discord.Logging;
using Discord.Net.Converters;
+using Discord.Net.WebSockets;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
@@ -14,9 +16,6 @@ using System.Threading.Tasks;
namespace Discord
{
- //TODO: Add event docstrings
- //TODO: Add reconnect logic (+ensure the heartbeat task to shut down)
- //TODO: Add resume logic
public partial class DiscordSocketClient : DiscordClient, IDiscordClient
{
private readonly ConcurrentQueue _largeGuilds;
@@ -25,9 +24,6 @@ namespace Discord
private readonly ILogger _benchmarkLogger;
#endif
private readonly JsonSerializer _serializer;
- private readonly int _connectionTimeout, _reconnectDelay, _failedReconnectDelay;
- private readonly int _largeThreshold;
- private readonly int _totalShards;
private string _sessionId;
private int _lastSeq;
@@ -46,9 +42,17 @@ namespace Discord
public ConnectionState ConnectionState { get; private set; }
/// Gets the estimated round-trip latency, in milliseconds, to the gateway server.
public int Latency { get; private set; }
-
+
+ //From DiscordConfig
+ internal int TotalShards { get; private set; }
+ internal int ConnectionTimeout { get; private set; }
+ internal int ReconnectDelay { get; private set; }
+ internal int FailedReconnectDelay { get; private set; }
internal int MessageCacheSize { get; private set; }
+ internal int LargeThreshold { get; private set; }
+ internal AudioMode AudioMode { get; private set; }
internal DataStore DataStore { get; private set; }
+ internal WebSocketProvider WebSocketProvider { get; private set; }
internal CachedSelfUser CurrentUser => _currentUser as CachedSelfUser;
internal IReadOnlyCollection Guilds => DataStore.Guilds;
@@ -62,15 +66,15 @@ namespace Discord
: base(config)
{
ShardId = config.ShardId;
- _totalShards = config.TotalShards;
-
- _connectionTimeout = config.ConnectionTimeout;
- _reconnectDelay = config.ReconnectDelay;
- _failedReconnectDelay = config.FailedReconnectDelay;
-
+ TotalShards = config.TotalShards;
+ ConnectionTimeout = config.ConnectionTimeout;
+ ReconnectDelay = config.ReconnectDelay;
+ FailedReconnectDelay = config.FailedReconnectDelay;
MessageCacheSize = config.MessageCacheSize;
- _largeThreshold = config.LargeThreshold;
-
+ LargeThreshold = config.LargeThreshold;
+ AudioMode = config.AudioMode;
+ WebSocketProvider = config.WebSocketProvider;
+
_gatewayLogger = _log.CreateLogger("Gateway");
#if BENCHMARK
_benchmarkLogger = _log.CreateLogger("Benchmark");
@@ -471,7 +475,7 @@ namespace Discord
case GatewayOpCode.Dispatch:
switch (type)
{
- //Global
+ //Connection
case "READY":
{
await _gatewayLogger.DebugAsync("Received Dispatch (READY)").ConfigureAwait(false);
@@ -507,6 +511,11 @@ namespace Discord
await _gatewayLogger.InfoAsync("Ready").ConfigureAwait(false);
}
break;
+ case "RESUMED":
+ await _gatewayLogger.DebugAsync("Received Dispatch (RESUMED)").ConfigureAwait(false);
+
+ await _gatewayLogger.InfoAsync("Resume").ConfigureAwait(false);
+ return;
//Guilds
case "GUILD_CREATE":
@@ -569,6 +578,28 @@ namespace Discord
}
}
break;
+ case "GUILD_EMOJI_UPDATE": //TODO: Add
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_EMOJI_UPDATE)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = DataStore.GetGuild(data.GuildId);
+ if (guild != null)
+ {
+ var before = guild.Clone();
+ guild.Update(data, UpdateSource.WebSocket);
+ await _guildUpdatedEvent.InvokeAsync(before, guild).ConfigureAwait(false);
+ }
+ else
+ {
+ await _gatewayLogger.WarningAsync("GUILD_EMOJI_UPDATE referenced an unknown guild.").ConfigureAwait(false);
+ return;
+ }
+ }
+ return;
+ case "GUILD_INTEGRATIONS_UPDATE":
+ await _gatewayLogger.DebugAsync("Ignored Dispatch (GUILD_INTEGRATIONS_UPDATE)").ConfigureAwait(false);
+ return;
case "GUILD_DELETE":
{
var data = (payload as JToken).ToObject(_serializer);
@@ -1099,26 +1130,17 @@ namespace Discord
}
}
break;
+ case "VOICE_SERVER_UPDATE":
+ await _gatewayLogger.DebugAsync("Ignored Dispatch (VOICE_SERVER_UPDATE)").ConfigureAwait(false);
+ return;
- //Ignored
+ //Ignored (User only)
case "USER_SETTINGS_UPDATE":
await _gatewayLogger.DebugAsync("Ignored Dispatch (USER_SETTINGS_UPDATE)").ConfigureAwait(false);
return;
- case "MESSAGE_ACK": //TODO: Add (User only)
+ case "MESSAGE_ACK":
await _gatewayLogger.DebugAsync("Ignored Dispatch (MESSAGE_ACK)").ConfigureAwait(false);
return;
- case "GUILD_EMOJIS_UPDATE": //TODO: Add
- await _gatewayLogger.DebugAsync("Ignored Dispatch (GUILD_EMOJIS_UPDATE)").ConfigureAwait(false);
- return;
- case "GUILD_INTEGRATIONS_UPDATE": //TODO: Add
- await _gatewayLogger.DebugAsync("Ignored Dispatch (GUILD_INTEGRATIONS_UPDATE)").ConfigureAwait(false);
- return;
- case "VOICE_SERVER_UPDATE": //TODO: Add
- await _gatewayLogger.DebugAsync("Ignored Dispatch (VOICE_SERVER_UPDATE)").ConfigureAwait(false);
- return;
- case "RESUMED": //TODO: Add
- await _gatewayLogger.DebugAsync("Ignored Dispatch (RESUMED)").ConfigureAwait(false);
- return;
//Others
default:
diff --git a/src/Discord.Net/DiscordSocketConfig.cs b/src/Discord.Net/DiscordSocketConfig.cs
index a40fba0e7..cd54fcd8d 100644
--- a/src/Discord.Net/DiscordSocketConfig.cs
+++ b/src/Discord.Net/DiscordSocketConfig.cs
@@ -1,4 +1,5 @@
-using Discord.Net.WebSockets;
+using Discord.Audio;
+using Discord.Net.WebSockets;
namespace Discord
{
@@ -28,7 +29,10 @@ namespace Discord
/// Decreasing this may reduce CPU usage while increasing login time and network usage.
///
public int LargeThreshold { get; set; } = 250;
-
+
+ /// Gets or sets the type of audio this DiscordClient supports.
+ public AudioMode AudioMode { get; set; } = AudioMode.Disabled;
+
/// Gets or sets the provider used to generate new websocket connections.
public WebSocketProvider WebSocketProvider { get; set; } = () => new DefaultWebSocketClient();
}
diff --git a/src/Discord.Net/Entities/Channels/IVoiceChannel.cs b/src/Discord.Net/Entities/Channels/IVoiceChannel.cs
index fc90b2935..5f6e8c817 100644
--- a/src/Discord.Net/Entities/Channels/IVoiceChannel.cs
+++ b/src/Discord.Net/Entities/Channels/IVoiceChannel.cs
@@ -1,4 +1,5 @@
using Discord.API.Rest;
+using Discord.Audio;
using System;
using System.Threading.Tasks;
@@ -13,5 +14,7 @@ namespace Discord
/// Modifies this voice channel.
Task ModifyAsync(Action func);
+ /// Connects to this voice channel.
+ Task ConnectAsync();
}
}
\ No newline at end of file
diff --git a/src/Discord.Net/Entities/Channels/VoiceChannel.cs b/src/Discord.Net/Entities/Channels/VoiceChannel.cs
index 4e2cb6e80..a7e32d5a4 100644
--- a/src/Discord.Net/Entities/Channels/VoiceChannel.cs
+++ b/src/Discord.Net/Entities/Channels/VoiceChannel.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Model = Discord.API.Channel;
+using Discord.Audio;
namespace Discord
{
@@ -49,6 +50,8 @@ namespace Discord
throw new NotSupportedException();
}
+ public virtual Task ConnectAsync() { throw new NotSupportedException(); }
+
private string DebuggerDisplay => $"{Name} ({Id}, Voice)";
}
}
diff --git a/src/Discord.Net/Entities/Guilds/Guild.cs b/src/Discord.Net/Entities/Guilds/Guild.cs
index d4a47f302..31a0f5916 100644
--- a/src/Discord.Net/Entities/Guilds/Guild.cs
+++ b/src/Discord.Net/Entities/Guilds/Guild.cs
@@ -1,4 +1,5 @@
using Discord.API.Rest;
+using Discord.Audio;
using Discord.Extensions;
using System;
using System.Collections.Concurrent;
@@ -311,6 +312,7 @@ namespace Discord
IReadOnlyCollection IGuild.Emojis => Emojis;
IReadOnlyCollection IGuild.Features => Features;
Task IGuild.DownloadUsersAsync() { throw new NotSupportedException(); }
+ IAudioClient IGuild.AudioClient => null;
IRole IGuild.GetRole(ulong id) => GetRole(id);
}
diff --git a/src/Discord.Net/Entities/Guilds/IGuild.cs b/src/Discord.Net/Entities/Guilds/IGuild.cs
index 7302e15f8..8979677ac 100644
--- a/src/Discord.Net/Entities/Guilds/IGuild.cs
+++ b/src/Discord.Net/Entities/Guilds/IGuild.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Discord.API.Rest;
+using Discord.Audio;
namespace Discord
{
@@ -37,6 +38,8 @@ namespace Discord
/// Gets the id of the region hosting this guild's voice channels.
string VoiceRegionId { get; }
+ /// Gets the IAudioClient currently associated with this guild.
+ IAudioClient AudioClient { get; }
/// Gets the built-in role containing all users in this guild.
IRole EveryoneRole { get; }
/// Gets a collection of all custom emojis for this guild.
diff --git a/src/Discord.Net/Entities/WebSocket/CachedGuild.cs b/src/Discord.Net/Entities/WebSocket/CachedGuild.cs
index 4d0af0783..2f383b4bc 100644
--- a/src/Discord.Net/Entities/WebSocket/CachedGuild.cs
+++ b/src/Discord.Net/Entities/WebSocket/CachedGuild.cs
@@ -1,4 +1,5 @@
-using Discord.Extensions;
+using Discord.Audio;
+using Discord.Extensions;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -6,6 +7,7 @@ using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using ChannelModel = Discord.API.Channel;
+using EmojiUpdateModel = Discord.API.Gateway.GuildEmojiUpdateEvent;
using ExtendedModel = Discord.API.Gateway.ExtendedGuild;
using MemberModel = Discord.API.GuildMember;
using Model = Discord.API.Guild;
@@ -25,6 +27,7 @@ namespace Discord
public bool Available { get; private set; }
public int MemberCount { get; private set; }
public int DownloadedMemberCount { get; private set; }
+ public IAudioClient AudioClient { get; private set; }
public bool HasAllMembers => _downloaderPromise.Task.IsCompleted;
public Task DownloaderPromise => _downloaderPromise.Task;
@@ -102,6 +105,16 @@ namespace Discord
_voiceStates = voiceStates;
}
+ public void Update(EmojiUpdateModel model, UpdateSource source)
+ {
+ if (source == UpdateSource.Rest && IsAttached) return;
+
+ var emojis = ImmutableArray.CreateBuilder(model.Emojis.Length);
+ for (int i = 0; i < model.Emojis.Length; i++)
+ emojis.Add(new Emoji(model.Emojis[i]));
+ Emojis = emojis.ToImmutableArray();
+ }
+
public override Task GetChannelAsync(ulong id) => Task.FromResult(GetChannel(id));
public override Task> GetChannelsAsync() => Task.FromResult>(Channels);
public void AddChannel(ChannelModel model, DataStore dataStore, ConcurrentHashSet channels = null)
diff --git a/src/Discord.Net/Entities/WebSocket/CachedVoiceChannel.cs b/src/Discord.Net/Entities/WebSocket/CachedVoiceChannel.cs
index 6b00d82b5..358464188 100644
--- a/src/Discord.Net/Entities/WebSocket/CachedVoiceChannel.cs
+++ b/src/Discord.Net/Entities/WebSocket/CachedVoiceChannel.cs
@@ -1,4 +1,6 @@
-using System.Collections.Generic;
+using Discord.Audio;
+using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
@@ -33,6 +35,19 @@ namespace Discord
return null;
}
+ public override async Task ConnectAsync()
+ {
+ var audioMode = Discord.AudioMode;
+ if (audioMode == AudioMode.Disabled)
+ throw new InvalidOperationException($"Audio is not enabled on this client, {nameof(DiscordSocketConfig.AudioMode)} in {nameof(DiscordSocketConfig)} must be set.");
+
+ await Discord.ApiClient.SendVoiceStateUpdateAsync(Guild.Id, Id,
+ (audioMode & AudioMode.Incoming) == 0,
+ (audioMode & AudioMode.Outgoing) == 0).ConfigureAwait(false);
+ return null;
+ //TODO: Block and return
+ }
+
public CachedVoiceChannel Clone() => MemberwiseClone() as CachedVoiceChannel;
ICachedChannel ICachedChannel.Clone() => Clone();
diff --git a/src/Discord.Net/project.json b/src/Discord.Net/project.json
index 04969b27b..76133d6d7 100644
--- a/src/Discord.Net/project.json
+++ b/src/Discord.Net/project.json
@@ -28,6 +28,7 @@
"System.Net.Http": "4.1.0",
"System.Net.WebSockets.Client": "4.0.0",
"System.Reflection.Extensions": "4.0.1",
+ "System.Runtime.InteropServices": "4.1.0",
"System.Runtime.Serialization.Primitives": "4.1.1",
"System.Text.RegularExpressions": "4.1.0"
},