From: Lars Op den Kamp Date: Sun, 1 Jan 2012 21:25:05 +0000 (+0100) Subject: cec: replace the command handler directly after receiving a changed vendor id. change... X-Git-Tag: upstream/2.2.0~1^2~42^2~14 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=3e61b35032f69fb93869796e2f985de8cff2ae33;p=deb_libcec.git cec: replace the command handler directly after receiving a changed vendor id. change the primary type from recording device to playback device for panasonic TVs --- diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 6af0664..e5a29ee 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -170,7 +170,7 @@ bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */, m_busDevices[m_logicalAddresses.primary]->m_strDeviceName = m_strDeviceName; /* get the vendor id from the TV, so we are using the correct handler */ - m_busDevices[CECDEVICE_TV]->GetVendorId(); + m_busDevices[CECDEVICE_TV]->RequestVendorId(); ReplaceHandlers(); bReturn = SetHDMIPort(m_iBaseDevice, m_iHDMIPort, true); @@ -181,7 +181,7 @@ bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */, { m_bInitialised = true; m_busDevices[m_logicalAddresses.primary]->m_bActiveSource = true; - bReturn = m_busDevices[CECDEVICE_TV]->InitHandler(); + bReturn = m_busDevices[CECDEVICE_TV]->ActivateSource(); } if (bReturn) @@ -239,6 +239,85 @@ bool CCECProcessor::FindLogicalAddressAudioSystem(void) return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM); } +bool CCECProcessor::ChangeDeviceType(cec_device_type from, cec_device_type to) +{ + bool bChanged(false); + + CStdString strLog; + strLog.Format("changing device type '%s' into '%s'", ToString(from), ToString(to)); + AddLog(CEC_LOG_NOTICE, strLog); + + CLockObject lock(&m_mutex); + CCECBusDevice *previousDevice = GetDeviceByType(from); + m_logicalAddresses.primary = CECDEVICE_UNKNOWN; + + for (unsigned int iPtr = 0; iPtr < 5; iPtr++) + { + if (m_types.types[iPtr] == CEC_DEVICE_TYPE_RESERVED) + continue; + + if (m_types.types[iPtr] == from) + { + bChanged = true; + m_types.types[iPtr] = to; + } + else if (m_types.types[iPtr] == to && bChanged) + { + m_types.types[iPtr] = CEC_DEVICE_TYPE_RESERVED; + } + } + + if (bChanged) + { + FindLogicalAddresses(); + + CCECBusDevice *newDevice = GetDeviceByType(to); + if (previousDevice && newDevice) + { + newDevice->SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC); + previousDevice->SetDeviceStatus(CEC_DEVICE_STATUS_UNKNOWN); + + newDevice->SetCecVersion(previousDevice->GetCecVersion(false)); + previousDevice->SetCecVersion(CEC_VERSION_UNKNOWN); + + newDevice->SetMenuLanguage(previousDevice->GetMenuLanguage(false)); + cec_menu_language lang; + lang.device = previousDevice->GetLogicalAddress(); + for (unsigned int iPtr = 0; iPtr < 4; iPtr++) + lang.language[iPtr] = '?'; + lang.language[3] = 0; + previousDevice->SetMenuLanguage(lang); + + newDevice->SetMenuState(previousDevice->GetMenuState()); + previousDevice->SetMenuState(CEC_MENU_STATE_DEACTIVATED); + + newDevice->SetOSDName(previousDevice->GetOSDName(false)); + previousDevice->SetOSDName(ToString(previousDevice->GetLogicalAddress())); + + newDevice->SetPhysicalAddress(previousDevice->GetPhysicalAddress(false)); + previousDevice->SetPhysicalAddress(0xFFFF); + + newDevice->SetPowerStatus(previousDevice->GetPowerStatus(false)); + previousDevice->SetPowerStatus(CEC_POWER_STATUS_UNKNOWN); + + newDevice->SetVendorId(previousDevice->GetVendorId(false)); + previousDevice->SetVendorId(CEC_VENDOR_UNKNOWN); + + if ((from == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || from == CEC_DEVICE_TYPE_RECORDING_DEVICE) && + (to == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || to == CEC_DEVICE_TYPE_RECORDING_DEVICE)) + { + ((CCECPlaybackDevice *) newDevice)->SetDeckControlMode(((CCECPlaybackDevice *) previousDevice)->GetDeckControlMode()); + ((CCECPlaybackDevice *) previousDevice)->SetDeckControlMode(CEC_DECK_CONTROL_MODE_STOP); + + ((CCECPlaybackDevice *) newDevice)->SetDeckStatus(((CCECPlaybackDevice *) previousDevice)->GetDeckStatus()); + ((CCECPlaybackDevice *) previousDevice)->SetDeckStatus(CEC_DECK_INFO_STOP); + } + } + } + + return true; +} + bool CCECProcessor::FindLogicalAddresses(void) { bool bReturn(true); @@ -1005,6 +1084,27 @@ bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination, bool bW return m_busDevices[iDestination]->TransmitKeyRelease(bWait); } +const char *CCECProcessor::ToString(const cec_device_type type) +{ + switch (type) + { + case CEC_DEVICE_TYPE_AUDIO_SYSTEM: + return "audio system"; + case CEC_DEVICE_TYPE_PLAYBACK_DEVICE: + return "playback device"; + case CEC_DEVICE_TYPE_RECORDING_DEVICE: + return "recording device"; + case CEC_DEVICE_TYPE_RESERVED: + return "reserved"; + case CEC_DEVICE_TYPE_TUNER: + return "tuner"; + case CEC_DEVICE_TYPE_TV: + return "TV"; + default: + return "unknown"; + } +} + const char *CCECProcessor::ToString(const cec_menu_state state) { switch (state) diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index 13243ab..a688bef 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -103,6 +103,7 @@ namespace CEC bool SetLineTimeout(uint8_t iTimeout); + const char *ToString(const cec_device_type type); const char *ToString(const cec_menu_state state); const char *ToString(const cec_version version); const char *ToString(const cec_power_status status); @@ -124,6 +125,7 @@ namespace CEC virtual void AddKey(void); virtual void AddLog(cec_log_level level, const CStdString &strMessage); + virtual bool ChangeDeviceType(cec_device_type from, cec_device_type to); virtual bool FindLogicalAddresses(void); virtual bool SetAckMask(uint16_t iMask); diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index bd68dfc..a2ce01d 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -176,11 +176,13 @@ bool CCECBusDevice::RequestCecVersion(void) if (!MyLogicalAddressContains(m_iLogicalAddress)) { + m_handler->MarkBusy(); CStdString strLog; strLog.Format("<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); AddLog(CEC_LOG_NOTICE, strLog); bReturn = m_handler->TransmitRequestCecVersion(GetMyLogicalAddress(), m_iLogicalAddress); + m_handler->MarkReady(); } return bReturn; } @@ -213,14 +215,22 @@ bool CCECBusDevice::RequestMenuLanguage(void) if (!MyLogicalAddressContains(m_iLogicalAddress) && !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE)) { + m_handler->MarkBusy(); CStdString strLog; strLog.Format("<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); AddLog(CEC_LOG_NOTICE, strLog); bReturn = m_handler->TransmitRequestMenuLanguage(GetMyLogicalAddress(), m_iLogicalAddress); + m_handler->MarkReady(); } return bReturn; } +cec_menu_state CCECBusDevice::GetMenuState(void) +{ + CLockObject lock(&m_mutex); + return m_menuState; +} + cec_logical_address CCECBusDevice::GetMyLogicalAddress(void) const { return m_processor->GetLogicalAddress(); @@ -255,10 +265,12 @@ bool CCECBusDevice::RequestOSDName(void) if (!MyLogicalAddressContains(m_iLogicalAddress) && !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME)) { + m_handler->MarkBusy(); CStdString strLog; strLog.Format("<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); AddLog(CEC_LOG_NOTICE, strLog); bReturn = m_handler->TransmitRequestOSDName(GetMyLogicalAddress(), m_iLogicalAddress); + m_handler->MarkReady(); } return bReturn; } @@ -285,10 +297,12 @@ bool CCECBusDevice::RequestPhysicalAddress(void) if (!MyLogicalAddressContains(m_iLogicalAddress)) { + m_handler->MarkBusy(); CStdString strLog; strLog.Format("<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); AddLog(CEC_LOG_NOTICE, strLog); bReturn = m_handler->TransmitRequestPhysicalAddress(GetMyLogicalAddress(), m_iLogicalAddress); + m_handler->MarkReady(); } return bReturn; } @@ -317,10 +331,12 @@ bool CCECBusDevice::RequestPowerStatus(void) if (!MyLogicalAddressContains(m_iLogicalAddress) && !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS)) { + m_handler->MarkBusy(); CStdString strLog; strLog.Format("<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); AddLog(CEC_LOG_NOTICE, strLog); bReturn = m_handler->TransmitRequestPowerStatus(GetMyLogicalAddress(), m_iLogicalAddress); + m_handler->MarkReady(); } return bReturn; } @@ -347,10 +363,14 @@ bool CCECBusDevice::RequestVendorId(void) if (!MyLogicalAddressContains(m_iLogicalAddress)) { + m_handler->MarkBusy(); CStdString strLog; strLog.Format("<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); AddLog(CEC_LOG_NOTICE, strLog); bReturn = m_handler->TransmitRequestVendorId(GetMyLogicalAddress(), m_iLogicalAddress); + m_handler->MarkReady(); + + ReplaceHandler(true); } return bReturn; } @@ -600,16 +620,23 @@ void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus) } } -bool CCECBusDevice::ReplaceHandler(bool bInitHandler /* = true */) +bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */) { CLockObject lock(&m_mutex); CLockObject handlerLock(&m_handlerMutex); if (m_vendor != m_handler->GetVendorId()) { + CStdString strLog; if (m_handler->InUse()) + { + strLog.Format("handler for device '%s' (%x) is being used. not replacing the command handler", GetLogicalAddressName(), GetLogicalAddress()); + m_processor->AddLog(CEC_LOG_DEBUG, strLog); return false; + } + strLog.Format("replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress()); + m_processor->AddLog(CEC_LOG_DEBUG, strLog); delete m_handler; switch (m_vendor) @@ -628,14 +655,16 @@ bool CCECBusDevice::ReplaceHandler(bool bInitHandler /* = true */) break; } - if (bInitHandler && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised()) - m_handler->InitHandler(); + m_handler->InitHandler(); + + if (bActivateSource && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised()) + m_handler->ActivateSource(); } return true; } -bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */) +bool CCECBusDevice::SetVendorId(uint64_t iVendorId) { bool bVendorChanged(false); @@ -643,7 +672,6 @@ bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true CLockObject lock(&m_mutex); bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId); m_vendor = (cec_vendor_id)iVendorId; - ReplaceHandler(bInitHandler); } CStdString strLog; @@ -874,10 +902,10 @@ void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode) m_unsupportedFeatures.insert(opcode); } -bool CCECBusDevice::InitHandler(void) +bool CCECBusDevice::ActivateSource(void) { CLockObject lock(&m_mutex); - return m_handler->InitHandler(); + return m_handler->ActivateSource(); } //@} diff --git a/src/lib/devices/CECBusDevice.h b/src/lib/devices/CECBusDevice.h index 30d8329..6157e0a 100644 --- a/src/lib/devices/CECBusDevice.h +++ b/src/lib/devices/CECBusDevice.h @@ -62,6 +62,7 @@ namespace CEC virtual cec_logical_address GetLogicalAddress(void) const { return m_iLogicalAddress; } virtual const char* GetLogicalAddressName(void) const; virtual cec_menu_language & GetMenuLanguage(bool bUpdate = false); + virtual cec_menu_state GetMenuState(void); virtual cec_logical_address GetMyLogicalAddress(void) const; virtual uint16_t GetMyPhysicalAddress(void) const; virtual CStdString GetOSDName(bool bUpdate = false); @@ -80,7 +81,7 @@ namespace CEC virtual void SetInactiveSource(void); virtual void SetActiveSource(void); virtual bool TryLogicalAddress(void); - virtual bool InitHandler(void); + virtual bool ActivateSource(void); virtual void SetDeviceStatus(const cec_bus_device_status newStatus); virtual void SetPhysicalAddress(uint16_t iNewAddress); @@ -89,7 +90,7 @@ namespace CEC virtual void SetMenuLanguage(const cec_menu_language &menuLanguage); virtual void SetOSDName(CStdString strName); virtual void SetMenuState(const cec_menu_state state); - virtual bool SetVendorId(uint64_t iVendorId, bool bInitHandler = true); + virtual bool SetVendorId(uint64_t iVendorId); virtual void SetPowerStatus(const cec_power_status powerStatus); virtual bool TransmitActiveSource(void); diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index 74f7648..4656110 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -60,7 +60,7 @@ CCECCommandHandler::~CCECCommandHandler(void) bool CCECCommandHandler::HandleCommand(const cec_command &command) { - bool bHandled(true), bHandlerChanged(false); + bool bHandled(true); MarkBusy(); CStdString strLog; @@ -81,49 +81,61 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) HandleSetMenuLanguage(command); break; case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS: - HandleGivePhysicalAddress(command); + if (m_processor->IsInitialised()) + HandleGivePhysicalAddress(command); break; case CEC_OPCODE_GIVE_OSD_NAME: - HandleGiveOSDName(command); + if (m_processor->IsInitialised()) + HandleGiveOSDName(command); break; case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID: - HandleGiveDeviceVendorId(command); + if (m_processor->IsInitialised()) + HandleGiveDeviceVendorId(command); break; case CEC_OPCODE_DEVICE_VENDOR_ID: - bHandlerChanged = HandleDeviceVendorId(command); + HandleDeviceVendorId(command); break; case CEC_OPCODE_VENDOR_COMMAND_WITH_ID: HandleDeviceVendorCommandWithId(command); break; case CEC_OPCODE_GIVE_DECK_STATUS: - HandleGiveDeckStatus(command); + if (m_processor->IsInitialised()) + HandleGiveDeckStatus(command); break; case CEC_OPCODE_DECK_CONTROL: HandleDeckControl(command); break; case CEC_OPCODE_MENU_REQUEST: - HandleMenuRequest(command); + if (m_processor->IsInitialised()) + HandleMenuRequest(command); break; case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS: - HandleGiveDevicePowerStatus(command); + if (m_processor->IsInitialised()) + HandleGiveDevicePowerStatus(command); break; case CEC_OPCODE_GET_CEC_VERSION: - HandleGetCecVersion(command); + if (m_processor->IsInitialised()) + HandleGetCecVersion(command); break; case CEC_OPCODE_USER_CONTROL_PRESSED: - HandleUserControlPressed(command); + if (m_processor->IsInitialised()) + HandleUserControlPressed(command); break; case CEC_OPCODE_USER_CONTROL_RELEASE: - HandleUserControlRelease(command); + if (m_processor->IsInitialised()) + HandleUserControlRelease(command); break; case CEC_OPCODE_GIVE_AUDIO_STATUS: - HandleGiveAudioStatus(command); + if (m_processor->IsInitialised()) + HandleGiveAudioStatus(command); break; case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS: - HandleGiveSystemAudioModeStatus(command); + if (m_processor->IsInitialised()) + HandleGiveSystemAudioModeStatus(command); break; case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST: - HandleSystemAudioModeRequest(command); + if (m_processor->IsInitialised()) + HandleSystemAudioModeRequest(command); break; case CEC_OPCODE_REPORT_AUDIO_STATUS: HandleReportAudioStatus(command); @@ -135,7 +147,8 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) HandleSetSystemAudioMode(command); break; case CEC_OPCODE_REQUEST_ACTIVE_SOURCE: - HandleRequestActiveSource(command); + if (m_processor->IsInitialised()) + HandleRequestActiveSource(command); break; case CEC_OPCODE_SET_STREAM_PATH: HandleSetStreamPath(command); @@ -147,7 +160,8 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) HandleRoutingInformation(command); break; case CEC_OPCODE_STANDBY: - HandleStandby(command); + if (m_processor->IsInitialised()) + HandleStandby(command); break; case CEC_OPCODE_ACTIVE_SOURCE: HandleActiveSource(command); @@ -176,7 +190,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) break; } - if (bHandled && !bHandlerChanged) + if (bHandled) { CLockObject lock(&m_receiveMutex); if (m_expectedResponse == CEC_OPCODE_NONE || @@ -938,6 +952,7 @@ bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */, cec_opcode expectedResponse /* = CEC_OPCODE_NONE */) { bool bReturn(false); + MarkBusy(); command.transmit_timeout = m_iTransmitTimeout; { @@ -959,10 +974,11 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* --m_iUseCounter; } + MarkReady(); return bReturn; } -bool CCECCommandHandler::InitHandler(void) +bool CCECCommandHandler::ActivateSource(void) { if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) { diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index c99d569..929f74d 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -52,7 +52,8 @@ namespace CEC virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool HandleReceiveFailed(void); - virtual bool InitHandler(void); + virtual bool InitHandler(void) { return true; } + virtual bool ActivateSource(void); virtual uint8_t GetTransmitRetries(void) const { return m_iTransmitRetries; } virtual bool TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination); diff --git a/src/lib/implementations/SLCommandHandler.cpp b/src/lib/implementations/SLCommandHandler.cpp index bc302aa..31376e5 100644 --- a/src/lib/implementations/SLCommandHandler.cpp +++ b/src/lib/implementations/SLCommandHandler.cpp @@ -58,7 +58,7 @@ CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) : /* imitate LG devices */ if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) - primary->SetVendorId(CEC_VENDOR_LG, false); + primary->SetVendorId(CEC_VENDOR_LG); SetLGDeckStatus(); /* LG TVs don't always reply to CEC version requests, so just set it to 1.3a */ @@ -105,6 +105,14 @@ bool CSLCommandHandler::InitHandler(void) return true; } +bool CSLCommandHandler::ActivateSource(void) +{ + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + primary->SetActiveSource(); + primary->TransmitActiveSource(); + return true; +} + bool CSLCommandHandler::HandleActiveSource(const cec_command &command) { if (command.parameters.size == 2) diff --git a/src/lib/implementations/SLCommandHandler.h b/src/lib/implementations/SLCommandHandler.h index 48674cc..8243d98 100644 --- a/src/lib/implementations/SLCommandHandler.h +++ b/src/lib/implementations/SLCommandHandler.h @@ -44,7 +44,9 @@ namespace CEC virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool HandleReceiveFailed(void); + virtual bool InitHandler(void); + virtual bool ActivateSource(void); protected: virtual bool HandleActiveSource(const cec_command &command); diff --git a/src/lib/implementations/VLCommandHandler.cpp b/src/lib/implementations/VLCommandHandler.cpp index fbbfa29..257a8f3 100644 --- a/src/lib/implementations/VLCommandHandler.cpp +++ b/src/lib/implementations/VLCommandHandler.cpp @@ -32,7 +32,7 @@ #include "VLCommandHandler.h" #include "../devices/CECBusDevice.h" -#include "../util/StdString.h" +#include "../CECProcessor.h" using namespace CEC; @@ -40,3 +40,13 @@ CVLCommandHandler::CVLCommandHandler(CCECBusDevice *busDevice) : CCECCommandHandler(busDevice) { } + +bool CVLCommandHandler::InitHandler(void) +{ + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) + { + return m_processor->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 3959ad7..9ed71cb 100644 --- a/src/lib/implementations/VLCommandHandler.h +++ b/src/lib/implementations/VLCommandHandler.h @@ -41,5 +41,6 @@ namespace CEC CVLCommandHandler(CCECBusDevice *busDevice); virtual ~CVLCommandHandler(void) {}; virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_PANASONIC; }; + virtual bool InitHandler(void); }; };