MythTV  master
mythcecadapter.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 "mythmainwindow.h"
11 #include "mythdisplay.h"
12 #include "mythcecadapter.h"
13 
14 // Std
15 #include <vector>
16 
17 // libcec
18 #include <libcec/cecloader.h>
19 
20 #define MAX_CEC_DEVICES 10
21 #define LOC QString("CECAdapter: ")
22 
23 #if CEC_LIB_VERSION_MAJOR <= 3
24 // cppcheck-suppress passedByValue
25 int MythCECAdapter::LogMessageCallback(void* /*unused*/, const cec_log_message Message)
26 {
27  return MythCECAdapter::LogMessage(Message);
28 }
29 
30 // cppcheck-suppress passedByValue
31 int MythCECAdapter::KeyPressCallback(void* Adapter, const cec_keypress Keypress)
32 {
33  MythCECAdapter* adapter = reinterpret_cast<MythCECAdapter*>(Adapter);
34  if (adapter)
35  return adapter->HandleKeyPress(Keypress);
36  return 1;
37 }
38 
39 // cppcheck-suppress passedByValue
40 int MythCECAdapter::CommandCallback(void* Adapter, const cec_command Command)
41 {
42  MythCECAdapter* adapter = reinterpret_cast<MythCECAdapter*>(Adapter);
43  if (adapter)
44  return adapter->HandleCommand(Command);
45  return 1;
46 }
47 
48 // cppcheck-suppress passedByValue
49 int MythCECAdapter::AlertCallback(void* /*unused*/, const libcec_alert Alert, const libcec_parameter Data)
50 {
51  return MythCECAdapter::HandleAlert(Alert, Data);
52 }
53 #else
54 void MythCECAdapter::LogMessageCallback(void* /*unused*/, const cec_log_message* Message)
55 {
57 }
58 
59 void MythCECAdapter::KeyPressCallback(void* Adapter, const cec_keypress* Keypress)
60 {
61  auto * adapter = reinterpret_cast<MythCECAdapter*>(Adapter);
62  if (adapter)
63  adapter->HandleKeyPress(*Keypress);
64 }
65 
66 void MythCECAdapter::CommandCallback(void* Adapter, const cec_command* Command)
67 {
68  auto * adapter = reinterpret_cast<MythCECAdapter*>(Adapter);
69  if (adapter)
70  adapter->HandleCommand(*Command);
71 }
72 
73 void MythCECAdapter::AlertCallback(void* /*unused*/, const libcec_alert Alert, const libcec_parameter Data)
74 {
75  MythCECAdapter::HandleAlert(Alert, Data);
76 }
77 #endif
78 
79 void MythCECAdapter::SourceCallback(void* /*unused*/, const cec_logical_address Address, const uint8_t Activated)
80 {
81  MythCECAdapter::HandleSource(Address, Activated);
82 }
83 
84 QString MythCECAdapter::AddressToString(int Address)
85 {
86  return QString("%1.%2.%3.%4").arg((Address >> 12) & 0xF).arg((Address >> 8) & 0xF)
87  .arg((Address >> 4) & 0xF).arg(Address & 0xF);
88 }
89 
91 {
92  Close();
93 }
94 
96 {
97  Close();
98 
99  // don't try if disabled
101  {
102  LOG(VB_GENERAL, LOG_INFO, LOC + "libCEC support is disabled.");
103  return;
104  }
105 
106  // get settings
107  // N.B. these need to be set manually since there is no UI
108  QString defaultDevice = gCoreContext->GetSetting(LIBCEC_DEVICE, "auto").trimmed();
109  // Note - if libcec supports automatic detection via EDID then
110  // these settings are not used
111  // The logical address of the HDMI device Myth is connected to
112  QString base_dev = gCoreContext->GetSetting(LIBCEC_BASE, "auto").trimmed();
113  // The number of the HDMI port Myth is connected to
114  QString hdmi_port = gCoreContext->GetSetting(LIBCEC_PORT, "auto").trimmed();
115 
120 
121  // create adapter interface
122  libcec_configuration configuration;
123  strcpy(configuration.strDeviceName, "MythTV");
124  configuration.deviceTypes.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
125 
126  if ("auto" != base_dev)
127  {
128  int base = base_dev.toInt();
129  if (base >= 0 && base < CECDEVICE_BROADCAST)
130  configuration.baseDevice = static_cast<cec_logical_address>(base);
131  }
132  if ("auto" != hdmi_port)
133  {
134  int defaultHDMIPort = hdmi_port.toInt();
135  if (defaultHDMIPort >= CEC_MIN_HDMI_PORTNUMBER && defaultHDMIPort <= CEC_MAX_HDMI_PORTNUMBER)
136  configuration.iHDMIPort = static_cast<uint8_t>(defaultHDMIPort);
137  }
138 
139  // MythDisplay has more accurate physical address detection than libcec - so
140  // use any physical address detected there.
141  // NOTE There is no guarantee that the adapter is actually connected via the
142  // same HDMI device (e.g. a USB CEC adapter could be connected to a different
143  // display).
144  // NOTE We could listen for display changes here but the adapter will be recreated
145  // following a screen change and realistically any setup with more than 1 display
146  // and/or CEC adapter is going to be very hit and miss.
147  MythDisplay* display = Window->GetDisplay();
148  if (display->GetEDID().Valid())
149  {
150  uint16_t address = display->GetEDID().PhysicalAddress();
151  if (address != 0)
152  {
153  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Using physical address %1 from EDID")
154  .arg(AddressToString(address)));
155  configuration.iPhysicalAddress = address;
156  }
157  }
158 
159  // Set up the callbacks
160 #if CEC_LIB_VERSION_MAJOR <= 3
165  m_callbacks.CBCecSourceActivated = &MythCECAdapter::SourceCallback;
166 #else
169  m_callbacks.commandReceived = &MythCECAdapter::CommandCallback;
171  m_callbacks.sourceActivated = &MythCECAdapter::SourceCallback;
172 #endif
173  configuration.callbackParam = this;
174  configuration.callbacks = &m_callbacks;
175 
176  // and initialise
177  m_adapter = LibCecInitialise(&configuration);
178 
179  if (!m_adapter)
180  {
181  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to load libcec.");
182  Close();
183  return;
184  }
185 
186  // initialise the host on which libCEC is running
187  m_adapter->InitVideoStandalone();
188 
189  // find adapters
190 #if CEC_LIB_VERSION_MAJOR >= 4
191  auto *devices = new cec_adapter_descriptor[MAX_CEC_DEVICES];
192  int8_t num_devices = m_adapter->DetectAdapters(devices, MAX_CEC_DEVICES, nullptr, true);
193 #else
194  cec_adapter *devices = new cec_adapter[MAX_CEC_DEVICES];
195  uint8_t num_devices = m_adapter->FindAdapters(devices, MAX_CEC_DEVICES, nullptr);
196 #endif
197  if (num_devices < 1)
198  {
199  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find any CEC devices.");
200  Close();
201  return;
202  }
203 
204  // find required device and debug
205  int devicenum = 0;
206  bool find = defaultDevice != "auto";
207 
208  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Found %1 CEC devices(s).")
209  .arg(num_devices));
210  for (uint8_t i = 0; i < num_devices; i++)
211  {
212 #if CEC_LIB_VERSION_MAJOR >= 4
213  QString comm = QString::fromLatin1(devices[i].strComName);
214  QString path = QString::fromLatin1(devices[i].strComPath);
215 #else
216  QString comm = QString::fromLatin1(devices[i].comm);
217  QString path = QString::fromLatin1(devices[i].path);
218 #endif
219  bool match = find ? (comm == defaultDevice) : (i == 0);
220  devicenum = match ? i : devicenum;
221  LOG(VB_GENERAL, LOG_INFO, LOC +
222  QString("Device %1: path '%2' com port '%3' %4").arg(i + 1)
223  .arg(path).arg(comm)
224  .arg(match ? "SELECTED" : ""));
225  }
226 
227  // open adapter
228 #if CEC_LIB_VERSION_MAJOR >= 4
229  QString comm = QString::fromLatin1(devices[devicenum].strComName);
230  QString path = QString::fromLatin1(devices[devicenum].strComPath);
231 #else
232  QString comm = QString::fromLatin1(devices[devicenum].comm);
233  QString path = QString::fromLatin1(devices[devicenum].path);
234 #endif
235  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Trying to open device %1 (%2).")
236  .arg(path).arg(comm));
237 
238 #if CEC_LIB_VERSION_MAJOR >= 4
239  if (!m_adapter->Open(devices[devicenum].strComName))
240 #else
241  if (!m_adapter->Open(devices[devicenum].comm))
242 #endif
243  {
244  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to open device.");
245  Close();
246  return;
247  }
248 
249  LOG(VB_GENERAL, LOG_INFO, LOC + "Opened CEC device.");
250  m_valid = true;
251 
252  // Power on TV if enabled and switch to our input
253  MythCECActions actions = SwitchInput;
254  if (m_powerOnTVOnStart)
255  actions |= PowerOnTV;
256  HandleActions(actions);
257 }
258 
260 {
261  if (m_adapter)
262  {
263  if (m_powerOffTVOnExit)
265  m_adapter->Close();
266  UnloadLibCec(m_adapter);
267  LOG(VB_GENERAL, LOG_INFO, LOC + "Closing down CEC.");
268  }
269  m_valid = false;
270  m_adapter = nullptr;
271 }
272 
273 int MythCECAdapter::LogMessage(const cec_log_message &Message)
274 {
275  QString msg(Message.message);
276  LogLevel_t level = LOG_UNKNOWN;
277  switch (Message.level)
278  {
279  case CEC_LOG_ERROR: level = LOG_ERR; break;
280  case CEC_LOG_WARNING: level = LOG_WARNING; break;
281  case CEC_LOG_NOTICE: level = LOG_INFO; break;
282  case CEC_LOG_DEBUG: level = LOG_DEBUG; break;
283  default: break;
284  }
285  LOG(VB_GENERAL, level, LOC + QString("%1").arg(msg));
286  return 1;
287 }
288 
289 int MythCECAdapter::HandleCommand(const cec_command &Command)
290 {
291  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Command %1 from '%2' (%3) - destination '%4' (%5)")
292  .arg(Command.opcode).arg(Command.initiator).arg(Command.initiator)
293  .arg(Command.destination).arg(Command.destination));
294 
295  switch (Command.opcode)
296  {
297  case CEC_OPCODE_MENU_REQUEST:
298  cec_keypress key;
299  key.keycode = CEC_USER_CONTROL_CODE_ROOT_MENU;
300  key.duration = 5;
301  HandleKeyPress(key);
302  // SetMenuState could be used to disable the TV menu here
303  // That may be a user-unfriendly thing to do
304  // So they have to see both the TV menu and the MythTV menu
305  break;
306  default:
307  break;
308  }
309  gCoreContext->SendSystemEvent(QString("CEC_COMMAND_RECEIVED COMMAND %1").arg(Command.opcode));
310  return 1;
311 }
312 
313 int MythCECAdapter::HandleKeyPress(const cec_keypress &Key) const
314 {
315  // Ignore key down events and wait for the key 'up'
316  if (Key.duration < 1 || m_ignoreKeys)
317  return 1;
318 
319  QString code;
320  int action = 0;
321  Qt::KeyboardModifier modifier = Qt::NoModifier;
322  switch (Key.keycode)
323  {
324  case CEC_USER_CONTROL_CODE_NUMBER0:
325  action = Qt::Key_0;
326  code = "0";
327  break;
328  case CEC_USER_CONTROL_CODE_NUMBER1:
329  action = Qt::Key_1;
330  code = "1";
331  break;
332  case CEC_USER_CONTROL_CODE_NUMBER2:
333  action = Qt::Key_2;
334  code = "2";
335  break;
336  case CEC_USER_CONTROL_CODE_NUMBER3:
337  action = Qt::Key_3;
338  code = "3";
339  break;
340  case CEC_USER_CONTROL_CODE_NUMBER4:
341  action = Qt::Key_4;
342  code = "4";
343  break;
344  case CEC_USER_CONTROL_CODE_NUMBER5:
345  action = Qt::Key_5;
346  code = "5";
347  break;
348  case CEC_USER_CONTROL_CODE_NUMBER6:
349  action = Qt::Key_6;
350  code = "6";
351  break;
352  case CEC_USER_CONTROL_CODE_NUMBER7:
353  action = Qt::Key_7;
354  code = "7";
355  break;
356  case CEC_USER_CONTROL_CODE_NUMBER8:
357  action = Qt::Key_8;
358  code = "8";
359  break;
360  case CEC_USER_CONTROL_CODE_NUMBER9:
361  action = Qt::Key_9;
362  code = "9";
363  break;
364  case CEC_USER_CONTROL_CODE_SELECT:
365  action = Qt::Key_Select;
366  code = "SELECT";
367  break;
368  case CEC_USER_CONTROL_CODE_ENTER:
369  action = Qt::Key_Enter;
370  code = "ENTER";
371  break;
372  case CEC_USER_CONTROL_CODE_UP:
373  action = Qt::Key_Up;
374  code = "UP";
375  break;
376  case CEC_USER_CONTROL_CODE_DOWN:
377  action = Qt::Key_Down;
378  code = "DOWN";
379  break;
380  case CEC_USER_CONTROL_CODE_LEFT:
381  action = Qt::Key_Left;
382  code = "LEFT";
383  break;
384  case CEC_USER_CONTROL_CODE_LEFT_UP:
385  action = Qt::Key_Left;
386  code = "LEFT_UP";
387  break;
388  case CEC_USER_CONTROL_CODE_LEFT_DOWN:
389  action = Qt::Key_Left;
390  code = "LEFT_DOWN";
391  break;
392  case CEC_USER_CONTROL_CODE_RIGHT:
393  action = Qt::Key_Right;
394  code = "RIGHT";
395  break;
396  case CEC_USER_CONTROL_CODE_RIGHT_UP:
397  action = Qt::Key_Right;
398  code = "RIGHT_UP";
399  break;
400  case CEC_USER_CONTROL_CODE_RIGHT_DOWN:
401  action = Qt::Key_Right;
402  code = "RIGHT_DOWN";
403  break;
404  case CEC_USER_CONTROL_CODE_ROOT_MENU:
405  action = Qt::Key_M;
406  code = "ROOT_MENU";
407  break;
408  case CEC_USER_CONTROL_CODE_AN_RETURN: //return (Samsung) (0x91)
409  case CEC_USER_CONTROL_CODE_EXIT:
410  action = Qt::Key_Escape;
411  code = "EXIT";
412  break;
413  case CEC_USER_CONTROL_CODE_PREVIOUS_CHANNEL:
414  action = Qt::Key_H;
415  code = "PREVIOUS_CHANNEL";
416  break;
417  case CEC_USER_CONTROL_CODE_SOUND_SELECT:
418  action = Qt::Key_Plus;
419  code = "SOUND_SELECT";
420  break;
421  case CEC_USER_CONTROL_CODE_VOLUME_UP:
422  action = Qt::Key_VolumeUp;
423  code = "VOLUME_UP";
424  break;
425  case CEC_USER_CONTROL_CODE_VOLUME_DOWN:
426  action = Qt::Key_VolumeDown;
427  code = "VOLUME_DOWN";
428  break;
429  case CEC_USER_CONTROL_CODE_MUTE:
430  action = Qt::Key_VolumeMute;
431  code = "MUTE";
432  break;
433  case CEC_USER_CONTROL_CODE_PLAY:
434  action = Qt::Key_P;
435  code = "PLAY";
436  // Play set to control-p to differentiate from pause
437  modifier = Qt::ControlModifier;
438  break;
439  case CEC_USER_CONTROL_CODE_PAUSE:
440  action = Qt::Key_P;
441  code = "PAUSE";
442  break;
443  case CEC_USER_CONTROL_CODE_STOP:
444  action = Qt::Key_Stop;
445  code = "STOP";
446  break;
447  case CEC_USER_CONTROL_CODE_RECORD:
448  action = Qt::Key_R;
449  code = "RECORD";
450  break;
451  case CEC_USER_CONTROL_CODE_CLEAR:
452  action = Qt::Key_Clear;
453  code = "CLEAR";
454  break;
455  case CEC_USER_CONTROL_CODE_DISPLAY_INFORMATION:
456  action = Qt::Key_I;
457  code = "DISPLAY_INFORMATION";
458  break;
459  case CEC_USER_CONTROL_CODE_PAGE_UP:
460  action = Qt::Key_PageUp;
461  code = "PAGE_UP";
462  break;
463  case CEC_USER_CONTROL_CODE_PAGE_DOWN:
464  action = Qt::Key_PageDown;
465  code = "PAGE_DOWN";
466  break;
467  case CEC_USER_CONTROL_CODE_EJECT:
468  action = Qt::Key_Eject;
469  code = "EJECT";
470  break;
471  case CEC_USER_CONTROL_CODE_FORWARD:
472  action = Qt::Key_Forward;
473  code = "FORWARD";
474  break;
475  case CEC_USER_CONTROL_CODE_BACKWARD:
476  action = Qt::Key_Back;
477  code = "BACKWARD";
478  break;
479  case CEC_USER_CONTROL_CODE_F1_BLUE:
480  action = Qt::Key_F5; // NB F1 is help and we normally map blue to F5
481  code = "F1_BLUE";
482  break;
483  case CEC_USER_CONTROL_CODE_F2_RED:
484  action = Qt::Key_F2;
485  code = "F2_RED";
486  break;
487  case CEC_USER_CONTROL_CODE_F3_GREEN:
488  action = Qt::Key_F3;
489  code = "F3_GREEN";
490  break;
491  case CEC_USER_CONTROL_CODE_F4_YELLOW:
492  action = Qt::Key_F4;
493  code = "F4_YELLOW";
494  break;
495  case CEC_USER_CONTROL_CODE_SETUP_MENU:
496  action = Qt::Key_M; // Duplicate of Root Menu
497  code = "SETUP_MENU";
498  break;
499  case CEC_USER_CONTROL_CODE_CONTENTS_MENU:
500  action = Qt::Key_M; // Duplicate of Root Menu
501  code = "CONTENTS_MENU";
502  break;
503  case CEC_USER_CONTROL_CODE_FAVORITE_MENU:
504  action = Qt::Key_M; // Duplicate of Root Menu
505  code = "FAVORITE_MENU";
506  break;
507  case CEC_USER_CONTROL_CODE_DOT:
508  action = Qt::Key_Period;
509  code = "DOT";
510  break;
511  case CEC_USER_CONTROL_CODE_NEXT_FAVORITE:
512  action = Qt::Key_Slash;
513  code = "NEXT_FAVORITE";
514  break;
515  case CEC_USER_CONTROL_CODE_INPUT_SELECT:
516  action = Qt::Key_C;
517  code = "INPUT_SELECT";
518  break;
519  case CEC_USER_CONTROL_CODE_HELP:
520  action = Qt::Key_F1;
521  code = "HELP";
522  break;
523  case CEC_USER_CONTROL_CODE_STOP_RECORD:
524  action = Qt::Key_R; // Duplicate of Record
525  code = "STOP_RECORD";
526  break;
527  case CEC_USER_CONTROL_CODE_SUB_PICTURE:
528  action = Qt::Key_V;
529  code = "SUB_PICTURE";
530  break;
531  case CEC_USER_CONTROL_CODE_ELECTRONIC_PROGRAM_GUIDE:
532  action = Qt::Key_S;
533  code = "ELECTRONIC_PROGRAM_GUIDE";
534  break;
535  case CEC_USER_CONTROL_CODE_POWER:
536  action = Qt::Key_PowerOff;
537  code = "POWER";
538  break;
539 
540  // these codes have 'non-standard' Qt key mappings to ensure
541  // each code has a unique key mapping
542  case CEC_USER_CONTROL_CODE_CHANNEL_DOWN:
543  action = Qt::Key_F20; // to differentiate from Up
544  code = "CHANNEL_DOWN";
545  break;
546  case CEC_USER_CONTROL_CODE_CHANNEL_UP:
547  action = Qt::Key_F21; // to differentiate from Down
548  code = "CHANNEL_UP";
549  break;
550  case CEC_USER_CONTROL_CODE_REWIND:
551  action = Qt::Key_F22; // to differentiate from Left
552  code = "REWIND";
553  break;
554  case CEC_USER_CONTROL_CODE_FAST_FORWARD:
555  action = Qt::Key_F23; // to differentiate from Right
556  code = "FAST_FORWARD";
557  break;
558  case CEC_USER_CONTROL_CODE_ANGLE:
559  action = Qt::Key_F24;
560  code = "ANGLE";
561  break;
562  case CEC_USER_CONTROL_CODE_F5:
563  action = Qt::Key_F6; // NB!
564  code = "F5";
565  break;
566 
567  // codes with no obvious MythTV action
568  case CEC_USER_CONTROL_CODE_INITIAL_CONFIGURATION:
569  code = "INITIAL_CONFIGURATION";
570  break;
571  case CEC_USER_CONTROL_CODE_PAUSE_RECORD:
572  code = "PAUSE_RECORD";
573  break;
574  case CEC_USER_CONTROL_CODE_VIDEO_ON_DEMAND:
575  code = "VIDEO_ON_DEMAND";
576  break;
577  case CEC_USER_CONTROL_CODE_TIMER_PROGRAMMING:
578  code = "TIMER_PROGRAMMING";
579  break;
580  case CEC_USER_CONTROL_CODE_UNKNOWN:
581  code = "UNKNOWN";
582  break;
583  case CEC_USER_CONTROL_CODE_DATA:
584  code = "DATA";
585  break;
586 
587  // Functions aren't implemented (similar to macros?)
588  case CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION:
589  code = "POWER_ON_FUNCTION";
590  break;
591  case CEC_USER_CONTROL_CODE_PLAY_FUNCTION:
592  code = "PLAY_FUNCTION";
593  break;
594  case CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION:
595  code = "PAUSE_PLAY_FUNCTION";
596  break;
597  case CEC_USER_CONTROL_CODE_RECORD_FUNCTION:
598  code = "RECORD_FUNCTION";
599  break;
600  case CEC_USER_CONTROL_CODE_PAUSE_RECORD_FUNCTION:
601  code = "PAUSE_RECORD_FUNCTION";
602  break;
603  case CEC_USER_CONTROL_CODE_STOP_FUNCTION:
604  code = "STOP_FUNCTION";
605  break;
606  case CEC_USER_CONTROL_CODE_MUTE_FUNCTION:
607  code = "MUTE_FUNCTION";
608  break;
609  case CEC_USER_CONTROL_CODE_RESTORE_VOLUME_FUNCTION:
610  code = "RESTORE_VOLUME_FUNCTION";
611  break;
612  case CEC_USER_CONTROL_CODE_TUNE_FUNCTION:
613  code = "TUNE_FUNCTION";
614  break;
615  case CEC_USER_CONTROL_CODE_SELECT_MEDIA_FUNCTION:
616  code = "SELECT_MEDIA_FUNCTION";
617  break;
618  case CEC_USER_CONTROL_CODE_SELECT_AV_INPUT_FUNCTION:
619  code = "SELECT_AV_INPUT_FUNCTION";
620  break;
621  case CEC_USER_CONTROL_CODE_SELECT_AUDIO_INPUT_FUNCTION:
622  code = "SELECT_AUDIO_INPUT_FUNCTION";
623  break;
624  case CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION:
625  code = "POWER_TOGGLE_FUNCTION";
626  break;
627  case CEC_USER_CONTROL_CODE_POWER_OFF_FUNCTION:
628  code = "POWER_OFF_FUNCTION";
629  break;
630 
631  default:
632  code = QString("UNKNOWN_FUNCTION_%1").arg(Key.keycode);
633  break;
634  }
635 
636  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Keypress %1 %2")
637  .arg(code).arg(0 == action ? "(Not actioned)" : ""));
638 
639  if (0 == action)
640  return 1;
641 
643  auto* ke = new QKeyEvent(QEvent::KeyPress, action, modifier);
644  QCoreApplication::postEvent(GetMythMainWindow(), ke);
645  return 1;
646 }
647 
648 int MythCECAdapter::HandleAlert(const libcec_alert Alert, const libcec_parameter &Data)
649 {
650  // These aren't handled yet
651  // Note that we *DON'T* want to just show these
652  // to the user in a popup, because some (eg prompting about firmware
653  // upgrades) aren't appropriate.
654  // Ideally we'd try to handle this, eg by reopening the adapter
655  // in a separate thread if it lost the connection....
656 
657  QString param;
658  switch (Data.paramType)
659  {
660  case CEC_PARAMETER_TYPE_STRING:
661  param = QString(": %1").arg(static_cast<char*>(Data.paramData));
662  break;
663  case CEC_PARAMETER_TYPE_UNKOWN: /* libcec typo */
664  if (Data.paramData != nullptr)
665  param = QString(": UNKNOWN param has type %1").arg(Data.paramType);
666  break;
667  }
668 
669  // There is no ToString method for libcec_alert...
670  // Plus libcec adds new values in minor releases (eg 2.1.1)
671  // but doesn't provide a #define for the last digit...
672  // Besides, it makes sense to do this, since we could be compiling
673  // against an older version than we're running against
674 #if CEC_LIB_VERSION_MAJOR == 2 && CEC_LIB_VERSION_MINOR < 1
675 // since 2.0.4
676 #define CEC_ALERT_PHYSICAL_ADDRESS_ERROR 4
677 #endif
678 #if CEC_LIB_VERSION_MAJOR == 2 && CEC_LIB_VERSION_MINOR < 2
679 // since 2.1.1
680 #define CEC_ALERT_TV_POLL_FAILED 5
681 #endif
682  switch (Alert)
683  {
684  case CEC_ALERT_SERVICE_DEVICE:
685  LOG(VB_GENERAL, LOG_INFO, LOC + QString("CEC device service message") + param);
686  break;
687  case CEC_ALERT_CONNECTION_LOST:
688  LOG(VB_GENERAL, LOG_ERR, LOC + QString("CEC device connection list") + param);
689  break;
690  case CEC_ALERT_PERMISSION_ERROR:
691  case CEC_ALERT_PORT_BUSY:
692  // Don't log due to possible false positives on the initial
693  // open. libcec will log via the logging callback anyway
694  break;
695  case CEC_ALERT_PHYSICAL_ADDRESS_ERROR:
696  LOG(VB_GENERAL, LOG_ERR, LOC + QString("CEC physical address error") + param);
697  break;
698  case CEC_ALERT_TV_POLL_FAILED:
699  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("CEC device can't poll TV") + param);
700  break;
701  }
702  return 1;
703 }
704 
705 void MythCECAdapter::HandleSource(const cec_logical_address Address, const uint8_t Activated)
706 {
707  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Source %1 %2")
708  .arg(Address).arg(Activated ? "Activated" : "Deactivated"));
709  if (Activated)
711 }
712 
713 void MythCECAdapter::HandleActions(MythCECActions Actions)
714 {
715  if (!m_adapter || !m_valid)
716  return;
717 
718  // power state
719  if (((Actions & PowerOffTV) != 0U) && m_powerOffTVAllowed)
720  {
721  if (m_adapter->StandbyDevices(CECDEVICE_TV))
722  LOG(VB_GENERAL, LOG_INFO, LOC + "Asked TV to turn off.");
723  else
724  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to turn TV off.");
725  }
726 
727  if (((Actions & PowerOnTV) != 0U) && m_powerOnTVAllowed)
728  {
729  if (m_adapter->PowerOnDevices(CECDEVICE_TV))
730  LOG(VB_GENERAL, LOG_INFO, LOC + "Asked TV to turn on.");
731  else
732  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to turn TV on.");
733  }
734 
735  // HDMI input
736  if (((Actions & SwitchInput) != 0U) && m_switchInputAllowed)
737  {
738  if (m_adapter->SetActiveSource())
739  LOG(VB_GENERAL, LOG_INFO, LOC + "Asked TV to switch to this input.");
740  else
741  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to switch to this input.");
742  }
743 }
744 
745 void MythCECAdapter::Action(const QString &Action)
746 {
747  if (ACTION_TVPOWERON == Action)
749  else if (ACTION_TVPOWEROFF == Action)
751 }
752 
753 void MythCECAdapter::IgnoreKeys(bool Ignore)
754 {
755  m_ignoreKeys = Ignore;
756 }
757 
mythevent.h
MythCECAdapter::SwitchInput
@ SwitchInput
Definition: mythcecadapter.h:31
MythCECAdapter::m_adapter
ICECAdapter * m_adapter
Definition: mythcecadapter.h:66
MythDisplay::GetEDID
MythEDID & GetEDID()
Definition: mythdisplay.cpp:836
POWEROFFTV_ALLOWED
#define POWEROFFTV_ALLOWED
Definition: mythcecadapter.h:11
MythEDID::PhysicalAddress
uint16_t PhysicalAddress(void) const
Definition: mythedid.cpp:52
mythcecadapter.h
MythCECAdapter::m_callbacks
ICECCallbacks m_callbacks
Definition: mythcecadapter.h:67
MythCECAdapter::m_powerOffTVOnExit
bool m_powerOffTVOnExit
Definition: mythcecadapter.h:71
MAX_CEC_DEVICES
#define MAX_CEC_DEVICES
Definition: mythcecadapter.cpp:20
arg
arg(title).arg(filename).arg(doDelete))
MythCECAdapter::m_powerOnTVAllowed
bool m_powerOnTVAllowed
Definition: mythcecadapter.h:72
MythCECAdapter::Open
void Open(MythMainWindow *Window)
Definition: mythcecadapter.cpp:95
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythEDID::Valid
bool Valid(void) const
Definition: mythedid.cpp:32
MythCECAdapter::IgnoreKeys
void IgnoreKeys(bool Ignore)
Definition: mythcecadapter.cpp:753
MythCECAdapter::LogMessage
static int LogMessage(const cec_log_message &Message)
Definition: mythcecadapter.cpp:273
Action
An action (for this plugin) consists of a description, and a set of key sequences.
Definition: action.h:41
MythCECAdapter::m_powerOnTVOnStart
bool m_powerOnTVOnStart
Definition: mythcecadapter.h:73
LIBCEC_ENABLED
#define LIBCEC_ENABLED
Definition: mythcecadapter.h:7
MythMainWindow::GetDisplay
MythDisplay * GetDisplay()
Definition: mythmainwindow.cpp:256
MythCECAdapter::m_valid
bool m_valid
Definition: mythcecadapter.h:68
MythCECAdapter::KeyPressCallback
static int KeyPressCallback(void *Adapter, const cec_keypress Keypress)
Definition: mythcecadapter.cpp:31
mythdisplay.h
LIBCEC_PORT
#define LIBCEC_PORT
Definition: mythcecadapter.h:10
Command
Definition: gamesettings.cpp:228
mythlogging.h
MythCECAdapter::PowerOffTV
@ PowerOffTV
Definition: mythcecadapter.h:29
ACTION_TVPOWEROFF
#define ACTION_TVPOWEROFF
Definition: mythuiactions.h:24
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1550
POWERONTV_ALLOWED
#define POWERONTV_ALLOWED
Definition: mythcecadapter.h:13
MythCECAdapter::m_powerOffTVAllowed
bool m_powerOffTVAllowed
Definition: mythcecadapter.h:70
MythCECAdapter::m_switchInputAllowed
bool m_switchInputAllowed
Definition: mythcecadapter.h:74
MythCECAdapter::m_ignoreKeys
bool m_ignoreKeys
Definition: mythcecadapter.h:69
MythCECAdapter::SourceCallback
static void SourceCallback(void *, cec_logical_address Address, uint8_t Activated)
Definition: mythcecadapter.cpp:79
MythCECAdapter::CommandCallback
static int CommandCallback(void *Adapter, const cec_command Command)
Definition: mythcecadapter.cpp:40
LIBCEC_BASE
#define LIBCEC_BASE
Definition: mythcecadapter.h:9
ACTION_TVPOWERON
#define ACTION_TVPOWERON
Definition: mythuiactions.h:25
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:56
MythDisplay
Definition: mythdisplay.h:19
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:929
MythCECAdapter::LogMessageCallback
static int LogMessageCallback(void *, const cec_log_message Message)
Definition: mythcecadapter.cpp:25
MythCECAdapter::HandleSource
static void HandleSource(cec_logical_address Address, uint8_t Activated)
Definition: mythcecadapter.cpp:705
POWERONTV_ONSTART
#define POWERONTV_ONSTART
Definition: mythcecadapter.h:14
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:923
LOC
#define LOC
Definition: mythcecadapter.cpp:21
MythCECAdapter::AlertCallback
static int AlertCallback(void *, const libcec_alert Alert, const libcec_parameter Data)
Definition: mythcecadapter.cpp:49
MythCECAdapter::HandleAlert
static int HandleAlert(libcec_alert Alert, const libcec_parameter &Data)
Definition: mythcecadapter.cpp:648
MythCECAdapter::AddressToString
static QString AddressToString(int Address)
Definition: mythcecadapter.cpp:84
mythcorecontext.h
MythCECAdapter::HandleKeyPress
int HandleKeyPress(const cec_keypress &Key) const
Definition: mythcecadapter.cpp:313
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:105
MythCECAdapter::PowerOnTV
@ PowerOnTV
Definition: mythcecadapter.h:30
build_compdb.action
action
Definition: build_compdb.py:9
LIBCEC_DEVICE
#define LIBCEC_DEVICE
Definition: mythcecadapter.h:8
MythCECAdapter::HandleCommand
int HandleCommand(const cec_command &Command)
Definition: mythcecadapter.cpp:289
uint16_t
unsigned short uint16_t
Definition: iso6937tables.h:3
MythCECAdapter::Close
void Close(void)
Definition: mythcecadapter.cpp:259
MythCECAdapter::~MythCECAdapter
~MythCECAdapter()
Definition: mythcecadapter.cpp:90
MythMainWindow::ResetScreensaver
static void ResetScreensaver()
Definition: mythmainwindow.cpp:601
MythCECAdapter::HandleActions
void HandleActions(MythCECActions Actions)
Definition: mythcecadapter.cpp:713
POWEROFFTV_ONEXIT
#define POWEROFFTV_ONEXIT
Definition: mythcecadapter.h:12
mythmainwindow.h
MythCECAdapter
Definition: mythcecadapter.h:24
MythMainWindow
Definition: mythmainwindow.h:35
find
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)
Definition: dvbstreamhandler.cpp:356
MythCECAdapter::Action
void Action(const QString &Action)
Definition: mythcecadapter.cpp:745
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:915