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