Ticket #11338: libcec2-upstream.patch

File libcec2-upstream.patch, 17.3 KB (added by Bradley Baetz <bbaetz@…>, 8 years ago)

Alternative patch

  • b/mythtv/libs/libmythui/cecadapter.cpp

    diff -u b/mythtv/libs/libmythui/cecadapter.cpp b/mythtv/libs/libmythui/cecadapter.cpp
     
    1313#include "cecadapter.h"
    1414#include <vector>
    1515
    16 #define MIN_LIBCEC_VERSION 1
    1716#define MAX_CEC_DEVICES 10
    1817#define LOC QString("CECAdapter: ")
    1918
     
    2726QMutex*         CECAdapter::gHandleActionsLock = new QMutex();
    2827QWaitCondition* CECAdapter::gActionsReady = new QWaitCondition();
    2928
     29#if CEC_LIB_VERSION_MAJOR < 2
     30// A few defines taken from libcec.h v2
     31#define CEC_MIN_HDMI_PORTNUMBER      1
     32#define CEC_MAX_HDMI_PORTNUMBER      15
     33// libcec1's callback parameters are pass-by-ref
     34#define CEC_CALLBACK_PARAM_TYPE &
     35#else
     36// libcec2's callback parameters are pass-by-value
     37#define CEC_CALLBACK_PARAM_TYPE
     38#endif
     39
    3040// The libCEC callback functions
    31 static int CECLogMessageCallback(void *adapter, const cec_log_message &message);
    32 static int CECKeyPressCallback(void *adapter, const cec_keypress &keypress);
    33 static int CECCommandCallback(void *adapter, const cec_command &command);
     41static int CECLogMessageCallback(void *adapter, const cec_log_message CEC_CALLBACK_PARAM_TYPE message);
     42static int CECKeyPressCallback(void *adapter, const cec_keypress CEC_CALLBACK_PARAM_TYPE keypress);
     43static int CECCommandCallback(void *adapter, const cec_command CEC_CALLBACK_PARAM_TYPE command);
     44
     45#if CEC_LIB_VERSION_MAJOR >= 2
     46static int CECAlertCallback(void *adapter, const libcec_alert alert, const libcec_parameter CEC_CALLBACK_PARAM_TYPE data);
     47static void CECSourceActivatedCallback(void *adapter, const cec_logical_address address, const uint8_t activated);
     48#endif
    3449
    3550class CECAdapterPriv
    3651{
    3752  public:
    3853    CECAdapterPriv()
    39       : adapter(NULL), defaultDevice("auto"), defaultHDMIPort(1),
    40         defaultDeviceID(CECDEVICE_PLAYBACKDEVICE1), valid(false),
     54      : adapter(NULL), valid(false),
    4155        powerOffTV(false),  powerOffTVAllowed(false), powerOffTVOnExit(false),
    4256        powerOnTV(false),   powerOnTVAllowed(false),  powerOnTVOnStart(false),
    4357        switchInput(false), switchInputAllowed(true)
    4458    {
    45                 // libcec2's ICECCallbacks has a constructor that clears
    46                 // all the entries. We're using 1.x....
    47                 memset(&callbacks, 0, sizeof(callbacks));
    48                 callbacks.CBCecLogMessage = &CECLogMessageCallback;
    49                 callbacks.CBCecKeyPress   = &CECKeyPressCallback;
    50                 callbacks.CBCecCommand    = &CECCommandCallback;
    51     }
    52 
    53     static QString addressToString(enum cec_logical_address addr, bool source)
    54     {
    55         switch (addr)
    56         {
    57             case CECDEVICE_UNKNOWN:          return QString("Unknown");
    58             case CECDEVICE_TV:               return QString("TV");
    59             case CECDEVICE_RECORDINGDEVICE1: return QString("RecordingDevice1");
    60             case CECDEVICE_RECORDINGDEVICE2: return QString("RecordingDevice2");
    61             case CECDEVICE_RECORDINGDEVICE3: return QString("RecordingDevice3");
    62             case CECDEVICE_TUNER1:           return QString("Tuner1");
    63             case CECDEVICE_TUNER2:           return QString("Tuner2");
    64             case CECDEVICE_TUNER3:           return QString("Tuner3");
    65             case CECDEVICE_TUNER4:           return QString("Tuner4");
    66             case CECDEVICE_PLAYBACKDEVICE1:  return QString("PlaybackDevice1");
    67             case CECDEVICE_PLAYBACKDEVICE2:  return QString("PlaybackDevice2");
    68             case CECDEVICE_PLAYBACKDEVICE3:  return QString("PlaybackDevice3");
    69             case CECDEVICE_AUDIOSYSTEM:      return QString("Audiosystem");
    70             case CECDEVICE_RESERVED1:        return QString("Reserved1");
    71             case CECDEVICE_RESERVED2:        return QString("Reserved2");
    72             case CECDEVICE_FREEUSE:          return QString("FreeUse");
    73             case CECDEVICE_UNREGISTERED:
    74             //case CECDEVICE_BROADCAST:
    75                 return source ? QString("Unregistered") : QString("Broadcast");
    76         }
    77         return QString("Invalid");
    78     }
    79 
    80     // N.B. This may need revisiting when the UI is added
    81     static QStringList GetDeviceList(void)
    82     {
    83         QStringList results;
    84         cec_device_type_list list;
    85         list.Clear();
    86         list.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
    87         ICECAdapter *adapter = LibCecInit("MythTV", list);
    88         if (!adapter)
    89             return results;
    90         cec_adapter *devices = new cec_adapter[MAX_CEC_DEVICES];
    91         uint8_t num_devices = adapter->FindAdapters(devices, MAX_CEC_DEVICES, NULL);
    92         if (num_devices < 1)
    93             return results;
    94         for (uint8_t i = 0; i < num_devices; i++)
    95             results << QString::fromAscii(devices[i].comm);
    96         UnloadLibCec(adapter);
    97         return results;
     59#if CEC_LIB_VERSION_MAJOR < 2
     60        // libcec1 has this as a POD struct, with no
     61        // automatic initialisation.
     62        // And no .Clear() method...
     63        memset(&callbacks, 0, sizeof(callbacks));
     64#endif
    9865    }
    9966
    10067    bool Open(void)
    10168    {
    10269        // get settings
    103         // N.B. these do not currently work as there is no UI
    104         defaultDevice     = gCoreContext->GetSetting(LIBCEC_DEVICE, "auto").trimmed();
    105         QString hdmi_port = gCoreContext->GetSetting(LIBCEC_PORT, "auto");
    106         QString device_id = gCoreContext->GetSetting(LIBCEC_DEVICEID, "auto");
     70        // N.B. these need to be set manually since there is no UI
     71        QString defaultDevice   = gCoreContext->GetSetting(LIBCEC_DEVICE, "auto").trimmed();
     72        // Note - if libcec supports automatic detection via EDID then
     73        // these settings are not used
     74        // The logical address of the HDMI device Myth is connected to
     75        QString base_dev        = gCoreContext->GetSetting(LIBCEC_BASE, "auto").trimmed();
     76        // The number of the HDMI port Myth is connected to
     77        QString hdmi_port       = gCoreContext->GetSetting(LIBCEC_PORT, "auto").trimmed();
     78
    10779        powerOffTVAllowed = (bool)gCoreContext->GetNumSetting(POWEROFFTV_ALLOWED, 1);
    10880        powerOffTVOnExit  = (bool)gCoreContext->GetNumSetting(POWEROFFTV_ONEXIT, 1);
    10981        powerOnTVAllowed  = (bool)gCoreContext->GetNumSetting(POWERONTV_ALLOWED, 1);
    11082        powerOnTVOnStart  = (bool)gCoreContext->GetNumSetting(POWERONTV_ONSTART, 1);
    11183
    112         defaultHDMIPort = 1;
    113         if ("auto" != hdmi_port)
     84        // create adapter interface
     85        libcec_configuration configuration;
     86#if CEC_LIB_VERSION_MAJOR < 2
     87        // libcec1 has this as a POD struct, with no
     88        // automatic initialisation
     89        configuration.Clear();
     90#endif
     91        strcpy(configuration.strDeviceName, "MythTV");
     92        configuration.deviceTypes.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
     93
     94        if ("auto" != base_dev)
    11495        {
    115             defaultHDMIPort = hdmi_port.toInt();
    116             if (defaultHDMIPort < 1 || defaultHDMIPort > 4)
    117                 defaultHDMIPort = 1;
     96            int base = base_dev.toInt();
     97            if (base >= 0 && base < CECDEVICE_BROADCAST) {
     98                configuration.baseDevice = (cec_logical_address)base;
     99            }
    118100        }
    119         defaultHDMIPort = defaultHDMIPort << 12;
    120101
    121         defaultDeviceID = CECDEVICE_PLAYBACKDEVICE1;
    122         if ("auto" != device_id)
     102        if ("auto" != hdmi_port)
    123103        {
    124             int id = device_id.toInt();
    125             if (id < 1 || id > 3)
    126                 id = 1;
    127             defaultDeviceID = (id == 1) ? CECDEVICE_PLAYBACKDEVICE1 :
    128                              ((id == 2) ? CECDEVICE_PLAYBACKDEVICE2 :
    129                                           CECDEVICE_PLAYBACKDEVICE3);
     104            int defaultHDMIPort = hdmi_port.toInt();
     105            if (defaultHDMIPort >= CEC_MIN_HDMI_PORTNUMBER && defaultHDMIPort <= CEC_MAX_HDMI_PORTNUMBER) {
     106                configuration.iHDMIPort = defaultHDMIPort;
     107            }
    130108        }
    131109
    132         // create adapter interface
    133         cec_device_type_list list;
    134         list.Clear();
    135         list.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
    136         adapter = LibCecInit("MythTV", list);
     110        // Set up the callbacks
     111        callbacks.CBCecLogMessage = &CECLogMessageCallback;
     112        callbacks.CBCecKeyPress   = &CECKeyPressCallback;
     113        callbacks.CBCecCommand    = &CECCommandCallback;
     114#if CEC_LIB_VERSION_MAJOR >= 2
     115        callbacks.CBCecAlert      = &CECAlertCallback;
     116        callbacks.CBCecSourceActivated = &CECSourceActivatedCallback;
     117#endif
     118        configuration.callbackParam = this;
     119        configuration.callbacks = &callbacks;
     120
     121        // and initialise
     122        adapter = LibCecInitialise(&configuration);
    137123
    138124        if (!adapter)
    139125        {
     
    141127            return false;
    142128        }
    143129
    144         if (adapter->GetMinLibVersion() > MIN_LIBCEC_VERSION)
    145         {
    146             LOG(VB_GENERAL, LOG_ERR, LOC +
    147                 QString("The installed libCEC supports version %1 and above. "
    148                         "This version of MythTV only supports version %2.")
    149                 .arg(adapter->GetMinLibVersion()).arg(MIN_LIBCEC_VERSION));
    150             return false;
    151         }
    152 
    153130        // find adapters
    154131        cec_adapter *devices = new cec_adapter[MAX_CEC_DEVICES];
    155132        uint8_t num_devices = adapter->FindAdapters(devices, MAX_CEC_DEVICES, NULL);
     
    182159        LOG(VB_GENERAL, LOG_INFO, LOC + QString("Trying to open device %1 (%2).")
    183160            .arg(path).arg(comm));
    184161
    185         // set the callbacks
    186         // don't error check - versions < 1.6.3 always return
    187         // false. And newer versions always return true, so
    188         // there's not much point anyway
    189         adapter->EnableCallbacks(this, &callbacks);
    190 
    191162        if (!adapter->Open(devices[devicenum].comm))
    192163        {
    193164            LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to open device.");
     
    196167
    197168        LOG(VB_GENERAL, LOG_INFO, LOC + "Opened CEC device.");
    198169
    199         // get the vendor ID (for non-standard implementations)
    200         adapter->GetDeviceVendorId(CECDEVICE_TV);
    201 
    202         // set the physical address
    203         adapter->SetPhysicalAddress(defaultHDMIPort);
    204 
    205         // set the logical address
    206         adapter->SetLogicalAddress(defaultDeviceID);
    207 
    208170        // all good to go
    209171        valid = true;
    210172
     
    219181        return true;
    220182    }
    221183
    222 
    223184    void Close(void)
    224185    {
    225186        if (adapter)
     
    253214        return 1;
    254215    }
    255216
     217    // NOTE - libcec2 changes the callbacks
     218    // to be pass-by-value.
     219    // For simplicity, this function remains as pass-by-ref
    256220    int HandleCommand(const cec_command &command)
    257221    {
    258222        if (!adapter || !valid)
     
    261225        LOG(VB_GENERAL, LOG_DEBUG, LOC +
    262226            QString("Command %1 from '%2' (%3) - destination '%4' (%5)")
    263227            .arg(command.opcode)
    264             .arg(addressToString(command.initiator, true))
     228            .arg(adapter->ToString(command.initiator))
    265229            .arg(command.initiator)
    266             .arg(addressToString(command.destination, false))
     230            .arg(adapter->ToString(command.destination))
    267231            .arg(command.destination));
    268232
    269233        switch (command.opcode)
     
    606570        return 1;
    607571    }
    608572
     573#if CEC_LIB_VERSION_MAJOR >= 2
     574    int HandleAlert(const libcec_alert alert, const libcec_parameter &data)
     575    {
     576        // These aren't handled yet
     577        // Note that we *DON'T* want to just show these
     578        // to the user in a popup, because some (eg prompting about firmware
     579        // upgrades) aren't appropriate.
     580        // Ideally we'd try to handle this, eg by reopening the adapter
     581        // in a separate thread if it lost the connection....
     582
     583        QString param;
     584        switch (data.paramType)
     585        {
     586            case CEC_PARAMETER_TYPE_STRING:
     587                param = QString(": %1").arg((char*)data.paramData);
     588                break;
     589            case CEC_PARAMETER_TYPE_UNKOWN: /* libcec typo */
     590            default:
     591                if (data.paramData != NULL)
     592                {
     593                    param = QString(": UNKNOWN param has type %1").arg(data.paramType);
     594                }
     595                break;
     596        }
     597
     598        // There is no ToString method for libcec_alert...
     599        // Plus libcec adds new values in minor releases (eg 2.1.1)
     600        // but doesn't provide a #define for the last digit...
     601        // Besides, it makes sense to do this, since we could be compiling
     602        // against an older version than we're running against
     603#if CEC_LIB_VERSION_MAJOR == 2 && CEC_LIB_VERSION_MINOR < 1
     604// since 2.0.4
     605#define CEC_ALERT_PHYSICAL_ADDRESS_ERROR        4
     606#endif
     607#if CEC_LIB_VERSION_MAJOR == 2 && CEC_LIB_VERSION_MINOR < 2
     608// since 2.1.1
     609#define CEC_ALERT_TV_POLL_FAILED                5
     610#endif
     611        switch (alert)
     612        {
     613            case CEC_ALERT_SERVICE_DEVICE:
     614                LOG(VB_GENERAL, LOG_INFO, LOC + QString("CEC device service message") + param);
     615                break;
     616            case CEC_ALERT_CONNECTION_LOST:
     617                LOG(VB_GENERAL, LOG_ERR, LOC + QString("CEC device connection list") + param);
     618                break;
     619            case CEC_ALERT_PERMISSION_ERROR:
     620            case CEC_ALERT_PORT_BUSY:
     621                /* Don't log due to possible false positives on the initial
     622                 * open. libcec will log via the logging callback anyway
     623                 */
     624                break;
     625            case CEC_ALERT_PHYSICAL_ADDRESS_ERROR:
     626                LOG(VB_GENERAL, LOG_ERR, LOC + QString("CEC physical address error") + param);
     627                break;
     628            case CEC_ALERT_TV_POLL_FAILED:
     629                LOG(VB_GENERAL, LOG_WARNING, LOC + QString("CEC device can't poll TV") + param);
     630                break;
     631            default:
     632                LOG(VB_GENERAL, LOG_WARNING, LOC + QString("UNKNOWN CEC device alert %1").arg(alert) + param);
     633                break;
     634        }
     635
     636        return 1;
     637    }
     638
     639    void HandleSourceActivated(const cec_logical_address address, const uint8_t activated)
     640    {
     641        if (!adapter || !valid)
     642            return;
     643
     644        LOG(VB_GENERAL, LOG_INFO, LOC + QString("Source %1 %2").arg(adapter->ToString(address)).arg(activated ? "Activated" : "Deactivated"));
     645
     646        if (activated)
     647            GetMythUI()->ResetScreensaver();
     648    }
     649#endif
     650
    609651    void HandleActions(void)
    610652    {
    611653        if (!adapter || !valid)
     
    631673        // HDMI input
    632674        if (switchInput && switchInputAllowed)
    633675        {
    634             if (adapter->SetActiveView())
     676            if (adapter->SetActiveSource())
    635677                LOG(VB_GENERAL, LOG_INFO, LOC + "Asked TV to switch to this input.");
    636678            else
    637679                LOG(VB_GENERAL, LOG_ERR,  LOC + "Failed to switch to this input.");
     
    644686
    645687    ICECAdapter *adapter;
    646688    ICECCallbacks callbacks;
    647     QString      defaultDevice;
    648     int          defaultHDMIPort;
    649     cec_logical_address defaultDeviceID;
    650689    bool         valid;
    651690    bool         powerOffTV;
    652691    bool         powerOffTVAllowed;
     
    658697    bool         switchInputAllowed;
    659698};
    660699
    661 QStringList CECAdapter::GetDeviceList(void)
    662 {
    663     QMutexLocker lock(gLock);
    664     return CECAdapterPriv::GetDeviceList();
    665 }
    666 
    667700CECAdapter::CECAdapter() : MThread("CECAdapter"), m_priv(new CECAdapterPriv)
    668701{
    669702    QMutexLocker lock(gLock);
     
    732 static int CECLogMessageCallback(void *adapter, const cec_log_message &message)
     765static int CECLogMessageCallback(void *adapter, const cec_log_message CEC_CALLBACK_PARAM_TYPE message)
    733766{
    734767    return ((CECAdapterPriv*)adapter)->LogMessage(message);
    735768}
    736769
    737 static int CECKeyPressCallback(void *adapter, const cec_keypress &keypress)
     770static int CECKeyPressCallback(void *adapter, const cec_keypress CEC_CALLBACK_PARAM_TYPE keypress)
    738771{
    739772    return ((CECAdapterPriv*)adapter)->HandleKeyPress(keypress);
    740773}
    741774
    742 static int CECCommandCallback(void *adapter, const cec_command &command)
     775static int CECCommandCallback(void *adapter, const cec_command CEC_CALLBACK_PARAM_TYPE command)
    743776{
    744777    return ((CECAdapterPriv*)adapter)->HandleCommand(command);
    745778}
    746779
     780#if CEC_LIB_VERSION_MAJOR >= 2
     781static int CECAlertCallback(void *adapter, const libcec_alert alert, const libcec_parameter CEC_CALLBACK_PARAM_TYPE data)
     782{
     783    return ((CECAdapterPriv*)adapter)->HandleAlert(alert, data);
     784}
     785
     786static void CECSourceActivatedCallback(void *adapter, const cec_logical_address address, const uint8_t activated)
     787{
     788    ((CECAdapterPriv*)adapter)->HandleSourceActivated(address, activated);
     789}
     790#endif
  • b/mythtv/libs/libmythui/cecadapter.h

    diff -u b/mythtv/libs/libmythui/cecadapter.h b/mythtv/libs/libmythui/cecadapter.h
     
    77
    88#define LIBCEC_ENABLED     QString("libCECEnabled")
    99#define LIBCEC_DEVICE      QString("libCECDevice")
     10#define LIBCEC_BASE        QString("libCECBase")
    1011#define LIBCEC_PORT        QString("libCECPort")
    11 #define LIBCEC_DEVICEID    QString("libCECDeviceID")
    1212#define POWEROFFTV_ALLOWED QString("PowerOffTVAllowed")
    1313#define POWEROFFTV_ONEXIT  QString("PowerOffTVOnExit")
    1414#define POWERONTV_ALLOWED  QString("PowerOnTVAllowed")
     
    2121  Q_OBJECT
    2222
    2323  public:
    24     static QStringList GetDeviceList(void);
    25 
    2624    CECAdapter();
    2725    virtual ~CECAdapter();
    2826    bool IsValid();
  • mythtv/configure

    only in patch2:
    unchanged:
    a b int main(void) { 
    54775477    if (CEC_LIB_VERSION_MAJOR < 1 || (CEC_LIB_VERSION_MAJOR == 1 &&
    54785478                                      CEC_LIB_VERSION_MINOR < 5))
    54795479        return 0;
    5480     return (long) LibCecInit;
     5480    return 1;
    54815481}
    54825482EOF
    54835483fi