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.5 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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 long ServerId;
  11. public VoiceDisconnectedEventArgs(long serverId, DisconnectedEventArgs e)
  12. : base(e.WasUnexpected, e.Error)
  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 long UserId;
  29. public readonly long ChannelId;
  30. public readonly byte[] Buffer;
  31. public readonly int Offset;
  32. public readonly int Count;
  33. public VoicePacketEventArgs(long userId, long 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<long, 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(long 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<long, DiscordAudioClient>();
  86. else
  87. {
  88. var logger = Client.Log().CreateLogger("Voice");
  89. var voiceSocket = new VoiceWebSocket(Client.Config, _config, logger);
  90. _defaultClient = new DiscordAudioClient(this, 0, logger, _client.WebSocket, voiceSocket);
  91. }
  92. _talkingUsers = new ConcurrentDictionary<User, bool>();
  93. client.Disconnected += async (s, e) =>
  94. {
  95. if (Config.EnableMultiserver)
  96. {
  97. var tasks = _voiceClients
  98. .Select(x => x.Value.Disconnect())
  99. .ToArray();
  100. await Task.WhenAll(tasks).ConfigureAwait(false);
  101. _voiceClients.Clear();
  102. }
  103. foreach (var member in _talkingUsers)
  104. {
  105. bool ignored;
  106. if (_talkingUsers.TryRemove(member.Key, out ignored))
  107. RaiseUserIsSpeakingUpdated(member.Key, false);
  108. }
  109. };
  110. }
  111. public DiscordAudioClient GetClient(Server server)
  112. {
  113. if (server == null) throw new ArgumentNullException(nameof(server));
  114. if (!Config.EnableMultiserver)
  115. {
  116. if (server.Id == _defaultClient.ServerId)
  117. return _defaultClient;
  118. else
  119. return null;
  120. }
  121. DiscordAudioClient client;
  122. if (_voiceClients.TryGetValue(server.Id, out client))
  123. return client;
  124. else
  125. return null;
  126. }
  127. private Task<DiscordAudioClient> CreateClient(Server server)
  128. {
  129. if (!Config.EnableMultiserver)
  130. {
  131. _defaultClient.SetServerId(server.Id);
  132. return Task.FromResult(_defaultClient);
  133. }
  134. var client = _voiceClients.GetOrAdd(server.Id, _ =>
  135. {
  136. int id = unchecked(++_nextClientId);
  137. var logger = Client.Log().CreateLogger($"Voice #{id}");
  138. DataWebSocket dataSocket = null;
  139. var voiceSocket = new VoiceWebSocket(Client.Config, _config, logger);
  140. var voiceClient = new DiscordAudioClient(this, id, logger, dataSocket, voiceSocket);
  141. voiceClient.SetServerId(server.Id);
  142. voiceSocket.OnPacket += (s, e) =>
  143. {
  144. RaiseOnPacket(e);
  145. };
  146. voiceSocket.IsSpeaking += (s, e) =>
  147. {
  148. var user = Client.GetUser(server, e.UserId);
  149. RaiseUserIsSpeakingUpdated(user, e.IsSpeaking);
  150. };
  151. return voiceClient;
  152. });
  153. //await client.Connect(dataSocket.Host, _client.Token).ConfigureAwait(false);
  154. return Task.FromResult(client);
  155. }
  156. public async Task<DiscordAudioClient> Join(Channel channel)
  157. {
  158. if (channel == null) throw new ArgumentNullException(nameof(channel));
  159. //CheckReady(true);
  160. var client = await CreateClient(channel.Server).ConfigureAwait(false);
  161. await client.Join(channel).ConfigureAwait(false);
  162. return client;
  163. }
  164. public async Task Leave(Server server)
  165. {
  166. if (server == null) throw new ArgumentNullException(nameof(server));
  167. //CheckReady(true);
  168. if (Config.EnableMultiserver)
  169. {
  170. //client.CheckReady();
  171. DiscordAudioClient client;
  172. if (_voiceClients.TryRemove(server.Id, out client))
  173. await client.Disconnect().ConfigureAwait(false);
  174. }
  175. else
  176. await _defaultClient.Disconnect().ConfigureAwait(false);
  177. }
  178. }
  179. }