diff options
Diffstat (limited to 'xbmc/peripherals/bus/virtual')
-rw-r--r-- | xbmc/peripherals/bus/virtual/CMakeLists.txt | 12 | ||||
-rw-r--r-- | xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp | 502 | ||||
-rw-r--r-- | xbmc/peripherals/bus/virtual/PeripheralBusAddon.h | 94 | ||||
-rw-r--r-- | xbmc/peripherals/bus/virtual/PeripheralBusApplication.cpp | 83 | ||||
-rw-r--r-- | xbmc/peripherals/bus/virtual/PeripheralBusApplication.h | 40 | ||||
-rw-r--r-- | xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp | 57 | ||||
-rw-r--r-- | xbmc/peripherals/bus/virtual/PeripheralBusCEC.h | 43 |
7 files changed, 831 insertions, 0 deletions
diff --git a/xbmc/peripherals/bus/virtual/CMakeLists.txt b/xbmc/peripherals/bus/virtual/CMakeLists.txt new file mode 100644 index 0000000..bf59695 --- /dev/null +++ b/xbmc/peripherals/bus/virtual/CMakeLists.txt @@ -0,0 +1,12 @@ +set(SOURCES PeripheralBusAddon.cpp + PeripheralBusApplication.cpp) + +set(HEADERS PeripheralBusAddon.h + PeripheralBusApplication.h) + +if(CEC_FOUND) + list(APPEND SOURCES PeripheralBusCEC.cpp) + list(APPEND HEADERS PeripheralBusCEC.h) +endif() + +core_add_library(peripheral_bus_virtual) diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp b/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp new file mode 100644 index 0000000..2162c45 --- /dev/null +++ b/xbmc/peripherals/bus/virtual/PeripheralBusAddon.cpp @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2014-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PeripheralBusAddon.h" + +#include "ServiceBroker.h" +#include "addons/AddonEvents.h" +#include "addons/AddonManager.h" +#include "addons/addoninfo/AddonInfo.h" +#include "addons/addoninfo/AddonType.h" +#include "messaging/helpers/DialogHelper.h" +#include "peripherals/Peripherals.h" +#include "peripherals/addons/PeripheralAddon.h" +#include "peripherals/devices/PeripheralJoystick.h" +#include "threads/SingleLock.h" +#include "utils/log.h" + +#include <algorithm> +#include <memory> +#include <mutex> + +using namespace KODI; +using namespace PERIPHERALS; + +CPeripheralBusAddon::CPeripheralBusAddon(CPeripherals& manager) + : CPeripheralBus("PeripBusAddon", manager, PERIPHERAL_BUS_ADDON) +{ + using namespace ADDON; + + CServiceBroker::GetAddonMgr().Events().Subscribe(this, &CPeripheralBusAddon::OnEvent); + + UpdateAddons(); +} + +CPeripheralBusAddon::~CPeripheralBusAddon() +{ + using namespace ADDON; + + CServiceBroker::GetAddonMgr().Events().Unsubscribe(this); + + // stop everything before destroying any (loaded) addons + Clear(); + + // destroy any (loaded) addons + for (const auto& addon : m_addons) + addon->DestroyAddon(); + + m_failedAddons.clear(); + m_addons.clear(); +} + +bool CPeripheralBusAddon::GetAddonWithButtonMap(PeripheralAddonPtr& addon) const +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + auto it = std::find_if(m_addons.begin(), m_addons.end(), + [](const PeripheralAddonPtr& addon) { return addon->HasButtonMaps(); }); + + if (it != m_addons.end()) + { + addon = *it; + return true; + } + + return false; +} + +bool CPeripheralBusAddon::GetAddonWithButtonMap(const CPeripheral* device, + PeripheralAddonPtr& addon) const +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + // If device is from an add-on, try to use that add-on + if (device && device->GetBusType() == PERIPHERAL_BUS_ADDON) + { + PeripheralAddonPtr addonWithButtonMap; + unsigned int index; + if (SplitLocation(device->Location(), addonWithButtonMap, index)) + { + if (addonWithButtonMap->HasButtonMaps()) + addon = std::move(addonWithButtonMap); + else + CLog::Log(LOGDEBUG, "Add-on {} doesn't provide button maps for its controllers", + addonWithButtonMap->ID()); + } + } + + if (!addon) + { + auto it = std::find_if(m_addons.begin(), m_addons.end(), + [](const PeripheralAddonPtr& addon) { return addon->HasButtonMaps(); }); + + if (it != m_addons.end()) + addon = *it; + } + + return addon.get() != nullptr; +} + +bool CPeripheralBusAddon::PerformDeviceScan(PeripheralScanResults& results) +{ + PeripheralAddonVector addons; + { + std::unique_lock<CCriticalSection> lock(m_critSection); + addons = m_addons; + } + + for (const auto& addon : addons) + addon->PerformDeviceScan(results); + + // Scan during bus initialization must return true or bus gets deleted + return true; +} + +bool CPeripheralBusAddon::InitializeProperties(CPeripheral& peripheral) +{ + if (!CPeripheralBus::InitializeProperties(peripheral)) + return false; + + bool bSuccess = false; + + PeripheralAddonPtr addon; + unsigned int index; + + if (SplitLocation(peripheral.Location(), addon, index)) + { + switch (peripheral.Type()) + { + case PERIPHERAL_JOYSTICK: + bSuccess = + addon->GetJoystickProperties(index, static_cast<CPeripheralJoystick&>(peripheral)); + break; + + default: + break; + } + } + + return bSuccess; +} + +bool CPeripheralBusAddon::SendRumbleEvent(const std::string& strLocation, + unsigned int motorIndex, + float magnitude) +{ + bool bHandled = false; + + PeripheralAddonPtr addon; + unsigned int peripheralIndex; + if (SplitLocation(strLocation, addon, peripheralIndex)) + bHandled = addon->SendRumbleEvent(peripheralIndex, motorIndex, magnitude); + + return bHandled; +} + +void CPeripheralBusAddon::ProcessEvents(void) +{ + PeripheralAddonVector addons; + + { + std::unique_lock<CCriticalSection> lock(m_critSection); + addons = m_addons; + } + + for (const auto& addon : addons) + addon->ProcessEvents(); +} + +void CPeripheralBusAddon::EnableButtonMapping() +{ + using namespace ADDON; + + std::unique_lock<CCriticalSection> lock(m_critSection); + + PeripheralAddonPtr dummy; + + if (!GetAddonWithButtonMap(dummy)) + { + std::vector<AddonInfoPtr> disabledAddons; + CServiceBroker::GetAddonMgr().GetDisabledAddonInfos(disabledAddons, AddonType::PERIPHERALDLL); + if (!disabledAddons.empty()) + PromptEnableAddons(disabledAddons); + } +} + +void CPeripheralBusAddon::PowerOff(const std::string& strLocation) +{ + PeripheralAddonPtr addon; + unsigned int peripheralIndex; + if (SplitLocation(strLocation, addon, peripheralIndex)) + addon->PowerOffJoystick(peripheralIndex); +} + +void CPeripheralBusAddon::UnregisterRemovedDevices(const PeripheralScanResults& results) +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + + PeripheralVector removedPeripherals; + + for (const auto& addon : m_addons) + addon->UnregisterRemovedDevices(results, removedPeripherals); + + for (const auto& peripheral : removedPeripherals) + m_manager.OnDeviceDeleted(*this, *peripheral); +} + +void CPeripheralBusAddon::Register(const PeripheralPtr& peripheral) +{ + if (!peripheral) + return; + + PeripheralAddonPtr addon; + unsigned int peripheralIndex; + + std::unique_lock<CCriticalSection> lock(m_critSection); + + if (SplitLocation(peripheral->Location(), addon, peripheralIndex)) + { + if (addon->Register(peripheralIndex, peripheral)) + m_manager.OnDeviceAdded(*this, *peripheral); + } +} + +void CPeripheralBusAddon::GetFeatures(std::vector<PeripheralFeature>& features) const +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + for (const auto& addon : m_addons) + addon->GetFeatures(features); +} + +bool CPeripheralBusAddon::HasFeature(const PeripheralFeature feature) const +{ + bool bReturn(false); + std::unique_lock<CCriticalSection> lock(m_critSection); + for (const auto& addon : m_addons) + bReturn = bReturn || addon->HasFeature(feature); + return bReturn; +} + +PeripheralPtr CPeripheralBusAddon::GetPeripheral(const std::string& strLocation) const +{ + PeripheralPtr peripheral; + PeripheralAddonPtr addon; + unsigned int peripheralIndex; + + std::unique_lock<CCriticalSection> lock(m_critSection); + + if (SplitLocation(strLocation, addon, peripheralIndex)) + peripheral = addon->GetPeripheral(peripheralIndex); + + return peripheral; +} + +PeripheralPtr CPeripheralBusAddon::GetByPath(const std::string& strPath) const +{ + PeripheralPtr result; + + std::unique_lock<CCriticalSection> lock(m_critSection); + + for (const auto& addon : m_addons) + { + PeripheralPtr peripheral = addon->GetByPath(strPath); + if (peripheral) + { + result = peripheral; + break; + } + } + + return result; +} + +bool CPeripheralBusAddon::SupportsFeature(PeripheralFeature feature) const +{ + bool bSupportsFeature = false; + + std::unique_lock<CCriticalSection> lock(m_critSection); + for (const auto& addon : m_addons) + bSupportsFeature |= addon->SupportsFeature(feature); + + return bSupportsFeature; +} + +unsigned int CPeripheralBusAddon::GetPeripheralsWithFeature(PeripheralVector& results, + const PeripheralFeature feature) const +{ + unsigned int iReturn = 0; + std::unique_lock<CCriticalSection> lock(m_critSection); + for (const auto& addon : m_addons) + iReturn += addon->GetPeripheralsWithFeature(results, feature); + return iReturn; +} + +unsigned int CPeripheralBusAddon::GetNumberOfPeripherals(void) const +{ + unsigned int iReturn = 0; + std::unique_lock<CCriticalSection> lock(m_critSection); + for (const auto& addon : m_addons) + iReturn += addon->GetNumberOfPeripherals(); + return iReturn; +} + +unsigned int CPeripheralBusAddon::GetNumberOfPeripheralsWithId(const int iVendorId, + const int iProductId) const +{ + unsigned int iReturn = 0; + std::unique_lock<CCriticalSection> lock(m_critSection); + for (const auto& addon : m_addons) + iReturn += addon->GetNumberOfPeripheralsWithId(iVendorId, iProductId); + return iReturn; +} + +void CPeripheralBusAddon::GetDirectory(const std::string& strPath, CFileItemList& items) const +{ + std::unique_lock<CCriticalSection> lock(m_critSection); + for (const auto& addon : m_addons) + addon->GetDirectory(strPath, items); +} + +void CPeripheralBusAddon::OnEvent(const ADDON::AddonEvent& event) +{ + if (typeid(event) == typeid(ADDON::AddonEvents::Enabled) || + typeid(event) == typeid(ADDON::AddonEvents::ReInstalled)) + { + if (CServiceBroker::GetAddonMgr().HasType(event.addonId, ADDON::AddonType::PERIPHERALDLL)) + UpdateAddons(); + } + else if (typeid(event) == typeid(ADDON::AddonEvents::Disabled)) + { + if (CServiceBroker::GetAddonMgr().HasType(event.addonId, ADDON::AddonType::PERIPHERALDLL)) + UnRegisterAddon(event.addonId); + } + else if (typeid(event) == typeid(ADDON::AddonEvents::UnInstalled)) + { + UnRegisterAddon(event.addonId); + } +} + +bool CPeripheralBusAddon::SplitLocation(const std::string& strLocation, + PeripheralAddonPtr& addon, + unsigned int& peripheralIndex) const +{ + std::vector<std::string> parts = StringUtils::Split(strLocation, "/"); + if (parts.size() == 2) + { + addon.reset(); + + std::unique_lock<CCriticalSection> lock(m_critSection); + + const std::string& strAddonId = parts[0]; + for (const auto& addonIt : m_addons) + { + if (addonIt->ID() == strAddonId) + { + addon = addonIt; + break; + } + } + + if (addon) + { + const char* strJoystickIndex = parts[1].c_str(); + char* p = NULL; + peripheralIndex = strtol(strJoystickIndex, &p, 10); + if (strJoystickIndex != p) + return true; + } + } + return false; +} + +void CPeripheralBusAddon::UpdateAddons(void) +{ + using namespace ADDON; + + auto GetPeripheralAddonID = [](const PeripheralAddonPtr& addon) { return addon->ID(); }; + auto GetAddonID = [](const AddonInfoPtr& addon) { return addon->ID(); }; + + std::set<std::string> currentIds; + std::set<std::string> newIds; + + std::set<std::string> added; + std::set<std::string> removed; + + // Get new add-ons + std::vector<AddonInfoPtr> newAddons; + CServiceBroker::GetAddonMgr().GetAddonInfos(newAddons, true, AddonType::PERIPHERALDLL); + std::transform(newAddons.begin(), newAddons.end(), std::inserter(newIds, newIds.end()), + GetAddonID); + + std::unique_lock<CCriticalSection> lock(m_critSection); + + // Get current add-ons + std::transform(m_addons.begin(), m_addons.end(), std::inserter(currentIds, currentIds.end()), + GetPeripheralAddonID); + std::transform(m_failedAddons.begin(), m_failedAddons.end(), + std::inserter(currentIds, currentIds.end()), GetPeripheralAddonID); + + // Differences + std::set_difference(newIds.begin(), newIds.end(), currentIds.begin(), currentIds.end(), + std::inserter(added, added.end())); + std::set_difference(currentIds.begin(), currentIds.end(), newIds.begin(), newIds.end(), + std::inserter(removed, removed.end())); + + // Register new add-ons + for (const std::string& addonId : added) + { + CLog::Log(LOGDEBUG, "Add-on bus: Registering add-on {}", addonId); + + auto GetAddon = [&addonId](const AddonInfoPtr& addon) { return addon->ID() == addonId; }; + + auto it = std::find_if(newAddons.begin(), newAddons.end(), GetAddon); + if (it != newAddons.end()) + { + PeripheralAddonPtr newAddon = std::make_shared<CPeripheralAddon>(*it, m_manager); + if (newAddon) + { + bool bCreated; + + { + CSingleExit exit(m_critSection); + bCreated = newAddon->CreateAddon(); + } + + if (bCreated) + m_addons.emplace_back(std::move(newAddon)); + else + m_failedAddons.emplace_back(std::move(newAddon)); + } + } + } + + // Destroy removed add-ons + for (const std::string& addonId : removed) + { + UnRegisterAddon(addonId); + } +} + +void CPeripheralBusAddon::UnRegisterAddon(const std::string& addonId) +{ + PeripheralAddonPtr erased; + auto ErasePeripheralAddon = [&addonId, &erased](const PeripheralAddonPtr& addon) { + if (addon->ID() == addonId) + { + erased = addon; + return true; + } + return false; + }; + + m_addons.erase(std::remove_if(m_addons.begin(), m_addons.end(), ErasePeripheralAddon), + m_addons.end()); + if (!erased) + m_failedAddons.erase( + std::remove_if(m_failedAddons.begin(), m_failedAddons.end(), ErasePeripheralAddon), + m_failedAddons.end()); + + if (erased) + { + CLog::Log(LOGDEBUG, "Add-on bus: Unregistered add-on {}", addonId); + CSingleExit exit(m_critSection); + erased->DestroyAddon(); + } +} + +void CPeripheralBusAddon::PromptEnableAddons( + const std::vector<std::shared_ptr<ADDON::CAddonInfo>>& disabledAddons) +{ + using namespace ADDON; + using namespace MESSAGING::HELPERS; + + // True if the user confirms enabling the disabled peripheral add-on + bool bAccepted = false; + + auto itAddon = + std::find_if(disabledAddons.begin(), disabledAddons.end(), [](const AddonInfoPtr& addonInfo) { + return CPeripheralAddon::ProvidesJoysticks(addonInfo); + }); + + if (itAddon != disabledAddons.end()) + { + // "Unable to configure controllers" + // "Controller configuration depends on a disabled add-on. Would you like to enable it?" + bAccepted = + (ShowYesNoDialogLines(CVariant{35017}, CVariant{35018}) == DialogResponse::CHOICE_YES); + } + + if (bAccepted) + { + for (const auto& addonInfo : disabledAddons) + { + if (CPeripheralAddon::ProvidesJoysticks(addonInfo)) + CServiceBroker::GetAddonMgr().EnableAddon(addonInfo->ID()); + } + } +} diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusAddon.h b/xbmc/peripherals/bus/virtual/PeripheralBusAddon.h new file mode 100644 index 0000000..696b189 --- /dev/null +++ b/xbmc/peripherals/bus/virtual/PeripheralBusAddon.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "peripherals/PeripheralTypes.h" +#include "peripherals/bus/PeripheralBus.h" + +#include <memory> +#include <string> +#include <vector> + +namespace ADDON +{ +struct AddonEvent; +class CAddonInfo; +} // namespace ADDON + +namespace PERIPHERALS +{ +class CPeripheralBusAddon : public CPeripheralBus +{ +public: + explicit CPeripheralBusAddon(CPeripherals& manager); + ~CPeripheralBusAddon(void) override; + + void UpdateAddons(void); + + /*! + * \brief Get peripheral add-on that can provide button maps + */ + bool GetAddonWithButtonMap(PeripheralAddonPtr& addon) const; + + /*! + * \brief Get peripheral add-on that can provide button maps for the given device + */ + bool GetAddonWithButtonMap(const CPeripheral* device, PeripheralAddonPtr& addon) const; + + /*! + * \brief Set the rumble state of a rumble motor + * + * \param strLocation The location of the peripheral with the motor + * \param motorIndex The index of the motor being rumbled + * \param magnitude The amount of vibration in the closed interval [0.0, 1.0] + * + * \return true if the rumble motor's state is set, false otherwise + * + * TODO: Move declaration to parent class + */ + bool SendRumbleEvent(const std::string& strLocation, unsigned int motorIndex, float magnitude); + + // Inherited from CPeripheralBus + bool InitializeProperties(CPeripheral& peripheral) override; + void Register(const PeripheralPtr& peripheral) override; + void GetFeatures(std::vector<PeripheralFeature>& features) const override; + bool HasFeature(const PeripheralFeature feature) const override; + PeripheralPtr GetPeripheral(const std::string& strLocation) const override; + PeripheralPtr GetByPath(const std::string& strPath) const override; + bool SupportsFeature(PeripheralFeature feature) const override; + unsigned int GetPeripheralsWithFeature(PeripheralVector& results, + const PeripheralFeature feature) const override; + unsigned int GetNumberOfPeripherals(void) const override; + unsigned int GetNumberOfPeripheralsWithId(const int iVendorId, + const int iProductId) const override; + void GetDirectory(const std::string& strPath, CFileItemList& items) const override; + void ProcessEvents(void) override; + void EnableButtonMapping() override; + void PowerOff(const std::string& strLocation) override; + + bool SplitLocation(const std::string& strLocation, + PeripheralAddonPtr& addon, + unsigned int& peripheralIndex) const; + +protected: + // Inherited from CPeripheralBus + bool PerformDeviceScan(PeripheralScanResults& results) override; + void UnregisterRemovedDevices(const PeripheralScanResults& results) override; + +private: + void OnEvent(const ADDON::AddonEvent& event); + void UnRegisterAddon(const std::string& addonId); + + void PromptEnableAddons(const std::vector<std::shared_ptr<ADDON::CAddonInfo>>& disabledAddons); + + PeripheralAddonVector m_addons; + PeripheralAddonVector m_failedAddons; +}; +using PeripheralBusAddonPtr = std::shared_ptr<CPeripheralBusAddon>; +} // namespace PERIPHERALS diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusApplication.cpp b/xbmc/peripherals/bus/virtual/PeripheralBusApplication.cpp new file mode 100644 index 0000000..4dad03c --- /dev/null +++ b/xbmc/peripherals/bus/virtual/PeripheralBusApplication.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PeripheralBusApplication.h" + +#include "ServiceBroker.h" +#include "guilib/LocalizeStrings.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/StringUtils.h" + +using namespace PERIPHERALS; + +CPeripheralBusApplication::CPeripheralBusApplication(CPeripherals& manager) + : CPeripheralBus("PeripBusApplication", manager, PERIPHERAL_BUS_APPLICATION) +{ + // Initialize CPeripheralBus + m_bNeedsPolling = false; +} + +void CPeripheralBusApplication::Initialise(void) +{ + CPeripheralBus::Initialise(); + TriggerDeviceScan(); +} + +bool CPeripheralBusApplication::PerformDeviceScan(PeripheralScanResults& results) +{ + { + PeripheralScanResult result(Type()); + result.m_type = PERIPHERAL_KEYBOARD; + result.m_strDeviceName = g_localizeStrings.Get(35150); // "Keyboard" + result.m_strLocation = PeripheralTypeTranslator::TypeToString(PERIPHERAL_KEYBOARD); + result.m_iVendorId = 0; + result.m_iProductId = 0; + result.m_mappedType = PERIPHERAL_KEYBOARD; + result.m_mappedBusType = Type(); + result.m_iSequence = 0; + + if (!results.ContainsResult(result)) + results.m_results.push_back(result); + } + + bool bHasMouse = CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool( + CSettings::SETTING_INPUT_ENABLEMOUSE); + + //! @todo Fix game clients to handle mouse disconnecting + //! For now mouse is always connected + bHasMouse = true; + + if (bHasMouse) + { + PeripheralScanResult result(Type()); + result.m_type = PERIPHERAL_MOUSE; + result.m_strDeviceName = g_localizeStrings.Get(35171); // "Mouse" + result.m_strLocation = PeripheralTypeTranslator::TypeToString(PERIPHERAL_MOUSE); + result.m_iVendorId = 0; + result.m_iProductId = 0; + result.m_mappedType = PERIPHERAL_MOUSE; + result.m_mappedBusType = Type(); + result.m_iSequence = 0; + + if (!results.ContainsResult(result)) + results.m_results.push_back(result); + } + + return true; +} + +void CPeripheralBusApplication::GetDirectory(const std::string& strPath, CFileItemList& items) const +{ + // Don't list virtual devices in the GUI +} + +std::string CPeripheralBusApplication::MakeLocation(unsigned int controllerIndex) const +{ + return std::to_string(controllerIndex); +} diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusApplication.h b/xbmc/peripherals/bus/virtual/PeripheralBusApplication.h new file mode 100644 index 0000000..4fcc40d --- /dev/null +++ b/xbmc/peripherals/bus/virtual/PeripheralBusApplication.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "peripherals/bus/PeripheralBus.h" + +namespace PERIPHERALS +{ +/*! + * @class CPeripheralBusApplication + * + * This exposes peripherals that exist logically at the application level, + * such as emulated joysticks. + */ +class CPeripheralBusApplication : public CPeripheralBus +{ +public: + explicit CPeripheralBusApplication(CPeripherals& manager); + ~CPeripheralBusApplication(void) override = default; + + // implementation of CPeripheralBus + void Initialise(void) override; + void GetDirectory(const std::string& strPath, CFileItemList& items) const override; + + /*! + * \brief Get the location for the specified controller index + */ + std::string MakeLocation(unsigned int controllerIndex) const; + +protected: + // implementation of CPeripheralBus + bool PerformDeviceScan(PeripheralScanResults& results) override; +}; +} // namespace PERIPHERALS diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp b/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp new file mode 100644 index 0000000..e119638 --- /dev/null +++ b/xbmc/peripherals/bus/virtual/PeripheralBusCEC.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "PeripheralBusCEC.h" + +#include <libcec/cec.h> + +using namespace PERIPHERALS; +using namespace CEC; + +CPeripheralBusCEC::CPeripheralBusCEC(CPeripherals& manager) + : CPeripheralBus("PeripBusCEC", manager, PERIPHERAL_BUS_CEC) +{ + m_cecAdapter = CECInitialise(&m_configuration); +} + +CPeripheralBusCEC::~CPeripheralBusCEC(void) +{ + if (m_cecAdapter) + CECDestroy(m_cecAdapter); +} + +bool CPeripheralBusCEC::PerformDeviceScan(PeripheralScanResults& results) +{ + cec_adapter_descriptor deviceList[10]; + int8_t iFound = m_cecAdapter->DetectAdapters(deviceList, 10, NULL, true); + + for (uint8_t iDevicePtr = 0; iDevicePtr < iFound; iDevicePtr++) + { + PeripheralScanResult result(m_type); + result.m_iVendorId = deviceList[iDevicePtr].iVendorId; + result.m_iProductId = deviceList[iDevicePtr].iProductId; + result.m_strLocation = deviceList[iDevicePtr].strComName; + result.m_type = PERIPHERAL_CEC; + + // override the bus type, so users don't have to reconfigure their adapters + switch (deviceList[iDevicePtr].adapterType) + { + case ADAPTERTYPE_P8_EXTERNAL: + case ADAPTERTYPE_P8_DAUGHTERBOARD: + result.m_mappedBusType = PERIPHERAL_BUS_USB; + break; + default: + break; + } + + result.m_iSequence = GetNumberOfPeripheralsWithId(result.m_iVendorId, result.m_iProductId); + if (!results.ContainsResult(result)) + results.m_results.push_back(result); + } + return true; +} diff --git a/xbmc/peripherals/bus/virtual/PeripheralBusCEC.h b/xbmc/peripherals/bus/virtual/PeripheralBusCEC.h new file mode 100644 index 0000000..9aa2643 --- /dev/null +++ b/xbmc/peripherals/bus/virtual/PeripheralBusCEC.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "peripherals/bus/PeripheralBus.h" + +// undefine macro isset, it collides with function in cectypes.h +#ifdef isset +#undef isset +#endif +#include <libcec/cectypes.h> + +namespace CEC +{ +class ICECAdapter; +} + +namespace PERIPHERALS +{ +class CPeripherals; + +class CPeripheralBusCEC : public CPeripheralBus +{ +public: + explicit CPeripheralBusCEC(CPeripherals& manager); + ~CPeripheralBusCEC(void) override; + + /*! + * @see PeripheralBus::PerformDeviceScan() + */ + bool PerformDeviceScan(PeripheralScanResults& results) override; + +private: + CEC::ICECAdapter* m_cecAdapter; + CEC::libcec_configuration m_configuration; +}; +} // namespace PERIPHERALS |