only call IPlayerCallback::OnPlayBackSpeedChanged if the speed has actually changed
[vuplus_xbmc] / xbmc / peripherals / bus / PeripheralBus.cpp
1 /*
2  *      Copyright (C) 2005-2011 Team XBMC
3  *      http://xbmc.org
4  *
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.
9  *
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.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "PeripheralBus.h"
23 #include "peripherals/Peripherals.h"
24 #include "utils/Variant.h"
25 #include "utils/log.h"
26 #include "FileItem.h"
27
28 using namespace std;
29 using namespace PERIPHERALS;
30
31 #define PERIPHERAL_DEFAULT_RESCAN_INTERVAL 1000
32
33 bool PeripheralScanResult::operator ==(const PeripheralScanResult &right) const
34 {
35   return m_iVendorId == right.m_iVendorId &&
36       m_iProductId == right.m_iProductId &&
37       m_type == right.m_type &&
38       m_strLocation.Equals(right.m_strLocation);
39 }
40
41 bool PeripheralScanResult::operator !=(const PeripheralScanResult &right) const
42 {
43   return !(*this == right);
44 }
45
46 bool PeripheralScanResult::operator ==(const CPeripheral &right) const
47 {
48   return m_iVendorId == right.VendorId() &&
49       m_iProductId == right.ProductId() &&
50       m_type == right.Type() &&
51       m_strLocation.Equals(right.Location());
52 }
53
54 bool PeripheralScanResult::operator !=(const CPeripheral &right) const
55 {
56   return !(*this == right);
57 }
58
59 bool PeripheralScanResults::GetDeviceOnLocation(const CStdString &strLocation, PeripheralScanResult *result) const
60 {
61   bool bReturn(false);
62
63   for (unsigned int iDevicePtr = 0; iDevicePtr < m_results.size(); iDevicePtr++)
64   {
65     if (m_results.at(iDevicePtr).m_strLocation == strLocation)
66     {
67       *result = m_results.at(iDevicePtr);
68       bReturn = true;
69       break;
70     }
71   }
72
73   return bReturn;
74 }
75
76 bool PeripheralScanResults::ContainsResult(const PeripheralScanResult &result) const
77 {
78   bool bReturn(false);
79
80   for (unsigned int iDevicePtr = 0; iDevicePtr < m_results.size(); iDevicePtr++)
81   {
82     if (m_results.at(iDevicePtr) == result)
83     {
84       bReturn = true;
85       break;
86     }
87   }
88
89   return bReturn;
90 }
91
92 CPeripheralBus::CPeripheralBus(CPeripherals *manager, PeripheralBusType type) :
93     CThread("XBMC Peripherals"),
94     m_iRescanTime(PERIPHERAL_DEFAULT_RESCAN_INTERVAL),
95     m_bInitialised(false),
96     m_bIsStarted(false),
97     m_bNeedsPolling(true),
98     m_manager(manager),
99     m_type(type),
100     m_triggerEvent(true)
101 {
102 }
103
104 void CPeripheralBus::OnDeviceAdded(const CStdString &strLocation)
105 {
106   ScanForDevices();
107 }
108
109 void CPeripheralBus::OnDeviceChanged(const CStdString &strLocation)
110 {
111   ScanForDevices();
112 }
113
114 void CPeripheralBus::OnDeviceRemoved(const CStdString &strLocation)
115 {
116   ScanForDevices();
117 }
118
119 void CPeripheralBus::Clear(void)
120 {
121   if (m_bNeedsPolling)
122   {
123     m_bStop = true;
124     m_triggerEvent.Set();
125     StopThread(true);
126   }
127
128   CSingleLock lock(m_critSection);
129   for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
130     delete m_peripherals.at(iPeripheralPtr);
131   m_peripherals.clear();
132 }
133
134 void CPeripheralBus::UnregisterRemovedDevices(const PeripheralScanResults &results)
135 {
136   CSingleLock lock(m_critSection);
137   for (int iDevicePtr = (int) m_peripherals.size() - 1; iDevicePtr >= 0; iDevicePtr--)
138   {
139     CPeripheral *peripheral = m_peripherals.at(iDevicePtr);
140     PeripheralScanResult updatedDevice;
141     if (!results.GetDeviceOnLocation(peripheral->Location(), &updatedDevice) ||
142         updatedDevice != *peripheral)
143     {
144       /* device removed */
145       if (peripheral->Type() != PERIPHERAL_UNKNOWN)
146         CLog::Log(LOGNOTICE, "%s - device removed from %s/%s: %s (%s:%s)", __FUNCTION__, PeripheralTypeTranslator::TypeToString(peripheral->Type()), peripheral->Location().c_str(), peripheral->DeviceName().c_str(), peripheral->VendorIdAsString(), peripheral->ProductIdAsString());
147       m_peripherals.erase(m_peripherals.begin() + iDevicePtr);
148       lock.Leave();
149
150       m_manager->OnDeviceDeleted(*this, peripheral->FileLocation());
151       delete peripheral;
152     }
153   }
154 }
155
156 void CPeripheralBus::RegisterNewDevices(const PeripheralScanResults &results)
157 {
158   CSingleLock lock(m_critSection);
159   for (unsigned int iResultPtr = 0; iResultPtr < results.m_results.size(); iResultPtr++)
160   {
161     PeripheralScanResult result = results.m_results.at(iResultPtr);
162     if (!HasPeripheral(result.m_strLocation) && result.m_type != PERIPHERAL_UNKNOWN)
163       g_peripherals.CreatePeripheral(*this, result.m_type, result.m_strLocation, result.m_iVendorId, result.m_iProductId);
164   }
165 }
166
167 bool CPeripheralBus::ScanForDevices(void)
168 {
169   bool bReturn(false);
170
171   PeripheralScanResults results;
172   if (PerformDeviceScan(results))
173   {
174     UnregisterRemovedDevices(results);
175     RegisterNewDevices(results);
176
177     bReturn = true;
178   }
179
180   m_bInitialised = true;
181   return bReturn;
182 }
183
184 bool CPeripheralBus::HasFeature(const PeripheralFeature feature) const
185 {
186   bool bReturn(false);
187   CSingleLock lock(m_critSection);
188   for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
189   {
190     if (m_peripherals.at(iPeripheralPtr)->HasFeature(feature))
191     {
192       bReturn = true;
193       break;
194     }
195   }
196   return bReturn;
197 }
198
199 void CPeripheralBus::GetFeatures(std::vector<PeripheralFeature> &features) const
200 {
201   CSingleLock lock(m_critSection);
202   for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
203     m_peripherals.at(iPeripheralPtr)->GetFeatures(features);
204 }
205
206 CPeripheral *CPeripheralBus::GetPeripheral(const CStdString &strLocation) const
207 {
208   CPeripheral *peripheral(NULL);
209   CSingleLock lock(m_critSection);
210   for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
211   {
212     if (m_peripherals.at(iPeripheralPtr)->Location() == strLocation)
213     {
214       peripheral = m_peripherals.at(iPeripheralPtr);
215       break;
216     }
217   }
218   return peripheral;
219 }
220
221 int CPeripheralBus::GetPeripheralsWithFeature(vector<CPeripheral *> &results, const PeripheralFeature feature) const
222 {
223   int iReturn(0);
224   CSingleLock lock(m_critSection);
225   for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < m_peripherals.size(); iPeripheralPtr++)
226   {
227     if (m_peripherals.at(iPeripheralPtr)->HasFeature(feature))
228     {
229       results.push_back(m_peripherals.at(iPeripheralPtr));
230       ++iReturn;
231     }
232   }
233
234   return iReturn;
235 }
236
237 void CPeripheralBus::Process(void)
238 {
239   while (!m_bStop)
240   {
241     m_triggerEvent.Reset();
242
243     if (!ScanForDevices())
244       break;
245
246     if (!m_bStop)
247       m_triggerEvent.WaitMSec(m_iRescanTime);
248   }
249
250   m_bIsStarted = false;
251 }
252
253 bool CPeripheralBus::Initialise(void)
254 {
255   CSingleLock lock(m_critSection);
256   if (!m_bIsStarted)
257   {
258     /* do an initial scan of the bus */
259     m_bIsStarted = ScanForDevices();
260
261     if (m_bIsStarted && m_bNeedsPolling)
262     {
263       lock.Leave();
264       m_triggerEvent.Reset();
265       Create();
266       SetPriority(-1);
267     }
268   }
269
270   return m_bIsStarted;
271 }
272
273 void CPeripheralBus::Register(CPeripheral *peripheral)
274 {
275   if (!peripheral)
276     return;
277
278   CSingleLock lock(m_critSection);
279   if (!HasPeripheral(peripheral->Location()))
280   {
281     m_peripherals.push_back(peripheral);
282     CLog::Log(LOGNOTICE, "%s - new %s device registered on %s->%s: %s (%s:%s)", __FUNCTION__, PeripheralTypeTranslator::TypeToString(peripheral->Type()), PeripheralTypeTranslator::BusTypeToString(m_type), peripheral->Location().c_str(), peripheral->DeviceName().c_str(), peripheral->VendorIdAsString(), peripheral->ProductIdAsString());
283     lock.Leave();
284
285     m_manager->OnDeviceAdded(*this, peripheral->FileLocation());
286   }
287 }
288
289 void CPeripheralBus::TriggerDeviceScan(void)
290 {
291   CSingleLock lock(m_critSection);
292   if (m_bNeedsPolling)
293   {
294     lock.Leave();
295     m_triggerEvent.Set();
296   }
297   else
298   {
299     lock.Leave();
300     ScanForDevices();
301   }
302 }
303
304 bool CPeripheralBus::HasPeripheral(const CStdString &strLocation) const
305 {
306   return (GetPeripheral(strLocation) != NULL);
307 }
308
309 void CPeripheralBus::GetDirectory(const CStdString &strPath, CFileItemList &items) const
310 {
311   CStdString strDevPath;
312   CSingleLock lock(m_critSection);
313   for (unsigned int iDevicePtr = 0; iDevicePtr < m_peripherals.size(); iDevicePtr++)
314   {
315     const CPeripheral *peripheral = m_peripherals.at(iDevicePtr);
316     if (peripheral->IsHidden())
317       continue;
318
319     CFileItemPtr peripheralFile(new CFileItem(peripheral->DeviceName()));
320     peripheralFile->SetPath(peripheral->FileLocation());
321     peripheralFile->SetProperty("vendor", peripheral->VendorIdAsString());
322     peripheralFile->SetProperty("product", peripheral->ProductIdAsString());
323     peripheralFile->SetProperty("bus", PeripheralTypeTranslator::BusTypeToString(peripheral->GetBusType()));
324     peripheralFile->SetProperty("location", peripheral->Location());
325     peripheralFile->SetProperty("class", PeripheralTypeTranslator::TypeToString(peripheral->Type()));
326     items.Add(peripheralFile);
327   }
328 }
329
330 CPeripheral *CPeripheralBus::GetByPath(const CStdString &strPath) const
331 {
332   CStdString strDevPath;
333   CSingleLock lock(m_critSection);
334   for (unsigned int iDevicePtr = 0; iDevicePtr < m_peripherals.size(); iDevicePtr++)
335   {
336     if (strPath.Equals(m_peripherals.at(iDevicePtr)->FileLocation()))
337       return m_peripherals.at(iDevicePtr);
338   }
339
340   return NULL;
341 }