MythTV  master
cecadapter.cpp
Go to the documentation of this file.
1 // Qt
2 #include <QApplication>
3 #include <QKeyEvent>
4 #include <QString>
5 
6 // MythTV
7 #include "mythcorecontext.h"
8 #include "mythlogging.h"
9 #include "mythevent.h"
10 #include "mythuihelper.h"
11 #include "mythmainwindow.h"
12 
13 #include "cecadapter.h"
14 #include <vector>
15 
16 #define MAX_CEC_DEVICES 10
17 #define LOC QString("CECAdapter: ")
18 
19 #include <libcec/cec.h>
20 #include <iostream>
21 using namespace CEC;
22 using namespace std;
23 #include <libcec/cecloader.h>
24 
25 QMutex* CECAdapter::gLock = new QMutex(QMutex::Recursive);
26 QMutex* CECAdapter::gHandleActionsLock = new QMutex();
27 QWaitCondition* CECAdapter::gActionsReady = new QWaitCondition();
28 
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 #if CEC_LIB_VERSION_MAJOR <= 3
37 // libcec2 and 3 callback parameters are pass-by-value
38 #define CEC_CALLBACK_PARAM_TYPE
39 #endif
40 #endif
41 
42 // The libCEC callback functions
43 #if CEC_LIB_VERSION_MAJOR <= 3
44 static int CECLogMessageCallback(void *adapter, const cec_log_message CEC_CALLBACK_PARAM_TYPE message);
45 static int CECKeyPressCallback(void *adapter, const cec_keypress CEC_CALLBACK_PARAM_TYPE keypress);
46 static int CECCommandCallback(void *adapter, const cec_command CEC_CALLBACK_PARAM_TYPE command);
47 #endif
48 #if CEC_LIB_VERSION_MAJOR >= 4
49 static void CECLogMessageCallback(void *adapter, const cec_log_message* message);
50 static void CECKeyPressCallback(void *adapter, const cec_keypress* keypress);
51 static void CECCommandCallback(void *adapter, const cec_command* command);
52 #endif
53 
54 #if CEC_LIB_VERSION_MAJOR >= 2
55 #if CEC_LIB_VERSION_MAJOR <= 3
56 static int CECAlertCallback(void *adapter, const libcec_alert alert, const libcec_parameter CEC_CALLBACK_PARAM_TYPE data);
57 #endif
58 #if CEC_LIB_VERSION_MAJOR >= 4
59 static void CECAlertCallback(void *adapter, libcec_alert alert, libcec_parameter data);
60 #endif
61 static void CECSourceActivatedCallback(void *adapter, cec_logical_address address, uint8_t activated);
62 #endif
63 
65 {
66  public:
67 #if CEC_LIB_VERSION_MAJOR < 2
69  {
70  // libcec1 has this as a POD struct, with no
71  // automatic initialisation.
72  // And no .Clear() method...
73  memset(&m_callbacks, 0, sizeof(m_callbacks));
74  }
75 #else
76  CECAdapterPriv() = default;
77 #endif
78 
79  bool Open(void)
80  {
81  // get settings
82  // N.B. these need to be set manually since there is no UI
83  QString defaultDevice = gCoreContext->GetSetting(LIBCEC_DEVICE, "auto").trimmed();
84  // Note - if libcec supports automatic detection via EDID then
85  // these settings are not used
86  // The logical address of the HDMI device Myth is connected to
87  QString base_dev = gCoreContext->GetSetting(LIBCEC_BASE, "auto").trimmed();
88  // The number of the HDMI port Myth is connected to
89  QString hdmi_port = gCoreContext->GetSetting(LIBCEC_PORT, "auto").trimmed();
90 
91  m_powerOffTVAllowed = (bool)gCoreContext->GetNumSetting(POWEROFFTV_ALLOWED, 1);
92  m_powerOffTVOnExit = (bool)gCoreContext->GetNumSetting(POWEROFFTV_ONEXIT, 1);
93  m_powerOnTVAllowed = (bool)gCoreContext->GetNumSetting(POWERONTV_ALLOWED, 1);
94  m_powerOnTVOnStart = (bool)gCoreContext->GetNumSetting(POWERONTV_ONSTART, 1);
95 
96  // create adapter interface
97  libcec_configuration configuration;
98 #if CEC_LIB_VERSION_MAJOR < 2
99  // libcec1 has this as a POD struct, with no
100  // automatic initialisation
101  configuration.Clear();
102 #endif
103  strcpy(configuration.strDeviceName, "MythTV");
104  configuration.deviceTypes.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
105 
106  if ("auto" != base_dev)
107  {
108  int base = base_dev.toInt();
109  if (base >= 0 && base < CECDEVICE_BROADCAST) {
110  configuration.baseDevice = (cec_logical_address)base;
111  }
112  }
113  if ("auto" != hdmi_port)
114  {
115  int defaultHDMIPort = hdmi_port.toInt();
116  if (defaultHDMIPort >= CEC_MIN_HDMI_PORTNUMBER && defaultHDMIPort <= CEC_MAX_HDMI_PORTNUMBER) {
117  configuration.iHDMIPort = defaultHDMIPort;
118  }
119  }
120 
121  // Set up the callbacks
122 #if CEC_LIB_VERSION_MAJOR <= 3
123  m_callbacks.CBCecLogMessage = &CECLogMessageCallback;
124  m_callbacks.CBCecKeyPress = &CECKeyPressCallback;
125  m_callbacks.CBCecCommand = &CECCommandCallback;
126 #endif
127 #if CEC_LIB_VERSION_MAJOR >= 4
128  m_callbacks.logMessage = &CECLogMessageCallback;
129  m_callbacks.keyPress = &CECKeyPressCallback;
130  m_callbacks.commandReceived = &CECCommandCallback;
131 #endif
132 #if CEC_LIB_VERSION_MAJOR >= 2 && CEC_LIB_VERSION_MAJOR <= 3
133  m_callbacks.CBCecAlert = &CECAlertCallback;
134  m_callbacks.CBCecSourceActivated = &CECSourceActivatedCallback;
135 #endif
136 #if CEC_LIB_VERSION_MAJOR >= 4
137  m_callbacks.alert = &CECAlertCallback;
138  m_callbacks.sourceActivated = &CECSourceActivatedCallback;
139 #endif
140  configuration.callbackParam = this;
141  configuration.callbacks = &m_callbacks;
142 
143  // and initialise
144  m_adapter = LibCecInitialise(&configuration);
145 
146  if (!m_adapter)
147  {
148  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to load libcec.");
149  return false;
150  }
151 
152  // initialise the host on which libCEC is running
153  m_adapter->InitVideoStandalone();
154 
155  // find adapters
156 #if CEC_LIB_VERSION_MAJOR >= 4
157  auto *devices = new cec_adapter_descriptor[MAX_CEC_DEVICES];
158  uint8_t num_devices = m_adapter->DetectAdapters(devices, MAX_CEC_DEVICES, nullptr, true);
159 #else
160  cec_adapter *devices = new cec_adapter[MAX_CEC_DEVICES];
161  uint8_t num_devices = m_adapter->FindAdapters(devices, MAX_CEC_DEVICES, nullptr);
162 #endif
163  if (num_devices < 1)
164  {
165  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find any CEC devices.");
166  return false;
167  }
168 
169  // find required device and debug
170  int devicenum = 0;
171  bool find = defaultDevice != "auto";
172 
173  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Found %1 CEC devices(s).")
174  .arg(num_devices));
175  for (uint8_t i = 0; i < num_devices; i++)
176  {
177 #if CEC_LIB_VERSION_MAJOR >= 4
178  QString comm = QString::fromLatin1(devices[i].strComName);
179  QString path = QString::fromLatin1(devices[i].strComPath);
180 #else
181  QString comm = QString::fromLatin1(devices[i].comm);
182  QString path = QString::fromLatin1(devices[i].path);
183 #endif
184  bool match = find ? (comm == defaultDevice) : (i == 0);
185  devicenum = match ? i : devicenum;
186  LOG(VB_GENERAL, LOG_INFO, LOC +
187  QString("Device %1: path '%2' com port '%3' %4").arg(i + 1)
188  .arg(path).arg(comm)
189  .arg(match ? "SELECTED" : ""));
190  }
191 
192  // open adapter
193 #if CEC_LIB_VERSION_MAJOR >= 4
194  QString comm = QString::fromLatin1(devices[devicenum].strComName);
195  QString path = QString::fromLatin1(devices[devicenum].strComPath);
196 #else
197  QString comm = QString::fromLatin1(devices[devicenum].comm);
198  QString path = QString::fromLatin1(devices[devicenum].path);
199 #endif
200  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Trying to open device %1 (%2).")
201  .arg(path).arg(comm));
202 
203 #if CEC_LIB_VERSION_MAJOR >= 4
204  if (!m_adapter->Open(devices[devicenum].strComName))
205 #else
206  if (!m_adapter->Open(devices[devicenum].comm))
207 #endif
208  {
209  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to open device.");
210  return false;
211  }
212 
213  LOG(VB_GENERAL, LOG_INFO, LOC + "Opened CEC device.");
214 
215  // turn on tv (if configured)
216  m_powerOnTV = m_powerOnTVOnStart;
217 
218  // switch input (if configured)
219  m_switchInput = true;
220 
221  // all good to go
222  m_valid = true;
223 
224  return true;
225  }
226 
227  void Close(void)
228  {
229  if (m_adapter)
230  {
231  // turn off tv (if configured)
232  m_powerOffTV = m_powerOffTVOnExit;
233  HandleActions();
234 
235  // delete adapter
236  m_adapter->Close();
237  UnloadLibCec(m_adapter);
238 
239  LOG(VB_GENERAL, LOG_INFO, LOC + "Closing down CEC.");
240  }
241  m_valid = false;
242  m_adapter = nullptr;
243  }
244 
245  static int LogMessage(const cec_log_message &message)
246  {
247  QString msg(message.message);
248  LogLevel_t lvl = LOG_UNKNOWN;
249  switch (message.level)
250  {
251  case CEC_LOG_ERROR: lvl = LOG_ERR; break;
252  case CEC_LOG_WARNING: lvl = LOG_WARNING; break;
253  case CEC_LOG_NOTICE: lvl = LOG_INFO; break;
254  case CEC_LOG_DEBUG: lvl = LOG_DEBUG; break;
255  default: break;
256  }
257  LOG(VB_GENERAL, lvl, LOC + QString("%1").arg(msg));
258  return 1;
259  }
260 
261  static void LogMessage(const cec_log_message* message)
262  {
263  QString msg(message->message);
264  LogLevel_t lvl = LOG_UNKNOWN;
265  switch (message->level)
266  {
267  case CEC_LOG_ERROR: lvl = LOG_ERR; break;
268  case CEC_LOG_WARNING: lvl = LOG_WARNING; break;
269  case CEC_LOG_NOTICE: lvl = LOG_INFO; break;
270  case CEC_LOG_DEBUG: lvl = LOG_DEBUG; break;
271  default: break;
272  }
273  LOG(VB_GENERAL, lvl, LOC + QString("%1").arg(msg));
274  }
275 
276  // NOTE - libcec2 changes the callbacks
277  // to be pass-by-value.
278  // For simplicity, this function remains as pass-by-ref
279  int HandleCommand(const cec_command &command)
280  {
281  if (!m_adapter || !m_valid)
282  return 0;
283 
284  LOG(VB_GENERAL, LOG_DEBUG, LOC +
285  QString("Command %1 from '%2' (%3) - destination '%4' (%5)")
286  .arg(command.opcode)
287  .arg(m_adapter->ToString(command.initiator))
288  .arg(command.initiator)
289  .arg(m_adapter->ToString(command.destination))
290  .arg(command.destination));
291 
292  switch (command.opcode)
293  {
294  case CEC_OPCODE_MENU_REQUEST:
295  cec_keypress key;
296  key.keycode = CEC_USER_CONTROL_CODE_ROOT_MENU;
297  key.duration = 5;
298  HandleKeyPress(key);
299  // SetMenuState could be used to disable the TV menu here
300  // That may be a user-unfriendly thing to do
301  // So they have to see both the TV menu and the MythTV menu
302  break;
303 
304  default:
305  break;
306  }
307  gCoreContext->SendSystemEvent(QString("CEC_COMMAND_RECEIVED COMMAND %1")
308  .arg(command.opcode));
309 
310  return 1;
311  }
312 
313  void HandleCommand(const cec_command* command)
314  {
315  if (!m_adapter || !m_valid)
316  return;
317 
318  LOG(VB_GENERAL, LOG_DEBUG, LOC +
319  QString("Command %1 from '%2' (%3) - destination '%4' (%5)")
320  .arg(command->opcode)
321  .arg(m_adapter->ToString(command->initiator))
322  .arg(command->initiator)
323  .arg(m_adapter->ToString(command->destination))
324  .arg(command->destination));
325 
326  switch (command->opcode)
327  {
328  // TODO
329  default:
330  break;
331  }
332  gCoreContext->SendSystemEvent(QString("CEC_COMMAND_RECEIVED COMMAND %1")
333  .arg(command->opcode));
334  }
335 
336  int HandleKeyPress(const cec_keypress &key)
337  {
338  if (!m_adapter || !m_valid)
339  return 0;
340 
341  // Ignore key down events and wait for the key 'up'
342  if (key.duration < 1)
343  return 1;
344 
345  QString code;
346  int action = 0;
347  Qt::KeyboardModifier modifier = Qt::NoModifier;
348  switch (key.keycode)
349  {
350  case CEC_USER_CONTROL_CODE_NUMBER0:
351  action = Qt::Key_0;
352  code = "0";
353  break;
354  case CEC_USER_CONTROL_CODE_NUMBER1:
355  action = Qt::Key_1;
356  code = "1";
357  break;
358  case CEC_USER_CONTROL_CODE_NUMBER2:
359  action = Qt::Key_2;
360  code = "2";
361  break;
362  case CEC_USER_CONTROL_CODE_NUMBER3:
363  action = Qt::Key_3;
364  code = "3";
365  break;
366  case CEC_USER_CONTROL_CODE_NUMBER4:
367  action = Qt::Key_4;
368  code = "4";
369  break;
370  case CEC_USER_CONTROL_CODE_NUMBER5:
371  action = Qt::Key_5;
372  code = "5";
373  break;
374  case CEC_USER_CONTROL_CODE_NUMBER6:
375  action = Qt::Key_6;
376  code = "6";
377  break;
378  case CEC_USER_CONTROL_CODE_NUMBER7:
379  action = Qt::Key_7;
380  code = "7";
381  break;
382  case CEC_USER_CONTROL_CODE_NUMBER8:
383  action = Qt::Key_8;
384  code = "8";
385  break;
386  case CEC_USER_CONTROL_CODE_NUMBER9:
387  action = Qt::Key_9;
388  code = "9";
389  break;
390  case CEC_USER_CONTROL_CODE_SELECT:
391  action = Qt::Key_Select;
392  code = "SELECT";
393  break;
394  case CEC_USER_CONTROL_CODE_ENTER:
395  action = Qt::Key_Enter;
396  code = "ENTER";
397  break;
398  case CEC_USER_CONTROL_CODE_UP:
399  action = Qt::Key_Up;
400  code = "UP";
401  break;
402  case CEC_USER_CONTROL_CODE_DOWN:
403  action = Qt::Key_Down;
404  code = "DOWN";
405  break;
406  case CEC_USER_CONTROL_CODE_LEFT:
407  action = Qt::Key_Left;
408  code = "LEFT";
409  break;
410  case CEC_USER_CONTROL_CODE_LEFT_UP:
411  action = Qt::Key_Left;
412  code = "LEFT_UP";
413  break;
414  case CEC_USER_CONTROL_CODE_LEFT_DOWN:
415  action = Qt::Key_Left;
416  code = "LEFT_DOWN";
417  break;
418  case CEC_USER_CONTROL_CODE_RIGHT:
419  action = Qt::Key_Right;
420  code = "RIGHT";
421  break;
422  case CEC_USER_CONTROL_CODE_RIGHT_UP:
423  action = Qt::Key_Right;
424  code = "RIGHT_UP";
425  break;
426  case CEC_USER_CONTROL_CODE_RIGHT_DOWN:
427  action = Qt::Key_Right;
428  code = "RIGHT_DOWN";
429  break;
430  case CEC_USER_CONTROL_CODE_ROOT_MENU:
431  action = Qt::Key_M;
432  code = "ROOT_MENU";
433  break;
434  case CEC_USER_CONTROL_CODE_AN_RETURN: //return (Samsung) (0x91)
435  case CEC_USER_CONTROL_CODE_EXIT:
436  action = Qt::Key_Escape;
437  code = "EXIT";
438  break;
439  case CEC_USER_CONTROL_CODE_PREVIOUS_CHANNEL:
440  action = Qt::Key_H;
441  code = "PREVIOUS_CHANNEL";
442  break;
443  case CEC_USER_CONTROL_CODE_SOUND_SELECT:
444  action = Qt::Key_Plus;
445  code = "SOUND_SELECT";
446  break;
447  case CEC_USER_CONTROL_CODE_VOLUME_UP:
448  action = Qt::Key_VolumeUp;
449  code = "VOLUME_UP";
450  break;
451  case CEC_USER_CONTROL_CODE_VOLUME_DOWN:
452  action = Qt::Key_VolumeDown;
453  code = "VOLUME_DOWN";
454  break;
455  case CEC_USER_CONTROL_CODE_MUTE:
456  action = Qt::Key_VolumeMute;
457  code = "MUTE";
458  break;
459  case CEC_USER_CONTROL_CODE_PLAY:
460  action = Qt::Key_P;
461  code = "PLAY";
462  // Play set to control-p to differentiate from pause
463  modifier = Qt::ControlModifier;
464  break;
465  case CEC_USER_CONTROL_CODE_PAUSE:
466  action = Qt::Key_P;
467  code = "PAUSE";
468  break;
469  case CEC_USER_CONTROL_CODE_STOP:
470  action = Qt::Key_Stop;
471  code = "STOP";
472  break;
473  case CEC_USER_CONTROL_CODE_RECORD:
474  action = Qt::Key_R;
475  code = "RECORD";
476  break;
477  case CEC_USER_CONTROL_CODE_CLEAR:
478  action = Qt::Key_Clear;
479  code = "CLEAR";
480  break;
481  case CEC_USER_CONTROL_CODE_DISPLAY_INFORMATION:
482  action = Qt::Key_I;
483  code = "DISPLAY_INFORMATION";
484  break;
485  case CEC_USER_CONTROL_CODE_PAGE_UP:
486  action = Qt::Key_PageUp;
487  code = "PAGE_UP";
488  break;
489  case CEC_USER_CONTROL_CODE_PAGE_DOWN:
490  action = Qt::Key_PageDown;
491  code = "PAGE_DOWN";
492  break;
493  case CEC_USER_CONTROL_CODE_EJECT:
494  action = Qt::Key_Eject;
495  code = "EJECT";
496  break;
497  case CEC_USER_CONTROL_CODE_FORWARD:
498  action = Qt::Key_Forward;
499  code = "FORWARD";
500  break;
501  case CEC_USER_CONTROL_CODE_BACKWARD:
502  action = Qt::Key_Back;
503  code = "BACKWARD";
504  break;
505  case CEC_USER_CONTROL_CODE_F1_BLUE:
506  action = Qt::Key_F5; // NB F1 is help and we normally map blue to F5
507  code = "F1_BLUE";
508  break;
509  case CEC_USER_CONTROL_CODE_F2_RED:
510  action = Qt::Key_F2;
511  code = "F2_RED";
512  break;
513  case CEC_USER_CONTROL_CODE_F3_GREEN:
514  action = Qt::Key_F3;
515  code = "F3_GREEN";
516  break;
517  case CEC_USER_CONTROL_CODE_F4_YELLOW:
518  action = Qt::Key_F4;
519  code = "F4_YELLOW";
520  break;
521  case CEC_USER_CONTROL_CODE_SETUP_MENU:
522  action = Qt::Key_M; // Duplicate of Root Menu
523  code = "SETUP_MENU";
524  break;
525  case CEC_USER_CONTROL_CODE_CONTENTS_MENU:
526  action = Qt::Key_M; // Duplicate of Root Menu
527  code = "CONTENTS_MENU";
528  break;
529  case CEC_USER_CONTROL_CODE_FAVORITE_MENU:
530  action = Qt::Key_M; // Duplicate of Root Menu
531  code = "FAVORITE_MENU";
532  break;
533  case CEC_USER_CONTROL_CODE_DOT:
534  action = Qt::Key_Period;
535  code = "DOT";
536  break;
537  case CEC_USER_CONTROL_CODE_NEXT_FAVORITE:
538  action = Qt::Key_Slash;
539  code = "NEXT_FAVORITE";
540  break;
541  case CEC_USER_CONTROL_CODE_INPUT_SELECT:
542  action = Qt::Key_C;
543  code = "INPUT_SELECT";
544  break;
545  case CEC_USER_CONTROL_CODE_HELP:
546  action = Qt::Key_F1;
547  code = "HELP";
548  break;
549  case CEC_USER_CONTROL_CODE_STOP_RECORD:
550  action = Qt::Key_R; // Duplicate of Record
551  code = "STOP_RECORD";
552  break;
553  case CEC_USER_CONTROL_CODE_SUB_PICTURE:
554  action = Qt::Key_V;
555  code = "SUB_PICTURE";
556  break;
557  case CEC_USER_CONTROL_CODE_ELECTRONIC_PROGRAM_GUIDE:
558  action = Qt::Key_S;
559  code = "ELECTRONIC_PROGRAM_GUIDE";
560  break;
561  case CEC_USER_CONTROL_CODE_POWER:
562  action = Qt::Key_PowerOff;
563  code = "POWER";
564  break;
565 
566  // these codes have 'non-standard' Qt key mappings to ensure
567  // each code has a unique key mapping
568  case CEC_USER_CONTROL_CODE_CHANNEL_DOWN:
569  action = Qt::Key_F20; // to differentiate from Up
570  code = "CHANNEL_DOWN";
571  break;
572  case CEC_USER_CONTROL_CODE_CHANNEL_UP:
573  action = Qt::Key_F21; // to differentiate from Down
574  code = "CHANNEL_UP";
575  break;
576  case CEC_USER_CONTROL_CODE_REWIND:
577  action = Qt::Key_F22; // to differentiate from Left
578  code = "REWIND";
579  break;
580  case CEC_USER_CONTROL_CODE_FAST_FORWARD:
581  action = Qt::Key_F23; // to differentiate from Right
582  code = "FAST_FORWARD";
583  break;
584  case CEC_USER_CONTROL_CODE_ANGLE:
585  action = Qt::Key_F24;
586  code = "ANGLE";
587  break;
588  case CEC_USER_CONTROL_CODE_F5:
589  action = Qt::Key_F6; // NB!
590  code = "F5";
591  break;
592 
593  // codes with no obvious MythTV action
594  case CEC_USER_CONTROL_CODE_INITIAL_CONFIGURATION:
595  code = "INITIAL_CONFIGURATION";
596  break;
597  case CEC_USER_CONTROL_CODE_PAUSE_RECORD:
598  code = "PAUSE_RECORD";
599  break;
600  case CEC_USER_CONTROL_CODE_VIDEO_ON_DEMAND:
601  code = "VIDEO_ON_DEMAND";
602  break;
603  case CEC_USER_CONTROL_CODE_TIMER_PROGRAMMING:
604  code = "TIMER_PROGRAMMING";
605  break;
606  case CEC_USER_CONTROL_CODE_UNKNOWN:
607  code = "UNKNOWN";
608  break;
609  case CEC_USER_CONTROL_CODE_DATA:
610  code = "DATA";
611  break;
612 
613  // Functions aren't implemented (similar to macros?)
614  case CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION:
615  code = "POWER_ON_FUNCTION";
616  break;
617  case CEC_USER_CONTROL_CODE_PLAY_FUNCTION:
618  code = "PLAY_FUNCTION";
619  break;
620  case CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION:
621  code = "PAUSE_PLAY_FUNCTION";
622  break;
623  case CEC_USER_CONTROL_CODE_RECORD_FUNCTION:
624  code = "RECORD_FUNCTION";
625  break;
626  case CEC_USER_CONTROL_CODE_PAUSE_RECORD_FUNCTION:
627  code = "PAUSE_RECORD_FUNCTION";
628  break;
629  case CEC_USER_CONTROL_CODE_STOP_FUNCTION:
630  code = "STOP_FUNCTION";
631  break;
632  case CEC_USER_CONTROL_CODE_MUTE_FUNCTION:
633  code = "MUTE_FUNCTION";
634  break;
635  case CEC_USER_CONTROL_CODE_RESTORE_VOLUME_FUNCTION:
636  code = "RESTORE_VOLUME_FUNCTION";
637  break;
638  case CEC_USER_CONTROL_CODE_TUNE_FUNCTION:
639  code = "TUNE_FUNCTION";
640  break;
641  case CEC_USER_CONTROL_CODE_SELECT_MEDIA_FUNCTION:
642  code = "SELECT_MEDIA_FUNCTION";
643  break;
644  case CEC_USER_CONTROL_CODE_SELECT_AV_INPUT_FUNCTION:
645  code = "SELECT_AV_INPUT_FUNCTION";
646  break;
647  case CEC_USER_CONTROL_CODE_SELECT_AUDIO_INPUT_FUNCTION:
648  code = "SELECT_AUDIO_INPUT_FUNCTION";
649  break;
650  case CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION:
651  code = "POWER_TOGGLE_FUNCTION";
652  break;
653  case CEC_USER_CONTROL_CODE_POWER_OFF_FUNCTION:
654  code = "POWER_OFF_FUNCTION";
655  break;
656 
657  default:
658  code = QString("UNKNOWN_FUNCTION_%1").arg(key.keycode);
659  break;
660  }
661 
662  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Keypress %1 %2")
663  .arg(code).arg(0 == action ? "(Not actioned)" : ""));
664 
665  if (0 == action)
666  return 1;
667 
669  auto* ke = new QKeyEvent(QEvent::KeyPress, action, modifier);
670  qApp->postEvent(GetMythMainWindow(), (QEvent*)ke);
671 
672  return 1;
673  }
674 
675  void HandleKeyPress(const cec_keypress* key)
676  {
677  if (!m_adapter || !m_valid)
678  return;
679 
680  // Ignore key down events and wait for the key 'up'
681  if (key->duration < 1)
682  return;
683 
684  QString code;
685  int action = 0;
686  switch (key->keycode)
687  {
688  case CEC_USER_CONTROL_CODE_NUMBER0:
689  action = Qt::Key_0;
690  code = "0";
691  break;
692  case CEC_USER_CONTROL_CODE_NUMBER1:
693  action = Qt::Key_1;
694  code = "1";
695  break;
696  case CEC_USER_CONTROL_CODE_NUMBER2:
697  action = Qt::Key_2;
698  code = "2";
699  break;
700  case CEC_USER_CONTROL_CODE_NUMBER3:
701  action = Qt::Key_3;
702  code = "3";
703  break;
704  case CEC_USER_CONTROL_CODE_NUMBER4:
705  action = Qt::Key_4;
706  code = "4";
707  break;
708  case CEC_USER_CONTROL_CODE_NUMBER5:
709  action = Qt::Key_5;
710  code = "5";
711  break;
712  case CEC_USER_CONTROL_CODE_NUMBER6:
713  action = Qt::Key_6;
714  code = "6";
715  break;
716  case CEC_USER_CONTROL_CODE_NUMBER7:
717  action = Qt::Key_7;
718  code = "7";
719  break;
720  case CEC_USER_CONTROL_CODE_NUMBER8:
721  action = Qt::Key_8;
722  code = "8";
723  break;
724  case CEC_USER_CONTROL_CODE_NUMBER9:
725  action = Qt::Key_9;
726  code = "9";
727  break;
728  case CEC_USER_CONTROL_CODE_SELECT:
729  action = Qt::Key_Select;
730  code = "SELECT";
731  break;
732  case CEC_USER_CONTROL_CODE_ENTER:
733  action = Qt::Key_Enter;
734  code = "ENTER";
735  break;
736  case CEC_USER_CONTROL_CODE_UP:
737  action = Qt::Key_Up;
738  code = "UP";
739  break;
740  case CEC_USER_CONTROL_CODE_DOWN:
741  action = Qt::Key_Down;
742  code = "DOWN";
743  break;
744  case CEC_USER_CONTROL_CODE_LEFT:
745  action = Qt::Key_Left;
746  code = "LEFT";
747  break;
748  case CEC_USER_CONTROL_CODE_LEFT_UP:
749  action = Qt::Key_Left;
750  code = "LEFT_UP";
751  break;
752  case CEC_USER_CONTROL_CODE_LEFT_DOWN:
753  action = Qt::Key_Left;
754  code = "LEFT_DOWN";
755  break;
756  case CEC_USER_CONTROL_CODE_RIGHT:
757  action = Qt::Key_Right;
758  code = "RIGHT";
759  break;
760  case CEC_USER_CONTROL_CODE_RIGHT_UP:
761  action = Qt::Key_Right;
762  code = "RIGHT_UP";
763  break;
764  case CEC_USER_CONTROL_CODE_RIGHT_DOWN:
765  action = Qt::Key_Right;
766  code = "RIGHT_DOWN";
767  break;
768  case CEC_USER_CONTROL_CODE_ROOT_MENU:
769  action = Qt::Key_M;
770  code = "ROOT_MENU";
771  break;
772  case CEC_USER_CONTROL_CODE_AN_RETURN: //return (Samsung) (0x91)
773  case CEC_USER_CONTROL_CODE_EXIT:
774  action = Qt::Key_Escape;
775  code = "EXIT";
776  break;
777  case CEC_USER_CONTROL_CODE_PREVIOUS_CHANNEL:
778  action = Qt::Key_H;
779  code = "PREVIOUS_CHANNEL";
780  break;
781  case CEC_USER_CONTROL_CODE_SOUND_SELECT:
782  action = Qt::Key_Plus;
783  code = "SOUND_SELECT";
784  break;
785  case CEC_USER_CONTROL_CODE_VOLUME_UP:
786  action = Qt::Key_VolumeUp;
787  code = "VOLUME_UP";
788  break;
789  case CEC_USER_CONTROL_CODE_VOLUME_DOWN:
790  action = Qt::Key_VolumeDown;
791  code = "VOLUME_DOWN";
792  break;
793  case CEC_USER_CONTROL_CODE_MUTE:
794  action = Qt::Key_VolumeMute;
795  code = "MUTE";
796  break;
797  case CEC_USER_CONTROL_CODE_PLAY:
798  action = Qt::Key_P;
799  code = "PLAY";
800  break;
801  case CEC_USER_CONTROL_CODE_PAUSE:
802  action = Qt::Key_P; // same as play
803  code = "PAUSE";
804  break;
805  case CEC_USER_CONTROL_CODE_STOP:
806  action = Qt::Key_Stop;
807  code = "STOP";
808  break;
809  case CEC_USER_CONTROL_CODE_RECORD:
810  action = Qt::Key_R;
811  code = "RECORD";
812  break;
813  case CEC_USER_CONTROL_CODE_CLEAR:
814  action = Qt::Key_Clear;
815  code = "CLEAR";
816  break;
817  case CEC_USER_CONTROL_CODE_DISPLAY_INFORMATION:
818  action = Qt::Key_I;
819  code = "DISPLAY_INFORMATION";
820  break;
821  case CEC_USER_CONTROL_CODE_PAGE_UP:
822  action = Qt::Key_PageUp;
823  code = "PAGE_UP";
824  break;
825  case CEC_USER_CONTROL_CODE_PAGE_DOWN:
826  action = Qt::Key_PageDown;
827  code = "PAGE_DOWN";
828  break;
829  case CEC_USER_CONTROL_CODE_EJECT:
830  action = Qt::Key_Eject;
831  code = "EJECT";
832  break;
833  case CEC_USER_CONTROL_CODE_FORWARD:
834  action = Qt::Key_Forward;
835  code = "FORWARD";
836  break;
837  case CEC_USER_CONTROL_CODE_BACKWARD:
838  action = Qt::Key_Back;
839  code = "BACKWARD";
840  break;
841  case CEC_USER_CONTROL_CODE_F1_BLUE:
842  action = Qt::Key_F5; // NB F1 is help and we normally map blue to F5
843  code = "F1_BLUE";
844  break;
845  case CEC_USER_CONTROL_CODE_F2_RED:
846  action = Qt::Key_F2;
847  code = "F2_RED";
848  break;
849  case CEC_USER_CONTROL_CODE_F3_GREEN:
850  action = Qt::Key_F3;
851  code = "F3_GREEN";
852  break;
853  case CEC_USER_CONTROL_CODE_F4_YELLOW:
854  action = Qt::Key_F4;
855  code = "F4_YELLOW";
856  break;
857  case CEC_USER_CONTROL_CODE_SETUP_MENU:
858  action = Qt::Key_M; // Duplicate of Root Menu
859  code = "SETUP_MENU";
860  break;
861  case CEC_USER_CONTROL_CODE_CONTENTS_MENU:
862  action = Qt::Key_M; // Duplicate of Root Menu
863  code = "CONTENTS_MENU";
864  break;
865  case CEC_USER_CONTROL_CODE_FAVORITE_MENU:
866  action = Qt::Key_M; // Duplicate of Root Menu
867  code = "FAVORITE_MENU";
868  break;
869  case CEC_USER_CONTROL_CODE_DOT:
870  action = Qt::Key_Period;
871  code = "DOT";
872  break;
873  case CEC_USER_CONTROL_CODE_NEXT_FAVORITE:
874  action = Qt::Key_Slash;
875  code = "NEXT_FAVORITE";
876  break;
877  case CEC_USER_CONTROL_CODE_INPUT_SELECT:
878  action = Qt::Key_C;
879  code = "INPUT_SELECT";
880  break;
881  case CEC_USER_CONTROL_CODE_HELP:
882  action = Qt::Key_F1;
883  code = "HELP";
884  break;
885  case CEC_USER_CONTROL_CODE_STOP_RECORD:
886  action = Qt::Key_R; // Duplicate of Record
887  code = "STOP_RECORD";
888  break;
889  case CEC_USER_CONTROL_CODE_SUB_PICTURE:
890  action = Qt::Key_V;
891  code = "SUB_PICTURE";
892  break;
893  case CEC_USER_CONTROL_CODE_ELECTRONIC_PROGRAM_GUIDE:
894  action = Qt::Key_S;
895  code = "ELECTRONIC_PROGRAM_GUIDE";
896  break;
897  case CEC_USER_CONTROL_CODE_POWER:
898  action = Qt::Key_PowerOff;
899  code = "POWER";
900  break;
901 
902  // these codes have 'non-standard' Qt key mappings to ensure
903  // each code has a unique key mapping
904  case CEC_USER_CONTROL_CODE_CHANNEL_DOWN:
905  action = Qt::Key_F20; // to differentiate from Up
906  code = "CHANNEL_DOWN";
907  break;
908  case CEC_USER_CONTROL_CODE_CHANNEL_UP:
909  action = Qt::Key_F21; // to differentiate from Down
910  code = "CHANNEL_UP";
911  break;
912  case CEC_USER_CONTROL_CODE_REWIND:
913  action = Qt::Key_F22; // to differentiate from Left
914  code = "REWIND";
915  break;
916  case CEC_USER_CONTROL_CODE_FAST_FORWARD:
917  action = Qt::Key_F23; // to differentiate from Right
918  code = "FAST_FORWARD";
919  break;
920  case CEC_USER_CONTROL_CODE_ANGLE:
921  action = Qt::Key_F24;
922  code = "ANGLE";
923  break;
924  case CEC_USER_CONTROL_CODE_F5:
925  action = Qt::Key_F6; // NB!
926  code = "F5";
927  break;
928 
929  // codes with no obvious MythTV action
930  case CEC_USER_CONTROL_CODE_INITIAL_CONFIGURATION:
931  code = "INITIAL_CONFIGURATION";
932  break;
933  case CEC_USER_CONTROL_CODE_PAUSE_RECORD:
934  code = "PAUSE_RECORD";
935  break;
936  case CEC_USER_CONTROL_CODE_VIDEO_ON_DEMAND:
937  code = "VIDEO_ON_DEMAND";
938  break;
939  case CEC_USER_CONTROL_CODE_TIMER_PROGRAMMING:
940  code = "TIMER_PROGRAMMING";
941  break;
942  case CEC_USER_CONTROL_CODE_UNKNOWN:
943  code = "UNKNOWN";
944  break;
945  case CEC_USER_CONTROL_CODE_DATA:
946  code = "DATA";
947  break;
948 
949  // Functions aren't implemented (similar to macros?)
950  case CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION:
951  code = "POWER_ON_FUNCTION";
952  break;
953  case CEC_USER_CONTROL_CODE_PLAY_FUNCTION:
954  code = "PLAY_FUNCTION";
955  break;
956  case CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION:
957  code = "PAUSE_PLAY_FUNCTION";
958  break;
959  case CEC_USER_CONTROL_CODE_RECORD_FUNCTION:
960  code = "RECORD_FUNCTION";
961  break;
962  case CEC_USER_CONTROL_CODE_PAUSE_RECORD_FUNCTION:
963  code = "PAUSE_RECORD_FUNCTION";
964  break;
965  case CEC_USER_CONTROL_CODE_STOP_FUNCTION:
966  code = "STOP_FUNCTION";
967  break;
968  case CEC_USER_CONTROL_CODE_MUTE_FUNCTION:
969  code = "MUTE_FUNCTION";
970  break;
971  case CEC_USER_CONTROL_CODE_RESTORE_VOLUME_FUNCTION:
972  code = "RESTORE_VOLUME_FUNCTION";
973  break;
974  case CEC_USER_CONTROL_CODE_TUNE_FUNCTION:
975  code = "TUNE_FUNCTION";
976  break;
977  case CEC_USER_CONTROL_CODE_SELECT_MEDIA_FUNCTION:
978  code = "SELECT_MEDIA_FUNCTION";
979  break;
980  case CEC_USER_CONTROL_CODE_SELECT_AV_INPUT_FUNCTION:
981  code = "SELECT_AV_INPUT_FUNCTION";
982  break;
983  case CEC_USER_CONTROL_CODE_SELECT_AUDIO_INPUT_FUNCTION:
984  code = "SELECT_AUDIO_INPUT_FUNCTION";
985  break;
986  case CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION:
987  code = "POWER_TOGGLE_FUNCTION";
988  break;
989  case CEC_USER_CONTROL_CODE_POWER_OFF_FUNCTION:
990  code = "POWER_OFF_FUNCTION";
991  break;
992 
993  default:
994  code = QString("UNKNOWN_FUNCTION_%1").arg(key->keycode);
995  break;
996  }
997 
998  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Keypress %1 %2")
999  .arg(code).arg(0 == action ? "(Not actioned)" : ""));
1000 
1001  if (0 == action)
1002  return;
1003 
1005  auto* ke = new QKeyEvent(QEvent::KeyPress, action, Qt::NoModifier);
1006  qApp->postEvent(GetMythMainWindow(), (QEvent*)ke);
1007  }
1008 
1009 #if CEC_LIB_VERSION_MAJOR >= 2
1010  static int HandleAlert(const libcec_alert alert, const libcec_parameter &data)
1011  {
1012  // These aren't handled yet
1013  // Note that we *DON'T* want to just show these
1014  // to the user in a popup, because some (eg prompting about firmware
1015  // upgrades) aren't appropriate.
1016  // Ideally we'd try to handle this, eg by reopening the adapter
1017  // in a separate thread if it lost the connection....
1018 
1019  QString param;
1020  switch (data.paramType)
1021  {
1022  case CEC_PARAMETER_TYPE_STRING:
1023  param = QString(": %1").arg((char*)data.paramData);
1024  break;
1025  case CEC_PARAMETER_TYPE_UNKOWN: /* libcec typo */
1026  default:
1027  if (data.paramData != nullptr)
1028  {
1029  param = QString(": UNKNOWN param has type %1").arg(data.paramType);
1030  }
1031  break;
1032  }
1033 
1034  // There is no ToString method for libcec_alert...
1035  // Plus libcec adds new values in minor releases (eg 2.1.1)
1036  // but doesn't provide a #define for the last digit...
1037  // Besides, it makes sense to do this, since we could be compiling
1038  // against an older version than we're running against
1039 #if CEC_LIB_VERSION_MAJOR == 2 && CEC_LIB_VERSION_MINOR < 1
1040 // since 2.0.4
1041 #define CEC_ALERT_PHYSICAL_ADDRESS_ERROR 4
1042 #endif
1043 #if CEC_LIB_VERSION_MAJOR == 2 && CEC_LIB_VERSION_MINOR < 2
1044 // since 2.1.1
1045 #define CEC_ALERT_TV_POLL_FAILED 5
1046 #endif
1047  switch (alert)
1048  {
1049  case CEC_ALERT_SERVICE_DEVICE:
1050  LOG(VB_GENERAL, LOG_INFO, LOC + QString("CEC device service message") + param);
1051  break;
1052  case CEC_ALERT_CONNECTION_LOST:
1053  LOG(VB_GENERAL, LOG_ERR, LOC + QString("CEC device connection list") + param);
1054  break;
1055  case CEC_ALERT_PERMISSION_ERROR:
1056  case CEC_ALERT_PORT_BUSY:
1057  /* Don't log due to possible false positives on the initial
1058  * open. libcec will log via the logging callback anyway
1059  */
1060  break;
1061  case CEC_ALERT_PHYSICAL_ADDRESS_ERROR:
1062  LOG(VB_GENERAL, LOG_ERR, LOC + QString("CEC physical address error") + param);
1063  break;
1064  case CEC_ALERT_TV_POLL_FAILED:
1065  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("CEC device can't poll TV") + param);
1066  break;
1067  default:
1068  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("UNKNOWN CEC device alert %1").arg(alert) + param);
1069  break;
1070  }
1071 
1072  return 1;
1073  }
1074 
1075  void HandleSourceActivated(const cec_logical_address address, const uint8_t activated)
1076  {
1077  if (!m_adapter || !m_valid)
1078  return;
1079 
1080  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Source %1 %2")
1081  .arg(m_adapter->ToString(address))
1082  .arg(activated ? "Activated" : "Deactivated"));
1083 
1084  if (activated)
1086  }
1087 #endif
1088 
1089  void HandleActions(void)
1090  {
1091  if (!m_adapter || !m_valid)
1092  return;
1093 
1094  // power state
1095  if (m_powerOffTV && m_powerOffTVAllowed)
1096  {
1097  if (m_adapter->StandbyDevices(CECDEVICE_TV))
1098  LOG(VB_GENERAL, LOG_INFO, LOC + "Asked TV to turn off.");
1099  else
1100  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to turn TV off.");
1101  }
1102 
1103  if (m_powerOnTV && m_powerOnTVAllowed)
1104  {
1105  if (m_adapter->PowerOnDevices(CECDEVICE_TV))
1106  LOG(VB_GENERAL, LOG_INFO, LOC + "Asked TV to turn on.");
1107  else
1108  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to turn TV on.");
1109  }
1110 
1111  // HDMI input
1112  if (m_switchInput && m_switchInputAllowed)
1113  {
1114  if (m_adapter->SetActiveSource())
1115  LOG(VB_GENERAL, LOG_INFO, LOC + "Asked TV to switch to this input.");
1116  else
1117  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to switch to this input.");
1118  }
1119 
1120  m_powerOffTV = false;
1121  m_powerOnTV = false;
1122  m_switchInput = false;
1123  }
1124 
1125  ICECAdapter *m_adapter {nullptr};
1126  ICECCallbacks m_callbacks;
1127  bool m_valid {false};
1128  bool m_powerOffTV {false};
1129  bool m_powerOffTVAllowed {false};
1130  bool m_powerOffTVOnExit {false};
1131  bool m_powerOnTV {false};
1132  bool m_powerOnTVAllowed {false};
1133  bool m_powerOnTVOnStart {false};
1134  bool m_switchInput {false};
1135  bool m_switchInputAllowed {true};
1136 };
1137 
1138 CECAdapter::CECAdapter() : MThread("CECAdapter"), m_priv(new CECAdapterPriv)
1139 {
1140  QMutexLocker lock(gLock);
1141 
1142  // don't try if disabled
1144  {
1145  LOG(VB_GENERAL, LOG_INFO, LOC + "libCEC support is disabled.");
1146  return;
1147  }
1148 
1149  // create the actual adapter
1150  if (!m_priv->Open())
1151  return;
1152 
1153  // start thread
1154  LOG(VB_GENERAL, LOG_DEBUG, LOC + "Starting thread.");
1155  start();
1156 }
1157 
1159 {
1160  RunProlog();
1161  // Handle any actions at startup
1162  // This is done outside the lock to handle initial setup -
1163  // we know that nothing else can be calling us this early.
1164  m_priv->HandleActions();
1165 
1166  while (IsValid()) {
1167  // Note that a lock is used because the QWaitCondition needs it
1168  // None of the other HandleActions callers need the lock because
1169  // they call HandleActions at open/close time, when
1170  // nothing else can be calling it....
1171  gHandleActionsLock->lock();
1173  if (IsValid()) {
1174  m_priv->HandleActions();
1175  }
1176  gHandleActionsLock->unlock();
1177  }
1178  RunEpilog();
1179 }
1180 
1182 {
1183  QMutexLocker lock(gLock);
1184 
1185  // delete the actual adapter
1186  m_priv->Close();
1187  // Free the thread
1188  gActionsReady->wakeAll();
1189  // Wait for it to end
1190  wait();
1191 }
1192 
1194 {
1195  return m_priv->m_valid;
1196 }
1197 
1198 void CECAdapter::Action(const QString &action)
1199 {
1200  QMutexLocker lock(gLock);
1201  if (ACTION_TVPOWERON == action)
1202  m_priv->m_powerOnTV = true;
1203  else if (ACTION_TVPOWEROFF == action)
1204  m_priv->m_powerOffTV = true;
1205  gActionsReady->wakeAll();
1206 }
1207 
1208 #if CEC_LIB_VERSION_MAJOR <= 3
1209 // cppcheck-suppress passedByValue
1210 static int CECLogMessageCallback(void *adapter, const cec_log_message CEC_CALLBACK_PARAM_TYPE message)
1211 {
1212  return ((CECAdapterPriv*)adapter)->LogMessage(message);
1213 }
1214 
1215 // cppcheck-suppress passedByValue
1216 static int CECKeyPressCallback(void *adapter, const cec_keypress CEC_CALLBACK_PARAM_TYPE keypress)
1217 {
1218  return ((CECAdapterPriv*)adapter)->HandleKeyPress(keypress);
1219 }
1220 
1221 // cppcheck-suppress passedByValue
1222 static int CECCommandCallback(void *adapter, const cec_command CEC_CALLBACK_PARAM_TYPE command)
1223 {
1224  return ((CECAdapterPriv*)adapter)->HandleCommand(command);
1225 }
1226 #endif
1227 #if CEC_LIB_VERSION_MAJOR >= 4
1228 static void CECLogMessageCallback(void *adapter, const cec_log_message* message)
1229 {
1230  Q_UNUSED(adapter);
1231  CECAdapterPriv::LogMessage(message);
1232 }
1233 
1234 static void CECKeyPressCallback(void *adapter, const cec_keypress* keypress)
1235 {
1236  ((CECAdapterPriv*)adapter)->HandleKeyPress(keypress);
1237 }
1238 
1239 static void CECCommandCallback(void *adapter, const cec_command* command)
1240 {
1241  ((CECAdapterPriv*)adapter)->HandleCommand(command);
1242 }
1243 #endif
1244 
1245 #if CEC_LIB_VERSION_MAJOR >= 2
1246 #if CEC_LIB_VERSION_MAJOR <= 3
1247 // cppcheck-suppress passedByValue
1248 static int CECAlertCallback(void *adapter, const libcec_alert alert, const libcec_parameter CEC_CALLBACK_PARAM_TYPE data)
1249 {
1250  return ((CECAdapterPriv*)adapter)->HandleAlert(alert, data);
1251 }
1252 #endif
1253 #if CEC_LIB_VERSION_MAJOR >= 4
1254 static void CECAlertCallback(void *adapter, const libcec_alert alert, const libcec_parameter data)
1255 {
1256  Q_UNUSED(adapter);
1257  CECAdapterPriv::HandleAlert(alert, data);
1258 }
1259 #endif
1260 static void CECSourceActivatedCallback(void *adapter, const cec_logical_address address, const uint8_t activated)
1261 {
1262  ((CECAdapterPriv*)adapter)->HandleSourceActivated(address, activated);
1263 }
1264 #endif
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:215
#define LIBCEC_PORT
Definition: cecadapter.h:11
bool Open(void)
Definition: cecadapter.cpp:79
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:294
bool IsValid()
#define CEC_MIN_HDMI_PORTNUMBER
Definition: cecadapter.cpp:31
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
static QMutex * gHandleActionsLock
Definition: cecadapter.h:35
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
#define LOC
Definition: cecadapter.cpp:17
#define POWEROFFTV_ONEXIT
Definition: cecadapter.h:13
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:311
bool
Definition: pxsup2dast.c:30
#define CEC_CALLBACK_PARAM_TYPE
Definition: cecadapter.cpp:34
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
virtual ~CECAdapter()
static int CECCommandCallback(void *adapter, const cec_command CEC_CALLBACK_PARAM_TYPE command)
static int CECKeyPressCallback(void *adapter, const cec_keypress CEC_CALLBACK_PARAM_TYPE keypress)
int HandleKeyPress(const cec_keypress &key)
Definition: cecadapter.cpp:336
#define LIBCEC_DEVICE
Definition: cecadapter.h:9
#define CEC_MAX_HDMI_PORTNUMBER
Definition: cecadapter.cpp:32
static int CECLogMessageCallback(void *adapter, const cec_log_message CEC_CALLBACK_PARAM_TYPE message)
static void LogMessage(const cec_log_message *message)
Definition: cecadapter.cpp:261
QString GetSetting(const QString &key, const QString &defaultval="")
ICECCallbacks m_callbacks
#define ACTION_TVPOWERON
Definition: mythuiactions.h:25
int HandleCommand(const cec_command &command)
Definition: cecadapter.cpp:279
#define POWERONTV_ALLOWED
Definition: cecadapter.h:14
#define ACTION_TVPOWEROFF
Definition: mythuiactions.h:24
#define POWERONTV_ONSTART
Definition: cecadapter.h:15
MythMainWindow * GetMythMainWindow(void)
void Action(const QString &action)
int GetNumSetting(const QString &key, int defaultval=0)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
#define LIBCEC_ENABLED
Definition: cecadapter.h:8
void HandleActions(void)
bool GetBoolSetting(const QString &key, bool defaultval=false)
void HandleCommand(const cec_command *command)
Definition: cecadapter.cpp:313
CECAdapterPriv * m_priv
Definition: cecadapter.h:33
static QMutex * gLock
Definition: cecadapter.h:34
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:202
void Close(void)
Definition: cecadapter.cpp:227
static void ResetScreensaver(void)
void HandleKeyPress(const cec_keypress *key)
Definition: cecadapter.cpp:675
static QWaitCondition * gActionsReady
Definition: cecadapter.h:36
#define POWEROFFTV_ALLOWED
Definition: cecadapter.h:12
#define MAX_CEC_DEVICES
Definition: cecadapter.cpp:16
void SendSystemEvent(const QString &msg)
#define LIBCEC_BASE
Definition: cecadapter.h:10
static int LogMessage(const cec_log_message &message)
Definition: cecadapter.cpp:245