2 #include <QApplication>
20 #include <libcec/cecloader.h>
23 #define LOC QString("CECAdapter: ")
25 #if CEC_LIB_VERSION_MAJOR <= 3
85 return QString(
"%1.%2.%3.%4").arg((Address >> 12) & 0xF).arg((Address >> 8) & 0xF)
86 .arg((Address >> 4) & 0xF).arg(Address & 0xF);
101 LOG(VB_GENERAL, LOG_INFO,
LOC +
"libCEC support is disabled.");
121 libcec_configuration configuration;
122 strcpy(configuration.strDeviceName,
"MythTV");
123 configuration.deviceTypes.Add(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
125 if (
"auto" != base_dev)
127 int base = base_dev.toInt();
128 if (base >= 0 && base < CECDEVICE_BROADCAST)
129 configuration.baseDevice =
static_cast<cec_logical_address
>(base);
131 if (
"auto" != hdmi_port)
133 int defaultHDMIPort = hdmi_port.toInt();
134 if (defaultHDMIPort >= CEC_MIN_HDMI_PORTNUMBER && defaultHDMIPort <= CEC_MAX_HDMI_PORTNUMBER)
135 configuration.iHDMIPort =
static_cast<uint8_t
>(defaultHDMIPort);
152 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Using physical address %1 from EDID")
154 configuration.iPhysicalAddress = address;
159 #if CEC_LIB_VERSION_MAJOR <= 3
172 configuration.callbackParam =
this;
176 m_adapter = LibCecInitialise(&configuration);
180 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to load libcec.");
189 #if CEC_LIB_VERSION_MAJOR >= 4
193 std::unique_ptr<cec_adapter_descriptor[]> cec_devices(devices);
200 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to find any CEC devices.");
207 bool find = defaultDevice !=
"auto";
209 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Found %1 CEC devices(s).")
211 for (uint8_t i = 0; i < num_devices; i++)
213 #if CEC_LIB_VERSION_MAJOR >= 4
214 QString comm = QString::fromLatin1(devices[i].strComName);
215 QString path = QString::fromLatin1(devices[i].strComPath);
217 QString comm = QString::fromLatin1(devices[i].comm);
218 QString path = QString::fromLatin1(devices[i].path);
220 bool match =
find ? (comm == defaultDevice) : (i == 0);
221 devicenum = match ? i : devicenum;
222 LOG(VB_GENERAL, LOG_INFO,
LOC +
223 QString(
"Device %1: path '%2' com port '%3' %4")
224 .arg(QString::number(i + 1),
225 path, comm, match ?
"SELECTED" :
""));
229 #if CEC_LIB_VERSION_MAJOR >= 4
230 QString comm = QString::fromLatin1(devices[devicenum].strComName);
231 QString path = QString::fromLatin1(devices[devicenum].strComPath);
233 QString comm = QString::fromLatin1(devices[devicenum].comm);
234 QString path = QString::fromLatin1(devices[devicenum].path);
236 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Trying to open device %1 (%2).")
239 #if CEC_LIB_VERSION_MAJOR >= 4
240 if (!
m_adapter->Open(devices[devicenum].strComName))
242 if (!
m_adapter->Open(devices[devicenum].comm))
245 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to open device.");
250 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Opened CEC device.");
271 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Closing down CEC.");
279 QString msg(Message.message);
280 LogLevel_t level = LOG_UNKNOWN;
281 switch (Message.level)
283 case CEC_LOG_ERROR: level = LOG_ERR;
break;
284 case CEC_LOG_WARNING: level = LOG_WARNING;
break;
285 case CEC_LOG_NOTICE: level = LOG_INFO;
break;
286 case CEC_LOG_DEBUG: level = LOG_DEBUG;
break;
289 LOG(VB_GENERAL, level,
LOC + QString(
"%1").arg(msg));
295 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Command %1 from '%2' (%3) - destination '%4' (%5)")
301 case CEC_OPCODE_MENU_REQUEST:
303 key.keycode = CEC_USER_CONTROL_CODE_ROOT_MENU;
325 Qt::KeyboardModifier modifier = Qt::NoModifier;
328 case CEC_USER_CONTROL_CODE_NUMBER0:
332 case CEC_USER_CONTROL_CODE_NUMBER1:
336 case CEC_USER_CONTROL_CODE_NUMBER2:
340 case CEC_USER_CONTROL_CODE_NUMBER3:
344 case CEC_USER_CONTROL_CODE_NUMBER4:
348 case CEC_USER_CONTROL_CODE_NUMBER5:
352 case CEC_USER_CONTROL_CODE_NUMBER6:
356 case CEC_USER_CONTROL_CODE_NUMBER7:
360 case CEC_USER_CONTROL_CODE_NUMBER8:
364 case CEC_USER_CONTROL_CODE_NUMBER9:
368 case CEC_USER_CONTROL_CODE_SELECT:
372 case CEC_USER_CONTROL_CODE_ENTER:
376 case CEC_USER_CONTROL_CODE_UP:
380 case CEC_USER_CONTROL_CODE_DOWN:
384 case CEC_USER_CONTROL_CODE_LEFT:
388 case CEC_USER_CONTROL_CODE_LEFT_UP:
392 case CEC_USER_CONTROL_CODE_LEFT_DOWN:
396 case CEC_USER_CONTROL_CODE_RIGHT:
400 case CEC_USER_CONTROL_CODE_RIGHT_UP:
404 case CEC_USER_CONTROL_CODE_RIGHT_DOWN:
408 case CEC_USER_CONTROL_CODE_ROOT_MENU:
412 case CEC_USER_CONTROL_CODE_AN_RETURN:
413 case CEC_USER_CONTROL_CODE_EXIT:
417 case CEC_USER_CONTROL_CODE_PREVIOUS_CHANNEL:
419 code =
"PREVIOUS_CHANNEL";
421 case CEC_USER_CONTROL_CODE_SOUND_SELECT:
423 code =
"SOUND_SELECT";
425 case CEC_USER_CONTROL_CODE_VOLUME_UP:
426 action = Qt::Key_VolumeUp;
429 case CEC_USER_CONTROL_CODE_VOLUME_DOWN:
430 action = Qt::Key_VolumeDown;
431 code =
"VOLUME_DOWN";
433 case CEC_USER_CONTROL_CODE_MUTE:
434 action = Qt::Key_VolumeMute;
437 case CEC_USER_CONTROL_CODE_PLAY:
441 modifier = Qt::ControlModifier;
443 case CEC_USER_CONTROL_CODE_PAUSE:
447 case CEC_USER_CONTROL_CODE_STOP:
451 case CEC_USER_CONTROL_CODE_RECORD:
455 case CEC_USER_CONTROL_CODE_CLEAR:
459 case CEC_USER_CONTROL_CODE_DISPLAY_INFORMATION:
461 code =
"DISPLAY_INFORMATION";
463 case CEC_USER_CONTROL_CODE_PAGE_UP:
467 case CEC_USER_CONTROL_CODE_PAGE_DOWN:
468 action = Qt::Key_PageDown;
471 case CEC_USER_CONTROL_CODE_EJECT:
475 case CEC_USER_CONTROL_CODE_FORWARD:
479 case CEC_USER_CONTROL_CODE_BACKWARD:
483 case CEC_USER_CONTROL_CODE_F1_BLUE:
487 case CEC_USER_CONTROL_CODE_F2_RED:
491 case CEC_USER_CONTROL_CODE_F3_GREEN:
495 case CEC_USER_CONTROL_CODE_F4_YELLOW:
499 case CEC_USER_CONTROL_CODE_SETUP_MENU:
503 case CEC_USER_CONTROL_CODE_CONTENTS_MENU:
505 code =
"CONTENTS_MENU";
507 case CEC_USER_CONTROL_CODE_FAVORITE_MENU:
509 code =
"FAVORITE_MENU";
511 case CEC_USER_CONTROL_CODE_DOT:
515 case CEC_USER_CONTROL_CODE_NEXT_FAVORITE:
517 code =
"NEXT_FAVORITE";
519 case CEC_USER_CONTROL_CODE_INPUT_SELECT:
521 code =
"INPUT_SELECT";
523 case CEC_USER_CONTROL_CODE_HELP:
527 case CEC_USER_CONTROL_CODE_STOP_RECORD:
529 code =
"STOP_RECORD";
531 case CEC_USER_CONTROL_CODE_SUB_PICTURE:
533 code =
"SUB_PICTURE";
535 case CEC_USER_CONTROL_CODE_ELECTRONIC_PROGRAM_GUIDE:
537 code =
"ELECTRONIC_PROGRAM_GUIDE";
539 case CEC_USER_CONTROL_CODE_POWER:
540 action = Qt::Key_PowerOff;
546 case CEC_USER_CONTROL_CODE_CHANNEL_DOWN:
548 code =
"CHANNEL_DOWN";
550 case CEC_USER_CONTROL_CODE_CHANNEL_UP:
554 case CEC_USER_CONTROL_CODE_REWIND:
558 case CEC_USER_CONTROL_CODE_FAST_FORWARD:
560 code =
"FAST_FORWARD";
562 case CEC_USER_CONTROL_CODE_ANGLE:
566 case CEC_USER_CONTROL_CODE_F5:
572 case CEC_USER_CONTROL_CODE_INITIAL_CONFIGURATION:
573 code =
"INITIAL_CONFIGURATION";
575 case CEC_USER_CONTROL_CODE_PAUSE_RECORD:
576 code =
"PAUSE_RECORD";
578 case CEC_USER_CONTROL_CODE_VIDEO_ON_DEMAND:
579 code =
"VIDEO_ON_DEMAND";
581 case CEC_USER_CONTROL_CODE_TIMER_PROGRAMMING:
582 code =
"TIMER_PROGRAMMING";
584 case CEC_USER_CONTROL_CODE_UNKNOWN:
587 case CEC_USER_CONTROL_CODE_DATA:
592 case CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION:
593 code =
"POWER_ON_FUNCTION";
595 case CEC_USER_CONTROL_CODE_PLAY_FUNCTION:
596 code =
"PLAY_FUNCTION";
598 case CEC_USER_CONTROL_CODE_PAUSE_PLAY_FUNCTION:
599 code =
"PAUSE_PLAY_FUNCTION";
601 case CEC_USER_CONTROL_CODE_RECORD_FUNCTION:
602 code =
"RECORD_FUNCTION";
604 case CEC_USER_CONTROL_CODE_PAUSE_RECORD_FUNCTION:
605 code =
"PAUSE_RECORD_FUNCTION";
607 case CEC_USER_CONTROL_CODE_STOP_FUNCTION:
608 code =
"STOP_FUNCTION";
610 case CEC_USER_CONTROL_CODE_MUTE_FUNCTION:
611 code =
"MUTE_FUNCTION";
613 case CEC_USER_CONTROL_CODE_RESTORE_VOLUME_FUNCTION:
614 code =
"RESTORE_VOLUME_FUNCTION";
616 case CEC_USER_CONTROL_CODE_TUNE_FUNCTION:
617 code =
"TUNE_FUNCTION";
619 case CEC_USER_CONTROL_CODE_SELECT_MEDIA_FUNCTION:
620 code =
"SELECT_MEDIA_FUNCTION";
622 case CEC_USER_CONTROL_CODE_SELECT_AV_INPUT_FUNCTION:
623 code =
"SELECT_AV_INPUT_FUNCTION";
625 case CEC_USER_CONTROL_CODE_SELECT_AUDIO_INPUT_FUNCTION:
626 code =
"SELECT_AUDIO_INPUT_FUNCTION";
628 case CEC_USER_CONTROL_CODE_POWER_TOGGLE_FUNCTION:
629 code =
"POWER_TOGGLE_FUNCTION";
631 case CEC_USER_CONTROL_CODE_POWER_OFF_FUNCTION:
632 code =
"POWER_OFF_FUNCTION";
636 code = QString(
"UNKNOWN_FUNCTION_%1").arg(Key.keycode);
640 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"Keypress %1 %2")
641 .arg(code, 0 ==
action ?
"(Not actioned)" :
""));
647 auto* ke =
new QKeyEvent(QEvent::KeyPress,
action, modifier);
662 switch (Data.paramType)
664 case CEC_PARAMETER_TYPE_STRING:
665 param = QString(
": %1").arg(
static_cast<char*
>(Data.paramData));
667 case CEC_PARAMETER_TYPE_UNKOWN:
668 if (Data.paramData !=
nullptr)
669 param = QString(
": UNKNOWN param has type %1").arg(Data.paramType);
678 #if CEC_LIB_VERSION_MAJOR == 2 && CEC_LIB_VERSION_MINOR < 1
680 #define CEC_ALERT_PHYSICAL_ADDRESS_ERROR 4
682 #if CEC_LIB_VERSION_MAJOR == 2 && CEC_LIB_VERSION_MINOR < 2
684 #define CEC_ALERT_TV_POLL_FAILED 5
688 case CEC_ALERT_SERVICE_DEVICE:
689 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"CEC device service message") + param);
691 case CEC_ALERT_CONNECTION_LOST:
692 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"CEC device connection list") + param);
694 case CEC_ALERT_PERMISSION_ERROR:
695 case CEC_ALERT_PORT_BUSY:
699 case CEC_ALERT_PHYSICAL_ADDRESS_ERROR:
700 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"CEC physical address error") + param);
702 case CEC_ALERT_TV_POLL_FAILED:
703 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"CEC device can't poll TV") + param);
711 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Source %1 %2")
712 .arg(Address).arg(Activated ?
"Activated" :
"Deactivated"));
725 if (
m_adapter->StandbyDevices(CECDEVICE_TV))
726 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Asked TV to turn off.");
728 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to turn TV off.");
733 if (
m_adapter->PowerOnDevices(CECDEVICE_TV))
734 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Asked TV to turn on.");
736 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to turn TV on.");
743 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Asked TV to switch to this input.");
745 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to switch to this input.");