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 
25 int MythCECAdapter::LogMessageCallback(void* /*unused*/, const cec_log_message Message)
26 {
27  return MythCECAdapter::LogMessage(Message);
28 }
29 
30 int MythCECAdapter::KeyPressCallback(void* Adapter, const cec_keypress Keypress)
31 {
32  MythCECAdapter* adapter = reinterpret_cast<MythCECAdapter*>(Adapter);
33  if (adapter)
34  return adapter->HandleKeyPress(Keypress);
35  return 1;
36 }
37 
38 int MythCECAdapter::CommandCallback(void* Adapter, const cec_command Command)
39 {
40  MythCECAdapter* adapter = reinterpret_cast<MythCECAdapter*>(Adapter);
41  if (adapter)
42  return adapter->HandleCommand(Command);
43  return 1;
44 }
45 
46 int MythCECAdapter::AlertCallback(void* /*unused*/, const libcec_alert Alert, const libcec_parameter Data)
47 {
48  return MythCECAdapter::HandleAlert(Alert, Data);
49 }
50 #else
51 void MythCECAdapter::LogMessageCallback(void* /*unused*/, const cec_log_message* Message)
52 {
54 }
55 
56 void MythCECAdapter::KeyPressCallback(void* Adapter, const cec_keypress* Keypress)
57 {
58  auto * adapter = reinterpret_cast<MythCECAdapter*>(Adapter);
59  if (adapter)
60  adapter->HandleKeyPress(*Keypress);
61 }
62 
63 void MythCECAdapter::CommandCallback(void* Adapter, const cec_command* Command)
64 {
65  auto * adapter = reinterpret_cast<MythCECAdapter*>(Adapter);
66  if (adapter)
67  adapter->HandleCommand(*Command);
68 }
69 
70 void MythCECAdapter::AlertCallback(void* /*unused*/, const libcec_alert Alert, const libcec_parameter Data)
71 {
72  MythCECAdapter::HandleAlert(Alert, Data);
73 }
74 #endif
75 
76 void MythCECAdapter::SourceCallback(void* /*unused*/, const cec_logical_address Address, const uint8_t Activated)
77 {
78  MythCECAdapter::HandleSource(Address, Activated);
79 }
80 
81 QString MythCECAdapter::AddressToString(int Address)
82 {
83  return QString("%1.%2.%3.%4").arg((Address >> 12) & 0xF).arg((Address >> 8) & 0xF)
84  .arg((Address >> 4) & 0xF).arg(Address & 0xF);
85 }
86 
88 {
89  Close();
90 }
91 
93 {
94  Close();
95 
96  // don't try if disabled
98  {
99  LOG(VB_GENERAL, LOG_INFO, LOC + "libCEC support is disabled.");
100  return;
101  }
102 
103  // get settings
104  // N.B. these need to be set manually since there is no UI
105  QString defaultDevice = gCoreContext->GetSetting(LIBCEC_DEVICE, "auto").trimmed();
106  // Note - if libcec supports automatic detection via EDID then
107  // these settings are not used
108  // The logical address of the HDMI device Myth is connected to
109  QString base_dev = gCoreContext->GetSetting(LIBCEC_BASE, "auto").trimmed();
110  // The number of the HDMI port Myth is connected to
111  QString hdmi_port = gCoreContext->GetSetting(LIBCEC_PORT, "auto").trimmed();
112 
117 
118  // create adapter interface
119  libcec_configuration configuration;
120  strcpy(configuration.strDeviceName, "MythTV");
121  configuration.deviceTypes.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
122 
123  if ("auto" != base_dev)
124  {
125  int base = base_dev.toInt();
126  if (base >= 0 && base < CECDEVICE_BROADCAST)
127  configuration.baseDevice = static_cast<cec_logical_address>(base);
128  }
129  if ("auto" != hdmi_port)
130  {
131  int defaultHDMIPort = hdmi_port.toInt();
132  if (defaultHDMIPort >= CEC_MIN_HDMI_PORTNUMBER && defaultHDMIPort <= CEC_MAX_HDMI_PORTNUMBER)
133  configuration.iHDMIPort = static_cast<uint8_t>(defaultHDMIPort);
134  }
135 
136  // MythDisplay has more accurate physical address detection than libcec - so
137  // use any physical address detected there.
138  // NOTE There is no guarantee that the adapter is actually connected via the
139  // same HDMI device (e.g. a USB CEC adapter could be connected to a different
140  // display).
141  // NOTE We could listen for display changes here but the adapter will be recreated
142  // following a screen change and realistically any setup with more than 1 display
143  // and/or CEC adapter is going to be very hit and miss.
144  MythDisplay* display = Window->GetDisplay();
145  if (display->GetEDID().Valid())
146  {
147  uint16_t address = display->GetEDID().PhysicalAddress();
148  if (address != 0)
149  {
150  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Using physical address %1 from EDID")
151  .arg(AddressToString(address)));
152  configuration.iPhysicalAddress = address;
153  }
154  }
155 
156  // Set up the callbacks
157 #if CEC_LIB_VERSION_MAJOR <= 3
162  m_callbacks.CBCecSourceActivated = &MythCECAdapter::SourceCallback;
163 #else
166  m_callbacks.commandReceived = &MythCECAdapter::CommandCallback;
168  m_callbacks.sourceActivated = &MythCECAdapter::SourceCallback;
169 #endif
170  configuration.callbackParam = this;
171  configuration.callbacks = &m_callbacks;
172 
173  // and initialise
174  m_adapter = LibCecInitialise(&configuration);
175 
176  if (!m_adapter)
177  {
178  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to load libcec.");
179  Close();
180  return;
181  }
182 
183  // initialise the host on which libCEC is running
184  m_adapter->InitVideoStandalone();
185 
186  // find adapters
187 #if CEC_LIB_VERSION_MAJOR >= 4
188  auto *devices = new cec_adapter_descriptor[MAX_CEC_DEVICES];
189  int8_t num_devices = m_adapter->DetectAdapters(devices, MAX_CEC_DEVICES, nullptr, true);
190 #else
191  cec_adapter *devices = new cec_adapter[MAX_CEC_DEVICES];
192  uint8_t num_devices = m_adapter->FindAdapters(devices, MAX_CEC_DEVICES, nullptr);
193 #endif
194  if (num_devices < 1)
195  {
196  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find any CEC devices.");
197  Close();
198  return;
199  }
200 
201  // find required device and debug
202  int devicenum = 0;
203  bool find = defaultDevice != "auto";
204 
205  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Found %1 CEC devices(s).")
206  .arg(num_devices));
207  for (uint8_t i = 0; i < num_devices; i++)
208  {
209 #if CEC_LIB_VERSION_MAJOR >= 4
210  QString comm = QString::fromLatin1(devices[i].strComName);
211  QString path = QString::fromLatin1(devices[i].strComPath);
212 #else
213  QString comm = QString::fromLatin1(devices[i].comm);
214  QString path = QString::fromLatin1(devices[i].path);
215 #endif
216  bool match = find ? (comm == defaultDevice) : (i == 0);
217  devicenum = match ? i : devicenum;
218  LOG(VB_GENERAL, LOG_INFO, LOC +
219  QString("Device %1: path '%2' com port '%3' %4")
220  .arg(QString::number(i + 1),
221  path, comm, match ? "SELECTED" : ""));
222  }
223 
224  // open adapter
225 #if CEC_LIB_VERSION_MAJOR >= 4
226  QString comm = QString::fromLatin1(devices[devicenum].strComName);
227  QString path = QString::fromLatin1(devices[devicenum].strComPath);
228 #else
229  QString comm = QString::fromLatin1(devices[devicenum].comm);
230  QString path = QString::fromLatin1(devices[devicenum].path);
231 #endif
232  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Trying to open device %1 (%2).")
233  .arg(path, comm));
234 
235 #if CEC_LIB_VERSION_MAJOR >= 4
236  if (!m_adapter->Open(devices[devicenum].strComName))
237 #else
238  if (!m_adapter->Open(devices[devicenum].comm))
239 #endif
240  {
241  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to open device.");
242  Close();
243  return;
244  }
245 
246  LOG(VB_GENERAL, LOG_INFO, LOC + "Opened CEC device.");
247  m_valid = true;
248 
249  // Power on TV if enabled and switch to our input
250  MythCECActions actions = SwitchInput;
251  if (m_powerOnTVOnStart)
252  actions |= PowerOnTV;
253  HandleActions(actions);
254 }
255 
257 {
258  if (m_adapter)
259  {
260  if (m_powerOffTVOnExit)
262  m_adapter->Close();
263  UnloadLibCec(m_adapter);
264  // Workaround for bug in libcec/cecloader.h
265  // MythTV issue #299, libcec issue #555
266  g_libCEC = nullptr;
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, 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:928
POWEROFFTV_ALLOWED
#define POWEROFFTV_ALLOWED
Definition: mythcecadapter.h:11
MythEDID::PhysicalAddress
uint16_t PhysicalAddress() const
Definition: mythedid.cpp:59
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
MythCECAdapter::HandleKeyPress
int HandleKeyPress(cec_keypress Key) const
Definition: mythcecadapter.cpp:313
MythCECAdapter::m_powerOnTVAllowed
bool m_powerOnTVAllowed
Definition: mythcecadapter.h:72
MythCECAdapter::Open
void Open(MythMainWindow *Window)
Definition: mythcecadapter.cpp:92
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
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:40
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:252
MythCECAdapter::m_valid
bool m_valid
Definition: mythcecadapter.h:68
MythCECAdapter::KeyPressCallback
static int KeyPressCallback(void *Adapter, const cec_keypress Keypress)
Definition: mythcecadapter.cpp:30
mythdisplay.h
LIBCEC_PORT
#define LIBCEC_PORT
Definition: mythcecadapter.h:10
Command
Definition: gamesettings.cpp:227
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:1556
POWERONTV_ALLOWED
#define POWERONTV_ALLOWED
Definition: mythcecadapter.h:13
MythCECAdapter::m_powerOffTVAllowed
bool m_powerOffTVAllowed
Definition: mythcecadapter.h:70
MythEDID::Valid
bool Valid() const
Definition: mythedid.cpp:39
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:76
MythCECAdapter::CommandCallback
static int CommandCallback(void *Adapter, const cec_command Command)
Definition: mythcecadapter.cpp:38
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:60
MythDisplay
Definition: mythdisplay.h:22
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:936
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:930
LOC
#define LOC
Definition: mythcecadapter.cpp:21
MythCECAdapter::AlertCallback
static int AlertCallback(void *, const libcec_alert Alert, const libcec_parameter Data)
Definition: mythcecadapter.cpp:46
MythCECAdapter::AddressToString
static QString AddressToString(int Address)
Definition: mythcecadapter.cpp:81
mythcorecontext.h
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
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:256
MythCECAdapter::~MythCECAdapter
~MythCECAdapter()
Definition: mythcecadapter.cpp:87
MythMainWindow::ResetScreensaver
static void ResetScreensaver()
Definition: mythmainwindow.cpp:588
MythCECAdapter::HandleActions
void HandleActions(MythCECActions Actions)
Definition: mythcecadapter.cpp:713
POWEROFFTV_ONEXIT
#define POWEROFFTV_ONEXIT
Definition: mythcecadapter.h:12
mythmainwindow.h
MythCECAdapter::HandleAlert
static int HandleAlert(libcec_alert Alert, libcec_parameter Data)
Definition: mythcecadapter.cpp:648
MythCECAdapter
Definition: mythcecadapter.h:23
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:922