diff --git a/mythtv/configure b/mythtv/configure index 7ab8aa7..7d5e39d 100755 --- a/mythtv/configure +++ b/mythtv/configure @@ -5178,10 +5178,12 @@ using namespace std; using namespace CEC; #include int main(void) { + if (CEC_LIB_VERSION_MAJOR == 2) + return 1; if (CEC_LIB_VERSION_MAJOR < 1 || (CEC_LIB_VERSION_MAJOR == 1 && CEC_LIB_VERSION_MINOR < 5)) return 0; - return (long) LibCecInit; + return 1; } EOF fi diff --git a/mythtv/libs/libmythui/cecadapter.cpp b/mythtv/libs/libmythui/cecadapter.cpp index edad8f6..5987d5d 100644 --- a/mythtv/libs/libmythui/cecadapter.cpp +++ b/mythtv/libs/libmythui/cecadapter.cpp @@ -14,9 +14,28 @@ #include "cecadapter.h" #include -#define MIN_LIBCEC_VERSION 1 +#ifdef CEC_CLIENT_VERSION_CURRENT // 2.0.3 and up +#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_CURRENT; +#else +#ifdef LIBCEC_VERSION_CURRENT // 1.6.2 and up +#define CEC_CONFIG_VERSION LIBCEC_VERSION_CURRENT; +#else +#define CEC_CONFIG_VERSION 0; +#endif +#endif + #define MAX_CEC_DEVICES 10 #define LOC QString("CECAdapter: ") +#define OSDNAME "MythTv" + +// TODO remove if we have a ui. +// hard code logical and physical address +#define CEC_DEFAULT_DEVICE_TYPE CEC_DEVICE_TYPE_RECORDING_DEVICE +#undef CEC_DEFAULT_HDMI_PORT +#define CEC_DEFAULT_HDMI_PORT 2 +#undef CEC_DEFAULT_BASE_DEVICE +#define CEC_DEFAULT_BASE_DEVICE CECDEVICE_AUDIOSYSTEM +#define CEC_DEFAULT_PHYSICALADDRESS (quint16)0x2200 #include #include @@ -25,17 +44,26 @@ using namespace std; #include QMutex* CECAdapter::gLock = new QMutex(QMutex::Recursive); +bool resetSafe = false; class CECAdapterPriv { public: CECAdapterPriv() - : adapter(NULL), defaultDevice("auto"), defaultHDMIPort(1), - defaultDeviceID(CECDEVICE_PLAYBACKDEVICE1), timer(NULL), valid(false), + : adapter(NULL), defaultDevice("auto"), defaultHDMIPort(CEC_DEFAULT_HDMI_PORT), + defaultDeviceID(CEC_DEFAULT_DEVICE_TYPE), timer(NULL), valid(false), powerOffTV(false), powerOffTVAllowed(false), powerOffTVOnExit(false), powerOnTV(false), powerOnTVAllowed(false), powerOnTVOnStart(false), switchInput(false), switchInputAllowed(true) { + callbacks.Clear(); + callbacks.CBCecLogMessage = LogMessages; + callbacks.CBCecKeyPress = HandleKeyPresses; + callbacks.CBCecCommand = HandleCommands; + callbacks.CBCecConfigurationChanged = HandleConfigurationChanged; + callbacks.CBCecAlert = HandleAlerts; + callbacks.CBCecMenuStateChanged = HandleMenuStateChanged; + callbacks.CBCecSourceActivated = HandleSourceActivated; } static QString addressToString(enum cec_logical_address addr, bool source) @@ -69,14 +97,15 @@ class CECAdapterPriv static QStringList GetDeviceList(void) { QStringList results; - cec_device_type_list list; - list.Clear(); - list.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE); - ICECAdapter *adapter = LibCecInit("MythTV", list); + libcec_configuration configuration; + configuration.Clear(); + ICECAdapter *adapter = LibCecInitialise(&configuration); if (!adapter) return results; cec_adapter *devices = new cec_adapter[MAX_CEC_DEVICES]; uint8_t num_devices = adapter->FindAdapters(devices, MAX_CEC_DEVICES, NULL); + LOG(VB_GENERAL, LOG_INFO, LOC + QString("GetDeviceList() found %1 devices(s).") + .arg(num_devices)); if (num_devices < 1) return results; for (uint8_t i = 0; i < num_devices; i++) @@ -89,39 +118,112 @@ class CECAdapterPriv { // get settings // N.B. these do not currently work as there is no UI + + // There is no way current CEC adapters can find their physical address + // on their own. The are only connected to the CEC pin of the HDMI connector. + // To construct a valid physical address libCEC needs: + // - the HDMI port (number) Myth is connected to + // - the HDMI device (TV, Receiver) Myth is connected to (the logical address) + + //The CEC adapter we want to connect to defaultDevice = gCoreContext->GetSetting(LIBCEC_DEVICE, "auto").trimmed(); + // The number of the HDMI port Myth is connected to QString hdmi_port = gCoreContext->GetSetting(LIBCEC_PORT, "auto"); + // The logical address of the HDMI device Myth is connected to + QString base_dev = gCoreContext->GetSetting(LIBCEC_BASE, "auto"); + // Device type we want Myth to use QString device_id = gCoreContext->GetSetting(LIBCEC_DEVICEID, "auto"); powerOffTVAllowed = (bool)gCoreContext->GetNumSetting(POWEROFFTV_ALLOWED, 1); powerOffTVOnExit = (bool)gCoreContext->GetNumSetting(POWEROFFTV_ONEXIT, 1); powerOnTVAllowed = (bool)gCoreContext->GetNumSetting(POWERONTV_ALLOWED, 1); powerOnTVOnStart = (bool)gCoreContext->GetNumSetting(POWERONTV_ONSTART, 1); - defaultHDMIPort = 1; if ("auto" != hdmi_port) { defaultHDMIPort = hdmi_port.toInt(); - if (defaultHDMIPort < 1 || defaultHDMIPort > 3) - defaultHDMIPort = 1; + if (defaultHDMIPort < CEC_MIN_HDMI_PORTNUMBER || defaultHDMIPort > CEC_MAX_HDMI_PORTNUMBER) + defaultHDMIPort = CEC_DEFAULT_HDMI_PORT; + } + else + { + defaultHDMIPort = CEC_DEFAULT_HDMI_PORT; } - defaultHDMIPort = defaultHDMIPort << 12; - defaultDeviceID = CECDEVICE_PLAYBACKDEVICE1; if ("auto" != device_id) { int id = device_id.toInt(); - if (id < 1 || id > 3) - id = 1; - defaultDeviceID = (id == 1) ? CECDEVICE_PLAYBACKDEVICE1 : - ((id == 2) ? CECDEVICE_PLAYBACKDEVICE2 : - CECDEVICE_PLAYBACKDEVICE3); + switch (id) + { + case CEC_DEVICE_TYPE_TV: + case CEC_DEVICE_TYPE_RECORDING_DEVICE: + case CEC_DEVICE_TYPE_RESERVED: + case CEC_DEVICE_TYPE_TUNER: + case CEC_DEVICE_TYPE_PLAYBACK_DEVICE: + case CEC_DEVICE_TYPE_AUDIO_SYSTEM: + defaultDeviceID = (cec_device_type)id; + break; + default: + defaultDeviceID = CEC_DEFAULT_DEVICE_TYPE; + break; + } + } + else + { + defaultDeviceID = CEC_DEFAULT_DEVICE_TYPE; } + LOG(VB_GENERAL, LOG_INFO, LOC + QString("base_dev= %1.") + .arg(base_dev)); + if ("auto" != base_dev) + { + base_device = (cec_logical_address)base_dev.toInt(); + LOG(VB_GENERAL, LOG_INFO, LOC + QString("base_device= %1.") + .arg(base_device)); + switch (base_device) + { + case CECDEVICE_TV: + case CECDEVICE_RECORDINGDEVICE1: + case CECDEVICE_RECORDINGDEVICE2: + case CECDEVICE_TUNER1: + case CECDEVICE_PLAYBACKDEVICE1: + case CECDEVICE_AUDIOSYSTEM: + case CECDEVICE_TUNER2: + case CECDEVICE_TUNER3: + case CECDEVICE_PLAYBACKDEVICE2: + case CECDEVICE_RECORDINGDEVICE3: + case CECDEVICE_TUNER4: + case CECDEVICE_PLAYBACKDEVICE3: + case CECDEVICE_FREEUSE: + break; + case CECDEVICE_UNKNOWN: + case CECDEVICE_RESERVED1: + case CECDEVICE_RESERVED2: + case CECDEVICE_BROADCAST: + default: + base_device = (cec_logical_address)CEC_DEFAULT_BASE_DEVICE; + break; + } + } + else + { + base_device = (cec_logical_address)CEC_DEFAULT_BASE_DEVICE; + } + // create adapter interface - cec_device_type_list list; - list.Clear(); - list.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE); - adapter = LibCecInit("MythTV", list); + libcec_configuration configuration; + configuration.Clear(); + configuration.clientVersion = LIBCEC_VERSION_CURRENT; + snprintf(configuration.strDeviceName, 13, "MythTV"); + configuration.deviceTypes.Add(defaultDeviceID); + configuration.iPhysicalAddress = CEC_DEFAULT_PHYSICALADDRESS; + configuration.iHDMIPort = defaultHDMIPort; + LOG(VB_GENERAL, LOG_INFO, LOC + QString("using HDMI port %1.") + .arg(defaultHDMIPort)); + configuration.baseDevice = base_device; + LOG(VB_GENERAL, LOG_INFO, LOC + QString("using base device %1.") + .arg(configuration.baseDevice)); + configuration.callbacks = &callbacks; + ICECAdapter *adapter = LibCecInitialise(&configuration); if (!adapter) { @@ -129,12 +231,12 @@ class CECAdapterPriv return false; } - if (adapter->GetMinLibVersion() > MIN_LIBCEC_VERSION) + if ((configuration.serverVersion >> 12) > CEC_MIN_LIB_VERSION) { LOG(VB_GENERAL, LOG_ERR, LOC + QString("The installed libCEC supports version %1 and above. " "This version of MythTV only supports version %2.") - .arg(adapter->GetMinLibVersion()).arg(MIN_LIBCEC_VERSION)); + .arg(configuration.serverVersion).arg(CEC_MIN_LIB_VERSION)); return false; } @@ -185,12 +287,6 @@ class CECAdapterPriv // get the vendor ID (for non-standard implementations) adapter->GetDeviceVendorId(CECDEVICE_TV); - // set the physical address - adapter->SetPhysicalAddress(defaultHDMIPort); - - // set the logical address - adapter->SetLogicalAddress(defaultDeviceID); - // switch input (if configured) switchInput = true; HandleActions(); @@ -210,7 +306,6 @@ class CECAdapterPriv // delete adapter adapter->Close(); - LogMessages(); UnloadLibCec(adapter); LOG(VB_GENERAL, LOG_INFO, LOC + "Closing down CEC."); @@ -219,14 +314,12 @@ class CECAdapterPriv adapter = NULL; } - void LogMessages(void) + #if CEC_LIB_VERSION_MAJOR < 2 + static int LogMessages(void *, const cec_log_message &message) + #else + static int LogMessages(void *, const cec_log_message message) + #endif { - if (!adapter || !valid) - return; - - cec_log_message message; - while (adapter->GetNextLogMessage(&message)) - { QString msg(message.message); int lvl = LOG_UNKNOWN; switch (message.level) @@ -237,19 +330,15 @@ class CECAdapterPriv case CEC_LOG_DEBUG: lvl = LOG_DEBUG; break; } LOG(VB_GENERAL, lvl, LOC + QString("%1").arg(msg)); - } + return 0; } - void HandleCommands(void) + #if CEC_LIB_VERSION_MAJOR < 2 + static int HandleCommands(void * /*cbParam*/, const cec_command &command) + #else + static int HandleCommands(void * /*cbParam*/, const cec_command command) + #endif { - if (!adapter || !valid) - return; - - LogMessages(); - - cec_command command; - while (adapter->GetNextCommand(&command)) - { LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Command %1 from '%2' (%3) - destination '%4' (%5)") .arg(command.opcode) @@ -260,27 +349,76 @@ class CECAdapterPriv switch (command.opcode) { - // TODO + // TODO handle CEC commands. default: break; } - } + return 0; + } - LogMessages(); + #if CEC_LIB_VERSION_MAJOR < 2 + static int HandleConfigurationChanged(void * /*cbParam*/, const libcec_configuration &config) + #else + static int HandleConfigurationChanged(void * /*cbParam*/, const libcec_configuration config) + #endif + { + LOG(VB_GENERAL, LOG_INFO, LOC + "Adapter configuration changed."); + return 1; } - void HandleKeyPresses(void) + #if CEC_LIB_VERSION_MAJOR < 2 + static int HandleAlerts(void * /*cbParam*/, const libcec_alert type, const libcec_parameter & /*param*/) + #else + static int HandleAlerts(void * /*cbParam*/, const libcec_alert type, const libcec_parameter /*param*/) + #endif { - if (!adapter || !valid) - return; + switch (type) // TODO Handle alerts. + { + case CEC_ALERT_CONNECTION_LOST: + LOG(VB_GENERAL, LOG_ERR, LOC + "Connection lost - TODO: need to handle this!"); + break; + default: + LOG(VB_GENERAL, LOG_ERR, LOC + "Received unknown alert."); + break; + } + return 0; + } - cec_keypress key; - if (!adapter->GetNextKeypress(&key)) - return; + #if CEC_LIB_VERSION_MAJOR < 2 + static int HandleMenuStateChanged(void * /*cbParam*/, const cec_menu_state &state) + #else + static int HandleMenuStateChanged(void * /*cbParam*/, const cec_menu_state state) + #endif + { + LOG(VB_GENERAL, LOG_INFO, LOC + QString("CEC menu state %1") + .arg(state == CEC_MENU_STATE_ACTIVATED ? "Activated" : "Deactivated")); + return 1; + } + #if CEC_LIB_VERSION_MAJOR < 2 + static void HandleSourceActivated(void * /*cbParam*/, const cec_logical_address &address, const &uint8_t activated) + #else + static void HandleSourceActivated(void * /*cbParam*/, const cec_logical_address address, const uint8_t activated) + #endif + { + LOG(VB_GENERAL, LOG_INFO, LOC + QString("Source %1 %2") + .arg(address).arg(activated ? "Activated" : "Deactivated")); + + if (activated && resetSafe) + GetMythUI()->ResetScreensaver(); + else + resetSafe = true; + } + + #if CEC_LIB_VERSION_MAJOR < 2 + static int HandleKeyPresses(void * /*cbParam*/, const cec_keypress &key) + #else + static int HandleKeyPresses(void * /*cbParam*/, const cec_keypress key) + #endif + { // Ignore key down events and wait for the key 'up' if (key.duration < 1) - return; + return 0; QString code; int action = 0; @@ -595,13 +733,12 @@ class CECAdapterPriv .arg(code).arg(0 == action ? "(Not actioned)" : "")); if (0 == action) - return; + return 0; GetMythUI()->ResetScreensaver(); QKeyEvent* ke = new QKeyEvent(QEvent::KeyPress, action, Qt::NoModifier); qApp->postEvent(GetMythMainWindow(), (QEvent*)ke); - - LogMessages(); + return 0; } void HandleActions(void) @@ -629,7 +766,7 @@ class CECAdapterPriv // HDMI input if (switchInput && switchInputAllowed) { - if (adapter->SetActiveView()) + if (adapter->SetActiveSource()) LOG(VB_GENERAL, LOG_INFO, LOC + "Asked TV to switch to this input."); else LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to switch to this input."); @@ -638,14 +775,14 @@ class CECAdapterPriv powerOffTV = false; powerOnTV = false; switchInput = false; - - LogMessages(); } ICECAdapter *adapter; + ICECCallbacks callbacks; QString defaultDevice; int defaultHDMIPort; - cec_logical_address defaultDeviceID; + cec_device_type defaultDeviceID; + cec_logical_address base_device; QTimer *timer; bool valid; bool powerOffTV; @@ -728,8 +865,6 @@ void CECAdapter::Action(const QString &action) void CECAdapter::Process(void) { gLock->lock(); - m_priv->HandleCommands(); - m_priv->HandleKeyPresses(); m_priv->HandleActions(); gLock->unlock(); } diff --git a/mythtv/libs/libmythui/cecadapter.h b/mythtv/libs/libmythui/cecadapter.h index e9cf6d6..bb5eba8 100644 --- a/mythtv/libs/libmythui/cecadapter.h +++ b/mythtv/libs/libmythui/cecadapter.h @@ -7,6 +7,7 @@ #define LIBCEC_ENABLED QString("libCECEnabled") #define LIBCEC_DEVICE QString("libCECDevice") #define LIBCEC_PORT QString("libCECPort") +#define LIBCEC_BASE QString("libCECBase") #define LIBCEC_DEVICEID QString("libCECDeviceID") #define POWEROFFTV_ALLOWED QString("PowerOffTVAllowed") #define POWEROFFTV_ONEXIT QString("PowerOffTVOnExit")