diff options
Diffstat (limited to 'OpenSim/Region/Environment/Modules/VoiceChat')
4 files changed, 608 insertions, 608 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 | } |
diff --git a/OpenSim/Region/Environment/Modules/VoiceChat/VoiceClient.cs b/OpenSim/Region/Environment/Modules/VoiceChat/VoiceClient.cs index 7eb2177..7be0dad 100644 --- a/OpenSim/Region/Environment/Modules/VoiceChat/VoiceClient.cs +++ b/OpenSim/Region/Environment/Modules/VoiceChat/VoiceClient.cs | |||
@@ -1,169 +1,169 @@ | |||
1 | using System; | 1 | using System; |
2 | using System.IO; | 2 | using System.IO; |
3 | using System.Collections.Generic; | 3 | using System.Collections.Generic; |
4 | using System.Text; | 4 | using System.Text; |
5 | using System.Net.Sockets; | 5 | using System.Net.Sockets; |
6 | using OpenSim.Region.Environment.Scenes; | 6 | using OpenSim.Region.Environment.Scenes; |
7 | using libsecondlife; | 7 | using libsecondlife; |
8 | 8 | ||
9 | namespace OpenSim.Region.Environment.Modules.VoiceChat | 9 | namespace OpenSim.Region.Environment.Modules.VoiceChat |
10 | { | 10 | { |
11 | /** | 11 | /** |
12 | * Represents a single voiceclient instance | 12 | * Represents a single voiceclient instance |
13 | **/ | 13 | **/ |
14 | public class VoiceClient | 14 | public class VoiceClient |
15 | { | 15 | { |
16 | private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 16 | private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
17 | 17 | ||
18 | public Socket m_socket; | 18 | public Socket m_socket; |
19 | public LLUUID m_clientId; | 19 | public LLUUID m_clientId; |
20 | public bool m_authenticated = false; | 20 | public bool m_authenticated = false; |
21 | 21 | ||
22 | protected VoicePacketHeader m_header = null; | 22 | protected VoicePacketHeader m_header = null; |
23 | protected int m_headerBytesReceived = 0; | 23 | protected int m_headerBytesReceived = 0; |
24 | 24 | ||
25 | protected int m_offset = 0; | 25 | protected int m_offset = 0; |
26 | protected int m_supportedCodecs = 0; | 26 | protected int m_supportedCodecs = 0; |
27 | 27 | ||
28 | protected byte[] m_buffer = null; | 28 | protected byte[] m_buffer = null; |
29 | protected byte[] m_headerBytes = new byte[5]; | 29 | protected byte[] m_headerBytes = new byte[5]; |
30 | 30 | ||
31 | protected bool m_enabled = true; | 31 | protected bool m_enabled = true; |
32 | 32 | ||
33 | protected VoiceChatServer m_server; | 33 | protected VoiceChatServer m_server; |
34 | 34 | ||
35 | public VoiceClient(Socket socket, VoiceChatServer server) | 35 | public VoiceClient(Socket socket, VoiceChatServer server) |
36 | { | 36 | { |
37 | m_socket = socket; | 37 | m_socket = socket; |
38 | m_server = server; | 38 | m_server = server; |
39 | } | 39 | } |
40 | 40 | ||
41 | public void OnDataReceived(byte[] data, int byteCount) | 41 | public void OnDataReceived(byte[] data, int byteCount) |
42 | { | 42 | { |
43 | int offset = 0; | 43 | int offset = 0; |
44 | while (offset < byteCount) | 44 | while (offset < byteCount) |
45 | { | 45 | { |
46 | if (m_header == null) | 46 | if (m_header == null) |
47 | { | 47 | { |
48 | if (m_headerBytesReceived < 5) | 48 | if (m_headerBytesReceived < 5) |
49 | { | 49 | { |
50 | m_headerBytes[m_headerBytesReceived++] = data[offset++]; | 50 | m_headerBytes[m_headerBytesReceived++] = data[offset++]; |
51 | } | 51 | } |
52 | else if (m_headerBytesReceived == 5) | 52 | else if (m_headerBytesReceived == 5) |
53 | { | 53 | { |
54 | m_header = new VoicePacketHeader(); | 54 | m_header = new VoicePacketHeader(); |
55 | m_header.Parse(m_headerBytes); | 55 | m_header.Parse(m_headerBytes); |
56 | if (m_header.length > 65535) | 56 | if (m_header.length > 65535) |
57 | { | 57 | { |
58 | throw new Exception("Packet size " + m_header.length + " > 65535"); | 58 | throw new Exception("Packet size " + m_header.length + " > 65535"); |
59 | } | 59 | } |
60 | 60 | ||
61 | m_buffer = new byte[m_header.length]; | 61 | m_buffer = new byte[m_header.length]; |
62 | m_offset = 0; | 62 | m_offset = 0; |
63 | m_headerBytesReceived = 0; | 63 | m_headerBytesReceived = 0; |
64 | } | 64 | } |
65 | } | 65 | } |
66 | else | 66 | else |
67 | { | 67 | { |
68 | int bytesToCopy = m_header.length-m_offset; | 68 | int bytesToCopy = m_header.length-m_offset; |
69 | if (bytesToCopy > byteCount - offset) | 69 | if (bytesToCopy > byteCount - offset) |
70 | bytesToCopy = byteCount - offset; | 70 | bytesToCopy = byteCount - offset; |
71 | 71 | ||
72 | Buffer.BlockCopy(data, offset, m_buffer, m_offset, bytesToCopy); | 72 | Buffer.BlockCopy(data, offset, m_buffer, m_offset, bytesToCopy); |
73 | 73 | ||
74 | offset += bytesToCopy; | 74 | offset += bytesToCopy; |
75 | m_offset += bytesToCopy; | 75 | m_offset += bytesToCopy; |
76 | 76 | ||
77 | if (m_offset == m_header.length) | 77 | if (m_offset == m_header.length) |
78 | { | 78 | { |
79 | ParsePacket(m_header.type, m_buffer); | 79 | ParsePacket(m_header.type, m_buffer); |
80 | m_header = null; | 80 | m_header = null; |
81 | } | 81 | } |
82 | } | 82 | } |
83 | } | 83 | } |
84 | } | 84 | } |
85 | 85 | ||
86 | void ParsePacket(byte type, byte[] data) | 86 | void ParsePacket(byte type, byte[] data) |
87 | { | 87 | { |
88 | switch (type) | 88 | switch (type) |
89 | { | 89 | { |
90 | case 0: //LOGIN | 90 | case 0: //LOGIN |
91 | ParseLogin(data); | 91 | ParseLogin(data); |
92 | break; | 92 | break; |
93 | 93 | ||
94 | case 1: //AUDIODATA | 94 | case 1: //AUDIODATA |
95 | if (m_authenticated) | 95 | if (m_authenticated) |
96 | { | 96 | { |
97 | VoicePacket packet = new VoicePacket(data); | 97 | VoicePacket packet = new VoicePacket(data); |
98 | packet.m_clientId = m_clientId; | 98 | packet.m_clientId = m_clientId; |
99 | m_server.BroadcastVoice(packet); | 99 | m_server.BroadcastVoice(packet); |
100 | } | 100 | } |
101 | else | 101 | else |
102 | { | 102 | { |
103 | m_log.Warn("[VOICECHAT]: Got unauthorized audio data from " + | 103 | m_log.Warn("[VOICECHAT]: Got unauthorized audio data from " + |
104 | m_socket.RemoteEndPoint.ToString()); | 104 | m_socket.RemoteEndPoint.ToString()); |
105 | m_socket.Close(); | 105 | m_socket.Close(); |
106 | } | 106 | } |
107 | break; | 107 | break; |
108 | 108 | ||
109 | case 3: //ENABLEVOIP | 109 | case 3: //ENABLEVOIP |
110 | if (data[0] == 0) | 110 | if (data[0] == 0) |
111 | { | 111 | { |
112 | m_log.Warn("[VOICECHAT]: VoiceChat has been disabled for " + m_clientId); | 112 | m_log.Warn("[VOICECHAT]: VoiceChat has been disabled for " + m_clientId); |
113 | m_enabled = false; | 113 | m_enabled = false; |
114 | } | 114 | } |
115 | else | 115 | else |
116 | { | 116 | { |
117 | m_log.Warn("[VOICECHAT]: VoiceChat has been enabled for " + m_clientId); | 117 | m_log.Warn("[VOICECHAT]: VoiceChat has been enabled for " + m_clientId); |
118 | m_enabled = true; | 118 | m_enabled = true; |
119 | } | 119 | } |
120 | break; | 120 | break; |
121 | 121 | ||
122 | 122 | ||
123 | default: | 123 | default: |
124 | throw new Exception("Invalid packet received"); | 124 | throw new Exception("Invalid packet received"); |
125 | } | 125 | } |
126 | } | 126 | } |
127 | 127 | ||
128 | void ParseLogin(byte[] data) | 128 | void ParseLogin(byte[] data) |
129 | { | 129 | { |
130 | m_clientId = new LLUUID(data, 0); | 130 | m_clientId = new LLUUID(data, 0); |
131 | 131 | ||
132 | m_supportedCodecs = data[16]; | 132 | m_supportedCodecs = data[16]; |
133 | m_supportedCodecs |= data[17] << 8; | 133 | m_supportedCodecs |= data[17] << 8; |
134 | m_supportedCodecs |= data[18] << 16; | 134 | m_supportedCodecs |= data[18] << 16; |
135 | m_supportedCodecs |= data[19] << 24; | 135 | m_supportedCodecs |= data[19] << 24; |
136 | 136 | ||
137 | if (m_server.AddClient(this, m_clientId)) | 137 | if (m_server.AddClient(this, m_clientId)) |
138 | { | 138 | { |
139 | m_log.Info("[VOICECHAT]: Client authenticated succesfully: " + m_clientId); | 139 | m_log.Info("[VOICECHAT]: Client authenticated succesfully: " + m_clientId); |
140 | m_authenticated = true; | 140 | m_authenticated = true; |
141 | } | 141 | } |
142 | else | 142 | else |
143 | { | 143 | { |
144 | throw new Exception("Unable to authenticate with id " + m_clientId); | 144 | throw new Exception("Unable to authenticate with id " + m_clientId); |
145 | } | 145 | } |
146 | } | 146 | } |
147 | 147 | ||
148 | public bool IsEnabled() | 148 | public bool IsEnabled() |
149 | { | 149 | { |
150 | return m_enabled; | 150 | return m_enabled; |
151 | } | 151 | } |
152 | 152 | ||
153 | public bool IsCodecSupported(int codec) | 153 | public bool IsCodecSupported(int codec) |
154 | { | 154 | { |
155 | if ((m_supportedCodecs & codec) != 0) | 155 | if ((m_supportedCodecs & codec) != 0) |
156 | return true; | 156 | return true; |
157 | 157 | ||
158 | return false; | 158 | return false; |
159 | } | 159 | } |
160 | 160 | ||
161 | public void SendTo(byte[] data) | 161 | public void SendTo(byte[] data) |
162 | { | 162 | { |
163 | if (m_authenticated) | 163 | if (m_authenticated) |
164 | { | 164 | { |
165 | //ServerStatus.ReportOutPacketTcp(m_socket.Send(data)); | 165 | //ServerStatus.ReportOutPacketTcp(m_socket.Send(data)); |
166 | } | 166 | } |
167 | } | 167 | } |
168 | } | 168 | } |
169 | } | 169 | } |
diff --git a/OpenSim/Region/Environment/Modules/VoiceChat/VoicePacket.cs b/OpenSim/Region/Environment/Modules/VoiceChat/VoicePacket.cs index e92fa43..db62f45 100644 --- a/OpenSim/Region/Environment/Modules/VoiceChat/VoicePacket.cs +++ b/OpenSim/Region/Environment/Modules/VoiceChat/VoicePacket.cs | |||
@@ -1,58 +1,58 @@ | |||
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 libsecondlife; | 4 | using libsecondlife; |
5 | 5 | ||
6 | namespace OpenSim.Region.Environment.Modules.VoiceChat | 6 | namespace OpenSim.Region.Environment.Modules.VoiceChat |
7 | { | 7 | { |
8 | public enum VoiceCodec | 8 | public enum VoiceCodec |
9 | { | 9 | { |
10 | None = 0, | 10 | None = 0, |
11 | PCM8 = 1 << 0, | 11 | PCM8 = 1 << 0, |
12 | PCM16 = 1 << 1, | 12 | PCM16 = 1 << 1, |
13 | PCM32 = 1 << 2, | 13 | PCM32 = 1 << 2, |
14 | Speex = 1 << 3, | 14 | Speex = 1 << 3, |
15 | } | 15 | } |
16 | 16 | ||
17 | public class VoicePacket | 17 | public class VoicePacket |
18 | { | 18 | { |
19 | public LLUUID m_clientId; | 19 | public LLUUID m_clientId; |
20 | byte[] m_audioData; | 20 | byte[] m_audioData; |
21 | public int m_codec; | 21 | public int m_codec; |
22 | 22 | ||
23 | public VoicePacket(byte[] data) | 23 | public VoicePacket(byte[] data) |
24 | { | 24 | { |
25 | int pos = 0; | 25 | int pos = 0; |
26 | m_codec = data[pos++]; | 26 | m_codec = data[pos++]; |
27 | m_codec |= data[pos++] << 8; | 27 | m_codec |= data[pos++] << 8; |
28 | m_codec |= data[pos++] << 16; | 28 | m_codec |= data[pos++] << 16; |
29 | m_codec |= data[pos++] << 24; | 29 | m_codec |= data[pos++] << 24; |
30 | 30 | ||
31 | m_audioData = new byte[data.Length - pos]; | 31 | m_audioData = new byte[data.Length - pos]; |
32 | Buffer.BlockCopy(data, pos, m_audioData, 0, data.Length - pos); | 32 | Buffer.BlockCopy(data, pos, m_audioData, 0, data.Length - pos); |
33 | } | 33 | } |
34 | 34 | ||
35 | public byte[] GetBytes() | 35 | public byte[] GetBytes() |
36 | { | 36 | { |
37 | VoicePacketHeader header = new VoicePacketHeader(); | 37 | VoicePacketHeader header = new VoicePacketHeader(); |
38 | byte[] bytes = new byte[5+16+4+m_audioData.Length]; | 38 | byte[] bytes = new byte[5+16+4+m_audioData.Length]; |
39 | 39 | ||
40 | header.length = bytes.Length-5; | 40 | header.length = bytes.Length-5; |
41 | 41 | ||
42 | //ToClient packets are type 2 | 42 | //ToClient packets are type 2 |
43 | header.type = 2; | 43 | header.type = 2; |
44 | 44 | ||
45 | int pos = 0; | 45 | int pos = 0; |
46 | header.CopyTo(bytes, pos); pos += 5; | 46 | header.CopyTo(bytes, pos); pos += 5; |
47 | m_clientId.GetBytes().CopyTo(bytes, pos); pos += 16; | 47 | m_clientId.GetBytes().CopyTo(bytes, pos); pos += 16; |
48 | 48 | ||
49 | bytes[pos++] = (byte)((m_codec) % 256); | 49 | bytes[pos++] = (byte)((m_codec) % 256); |
50 | bytes[pos++] = (byte)((m_codec << 8) % 256); | 50 | bytes[pos++] = (byte)((m_codec << 8) % 256); |
51 | bytes[pos++] = (byte)((m_codec << 16) % 256); | 51 | bytes[pos++] = (byte)((m_codec << 16) % 256); |
52 | bytes[pos++] = (byte)((m_codec << 24) % 256); | 52 | bytes[pos++] = (byte)((m_codec << 24) % 256); |
53 | 53 | ||
54 | m_audioData.CopyTo(bytes, pos); | 54 | m_audioData.CopyTo(bytes, pos); |
55 | return bytes; | 55 | return bytes; |
56 | } | 56 | } |
57 | } | 57 | } |
58 | } | 58 | } |
diff --git a/OpenSim/Region/Environment/Modules/VoiceChat/VoicePacketHeader.cs b/OpenSim/Region/Environment/Modules/VoiceChat/VoicePacketHeader.cs index 2f9ec55..19b2e7b 100644 --- a/OpenSim/Region/Environment/Modules/VoiceChat/VoicePacketHeader.cs +++ b/OpenSim/Region/Environment/Modules/VoiceChat/VoicePacketHeader.cs | |||
@@ -1,38 +1,38 @@ | |||
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 | 4 | ||
5 | namespace OpenSim.Region.Environment.Modules.VoiceChat | 5 | namespace OpenSim.Region.Environment.Modules.VoiceChat |
6 | { | 6 | { |
7 | public class VoicePacketHeader | 7 | public class VoicePacketHeader |
8 | { | 8 | { |
9 | public byte type; | 9 | public byte type; |
10 | public int length; | 10 | public int length; |
11 | 11 | ||
12 | public void Parse(byte[] data) | 12 | public void Parse(byte[] data) |
13 | { | 13 | { |
14 | int offset = 0; | 14 | int offset = 0; |
15 | type = data[offset++]; | 15 | type = data[offset++]; |
16 | 16 | ||
17 | length = data[offset++]; | 17 | length = data[offset++]; |
18 | length |= data[offset++] << 8; | 18 | length |= data[offset++] << 8; |
19 | length |= data[offset++] << 16; | 19 | length |= data[offset++] << 16; |
20 | length |= data[offset++] << 24; | 20 | length |= data[offset++] << 24; |
21 | } | 21 | } |
22 | 22 | ||
23 | public void CopyTo(byte[] data, int offset) | 23 | public void CopyTo(byte[] data, int offset) |
24 | { | 24 | { |
25 | data[offset + 0] = type; | 25 | data[offset + 0] = type; |
26 | 26 | ||
27 | data[offset + 1] = (byte)(length & 0x000000FF); | 27 | data[offset + 1] = (byte)(length & 0x000000FF); |
28 | data[offset + 2] = (byte)((length & 0x0000FF00) >> 8); | 28 | data[offset + 2] = (byte)((length & 0x0000FF00) >> 8); |
29 | data[offset + 3] = (byte)((length & 0x00FF0000) >> 16); | 29 | data[offset + 3] = (byte)((length & 0x00FF0000) >> 16); |
30 | data[offset + 4] = (byte)((length & 0xFF000000) >> 24); | 30 | data[offset + 4] = (byte)((length & 0xFF000000) >> 24); |
31 | } | 31 | } |
32 | 32 | ||
33 | public int GetLength() | 33 | public int GetLength() |
34 | { | 34 | { |
35 | return 5; | 35 | return 5; |
36 | } | 36 | } |
37 | } | 37 | } |
38 | } | 38 | } |