You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

AudioService.cs 5.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. using Discord.Net.WebSockets;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. namespace Discord.Audio
  7. {
  8. public class VoiceDisconnectedEventArgs : DisconnectedEventArgs
  9. {
  10. public readonly ulong ServerId;
  11. public VoiceDisconnectedEventArgs(ulong serverId, DisconnectedEventArgs e)
  12. : base(e.WasUnexpected, e.Exception)
  13. {
  14. ServerId = serverId;
  15. }
  16. }
  17. public class UserIsSpeakingEventArgs : UserEventArgs
  18. {
  19. public readonly bool IsSpeaking;
  20. public UserIsSpeakingEventArgs(User user, bool isSpeaking)
  21. : base(user)
  22. {
  23. IsSpeaking = isSpeaking;
  24. }
  25. }
  26. public class VoicePacketEventArgs : EventArgs
  27. {
  28. public readonly ulong UserId;
  29. public readonly ulong ChannelId;
  30. public readonly byte[] Buffer;
  31. public readonly int Offset;
  32. public readonly int Count;
  33. public VoicePacketEventArgs(ulong userId, ulong channelId, byte[] buffer, int offset, int count)
  34. {
  35. UserId = userId;
  36. ChannelId = channelId;
  37. Buffer = buffer;
  38. Offset = offset;
  39. Count = count;
  40. }
  41. }
  42. public class AudioService : IService
  43. {
  44. private DiscordAudioClient _defaultClient;
  45. private ConcurrentDictionary<ulong, DiscordAudioClient> _voiceClients;
  46. private ConcurrentDictionary<User, bool> _talkingUsers;
  47. private int _nextClientId;
  48. internal DiscordClient Client => _client;
  49. private DiscordClient _client;
  50. public AudioServiceConfig Config => _config;
  51. private readonly AudioServiceConfig _config;
  52. public event EventHandler Connected;
  53. private void RaiseConnected()
  54. {
  55. if (Connected != null)
  56. Connected(this, EventArgs.Empty);
  57. }
  58. public event EventHandler<VoiceDisconnectedEventArgs> Disconnected;
  59. private void RaiseDisconnected(ulong serverId, DisconnectedEventArgs e)
  60. {
  61. if (Disconnected != null)
  62. Disconnected(this, new VoiceDisconnectedEventArgs(serverId, e));
  63. }
  64. public event EventHandler<VoicePacketEventArgs> OnPacket;
  65. internal void RaiseOnPacket(VoicePacketEventArgs e)
  66. {
  67. if (OnPacket != null)
  68. OnPacket(this, e);
  69. }
  70. public event EventHandler<UserIsSpeakingEventArgs> UserIsSpeakingUpdated;
  71. private void RaiseUserIsSpeakingUpdated(User user, bool isSpeaking)
  72. {
  73. if (UserIsSpeakingUpdated != null)
  74. UserIsSpeakingUpdated(this, new UserIsSpeakingEventArgs(user, isSpeaking));
  75. }
  76. public AudioService(AudioServiceConfig config)
  77. {
  78. _config = config;
  79. _config.Lock();
  80. }
  81. public void Install(DiscordClient client)
  82. {
  83. _client = client;
  84. if (Config.EnableMultiserver)
  85. _voiceClients = new ConcurrentDictionary<ulong, DiscordAudioClient>();
  86. else
  87. {
  88. var logger = Client.Log.CreateLogger("Voice");
  89. _defaultClient = new DiscordAudioClient(this, 0, logger, _client.GatewaySocket);
  90. }
  91. _talkingUsers = new ConcurrentDictionary<User, bool>();
  92. client.Disconnected += async (s, e) =>
  93. {
  94. if (Config.EnableMultiserver)
  95. {
  96. var tasks = _voiceClients
  97. .Select(x => x.Value.Disconnect())
  98. .ToArray();
  99. await Task.WhenAll(tasks).ConfigureAwait(false);
  100. _voiceClients.Clear();
  101. }
  102. foreach (var member in _talkingUsers)
  103. {
  104. bool ignored;
  105. if (_talkingUsers.TryRemove(member.Key, out ignored))
  106. RaiseUserIsSpeakingUpdated(member.Key, false);
  107. }
  108. };
  109. }
  110. public DiscordAudioClient GetClient(Server server)
  111. {
  112. if (server == null) throw new ArgumentNullException(nameof(server));
  113. if (!Config.EnableMultiserver)
  114. {
  115. if (server.Id == _defaultClient.ServerId)
  116. return _defaultClient;
  117. else
  118. return null;
  119. }
  120. DiscordAudioClient client;
  121. if (_voiceClients.TryGetValue(server.Id, out client))
  122. return client;
  123. else
  124. return null;
  125. }
  126. private Task<DiscordAudioClient> CreateClient(Server server)
  127. {
  128. if (!Config.EnableMultiserver)
  129. {
  130. _defaultClient.SetServerId(server.Id);
  131. return Task.FromResult(_defaultClient);
  132. }
  133. var client = _voiceClients.GetOrAdd(server.Id, _ =>
  134. {
  135. int id = unchecked(++_nextClientId);
  136. var logger = Client.Log.CreateLogger($"Voice #{id}");
  137. GatewaySocket gatewaySocket = null;
  138. var voiceClient = new DiscordAudioClient(this, id, logger, gatewaySocket);
  139. voiceClient.SetServerId(server.Id);
  140. voiceClient.VoiceSocket.OnPacket += (s, e) =>
  141. {
  142. RaiseOnPacket(e);
  143. };
  144. voiceClient.VoiceSocket.IsSpeaking += (s, e) =>
  145. {
  146. var user = server.GetUser(e.UserId);
  147. RaiseUserIsSpeakingUpdated(user, e.IsSpeaking);
  148. };
  149. return voiceClient;
  150. });
  151. //await client.Connect(gatewaySocket.Host, _client.Token).ConfigureAwait(false);
  152. return Task.FromResult(client);
  153. }
  154. public async Task<DiscordAudioClient> Join(Channel channel)
  155. {
  156. if (channel == null) throw new ArgumentNullException(nameof(channel));
  157. //CheckReady(true);
  158. var client = await CreateClient(channel.Server).ConfigureAwait(false);
  159. await client.Join(channel).ConfigureAwait(false);
  160. return client;
  161. }
  162. public async Task Leave(Server server)
  163. {
  164. if (server == null) throw new ArgumentNullException(nameof(server));
  165. //CheckReady(true);
  166. if (Config.EnableMultiserver)
  167. {
  168. //client.CheckReady();
  169. DiscordAudioClient client;
  170. if (_voiceClients.TryRemove(server.Id, out client))
  171. await client.Disconnect().ConfigureAwait(false);
  172. }
  173. else
  174. await _defaultClient.Disconnect().ConfigureAwait(false);
  175. }
  176. }
  177. }