diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs | 686 |
1 files changed, 343 insertions, 343 deletions
diff --git a/OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs b/OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs index 68197bb..5ec0ca8 100644 --- a/OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs +++ b/OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs | |||
@@ -1,343 +1,343 @@ | |||
1 | using System; | 1 | using System; |
2 | using System.Collections.Generic; | 2 | using System.Collections.Generic; |
3 | using System.Text; | 3 | using System.Text; |
4 | using System.Threading; | 4 | using System.Threading; |
5 | using System.Net.Sockets; | 5 | using System.Net.Sockets; |
6 | using System.Net; | 6 | using System.Net; |
7 | using OpenSim.Region.Environment.Scenes; | 7 | using OpenSim.Region.Environment.Scenes; |
8 | using OpenSim.Framework; | 8 | using OpenSim.Framework; |
9 | using OpenSim.Region.Environment.Modules; | 9 | using OpenSim.Region.Environment.Modules; |
10 | using OpenSim.Region.Environment.Interfaces; | 10 | using OpenSim.Region.Environment.Interfaces; |
11 | using Nini; | 11 | using Nini; |
12 | using libsecondlife; | 12 | using libsecondlife; |
13 | 13 | ||
14 | namespace OpenSim.Region.Environment.Modules.VoiceChat | 14 | namespace OpenSim.Region.Environment.Modules.VoiceChat |
15 | { | 15 | { |
16 | public class VoiceChatServer : IRegionModule | 16 | public class VoiceChatServer : IRegionModule |
17 | { | 17 | { |
18 | private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 18 | private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
19 | 19 | ||
20 | int m_dummySocketPort = 53134; | 20 | int m_dummySocketPort = 53134; |
21 | 21 | ||
22 | Thread m_listenerThread; | 22 | Thread m_listenerThread; |
23 | Thread m_mainThread; | 23 | Thread m_mainThread; |
24 | List<Scene> m_scenes = new List<Scene>(); | 24 | List<Scene> m_scenes = new List<Scene>(); |
25 | Socket m_server; | 25 | Socket m_server; |
26 | Socket m_selectCancel; | 26 | Socket m_selectCancel; |
27 | bool m_enabled = false; | 27 | bool m_enabled = false; |
28 | 28 | ||
29 | Dictionary<Socket, VoiceClient> m_clients = new Dictionary<Socket,VoiceClient>(); | 29 | Dictionary<Socket, VoiceClient> m_clients = new Dictionary<Socket,VoiceClient>(); |
30 | Dictionary<LLUUID, VoiceClient> m_uuidToClient = new Dictionary<LLUUID,VoiceClient>(); | 30 | Dictionary<LLUUID, VoiceClient> m_uuidToClient = new Dictionary<LLUUID,VoiceClient>(); |
31 | 31 | ||
32 | 32 | ||
33 | #region IRegionModule Members | 33 | #region IRegionModule Members |
34 | 34 | ||
35 | public void Initialise(Scene scene, Nini.Config.IConfigSource source) | 35 | public void Initialise(Scene scene, Nini.Config.IConfigSource source) |
36 | { | 36 | { |
37 | try | 37 | try |
38 | { | 38 | { |
39 | m_enabled = source.Configs["Voice"].GetBoolean("enabled", m_enabled); | 39 | m_enabled = source.Configs["Voice"].GetBoolean("enabled", m_enabled); |
40 | } | 40 | } |
41 | catch (Exception) | 41 | catch (Exception) |
42 | { } | 42 | { } |
43 | 43 | ||
44 | if (m_enabled) | 44 | if (m_enabled) |
45 | { | 45 | { |
46 | if (!m_scenes.Contains(scene)) | 46 | if (!m_scenes.Contains(scene)) |
47 | m_scenes.Add(scene); | 47 | m_scenes.Add(scene); |
48 | 48 | ||
49 | scene.EventManager.OnNewClient += NewClient; | 49 | scene.EventManager.OnNewClient += NewClient; |
50 | scene.EventManager.OnRemovePresence += RemovePresence; | 50 | scene.EventManager.OnRemovePresence += RemovePresence; |
51 | } | 51 | } |
52 | } | 52 | } |
53 | 53 | ||
54 | public void PostInitialise() | 54 | public void PostInitialise() |
55 | { | 55 | { |
56 | if (m_enabled != true) | 56 | if (m_enabled != true) |
57 | return; | 57 | return; |
58 | 58 | ||
59 | try | 59 | try |
60 | { | 60 | { |
61 | CreateListeningSocket(); | 61 | CreateListeningSocket(); |
62 | } | 62 | } |
63 | catch (Exception) | 63 | catch (Exception) |
64 | { | 64 | { |
65 | m_log.Error("[VOICECHAT]: Unable to start listening"); | 65 | m_log.Error("[VOICECHAT]: Unable to start listening"); |
66 | return; | 66 | return; |
67 | } | 67 | } |
68 | 68 | ||
69 | m_listenerThread = new Thread(new ThreadStart(ListenIncomingConnections)); | 69 | m_listenerThread = new Thread(new ThreadStart(ListenIncomingConnections)); |
70 | m_listenerThread.IsBackground = true; | 70 | m_listenerThread.IsBackground = true; |
71 | m_listenerThread.Start(); | 71 | m_listenerThread.Start(); |
72 | 72 | ||
73 | m_mainThread = new Thread(new ThreadStart(RunVoiceChat)); | 73 | m_mainThread = new Thread(new ThreadStart(RunVoiceChat)); |
74 | m_mainThread.IsBackground = true; | 74 | m_mainThread.IsBackground = true; |
75 | m_mainThread.Start(); | 75 | m_mainThread.Start(); |
76 | 76 | ||
77 | Thread.Sleep(500); | 77 | Thread.Sleep(500); |
78 | m_selectCancel = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | 78 | m_selectCancel = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
79 | m_selectCancel.Connect("localhost", m_dummySocketPort); | 79 | m_selectCancel.Connect("localhost", m_dummySocketPort); |
80 | } | 80 | } |
81 | 81 | ||
82 | public void Close() | 82 | public void Close() |
83 | { | 83 | { |
84 | throw new NotImplementedException(); | 84 | throw new NotImplementedException(); |
85 | } | 85 | } |
86 | 86 | ||
87 | public string Name | 87 | public string Name |
88 | { | 88 | { |
89 | get { return "VoiceChatModule"; } | 89 | get { return "VoiceChatModule"; } |
90 | } | 90 | } |
91 | 91 | ||
92 | public bool IsSharedModule | 92 | public bool IsSharedModule |
93 | { | 93 | { |
94 | get { return true; } // I think we can share this one. | 94 | get { return true; } // I think we can share this one. |
95 | } | 95 | } |
96 | 96 | ||
97 | #endregion | 97 | #endregion |
98 | 98 | ||
99 | public void NewClient(IClientAPI client) | 99 | public void NewClient(IClientAPI client) |
100 | { | 100 | { |
101 | m_log.Info("[VOICECHAT]: New client: " + client.AgentId); | 101 | m_log.Info("[VOICECHAT]: New client: " + client.AgentId); |
102 | lock (m_uuidToClient) | 102 | lock (m_uuidToClient) |
103 | { | 103 | { |
104 | m_uuidToClient[client.AgentId] = null; | 104 | m_uuidToClient[client.AgentId] = null; |
105 | } | 105 | } |
106 | } | 106 | } |
107 | 107 | ||
108 | public void RemovePresence(LLUUID uuid) | 108 | public void RemovePresence(LLUUID uuid) |
109 | { | 109 | { |
110 | lock (m_uuidToClient) | 110 | lock (m_uuidToClient) |
111 | { | 111 | { |
112 | if (m_uuidToClient.ContainsKey(uuid)) | 112 | if (m_uuidToClient.ContainsKey(uuid)) |
113 | { | 113 | { |
114 | if (m_uuidToClient[uuid] != null) | 114 | if (m_uuidToClient[uuid] != null) |
115 | { | 115 | { |
116 | RemoveClient(m_uuidToClient[uuid].m_socket); | 116 | RemoveClient(m_uuidToClient[uuid].m_socket); |
117 | } | 117 | } |
118 | m_uuidToClient.Remove(uuid); | 118 | m_uuidToClient.Remove(uuid); |
119 | } | 119 | } |
120 | else | 120 | else |
121 | { | 121 | { |
122 | m_log.Error("[VOICECHAT]: Presence not found on RemovePresence: " + uuid); | 122 | m_log.Error("[VOICECHAT]: Presence not found on RemovePresence: " + uuid); |
123 | } | 123 | } |
124 | } | 124 | } |
125 | } | 125 | } |
126 | 126 | ||
127 | public bool AddClient(VoiceClient client, LLUUID uuid) | 127 | public bool AddClient(VoiceClient client, LLUUID uuid) |
128 | { | 128 | { |
129 | lock (m_uuidToClient) | 129 | lock (m_uuidToClient) |
130 | { | 130 | { |
131 | if (m_uuidToClient.ContainsKey(uuid)) | 131 | if (m_uuidToClient.ContainsKey(uuid)) |
132 | { | 132 | { |
133 | if (m_uuidToClient[uuid] != null) { | 133 | if (m_uuidToClient[uuid] != null) { |
134 | m_log.Warn("[VOICECHAT]: Multiple login attempts for " + uuid); | 134 | m_log.Warn("[VOICECHAT]: Multiple login attempts for " + uuid); |
135 | return false; | 135 | return false; |
136 | } | 136 | } |
137 | m_uuidToClient[uuid] = client; | 137 | m_uuidToClient[uuid] = client; |
138 | return true; | 138 | return true; |
139 | } | 139 | } |
140 | } | 140 | } |
141 | return false; | 141 | return false; |
142 | } | 142 | } |
143 | 143 | ||
144 | public void RemoveClient(Socket socket) | 144 | public void RemoveClient(Socket socket) |
145 | { | 145 | { |
146 | m_log.Info("[VOICECHAT]: Removing client"); | 146 | m_log.Info("[VOICECHAT]: Removing client"); |
147 | lock(m_clients) | 147 | lock(m_clients) |
148 | { | 148 | { |
149 | VoiceClient client = m_clients[socket]; | 149 | VoiceClient client = m_clients[socket]; |
150 | 150 | ||
151 | lock(m_uuidToClient) | 151 | lock(m_uuidToClient) |
152 | { | 152 | { |
153 | if (m_uuidToClient.ContainsKey(client.m_clientId)) | 153 | if (m_uuidToClient.ContainsKey(client.m_clientId)) |
154 | { | 154 | { |
155 | m_uuidToClient[client.m_clientId] = null; | 155 | m_uuidToClient[client.m_clientId] = null; |
156 | } | 156 | } |
157 | } | 157 | } |
158 | 158 | ||
159 | m_clients.Remove(socket); | 159 | m_clients.Remove(socket); |
160 | client.m_socket.Close(); | 160 | client.m_socket.Close(); |
161 | } | 161 | } |
162 | } | 162 | } |
163 | 163 | ||
164 | protected void CreateListeningSocket() | 164 | protected void CreateListeningSocket() |
165 | { | 165 | { |
166 | IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 12000); | 166 | IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 12000); |
167 | m_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | 167 | m_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
168 | m_server.Bind(listenEndPoint); | 168 | m_server.Bind(listenEndPoint); |
169 | m_server.Listen(50); | 169 | m_server.Listen(50); |
170 | } | 170 | } |
171 | 171 | ||
172 | void ListenIncomingConnections() | 172 | void ListenIncomingConnections() |
173 | { | 173 | { |
174 | m_log.Info("[VOICECHAT]: Listening connections..."); | 174 | m_log.Info("[VOICECHAT]: Listening connections..."); |
175 | //ServerStatus.ReportThreadName("VoiceChat: Connection listener"); | 175 | //ServerStatus.ReportThreadName("VoiceChat: Connection listener"); |
176 | 176 | ||
177 | byte[] dummyBuffer = new byte[1]; | 177 | byte[] dummyBuffer = new byte[1]; |
178 | 178 | ||
179 | while (true) | 179 | while (true) |
180 | { | 180 | { |
181 | try | 181 | try |
182 | { | 182 | { |
183 | Socket connection = m_server.Accept(); | 183 | Socket connection = m_server.Accept(); |
184 | lock (m_clients) | 184 | lock (m_clients) |
185 | { | 185 | { |
186 | m_clients[connection] = new VoiceClient(connection, this); | 186 | m_clients[connection] = new VoiceClient(connection, this); |
187 | m_selectCancel.Send(dummyBuffer); | 187 | m_selectCancel.Send(dummyBuffer); |
188 | m_log.Info("[VOICECHAT]: Voicechat connection from " + connection.RemoteEndPoint.ToString()); | 188 | m_log.Info("[VOICECHAT]: Voicechat connection from " + connection.RemoteEndPoint.ToString()); |
189 | } | 189 | } |
190 | } | 190 | } |
191 | catch (SocketException e) | 191 | catch (SocketException e) |
192 | { | 192 | { |
193 | m_log.Error("[VOICECHAT]: During accept: " + e.ToString()); | 193 | m_log.Error("[VOICECHAT]: During accept: " + e.ToString()); |
194 | } | 194 | } |
195 | } | 195 | } |
196 | } | 196 | } |
197 | 197 | ||
198 | Socket ListenLoopbackSocket() | 198 | Socket ListenLoopbackSocket() |
199 | { | 199 | { |
200 | IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), m_dummySocketPort); | 200 | IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), m_dummySocketPort); |
201 | Socket dummyListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | 201 | Socket dummyListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
202 | dummyListener.Bind(listenEndPoint); | 202 | dummyListener.Bind(listenEndPoint); |
203 | dummyListener.Listen(1); | 203 | dummyListener.Listen(1); |
204 | Socket socket = dummyListener.Accept(); | 204 | Socket socket = dummyListener.Accept(); |
205 | dummyListener.Close(); | 205 | dummyListener.Close(); |
206 | return socket; | 206 | return socket; |
207 | } | 207 | } |
208 | 208 | ||
209 | void RunVoiceChat() | 209 | void RunVoiceChat() |
210 | { | 210 | { |
211 | m_log.Info("[VOICECHAT]: Connection handler started..."); | 211 | m_log.Info("[VOICECHAT]: Connection handler started..."); |
212 | //ServerStatus.ReportThreadName("VoiceChat: Connection handler"); | 212 | //ServerStatus.ReportThreadName("VoiceChat: Connection handler"); |
213 | 213 | ||
214 | //Listen a loopback socket for aborting select call | 214 | //Listen a loopback socket for aborting select call |
215 | Socket dummySocket = ListenLoopbackSocket(); | 215 | Socket dummySocket = ListenLoopbackSocket(); |
216 | 216 | ||
217 | List<Socket> sockets = new List<Socket>(); | 217 | List<Socket> sockets = new List<Socket>(); |
218 | byte[] buffer = new byte[65536]; | 218 | byte[] buffer = new byte[65536]; |
219 | 219 | ||
220 | while (true) | 220 | while (true) |
221 | { | 221 | { |
222 | if (m_clients.Count == 0) | 222 | if (m_clients.Count == 0) |
223 | { | 223 | { |
224 | Thread.Sleep(100); | 224 | Thread.Sleep(100); |
225 | continue; | 225 | continue; |
226 | } | 226 | } |
227 | 227 | ||
228 | lock (m_clients) | 228 | lock (m_clients) |
229 | { | 229 | { |
230 | foreach (Socket s in m_clients.Keys) | 230 | foreach (Socket s in m_clients.Keys) |
231 | { | 231 | { |
232 | sockets.Add(s); | 232 | sockets.Add(s); |
233 | } | 233 | } |
234 | } | 234 | } |
235 | sockets.Add(dummySocket); | 235 | sockets.Add(dummySocket); |
236 | 236 | ||
237 | try | 237 | try |
238 | { | 238 | { |
239 | Socket.Select(sockets, null, null, 200000); | 239 | Socket.Select(sockets, null, null, 200000); |
240 | } | 240 | } |
241 | catch (SocketException e) | 241 | catch (SocketException e) |
242 | { | 242 | { |
243 | m_log.Warn("[VOICECHAT]: " + e.Message); | 243 | m_log.Warn("[VOICECHAT]: " + e.Message); |
244 | } | 244 | } |
245 | 245 | ||
246 | foreach (Socket s in sockets) | 246 | foreach (Socket s in sockets) |
247 | { | 247 | { |
248 | try | 248 | try |
249 | { | 249 | { |
250 | if (s.RemoteEndPoint != dummySocket.RemoteEndPoint) | 250 | if (s.RemoteEndPoint != dummySocket.RemoteEndPoint) |
251 | { | 251 | { |
252 | ReceiveFromSocket(s, buffer); | 252 | ReceiveFromSocket(s, buffer); |
253 | } | 253 | } |
254 | else | 254 | else |
255 | { | 255 | { |
256 | //Receive data and check if there was an error with select abort socket | 256 | //Receive data and check if there was an error with select abort socket |
257 | if (s.Receive(buffer) <= 0) | 257 | if (s.Receive(buffer) <= 0) |
258 | { | 258 | { |
259 | //Just give a warning for now | 259 | //Just give a warning for now |
260 | m_log.Error("[VOICECHAT]: Select abort socket was closed"); | 260 | m_log.Error("[VOICECHAT]: Select abort socket was closed"); |
261 | } | 261 | } |
262 | } | 262 | } |
263 | } | 263 | } |
264 | catch(ObjectDisposedException e) | 264 | catch(ObjectDisposedException e) |
265 | { | 265 | { |
266 | m_log.Warn("[VOICECHAT]: Connection has been already closed"); | 266 | m_log.Warn("[VOICECHAT]: Connection has been already closed"); |
267 | } | 267 | } |
268 | catch (Exception e) | 268 | catch (Exception e) |
269 | { | 269 | { |
270 | m_log.Error("[VOICECHAT]: Exception: " + e.Message); | 270 | m_log.Error("[VOICECHAT]: Exception: " + e.Message); |
271 | 271 | ||
272 | RemoveClient(s); | 272 | RemoveClient(s); |
273 | } | 273 | } |
274 | } | 274 | } |
275 | 275 | ||
276 | sockets.Clear(); | 276 | sockets.Clear(); |
277 | } | 277 | } |
278 | } | 278 | } |
279 | 279 | ||
280 | private void ReceiveFromSocket( Socket s, byte[] buffer ) | 280 | private void ReceiveFromSocket( Socket s, byte[] buffer ) |
281 | { | 281 | { |
282 | int byteCount = s.Receive(buffer); | 282 | int byteCount = s.Receive(buffer); |
283 | if (byteCount <= 0) | 283 | if (byteCount <= 0) |
284 | { | 284 | { |
285 | m_log.Info("[VOICECHAT]: Connection lost to " + s.RemoteEndPoint); | 285 | m_log.Info("[VOICECHAT]: Connection lost to " + s.RemoteEndPoint); |
286 | lock (m_clients) | 286 | lock (m_clients) |
287 | { | 287 | { |
288 | RemoveClient(s); | 288 | RemoveClient(s); |
289 | } | 289 | } |
290 | } | 290 | } |
291 | else | 291 | else |
292 | { | 292 | { |
293 | //ServerStatus.ReportInPacketTcp(byteCount); | 293 | //ServerStatus.ReportInPacketTcp(byteCount); |
294 | lock (m_clients) | 294 | lock (m_clients) |
295 | { | 295 | { |
296 | if (m_clients.ContainsKey(s)) | 296 | if (m_clients.ContainsKey(s)) |
297 | { | 297 | { |
298 | m_clients[s].OnDataReceived(buffer, byteCount); | 298 | m_clients[s].OnDataReceived(buffer, byteCount); |
299 | } | 299 | } |
300 | else | 300 | else |
301 | { | 301 | { |
302 | m_log.Warn("[VOICECHAT]: Got data from " + s.RemoteEndPoint + | 302 | m_log.Warn("[VOICECHAT]: Got data from " + s.RemoteEndPoint + |
303 | ", but source is not a valid voice client"); | 303 | ", but source is not a valid voice client"); |
304 | } | 304 | } |
305 | } | 305 | } |
306 | } | 306 | } |
307 | } | 307 | } |
308 | 308 | ||
309 | public LLVector3 getScenePresencePosition(LLUUID clientID) | 309 | public LLVector3 getScenePresencePosition(LLUUID clientID) |
310 | { | 310 | { |
311 | foreach (Scene scene in m_scenes) | 311 | foreach (Scene scene in m_scenes) |
312 | { | 312 | { |
313 | ScenePresence x; | 313 | ScenePresence x; |
314 | if ((x = scene.GetScenePresence(clientID)) != null) | 314 | if ((x = scene.GetScenePresence(clientID)) != null) |
315 | { | 315 | { |
316 | return x.AbsolutePosition + new LLVector3(Constants.RegionSize * scene.RegionInfo.RegionLocX, | 316 | return x.AbsolutePosition + new LLVector3(Constants.RegionSize * scene.RegionInfo.RegionLocX, |
317 | Constants.RegionSize * scene.RegionInfo.RegionLocY, 0); | 317 | Constants.RegionSize * scene.RegionInfo.RegionLocY, 0); |
318 | } | 318 | } |
319 | } | 319 | } |
320 | return LLVector3.Zero; | 320 | return LLVector3.Zero; |
321 | } | 321 | } |
322 | 322 | ||
323 | public void BroadcastVoice(VoicePacket packet) | 323 | public void BroadcastVoice(VoicePacket packet) |
324 | { | 324 | { |
325 | libsecondlife.LLVector3 origPos = getScenePresencePosition(packet.m_clientId); | 325 | libsecondlife.LLVector3 origPos = getScenePresencePosition(packet.m_clientId); |
326 | 326 | ||
327 | byte[] bytes = packet.GetBytes(); | 327 | byte[] bytes = packet.GetBytes(); |
328 | foreach (VoiceClient client in m_clients.Values) | 328 | foreach (VoiceClient client in m_clients.Values) |
329 | { | 329 | { |
330 | if (client.IsEnabled() && client.m_clientId != packet.m_clientId && | 330 | if (client.IsEnabled() && client.m_clientId != packet.m_clientId && |
331 | client.m_authenticated && client.IsCodecSupported(packet.m_codec)) | 331 | client.m_authenticated && client.IsCodecSupported(packet.m_codec)) |
332 | { | 332 | { |
333 | LLVector3 presenceLoc = getScenePresencePosition(client.m_clientId); | 333 | LLVector3 presenceLoc = getScenePresencePosition(client.m_clientId); |
334 | 334 | ||
335 | if (presenceLoc != LLVector3.Zero && Util.GetDistanceTo(presenceLoc, origPos) < 20) | 335 | if (presenceLoc != LLVector3.Zero && Util.GetDistanceTo(presenceLoc, origPos) < 20) |
336 | { | 336 | { |
337 | client.SendTo(bytes); | 337 | client.SendTo(bytes); |
338 | } | 338 | } |
339 | } | 339 | } |
340 | } | 340 | } |
341 | } | 341 | } |
342 | } | 342 | } |
343 | } | 343 | } |