From 42d28d15d07f893b491051970ade1bd56bb596eb Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Sun, 10 Jun 2012 11:14:45 +0200 Subject: [PATCH] cec: get the vendor id of the TV before allocating logical addresses, so we can determine if the TV supports the requested device type directly. for panasonic, this means that a playback device will be allocated directly, instead of allocating a recording device first and switching to playback device afterwards, which may possibly confuse the tv --- src/lib/CECClient.cpp | 33 ++++++++++++++++++-- src/lib/CECClient.h | 5 +++ src/lib/CECProcessor.cpp | 11 +++++++ src/lib/devices/CECBusDevice.cpp | 10 ++++-- src/lib/implementations/CECCommandHandler.h | 2 ++ src/lib/implementations/RLCommandHandler.cpp | 25 ++++++++------- src/lib/implementations/SLCommandHandler.cpp | 31 +++++++++--------- src/lib/implementations/VLCommandHandler.cpp | 28 +++++++++-------- src/lib/implementations/VLCommandHandler.h | 2 ++ 9 files changed, 101 insertions(+), 46 deletions(-) diff --git a/src/lib/CECClient.cpp b/src/lib/CECClient.cpp index ae0b9f6..7cf542b 100644 --- a/src/lib/CECClient.cpp +++ b/src/lib/CECClient.cpp @@ -37,6 +37,7 @@ #include "devices/CECPlaybackDevice.h" #include "devices/CECAudioSystem.h" #include "devices/CECTV.h" +#include "implementations/CECCommandHandler.h" using namespace CEC; using namespace PLATFORM; @@ -120,9 +121,6 @@ bool CCECClient::OnRegister(void) // set the physical address SetPhysicalAddress(m_configuration); - // ensure that we know the vendor id of the TV, so we are using the correct handler - m_processor->GetTV()->GetVendorId(GetPrimaryLogicalAdddress()); - // make the primary device the active source if the option is set if (m_configuration.bActivateSource == 1) GetPrimaryDevice()->ActivateSource(); @@ -250,11 +248,40 @@ bool CCECClient::SetPhysicalAddress(const uint16_t iPhysicalAddress) return true; } +void CCECClient::SetSupportedDeviceTypes(void) +{ + cec_device_type_list types; + types.Clear(); + + // get the command handler for the tv + CCECCommandHandler *tvHandler = m_processor->GetTV()->GetHandler(); + if (!tvHandler) + return; + + // check all device types + for (uint8_t iPtr = 0; iPtr < 5; iPtr++) + { + if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED) + continue; + + // get the supported device type. the handler will replace types it doesn't support by one it does support + cec_device_type type = tvHandler->GetReplacementDeviceType(m_configuration.deviceTypes.types[iPtr]); + if (!types.IsSet(type)) + types.Add(type); + } + + // set the new type list + m_configuration.deviceTypes = types; +} + bool CCECClient::AllocateLogicalAddresses(void) { // reset all previous LAs that were set m_configuration.logicalAddresses.Clear(); + // get the supported device types from the command handler of the TV + SetSupportedDeviceTypes(); + // display an error if no device types are set if (m_configuration.deviceTypes.IsEmpty()) { diff --git a/src/lib/CECClient.h b/src/lib/CECClient.h index 3d812f0..87a4b7f 100644 --- a/src/lib/CECClient.h +++ b/src/lib/CECClient.h @@ -292,6 +292,11 @@ namespace CEC */ virtual bool AutodetectPhysicalAddress(void); + /*! + * @brief Replaces all device types in m_configuration by types that are supported by the command handler of the TV + */ + virtual void SetSupportedDeviceTypes(void); + CCECProcessor * m_processor; /**< a pointer to the processor */ libcec_configuration m_configuration; /**< the configuration of this client */ bool m_bInitialised; /**< true when initialised, false otherwise */ diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 0012a53..034c7e6 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -645,6 +645,9 @@ bool CCECProcessor::RegisterClient(CCECClient *client) return false; } + // ensure that we know the vendor id of the TV + GetTV()->GetVendorId(CECDEVICE_UNREGISTERED); + // unregister the client first if it's already been marked as registered if (client->IsRegistered()) UnregisterClient(client); @@ -720,6 +723,14 @@ bool CCECProcessor::RegisterClient(CCECClient *client) client->Alert(CEC_ALERT_SERVICE_DEVICE, param); } + // ensure that the command handler for the TV is initialised + if (bReturn) + { + CCECCommandHandler *handler = GetTV()->GetHandler(); + if (handler) + handler->InitHandler(); + } + return bReturn; } diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 686988c..6fd0770 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -133,10 +133,14 @@ bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */) if (bInitHandler) { - m_handler->InitHandler(); + CCECBusDevice *primary = GetProcessor()->GetPrimaryDevice(); + if (primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED) + { + m_handler->InitHandler(); - if (bActivateSource && IsHandledByLibCEC() && IsActiveSource()) - m_handler->ActivateSource(); + if (bActivateSource && IsHandledByLibCEC() && IsActiveSource()) + m_handler->ActivateSource(); + } } MarkReady(); diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index 6e0121f..3a9bd6f 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -163,6 +163,8 @@ namespace CEC virtual void SignalOpcode(cec_opcode opcode); virtual bool ActiveSourcePending(void); + virtual bool SupportsDeviceType(const cec_device_type UNUSED(type)) const { return true; }; + cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type; } protected: virtual bool HandleActiveSource(const cec_command &command); diff --git a/src/lib/implementations/RLCommandHandler.cpp b/src/lib/implementations/RLCommandHandler.cpp index 9643ee5..b913c32 100644 --- a/src/lib/implementations/RLCommandHandler.cpp +++ b/src/lib/implementations/RLCommandHandler.cpp @@ -42,14 +42,6 @@ CRLCommandHandler::CRLCommandHandler(CCECBusDevice *busDevice) : CCECCommandHandler(busDevice) { m_vendorId = CEC_VENDOR_TOSHIBA; - CCECBusDevice *primary = m_processor->GetPrimaryDevice(); - - /* imitate Toshiba devices */ - if (primary && m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) - { - primary->SetVendorId(CEC_VENDOR_TOSHIBA); - primary->ReplaceHandler(false); - } } bool CRLCommandHandler::InitHandler(void) @@ -58,12 +50,21 @@ bool CRLCommandHandler::InitHandler(void) return true; m_bHandlerInited = true; - if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + if (primary && primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED) { - CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + /* imitate Toshiba devices */ + if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) + { + primary->SetVendorId(CEC_VENDOR_TOSHIBA); + primary->ReplaceHandler(false); + } - /* send the vendor id */ - primary->TransmitVendorID(CECDEVICE_BROADCAST); + if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) + { + /* send the vendor id */ + primary->TransmitVendorID(CECDEVICE_BROADCAST); + } } return true; diff --git a/src/lib/implementations/SLCommandHandler.cpp b/src/lib/implementations/SLCommandHandler.cpp index 46ef3d7..6066d3b 100644 --- a/src/lib/implementations/SLCommandHandler.cpp +++ b/src/lib/implementations/SLCommandHandler.cpp @@ -62,14 +62,6 @@ CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) : m_bActiveSourceSent(false) { m_vendorId = CEC_VENDOR_LG; - CCECBusDevice *primary = m_processor->GetPrimaryDevice(); - - /* imitate LG devices */ - if (primary && m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) - { - primary->SetVendorId(CEC_VENDOR_LG); - primary->ReplaceHandler(false); - } /* LG devices don't always reply to CEC version requests, so just set it to 1.3a */ m_busDevice->SetCecVersion(CEC_VERSION_1_3A); @@ -87,16 +79,25 @@ bool CSLCommandHandler::InitHandler(void) return true; m_bHandlerInited = true; - if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + if (primary && primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED) { - CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + /* imitate LG devices */ + if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) + { + primary->SetVendorId(CEC_VENDOR_LG); + primary->ReplaceHandler(false); + } - /* start as 'in transition standby->on' */ - primary->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); - primary->TransmitPowerState(CECDEVICE_TV); + if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) + { + /* start as 'in transition standby->on' */ + primary->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); + primary->TransmitPowerState(CECDEVICE_TV); - /* send the vendor id */ - primary->TransmitVendorID(CECDEVICE_BROADCAST); + /* send the vendor id */ + primary->TransmitVendorID(CECDEVICE_BROADCAST); + } } return true; diff --git a/src/lib/implementations/VLCommandHandler.cpp b/src/lib/implementations/VLCommandHandler.cpp index 06468f8..3d96004 100644 --- a/src/lib/implementations/VLCommandHandler.cpp +++ b/src/lib/implementations/VLCommandHandler.cpp @@ -52,24 +52,26 @@ CVLCommandHandler::CVLCommandHandler(CCECBusDevice *busDevice) : m_bPowerUpEventReceived(false) { m_vendorId = CEC_VENDOR_PANASONIC; - - /* use the VL commandhandler for the primary device that is handled by libCEC */ - if (busDevice->GetLogicalAddress() == CECDEVICE_TV) - { - CCECBusDevice *primary = m_processor->GetPrimaryDevice(); - if (primary && m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) - { - primary->SetVendorId(CEC_VENDOR_PANASONIC); - primary->ReplaceHandler(false); - } - } } bool CVLCommandHandler::InitHandler(void) { CCECBusDevice *primary = m_processor->GetPrimaryDevice(); - if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) - return m_processor->GetPrimaryClient()->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE); + if (primary && primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED) + { + /* use the VL commandhandler for the primary device that is handled by libCEC */ + if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) + { + if (primary && m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) + { + primary->SetVendorId(CEC_VENDOR_PANASONIC); + primary->ReplaceHandler(false); + } + } + + if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) + return m_processor->GetPrimaryClient()->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE); + } return CCECCommandHandler::InitHandler(); } diff --git a/src/lib/implementations/VLCommandHandler.h b/src/lib/implementations/VLCommandHandler.h index d24ea3d..f2bfc7e 100644 --- a/src/lib/implementations/VLCommandHandler.h +++ b/src/lib/implementations/VLCommandHandler.h @@ -48,6 +48,8 @@ namespace CEC bool TransmitPendingActiveSourceCommands(void); bool PowerUpEventReceived(void); + bool SupportsDeviceType(const cec_device_type type) const { return type != CEC_DEVICE_TYPE_RECORDING_DEVICE; }; + cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type == CEC_DEVICE_TYPE_RECORDING_DEVICE ? CEC_DEVICE_TYPE_PLAYBACK_DEVICE : type; } private: PLATFORM::CMutex m_mutex; -- 2.34.1