diff options
author | Rainer Hochecker <fernetmenta@online.de> | 2018-04-15 12:53:44 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-15 12:53:44 +0200 |
commit | 50f98abb88ee12da611436df412a0a1ddd0e8c5c (patch) | |
tree | 3e0f6b210d0fdf45a12e58e6f4306b8df0cedbef | |
parent | 326fb2d1d3adc8514e53a4e7dd4698489a7b6ed6 (diff) | |
parent | bac44c410e4d8dc6f3ea5ea136f37634198db9e2 (diff) |
Merge pull request #13761 from FernetMenta/lirc
lirc: redesign, fix
26 files changed, 234 insertions, 478 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 1aafc21a54..18568cd550 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,7 +64,6 @@ if(NOT WIN32) option(WITH_CPU "build with given cpu" OFF) endif() if(CORE_SYSTEM_NAME STREQUAL linux) - option(ENABLE_LIRC "Enable LIRC support?" ON) option(ENABLE_EVENTCLIENTS "Enable event clients support?" OFF) endif() @@ -149,6 +148,7 @@ set(optional_deps Alsa CCache DBus LCMS2 + LircClient MDNS MicroHttpd PulseAudio @@ -201,11 +201,6 @@ if(ENABLE_OPTICAL) list(APPEND DEP_DEFINES -DHAS_DVD_DRIVE -DHAS_CDDA_RIPPER) endif() -if(ENABLE_LIRC) - set(LIRC_DEVICE /dev/lircd CACHE STRING "LIRC device to use") - list(APPEND DEP_DEFINES -DLIRC_DEVICE="${LIRC_DEVICE}" -DHAS_LIRC=1) -endif() - if(ENABLE_AIRTUNES) find_package(Shairplay) if(SHAIRPLAY_FOUND) diff --git a/cmake/modules/FindLircClient.cmake b/cmake/modules/FindLircClient.cmake new file mode 100644 index 0000000000..528c38e8ee --- /dev/null +++ b/cmake/modules/FindLircClient.cmake @@ -0,0 +1,36 @@ +# FindLircClient +# ----------- +# Finds the liblirc_client library +# +# This will will define the following variables:: +# +# LIRCCLIENT_FOUND - if false, do not try to link to lirc_client +# LIRCCLIENT_INCLUDE_DIRS - where to find lirc/lirc_client.h +# LIRCCLIENT_LIBRARYS - the library to link against +# LIRCCLIENT_DEFINITIONS - the lirc definitions + +if(PKG_CONFIG_FOUND) + pkg_check_modules(PC_LIRC lirc QUIET) +endif() + +find_path(LIRCCLIENT_INCLUDE_DIR lirc/lirc_client.h PATHS ${PC_LIRC_INCLUDEDIR}) +find_library(LIRCCLIENT_LIBRARY lirc_client PATHS ${PC_LIRC_LIBDIR}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LircClient + REQUIRED_VARS LIRCCLIENT_LIBRARY LIRCCLIENT_INCLUDE_DIR) + +if(LIRCCLIENT_FOUND) + set(LIRCCLIENT_LIBRARIES ${LIRCCLIENT_LIBRARY}) + set(LIRCCLIENT_INCLUDE_DIRS ${LIRCCLIENT_INCLUDE_DIR}) + set(LIRCCLIENT_DEFINITIONS -DHAS_LIRC=1) + + if(NOT TARGET LIRCCLIENT::LIRCCLIENT) + add_library(LIRCCLIENT::LIRCCLIENT UNKNOWN IMPORTED) + set_target_properties(LIRCCLIENT::LIRCCLIENT PROPERTIES + IMPORTED_LOCATION "${LIRCCLIENT_LIBRARYS}" + INTERFACE_INCLUDE_DIRECTORIES "${LIRCCLIENT_INCLUDE_DIRS}") + endif() +endif() + +mark_as_advanced(LIRCCLIENT_LIBRARY LIRCCLIENT_INCLUDE_DIR)
\ No newline at end of file diff --git a/docs/README.linux b/docs/README.linux index 5826dfbaa4..ee1c5b4cf4 100644 --- a/docs/README.linux +++ b/docs/README.linux @@ -57,7 +57,8 @@ Build-Depends: autoconf, automake, autopoint, autotools-dev, cmake, curl, libtag1-dev (>= 1.8), libtinyxml-dev (>= 2.6.2), libtool, libudev-dev, libusb-dev, libva-dev, libvdpau-dev, libxml2-dev, libxmu-dev, libxrandr-dev, libxslt1-dev, libxt-dev, lsb-release, rapidjson-dev, - nasm [!amd64], python-dev, python-imaging, python-support, swig, uuid-dev, yasm, zlib1g-dev + nasm [!amd64], python-dev, python-imaging, python-support, swig, uuid-dev, yasm, zlib1g-dev, + liblirc-dev If you want to build with Wayland instead of X11, you will need: wayland-protocols (>= 1.7), libwaylandpp-dev diff --git a/docs/README.ubuntu b/docs/README.ubuntu index 83c971de27..fba3d86cf9 100644 --- a/docs/README.ubuntu +++ b/docs/README.ubuntu @@ -91,7 +91,7 @@ For Ubuntu (all versions >= 7.04): libsqlite3-dev libssh-dev libssl-dev libtinyxml-dev libtool libudev-dev libusb-dev \ libva-dev libvdpau-dev libxml2-dev libxmu-dev libxrandr-dev \ libxrender-dev libxslt1-dev libxt-dev mesa-utils nasm pmount python-dev python-imaging \ - python-sqlite rapidjson-dev swig uuid-dev yasm zlib1g-dev + python-sqlite rapidjson-dev swig uuid-dev yasm zlib1g-dev liblirc-dev For >= 10.10: $ sudo apt-get install autopoint libltdl-dev diff --git a/xbmc/AppParamParser.cpp b/xbmc/AppParamParser.cpp index 31f671f7b3..cbe5d1cf8b 100644 --- a/xbmc/AppParamParser.cpp +++ b/xbmc/AppParamParser.cpp @@ -98,10 +98,6 @@ void CAppParamParser::DisplayHelp() printf("\t\t\tenables network settings.\n"); printf(" -p or --portable\t%s will look for configurations in install folder instead of ~/.%s\n", CSysInfo::GetAppName().c_str(), lcAppName.c_str()); printf(" --legacy-res\t\tEnables screen resolutions such as PAL, NTSC, etc.\n"); -#ifdef HAS_LIRC - printf(" -l or --lircdev\tLircDevice to use default is " LIRC_DEVICE " .\n"); - printf(" -n or --nolirc\tdo not use Lirc, i.e. no remote input.\n"); -#endif printf(" --debug\t\tEnable debug logging\n"); printf(" --version\t\tPrint version information\n"); printf(" --test\t\tEnable test mode. [FILE] required.\n"); diff --git a/xbmc/ServiceManager.cpp b/xbmc/ServiceManager.cpp index 9423e49866..6847a6b317 100644 --- a/xbmc/ServiceManager.cpp +++ b/xbmc/ServiceManager.cpp @@ -173,8 +173,7 @@ bool CServiceManager::InitStageTwo(const CAppParamParser ¶ms) m_contextMenuManager.reset(new CContextMenuManager(*m_addonMgr.get())); m_gameControllerManager.reset(new GAME::CControllerManager); - m_inputManager.reset(new CInputManager(params, - *m_profileManager)); + m_inputManager.reset(new CInputManager(params)); m_inputManager->InitializeInputs(); m_peripherals.reset(new PERIPHERALS::CPeripherals(*m_announcementManager, diff --git a/xbmc/input/IRTranslator.cpp b/xbmc/input/IRTranslator.cpp index 18ef268f85..98f40ef599 100644 --- a/xbmc/input/IRTranslator.cpp +++ b/xbmc/input/IRTranslator.cpp @@ -19,6 +19,7 @@ */ #include "IRTranslator.h" +#include "ServiceBroker.h" #include "filesystem/File.h" #include "input/remote/IRRemote.h" #include "profiles/ProfilesManager.h" @@ -30,8 +31,7 @@ #include <stdlib.h> #include <vector> -CIRTranslator::CIRTranslator(const CProfilesManager &profileManager) : - m_profileManager(profileManager) +CIRTranslator::CIRTranslator() { } @@ -50,7 +50,7 @@ void CIRTranslator::Load(const std::string &irMapName) else CLog::Log(LOGDEBUG, "CIRTranslator::Load - no system %s found, skipping", irMapName.c_str()); - irMapPath = m_profileManager.GetUserDataItem(irMapName); + irMapPath = CServiceBroker::GetProfileManager().GetUserDataItem(irMapName); if (XFILE::CFile::Exists(irMapPath)) success |= LoadIRMap(irMapPath); else @@ -63,7 +63,9 @@ void CIRTranslator::Load(const std::string &irMapName) bool CIRTranslator::LoadIRMap(const std::string &irMapPath) { std::string remoteMapTag = URIUtils::GetFileName(irMapPath); - URIUtils::RemoveExtension(remoteMapTag); + size_t lastindex = remoteMapTag.find_last_of("."); + if (lastindex != std::string::npos) + remoteMapTag = remoteMapTag.substr(0, lastindex); StringUtils::ToLower(remoteMapTag); // Load our xml file, and fill up our mapping tables diff --git a/xbmc/input/IRTranslator.h b/xbmc/input/IRTranslator.h index 1326f5d9d5..50a61dc666 100644 --- a/xbmc/input/IRTranslator.h +++ b/xbmc/input/IRTranslator.h @@ -23,13 +23,12 @@ #include <memory> #include <string> -class CProfilesManager; class TiXmlNode; class CIRTranslator { public: - CIRTranslator(const CProfilesManager &profileManager); + CIRTranslator(); /*! * \brief Loads Lircmap.xml/IRSSmap.xml @@ -50,9 +49,6 @@ private: bool LoadIRMap(const std::string &irMapPath); void MapRemote(TiXmlNode *pRemote, const std::string &szDevice); - // Construction parameters - const CProfilesManager &m_profileManager; - using IRButtonMap = std::map<std::string, std::string>; std::map<std::string, std::shared_ptr<IRButtonMap>> m_irRemotesMap; diff --git a/xbmc/input/InputManager.cpp b/xbmc/input/InputManager.cpp index 90a8c680d5..ec3dc8d897 100644 --- a/xbmc/input/InputManager.cpp +++ b/xbmc/input/InputManager.cpp @@ -62,11 +62,10 @@ using namespace MESSAGING; CreateRemoteControlFunc CInputManager::m_createRemoteControl = nullptr; -CInputManager::CInputManager(const CAppParamParser ¶ms, - const CProfilesManager &profileManager) : +CInputManager::CInputManager(const CAppParamParser ¶ms) : m_keymapEnvironment(new CKeymapEnvironment), m_buttonTranslator(new CButtonTranslator), - m_irTranslator(new CIRTranslator(profileManager)), + m_irTranslator(new CIRTranslator()), m_customControllerTranslator(new CCustomControllerTranslator), m_touchTranslator(new CTouchTranslator), m_joystickTranslator(new CJoystickMapper), @@ -470,6 +469,12 @@ bool CInputManager::OnEvent(XBMC_Event& newEvent) } break; } //case + case XBMC_BUTTON: + { + CKey key(newEvent.keybutton.button, newEvent.keybutton.holdtime); + OnKey(key); + break; + } }//switch return true; @@ -736,10 +741,6 @@ bool CInputManager::ExecuteInputAction(const CAction &action) bool CInputManager::HasBuiltin(const std::string& command) { - if (HasRemoteControl()) - return command == "lirc.stop" || - command == "lirc.start" || - command == "lirc.send"; return false; } @@ -747,29 +748,7 @@ int CInputManager::ExecuteBuiltin(const std::string& execute, const std::vector< { if (HasRemoteControl()) { - if (execute == "lirc.stop") - { - m_RemoteControl->Disconnect(); - m_RemoteControl->SetEnabled(false); - } - else if (execute == "lirc.start") - { - m_RemoteControl->SetEnabled(true); - m_RemoteControl->Initialize(); - } - else if (execute == "lirc.send") - { - std::string command; - for (int i = 0; i < (int)params.size(); i++) - { - command += params[i]; - if (i < (int)params.size() - 1) - command += ' '; - } - m_RemoteControl->AddSendCommand(command); - } - else - return -1; + return -1; } return 0; } @@ -1013,3 +992,4 @@ void CInputManager::RegisterRemoteControl(CreateRemoteControlFunc createFunc) { m_createRemoteControl = createFunc; } + diff --git a/xbmc/input/InputManager.h b/xbmc/input/InputManager.h index 6020bb8452..c62d875821 100644 --- a/xbmc/input/InputManager.h +++ b/xbmc/input/InputManager.h @@ -48,6 +48,7 @@ class IWindowKeymap; namespace KODI { + namespace KEYBOARD { class IKeyboardDriverHandler; @@ -78,8 +79,7 @@ class CInputManager : public ISettingCallback, public Observable { public: - explicit CInputManager(const CAppParamParser ¶ms, - const CProfilesManager &profileManager); + explicit CInputManager(const CAppParamParser ¶ms); CInputManager(const CInputManager&) = delete; CInputManager const& operator=(CInputManager const&) = delete; ~CInputManager() override; @@ -287,6 +287,7 @@ public: virtual void UnregisterMouseDriverHandler(KODI::MOUSE::IMouseDriverHandler* handler); static void RegisterRemoteControl(CreateRemoteControlFunc createFunc); + private: /*! \brief Process keyboard event and translate into an action diff --git a/xbmc/platform/linux/OptionalsReg.cpp b/xbmc/platform/linux/OptionalsReg.cpp index 34bd08d18f..9b393f648d 100644 --- a/xbmc/platform/linux/OptionalsReg.cpp +++ b/xbmc/platform/linux/OptionalsReg.cpp @@ -74,3 +74,35 @@ bool OPTIONALS::SndioRegister() return false; } #endif + +//----------------------------------------------------------------------------- +// Lirc +//----------------------------------------------------------------------------- + +#ifdef HAS_LIRC +#include "platform/linux/input/LIRC.h" +#include "ServiceBroker.h" +class OPTIONALS::CLircContainer +{ +public: + CLircContainer() + { + m_lirc.Start(); + } +protected: + CLirc m_lirc; +}; +#else +class OPTIONALS::CLircContainer +{ +}; +#endif + +OPTIONALS::CLircContainer* OPTIONALS::LircRegister() +{ + return new CLircContainer(); +} +void OPTIONALS::delete_CLircContainer::operator()(CLircContainer *p) const +{ + delete p; +} diff --git a/xbmc/platform/linux/OptionalsReg.h b/xbmc/platform/linux/OptionalsReg.h index cda502374c..07a985b18a 100644 --- a/xbmc/platform/linux/OptionalsReg.h +++ b/xbmc/platform/linux/OptionalsReg.h @@ -46,3 +46,17 @@ namespace OPTIONALS { bool SndioRegister(); } + +//----------------------------------------------------------------------------- +// Lirc +//----------------------------------------------------------------------------- + +namespace OPTIONALS +{ +class CLircContainer; +CLircContainer* LircRegister(); +struct delete_CLircContainer +{ + void operator()(CLircContainer *p) const; +}; +} diff --git a/xbmc/platform/linux/input/CMakeLists.txt b/xbmc/platform/linux/input/CMakeLists.txt index 0b0561e009..c8cf402e3e 100644 --- a/xbmc/platform/linux/input/CMakeLists.txt +++ b/xbmc/platform/linux/input/CMakeLists.txt @@ -1,7 +1,7 @@ set(SOURCES "") set(HEADERS "") -if(LIRC_DEVICE) +if(LIRCCLIENT_FOUND) list(APPEND SOURCES LIRC.cpp) list(APPEND HEADERS LIRC.h) endif() diff --git a/xbmc/platform/linux/input/LIRC.cpp b/xbmc/platform/linux/input/LIRC.cpp index a72d646d94..cfc48f6ef7 100644 --- a/xbmc/platform/linux/input/LIRC.cpp +++ b/xbmc/platform/linux/input/LIRC.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) 2007-2013 Team XBMC +* Copyright (C) 2007-2018 Team XBMC * http://kodi.tv * * This Program is free software; you can redistribute it and/or modify @@ -18,389 +18,126 @@ * */ -#include "threads/SystemClock.h" -#include <sys/time.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <limits.h> -#include <unistd.h> #include "LIRC.h" -#ifdef HAVE_INOTIFY -#include <sys/inotify.h> -#endif -#include "input/InputManager.h" -#include "platform/linux/PlatformDefs.h" -#include "utils/log.h" -#include "settings/AdvancedSettings.h" -#include "utils/TimeUtils.h" -#include "threads/SingleLock.h" +#include "Application.h" #include "ServiceBroker.h" +#include "profiles/ProfilesManager.h" +#include "settings/AdvancedSettings.h" +#include "utils/log.h" +#include <lirc/lirc_client.h> +#include <fcntl.h> +#include <sys/socket.h> -#define LIRC_MAP_FILENAME "Lircmap.xml" - -KODI::REMOTE::IRemoteControl* CRemoteControl::CreateInstance() -{ - return new CRemoteControl(); -} - -void CRemoteControl::Register() -{ - CInputManager::RegisterRemoteControl(CRemoteControl::CreateInstance); -} - -CRemoteControl::CRemoteControl() - : CThread("RemoteControl") - , m_fd(-1) -#ifdef HAVE_INOTIFY - , m_inotify_fd(-1) - , m_inotify_wd(-1) -#endif - , m_file(nullptr) - , m_holdTime(0) - , m_button(0) - , m_bInitialized(false) - , m_inReply(false) - , m_nrSending(0) - , m_used(true) - , m_deviceName(LIRC_DEVICE) -{ -} - -CRemoteControl::~CRemoteControl() -{ - if (m_file != NULL) - fclose(m_file); -} - -std::string CRemoteControl::GetMapFile() -{ - return LIRC_MAP_FILENAME; -} - -void CRemoteControl::SetEnabled(bool bEnabled) -{ - m_used = bEnabled; - if (!bEnabled) - CLog::Log(LOGINFO, "LIRC %s: disabled", __FUNCTION__); -} - -void CRemoteControl::Reset() +CLirc::CLirc() : CThread("Lirc") { - m_button = 0; - m_holdTime = 0; } -void CRemoteControl::Disconnect() +CLirc::~CLirc() { - CSingleLock lock(m_CS); - //make sure that any new function calls abort directly - m_bInitialized = false; - m_event.Set(); - - if (IsRunning()) - StopThread(); - - if (m_fd != -1) { - if (m_file != NULL) - fclose(m_file); - if (m_fd != -1) - close(m_fd); - m_fd = -1; - m_file = NULL; -#ifdef HAVE_INOTIFY - if (m_inotify_wd >= 0) { - inotify_rm_watch(m_inotify_fd, m_inotify_wd); - m_inotify_wd = -1; - } - if (m_inotify_fd >= 0) - close(m_inotify_fd); -#endif - - m_inReply = false; - m_nrSending = 0; - m_sendData.clear(); + CSingleLock lock(m_critSection); + if (m_fd > 0) + shutdown(m_fd, SHUT_RDWR); } + StopThread(); } -void CRemoteControl::SetDeviceName(const std::string& name) +void CLirc::Start() { - if (name.length() > 0) - m_deviceName = name; - else - m_deviceName = LIRC_DEVICE; -} - -void CRemoteControl::Initialize() -{ - //Create must not be called twice, make sure to lock before - //check IsRunning() so that any other thread will block until - //we know IsRunning is true and will not call Create again - CSingleLock lock(m_CS); - - if (m_bInitialized || !m_used || IsRunning()) - return; - Create(); -} -void CRemoteControl::Process() -{ - struct sockaddr_un addr; - if (m_deviceName.length() >= sizeof(addr.sun_path)) - { - CLog::Log(LOGERROR, "LIRC %s: device name is too long (%" PRIdS"), maximum is %" PRIdS"", - __FUNCTION__, m_deviceName.length(), sizeof(addr.sun_path)); - return; - } - - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, m_deviceName.c_str()); - - CLog::Log(LOGINFO, "LIRC %s: using: %s", __FUNCTION__, addr.sun_path); - - int iAttempt = 0; - unsigned int iMsRetryDelay = 5000; - - // try to connect 60 times @ a 5 second interval (5 minutes) - // multiple tries because LIRC service might be up and running a little later then xbmc on boot. - while (!m_bStop && iAttempt <= 60) - { - if (Connect(addr, iAttempt == 0)) - { - m_bInitialized = true; - break; - } - - if (iAttempt == 0) - CLog::Log(LOGINFO, "CRemoteControl::Process - failed to connect to LIRC, will keep retrying every %d seconds", iMsRetryDelay / 1000); - - ++iAttempt; - - if (AbortableWait(m_event, iMsRetryDelay) == WAIT_INTERRUPTED) - break; - } - - if (!m_bInitialized) - { - CLog::Log(LOGDEBUG, "Failed to connect to LIRC. Giving up."); - } -} - -bool CRemoteControl::CheckDevice() { - if (!m_bInitialized || !m_used) - return false; - -#ifdef HAVE_INOTIFY - if (m_inotify_fd < 0 || m_inotify_wd < 0) - return true; // inotify wasn't setup for some reason, assume all is well - int bufsize = sizeof(struct inotify_event) + PATH_MAX; - char buf[bufsize]; - int ret = read(m_inotify_fd, buf, bufsize); - for (int i = 0; i + (int)sizeof(struct inotify_event) <= ret;) { - struct inotify_event* e = (struct inotify_event*)(buf+i); - if (e->mask & IN_DELETE_SELF) { - CLog::Log(LOGDEBUG, "LIRC device removed, disconnecting..."); - Disconnect(); - return false; - } - i += sizeof(struct inotify_event)+e->len; - } -#endif - return true; + SetPriority(GetMinPriority()); } -void CRemoteControl::Update() +void CLirc::Process() { - if (!m_bInitialized || !m_used ) - return; - - if (!CheckDevice()) - return; - - uint32_t now = XbmcThreads::SystemClockMillis(); + m_profileId = CServiceBroker::GetProfileManager().GetCurrentProfileId(); + m_irTranslator.Load("Lircmap.xml"); - char buf[128]; - // Read a line from the socket - while (true) + while (!m_bStop) { { - CSingleLock lock(m_CS); - if (fgets(buf, sizeof(buf), m_file) == NULL) - break; - } - - // Remove the \n - buf[strlen(buf)-1] = '\0'; - - // Parse the result. Sample line: - // 000000037ff07bdd 00 OK mceusb - char scanCode[128]; - char buttonName[128]; - char repeatStr[4]; - char deviceName[128]; - sscanf(buf, "%s %s %s %s", &scanCode[0], &repeatStr[0], &buttonName[0], &deviceName[0]); - - //beginning of lirc reply packet - //we get one when lirc is done sending something - if (!m_inReply && strcmp("BEGIN", scanCode) == 0) - { - m_inReply = true; - continue; - } - else if (m_inReply && strcmp("END", scanCode) == 0) //end of lirc reply packet - { - m_inReply = false; - if (m_nrSending > 0) - m_nrSending--; - continue; - } - - if (m_inReply) - continue; - - // Some template LIRC configuration have button names in apostrophes or quotes. - // If we got a quoted button name, strip 'em - unsigned int buttonNameLen = strlen(buttonName); - if ( buttonNameLen > 2 - && ( (buttonName[0] == '\'' && buttonName[buttonNameLen-1] == '\'') - || ((buttonName[0] == '"' && buttonName[buttonNameLen-1] == '"') ) ) ) - { - memmove( buttonName, buttonName + 1, buttonNameLen - 2 ); - buttonName[ buttonNameLen - 2 ] = '\0'; + CSingleLock lock(m_critSection); + m_fd = lirc_init(const_cast<char*>("kodi"), 0); + if (m_fd <= 0) + { + CSingleExit lock(m_critSection); + Sleep(1000); + continue; + } } - m_button = CServiceBroker::GetInputManager().TranslateLircRemoteString(deviceName, buttonName); - - char *end = NULL; - long repeat = strtol(repeatStr, &end, 16); - if (!end || *end != 0) - CLog::Log(LOGERROR, "LIRC: invalid non-numeric character in expression %s", repeatStr); - if (repeat == 0) - { - CLog::Log(LOGDEBUG, "LIRC: %s - NEW at %d:%s (%s)", __FUNCTION__, now, buf, buttonName); - m_firstClickTime = now; - m_holdTime = 0; - return; - } - else if (repeat > g_advancedSettings.m_remoteDelay) - { - m_holdTime = now - m_firstClickTime; - } - else + char *code; + while (!m_bStop) { - m_holdTime = 0; - m_button = 0; + int ret = lirc_nextcode(&code); + if (ret < 0) + { + lirc_deinit(); + Sleep(1000); + break; + } + if (code != nullptr) + { + if (m_profileId != CServiceBroker::GetProfileManager().GetCurrentProfileId()) + { + m_profileId = CServiceBroker::GetProfileManager().GetCurrentProfileId(); + m_irTranslator.Load("Lircmap.xml"); + } + ProcessCode(code); + free(code); + } } } - //drop commands when already sending - //because keypresses come in faster than lirc can send we risk hammering the daemon with commands - CSingleLock lock(m_CS); - - if (m_nrSending > 0) - { - m_sendData.clear(); - } - else if (!m_sendData.empty()) - { - fputs(m_sendData.c_str(), m_file); - fflush(m_file); - - //nr of newlines equals nr of commands - for (int i = 0; i < (int)m_sendData.size(); i++) - if (m_sendData[i] == '\n') - m_nrSending++; + lirc_deinit(); +} - m_sendData.clear(); - } +void CLirc::ProcessCode(char *buf) +{ + // Parse the result. Sample line: + // 000000037ff07bdd 00 OK mceusb + char scanCode[128]; + char buttonName[128]; + char repeatStr[4]; + char deviceName[128]; + sscanf(buf, "%s %s %s %s", &scanCode[0], &repeatStr[0], &buttonName[0], &deviceName[0]); - if (feof(m_file) != 0) + // Some template LIRC configuration have button names in apostrophes or quotes. + // If we got a quoted button name, strip 'em + unsigned int buttonNameLen = strlen(buttonName); + if (buttonNameLen > 2 && + ((buttonName[0] == '\'' && buttonName[buttonNameLen-1] == '\'') || + ((buttonName[0] == '"' && buttonName[buttonNameLen-1] == '"')))) { - CSingleExit ex(m_CS); //Disconnect takes the lock - Disconnect(); + memmove(buttonName, buttonName + 1, buttonNameLen - 2); + buttonName[buttonNameLen - 2] = '\0'; } -} -uint16_t CRemoteControl::GetButton() const -{ - return m_button; -} + int button = m_irTranslator.TranslateButton(deviceName, buttonName); -uint32_t CRemoteControl::GetHoldTimeMs() const -{ - return m_holdTime; -} + char *end = nullptr; + long repeat = strtol(repeatStr, &end, 16); + if (!end || *end != 0) + CLog::Log(LOGERROR, "LIRC: invalid non-numeric character in expression %s", repeatStr); -void CRemoteControl::AddSendCommand(const std::string& command) -{ - if (!m_bInitialized || !m_used) + if (repeat == 0) + { + CLog::Log(LOGDEBUG, "LIRC: - NEW %s %s %s %s (%s)", &scanCode[0], &repeatStr[0], &buttonName[0], &deviceName[0], buttonName); + m_firstClickTime = XbmcThreads::SystemClockMillis(); + + XBMC_Event newEvent; + newEvent.type = XBMC_BUTTON; + newEvent.keybutton.button = button; + newEvent.keybutton.holdtime = 0; + g_application.OnEvent(newEvent); return; - - CSingleLock lock(m_CS); - - m_sendData += command; - m_sendData += '\n'; -} - -bool CRemoteControl::Connect(struct sockaddr_un addr, bool logMessages) -{ - bool bResult = false; - // Open the socket from which we will receive the remote commands - if ((m_fd = socket(AF_UNIX, SOCK_STREAM, 0)) != -1) + } + else if (repeat > g_advancedSettings.m_remoteDelay) { - // Connect to the socket - if (connect(m_fd, (struct sockaddr *)&addr, sizeof(addr)) != -1) - { - int opts; - if ((opts = fcntl(m_fd, F_GETFL)) != -1) - { - // Set the socket to non-blocking - opts = (opts | O_NONBLOCK); - if (fcntl(m_fd, F_SETFL, opts) != -1) - { - if ((m_file = fdopen(m_fd, "r+")) != NULL) - { -#ifdef HAVE_INOTIFY - // Setup inotify so we can disconnect if lircd is restarted - if ((m_inotify_fd = inotify_init()) >= 0) - { - // Set the fd non-blocking - if ((opts = fcntl(m_inotify_fd, F_GETFL)) != -1) - { - opts |= O_NONBLOCK; - if (fcntl(m_inotify_fd, F_SETFL, opts) != -1) - { - // Set an inotify watch on the lirc device - if ((m_inotify_wd = inotify_add_watch(m_inotify_fd, m_deviceName.c_str(), IN_DELETE_SELF)) != -1) - { - bResult = true; - CLog::Log(LOGINFO, "LIRC %s: successfully started", __FUNCTION__); - } - else - CLog::Log(LOGDEBUG, "LIRC: Failed to initialize Inotify. LIRC device will not be monitored."); - } - } - } -#else - bResult = true; - CLog::Log(LOGINFO, "LIRC %s: successfully started", __FUNCTION__); -#endif - } - else - CLog::Log(LOGERROR, "LIRC %s: fdopen failed: %s", __FUNCTION__, strerror(errno)); - } - else - CLog::Log(LOGERROR, "LIRC %s: fcntl(F_SETFL) failed: %s", __FUNCTION__, strerror(errno)); - } - else - CLog::Log(LOGERROR, "LIRC %s: fcntl(F_GETFL) failed: %s", __FUNCTION__, strerror(errno)); - } - else if (logMessages) - CLog::Log(LOGINFO, "LIRC %s: connect failed: %s", __FUNCTION__, strerror(errno)); + XBMC_Event newEvent; + newEvent.type = XBMC_BUTTON; + newEvent.keybutton.button = button; + newEvent.keybutton.holdtime = XbmcThreads::SystemClockMillis() - m_firstClickTime; + g_application.OnEvent(newEvent); } - else if (logMessages) - CLog::Log(LOGINFO, "LIRC %s: socket failed: %s", __FUNCTION__, strerror(errno)); - - return bResult; } diff --git a/xbmc/platform/linux/input/LIRC.h b/xbmc/platform/linux/input/LIRC.h index aa24c4f603..d8c8ddbf51 100644 --- a/xbmc/platform/linux/input/LIRC.h +++ b/xbmc/platform/linux/input/LIRC.h @@ -1,5 +1,5 @@ /* -* Copyright (C) 2007-2013 Team XBMC +* Copyright (C) 2007-2018 Team XBMC * http://kodi.tv * * This Program is free software; you can redistribute it and/or modify @@ -20,62 +20,25 @@ #pragma once -#include <string> -#include <atomic> - -#include "input/remote/IRemoteControl.h" #include "threads/Thread.h" -#include "threads/Event.h" +#include "threads/CriticalSection.h" +#include "input/IRTranslator.h" +#include <string> -class CRemoteControl : public KODI::REMOTE::IRemoteControl, CThread +class CLirc : CThread { public: - CRemoteControl(); - ~CRemoteControl() override; - void Initialize() override; - void Disconnect() override; - void Reset() override; - void Update() override; - uint16_t GetButton() const override; - /*! \brief retrieve the time in milliseconds that the button has been held - \return time in milliseconds the button has been down - */ - uint32_t GetHoldTimeMs() const override; - void SetDeviceName(const std::string& name) override; - void SetEnabled(bool bEnabled) override; - bool IsInUse() const override { return m_used; } - bool IsInitialized() const override { return m_bInitialized; } - void AddSendCommand(const std::string& command) override; - std::string GetMapFile() override; - - static IRemoteControl* CreateInstance(); - static void Register(); + CLirc(); + ~CLirc() override; + void Start(); protected: void Process() override; + void ProcessCode(char *buf); - bool Connect(struct sockaddr_un addr, bool logMessages); - -private: - int m_fd; -#ifdef HAVE_INOTIFY - int m_inotify_fd; - int m_inotify_wd; -#endif - FILE* m_file; - unsigned int m_holdTime; - int32_t m_button; - - std::atomic<bool> m_bInitialized; - std::atomic<bool> m_inReply; - std::atomic<int> m_nrSending; - - bool m_used; - uint32_t m_firstClickTime; - std::string m_deviceName; - bool CheckDevice(); - std::string m_sendData; - CEvent m_event; - CCriticalSection m_CS; - + int m_fd = -1; + uint32_t m_firstClickTime = 0; + CCriticalSection m_critSection; + CIRTranslator m_irTranslator; + int m_profileId; }; diff --git a/xbmc/powermanagement/PowerManager.cpp b/xbmc/powermanagement/PowerManager.cpp index 6f177b97fd..9582aec05e 100644 --- a/xbmc/powermanagement/PowerManager.cpp +++ b/xbmc/powermanagement/PowerManager.cpp @@ -184,13 +184,6 @@ void CPowerManager::OnSleep() CLog::Log(LOGNOTICE, "%s: Running sleep jobs", __FUNCTION__); - // stop lirc - if (CBuiltins::GetInstance().HasCommand("LIRC.Stop")) - { - CLog::Log(LOGNOTICE, "%s: Stopping lirc", __FUNCTION__); - CBuiltins::GetInstance().Execute("LIRC.Stop"); - } - CServiceBroker::GetPVRManager().OnSleep(); StorePlayerState(); g_application.StopPlaying(); @@ -224,13 +217,6 @@ void CPowerManager::OnWake() g_application.ResetScreenSaver(); #endif - // restart lirc - if (CBuiltins::GetInstance().HasCommand("LIRC.Start")) - { - CLog::Log(LOGNOTICE, "%s: Restarting lirc", __FUNCTION__); - CBuiltins::GetInstance().Execute("LIRC.Start"); - } - CServiceBroker::GetActiveAE()->Resume(); g_application.UpdateLibraries(); CServiceBroker::GetWeatherManager().Refresh(); diff --git a/xbmc/windowing/WinSystem.cpp b/xbmc/windowing/WinSystem.cpp index e41194cd7a..3bb63a7bed 100644 --- a/xbmc/windowing/WinSystem.cpp +++ b/xbmc/windowing/WinSystem.cpp @@ -30,9 +30,6 @@ #if HAS_GLES #include "guilib/GUIFontTTFGL.h" #endif -#if HAS_LIRC -#include "platform/linux/input/LIRC.h" -#endif CWinSystemBase::CWinSystemBase() { @@ -42,9 +39,6 @@ CWinSystemBase::CWinSystemBase() m_gfxContext->ResetScreenParameters((RESOLUTION)i); m_gfxContext->ResetOverscan((RESOLUTION)i, CDisplaySettings::GetInstance().GetResolutionInfo(i).Overscan); } -#if HAS_LIRC - CRemoteControl::Register(); -#endif } CWinSystemBase::~CWinSystemBase() = default; diff --git a/xbmc/windowing/X11/WinSystemX11GLContext.cpp b/xbmc/windowing/X11/WinSystemX11GLContext.cpp index f46cbf25f6..17b83a0548 100644 --- a/xbmc/windowing/X11/WinSystemX11GLContext.cpp +++ b/xbmc/windowing/X11/WinSystemX11GLContext.cpp @@ -77,6 +77,8 @@ CWinSystemX11GLContext::CWinSystemX11GLContext() } } } + + m_lirc.reset(OPTIONALS::LircRegister()); } CWinSystemX11GLContext::~CWinSystemX11GLContext() diff --git a/xbmc/windowing/X11/WinSystemX11GLContext.h b/xbmc/windowing/X11/WinSystemX11GLContext.h index 59ca4221b0..441bec8e95 100644 --- a/xbmc/windowing/X11/WinSystemX11GLContext.h +++ b/xbmc/windowing/X11/WinSystemX11GLContext.h @@ -24,6 +24,7 @@ #include "EGL/egl.h" #include "rendering/gl/RenderSystemGL.h" +#include "platform/linux/OptionalsReg.h" #include <memory> class CGLContext; @@ -71,4 +72,6 @@ protected: void operator()(CVaapiProxy *p) const; }; std::unique_ptr<CVaapiProxy, delete_CVaapiProxy> m_vaapiProxy; + + std::unique_ptr<OPTIONALS::CLircContainer, OPTIONALS::delete_CLircContainer> m_lirc; }; diff --git a/xbmc/windowing/XBMC_events.h b/xbmc/windowing/XBMC_events.h index 853614f1a8..f6d00992ba 100644 --- a/xbmc/windowing/XBMC_events.h +++ b/xbmc/windowing/XBMC_events.h @@ -43,6 +43,7 @@ typedef enum { XBMC_VIDEOMOVE, /* User moved the window */ XBMC_MODECHANGE, /* Video mode must be changed */ XBMC_TOUCH, + XBMC_BUTTON, /* Button (remote) pressed */ XBMC_SETFOCUS, XBMC_USEREVENT, @@ -114,6 +115,13 @@ typedef struct XBMC_SetFocusEvent { int y; /* y position */ } XBMC_SetFocusEvent; +/* Button event structure */ +typedef struct XBMC_ButtonEvent +{ + uint32_t button; + uint32_t holdtime; +} XBMC_ButtonEvent; + /* General event structure */ typedef struct XBMC_Event { uint8_t type; @@ -129,6 +137,7 @@ typedef struct XBMC_Event { XBMC_UserEvent user; XBMC_AppCommandEvent appcommand; XBMC_TouchEvent touch; + XBMC_ButtonEvent keybutton; XBMC_SetFocusEvent focus; }; } XBMC_Event; diff --git a/xbmc/windowing/gbm/WinSystemGbm.cpp b/xbmc/windowing/gbm/WinSystemGbm.cpp index f96b8782ff..45783bd9f1 100644 --- a/xbmc/windowing/gbm/WinSystemGbm.cpp +++ b/xbmc/windowing/gbm/WinSystemGbm.cpp @@ -71,6 +71,7 @@ CWinSystemGbm::CWinSystemGbm() : m_winEvents.reset(new CWinEventsLinux()); CLinuxPowerSyscall::Register(); + m_lirc.reset(OPTIONALS::LircRegister()); } bool CWinSystemGbm::InitWindowSystem() diff --git a/xbmc/windowing/gbm/WinSystemGbm.h b/xbmc/windowing/gbm/WinSystemGbm.h index 87a5afcbae..90771df278 100644 --- a/xbmc/windowing/gbm/WinSystemGbm.h +++ b/xbmc/windowing/gbm/WinSystemGbm.h @@ -23,6 +23,7 @@ #include <gbm.h> #include <EGL/egl.h> +#include "platform/linux/OptionalsReg.h" #include "threads/CriticalSection.h" #include "windowing/WinSystem.h" #include "DRMUtils.h" @@ -69,4 +70,5 @@ protected: bool m_delayDispReset; XbmcThreads::EndTime m_dispResetTimer; + std::unique_ptr<OPTIONALS::CLircContainer, OPTIONALS::delete_CLircContainer> m_lirc; }; diff --git a/xbmc/windowing/rpi/WinSystemRpi.cpp b/xbmc/windowing/rpi/WinSystemRpi.cpp index 0bcd31890a..82534f27c2 100644 --- a/xbmc/windowing/rpi/WinSystemRpi.cpp +++ b/xbmc/windowing/rpi/WinSystemRpi.cpp @@ -57,6 +57,7 @@ CWinSystemRpi::CWinSystemRpi() AE::CAESinkFactory::ClearSinks(); CAESinkPi::Register(); CLinuxPowerSyscall::Register(); + m_lirc.reset(OPTIONALS::LircRegister()); } CWinSystemRpi::~CWinSystemRpi() diff --git a/xbmc/windowing/rpi/WinSystemRpi.h b/xbmc/windowing/rpi/WinSystemRpi.h index b6efbe0bbf..b002426c66 100644 --- a/xbmc/windowing/rpi/WinSystemRpi.h +++ b/xbmc/windowing/rpi/WinSystemRpi.h @@ -21,6 +21,7 @@ #pragma once #include "RPIUtils.h" +#include "platform/linux/OptionalsReg.h" #include "rendering/gles/RenderSystemGLES.h" #include "threads/CriticalSection.h" #include "windowing/WinSystem.h" @@ -65,4 +66,5 @@ protected: CCriticalSection m_resourceSection; std::vector<IDispResource*> m_resources; + std::unique_ptr<OPTIONALS::CLircContainer, OPTIONALS::delete_CLircContainer> m_lirc; }; diff --git a/xbmc/windowing/wayland/WinSystemWayland.cpp b/xbmc/windowing/wayland/WinSystemWayland.cpp index bfedc8bb26..be7c40d23f 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.cpp +++ b/xbmc/windowing/wayland/WinSystemWayland.cpp @@ -175,6 +175,7 @@ CWinSystemWayland::CWinSystemWayland() } m_winEvents.reset(new CWinEventsWayland()); CLinuxPowerSyscall::Register(); + m_lirc.reset(OPTIONALS::LircRegister()); } CWinSystemWayland::~CWinSystemWayland() noexcept diff --git a/xbmc/windowing/wayland/WinSystemWayland.h b/xbmc/windowing/wayland/WinSystemWayland.h index dab870df7a..786d8c722b 100644 --- a/xbmc/windowing/wayland/WinSystemWayland.h +++ b/xbmc/windowing/wayland/WinSystemWayland.h @@ -36,6 +36,7 @@ #include "Seat.h" #include "Signals.h" #include "ShellSurface.h" +#include "platform/linux/OptionalsReg.h" #include "threads/CriticalSection.h" #include "threads/Event.h" #include "utils/ActorProtocol.h" @@ -296,6 +297,8 @@ private: std::uint32_t m_lastAckedSerial{0u}; /// Whether this is the first call to SetFullScreen bool m_isInitialSetFullScreen{true}; + + std::unique_ptr<OPTIONALS::CLircContainer, OPTIONALS::delete_CLircContainer> m_lirc; }; |