+ if (m_iLogicalAddress == CECDEVICE_BROADCAST)
+ return false;
+
+ bool bInitHandler(false);
+ {
+ CLockObject lock(m_mutex);
+ CLockObject handlerLock(m_handlerMutex);
+ if (m_iHandlerUseCount > 0)
+ return false;
+
+ MarkBusy();
+
+ if (m_vendor != m_handler->GetVendorId())
+ {
+ if (CCECCommandHandler::HasSpecificHandler(m_vendor))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
+
+ int32_t iTransmitTimeout = m_handler->m_iTransmitTimeout;
+ int32_t iTransmitWait = m_handler->m_iTransmitWait;
+ int8_t iTransmitRetries = m_handler->m_iTransmitRetries;
+ int64_t iActiveSourcePending = m_handler->m_iActiveSourcePending;
+
+ DELETE_AND_NULL(m_handler);
+
+ switch (m_vendor)
+ {
+ case CEC_VENDOR_SAMSUNG:
+ m_handler = new CANCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_LG:
+ m_handler = new CSLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_PANASONIC:
+ m_handler = new CVLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_PHILIPS:
+ m_handler = new CPHCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_TOSHIBA:
+ case CEC_VENDOR_TOSHIBA2:
+ m_handler = new CRLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_ONKYO:
+ m_handler = new CRHCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ case CEC_VENDOR_SHARP:
+ m_handler = new CAQCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ default:
+ m_handler = new CCECCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+ break;
+ }
+
+ m_handler->SetVendorId(m_vendor);
+ bInitHandler = true;
+ }
+ }
+ }
+
+ if (bInitHandler)
+ {
+ CCECBusDevice *primary = GetProcessor()->GetPrimaryDevice();
+ if (primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED)
+ {
+ m_handler->InitHandler();
+
+ if (bActivateSource && IsHandledByLibCEC() && IsActiveSource())
+ m_handler->ActivateSource();
+ }
+ }
+
+ MarkReady();
+
+ return true;
+}
+
+CCECCommandHandler *CCECBusDevice::GetHandler(void)
+{
+ ReplaceHandler(false);
+ MarkBusy();
+ return m_handler;
+}
+
+bool CCECBusDevice::HandleCommand(const cec_command &command)
+{
+ bool bHandled(false);
+
+ /* update "last active" */
+ {
+ CLockObject lock(m_mutex);
+ m_iLastActive = GetTimeMs();
+ MarkBusy();
+ }
+
+ /* handle the command */
+ bHandled = m_handler->HandleCommand(command);
+
+ /* change status to present */
+ if (bHandled && GetLogicalAddress() != CECDEVICE_BROADCAST && command.opcode_set == 1)
+ {
+ CLockObject lock(m_mutex);
+ if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+ {
+ if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
+ m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
+ }
+ }
+
+ MarkReady();
+ return bHandled;
+}
+
+const char* CCECBusDevice::GetLogicalAddressName(void) const
+{
+ return ToString(m_iLogicalAddress);
+}
+
+bool CCECBusDevice::IsPresent(void)
+{
+ CLockObject lock(m_mutex);
+ return m_deviceStatus == CEC_DEVICE_STATUS_PRESENT;
+}
+
+bool CCECBusDevice::IsHandledByLibCEC(void)
+{
+ CLockObject lock(m_mutex);
+ return m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC;
+}
+
+void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
+{
+ // some commands should never be marked as unsupported
+ if (opcode == CEC_OPCODE_VENDOR_COMMAND ||
+ opcode == CEC_OPCODE_VENDOR_COMMAND_WITH_ID ||
+ opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN ||
+ opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP ||
+ opcode == CEC_OPCODE_ABORT ||
+ opcode == CEC_OPCODE_FEATURE_ABORT ||
+ opcode == CEC_OPCODE_NONE ||
+ opcode == CEC_OPCODE_USER_CONTROL_PRESSED ||
+ opcode == CEC_OPCODE_USER_CONTROL_RELEASE)
+ return;
+
+ {
+ CLockObject lock(m_mutex);
+ if (m_unsupportedFeatures.find(opcode) == m_unsupportedFeatures.end())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking opcode '%s' as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
+ m_unsupportedFeatures.insert(opcode);
+ }
+ }
+
+ // signal threads that are waiting for a reponse
+ MarkBusy();
+ SignalOpcode(cec_command::GetResponseOpcode(opcode));
+ MarkReady();
+}
+
+bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode)
+{
+ CLockObject lock(m_mutex);
+ bool bUnsupported = (m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end());
+ if (bUnsupported)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "'%s' is marked as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
+ return bUnsupported;
+}
+
+bool CCECBusDevice::TransmitKeypress(const cec_logical_address initiator, cec_user_control_code key, bool bWait /* = true */)
+{
+ MarkBusy();
+ bool bReturn = m_handler->TransmitKeypress(initiator, m_iLogicalAddress, key, bWait);
+ MarkReady();
+ return bReturn;