From aa4c0d341117a7e3b75b665fbc61f3bb40be5d79 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Thu, 21 Jun 2012 12:28:03 +0200 Subject: [PATCH 1/1] cec: removed dupe code around delayed activate source commands. check for delayed active source commands every 5 seconds instead of 15 seconds. fixed delayed source switch for panasonic --- include/cectypes.h | 2 + src/lib/CECProcessor.cpp | 23 +--- src/lib/CECProcessor.h | 1 - src/lib/devices/CECBusDevice.cpp | 2 +- src/lib/implementations/CECCommandHandler.cpp | 60 ++++++---- src/lib/implementations/CECCommandHandler.h | 8 +- src/lib/implementations/VLCommandHandler.cpp | 110 +++++++++--------- src/lib/implementations/VLCommandHandler.h | 7 +- 8 files changed, 110 insertions(+), 103 deletions(-) diff --git a/include/cectypes.h b/include/cectypes.h index a47a570..bb9dc32 100644 --- a/include/cectypes.h +++ b/include/cectypes.h @@ -110,6 +110,8 @@ namespace CEC { #define CEC_SERIAL_DEFAULT_BAUDRATE 38400 #define CEC_CLEAR_INPUT_DEFAULT_WAIT 1000 +#define CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS 5000 + #define CEC_MIN_LIB_VERSION 1 #define CEC_LIB_VERSION_MAJOR 1 #define CEC_LIB_VERSION_MAJOR_STR "1" diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 848800e..1975421 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -51,7 +51,7 @@ using namespace std; using namespace PLATFORM; #define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000 -#define ACTIVE_SOURCE_CHECK_TIMEOUT 15000 +#define ACTIVE_SOURCE_CHECK_INTERVAL 500 #define ToString(x) CCECTypeUtils::ToString(x) @@ -198,20 +198,6 @@ void CCECProcessor::ReplaceHandlers(void) it->second->ReplaceHandler(true); } -void CCECProcessor::CheckPendingActiveSource(void) -{ - if (!CECInitialised()) - return; - - // check each device - for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++) - { - if (it->second->GetHandler()->ActiveSourcePending()) - it->second->ActivateSource(); - it->second->MarkHandlerReady(); - } -} - bool CCECProcessor::OnCommandReceived(const cec_command &command) { return m_inBuffer.Push(command); @@ -222,7 +208,7 @@ void *CCECProcessor::Process(void) m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started"); cec_command command; - CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_TIMEOUT); + CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_INTERVAL); // as long as we're not being stopped and the connection is open while (!IsStopped() && m_communication->IsOpen()) @@ -242,8 +228,9 @@ void *CCECProcessor::Process(void) // check whether we need to activate a source, if it failed before if (activeSourceCheck.TimeLeft() == 0) { - CheckPendingActiveSource(); - activeSourceCheck.Init(ACTIVE_SOURCE_CHECK_TIMEOUT); + if (CECInitialised()) + TransmitPendingActiveSourceCommands(); + activeSourceCheck.Init(ACTIVE_SOURCE_CHECK_INTERVAL); } } } diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index 04d84f5..5f496d2 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -134,7 +134,6 @@ namespace CEC void SetCECInitialised(bool bSetTo = true); void ReplaceHandlers(void); - void CheckPendingActiveSource(void); bool PhysicalAddressInUse(uint16_t iPhysicalAddress); bool SetAckMask(uint16_t iMask); diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 3fb30e8..47bd53a 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -1015,7 +1015,7 @@ bool CCECBusDevice::TransmitInactiveSource(void) bool CCECBusDevice::TransmitPendingActiveSourceCommands(void) { MarkBusy(); - bool bReturn = m_handler->TransmitPendingActiveSourceCommands(); + bool bReturn = m_handler->ActivateSource(true); MarkReady(); return bReturn; } diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index 395aace..f99d4c0 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -57,7 +57,7 @@ CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) : m_bOPTSendDeckStatusUpdateOnActiveSource(false), m_vendorId(CEC_VENDOR_UNKNOWN), m_waitForResponse(new CWaitForResponse), - m_bActiveSourcePending(false) + m_iActiveSourcePending(0) { } @@ -1089,38 +1089,64 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* = return bReturn; } -bool CCECCommandHandler::ActivateSource(void) +bool CCECCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = false */) { if (m_busDevice->IsActiveSource() && - m_busDevice->IsHandledByLibCEC()) + m_busDevice->IsHandledByLibCEC()) { { CLockObject lock(m_mutex); - m_bActiveSourcePending = false; + // check if we need to send a delayed source switch + if (bTransmitDelayedCommandsOnly) + { + if (m_iActiveSourcePending == 0 || GetTimeMs() < m_iActiveSourcePending) + return false; + + LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command"); + } + + // clear previous pending active source command + m_iActiveSourcePending = 0; } + // update the power state and menu state m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON); - m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED); + m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED); // TODO: LG + + // power on the TV + bool bActiveSourceFailed = !m_busDevice->TransmitImageViewOn(); - bool bActiveSourceFailed = !m_busDevice->TransmitImageViewOn() || - !m_busDevice->TransmitActiveSource() || - !m_busDevice->TransmitMenuState(CECDEVICE_TV); + // check if we're allowed to switch sources + bool bSourceSwitchAllowed = SourceSwitchAllowed(); + if (!bSourceSwitchAllowed) + LIB_CEC->AddLog(CEC_LOG_DEBUG, "source switch is currently not allowed by command handler"); - if (!bActiveSourceFailed) + // switch sources (if allowed) + if (!bActiveSourceFailed && bSourceSwitchAllowed) { - CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice(); - if (playbackDevice && SendDeckStatusUpdateOnActiveSource()) - bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV); + bActiveSourceFailed = !m_busDevice->TransmitActiveSource() || + !m_busDevice->TransmitMenuState(CECDEVICE_TV); + + // update the deck status for playback devices + if (!bActiveSourceFailed) + { + CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice(); + if (playbackDevice && SendDeckStatusUpdateOnActiveSource()) + bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV); + } } - if (bActiveSourceFailed) + // retry later + if (bActiveSourceFailed || !bSourceSwitchAllowed) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to make '%s' the active source. will retry later", m_busDevice->GetLogicalAddressName()); CLockObject lock(m_mutex); - m_bActiveSourcePending = true; + m_iActiveSourcePending = GetTimeMs() + CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS; return false; } + // mark the handler as initialised + CLockObject lock(m_mutex); m_bHandlerInited = true; } return true; @@ -1130,9 +1156,3 @@ void CCECCommandHandler::SignalOpcode(cec_opcode opcode) { m_waitForResponse->Received(opcode); } - -bool CCECCommandHandler::ActiveSourcePending(void) -{ - CLockObject lock(m_mutex); - return m_bActiveSourcePending; -} diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index 607a56a..70ba309 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -128,7 +128,7 @@ namespace CEC static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC;} virtual bool InitHandler(void) { return true; } - virtual bool ActivateSource(void); + virtual bool ActivateSource(bool bTransmitDelayedCommandsOnly = false); virtual uint8_t GetTransmitRetries(void) const { return m_iTransmitRetries; } virtual bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination); @@ -160,11 +160,9 @@ namespace CEC virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait = true); virtual bool TransmitSetStreamPath(uint16_t iStreamPath); virtual bool SendDeckStatusUpdateOnActiveSource(void) const { return m_bOPTSendDeckStatusUpdateOnActiveSource; }; - virtual bool TransmitPendingActiveSourceCommands(void) { return true; } virtual void SignalOpcode(cec_opcode opcode); - virtual bool ActiveSourcePending(void); virtual bool SupportsDeviceType(const cec_device_type UNUSED(type)) const { return true; }; virtual cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type; } @@ -217,6 +215,8 @@ namespace CEC virtual bool Transmit(cec_command &command, bool bSuppressWait = false); + virtual bool SourceSwitchAllowed(void) { return true; } + CCECBusDevice * m_busDevice; CCECProcessor * m_processor; int32_t m_iTransmitTimeout; @@ -226,7 +226,7 @@ namespace CEC bool m_bOPTSendDeckStatusUpdateOnActiveSource; cec_vendor_id m_vendorId; CWaitForResponse *m_waitForResponse; - bool m_bActiveSourcePending; + int m_iActiveSourcePending; PLATFORM::CMutex m_mutex; }; }; diff --git a/src/lib/implementations/VLCommandHandler.cpp b/src/lib/implementations/VLCommandHandler.cpp index 74b2650..c347649 100644 --- a/src/lib/implementations/VLCommandHandler.cpp +++ b/src/lib/implementations/VLCommandHandler.cpp @@ -32,6 +32,8 @@ #include "VLCommandHandler.h" #include "../devices/CECBusDevice.h" +#include "../devices/CECPlaybackDevice.h" +#include "../devices/CECTV.h" #include "../CECProcessor.h" #include "../LibCEC.h" #include "../CECClient.h" @@ -46,10 +48,12 @@ using namespace PLATFORM; #define LIB_CEC m_busDevice->GetProcessor()->GetLib() #define ToString(p) LIB_CEC->ToString(p) +// wait this amount of ms before trying to switch sources after receiving the message from the TV that it's powered on +#define SOURCE_SWITCH_DELAY_MS 1000 + CVLCommandHandler::CVLCommandHandler(CCECBusDevice *busDevice) : CCECCommandHandler(busDevice), - m_bActiveSourcePending(false), - m_bPowerUpEventReceived(false) + m_iPowerUpEventReceived(0) { m_vendorId = CEC_VENDOR_PANASONIC; } @@ -71,6 +75,8 @@ bool CVLCommandHandler::InitHandler(void) if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) return m_processor->GetPrimaryClient()->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE); + + m_processor->GetTV()->RequestPowerStatus(primary->GetLogicalAddress(), false); } return CCECCommandHandler::InitHandler(); @@ -89,17 +95,27 @@ int CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &comman { if (command.parameters.At(4) == VL_POWERED_UP) { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV powered up"); + // set the power up event time { CLockObject lock(m_mutex); - m_bPowerUpEventReceived = true; + if (m_iPowerUpEventReceived == 0) + m_iPowerUpEventReceived = GetTimeMs(); } - m_processor->TransmitPendingActiveSourceCommands(); + // mark the TV as powered on + m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON); } else if (command.parameters.At(4) == VL_POWERED_DOWN) - LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV powered down"); - else if (command.parameters.At(4) == VL_POWERED_DOWN) - LIB_CEC->AddLog(CEC_LOG_DEBUG, "unknown vendor command"); + { + // reset the power up event time + { + CLockObject lock(m_mutex); + m_iPowerUpEventReceived = 0; + } + // mark the TV as powered off + m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_STANDBY); + } + else + LIB_CEC->AddLog(CEC_LOG_DEBUG, "skipping unknown vendor command"); return COMMAND_HANDLED; } @@ -107,68 +123,48 @@ int CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &comman return CCECCommandHandler::HandleDeviceVendorCommandWithId(command); } -bool CVLCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress) +bool CVLCommandHandler::PowerUpEventReceived(void) { - bool bPowerUpEventReceived(false); + bool bPowerUpEventReceived(true); - CCECBusDevice *tv = m_processor->GetDevice(CECDEVICE_TV); - if (tv && tv->GetCurrentVendorId() == CEC_VENDOR_PANASONIC) + if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV) { - CVLCommandHandler *handler = static_cast(tv->GetHandler()); - bPowerUpEventReceived = handler ? handler->PowerUpEventReceived() : false; - tv->MarkHandlerReady(); - } - - if (!bPowerUpEventReceived) - { - CLockObject lock(m_mutex); - // wait until we received the event - m_bActiveSourcePending = true; - return true; + // get the status from the TV + CCECBusDevice *tv = m_processor->GetTV(); + if (tv && tv->GetCurrentVendorId() == CEC_VENDOR_PANASONIC) + { + CVLCommandHandler *handler = static_cast(tv->GetHandler()); + bPowerUpEventReceived = handler ? handler->PowerUpEventReceived() : false; + tv->MarkHandlerReady(); + } } else { - // transmit standard active source message - return CCECCommandHandler::TransmitActiveSource(iInitiator, iPhysicalAddress); - } -} - -bool CVLCommandHandler::TransmitPendingActiveSourceCommands(void) -{ - bool bTransmitCommand(false); - { - CLockObject lock(m_mutex); - bTransmitCommand = m_bActiveSourcePending; - m_bActiveSourcePending = false; - } - - if (bTransmitCommand) - { - LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command"); - return CCECCommandHandler::TransmitActiveSource(m_busDevice->GetLogicalAddress(), m_busDevice->GetCurrentPhysicalAddress()) && - TransmitMenuState(m_busDevice->GetLogicalAddress(), CECDEVICE_TV, CEC_MENU_STATE_ACTIVATED); - } - return true; -} + // get the current status + { + CLockObject lock(m_mutex); + bPowerUpEventReceived = m_iPowerUpEventReceived > 0 && + GetTimeMs() - m_iPowerUpEventReceived > SOURCE_SWITCH_DELAY_MS; + } -bool CVLCommandHandler::PowerUpEventReceived(void) -{ - { - CLockObject lock(m_mutex); - if (m_bPowerUpEventReceived) - return true; + // if we didn't receive the event, check if the TV is already marked as powered on + if (!bPowerUpEventReceived && m_busDevice->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON) + { + CLockObject lock(m_mutex); + m_iPowerUpEventReceived = GetTimeMs(); + bPowerUpEventReceived = true; + } } - CLockObject lock(m_mutex); - m_bPowerUpEventReceived = (m_busDevice->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON); - return m_bPowerUpEventReceived; + return bPowerUpEventReceived; } int CVLCommandHandler::HandleStandby(const cec_command &command) { + // reset the power up event time { CLockObject lock(m_mutex); - m_bPowerUpEventReceived = false; + m_iPowerUpEventReceived = 0; } return CCECCommandHandler::HandleStandby(command); @@ -195,3 +191,7 @@ int CVLCommandHandler::HandleVendorCommand(const cec_command &command) return CEC_ABORT_REASON_INVALID_OPERAND; } +bool CVLCommandHandler::SourceSwitchAllowed(void) +{ + return PowerUpEventReceived(); +} diff --git a/src/lib/implementations/VLCommandHandler.h b/src/lib/implementations/VLCommandHandler.h index 699ef40..433a394 100644 --- a/src/lib/implementations/VLCommandHandler.h +++ b/src/lib/implementations/VLCommandHandler.h @@ -45,17 +45,16 @@ namespace CEC int HandleDeviceVendorCommandWithId(const cec_command &command); int HandleStandby(const cec_command &command); - bool TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress); - bool TransmitPendingActiveSourceCommands(void); int HandleVendorCommand(const cec_command &command); 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; } + bool SourceSwitchAllowed(void); + private: PLATFORM::CMutex m_mutex; - bool m_bActiveSourcePending; - bool m_bPowerUpEventReceived; + uint64_t m_iPowerUpEventReceived; }; }; -- 2.34.1