+
+bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort, bool bIsReply)
+{
+ bool bReturn(false);
+ uint64_t iVendorId;
+ {
+ CLockObject lock(m_mutex);
+ iVendorId = (uint64_t)m_vendor;
+ }
+
+ MarkBusy();
+ if (iVendorId == CEC_VENDOR_UNKNOWN)
+ {
+ if (bSendAbort)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
+ m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+ bReturn = true;
+ }
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString((cec_vendor_id)iVendorId), iVendorId);
+ bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, destination, iVendorId, bIsReply);
+ }
+ MarkReady();
+ return bReturn;
+}
+
+cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bool bSuppressPoll /* = false */)
+{
+ if (m_iLogicalAddress == CECDEVICE_BROADCAST)
+ return CEC_DEVICE_STATUS_NOT_PRESENT;
+
+ cec_bus_device_status status(CEC_DEVICE_STATUS_UNKNOWN);
+ bool bNeedsPoll(false);
+
+ {
+ CLockObject lock(m_mutex);
+ status = m_deviceStatus;
+ bNeedsPoll = !bSuppressPoll &&
+ m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC &&
+ // poll forced
+ (bForcePoll ||
+ // don't know the status
+ m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN ||
+ // always poll the TV if it's marked as not present
+ (m_deviceStatus == CEC_DEVICE_STATUS_NOT_PRESENT && m_iLogicalAddress == CECDEVICE_TV));
+ }
+
+ if (bNeedsPoll)
+ {
+ bool bPollAcked(false);
+ if (bNeedsPoll)
+ bPollAcked = m_processor->PollDevice(m_iLogicalAddress);
+
+ status = bPollAcked ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT;
+ SetDeviceStatus(status);
+ }
+
+ return status;
+}
+
+void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus, cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */)
+{
+ if (m_iLogicalAddress == CECDEVICE_UNREGISTERED)
+ return;
+
+ {
+ CLockObject lock(m_mutex);
+ switch (newStatus)
+ {
+ case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
+ if (m_deviceStatus != newStatus)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'handled by libCEC'", GetLogicalAddressName(), m_iLogicalAddress);
+ SetPowerStatus (CEC_POWER_STATUS_ON);
+ SetVendorId (CEC_VENDOR_UNKNOWN);
+ SetMenuState (CEC_MENU_STATE_ACTIVATED);
+ SetCecVersion (libCECSpecVersion);
+ SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
+ MarkAsInactiveSource();
+ m_iLastActive = 0;
+ m_deviceStatus = newStatus;
+ break;
+ case CEC_DEVICE_STATUS_PRESENT:
+ if (m_deviceStatus != newStatus)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'present'", GetLogicalAddressName(), m_iLogicalAddress);
+ m_deviceStatus = newStatus;
+ m_iLastActive = GetTimeMs();
+ break;
+ case CEC_DEVICE_STATUS_NOT_PRESENT:
+ if (m_deviceStatus != newStatus)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'not present'", GetLogicalAddressName(), m_iLogicalAddress);
+ ResetDeviceStatus(true);
+ m_deviceStatus = newStatus;
+ }
+ break;
+ default:
+ ResetDeviceStatus();
+ break;
+ }
+ }
+}
+
+void CCECBusDevice::ResetDeviceStatus(bool bClientUnregistered /* = false */)
+{
+ CLockObject lock(m_mutex);
+ SetPowerStatus (CEC_POWER_STATUS_UNKNOWN);
+ SetVendorId (CEC_VENDOR_UNKNOWN);
+ SetMenuState (CEC_MENU_STATE_ACTIVATED);
+ SetCecVersion (CEC_VERSION_UNKNOWN);
+ SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
+ SetOSDName (ToString(m_iLogicalAddress));
+ MarkAsInactiveSource(bClientUnregistered);
+
+ m_iLastActive = 0;
+ m_bVendorIdRequested = false;
+ m_unsupportedFeatures.clear();
+ m_waitForResponse->Clear();
+
+ if (m_deviceStatus != CEC_DEVICE_STATUS_UNKNOWN)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'unknown'", GetLogicalAddressName(), m_iLogicalAddress);
+ m_deviceStatus = CEC_DEVICE_STATUS_UNKNOWN;
+}
+
+bool CCECBusDevice::TransmitPoll(const cec_logical_address dest, bool bUpdateDeviceStatus)
+{
+ bool bReturn(false);
+ cec_logical_address destination(dest);
+ if (destination == CECDEVICE_UNKNOWN)
+ destination = m_iLogicalAddress;
+
+ CCECBusDevice *destDevice = m_processor->GetDevice(destination);
+ if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+ return bReturn;
+
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
+ bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination, false);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
+
+ if (bUpdateDeviceStatus)
+ destDevice->SetDeviceStatus(bReturn ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT);
+
+ MarkReady();
+ return bReturn;
+}
+
+void CCECBusDevice::HandlePoll(const cec_logical_address destination)
+{
+ if (destination >= 0 && destination < CECDEVICE_BROADCAST)
+ {
+ CCECBusDevice *device = m_processor->GetDevice(destination);
+ if (device)
+ device->HandlePollFrom(m_iLogicalAddress);
+ }
+}
+
+void CCECBusDevice::HandlePollFrom(const cec_logical_address initiator)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
+ m_bAwaitingReceiveFailed = true;
+}
+
+bool CCECBusDevice::HandleReceiveFailed(void)
+{
+ bool bReturn = m_bAwaitingReceiveFailed;
+ m_bAwaitingReceiveFailed = false;
+ return bReturn;
+}
+
+cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
+{
+ CLockObject lock(m_mutex);
+ return m_menuState;
+}
+
+void CCECBusDevice::SetMenuState(const cec_menu_state state)
+{
+ CLockObject lock(m_mutex);
+ if (m_menuState != state)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
+ m_menuState = state;
+ }
+}
+
+bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest, bool bIsReply)
+{
+ cec_menu_state menuState;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
+ menuState = m_menuState;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState, bIsReply);
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::ActivateSource(uint64_t iDelay /* = 0 */)
+{
+ MarkAsActiveSource();
+ MarkBusy();
+ bool bReturn(true);
+ if (iDelay == 0)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending active source message for '%s'", ToString(m_iLogicalAddress));
+ bReturn = m_handler->ActivateSource();
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "scheduling active source message for '%s'", ToString(m_iLogicalAddress));
+ m_handler->ScheduleActivateSource(iDelay);
+ }
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
+{
+ bool bReturn(false);
+
+ if (IsHandledByLibCEC())
+ {
+ MarkBusy();
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting active source");
+
+ bReturn = m_handler->TransmitRequestActiveSource(m_iLogicalAddress, bWaitForResponse);
+ MarkReady();
+ }
+ return bReturn;
+}
+
+void CCECBusDevice::MarkAsActiveSource(void)
+{
+ bool bWasActivated(false);
+
+ // set the power status to powered on
+ SetPowerStatus(CEC_POWER_STATUS_ON);
+
+ // mark this device as active source
+ {
+ CLockObject lock(m_mutex);
+ if (!m_bActiveSource)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
+ bWasActivated = true;
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
+
+ m_bActiveSource = true;
+ }
+
+ CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+ if (tv)
+ tv->OnImageViewOnSent(false);
+
+ // mark other devices as inactive sources
+ CECDEVICEVEC devices;
+ m_processor->GetDevices()->Get(devices);
+ for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+ if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
+ (*it)->MarkAsInactiveSource();
+
+ if (bWasActivated)
+ {
+ if (IsHandledByLibCEC())
+ m_processor->SetActiveSource(true, false);
+ CCECClient *client = GetClient();
+ if (client)
+ client->SourceActivated(m_iLogicalAddress);
+ }
+}
+
+void CCECBusDevice::MarkAsInactiveSource(bool bClientUnregistered /* = false */)
+{
+ bool bWasDeactivated(false);
+ {
+ CLockObject lock(m_mutex);
+ if (m_bActiveSource)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+ bWasDeactivated = true;
+ }
+ m_bActiveSource = false;
+ }
+
+ if (bWasDeactivated)
+ {
+ if (IsHandledByLibCEC())
+ m_processor->SetActiveSource(false, bClientUnregistered);
+ CCECClient *client = GetClient();
+ if (client)
+ client->SourceDeactivated(m_iLogicalAddress);
+ }
+}
+
+bool CCECBusDevice::TransmitActiveSource(bool bIsReply)
+{
+ bool bSendActiveSource(false);
+ uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
+
+ {
+ CLockObject lock(m_mutex);
+ if (!HasValidPhysicalAddress())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X) has an invalid physical address (%04x), not sending active source commands", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+ return false;
+ }
+
+ iPhysicalAddress = m_iPhysicalAddress;
+
+ if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+ else if (m_bActiveSource)
+ {
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+ bSendActiveSource = true;
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
+ }
+
+ bool bActiveSourceSent(false);
+ if (bSendActiveSource)
+ {
+ MarkBusy();
+ bActiveSourceSent = m_handler->TransmitActiveSource(m_iLogicalAddress, iPhysicalAddress, bIsReply);
+ MarkReady();
+ }
+
+ return bActiveSourceSent;
+}
+
+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)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+ return false;
+ }
+ }
+
+ CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+ if (!tv)
+ {
+ LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - couldn't get TV instance", __FUNCTION__);
+ return false;
+ }
+
+ if (tv->ImageViewOnSent())
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - 'image view on' already sent", __FUNCTION__);
+ return true;
+ }
+
+ bool bImageViewOnSent(false);
+ MarkBusy();
+ bImageViewOnSent = m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
+ MarkReady();
+
+ if (bImageViewOnSent)
+ tv->OnImageViewOnSent(true);
+
+ return bImageViewOnSent;
+}
+
+bool CCECBusDevice::TransmitInactiveSource(void)
+{
+ uint16_t iPhysicalAddress;
+ {
+ CLockObject lock(m_mutex);
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+ iPhysicalAddress = m_iPhysicalAddress;
+ }
+
+ MarkBusy();
+ bool bReturn = m_handler->TransmitInactiveSource(m_iLogicalAddress, iPhysicalAddress);
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
+{
+ MarkBusy();
+ bool bReturn = m_handler->ActivateSource(true);
+ MarkReady();
+ return bReturn;
+}
+
+void CCECBusDevice::SetActiveRoute(uint16_t iRoute)
+{
+ SetPowerStatus(CEC_POWER_STATUS_ON);
+
+ CCECDeviceMap* map = m_processor->GetDevices();
+ if (!map)
+ return;
+
+ CCECBusDevice* newRoute = m_processor->GetDeviceByPhysicalAddress(iRoute, true);
+ if (newRoute && newRoute->IsHandledByLibCEC())
+ {
+ // we were made the active source, send notification
+ newRoute->ActivateSource();
+ }
+}
+
+void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
+{
+ if (iNewAddress != CEC_INVALID_PHYSICAL_ADDRESS)
+ SetPowerStatus(CEC_POWER_STATUS_ON);
+
+ CLockObject lock(m_mutex);
+ if (iNewAddress != m_iStreamPath)
+ {
+ LIB_CEC->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 (!LIB_CEC->IsValidPhysicalAddress(iNewAddress))
+ return;
+
+ CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
+ if (device)
+ {
+ // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
+ device->MarkAsActiveSource();
+
+ // respond with an active source message if this device is handled by libCEC
+ if (device->IsHandledByLibCEC())
+ device->TransmitActiveSource(true);
+ }
+ else
+ {
+ // try to find the device with the old address, and mark it as inactive when found
+ device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
+ if (device)
+ device->MarkAsInactiveSource();
+ }
+}
+
+bool CCECBusDevice::PowerOn(const cec_logical_address initiator)
+{
+ bool bReturn(false);
+ GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
+
+ MarkBusy();
+ cec_power_status currentStatus;
+ if (m_iLogicalAddress == CECDEVICE_TV ||
+ ((currentStatus = GetPowerStatus(initiator, false)) != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
+ currentStatus != CEC_POWER_STATUS_ON))
+ {
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+ bReturn = m_handler->PowerOn(initiator, m_iLogicalAddress);
+ }
+ else
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
+ }
+
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::Standby(const cec_logical_address initiator)
+{
+ GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
+
+ LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
+ MarkBusy();
+ bool bReturn = m_handler->TransmitStandby(initiator, m_iLogicalAddress);
+ MarkReady();
+ return bReturn;
+}
+
+bool CCECBusDevice::NeedsPoll(void)
+{
+ bool bSendPoll(false);
+ cec_logical_address pollAddress(CECDEVICE_UNKNOWN);
+ switch (m_iLogicalAddress)
+ {
+ case CECDEVICE_PLAYBACKDEVICE3:
+ pollAddress = CECDEVICE_PLAYBACKDEVICE2;
+ break;
+ case CECDEVICE_PLAYBACKDEVICE2:
+ pollAddress = CECDEVICE_PLAYBACKDEVICE1;
+ break;
+ case CECDEVICE_RECORDINGDEVICE3:
+ pollAddress = CECDEVICE_RECORDINGDEVICE2;
+ break;
+ case CECDEVICE_RECORDINGDEVICE2:
+ pollAddress = CECDEVICE_RECORDINGDEVICE1;
+ break;
+ case CECDEVICE_TUNER4:
+ pollAddress = CECDEVICE_TUNER3;
+ break;
+ case CECDEVICE_TUNER3:
+ pollAddress = CECDEVICE_TUNER2;
+ break;
+ case CECDEVICE_TUNER2:
+ pollAddress = CECDEVICE_TUNER1;
+ break;
+ case CECDEVICE_AUDIOSYSTEM:
+ case CECDEVICE_PLAYBACKDEVICE1:
+ case CECDEVICE_RECORDINGDEVICE1:
+ case CECDEVICE_TUNER1:
+ case CECDEVICE_TV:
+ bSendPoll = true;
+ break;
+ default:
+ break;
+ }
+
+ if (!bSendPoll && pollAddress != CECDEVICE_UNKNOWN)
+ {
+ CCECBusDevice *device = m_processor->GetDevice(pollAddress);
+ if (device)
+ {
+ cec_bus_device_status status = device->GetStatus();
+ bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+ }
+ else
+ {
+ bSendPoll = true;
+ }
+ }
+
+ return bSendPoll;
+}
+
+void CCECBusDevice::CheckVendorIdRequested(const cec_logical_address initiator)
+{
+ bool bRequestVendorId(false);
+ {
+ CLockObject lock(m_mutex);
+ bRequestVendorId = !m_bVendorIdRequested;
+ m_bVendorIdRequested = true;
+ }
+
+ if (bRequestVendorId)
+ {
+ ReplaceHandler(false);
+ GetVendorId(initiator);
+ }
+}
+//@}
+
+CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
+{
+ return AsAudioSystem(this);
+}
+
+CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
+{
+ return AsPlaybackDevice(this);
+}
+
+CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
+{
+ return AsRecordingDevice(this);
+}
+
+CCECTuner *CCECBusDevice::AsTuner(void)
+{
+ return AsTuner(this);
+}
+
+CCECTV *CCECBusDevice::AsTV(void)
+{
+ return AsTV(this);
+}
+
+CCECAudioSystem *CCECBusDevice::AsAudioSystem(CCECBusDevice *device)
+{
+ if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+ return static_cast<CCECAudioSystem *>(device);
+ return NULL;
+}
+
+CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(CCECBusDevice *device)
+{
+ if (device &&
+ (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
+ device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+ return static_cast<CCECPlaybackDevice *>(device);
+ return NULL;
+}
+
+CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(CCECBusDevice *device)
+{
+ if (device && device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+ return static_cast<CCECRecordingDevice *>(device);
+ return NULL;
+}
+
+CCECTuner *CCECBusDevice::AsTuner(CCECBusDevice *device)
+{
+ if (device && device->GetType() == CEC_DEVICE_TYPE_TUNER)
+ return static_cast<CCECTuner *>(device);
+ return NULL;
+}
+
+CCECTV *CCECBusDevice::AsTV(CCECBusDevice *device)
+{
+ if (device && device->GetType() == CEC_DEVICE_TYPE_TV)
+ return static_cast<CCECTV *>(device);
+ return NULL;
+}
+
+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::TryLogicalAddress(cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */)
+{
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
+
+ if (!TransmitPoll(m_iLogicalAddress, false))
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "using logical address '%s'", GetLogicalAddressName());
+ SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC, libCECSpecVersion);
+
+ return true;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
+ SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
+ return false;
+}
+
+CCECClient *CCECBusDevice::GetClient(void)
+{
+ return m_processor->GetClient(m_iLogicalAddress);
+}
+
+void CCECBusDevice::SignalOpcode(cec_opcode opcode)
+{
+ m_waitForResponse->Received(opcode);
+}
+
+bool CCECBusDevice::WaitForOpcode(cec_opcode opcode)
+{
+ return m_waitForResponse->Wait(opcode);
+}