@@ -136,12 +136,12 @@ namespace Discord.Audio | |||||
else | else | ||||
return null; | return null; | ||||
} | } | ||||
private Task<DiscordAudioClient> CreateClient(Server server) | |||||
private async Task<DiscordAudioClient> CreateClient(Server server) | |||||
{ | { | ||||
if (!Config.EnableMultiserver) | if (!Config.EnableMultiserver) | ||||
{ | { | ||||
_defaultClient.SetServerId(server.Id); | |||||
return Task.FromResult(_defaultClient); | |||||
await _defaultClient.SetServer(server.Id); | |||||
return _defaultClient; | |||||
} | } | ||||
else | else | ||||
throw new InvalidOperationException("Multiserver voice is not currently supported"); | throw new InvalidOperationException("Multiserver voice is not currently supported"); | ||||
@@ -175,7 +175,7 @@ namespace Discord.Audio | |||||
//CheckReady(true); | //CheckReady(true); | ||||
var client = await CreateClient(channel.Server).ConfigureAwait(false); | var client = await CreateClient(channel.Server).ConfigureAwait(false); | ||||
await client.Join(channel).ConfigureAwait(false); | |||||
await client.JoinChannel(channel).ConfigureAwait(false); | |||||
return client; | return client; | ||||
} | } | ||||
@@ -22,6 +22,7 @@ namespace Discord.Audio | |||||
public ulong? ServerId => VoiceSocket.ServerId; | public ulong? ServerId => VoiceSocket.ServerId; | ||||
public ulong? ChannelId => VoiceSocket.ChannelId; | public ulong? ChannelId => VoiceSocket.ChannelId; | ||||
public ConnectionState State => VoiceSocket.State; | |||||
public DiscordAudioClient(AudioService service, int id, Logger logger, GatewaySocket gatewaySocket) | public DiscordAudioClient(AudioService service, int id, Logger logger, GatewaySocket gatewaySocket) | ||||
{ | { | ||||
@@ -76,51 +77,57 @@ namespace Discord.Audio | |||||
_voiceSocket.ParentCancelToken = _cancelToken; | _voiceSocket.ParentCancelToken = _cancelToken; | ||||
};*/ | };*/ | ||||
GatewaySocket.ReceivedDispatch += OnReceivedDispatch; | |||||
} | |||||
} | |||||
internal void SetServerId(ulong serverId) | |||||
internal async Task SetServer(ulong serverId) | |||||
{ | { | ||||
VoiceSocket.ServerId = serverId; | |||||
if (serverId != VoiceSocket.ServerId) | |||||
{ | |||||
await Disconnect().ConfigureAwait(false); | |||||
VoiceSocket.ServerId = serverId; | |||||
VoiceSocket.ChannelId = null; | |||||
SendVoiceUpdate(); | |||||
} | |||||
} | } | ||||
public Task Join(Channel channel) | |||||
public Task JoinChannel(Channel channel) | |||||
{ | { | ||||
if (channel == null) throw new ArgumentNullException(nameof(channel)); | if (channel == null) throw new ArgumentNullException(nameof(channel)); | ||||
ulong? serverId = channel.Server?.Id; | |||||
if (serverId != ServerId) | |||||
var serverId = channel.Server?.Id; | |||||
var channelId = channel.Id; | |||||
if (serverId != ServerId) | |||||
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."); | ||||
if (channelId == VoiceSocket.ChannelId) | |||||
return TaskHelper.CompletedTask; | |||||
//CheckReady(checkVoice: true); | //CheckReady(checkVoice: true); | ||||
return Task.Run(async () => | return Task.Run(async () => | ||||
{ | { | ||||
_connectionLock.WaitOne(); | _connectionLock.WaitOne(); | ||||
GatewaySocket.ReceivedDispatch += OnReceivedDispatch; | |||||
try | try | ||||
{ | { | ||||
await VoiceSocket.Disconnect().ConfigureAwait(false); | |||||
if (State != ConnectionState.Disconnected) | |||||
await Disconnect().ConfigureAwait(false); | |||||
_cancelTokenSource = new CancellationTokenSource(); | _cancelTokenSource = new CancellationTokenSource(); | ||||
var cancelToken = _cancelTokenSource.Token; | var cancelToken = _cancelTokenSource.Token; | ||||
VoiceSocket.ParentCancelToken = cancelToken; | VoiceSocket.ParentCancelToken = cancelToken; | ||||
VoiceSocket.ChannelId = channel.Id; | |||||
GatewaySocket.SendUpdateVoice(channel.Server.Id, channel.Id, | |||||
(Service.Config.Mode | AudioMode.Outgoing) == 0, | |||||
(Service.Config.Mode | AudioMode.Incoming) == 0); | |||||
VoiceSocket.ChannelId = channelId; | |||||
SendVoiceUpdate(); | |||||
VoiceSocket.WaitForConnection(cancelToken); | VoiceSocket.WaitForConnection(cancelToken); | ||||
} | } | ||||
finally | finally | ||||
{ | { | ||||
GatewaySocket.ReceivedDispatch -= OnReceivedDispatch; | |||||
_connectionLock.Release(); | _connectionLock.Release(); | ||||
} | } | ||||
}); | }); | ||||
} | } | ||||
public Task Disconnect() | public Task Disconnect() | ||||
{ | |||||
GatewaySocket.ReceivedDispatch -= OnReceivedDispatch; | |||||
return VoiceSocket.Disconnect(); | |||||
} | |||||
=> VoiceSocket.Disconnect(); | |||||
private async void OnReceivedDispatch(object sender, WebSocketEventEventArgs e) | private async void OnReceivedDispatch(object sender, WebSocketEventEventArgs e) | ||||
{ | { | ||||
@@ -172,12 +179,22 @@ namespace Discord.Audio | |||||
} | } | ||||
/// <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> | ||||
public Task Wait() | |||||
public void Wait() | |||||
{ | { | ||||
//CheckReady(checkVoice: true); | //CheckReady(checkVoice: true); | ||||
VoiceSocket.WaitForQueue(); | VoiceSocket.WaitForQueue(); | ||||
return TaskHelper.CompletedTask; | |||||
} | } | ||||
private void SendVoiceUpdate() | |||||
{ | |||||
var serverId = VoiceSocket.ServerId; | |||||
if (serverId != null) | |||||
{ | |||||
GatewaySocket.SendUpdateVoice(serverId, VoiceSocket.ChannelId, | |||||
(Service.Config.Mode | AudioMode.Outgoing) == 0, | |||||
(Service.Config.Mode | AudioMode.Incoming) == 0); | |||||
} | |||||
} | |||||
} | } | ||||
} | } |
@@ -101,13 +101,15 @@ namespace Discord.Net.WebSockets | |||||
_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) | |||||
{ | |||||
_receiveThread = new Thread(new ThreadStart(() => ReceiveVoiceAsync(CancelToken))); | |||||
_receiveThread.IsBackground = true; | |||||
_receiveThread.Start(); | |||||
} | } | ||||
/*if ((_config.Mode & AudioMode.Incoming) != 0) | |||||
{*/ | |||||
_receiveThread = new Thread(new ThreadStart(() => ReceiveVoiceAsync(CancelToken))); | |||||
_receiveThread.IsBackground = true; | |||||
_receiveThread.Start(); | |||||
/*} | |||||
else | |||||
tasks.Add(Task.Run(() => ReceiveVoiceAsync(CancelToken)));*/ | |||||
SendIdentify(); | SendIdentify(); | ||||
@@ -10,10 +10,10 @@ namespace Discord.API.Client.GatewaySocket | |||||
object IWebSocketMessage.Payload => this; | object IWebSocketMessage.Payload => this; | ||||
bool IWebSocketMessage.IsPrivate => false; | bool IWebSocketMessage.IsPrivate => false; | ||||
[JsonProperty("guild_id"), JsonConverter(typeof(LongStringConverter))] | |||||
public ulong GuildId { get; set; } | |||||
[JsonProperty("channel_id"), JsonConverter(typeof(LongStringConverter))] | |||||
public ulong ChannelId { get; set; } | |||||
[JsonProperty("guild_id"), JsonConverter(typeof(NullableLongStringConverter))] | |||||
public ulong? GuildId { get; set; } | |||||
[JsonProperty("channel_id"), JsonConverter(typeof(NullableLongStringConverter))] | |||||
public ulong? ChannelId { get; set; } | |||||
[JsonProperty("self_mute")] | [JsonProperty("self_mute")] | ||||
public bool IsSelfMuted { get; set; } | public bool IsSelfMuted { get; set; } | ||||
[JsonProperty("self_deaf")] | [JsonProperty("self_deaf")] | ||||
@@ -173,7 +173,7 @@ namespace Discord.Net.WebSockets | |||||
IdleSince = idleSince, | IdleSince = idleSince, | ||||
Game = gameName != null ? new UpdateStatusCommand.GameInfo { Name = gameName } : null | Game = gameName != null ? new UpdateStatusCommand.GameInfo { Name = gameName } : null | ||||
}); | }); | ||||
public void SendUpdateVoice(ulong serverId, ulong channelId, bool isSelfMuted, bool isSelfDeafened) | |||||
public void SendUpdateVoice(ulong? serverId, ulong? channelId, bool isSelfMuted, bool isSelfDeafened) | |||||
=> QueueMessage(new UpdateVoiceCommand { GuildId = serverId, ChannelId = channelId, IsSelfMuted = isSelfMuted, IsSelfDeafened = isSelfDeafened }); | => QueueMessage(new UpdateVoiceCommand { GuildId = serverId, ChannelId = channelId, IsSelfMuted = isSelfMuted, IsSelfDeafened = isSelfDeafened }); | ||||
public void SendRequestMembers(ulong serverId, string query, int limit) | public void SendRequestMembers(ulong serverId, string query, int limit) | ||||
=> QueueMessage(new RequestMembersCommand { GuildId = serverId, Query = query, Limit = limit }); | => QueueMessage(new RequestMembersCommand { GuildId = serverId, Query = query, Limit = limit }); | ||||