VTB: release CVBuffer after it actually has been rendered
[xbmc.git] / xbmc / network / EventServer.cpp
blob12c3e77a59b72773e5d140d8eaee768a790db564
1 /*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "system.h"
23 #ifdef HAS_EVENT_SERVER
25 #include "EventServer.h"
26 #include "EventPacket.h"
27 #include "EventClient.h"
28 #include "Socket.h"
29 #include "threads/CriticalSection.h"
30 #include "Application.h"
31 #include "interfaces/builtins/Builtins.h"
32 #include "input/ButtonTranslator.h"
33 #include "threads/SingleLock.h"
34 #include "Zeroconf.h"
35 #include "guilib/GUIAudioManager.h"
36 #include "input/Key.h"
37 #include "utils/log.h"
38 #include "utils/SystemInfo.h"
39 #include "Util.h"
40 #include <map>
41 #include <queue>
42 #include <cassert>
44 using namespace EVENTSERVER;
45 using namespace EVENTPACKET;
46 using namespace EVENTCLIENT;
47 using namespace SOCKETS;
49 /************************************************************************/
50 /* CEventServer */
51 /************************************************************************/
52 CEventServer* CEventServer::m_pInstance = NULL;
53 CEventServer::CEventServer() : CThread("EventServer")
55 m_pSocket = NULL;
56 m_pPacketBuffer = NULL;
57 m_bStop = false;
58 m_bRunning = false;
59 m_bRefreshSettings = false;
61 // default timeout in ms for receiving a single packet
62 m_iListenTimeout = 1000;
65 void CEventServer::RemoveInstance()
67 if (m_pInstance)
69 delete m_pInstance;
70 m_pInstance=NULL;
74 CEventServer* CEventServer::GetInstance()
76 if (!m_pInstance)
78 m_pInstance = new CEventServer();
80 return m_pInstance;
83 void CEventServer::StartServer()
85 CSingleLock lock(m_critSection);
86 if(m_bRunning)
87 return;
89 // set default port
90 m_iPort = CSettings::GetInstance().GetInt(CSettings::SETTING_SERVICES_ESPORT);
91 assert(m_iPort <= 65535 && m_iPort >= 1);
93 // max clients
94 m_iMaxClients = CSettings::GetInstance().GetInt(CSettings::SETTING_SERVICES_ESMAXCLIENTS);
95 if (m_iMaxClients < 0)
97 CLog::Log(LOGERROR, "ES: Invalid maximum number of clients specified %d", m_iMaxClients);
98 m_iMaxClients = 20;
101 CThread::Create();
104 void CEventServer::StopServer(bool bWait)
106 CZeroconf::GetInstance()->RemoveService("services.eventserver");
107 StopThread(bWait);
110 void CEventServer::Cleanup()
112 if (m_pSocket)
114 m_pSocket->Close();
115 delete m_pSocket;
116 m_pSocket = NULL;
119 if (m_pPacketBuffer)
121 free(m_pPacketBuffer);
122 m_pPacketBuffer = NULL;
124 CSingleLock lock(m_critSection);
126 std::map<unsigned long, CEventClient*>::iterator iter = m_clients.begin();
127 while (iter != m_clients.end())
129 if (iter->second)
131 delete iter->second;
133 m_clients.erase(iter);
134 iter = m_clients.begin();
138 int CEventServer::GetNumberOfClients()
140 CSingleLock lock(m_critSection);
141 return m_clients.size();
144 void CEventServer::Process()
146 while(!m_bStop)
148 Run();
149 if (!m_bStop)
150 Sleep(1000);
154 void CEventServer::Run()
156 CSocketListener listener;
157 int packetSize = 0;
159 CLog::Log(LOGNOTICE, "ES: Starting UDP Event server on port %d", m_iPort);
161 Cleanup();
163 // create socket and initialize buffer
164 m_pSocket = CSocketFactory::CreateUDPSocket();
165 if (!m_pSocket)
167 CLog::Log(LOGERROR, "ES: Could not create socket, aborting!");
168 return;
170 m_pPacketBuffer = (unsigned char *)malloc(PACKET_SIZE);
172 if (!m_pPacketBuffer)
174 CLog::Log(LOGERROR, "ES: Out of memory, could not allocate packet buffer");
175 return;
178 // bind to IP and start listening on port
179 int port_range = CSettings::GetInstance().GetInt(CSettings::SETTING_SERVICES_ESPORTRANGE);
180 if (port_range < 1 || port_range > 100)
182 CLog::Log(LOGERROR, "ES: Invalid port range specified %d, defaulting to 10", port_range);
183 port_range = 10;
185 if (!m_pSocket->Bind(!CSettings::GetInstance().GetBool(CSettings::SETTING_SERVICES_ESALLINTERFACES), m_iPort, port_range))
187 CLog::Log(LOGERROR, "ES: Could not listen on port %d", m_iPort);
188 return;
191 // publish service
192 std::vector<std::pair<std::string, std::string> > txt;
193 CZeroconf::GetInstance()->PublishService("servers.eventserver",
194 "_xbmc-events._udp",
195 CSysInfo::GetDeviceName(),
196 m_iPort,
197 txt);
199 // add our socket to the 'select' listener
200 listener.AddSocket(m_pSocket);
202 m_bRunning = true;
204 while (!m_bStop)
208 // start listening until we timeout
209 if (listener.Listen(m_iListenTimeout))
211 CAddress addr;
212 if ((packetSize = m_pSocket->Read(addr, PACKET_SIZE, (void *)m_pPacketBuffer)) > -1)
214 ProcessPacket(addr, packetSize);
218 catch (...)
220 CLog::Log(LOGERROR, "ES: Exception caught while listening for socket");
221 break;
224 // process events and queue the necessary actions and button codes
225 ProcessEvents();
227 // refresh client list
228 RefreshClients();
230 // broadcast
231 // BroadcastBeacon();
234 CLog::Log(LOGNOTICE, "ES: UDP Event server stopped");
235 m_bRunning = false;
236 Cleanup();
239 void CEventServer::ProcessPacket(CAddress& addr, int pSize)
241 // check packet validity
242 CEventPacket* packet = new CEventPacket(pSize, m_pPacketBuffer);
243 if(packet == NULL)
245 CLog::Log(LOGERROR, "ES: Out of memory, cannot accept packet");
246 return;
249 unsigned int clientToken;
251 if (!packet->IsValid())
253 CLog::Log(LOGDEBUG, "ES: Received invalid packet");
254 delete packet;
255 return;
258 clientToken = packet->ClientToken();
259 if (!clientToken)
260 clientToken = addr.ULong(); // use IP if packet doesn't have a token
262 CSingleLock lock(m_critSection);
264 // first check if we have a client for this address
265 std::map<unsigned long, CEventClient*>::iterator iter = m_clients.find(clientToken);
267 if ( iter == m_clients.end() )
269 if ( m_clients.size() >= (unsigned int)m_iMaxClients)
271 CLog::Log(LOGWARNING, "ES: Cannot accept any more clients, maximum client count reached");
272 delete packet;
273 return;
276 // new client
277 CEventClient* client = new CEventClient ( addr );
278 if (client==NULL)
280 CLog::Log(LOGERROR, "ES: Out of memory, cannot accept new client connection");
281 delete packet;
282 return;
285 m_clients[clientToken] = client;
287 m_clients[clientToken]->AddPacket(packet);
290 void CEventServer::RefreshClients()
292 CSingleLock lock(m_critSection);
293 std::map<unsigned long, CEventClient*>::iterator iter = m_clients.begin();
295 while ( iter != m_clients.end() )
297 if (! (iter->second->Alive()))
299 CLog::Log(LOGNOTICE, "ES: Client %s from %s timed out", iter->second->Name().c_str(),
300 iter->second->Address().Address());
301 delete iter->second;
302 m_clients.erase(iter);
303 iter = m_clients.begin();
305 else
307 if (m_bRefreshSettings)
309 iter->second->RefreshSettings();
311 ++iter;
314 m_bRefreshSettings = false;
317 void CEventServer::ProcessEvents()
319 CSingleLock lock(m_critSection);
320 std::map<unsigned long, CEventClient*>::iterator iter = m_clients.begin();
322 while (iter != m_clients.end())
324 iter->second->ProcessEvents();
325 ++iter;
329 bool CEventServer::ExecuteNextAction()
331 CSingleLock lock(m_critSection);
333 CEventAction actionEvent;
334 std::map<unsigned long, CEventClient*>::iterator iter = m_clients.begin();
336 while (iter != m_clients.end())
338 if (iter->second->GetNextAction(actionEvent))
340 // Leave critical section before processing action
341 lock.Leave();
342 switch(actionEvent.actionType)
344 case AT_EXEC_BUILTIN:
345 CBuiltins::GetInstance().Execute(actionEvent.actionName);
346 break;
348 case AT_BUTTON:
350 int actionID;
351 CButtonTranslator::TranslateActionString(actionEvent.actionName.c_str(), actionID);
352 CAction action(actionID, 1.0f, 0.0f, actionEvent.actionName);
353 g_audioManager.PlayActionSound(action);
354 g_application.OnAction(action);
356 break;
358 return true;
360 ++iter;
363 return false;
366 unsigned int CEventServer::GetButtonCode(std::string& strMapName, bool& isAxis, float& fAmount, bool &isJoystick)
368 CSingleLock lock(m_critSection);
369 std::map<unsigned long, CEventClient*>::iterator iter = m_clients.begin();
370 unsigned int bcode = 0;
372 while (iter != m_clients.end())
374 bcode = iter->second->GetButtonCode(strMapName, isAxis, fAmount, isJoystick);
375 if (bcode)
376 return bcode;
377 ++iter;
379 return bcode;
382 bool CEventServer::GetMousePos(float &x, float &y)
384 CSingleLock lock(m_critSection);
385 std::map<unsigned long, CEventClient*>::iterator iter = m_clients.begin();
387 while (iter != m_clients.end())
389 if (iter->second->GetMousePos(x, y))
390 return true;
391 ++iter;
393 return false;
396 #endif // HAS_EVENT_SERVER