Merge pull request #4775 from jmarshallnz/empty_episode_playcount
[vuplus_xbmc] / xbmc / peripherals / Peripherals.cpp
1 /*
2  *      Copyright (C) 2005-2013 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, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "Peripherals.h"
22 #include "bus/PeripheralBus.h"
23 #include "devices/PeripheralBluetooth.h"
24 #include "devices/PeripheralDisk.h"
25 #include "devices/PeripheralHID.h"
26 #include "devices/PeripheralNIC.h"
27 #include "devices/PeripheralNyxboard.h"
28 #include "devices/PeripheralTuner.h"
29 #include "devices/PeripheralCecAdapter.h"
30 #include "devices/PeripheralImon.h"
31 #include "bus/PeripheralBusUSB.h"
32 #include "dialogs/GUIDialogPeripheralManager.h"
33
34 #if defined(HAVE_LIBCEC)
35 #include "bus/virtual/PeripheralBusCEC.h"
36 #endif
37
38 #include "threads/SingleLock.h"
39 #include "utils/log.h"
40 #include "utils/XMLUtils.h"
41 #include "utils/XBMCTinyXML.h"
42 #include "filesystem/Directory.h"
43 #include "guilib/GUIWindowManager.h"
44 #include "guilib/LocalizeStrings.h"
45 #include "dialogs/GUIDialogKaiToast.h"
46 #include "GUIUserMessages.h"
47 #include "utils/StringUtils.h"
48 #include "Util.h"
49 #include "guilib/Key.h"
50 #include "settings/lib/Setting.h"
51
52 using namespace PERIPHERALS;
53 using namespace XFILE;
54 using namespace std;
55
56 CPeripherals::CPeripherals(void)
57 {
58   Clear();
59 }
60
61 CPeripherals::~CPeripherals(void)
62 {
63   Clear();
64 }
65
66 CPeripherals &CPeripherals::Get(void)
67 {
68   static CPeripherals peripheralsInstance;
69   return peripheralsInstance;
70 }
71
72 void CPeripherals::Initialise(void)
73 {
74   CSingleLock lock(m_critSection);
75   if (!m_bIsStarted)
76   {
77     m_bIsStarted = true;
78
79     CDirectory::Create("special://profile/peripheral_data");
80
81     /* load mappings from peripherals.xml */
82     LoadMappings();
83
84 #if defined(HAVE_PERIPHERAL_BUS_USB)
85     m_busses.push_back(new CPeripheralBusUSB(this));
86 #endif
87 #if defined(HAVE_LIBCEC)
88     m_busses.push_back(new CPeripheralBusCEC(this));
89 #endif
90
91     /* initialise all known busses */
92     for (int iBusPtr = (int)m_busses.size() - 1; iBusPtr >= 0; iBusPtr--)
93     {
94       if (!m_busses.at(iBusPtr)->Initialise())
95       {
96         CLog::Log(LOGERROR, "%s - failed to initialise bus %s", __FUNCTION__, PeripheralTypeTranslator::BusTypeToString(m_busses.at(iBusPtr)->Type()));
97         delete m_busses.at(iBusPtr);
98         m_busses.erase(m_busses.begin() + iBusPtr);
99       }
100     }
101
102     m_bInitialised = true;
103   }
104 }
105
106 void CPeripherals::Clear(void)
107 {
108   CSingleLock lock(m_critSection);
109   /* delete busses and devices */
110   for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
111     delete m_busses.at(iBusPtr);
112   m_busses.clear();
113
114   /* delete mappings */
115   for (unsigned int iMappingPtr = 0; iMappingPtr < m_mappings.size(); iMappingPtr++)
116   {
117     map<CStdString, PeripheralDeviceSetting> settings = m_mappings.at(iMappingPtr).m_settings;
118     for (map<CStdString, PeripheralDeviceSetting>::iterator itr = settings.begin(); itr != settings.end(); ++itr)
119       delete itr->second.m_setting;
120     m_mappings.at(iMappingPtr).m_settings.clear();
121   }
122   m_mappings.clear();
123
124   /* reset class state */
125   m_bIsStarted   = false;
126   m_bInitialised = false;
127 #if !defined(HAVE_LIBCEC)
128   m_bMissingLibCecWarningDisplayed = false;
129 #endif
130 }
131
132 void CPeripherals::TriggerDeviceScan(const PeripheralBusType type /* = PERIPHERAL_BUS_UNKNOWN */)
133 {
134   CSingleLock lock(m_critSection);
135   for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
136   {
137     if (type == PERIPHERAL_BUS_UNKNOWN || m_busses.at(iBusPtr)->Type() == type)
138     {
139       m_busses.at(iBusPtr)->TriggerDeviceScan();
140       if (type != PERIPHERAL_BUS_UNKNOWN)
141         break;
142     }
143   }
144 }
145
146 CPeripheralBus *CPeripherals::GetBusByType(const PeripheralBusType type) const
147 {
148   CSingleLock lock(m_critSection);
149   CPeripheralBus *bus(NULL);
150   for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
151   {
152     if (m_busses.at(iBusPtr)->Type() == type)
153     {
154       bus = m_busses.at(iBusPtr);
155       break;
156     }
157   }
158
159   return bus;
160 }
161
162 CPeripheral *CPeripherals::GetPeripheralAtLocation(const CStdString &strLocation, PeripheralBusType busType /* = PERIPHERAL_BUS_UNKNOWN */) const
163 {
164   CSingleLock lock(m_critSection);
165   CPeripheral *peripheral(NULL);
166   for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
167   {
168     /* check whether the bus matches if a bus type other than unknown was passed */
169     if (busType != PERIPHERAL_BUS_UNKNOWN && m_busses.at(iBusPtr)->Type() != busType)
170       continue;
171
172     /* return the first device that matches */
173     if ((peripheral = m_busses.at(iBusPtr)->GetPeripheral(strLocation)) != NULL)
174       break;
175   }
176
177   return peripheral;
178 }
179
180 bool CPeripherals::HasPeripheralAtLocation(const CStdString &strLocation, PeripheralBusType busType /* = PERIPHERAL_BUS_UNKNOWN */) const
181 {
182   return (GetPeripheralAtLocation(strLocation, busType) != NULL);
183 }
184
185 CPeripheralBus *CPeripherals::GetBusWithDevice(const CStdString &strLocation) const
186 {
187   CSingleLock lock(m_critSection);
188   for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
189   {
190     /* return the first bus that matches */
191     if (m_busses.at(iBusPtr)->HasPeripheral(strLocation))
192       return m_busses.at(iBusPtr);
193   }
194
195   return NULL;
196 }
197
198 int CPeripherals::GetPeripheralsWithFeature(vector<CPeripheral *> &results, const PeripheralFeature feature, PeripheralBusType busType /* = PERIPHERAL_BUS_UNKNOWN */) const
199 {
200   CSingleLock lock(m_critSection);
201   int iReturn(0);
202   for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
203   {
204     /* check whether the bus matches if a bus type other than unknown was passed */
205     if (busType != PERIPHERAL_BUS_UNKNOWN && m_busses.at(iBusPtr)->Type() != busType)
206       continue;
207
208     iReturn += m_busses.at(iBusPtr)->GetPeripheralsWithFeature(results, feature);
209   }
210
211   return iReturn;
212 }
213
214 size_t CPeripherals::GetNumberOfPeripherals() const
215 {
216   size_t iReturn(0);
217   CSingleLock lock(m_critSection);
218   for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
219   {
220     iReturn += m_busses.at(iBusPtr)->GetNumberOfPeripherals();
221   }
222
223   return iReturn;
224 }
225
226 bool CPeripherals::HasPeripheralWithFeature(const PeripheralFeature feature, PeripheralBusType busType /* = PERIPHERAL_BUS_UNKNOWN */) const
227 {
228   vector<CPeripheral *> dummy;
229   return (GetPeripheralsWithFeature(dummy, feature, busType) > 0);
230 }
231
232 CPeripheral *CPeripherals::CreatePeripheral(CPeripheralBus &bus, const PeripheralScanResult& result)
233 {
234   CPeripheral *peripheral = NULL;
235   PeripheralScanResult mappedResult = result;
236   if (mappedResult.m_busType == PERIPHERAL_BUS_UNKNOWN)
237     mappedResult.m_busType = bus.Type();
238
239   /* check whether there's something mapped in peripherals.xml */
240   if (!GetMappingForDevice(bus, mappedResult))
241   {
242     /* don't create instances for devices that aren't mapped in peripherals.xml */
243     return NULL;
244   }
245
246   switch(mappedResult.m_mappedType)
247   {
248   case PERIPHERAL_HID:
249     peripheral = new CPeripheralHID(mappedResult);
250     break;
251
252   case PERIPHERAL_NIC:
253     peripheral = new CPeripheralNIC(mappedResult);
254     break;
255
256   case PERIPHERAL_DISK:
257     peripheral = new CPeripheralDisk(mappedResult);
258     break;
259
260   case PERIPHERAL_NYXBOARD:
261     peripheral = new CPeripheralNyxboard(mappedResult);
262     break;
263
264   case PERIPHERAL_TUNER:
265     peripheral = new CPeripheralTuner(mappedResult);
266     break;
267
268   case PERIPHERAL_BLUETOOTH:
269     peripheral = new CPeripheralBluetooth(mappedResult);
270     break;
271
272   case PERIPHERAL_CEC:
273 #if defined(HAVE_LIBCEC)
274     if (bus.Type() == PERIPHERAL_BUS_CEC)
275       peripheral = new CPeripheralCecAdapter(mappedResult);
276 #else
277     if (!m_bMissingLibCecWarningDisplayed)
278     {
279       m_bMissingLibCecWarningDisplayed = true;
280       CLog::Log(LOGWARNING, "%s - libCEC support has not been compiled in, so the CEC adapter cannot be used.", __FUNCTION__);
281       CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(36000), g_localizeStrings.Get(36017));
282     }
283 #endif
284     break;
285
286   case PERIPHERAL_IMON:
287     peripheral = new CPeripheralImon(mappedResult);
288     break;
289
290   default:
291     break;
292   }
293
294   if (peripheral)
295   {
296     /* try to initialise the new peripheral
297      * Initialise() will make sure that each device is only initialised once */
298     if (peripheral->Initialise())
299     {
300       bus.Register(peripheral);
301     }
302     else
303     {
304       CLog::Log(LOGDEBUG, "%s - failed to initialise peripheral on '%s'", __FUNCTION__, mappedResult.m_strLocation.c_str());
305       delete peripheral;
306       peripheral = NULL;
307     }
308   }
309
310   return peripheral;
311 }
312
313 void CPeripherals::OnDeviceAdded(const CPeripheralBus &bus, const CPeripheral &peripheral)
314 {
315   CGUIDialogPeripheralManager *dialog = (CGUIDialogPeripheralManager *)g_windowManager.GetWindow(WINDOW_DIALOG_PERIPHERAL_MANAGER);
316   if (dialog && dialog->IsActive())
317     dialog->Update();
318
319   // refresh settings (peripherals manager could be enabled now)
320   CGUIMessage msg(GUI_MSG_UPDATE, WINDOW_SETTINGS_SYSTEM, 0);
321   g_windowManager.SendThreadMessage(msg, WINDOW_SETTINGS_SYSTEM);
322
323   SetChanged();
324
325   // don't show a notification for devices detected during the initial scan
326   if (bus.IsInitialised())
327     CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(35005), peripheral.DeviceName());
328 }
329
330 void CPeripherals::OnDeviceDeleted(const CPeripheralBus &bus, const CPeripheral &peripheral)
331 {
332   CGUIDialogPeripheralManager *dialog = (CGUIDialogPeripheralManager *)g_windowManager.GetWindow(WINDOW_DIALOG_PERIPHERAL_MANAGER);
333   if (dialog && dialog->IsActive())
334     dialog->Update();
335
336   // refresh settings (peripherals manager could be disabled now)
337   CGUIMessage msg(GUI_MSG_UPDATE, WINDOW_SETTINGS_SYSTEM, 0);
338   g_windowManager.SendThreadMessage(msg, WINDOW_SETTINGS_SYSTEM);
339
340   SetChanged();
341
342   CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, g_localizeStrings.Get(35006), peripheral.DeviceName());
343 }
344
345 bool CPeripherals::GetMappingForDevice(const CPeripheralBus &bus, PeripheralScanResult& result) const
346 {
347   /* check all mappings in the order in which they are defined in peripherals.xml */
348   for (unsigned int iMappingPtr = 0; iMappingPtr < m_mappings.size(); iMappingPtr++)
349   {
350     PeripheralDeviceMapping mapping = m_mappings.at(iMappingPtr);
351
352     bool bProductMatch = false;
353     if (mapping.m_PeripheralID.size() == 0)
354     {
355       bProductMatch = true;
356     }
357     else
358     {
359       for (unsigned int i = 0; i < mapping.m_PeripheralID.size(); i++)
360         if (mapping.m_PeripheralID[i].m_iVendorId == result.m_iVendorId && mapping.m_PeripheralID[i].m_iProductId == result.m_iProductId)
361           bProductMatch = true;
362     }
363
364     bool bBusMatch = (mapping.m_busType == PERIPHERAL_BUS_UNKNOWN || mapping.m_busType == bus.Type());
365     bool bClassMatch = (mapping.m_class == PERIPHERAL_UNKNOWN || mapping.m_class == result.m_type);
366
367     if (bProductMatch && bBusMatch && bClassMatch)
368     {
369       CStdString strVendorId, strProductId;
370       PeripheralTypeTranslator::FormatHexString(result.m_iVendorId, strVendorId);
371       PeripheralTypeTranslator::FormatHexString(result.m_iProductId, strProductId);
372       CLog::Log(LOGDEBUG, "%s - device (%s:%s) mapped to %s (type = %s)", __FUNCTION__, strVendorId.c_str(), strProductId.c_str(), mapping.m_strDeviceName.c_str(), PeripheralTypeTranslator::TypeToString(mapping.m_mappedTo));
373       result.m_mappedType    = m_mappings[iMappingPtr].m_mappedTo;
374       result.m_strDeviceName = m_mappings[iMappingPtr].m_strDeviceName;
375       return true;
376     }
377   }
378
379   return false;
380 }
381
382 void CPeripherals::GetSettingsFromMapping(CPeripheral &peripheral) const
383 {
384   /* check all mappings in the order in which they are defined in peripherals.xml */
385   for (unsigned int iMappingPtr = 0; iMappingPtr < m_mappings.size(); iMappingPtr++)
386   {
387     const PeripheralDeviceMapping *mapping = &m_mappings.at(iMappingPtr);
388
389     bool bProductMatch = false;
390     if (mapping->m_PeripheralID.size() == 0)
391     {
392       bProductMatch = true;
393     }
394     else
395     {
396       for (unsigned int i = 0; i < mapping->m_PeripheralID.size(); i++)
397         if (mapping->m_PeripheralID[i].m_iVendorId == peripheral.VendorId() && mapping->m_PeripheralID[i].m_iProductId == peripheral.ProductId())
398           bProductMatch = true;
399     }
400
401     bool bBusMatch = (mapping->m_busType == PERIPHERAL_BUS_UNKNOWN || mapping->m_busType == peripheral.GetBusType());
402     bool bClassMatch = (mapping->m_class == PERIPHERAL_UNKNOWN || mapping->m_class == peripheral.Type());
403
404     if (bBusMatch && bProductMatch && bClassMatch)
405     {
406       for (map<CStdString, PeripheralDeviceSetting>::const_iterator itr = mapping->m_settings.begin(); itr != mapping->m_settings.end(); ++itr)
407         peripheral.AddSetting((*itr).first, (*itr).second.m_setting, (*itr).second.m_order);
408     }
409   }
410 }
411
412 bool CPeripherals::LoadMappings(void)
413 {
414   CXBMCTinyXML xmlDoc;
415   if (!xmlDoc.LoadFile("special://xbmc/system/peripherals.xml"))
416   {
417     CLog::Log(LOGWARNING, "%s - peripherals.xml does not exist", __FUNCTION__);
418     return true;
419   }
420
421   TiXmlElement *pRootElement = xmlDoc.RootElement();
422   if (strcmpi(pRootElement->Value(), "peripherals") != 0)
423   {
424     CLog::Log(LOGERROR, "%s - peripherals.xml does not contain <peripherals>", __FUNCTION__);
425     return false;
426   }
427
428   for (TiXmlElement *currentNode = pRootElement->FirstChildElement("peripheral"); currentNode; currentNode = currentNode->NextSiblingElement("peripheral"))
429   {
430     CStdStringArray vpArray, idArray;
431     PeripheralID id;
432     PeripheralDeviceMapping mapping;
433
434     mapping.m_strDeviceName = currentNode->Attribute("name") ? CStdString(currentNode->Attribute("name")) : StringUtils::EmptyString;
435
436     // If there is no vendor_product attribute ignore this entry
437     if (currentNode->Attribute("vendor_product"))
438     {
439       // The vendor_product attribute is a list of comma separated vendor:product pairs
440       StringUtils::SplitString(currentNode->Attribute("vendor_product"), ",", vpArray);
441       for (unsigned int i = 0; i < vpArray.size(); i++)
442       {
443         StringUtils::SplitString(vpArray[i], ":", idArray);
444         if (idArray.size() != 2)
445         {
446           CLog::Log(LOGERROR, "%s - ignoring node \"%s\" with invalid vendor_product attribute", __FUNCTION__, mapping.m_strDeviceName.c_str());
447           continue;
448         }
449
450         id.m_iVendorId = PeripheralTypeTranslator::HexStringToInt(idArray[0]);
451         id.m_iProductId = PeripheralTypeTranslator::HexStringToInt(idArray[1]);
452         mapping.m_PeripheralID.push_back(id);
453       }
454     }
455
456     mapping.m_busType       = PeripheralTypeTranslator::GetBusTypeFromString(currentNode->Attribute("bus"));
457     mapping.m_class         = PeripheralTypeTranslator::GetTypeFromString(currentNode->Attribute("class"));
458     mapping.m_mappedTo      = PeripheralTypeTranslator::GetTypeFromString(currentNode->Attribute("mapTo"));
459     GetSettingsFromMappingsFile(currentNode, mapping.m_settings);
460
461     m_mappings.push_back(mapping);
462     CLog::Log(LOGDEBUG, "%s - loaded node \"%s\"", __FUNCTION__, mapping.m_strDeviceName.c_str());
463   }
464
465   return true;
466 }
467
468 void CPeripherals::GetSettingsFromMappingsFile(TiXmlElement *xmlNode, map<CStdString, PeripheralDeviceSetting> &settings)
469 {
470   TiXmlElement *currentNode = xmlNode->FirstChildElement("setting");
471   int iMaxOrder = 0;
472
473   while (currentNode)
474   {
475     CSetting *setting = NULL;
476     CStdString strKey(currentNode->Attribute("key"));
477     if (strKey.empty())
478       continue;
479
480     CStdString strSettingsType(currentNode->Attribute("type"));
481     int iLabelId = currentNode->Attribute("label") ? atoi(currentNode->Attribute("label")) : -1;
482     bool bConfigurable = (!currentNode->Attribute("configurable") ||
483                           strcmp(currentNode->Attribute("configurable"), "") == 0 ||
484                            (strcmp(currentNode->Attribute("configurable"), "no") != 0 &&
485                             strcmp(currentNode->Attribute("configurable"), "false") != 0 &&
486                             strcmp(currentNode->Attribute("configurable"), "0") != 0));
487     if (strSettingsType.Equals("bool"))
488     {
489       bool bValue = (strcmp(currentNode->Attribute("value"), "no") != 0 &&
490                      strcmp(currentNode->Attribute("value"), "false") != 0 &&
491                      strcmp(currentNode->Attribute("value"), "0") != 0);
492       setting = new CSettingBool(strKey, iLabelId, bValue);
493     }
494     else if (strSettingsType.Equals("int"))
495     {
496       int iValue = currentNode->Attribute("value") ? atoi(currentNode->Attribute("value")) : 0;
497       int iMin   = currentNode->Attribute("min") ? atoi(currentNode->Attribute("min")) : 0;
498       int iStep  = currentNode->Attribute("step") ? atoi(currentNode->Attribute("step")) : 1;
499       int iMax   = currentNode->Attribute("max") ? atoi(currentNode->Attribute("max")) : 255;
500       setting = new CSettingInt(strKey, iLabelId, iValue, iMin, iStep, iMax);
501     }
502     else if (strSettingsType.Equals("float"))
503     {
504       float fValue = currentNode->Attribute("value") ? (float) atof(currentNode->Attribute("value")) : 0;
505       float fMin   = currentNode->Attribute("min") ? (float) atof(currentNode->Attribute("min")) : 0;
506       float fStep  = currentNode->Attribute("step") ? (float) atof(currentNode->Attribute("step")) : 0;
507       float fMax   = currentNode->Attribute("max") ? (float) atof(currentNode->Attribute("max")) : 0;
508       setting = new CSettingNumber(strKey, iLabelId, fValue, fMin, fStep, fMax);
509     }
510     else if (strSettingsType.Equals("enum"))
511     {
512       CStdString strEnums(currentNode->Attribute("lvalues"));
513       if (!strEnums.empty())
514       {
515         vector< pair<int,int> > enums;
516         vector<std::string> valuesVec;
517         StringUtils::Tokenize(strEnums, valuesVec, "|");
518         for (unsigned int i = 0; i < valuesVec.size(); i++)
519           enums.push_back(make_pair(atoi(valuesVec[i].c_str()), atoi(valuesVec[i].c_str())));
520         int iValue = currentNode->Attribute("value") ? atoi(currentNode->Attribute("value")) : 0;
521         setting = new CSettingInt(strKey, iLabelId, iValue, enums);
522       }
523     }
524     else
525     {
526       CStdString strValue(currentNode->Attribute("value"));
527       setting = new CSettingString(strKey, iLabelId, strValue);
528     }
529
530     if (setting)
531     {
532       //TODO add more types if needed
533
534       /* set the visibility */
535       setting->SetVisible(bConfigurable);
536
537       /* set the order */
538       int iOrder = 0;
539       currentNode->Attribute("order", &iOrder);
540       /* if the order attribute is invalid or 0, then the setting will be added at the end */
541       if (iOrder < 0)
542         iOrder = 0;
543       if (iOrder > iMaxOrder)
544        iMaxOrder = iOrder;
545
546       /* and add this new setting */
547       PeripheralDeviceSetting deviceSetting = { setting, iOrder };
548       settings[strKey] = deviceSetting;
549     }
550
551     currentNode = currentNode->NextSiblingElement("setting");
552   }
553
554   /* add the settings without an order attribute or an invalid order attribute set at the end */
555   for (map<CStdString, PeripheralDeviceSetting>::iterator it = settings.begin(); it != settings.end(); ++it)
556   {
557     if (it->second.m_order == 0)
558       it->second.m_order = ++iMaxOrder;
559   }
560 }
561
562 void CPeripherals::GetDirectory(const CStdString &strPath, CFileItemList &items) const
563 {
564   if (!StringUtils::StartsWithNoCase(strPath, "peripherals://"))
565     return;
566
567   CStdString strPathCut = strPath.substr(14);
568   CStdString strBus = strPathCut.substr(0, strPathCut.find('/'));
569
570   CSingleLock lock(m_critSection);
571   for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
572   {
573     if (strBus.Equals("all") || strBus.Equals(PeripheralTypeTranslator::BusTypeToString(m_busses.at(iBusPtr)->Type())))
574       m_busses.at(iBusPtr)->GetDirectory(strPath, items);
575   }
576 }
577
578 CPeripheral *CPeripherals::GetByPath(const CStdString &strPath) const
579 {
580   if (!StringUtils::StartsWithNoCase(strPath, "peripherals://"))
581     return NULL;
582
583   CStdString strPathCut = strPath.substr(14);
584   CStdString strBus = strPathCut.substr(0, strPathCut.find('/'));
585
586   CSingleLock lock(m_critSection);
587   for (unsigned int iBusPtr = 0; iBusPtr < m_busses.size(); iBusPtr++)
588   {
589     if (strBus.Equals(PeripheralTypeTranslator::BusTypeToString(m_busses.at(iBusPtr)->Type())))
590       return m_busses.at(iBusPtr)->GetByPath(strPath);
591   }
592
593   return NULL;
594 }
595
596 bool CPeripherals::OnAction(const CAction &action)
597 {
598   if (action.GetID() == ACTION_MUTE)
599   {
600     return ToggleMute();
601   }
602
603   if (SupportsCEC() && action.GetAmount() && (action.GetID() == ACTION_VOLUME_UP || action.GetID() == ACTION_VOLUME_DOWN))
604   {
605     vector<CPeripheral *> peripherals;
606     if (GetPeripheralsWithFeature(peripherals, FEATURE_CEC))
607     {
608       for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < peripherals.size(); iPeripheralPtr++)
609       {
610         CPeripheralCecAdapter *cecDevice = (CPeripheralCecAdapter *) peripherals.at(iPeripheralPtr);
611         if (cecDevice && cecDevice->HasAudioControl())
612         {
613           if (action.GetID() == ACTION_VOLUME_UP)
614             cecDevice->VolumeUp();
615           else
616             cecDevice->VolumeDown();
617           return true;
618         }
619       }
620     }
621   }
622
623   return false;
624 }
625
626 bool CPeripherals::IsMuted(void)
627 {
628   vector<CPeripheral *> peripherals;
629   if (SupportsCEC() && GetPeripheralsWithFeature(peripherals, FEATURE_CEC))
630   {
631     for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < peripherals.size(); iPeripheralPtr++)
632     {
633       CPeripheralCecAdapter *cecDevice = (CPeripheralCecAdapter *) peripherals.at(iPeripheralPtr);
634       if (cecDevice && cecDevice->IsMuted())
635         return true;
636     }
637   }
638
639   return false;
640 }
641
642 bool CPeripherals::ToggleMute(void)
643 {
644   vector<CPeripheral *> peripherals;
645   if (SupportsCEC() && GetPeripheralsWithFeature(peripherals, FEATURE_CEC))
646   {
647     for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < peripherals.size(); iPeripheralPtr++)
648     {
649       CPeripheralCecAdapter *cecDevice = (CPeripheralCecAdapter *) peripherals.at(iPeripheralPtr);
650       if (cecDevice && cecDevice->HasAudioControl())
651       {
652         cecDevice->ToggleMute();
653         return true;
654       }
655     }
656   }
657
658   return false;
659 }
660
661 bool CPeripherals::ToggleDeviceState(CecStateChange mode /*= STATE_SWITCH_TOGGLE */, unsigned int iPeripheral /*= 0 */)
662 {
663   bool ret(false);
664   vector<CPeripheral *> peripherals;
665
666   if (SupportsCEC() && GetPeripheralsWithFeature(peripherals, FEATURE_CEC))
667   {
668     for (unsigned int iPeripheralPtr = iPeripheral; iPeripheralPtr < peripherals.size(); iPeripheralPtr++)
669     {
670       CPeripheralCecAdapter *cecDevice = (CPeripheralCecAdapter *) peripherals.at(iPeripheralPtr);
671       if (cecDevice)
672         ret = cecDevice->ToggleDeviceState(mode);
673       if (iPeripheral)
674         break;
675     }
676   }
677
678   return ret;
679 }
680
681 bool CPeripherals::GetNextKeypress(float frameTime, CKey &key)
682 {
683   vector<CPeripheral *> peripherals;
684   if (SupportsCEC() && GetPeripheralsWithFeature(peripherals, FEATURE_CEC))
685   {
686     for (unsigned int iPeripheralPtr = 0; iPeripheralPtr < peripherals.size(); iPeripheralPtr++)
687     {
688       CPeripheralCecAdapter *cecDevice = (CPeripheralCecAdapter *) peripherals.at(iPeripheralPtr);
689       if (cecDevice && cecDevice->GetButton())
690       {
691         CKey newKey(cecDevice->GetButton(), cecDevice->GetHoldTime());
692         cecDevice->ResetButton();
693         key = newKey;
694         return true;
695       }
696     }
697   }
698
699   return false;
700 }
701
702 void CPeripherals::OnSettingChanged(const CSetting *setting)
703 {
704   if (setting == NULL)
705     return;
706
707   const std::string &settingId = setting->GetId();
708   if (settingId == "locale.language")
709   {
710     // user set language, no longer use the TV's language
711     vector<CPeripheral *> cecDevices;
712     if (g_peripherals.GetPeripheralsWithFeature(cecDevices, FEATURE_CEC) > 0)
713     {
714       for (vector<CPeripheral *>::iterator it = cecDevices.begin(); it != cecDevices.end(); ++it)
715         (*it)->SetSetting("use_tv_menu_language", false);
716     }
717   }
718 }
719
720 void CPeripherals::OnSettingAction(const CSetting *setting)
721 {
722   if (setting == NULL)
723     return;
724
725   const std::string &settingId = setting->GetId();
726   if (settingId == "input.peripherals")
727   {
728     CGUIDialogPeripheralManager *dialog = (CGUIDialogPeripheralManager *)g_windowManager.GetWindow(WINDOW_DIALOG_PERIPHERAL_MANAGER);
729     if (dialog != NULL)
730       dialog->DoModal();
731   }
732 }