diff --git a/packages/mediacenter/kodi/patches/kodi-995.01-fernetmenta.patch b/packages/mediacenter/kodi/patches/kodi-995.01-fernetmenta.patch index 9b171f4a2d..6b365972ce 100644 --- a/packages/mediacenter/kodi/patches/kodi-995.01-fernetmenta.patch +++ b/packages/mediacenter/kodi/patches/kodi-995.01-fernetmenta.patch @@ -1809,1012 +1809,6 @@ index 732e92b..849e26a 100644 if (m_vaapiOutput.m_controlPort.SendOutMessageSync(COutputControlProtocol::PRECLEANUP, &reply, -From 7aea148f78db91c4a2e75c280972e98735791a28 Mon Sep 17 00:00:00 2001 -From: Anssi Hannula -Date: Sun, 19 Oct 2014 21:34:47 +0300 -Subject: [PATCH 20/23] [linux] Add FDEventMonitor for monitoring file - descriptors - -Add FDEventMonitor helper thread for monitoring file descriptors for -events (ready for read, ready for write) without the need for spawning -a separate thread with a tight loop around poll()/select(). - -FDEventMonitor uses an eventfd for signaling poll() instead of a -timeout, therefore it can sleep for long times in case of no events but -still immediately respond to e.g. shutdown. ---- - xbmc/linux/FDEventMonitor.cpp | 248 ++++++++++++++++++++++++++++++++++++++++++ - xbmc/linux/FDEventMonitor.h | 89 +++++++++++++++ - xbmc/linux/Makefile.in | 1 + - 3 files changed, 338 insertions(+) - create mode 100644 xbmc/linux/FDEventMonitor.cpp - create mode 100644 xbmc/linux/FDEventMonitor.h - -diff --git a/xbmc/linux/FDEventMonitor.cpp b/xbmc/linux/FDEventMonitor.cpp -new file mode 100644 -index 0000000..4a41477 ---- /dev/null -+++ b/xbmc/linux/FDEventMonitor.cpp -@@ -0,0 +1,248 @@ -+/* -+ * Copyright (C) 2014 Team Kodi -+ * http://xbmc.org -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This Program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with Kodi; see the file COPYING. If not, see -+ * . -+ * -+ */ -+#include "system.h" -+#ifdef HAS_ALSA -+ -+#include -+#include -+#include -+ -+#include "utils/log.h" -+ -+#include "FDEventMonitor.h" -+ -+CFDEventMonitor::CFDEventMonitor() : -+ CThread("FDEventMonitor"), -+ m_nextID(0), -+ m_wakeupfd(-1) -+{ -+} -+ -+CFDEventMonitor::~CFDEventMonitor() -+{ -+ CSingleLock lock(m_mutex); -+ InterruptPoll(); -+ -+ if (m_wakeupfd >= 0) -+ { -+ /* sets m_bStop */ -+ StopThread(false); -+ -+ /* wake up the poll() call */ -+ eventfd_write(m_wakeupfd, 1); -+ -+ /* Wait for the thread to stop */ -+ { -+ CSingleExit exit(m_mutex); -+ StopThread(true); -+ } -+ -+ close(m_wakeupfd); -+ } -+} -+ -+void CFDEventMonitor::AddFD(const MonitoredFD& monitoredFD, int& id) -+{ -+ CSingleLock lock(m_mutex); -+ InterruptPoll(); -+ -+ AddFDLocked(monitoredFD, id); -+ -+ StartMonitoring(); -+} -+ -+void CFDEventMonitor::AddFDs(const std::vector& monitoredFDs, -+ std::vector& ids) -+{ -+ CSingleLock lock(m_mutex); -+ InterruptPoll(); -+ -+ for (unsigned int i = 0; i < monitoredFDs.size(); ++i) -+ { -+ int id; -+ AddFDLocked(monitoredFDs[i], id); -+ ids.push_back(id); -+ } -+ -+ StartMonitoring(); -+} -+ -+void CFDEventMonitor::RemoveFD(int id) -+{ -+ CSingleLock lock(m_mutex); -+ InterruptPoll(); -+ -+ if (m_monitoredFDs.erase(id) != 1) -+ { -+ CLog::Log(LOGERROR, "CFDEventMonitor::RemoveFD - Tried to remove non-existing monitoredFD %d", id); -+ } -+ -+ UpdatePollDescs(); -+} -+ -+void CFDEventMonitor::RemoveFDs(const std::vector& ids) -+{ -+ CSingleLock lock(m_mutex); -+ InterruptPoll(); -+ -+ for (unsigned int i = 0; i < ids.size(); ++i) -+ { -+ if (m_monitoredFDs.erase(ids[i]) != 1) -+ { -+ CLog::Log(LOGERROR, "CFDEventMonitor::RemoveFDs - Tried to remove non-existing monitoredFD %d while removing %u FDs", ids[i], (unsigned)ids.size()); -+ } -+ } -+ -+ UpdatePollDescs(); -+} -+ -+void CFDEventMonitor::Process() -+{ -+ eventfd_t dummy; -+ -+ while (!m_bStop) -+ { -+ CSingleLock lock(m_mutex); -+ CSingleLock pollLock(m_pollMutex); -+ -+ /* -+ * Leave the main mutex here to allow another thread to -+ * lock it while we are in poll(). -+ * By then calling InterruptPoll() the other thread can -+ * wake up poll and wait for the processing to pause at -+ * the above lock(m_mutex). -+ */ -+ lock.Leave(); -+ -+ int err = poll(&m_pollDescs[0], m_pollDescs.size(), -1); -+ -+ if (err < 0 && errno != EINTR) -+ { -+ CLog::Log(LOGERROR, "CFDEventMonitor::Process - poll() failed, error %d, stopping monitoring", errno); -+ StopThread(false); -+ } -+ -+ // Something woke us up - either there is data available or we are being -+ // paused/stopped via m_wakeupfd. -+ -+ for (unsigned int i = 0; i < m_pollDescs.size(); ++i) -+ { -+ struct pollfd& pollDesc = m_pollDescs[i]; -+ int id = m_monitoredFDbyPollDescs[i]; -+ const MonitoredFD& monitoredFD = m_monitoredFDs[id]; -+ -+ if (pollDesc.revents) -+ { -+ if (monitoredFD.callback) -+ { -+ monitoredFD.callback(id, pollDesc.fd, pollDesc.revents, -+ monitoredFD.callbackData); -+ } -+ -+ if (pollDesc.revents & (POLLERR | POLLHUP | POLLNVAL)) -+ { -+ CLog::Log(LOGERROR, "CFDEventMonitor::Process - polled fd %d got revents 0x%x, removing it", pollDesc.fd, pollDesc.revents); -+ -+ /* Probably would be nice to inform our caller that their FD was -+ * dropped, but oh well... */ -+ m_monitoredFDs.erase(id); -+ UpdatePollDescs(); -+ } -+ -+ pollDesc.revents = 0; -+ } -+ } -+ -+ /* flush wakeup fd */ -+ eventfd_read(m_wakeupfd, &dummy); -+ -+ } -+} -+ -+void CFDEventMonitor::AddFDLocked(const MonitoredFD& monitoredFD, int& id) -+{ -+ id = m_nextID; -+ -+ while (m_monitoredFDs.count(id)) -+ { -+ ++id; -+ } -+ m_nextID = id + 1; -+ -+ m_monitoredFDs[id] = monitoredFD; -+ -+ AddPollDesc(id, monitoredFD.fd, monitoredFD.events); -+} -+ -+void CFDEventMonitor::AddPollDesc(int id, int fd, short events) -+{ -+ struct pollfd newPollFD; -+ newPollFD.fd = fd; -+ newPollFD.events = events; -+ newPollFD.revents = 0; -+ -+ m_pollDescs.push_back(newPollFD); -+ m_monitoredFDbyPollDescs.push_back(id); -+} -+ -+void CFDEventMonitor::UpdatePollDescs() -+{ -+ m_monitoredFDbyPollDescs.clear(); -+ m_pollDescs.clear(); -+ -+ for (std::map::iterator it = m_monitoredFDs.begin(); -+ it != m_monitoredFDs.end(); ++it) -+ { -+ AddPollDesc(it->first, it->second.fd, it->second.events); -+ } -+} -+ -+void CFDEventMonitor::StartMonitoring() -+{ -+ if (!IsRunning()) -+ { -+ /* Start the monitoring thread */ -+ -+ m_wakeupfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); -+ if (m_wakeupfd < 0) -+ { -+ CLog::Log(LOGERROR, "CFDEventMonitor::StartMonitoring - Failed to create eventfd, error %d", errno); -+ return; -+ } -+ -+ /* Add wakeup fd to the fd list */ -+ int id; -+ AddFDLocked(MonitoredFD(m_wakeupfd, POLLIN, NULL, NULL), id); -+ -+ Create(false); -+ } -+} -+ -+void CFDEventMonitor::InterruptPoll() -+{ -+ if (m_wakeupfd >= 0) -+ { -+ eventfd_write(m_wakeupfd, 1); -+ /* wait for the poll() result handling (if any) to end */ -+ CSingleLock pollLock(m_pollMutex); -+ } -+} -+ -+#endif -diff --git a/xbmc/linux/FDEventMonitor.h b/xbmc/linux/FDEventMonitor.h -new file mode 100644 -index 0000000..4602d12 ---- /dev/null -+++ b/xbmc/linux/FDEventMonitor.h -@@ -0,0 +1,89 @@ -+#pragma once -+/* -+ * Copyright (C) 2014 Team Kodi -+ * http://xbmc.org -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This Program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with Kodi; see the file COPYING. If not, see -+ * . -+ * -+ */ -+ -+#include "system.h" -+ -+#include -+#include -+ -+#include "threads/CriticalSection.h" -+#include "threads/Thread.h" -+ -+#include "utils/GlobalsHandling.h" -+ -+/** -+ * Monitor a file descriptor with callback on poll() events. -+ */ -+class CFDEventMonitor : private CThread -+{ -+public: -+ -+ typedef void (*EventCallback)(int id, int fd, short revents, void *data); -+ -+ struct MonitoredFD -+ { -+ int fd; /**< File descriptor to be monitored */ -+ short events; /**< Events to be monitored (see poll(2)) */ -+ -+ EventCallback callback; /** Callback to be called on events */ -+ void *callbackData; /** data parameter for EventCallback */ -+ -+ MonitoredFD(int fd_, short events_, EventCallback callback_, void *callbackData_) : -+ fd(fd_), events(events_), callback(callback_), callbackData(callbackData_) {} -+ MonitoredFD() : fd(-1), events(0), callback(NULL), callbackData(NULL) {} -+ }; -+ -+ CFDEventMonitor(); -+ ~CFDEventMonitor(); -+ -+ void AddFD(const MonitoredFD& monitoredFD, int& id); -+ void AddFDs(const std::vector& monitoredFDs, std::vector& ids); -+ -+ void RemoveFD(int id); -+ void RemoveFDs(const std::vector& ids); -+ -+protected: -+ virtual void Process(); -+ -+private: -+ void AddFDLocked(const MonitoredFD& monitoredFD, int& id); -+ -+ void AddPollDesc(int id, int fd, short events); -+ void UpdatePollDescs(); -+ -+ void StartMonitoring(); -+ void InterruptPoll(); -+ -+ std::map m_monitoredFDs; -+ -+ /* these are kept synchronized */ -+ std::vector m_monitoredFDbyPollDescs; -+ std::vector m_pollDescs; -+ -+ int m_nextID; -+ int m_wakeupfd; -+ -+ CCriticalSection m_mutex; -+ CCriticalSection m_pollMutex; -+}; -+ -+XBMC_GLOBAL_REF(CFDEventMonitor, g_fdEventMonitor); -+#define g_fdEventMonitor XBMC_GLOBAL_USE(CFDEventMonitor) -diff --git a/xbmc/linux/Makefile.in b/xbmc/linux/Makefile.in -index c147d8f..744fd06 100644 ---- a/xbmc/linux/Makefile.in -+++ b/xbmc/linux/Makefile.in -@@ -4,6 +4,7 @@ SRCS = ConvUtils.cpp - SRCS += DBusUtil.cpp - SRCS += DBusMessage.cpp - SRCS += DBusReserve.cpp -+SRCS += FDEventMonitor.cpp - SRCS += LinuxResourceCounter.cpp - SRCS += LinuxTimezone.cpp - SRCS += PosixMountProvider.cpp - -From b465939ca69cc2e02190a815d7b3e7291e14ca87 Mon Sep 17 00:00:00 2001 -From: Anssi Hannula -Date: Sun, 19 Oct 2014 21:36:44 +0300 -Subject: [PATCH 21/23] [AE] ALSA: Add ALSADeviceMonitor for monitoring card - removals/additions - ---- - xbmc/cores/AudioEngine/Makefile.in | 1 + - xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 8 ++ - xbmc/cores/AudioEngine/Sinks/AESinkALSA.h | 9 ++ - .../AudioEngine/Sinks/alsa/ALSADeviceMonitor.cpp | 131 +++++++++++++++++++++ - .../AudioEngine/Sinks/alsa/ALSADeviceMonitor.h | 49 ++++++++ - 5 files changed, 198 insertions(+) - create mode 100644 xbmc/cores/AudioEngine/Sinks/alsa/ALSADeviceMonitor.cpp - create mode 100644 xbmc/cores/AudioEngine/Sinks/alsa/ALSADeviceMonitor.h - -diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in -index efb44cc..614ede2 100644 ---- a/xbmc/cores/AudioEngine/Makefile.in -+++ b/xbmc/cores/AudioEngine/Makefile.in -@@ -50,6 +50,7 @@ SRCS += Sinks/osx/CoreAudioHelpers.cpp - SRCS += Sinks/osx/CoreAudioStream.cpp - else - SRCS += Sinks/AESinkALSA.cpp -+SRCS += Sinks/alsa/ALSADeviceMonitor.cpp - SRCS += Sinks/AESinkOSS.cpp - ifeq (@USE_PULSE@,1) - SRCS += Sinks/AESinkPULSE.cpp -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -index a464b4b..c2d5758 100644 ---- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -@@ -1066,6 +1066,10 @@ bool CAESinkALSA::OpenPCMDevice(const std::string &name, const std::string ¶ - - void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) - { -+#if HAVE_LIBUDEV -+ m_deviceMonitor.Start(); -+#endif -+ - /* ensure that ALSA has been initialized */ - snd_lib_error_set_handler(sndLibErrorHandler); - if(!snd_config || force) -@@ -1577,4 +1581,8 @@ void CAESinkALSA::sndLibErrorHandler(const char *file, int line, const char *fun - va_end(arg); - } - -+#if HAVE_LIBUDEV -+CALSADeviceMonitor CAESinkALSA::m_deviceMonitor; // ARGH -+#endif -+ - #endif -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h -index 7e05ce6..1177f41 100644 ---- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h -@@ -24,6 +24,7 @@ - - #include "cores/AudioEngine/Interfaces/AESink.h" - #include "cores/AudioEngine/Utils/AEDeviceInfo.h" -+#include "cores/AudioEngine/Sinks/alsa/ALSADeviceMonitor.h" - #include - - #define ALSA_PCM_NEW_HW_PARAMS_API -@@ -31,6 +32,10 @@ - - #include "threads/CriticalSection.h" - -+// ARGH... this is apparently needed to avoid FDEventMonitor -+// being destructed before CALSA*Monitor below. -+#include "linux/FDEventMonitor.h" -+ - class CAESinkALSA : public IAESink - { - public: -@@ -79,6 +84,10 @@ class CAESinkALSA : public IAESink - snd_pcm_t *m_pcm; - int m_timeout; - -+#if HAVE_LIBUDEV -+ static CALSADeviceMonitor m_deviceMonitor; -+#endif -+ - struct ALSAConfig - { - unsigned int sampleRate; -diff --git a/xbmc/cores/AudioEngine/Sinks/alsa/ALSADeviceMonitor.cpp b/xbmc/cores/AudioEngine/Sinks/alsa/ALSADeviceMonitor.cpp -new file mode 100644 -index 0000000..e3269ad ---- /dev/null -+++ b/xbmc/cores/AudioEngine/Sinks/alsa/ALSADeviceMonitor.cpp -@@ -0,0 +1,131 @@ -+/* -+ * Copyright (C) 2014 Team Kodi -+ * http://xbmc.org -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This Program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with Kodi; see the file COPYING. If not, see -+ * . -+ * -+ */ -+#include "system.h" -+#if defined(HAS_ALSA) && defined(HAVE_LIBUDEV) -+ -+#include -+ -+#include "ALSADeviceMonitor.h" -+#include "AEFactory.h" -+#include "linux/FDEventMonitor.h" -+#include "utils/log.h" -+ -+CALSADeviceMonitor::CALSADeviceMonitor() : -+ m_fdMonitorId(0), -+ m_udev(NULL), -+ m_udevMonitor(NULL) -+{ -+} -+ -+CALSADeviceMonitor::~CALSADeviceMonitor() -+{ -+ Stop(); -+} -+ -+void CALSADeviceMonitor::Start() -+{ -+ int err; -+ -+ if (!m_udev) -+ { -+ m_udev = udev_new(); -+ if (!m_udev) -+ { -+ CLog::Log(LOGWARNING, "CALSADeviceMonitor::Start - Unable to open udev handle"); -+ return; -+ } -+ -+ m_udevMonitor = udev_monitor_new_from_netlink(m_udev, "udev"); -+ if (!m_udevMonitor) -+ { -+ CLog::Log(LOGERROR, "CALSADeviceMonitor::Start - udev_monitor_new_from_netlink() failed"); -+ goto err_unref_udev; -+ } -+ -+ err = udev_monitor_filter_add_match_subsystem_devtype(m_udevMonitor, "sound", NULL); -+ if (err) -+ { -+ CLog::Log(LOGERROR, "CALSADeviceMonitor::Start - udev_monitor_filter_add_match_subsystem_devtype() failed"); -+ goto err_unref_monitor; -+ } -+ -+ err = udev_monitor_enable_receiving(m_udevMonitor); -+ if (err) -+ { -+ CLog::Log(LOGERROR, "CALSADeviceMonitor::Start - udev_monitor_enable_receiving() failed"); -+ goto err_unref_monitor; -+ } -+ -+ g_fdEventMonitor.AddFD( -+ CFDEventMonitor::MonitoredFD(udev_monitor_get_fd(m_udevMonitor), -+ POLLIN, FDEventCallback, m_udevMonitor), -+ m_fdMonitorId); -+ } -+ -+ return; -+ -+err_unref_monitor: -+ udev_monitor_unref(m_udevMonitor); -+ m_udevMonitor = NULL; -+err_unref_udev: -+ udev_unref(m_udev); -+ m_udev = NULL; -+} -+ -+void CALSADeviceMonitor::Stop() -+{ -+ if (m_udev) -+ { -+ g_fdEventMonitor.RemoveFD(m_fdMonitorId); -+ -+ udev_monitor_unref(m_udevMonitor); -+ m_udevMonitor = NULL; -+ udev_unref(m_udev); -+ m_udev = NULL; -+ } -+} -+ -+void CALSADeviceMonitor::FDEventCallback(int id, int fd, short revents, void *data) -+{ -+ struct udev_monitor *udevMonitor = (struct udev_monitor *)data; -+ bool audioDevicesChanged = false; -+ struct udev_device *device; -+ -+ while ((device = udev_monitor_receive_device(udevMonitor)) != NULL) -+ { -+ const char* action = udev_device_get_action(device); -+ const char* soundInitialized = udev_device_get_property_value(device, "SOUND_INITIALIZED"); -+ -+ /* cardX devices emit a "change" event when ready (i.e. all subdevices added) */ -+ if (action && soundInitialized && -+ (strcmp(action, "change") == 0 || strcmp(action, "remove") == 0)) -+ { -+ audioDevicesChanged = true; -+ } -+ udev_device_unref(device); -+ } -+ -+ if (audioDevicesChanged) -+ { -+ CAEFactory::DeviceChange(); -+ } -+} -+ -+#endif -diff --git a/xbmc/cores/AudioEngine/Sinks/alsa/ALSADeviceMonitor.h b/xbmc/cores/AudioEngine/Sinks/alsa/ALSADeviceMonitor.h -new file mode 100644 -index 0000000..f9e2f26 ---- /dev/null -+++ b/xbmc/cores/AudioEngine/Sinks/alsa/ALSADeviceMonitor.h -@@ -0,0 +1,49 @@ -+#pragma once -+/* -+ * Copyright (C) 2014 Team Kodi -+ * http://xbmc.org -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This Program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with Kodi; see the file COPYING. If not, see -+ * . -+ * -+ */ -+ -+#include "system.h" -+#if defined(HAS_ALSA) && defined(HAVE_LIBUDEV) -+ -+#include -+#include -+ -+#include -+ -+class CALSADeviceMonitor -+{ -+public: -+ CALSADeviceMonitor(); -+ ~CALSADeviceMonitor(); -+ -+ void Start(); -+ void Stop(); -+ -+private: -+ static void FDEventCallback(int id, int fd, short revents, void *data); -+ -+ int m_fdMonitorId; -+ -+ struct udev *m_udev; -+ struct udev_monitor* m_udevMonitor; -+}; -+ -+#endif -+ - -From f5555b53d7886387a624f011e7a58ec5cd247635 Mon Sep 17 00:00:00 2001 -From: Anssi Hannula -Date: Sun, 19 Oct 2014 21:37:49 +0300 -Subject: [PATCH 22/23] [AE] ALSA: Add ALSADeviceMonitor for monitoring ELD - changes - -ELD changes can happen e.g. when the connected HDMI sink is changed. ---- - xbmc/cores/AudioEngine/Makefile.in | 1 + - xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 9 ++ - xbmc/cores/AudioEngine/Sinks/AESinkALSA.h | 2 + - .../AudioEngine/Sinks/alsa/ALSAHControlMonitor.cpp | 173 +++++++++++++++++++++ - .../AudioEngine/Sinks/alsa/ALSAHControlMonitor.h | 69 ++++++++ - 5 files changed, 254 insertions(+) - create mode 100644 xbmc/cores/AudioEngine/Sinks/alsa/ALSAHControlMonitor.cpp - create mode 100644 xbmc/cores/AudioEngine/Sinks/alsa/ALSAHControlMonitor.h - -diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in -index 614ede2..8f13088 100644 ---- a/xbmc/cores/AudioEngine/Makefile.in -+++ b/xbmc/cores/AudioEngine/Makefile.in -@@ -51,6 +51,7 @@ SRCS += Sinks/osx/CoreAudioStream.cpp - else - SRCS += Sinks/AESinkALSA.cpp - SRCS += Sinks/alsa/ALSADeviceMonitor.cpp -+SRCS += Sinks/alsa/ALSAHControlMonitor.cpp - SRCS += Sinks/AESinkOSS.cpp - ifeq (@USE_PULSE@,1) - SRCS += Sinks/AESinkPULSE.cpp -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -index c2d5758..f92f488 100644 ---- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp -@@ -1083,6 +1083,8 @@ void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) - snd_config_t *config; - snd_config_copy(&config, snd_config); - -+ m_controlMonitor.Clear(); -+ - /* Always enumerate the default device. - * Note: If "default" is a stereo device, EnumerateDevice() - * will automatically add "@" instead to enable surroundXX mangling. -@@ -1160,6 +1162,8 @@ void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) - } - snd_device_name_free_hint(hints); - -+ m_controlMonitor.Start(); -+ - /* set the displayname for default device */ - if (!list.empty() && list[0].m_deviceName == "default") - { -@@ -1340,6 +1344,10 @@ void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &dev - { - snd_hctl_load(hctl); - bool badHDMI = false; -+ -+ /* add ELD to monitoring */ -+ m_controlMonitor.Add(strHwName, SND_CTL_ELEM_IFACE_PCM, dev, "ELD"); -+ - if (!GetELD(hctl, dev, info, badHDMI)) - CLog::Log(LOGDEBUG, "CAESinkALSA - Unable to obtain ELD information for device \"%s\" (not supported by device, or kernel older than 3.2)", - device.c_str()); -@@ -1584,5 +1592,6 @@ void CAESinkALSA::sndLibErrorHandler(const char *file, int line, const char *fun - #if HAVE_LIBUDEV - CALSADeviceMonitor CAESinkALSA::m_deviceMonitor; // ARGH - #endif -+CALSAHControlMonitor CAESinkALSA::m_controlMonitor; // ARGH - - #endif -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h -index 1177f41..8be8709 100644 ---- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.h -@@ -25,6 +25,7 @@ - #include "cores/AudioEngine/Interfaces/AESink.h" - #include "cores/AudioEngine/Utils/AEDeviceInfo.h" - #include "cores/AudioEngine/Sinks/alsa/ALSADeviceMonitor.h" -+#include "cores/AudioEngine/Sinks/alsa/ALSAHControlMonitor.h" - #include - - #define ALSA_PCM_NEW_HW_PARAMS_API -@@ -87,6 +88,7 @@ class CAESinkALSA : public IAESink - #if HAVE_LIBUDEV - static CALSADeviceMonitor m_deviceMonitor; - #endif -+ static CALSAHControlMonitor m_controlMonitor; - - struct ALSAConfig - { -diff --git a/xbmc/cores/AudioEngine/Sinks/alsa/ALSAHControlMonitor.cpp b/xbmc/cores/AudioEngine/Sinks/alsa/ALSAHControlMonitor.cpp -new file mode 100644 -index 0000000..9b595ee ---- /dev/null -+++ b/xbmc/cores/AudioEngine/Sinks/alsa/ALSAHControlMonitor.cpp -@@ -0,0 +1,173 @@ -+/* -+ * Copyright (C) 2014 Team Kodi -+ * http://xbmc.org -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This Program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with Kodi; see the file COPYING. If not, see -+ * . -+ * -+ */ -+#include "system.h" -+#ifdef HAS_ALSA -+ -+#include "ALSAHControlMonitor.h" -+ -+#include "AEFactory.h" -+#include "linux/FDEventMonitor.h" -+#include "utils/log.h" -+ -+CALSAHControlMonitor::CALSAHControlMonitor() -+{ -+} -+ -+CALSAHControlMonitor::~CALSAHControlMonitor() -+{ -+ Clear(); -+} -+ -+bool CALSAHControlMonitor::Add(const std::string& ctlHandleName, -+ snd_ctl_elem_iface_t interface, -+ unsigned int device, -+ const std::string& name) -+{ -+ snd_hctl_t *hctl = GetHandle(ctlHandleName); -+ -+ if (!hctl) -+ { -+ return false; -+ } -+ -+ snd_ctl_elem_id_t *id; -+ -+ snd_ctl_elem_id_alloca(&id); -+ -+ snd_ctl_elem_id_set_interface(id, interface); -+ snd_ctl_elem_id_set_name (id, name.c_str()); -+ snd_ctl_elem_id_set_device (id, device); -+ -+ snd_hctl_elem_t *elem = snd_hctl_find_elem(hctl, id); -+ -+ if (!elem) -+ { -+ PutHandle(ctlHandleName); -+ return false; -+ } -+ -+ snd_hctl_elem_set_callback(elem, HCTLCallback); -+ -+ return true; -+} -+ -+void CALSAHControlMonitor::Clear() -+{ -+ Stop(); -+ -+ for (std::map::iterator it = m_ctlHandles.begin(); -+ it != m_ctlHandles.end(); ++it) -+ { -+ snd_hctl_close(it->second.handle); -+ } -+ m_ctlHandles.clear(); -+} -+ -+void CALSAHControlMonitor::Start() -+{ -+ assert(m_fdMonitorIds.size() == 0); -+ -+ std::vector pollfds; -+ std::vector monitoredFDs; -+ -+ for (std::map::iterator it = m_ctlHandles.begin(); -+ it != m_ctlHandles.end(); ++it) -+ { -+ pollfds.resize(snd_hctl_poll_descriptors_count(it->second.handle)); -+ int fdcount = snd_hctl_poll_descriptors(it->second.handle, &pollfds[0], pollfds.size()); -+ -+ for (int j = 0; j < fdcount; ++j) -+ { -+ monitoredFDs.push_back(CFDEventMonitor::MonitoredFD(pollfds[j].fd, -+ pollfds[j].events, -+ FDEventCallback, -+ it->second.handle)); -+ } -+ } -+ -+ g_fdEventMonitor.AddFDs(monitoredFDs, m_fdMonitorIds); -+} -+ -+ -+void CALSAHControlMonitor::Stop() -+{ -+ g_fdEventMonitor.RemoveFDs(m_fdMonitorIds); -+ m_fdMonitorIds.clear(); -+} -+ -+int CALSAHControlMonitor::HCTLCallback(snd_hctl_elem_t *elem, unsigned int mask) -+{ -+ /* -+ * Currently we just re-enumerate on any change. -+ * Custom callbacks for handling other control monitoring may be implemented when needed. -+ */ -+ if (mask & SND_CTL_EVENT_MASK_VALUE) -+ { -+ CAEFactory::DeviceChange(); -+ } -+ -+ return 0; -+} -+ -+void CALSAHControlMonitor::FDEventCallback(int id, int fd, short revents, void *data) -+{ -+ /* Run ALSA event handling when the FD has events */ -+ snd_hctl_t *hctl = (snd_hctl_t *)data; -+ snd_hctl_handle_events(hctl); -+} -+ -+snd_hctl_t* CALSAHControlMonitor::GetHandle(const std::string& ctlHandleName) -+{ -+ if (!m_ctlHandles.count(ctlHandleName)) -+ { -+ snd_hctl_t *hctl; -+ -+ if (snd_hctl_open(&hctl, ctlHandleName.c_str(), 0) != 0) -+ { -+ CLog::Log(LOGWARNING, "CALSAHControlMonitor::GetHandle - snd_hctl_open() failed for \"%s\"", ctlHandleName.c_str()); -+ return NULL; -+ } -+ if (snd_hctl_load(hctl) != 0) -+ { -+ CLog::Log(LOGERROR, "CALSAHControlMonitor::GetHandle - snd_hctl_load() failed for \"%s\"", ctlHandleName.c_str()); -+ snd_hctl_close(hctl); -+ return NULL; -+ } -+ -+ snd_hctl_nonblock(hctl, 1); -+ -+ m_ctlHandles[ctlHandleName] = CTLHandle(hctl); -+ } -+ -+ m_ctlHandles[ctlHandleName].useCount++; -+ return m_ctlHandles[ctlHandleName].handle; -+} -+ -+void CALSAHControlMonitor::PutHandle(const std::string& ctlHandleName) -+{ -+ if (--m_ctlHandles[ctlHandleName].useCount == 0) -+ { -+ snd_hctl_close(m_ctlHandles[ctlHandleName].handle); -+ m_ctlHandles.erase(ctlHandleName); -+ } -+} -+ -+ -+#endif -diff --git a/xbmc/cores/AudioEngine/Sinks/alsa/ALSAHControlMonitor.h b/xbmc/cores/AudioEngine/Sinks/alsa/ALSAHControlMonitor.h -new file mode 100644 -index 0000000..56dfd50 ---- /dev/null -+++ b/xbmc/cores/AudioEngine/Sinks/alsa/ALSAHControlMonitor.h -@@ -0,0 +1,69 @@ -+#pragma once -+/* -+ * Copyright (C) 2014 Team Kodi -+ * http://xbmc.org -+ * -+ * This Program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2, or (at your option) -+ * any later version. -+ * -+ * This Program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with Kodi; see the file COPYING. If not, see -+ * . -+ * -+ */ -+ -+#include "system.h" -+#ifdef HAS_ALSA -+ -+#include -+#include -+#include -+ -+#include -+ -+class CALSAHControlMonitor -+{ -+public: -+ CALSAHControlMonitor(); -+ ~CALSAHControlMonitor(); -+ -+ bool Add(const std::string& ctlHandleName, -+ snd_ctl_elem_iface_t interface, -+ unsigned int device, -+ const std::string& name); -+ -+ void Clear(); -+ -+ void Start(); -+ void Stop(); -+ -+private: -+ static int HCTLCallback(snd_hctl_elem_t *elem, unsigned int mask); -+ static void FDEventCallback(int id, int fd, short revents, void *data); -+ -+ snd_hctl_t* GetHandle(const std::string& ctlHandleName); -+ void PutHandle(const std::string& ctlHandleName); -+ -+ struct CTLHandle -+ { -+ snd_hctl_t *handle; -+ int useCount; -+ -+ CTLHandle(snd_hctl_t *handle_) : handle(handle_), useCount(0) {} -+ CTLHandle() : handle(NULL), useCount(0) {} -+ }; -+ -+ std::map m_ctlHandles; -+ -+ std::vector m_fdMonitorIds; -+}; -+ -+#endif -+ - From 09b1724482fd9666e976c831976e30afe33537ab Mon Sep 17 00:00:00 2001 From: Rainer Hochecker Date: Sat, 1 Nov 2014 07:47:16 +0100