+ {
+ CLockObject lock(m_mutex);
+ if (m_bActiveSource)
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+ m_bActiveSource = false;
+ }
+
+ if (MyLogicalAddressContains(m_iLogicalAddress))
+ SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+}
+
+void CCECBusDevice::SetActiveSource(void)
+{
+ CLockObject lock(m_mutex);
+ if (!m_bActiveSource)
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
+
+ for (int iPtr = 0; iPtr < 16; iPtr++)
+ if (iPtr != m_iLogicalAddress)
+ m_processor->m_busDevices[iPtr]->SetInactiveSource();
+
+ m_bActiveSource = true;
+ SetPowerStatus(CEC_POWER_STATUS_ON);
+}
+
+bool CCECBusDevice::TryLogicalAddress(void)
+{
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
+
+ m_processor->SetAckMask(0);
+ if (!TransmitPoll(m_iLogicalAddress))
+ {
+ CLibCEC::AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
+ SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+
+ return true;
+ }
+
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
+ SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
+ return false;
+}
+
+void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
+{
+ CLockObject lock(m_mutex);
+ switch (newStatus)
+ {
+ case CEC_DEVICE_STATUS_UNKNOWN:
+ if (m_deviceStatus != newStatus)
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'unknown'", ToString(m_iLogicalAddress));
+ m_iStreamPath = 0;
+ m_powerStatus = CEC_POWER_STATUS_UNKNOWN;
+ m_vendor = CEC_VENDOR_UNKNOWN;
+ m_menuState = CEC_MENU_STATE_ACTIVATED;
+ m_bActiveSource = false;
+ m_iLastActive = 0;
+ m_cecVersion = CEC_VERSION_UNKNOWN;
+ m_deviceStatus = newStatus;
+ break;
+ case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
+ if (m_deviceStatus != newStatus)
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'handled by libCEC'", ToString(m_iLogicalAddress));
+ m_iStreamPath = 0;
+ m_powerStatus = CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON;
+ m_vendor = CEC_VENDOR_UNKNOWN;
+ m_menuState = CEC_MENU_STATE_ACTIVATED;
+ m_bActiveSource = false;
+ m_iLastActive = 0;
+ m_cecVersion = CEC_VERSION_1_3A;
+ m_deviceStatus = newStatus;
+ break;
+ case CEC_DEVICE_STATUS_PRESENT:
+ if (m_deviceStatus != newStatus)
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'present'", ToString(m_iLogicalAddress));
+ m_deviceStatus = newStatus;
+ break;
+ case CEC_DEVICE_STATUS_NOT_PRESENT:
+ if (m_deviceStatus != newStatus)
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'not present'", ToString(m_iLogicalAddress));
+ m_deviceStatus = newStatus;
+ break;
+ }
+}
+
+void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
+{
+ CLockObject lock(m_mutex);
+ if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
+ {
+ CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
+ m_iPhysicalAddress = iNewAddress;
+ }
+}
+
+void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = 0 */)
+{
+ CLockObject lock(m_mutex);
+ if (iNewAddress > 0)
+ {
+ CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
+ m_iStreamPath = iNewAddress;
+
+ if (iNewAddress > 0)
+ {
+ lock.Unlock();
+ SetPowerStatus(CEC_POWER_STATUS_ON);
+ }
+ }
+}
+
+void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
+{
+ CLockObject lock(m_mutex);
+ if (m_powerStatus != powerStatus)
+ {
+ m_iLastPowerStateUpdate = GetTimeMs();
+ CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
+ m_powerStatus = powerStatus;
+ }
+}
+
+void CCECBusDevice::MarkBusy(void)
+{
+ CLockObject handlerLock(m_handlerMutex);
+ ++m_iHandlerUseCount;
+}
+
+void CCECBusDevice::MarkReady(void)
+{
+ CLockObject handlerLock(m_handlerMutex);
+ if (m_iHandlerUseCount > 0)
+ --m_iHandlerUseCount;
+}
+
+bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
+{
+ bool bInitHandler(false);
+ {
+ CTryLockObject lock(m_mutex);
+ if (!lock.IsLocked())
+ return false;
+
+ CLockObject handlerLock(m_handlerMutex);
+ if (m_iHandlerUseCount > 0)
+ return false;
+
+ MarkBusy();
+
+ if (m_vendor != m_handler->GetVendorId())
+ {
+ if (CCECCommandHandler::HasSpecificHandler(m_vendor))
+ {
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
+ delete m_handler;
+
+ switch (m_vendor)
+ {
+ case CEC_VENDOR_SAMSUNG:
+ m_handler = new CANCommandHandler(this);
+ break;
+ case CEC_VENDOR_LG:
+ m_handler = new CSLCommandHandler(this);
+ break;
+ case CEC_VENDOR_PANASONIC:
+ m_handler = new CVLCommandHandler(this);
+ break;
+ default:
+ m_handler = new CCECCommandHandler(this);
+ break;
+ }
+
+ m_handler->SetVendorId(m_vendor);
+ bInitHandler = true;
+ }
+ }
+ }
+
+ if (bInitHandler)
+ {
+ m_handler->InitHandler();
+
+ if (bActivateSource && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised() && IsActiveSource())
+ m_handler->ActivateSource();
+ }
+
+ MarkReady();
+
+ return true;
+}
+
+bool CCECBusDevice::SetVendorId(uint64_t iVendorId)
+{
+ bool bVendorChanged(false);
+
+ {
+ CLockObject lock(m_mutex);
+ bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
+ m_vendor = (cec_vendor_id)iVendorId;
+ }
+
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
+
+ return bVendorChanged;
+}
+//@}
+
+/** @name Transmit methods */
+//@{
+bool CCECBusDevice::TransmitActiveSource(void)
+{
+ bool bSendActiveSource(false);
+
+ {
+ CLockObject lock(m_mutex);
+ if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+ else if (m_bActiveSource)
+ {
+ CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+ bSendActiveSource = true;
+ }
+ else
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
+ }
+
+ if (bSendActiveSource)
+ {
+ MarkBusy();
+ m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
+ MarkReady();
+ return true;
+ }
+
+ return false;
+}
+
+bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest)
+{
+ cec_version version;
+ {
+ CLockObject lock(m_mutex);
+ CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_cecVersion));
+ version = m_cecVersion;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, dest, version);
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitImageViewOn(void)
+{
+ {
+ CLockObject lock(m_mutex);
+ if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
+ {
+ CLibCEC::AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+ return false;
+ }
+ }
+
+ MarkBusy();
+ m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
+ MarkReady();