From: Lars Op den Kamp Date: Thu, 29 Dec 2011 02:11:43 +0000 (+0100) Subject: Merge branch 'master' into release X-Git-Tag: upstream/2.2.0~1^2~43 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=fe0cd8aa72091d860ad374abcbc0d8217f25ba69;hp=32fe963d1e884cbe0016ca880212111a1ba94e42;p=deb_libcec.git Merge branch 'master' into release --- diff --git a/ChangeLog b/ChangeLog index c24e400..26e7662 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +libcec (1.3-2) unstable; urgency=low + + * changed/added: + * copy libcec.dll to the XBMC installation dir when XBMC is found + * disable background polling. let the client request this info when needed + * update the power status of a device when it's set to + CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON + * wait for the correct response when requesting something, not just any + response + * don't keep trying the same command/request after receiving a feature + abort message + * interface changes: + * change the previously unused boolean parameter in volume control methods + to bSendRelease, and only send a key release when it's true. default to + true + * fixed: + * don't send the power up/down keypress to listeners when in the initial + device state (powered off). fixes unexpected shutdown in XBMC when + connecting to the CEC adapter. + * send a 'menu state activated' command when starting up. bugzid: 113 + * don't wait for a response when not needed + * don't hold a lock while waiting for a response. fixes failed libCEC + inits and slow responses + * don't replace a command handler when it's being used. fixes possible + crash on startup + * don't try to do anything before the processor thread has started + * don't transmit active source messages when the physical address is + still 0xFFFF + * don't init the default handler before the physical address is known + + -- Pulse-Eight Packaging Thu, 29 Dec 2011 03:05:00 +0100 + libcec (1.3-1) unstable; urgency=low * changed/added: diff --git a/debian/changelog b/debian/changelog index c24e400..26e7662 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,35 @@ +libcec (1.3-2) unstable; urgency=low + + * changed/added: + * copy libcec.dll to the XBMC installation dir when XBMC is found + * disable background polling. let the client request this info when needed + * update the power status of a device when it's set to + CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON + * wait for the correct response when requesting something, not just any + response + * don't keep trying the same command/request after receiving a feature + abort message + * interface changes: + * change the previously unused boolean parameter in volume control methods + to bSendRelease, and only send a key release when it's true. default to + true + * fixed: + * don't send the power up/down keypress to listeners when in the initial + device state (powered off). fixes unexpected shutdown in XBMC when + connecting to the CEC adapter. + * send a 'menu state activated' command when starting up. bugzid: 113 + * don't wait for a response when not needed + * don't hold a lock while waiting for a response. fixes failed libCEC + inits and slow responses + * don't replace a command handler when it's being used. fixes possible + crash on startup + * don't try to do anything before the processor thread has started + * don't transmit active source messages when the physical address is + still 0xFFFF + * don't init the default handler before the physical address is known + + -- Pulse-Eight Packaging Thu, 29 Dec 2011 03:05:00 +0100 + libcec (1.3-1) unstable; urgency=low * changed/added: diff --git a/include/cec.h b/include/cec.h index 88381c4..61e4bb3 100644 --- a/include/cec.h +++ b/include/cec.h @@ -286,24 +286,24 @@ namespace CEC /*! * @brief Sends a volume up keypress to an audiosystem if it's present. - * @param bWait Wait for the response of the audiosystem when true. + * @param bSendRelease Send a key release after the keypress. * @return The new audio status. */ - virtual uint8_t VolumeUp(bool bWait = true) = 0; + virtual uint8_t VolumeUp(bool bSendRelease = true) = 0; /*! * @brief Sends a volume down keypress to an audiosystem if it's present. - * @param bWait Wait for the response of the audiosystem when true. + * @param bSendRelease Send a key release after the keypress. * @return The new audio status. */ - virtual uint8_t VolumeDown(bool bWait = true) = 0; + virtual uint8_t VolumeDown(bool bSendRelease = true) = 0; /*! * @brief Sends a mute keypress to an audiosystem if it's present. - * @param bWait Wait for the response of the audiosystem when true. + * @param bSendRelease Send a key release after the keypress. * @return The new audio status. */ - virtual uint8_t MuteAudio(bool bWait = true) = 0; + virtual uint8_t MuteAudio(bool bSendRelease = true) = 0; /*! * @brief Send a keypress to a device on the CEC bus. diff --git a/include/cecc.h b/include/cecc.h index 37bccc1..ddb141b 100644 --- a/include/cecc.h +++ b/include/cecc.h @@ -227,11 +227,11 @@ extern DECLSPEC int cec_set_hdmi_port(CEC::cec_logical_address iBaseDevice, uint extern DECLSPEC int cec_set_hdmi_port(cec_logical_address iBaseDevice, uint8_t iPort); #endif -extern DECLSPEC int cec_volume_up(int bWait); +extern DECLSPEC int cec_volume_up(int bSendRelease); -extern DECLSPEC int cec_volume_down(int bWait); +extern DECLSPEC int cec_volume_down(int bSendRelease); -extern DECLSPEC int cec_mute_audio(int bWait); +extern DECLSPEC int cec_mute_audio(int bSendRelease); #ifdef __cplusplus extern DECLSPEC int cec_send_keypress(CEC::cec_logical_address iDestination, CEC::cec_user_control_code key, int bWait); diff --git a/project/libCEC.nsi b/project/libCEC.nsi index 591cc1d..36cd65b 100644 --- a/project/libCEC.nsi +++ b/project/libCEC.nsi @@ -56,6 +56,13 @@ Section "libCEC" SecLibCEC File "..\pthreadVC2.dll" File "..\README" + ; Copy to XBMC\system + ReadRegStr $1 HKCU "Software\XBMC" "" + ${If} $1 != "" + SetOutPath "$1\system" + File "..\libcec.dll" + ${EndIf} + SetOutPath "$INSTDIR\driver" File "..\dpinst-amd64.exe" File "..\dpinst-x86.exe" diff --git a/project/libcec.rc b/project/libcec.rc index 1fe06c5..afac3b1 100644 Binary files a/project/libcec.rc and b/project/libcec.rc differ diff --git a/project/testclient.rc b/project/testclient.rc index c63d3c9..e21afdc 100644 Binary files a/project/testclient.rc and b/project/testclient.rc differ diff --git a/src/CecSharpTester/AssemblyInfo.cs b/src/CecSharpTester/AssemblyInfo.cs index 058bbb9..5bddf86 100644 --- a/src/CecSharpTester/AssemblyInfo.cs +++ b/src/CecSharpTester/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.3.1.0")] +[assembly: AssemblyFileVersion("1.3.1.0")] diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 60a6d19..6af0664 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -49,13 +49,13 @@ using namespace std; CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec_logical_address iLogicalAddress /* = CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS*/) : m_bStarted(false), + m_bInitialised(false), m_iHDMIPort(CEC_DEFAULT_HDMI_PORT), m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE), m_lastInitiator(CECDEVICE_UNKNOWN), m_strDeviceName(strDeviceName), m_controller(controller), m_bMonitor(false), - m_busScan(NULL), m_iStandardLineTimeout(3), m_iRetryLineTimeout(3), m_iLastTransmission(0) @@ -70,6 +70,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types) : m_bStarted(false), + m_bInitialised(false), m_iHDMIPort(CEC_DEFAULT_HDMI_PORT), m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE), m_strDeviceName(strDeviceName), @@ -130,46 +131,70 @@ CCECProcessor::~CCECProcessor(void) bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = 38400 */, uint32_t iTimeoutMs /* = 10000 */) { - CLockObject lock(&m_mutex); - if (!m_communication || m_communication->IsOpen()) - { - m_controller->AddLog(CEC_LOG_ERROR, "connection already opened"); - return false; - } + bool bReturn(false); - if (!m_communication->Open(strPort, iBaudRate, iTimeoutMs)) { - m_controller->AddLog(CEC_LOG_ERROR, "could not open a connection"); - return false; - } + CLockObject lock(&m_mutex); - if (CreateThread()) - { - if (!m_startCondition.Wait(&m_mutex) || !m_bStarted) + /* check for an already opened connection */ + if (!m_communication || m_communication->IsOpen()) { - m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread"); - return false; + m_controller->AddLog(CEC_LOG_ERROR, "connection already opened"); + return bReturn; } - lock.Leave(); - - m_busDevices[CECDEVICE_TV]->GetVendorId(); - - if (SetHDMIPort(m_iBaseDevice, m_iHDMIPort, true)) + /* open a new connection */ + if (!m_communication->Open(strPort, iBaudRate, iTimeoutMs)) { - m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started"); - m_busScan = new CCECBusScan(this); - m_busScan->CreateThread(true); - return true; + m_controller->AddLog(CEC_LOG_ERROR, "could not open a connection"); + return bReturn; } - else + + /* create the processor thread */ + if (!CreateThread() || !m_startCondition.Wait(&m_mutex) || !m_bStarted) { - m_controller->AddLog(CEC_LOG_ERROR, "failed to initialise the processor"); + m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread"); + return bReturn; } } - m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread"); - return false; + /* find the logical address for the adapter */ + bReturn = m_logicalAddresses.IsEmpty() ? FindLogicalAddresses() : true; + if (!bReturn) + m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addresses"); + + /* set the physical address for the adapter */ + if (bReturn) + { + /* only set our OSD name for the primary device */ + 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(); + ReplaceHandlers(); + + bReturn = SetHDMIPort(m_iBaseDevice, m_iHDMIPort, true); + } + + /* make the primary device the active source */ + if (bReturn) + { + m_bInitialised = true; + m_busDevices[m_logicalAddresses.primary]->m_bActiveSource = true; + bReturn = m_busDevices[CECDEVICE_TV]->InitHandler(); + } + + if (bReturn) + { + m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started"); + } + else + { + m_controller->AddLog(CEC_LOG_ERROR, "could not create a processor thread"); + StopThread(true); + } + + return bReturn; } bool CCECProcessor::TryLogicalAddress(cec_logical_address address) @@ -238,30 +263,25 @@ bool CCECProcessor::FindLogicalAddresses(void) bReturn &= FindLogicalAddressAudioSystem(); } + if (bReturn) + SetAckMask(m_logicalAddresses.AckMask()); + return bReturn; } +void CCECProcessor::ReplaceHandlers(void) +{ + for (uint8_t iPtr = 0; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++) + m_busDevices[iPtr]->ReplaceHandler(m_bInitialised); +} + void *CCECProcessor::Process(void) { bool bParseFrame(false); cec_command command; CCECAdapterMessage msg; - if (m_logicalAddresses.IsEmpty() && !FindLogicalAddresses()) { - CLockObject lock(&m_mutex); - m_controller->AddLog(CEC_LOG_ERROR, "could not detect our logical addresses"); - m_startCondition.Signal(); - return NULL; - } - else - { - /* only set our OSD name and active source for the primary device */ - m_busDevices[m_logicalAddresses.primary]->m_strDeviceName = m_strDeviceName; - m_busDevices[m_logicalAddresses.primary]->m_bActiveSource = true; - - SetAckMask(m_logicalAddresses.AckMask()); - CLockObject lock(&m_mutex); m_bStarted = true; m_controller->AddLog(CEC_LOG_DEBUG, "processor thread started"); @@ -270,6 +290,7 @@ void *CCECProcessor::Process(void) while (!IsStopped()) { + ReplaceHandlers(); command.Clear(); msg.clear(); @@ -295,13 +316,6 @@ void *CCECProcessor::Process(void) m_controller->CheckKeypressTimeout(); } - if (m_busScan) - { - m_busScan->StopThread(); - delete m_busScan; - m_busScan = NULL; - } - if (m_communication) m_communication->Close(); @@ -330,12 +344,15 @@ bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RE } m_busDevices[addr]->SetActiveSource(); - bReturn = m_busDevices[addr]->TransmitActiveSource(); - - if (bReturn && (m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || - m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)) + if (m_busDevices[addr]->GetPhysicalAddress(false) != 0xFFFF) { - bReturn = ((CCECPlaybackDevice *)m_busDevices[addr])->TransmitDeckStatus(CECDEVICE_TV); + bReturn = m_busDevices[addr]->TransmitActiveSource(); + + if (bReturn && (m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || + m_busDevices[addr]->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)) + { + bReturn = ((CCECPlaybackDevice *)m_busDevices[addr])->TransmitDeckStatus(CECDEVICE_TV); + } } return bReturn; @@ -407,11 +424,14 @@ bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true * bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */) { bool bReturn(false); + { + CLockObject lock(&m_mutex); - m_iBaseDevice = iBaseDevice; - m_iHDMIPort = iPort; - if (!m_bStarted && !bForce) - return true; + m_iBaseDevice = iBaseDevice; + m_iHDMIPort = iPort; + if (!m_bStarted && !bForce) + return true; + } CStdString strLog; strLog.Format("setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice); @@ -421,44 +441,24 @@ bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, if (iBaseDevice > CECDEVICE_TV) iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress(); - if (iPhysicalAddress == 0xffff) - { - SetPhysicalAddress((uint16_t)iPort * 0x1000); - bReturn = false; - } - else + if (iPhysicalAddress < 0xffff) { - uint16_t iPos = 0; if (iPhysicalAddress == 0) - iPos = 0x1000; + iPhysicalAddress += 0x1000 * iPort; else if (iPhysicalAddress % 0x1000 == 0) - iPos = 0x100; + iPhysicalAddress += 0x100 * iPort; else if (iPhysicalAddress % 0x100 == 0) - iPos = 0x10; + iPhysicalAddress += 0x10 * iPort; else if (iPhysicalAddress % 0x10 == 0) - iPos = 0x1; + iPhysicalAddress += iPort; - while(!bReturn && iPos > 0) - { - iPhysicalAddress += (uint16_t)(iPort * iPos); - strLog.Format("checking physical address %4x", iPhysicalAddress); - AddLog(CEC_LOG_DEBUG, strLog); - if (PhysicalAddressInUse(iPhysicalAddress)) - { - strLog.Format("physical address %4x is in use", iPhysicalAddress); - AddLog(CEC_LOG_DEBUG, strLog); - iPos = (iPos == 1) ? 0 : iPos / 0x10; - } - else - { - strLog.Format("physical address %4x is free", iPhysicalAddress); - AddLog(CEC_LOG_DEBUG, strLog); - SetPhysicalAddress(iPhysicalAddress); - bReturn = true; - } - } + SetPhysicalAddress(iPhysicalAddress); + bReturn = true; } + if (!bReturn) + m_controller->AddLog(CEC_LOG_ERROR, "failed to set the physical address"); + return bReturn; } @@ -496,6 +496,7 @@ void CCECProcessor::LogOutput(const cec_command &data) bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress) { + CLockObject lock(&m_mutex); if (m_logicalAddresses.primary != iLogicalAddress) { CStdString strLog; @@ -525,6 +526,7 @@ bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = tru bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress) { + CLockObject lock(&m_mutex); if (!m_logicalAddresses.IsEmpty()) { for (uint8_t iPtr = 0; iPtr < 15; iPtr++) @@ -548,24 +550,6 @@ bool CCECProcessor::SwitchMonitoring(bool bEnable) { CLockObject lock(&m_mutex); m_bMonitor = bEnable; - - if (!bEnable) - { - if (!m_busScan) - { - m_busScan = new CCECBusScan(this); - m_busScan->CreateThread(true); - } - } - else - { - if (m_busScan) - { - m_busScan->StopThread(); - delete m_busScan; - m_busScan = NULL; - } - } } if (bEnable) @@ -585,29 +569,29 @@ bool CCECProcessor::PollDevice(cec_logical_address iAddress) return false; } -uint8_t CCECProcessor::VolumeUp(void) +uint8_t CCECProcessor::VolumeUp(bool bSendRelease /* = true */) { uint8_t status = 0; if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM)) - status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeUp(); + status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeUp(bSendRelease); return status; } -uint8_t CCECProcessor::VolumeDown(void) +uint8_t CCECProcessor::VolumeDown(bool bSendRelease /* = true */) { uint8_t status = 0; if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM)) - status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeDown(); + status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeDown(bSendRelease); return status; } -uint8_t CCECProcessor::MuteAudio(void) +uint8_t CCECProcessor::MuteAudio(bool bSendRelease /* = true */) { uint8_t status = 0; if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM)) - status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->MuteAudio(); + status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->MuteAudio(bSendRelease); return status; } @@ -634,9 +618,9 @@ CCECBusDevice *CCECProcessor::GetDeviceByType(cec_device_type type) const { CCECBusDevice *device = NULL; - for (unsigned int iPtr = 0; iPtr < 16; iPtr++) + for (uint8_t iPtr = 0; iPtr < 16; iPtr++) { - if (m_busDevices[iPtr]->m_type == type) + if (m_busDevices[iPtr]->m_type == type && m_logicalAddresses[iPtr]) { device = m_busDevices[iPtr]; break; @@ -646,6 +630,15 @@ CCECBusDevice *CCECProcessor::GetDeviceByType(cec_device_type type) const return device; } +CCECBusDevice *CCECProcessor::GetPrimaryDevice(void) const +{ + CCECBusDevice *device(NULL); + cec_logical_address primary = m_logicalAddresses.primary; + if (primary != CECDEVICE_UNKNOWN) + device = m_busDevices[primary]; + return device; +} + cec_version CCECProcessor::GetDeviceCecVersion(cec_logical_address iAddress) { return m_busDevices[iAddress]->GetCecVersion(); @@ -1002,14 +995,14 @@ bool CCECProcessor::SetAckMask(uint16_t iMask) return bReturn; } -bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key) +bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */) { - return m_busDevices[iDestination]->TransmitKeypress(key); + return m_busDevices[iDestination]->TransmitKeypress(key, bWait); } -bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination) +bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination, bool bWait /* = true */) { - return m_busDevices[iDestination]->TransmitKeyRelease(); + return m_busDevices[iDestination]->TransmitKeyRelease(bWait); } const char *CCECProcessor::ToString(const cec_menu_state state) diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index a0e0e73..13243ab 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -59,6 +59,7 @@ namespace CEC virtual bool IsMonitoring(void) const { return m_bMonitor; } virtual CCECBusDevice * GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh = false) const; virtual CCECBusDevice * GetDeviceByType(cec_device_type type) const; + virtual CCECBusDevice * GetPrimaryDevice(void) const; virtual cec_version GetDeviceCecVersion(cec_logical_address iAddress); virtual bool GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language); virtual const std::string & GetDeviceName(void) { return m_strDeviceName; } @@ -77,6 +78,7 @@ namespace CEC virtual bool IsStarted(void) const { return m_bStarted; } virtual cec_logical_address GetActiveSource(void); virtual bool IsActiveSource(cec_logical_address iAddress); + virtual bool IsInitialised(void) const { return m_bInitialised; } virtual bool SetActiveView(void); virtual bool SetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED); @@ -90,11 +92,11 @@ namespace CEC virtual bool SetActiveSource(uint16_t iStreamPath); virtual bool SwitchMonitoring(bool bEnable); virtual bool PollDevice(cec_logical_address iAddress); - virtual uint8_t VolumeUp(void); - virtual uint8_t VolumeDown(void); - virtual uint8_t MuteAudio(void); - virtual bool TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key); - virtual bool TransmitKeyRelease(cec_logical_address iDestination); + virtual uint8_t VolumeUp(bool bSendRelease = true); + virtual uint8_t VolumeDown(bool bSendRelease = true); + virtual uint8_t MuteAudio(bool bSendRelease = true); + virtual bool TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = true); + virtual bool TransmitKeyRelease(cec_logical_address iDestination, bool bWait = true); virtual bool EnablePhysicalAddressDetection(void) { return false; }; void SetStandardLineTimeout(uint8_t iTimeout); void SetRetryLineTimeout(uint8_t iTimeout); @@ -132,6 +134,7 @@ namespace CEC CMutex m_transmitMutex; private: + void ReplaceHandlers(void); void ScanCECBus(void); bool PhysicalAddressInUse(uint16_t iPhysicalAddress); bool TryLogicalAddress(cec_logical_address address); @@ -146,6 +149,7 @@ namespace CEC void ParseCommand(cec_command &command); bool m_bStarted; + bool m_bInitialised; uint8_t m_iHDMIPort; cec_logical_address m_iBaseDevice; cec_command m_currentframe; diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index 0ca0188..1366ff6 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -278,39 +278,39 @@ bool CLibCEC::IsActiveDeviceType(cec_device_type type) return false; } -uint8_t CLibCEC::VolumeUp(bool bWait /* = true */) +uint8_t CLibCEC::VolumeUp(bool bSendRelease /* = true */) { if (m_cec) - return m_cec->VolumeUp(); + return m_cec->VolumeUp(bSendRelease); return 0; } -uint8_t CLibCEC::VolumeDown(bool bWait /* = true */) +uint8_t CLibCEC::VolumeDown(bool bSendRelease /* = true */) { if (m_cec) - return m_cec->VolumeDown(); + return m_cec->VolumeDown(bSendRelease); return 0; } -uint8_t CLibCEC::MuteAudio(bool bWait /* = true */) +uint8_t CLibCEC::MuteAudio(bool bSendRelease /* = true */) { if (m_cec) - return m_cec->MuteAudio(); + return m_cec->MuteAudio(bSendRelease); return 0; } -bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = false */) +bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */) { if (m_cec) - return m_cec->TransmitKeypress(iDestination, key); + return m_cec->TransmitKeypress(iDestination, key, bWait); return false; } -bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = false */) +bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = true */) { if (m_cec) - return m_cec->TransmitKeyRelease(iDestination); + return m_cec->TransmitKeyRelease(iDestination, bWait); return false; } diff --git a/src/lib/LibCEC.h b/src/lib/LibCEC.h index c891790..9c3e8f1 100644 --- a/src/lib/LibCEC.h +++ b/src/lib/LibCEC.h @@ -89,11 +89,11 @@ namespace CEC virtual bool IsActiveDevice(cec_logical_address iAddress); virtual bool IsActiveDeviceType(cec_device_type type); virtual bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort = CEC_DEFAULT_HDMI_PORT); - virtual uint8_t VolumeUp(bool bWait = true); - virtual uint8_t VolumeDown(bool bWait = true); - virtual uint8_t MuteAudio(bool bWait = true); - virtual bool SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = false); - virtual bool SendKeyRelease(cec_logical_address iDestination, bool bWait = false); + virtual uint8_t VolumeUp(bool bSendRelease = true); + virtual uint8_t VolumeDown(bool bSendRelease = true); + virtual uint8_t MuteAudio(bool bSendRelease = true); + virtual bool SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = true); + virtual bool SendKeyRelease(cec_logical_address iDestination, bool bWait = true); virtual cec_osd_name GetDeviceOSDName(cec_logical_address iAddress); virtual bool EnablePhysicalAddressDetection(void); virtual cec_logical_address GetActiveSource(void); diff --git a/src/lib/LibCECC.cpp b/src/lib/LibCECC.cpp index 938e0b7..cbf7b28 100644 --- a/src/lib/LibCECC.cpp +++ b/src/lib/LibCECC.cpp @@ -312,24 +312,24 @@ int cec_set_hdmi_port(cec_logical_address iBaseDevice, uint8_t iPort) return -1; } -int cec_volume_up(int bWait) +int cec_volume_up(int bSendRelease) { if (cec_parser) - return cec_parser->VolumeUp(bWait == 1); + return cec_parser->VolumeUp(bSendRelease == 1); return -1; } -int cec_volume_down(int bWait) +int cec_volume_down(int bSendRelease) { if (cec_parser) - return cec_parser->VolumeDown(bWait == 1); + return cec_parser->VolumeDown(bSendRelease == 1); return -1; } -int cec_mute_audio(int bWait) +int cec_mute_audio(int bSendRelease) { if (cec_parser) - return cec_parser->MuteAudio(bWait == 1); + return cec_parser->MuteAudio(bSendRelease == 1); return -1; } diff --git a/src/lib/devices/CECAudioSystem.cpp b/src/lib/devices/CECAudioSystem.cpp index 81a92c3..87b4505 100644 --- a/src/lib/devices/CECAudioSystem.cpp +++ b/src/lib/devices/CECAudioSystem.cpp @@ -48,7 +48,7 @@ CCECAudioSystem::CCECAudioSystem(CCECProcessor *processor, cec_logical_address a bool CCECAudioSystem::SetAudioStatus(uint8_t status) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_audioStatus != status) { CStdString strLog; @@ -64,7 +64,7 @@ bool CCECAudioSystem::SetAudioStatus(uint8_t status) bool CCECAudioSystem::SetSystemAudioModeStatus(const cec_system_audio_status mode) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_systemAudioStatus != mode) { CStdString strLog; @@ -82,7 +82,7 @@ bool CCECAudioSystem::TransmitAudioStatus(cec_logical_address dest) { uint8_t state; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); CStdString strLog; strLog.Format("<< %x -> %x: audio status '%2x'", m_iLogicalAddress, dest, m_audioStatus); AddLog(CEC_LOG_NOTICE, strLog); @@ -96,7 +96,7 @@ bool CCECAudioSystem::TransmitSetSystemAudioMode(cec_logical_address dest) { cec_system_audio_status state; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); CStdString strLog; strLog.Format("<< %x -> %x: set system audio mode '%2x'", m_iLogicalAddress, dest, m_audioStatus); AddLog(CEC_LOG_NOTICE, strLog); @@ -110,7 +110,7 @@ bool CCECAudioSystem::TransmitSystemAudioModeStatus(cec_logical_address dest) { cec_system_audio_status state; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); CStdString strLog; strLog.Format("<< %x -> %x: system audio mode '%s'", m_iLogicalAddress, dest, ToString(m_systemAudioStatus)); AddLog(CEC_LOG_NOTICE, strLog); @@ -120,27 +120,27 @@ bool CCECAudioSystem::TransmitSystemAudioModeStatus(cec_logical_address dest) return m_handler->TransmitSystemAudioModeStatus(m_iLogicalAddress, dest, state); } -uint8_t CCECAudioSystem::VolumeUp(void) +uint8_t CCECAudioSystem::VolumeUp(bool bSendRelease /* = true */) { - if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_UP)) + if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_UP) && bSendRelease) TransmitKeyRelease(); CLockObject lock(&m_mutex); return m_audioStatus; } -uint8_t CCECAudioSystem::VolumeDown(void) +uint8_t CCECAudioSystem::VolumeDown(bool bSendRelease /* = true */) { - if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_DOWN)) + if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_DOWN) && bSendRelease) TransmitKeyRelease(); CLockObject lock(&m_mutex); return m_audioStatus; } -uint8_t CCECAudioSystem::MuteAudio(void) +uint8_t CCECAudioSystem::MuteAudio(bool bSendRelease /* = true */) { - if (TransmitKeypress(CEC_USER_CONTROL_CODE_MUTE)) + if (TransmitKeypress(CEC_USER_CONTROL_CODE_MUTE) && bSendRelease) TransmitKeyRelease(); CLockObject lock(&m_mutex); diff --git a/src/lib/devices/CECAudioSystem.h b/src/lib/devices/CECAudioSystem.h index 291b0ec..dc35ef0 100644 --- a/src/lib/devices/CECAudioSystem.h +++ b/src/lib/devices/CECAudioSystem.h @@ -47,9 +47,9 @@ namespace CEC virtual bool TransmitSetSystemAudioMode(cec_logical_address dest); virtual bool TransmitSystemAudioModeStatus(cec_logical_address dest); - virtual uint8_t VolumeUp(void); - virtual uint8_t VolumeDown(void); - virtual uint8_t MuteAudio(void); + virtual uint8_t VolumeUp(bool bSendRelease = true); + virtual uint8_t VolumeDown(bool bSendRelease = true); + virtual uint8_t MuteAudio(bool bSendRelease = true); virtual bool TransmitActiveSource(void) { return false; } diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 41643a3..bd68dfc 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -50,11 +50,13 @@ CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogi m_powerStatus(CEC_POWER_STATUS_UNKNOWN), m_processor(processor), m_vendor(CEC_VENDOR_UNKNOWN), + m_bReplaceHandler(false), m_menuState(CEC_MENU_STATE_ACTIVATED), m_bActiveSource(false), m_iLastActive(0), m_cecVersion(CEC_VERSION_UNKNOWN), - m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN) + m_deviceStatus(CEC_DEVICE_STATUS_UNKNOWN), + m_handlerMutex(false) { m_handler = new CCECCommandHandler(this); @@ -82,7 +84,7 @@ bool CCECBusDevice::HandleCommand(const cec_command &command) /* update "last active" */ { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); m_iLastActive = GetTimeMs(); if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC) @@ -95,7 +97,7 @@ bool CCECBusDevice::HandleCommand(const cec_command &command) /* change status to present */ if (bHandled) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC) { if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT) @@ -117,7 +119,7 @@ bool CCECBusDevice::PowerOn(void) strLog.Format("<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); AddLog(CEC_LOG_DEBUG, strLog.c_str()); - if (m_handler->TransmitPowerOn(GetMyLogicalAddress(), m_iLogicalAddress)) + if (m_handler->TransmitImageViewOn(GetMyLogicalAddress(), m_iLogicalAddress)) { { CLockObject lock(&m_mutex); @@ -154,17 +156,24 @@ bool CCECBusDevice::Standby(void) //@{ cec_version CCECBusDevice::GetCecVersion(bool bUpdate /* = false */) { - CLockObject lock(&m_mutex); - if (GetStatus() == CEC_DEVICE_STATUS_PRESENT && - (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN)) + bool bRequestUpdate(false); + { + CLockObject lock(&m_mutex); + bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT && + (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN)); + } + + if (bRequestUpdate) RequestCecVersion(); + CLockObject lock(&m_mutex); return m_cecVersion; } bool CCECBusDevice::RequestCecVersion(void) { bool bReturn(false); + if (!MyLogicalAddressContains(m_iLogicalAddress)) { CStdString strLog; @@ -183,18 +192,26 @@ const char* CCECBusDevice::GetLogicalAddressName(void) const cec_menu_language &CCECBusDevice::GetMenuLanguage(bool bUpdate /* = false */) { - CLockObject lock(&m_mutex); - if (GetStatus() == CEC_DEVICE_STATUS_PRESENT && - (bUpdate || !strcmp(m_menuLanguage.language, "???"))) + bool bRequestUpdate(false); + { + CLockObject lock(&m_mutex); + bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT && + (bUpdate || !strcmp(m_menuLanguage.language, "???"))); + } + + if (bRequestUpdate) RequestMenuLanguage(); + CLockObject lock(&m_mutex); return m_menuLanguage; } bool CCECBusDevice::RequestMenuLanguage(void) { bool bReturn(false); - if (!MyLogicalAddressContains(m_iLogicalAddress)) + + if (!MyLogicalAddressContains(m_iLogicalAddress) && + !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE)) { CStdString strLog; strLog.Format("<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); @@ -216,19 +233,27 @@ uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const CStdString CCECBusDevice::GetOSDName(bool bUpdate /* = false */) { - CLockObject lock(&m_mutex); - if (GetStatus() == CEC_DEVICE_STATUS_PRESENT && - (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) && - m_type != CEC_DEVICE_TYPE_TV) + bool bRequestUpdate(false); + { + CLockObject lock(&m_mutex); + bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT && + (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) && + m_type != CEC_DEVICE_TYPE_TV); + } + + if (bRequestUpdate) RequestOSDName(); + CLockObject lock(&m_mutex); return m_strDeviceName; } bool CCECBusDevice::RequestOSDName(void) { bool bReturn(false); - if (!MyLogicalAddressContains(m_iLogicalAddress)) + + if (!MyLogicalAddressContains(m_iLogicalAddress) && + !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME)) { CStdString strLog; strLog.Format("<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); @@ -240,20 +265,24 @@ bool CCECBusDevice::RequestOSDName(void) uint16_t CCECBusDevice::GetPhysicalAddress(bool bUpdate /* = false */) { - CLockObject lock(&m_mutex); - if (GetStatus() == CEC_DEVICE_STATUS_PRESENT && - (m_iPhysicalAddress == 0xFFFF || bUpdate)) + bool bRequestUpdate(false); { - if (!RequestPhysicalAddress()) - AddLog(CEC_LOG_ERROR, "failed to request the physical address"); + CLockObject lock(&m_mutex); + bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT && + (m_iPhysicalAddress == 0xFFFF || bUpdate)); } + if (bRequestUpdate && !RequestPhysicalAddress()) + AddLog(CEC_LOG_ERROR, "failed to request the physical address (1)"); + + CLockObject lock(&m_mutex); return m_iPhysicalAddress; } bool CCECBusDevice::RequestPhysicalAddress(void) { bool bReturn(false); + if (!MyLogicalAddressContains(m_iLogicalAddress)) { CStdString strLog; @@ -266,18 +295,27 @@ bool CCECBusDevice::RequestPhysicalAddress(void) cec_power_status CCECBusDevice::GetPowerStatus(bool bUpdate /* = false */) { - CLockObject lock(&m_mutex); - if (GetStatus() == CEC_DEVICE_STATUS_PRESENT && - (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN)) + bool bRequestUpdate(false); + { + CLockObject lock(&m_mutex); + bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT && + (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN || + m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)); + } + + if (bRequestUpdate) RequestPowerStatus(); + CLockObject lock(&m_mutex); return m_powerStatus; } bool CCECBusDevice::RequestPowerStatus(void) { bool bReturn(false); - if (!MyLogicalAddressContains(m_iLogicalAddress)) + + if (!MyLogicalAddressContains(m_iLogicalAddress) && + !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS)) { CStdString strLog; strLog.Format("<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress); @@ -289,17 +327,24 @@ bool CCECBusDevice::RequestPowerStatus(void) cec_vendor_id CCECBusDevice::GetVendorId(bool bUpdate /* = false */) { - CLockObject lock(&m_mutex); - if (GetStatus() == CEC_DEVICE_STATUS_PRESENT && - (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN)) + bool bRequestUpdate(false); + { + CLockObject lock(&m_mutex); + bRequestUpdate = (GetStatus() == CEC_DEVICE_STATUS_PRESENT && + (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN)); + } + + if (bRequestUpdate) RequestVendorId(); + CLockObject lock(&m_mutex); return m_vendor; } bool CCECBusDevice::RequestVendorId(void) { bool bReturn(false); + if (!MyLogicalAddressContains(m_iLogicalAddress)) { CStdString strLog; @@ -369,7 +414,7 @@ bool CCECBusDevice::NeedsPoll(void) cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC && (m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN || bForcePoll)) { @@ -400,7 +445,7 @@ void CCECBusDevice::SetCecVersion(const cec_version newVersion) void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (language.device == m_iLogicalAddress) { CStdString strLog; @@ -412,7 +457,7 @@ void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language) void CCECBusDevice::SetOSDName(CStdString strName) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_strDeviceName != strName) { CStdString strLog; @@ -424,7 +469,7 @@ void CCECBusDevice::SetOSDName(CStdString strName) void CCECBusDevice::SetMenuState(const cec_menu_state state) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_menuState != state) { CStdString strLog; @@ -437,7 +482,7 @@ void CCECBusDevice::SetMenuState(const cec_menu_state state) void CCECBusDevice::SetInactiveSource(void) { { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); m_bActiveSource = false; } @@ -447,7 +492,7 @@ void CCECBusDevice::SetInactiveSource(void) void CCECBusDevice::SetActiveSource(void) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); for (int iPtr = 0; iPtr < 16; iPtr++) if (iPtr != m_iLogicalAddress) @@ -481,7 +526,7 @@ bool CCECBusDevice::TryLogicalAddress(void) void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); switch (newStatus) { case CEC_DEVICE_STATUS_UNKNOWN: @@ -513,7 +558,7 @@ void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus) void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress) { CStdString strLog; @@ -526,7 +571,7 @@ void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress) void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = 0 */) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (iNewAddress > 0) { CStdString strLog; @@ -545,7 +590,7 @@ void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_powerStatus != powerStatus) { CStdString strLog; @@ -555,41 +600,51 @@ void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus) } } -bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */) +bool CCECBusDevice::ReplaceHandler(bool bInitHandler /* = true */) { - bool bVendorChanged(false); + CLockObject lock(&m_mutex); + CLockObject handlerLock(&m_handlerMutex); + if (m_vendor != m_handler->GetVendorId()) { - CLockObject lock(&m_writeMutex); - bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId); - m_vendor = (cec_vendor_id)iVendorId; + if (m_handler->InUse()) + return false; - if (bVendorChanged) - delete m_handler; + delete m_handler; - switch (iVendorId) + switch (m_vendor) { case CEC_VENDOR_SAMSUNG: - if (bVendorChanged) - m_handler = new CANCommandHandler(this); + m_handler = new CANCommandHandler(this); break; case CEC_VENDOR_LG: - if (bVendorChanged) - m_handler = new CSLCommandHandler(this); + m_handler = new CSLCommandHandler(this); break; case CEC_VENDOR_PANASONIC: - if (bVendorChanged) - m_handler = new CVLCommandHandler(this); + m_handler = new CVLCommandHandler(this); break; default: - if (bVendorChanged) - m_handler = new CCECCommandHandler(this); + m_handler = new CCECCommandHandler(this); break; } + + if (bInitHandler && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised()) + m_handler->InitHandler(); } - if (bVendorChanged && bInitHandler) - m_handler->InitHandler(); + return true; +} + +bool CCECBusDevice::SetVendorId(uint64_t iVendorId, bool bInitHandler /* = true */) +{ + bool bVendorChanged(false); + + { + CLockObject lock(&m_mutex); + bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId); + m_vendor = (cec_vendor_id)iVendorId; + ReplaceHandler(bInitHandler); + } CStdString strLog; strLog.Format("%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor); @@ -606,7 +661,7 @@ bool CCECBusDevice::TransmitActiveSource(void) bool bSendActiveSource(false); { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_powerStatus != CEC_POWER_STATUS_ON) { CStdString strLog; @@ -628,14 +683,21 @@ bool CCECBusDevice::TransmitActiveSource(void) } } - return bSendActiveSource ? m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress) : false; + if (bSendActiveSource) + { + m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV); + m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress); + return true; + } + + return false; } bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest) { cec_version version; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); CStdString strLog; strLog.Format("<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_cecVersion)); AddLog(CEC_LOG_NOTICE, strLog); @@ -649,7 +711,7 @@ bool CCECBusDevice::TransmitInactiveSource(void) { uint16_t iPhysicalAddress; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); CStdString strLog; strLog.Format("<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress); AddLog(CEC_LOG_NOTICE, strLog); @@ -663,7 +725,7 @@ bool CCECBusDevice::TransmitMenuState(cec_logical_address dest) { cec_menu_state menuState; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); CStdString strLog; strLog.Format("<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState)); AddLog(CEC_LOG_NOTICE, strLog); @@ -677,7 +739,7 @@ bool CCECBusDevice::TransmitOSDName(cec_logical_address dest) { CStdString strDeviceName; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); CStdString strLog; strLog.Format("<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, m_strDeviceName.c_str()); AddLog(CEC_LOG_NOTICE, strLog.c_str()); @@ -689,11 +751,15 @@ bool CCECBusDevice::TransmitOSDName(cec_logical_address dest) bool CCECBusDevice::TransmitOSDString(cec_logical_address dest, cec_display_control duration, const char *strMessage) { - CStdString strLog; - strLog.Format("<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, strMessage); - AddLog(CEC_LOG_NOTICE, strLog.c_str()); + if (!IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING)) + { + CStdString strLog; + strLog.Format("<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, strMessage); + AddLog(CEC_LOG_NOTICE, strLog.c_str()); - return m_handler->TransmitOSDString(m_iLogicalAddress, dest, duration, strMessage); + return m_handler->TransmitOSDString(m_iLogicalAddress, dest, duration, strMessage); + } + return false; } bool CCECBusDevice::TransmitPhysicalAddress(void) @@ -701,7 +767,7 @@ bool CCECBusDevice::TransmitPhysicalAddress(void) uint16_t iPhysicalAddress; cec_device_type type; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_iPhysicalAddress == 0xffff) return false; @@ -732,7 +798,7 @@ bool CCECBusDevice::TransmitPoll(cec_logical_address dest) bReturn = m_handler->TransmitPoll(m_iLogicalAddress, dest); AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent"); - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (bReturn) { m_iLastActive = GetTimeMs(); @@ -748,7 +814,7 @@ bool CCECBusDevice::TransmitPowerState(cec_logical_address dest) { cec_power_status state; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); CStdString strLog; strLog.Format("<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_powerStatus)); AddLog(CEC_LOG_NOTICE, strLog.c_str()); @@ -762,7 +828,7 @@ bool CCECBusDevice::TransmitVendorID(cec_logical_address dest, bool bSendAbort / { uint64_t iVendorId; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); iVendorId = (uint64_t)m_vendor; } @@ -788,13 +854,30 @@ bool CCECBusDevice::TransmitVendorID(cec_logical_address dest, bool bSendAbort / } } -bool CCECBusDevice::TransmitKeypress(cec_user_control_code key) +bool CCECBusDevice::TransmitKeypress(cec_user_control_code key, bool bWait /* = true */) { - return m_handler->TransmitKeypress(m_processor->GetLogicalAddress(), m_iLogicalAddress, key); + return m_handler->TransmitKeypress(m_processor->GetLogicalAddress(), m_iLogicalAddress, key, bWait); } -bool CCECBusDevice::TransmitKeyRelease(void) +bool CCECBusDevice::TransmitKeyRelease(bool bWait /* = true */) { - return m_handler->TransmitKeyRelease(m_processor->GetLogicalAddress(), m_iLogicalAddress); + return m_handler->TransmitKeyRelease(m_processor->GetLogicalAddress(), m_iLogicalAddress, bWait); } + +bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode) const +{ + return m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end(); +} + +void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode) +{ + m_unsupportedFeatures.insert(opcode); +} + +bool CCECBusDevice::InitHandler(void) +{ + CLockObject lock(&m_mutex); + return m_handler->InitHandler(); +} + //@} diff --git a/src/lib/devices/CECBusDevice.h b/src/lib/devices/CECBusDevice.h index b8a9aa9..30d8329 100644 --- a/src/lib/devices/CECBusDevice.h +++ b/src/lib/devices/CECBusDevice.h @@ -32,6 +32,7 @@ */ #include +#include #include "../platform/threads.h" #include "../util/StdString.h" @@ -73,11 +74,13 @@ namespace CEC virtual bool MyLogicalAddressContains(cec_logical_address address) const; virtual cec_bus_device_status GetStatus(bool bForcePoll = false); virtual bool IsActiveSource(void) const { return m_bActiveSource; } - + virtual bool IsUnsupportedFeature(cec_opcode opcode) const; + virtual void SetUnsupportedFeature(cec_opcode opcode); virtual void SetInactiveSource(void); virtual void SetActiveSource(void); virtual bool TryLogicalAddress(void); + virtual bool InitHandler(void); virtual void SetDeviceStatus(const cec_bus_device_status newStatus); virtual void SetPhysicalAddress(uint16_t iNewAddress); @@ -99,10 +102,12 @@ namespace CEC virtual bool TransmitPowerState(cec_logical_address dest); virtual bool TransmitPoll(cec_logical_address dest); virtual bool TransmitVendorID(cec_logical_address dest, bool bSendAbort = true); - virtual bool TransmitKeypress(cec_user_control_code key); - virtual bool TransmitKeyRelease(void); + virtual bool TransmitKeypress(cec_user_control_code key, bool bWait = true); + virtual bool TransmitKeyRelease(bool bWait = true); protected: + bool ReplaceHandler(bool bInitHandler = true); + bool RequestCecVersion(void); bool RequestMenuLanguage(void); bool RequestPowerStatus(void); @@ -122,12 +127,14 @@ namespace CEC CCECProcessor * m_processor; CCECCommandHandler * m_handler; cec_vendor_id m_vendor; + bool m_bReplaceHandler; cec_menu_state m_menuState; bool m_bActiveSource; uint64_t m_iLastActive; cec_version m_cecVersion; cec_bus_device_status m_deviceStatus; - CMutex m_writeMutex; + std::set m_unsupportedFeatures; CMutex m_mutex; + CMutex m_handlerMutex; }; }; diff --git a/src/lib/devices/CECPlaybackDevice.cpp b/src/lib/devices/CECPlaybackDevice.cpp index 4c90b9f..4969de5 100644 --- a/src/lib/devices/CECPlaybackDevice.cpp +++ b/src/lib/devices/CECPlaybackDevice.cpp @@ -54,7 +54,7 @@ cec_deck_info CCECPlaybackDevice::GetDeckStatus(void) void CCECPlaybackDevice::SetDeckStatus(cec_deck_info deckStatus) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_deckStatus != deckStatus && m_deckStatus != CEC_DECK_INFO_OTHER_STATUS_LG) { CStdString strLog; @@ -73,7 +73,7 @@ cec_deck_control_mode CCECPlaybackDevice::GetDeckControlMode(void) void CCECPlaybackDevice::SetDeckControlMode(cec_deck_control_mode mode) { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); if (m_deckControlMode != mode) { CStdString strLog; @@ -88,7 +88,7 @@ bool CCECPlaybackDevice::TransmitDeckStatus(cec_logical_address dest) { cec_deck_info state; { - CLockObject lock(&m_writeMutex); + CLockObject lock(&m_mutex); CStdString strLog; strLog.Format("<< %s (%X) -> %s (%X): deck status '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_deckStatus)); AddLog(CEC_LOG_NOTICE, strLog); diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index 80bc280..74f7648 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -44,12 +44,17 @@ CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) : m_processor(m_busDevice->GetProcessor()), m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT), m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT), - m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES) + m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES), + m_bHandlerInited(false), + m_iUseCounter(0), + m_expectedResponse(CEC_OPCODE_NONE) { } CCECCommandHandler::~CCECCommandHandler(void) { + CLockObject lock(&m_processor->m_transmitMutex); + CLockObject receiveLock(&m_receiveMutex); m_condition.Broadcast(); } @@ -57,6 +62,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) { bool bHandled(true), bHandlerChanged(false); + MarkBusy(); CStdString strLog; strLog.Format(">> %s (%X) -> %s (%X): %s (%2X)", m_processor->ToString(command.initiator), command.initiator, m_processor->ToString(command.destination), command.destination, m_processor->ToString(command.opcode), command.opcode); m_busDevice->AddLog(CEC_LOG_NOTICE, strLog); @@ -158,6 +164,12 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) case CEC_OPCODE_TEXT_VIEW_ON: HandleTextViewOn(command); break; + case CEC_OPCODE_FEATURE_ABORT: + HandleFeatureAbort(command); + break; + case CEC_OPCODE_VENDOR_COMMAND: + HandleVendorCommand(command); + break; default: UnhandledCommand(command); bHandled = false; @@ -167,9 +179,12 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) if (bHandled && !bHandlerChanged) { CLockObject lock(&m_receiveMutex); - m_condition.Signal(); + if (m_expectedResponse == CEC_OPCODE_NONE || + m_expectedResponse == command.opcode) + m_condition.Signal(); } + MarkReady(); return bHandled; } @@ -221,6 +236,15 @@ bool CCECCommandHandler::HandleDeviceVendorId(const cec_command &command) return SetVendorId(command); } +bool CCECCommandHandler::HandleFeatureAbort(const cec_command &command) +{ + if (command.parameters.size == 2) + { + m_processor->m_busDevices[command.initiator]->SetUnsupportedFeature((cec_opcode)command.parameters[0]); + } + return true; +} + bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command) { if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination)) @@ -299,7 +323,11 @@ bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command) { CCECBusDevice *device = GetDevice(command.destination); if (device) - return device->TransmitPhysicalAddress(); + { + device->SetActiveSource(); + return device->TransmitPhysicalAddress() && + device->TransmitActiveSource(); + } } return false; @@ -577,8 +605,10 @@ bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command) } } } - - m_processor->SetCurrentButton((cec_user_control_code) command.parameters[0]); + else + { + m_processor->SetCurrentButton((cec_user_control_code) command.parameters[0]); + } return true; } } @@ -685,12 +715,12 @@ bool CCECCommandHandler::HandleReceiveFailed(void) return true; } -bool CCECCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination) +bool CCECCommandHandler::TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -698,7 +728,7 @@ bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, c cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_STANDBY); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -706,7 +736,7 @@ bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iIn cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_CEC_VERSION); - return Transmit(command); + return Transmit(command, true, CEC_OPCODE_CEC_VERSION); } bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -714,7 +744,7 @@ bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address i cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_MENU_LANGUAGE); - return Transmit(command); + return Transmit(command, true, CEC_OPCODE_SET_MENU_LANGUAGE); } bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -722,7 +752,7 @@ bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iIniti cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_OSD_NAME); - return Transmit(command); + return Transmit(command, true, CEC_OPCODE_SET_OSD_NAME); } bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -730,7 +760,7 @@ bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_addres cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS); - return Transmit(command); + return Transmit(command, true, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS); } bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -738,7 +768,7 @@ bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iI cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS); - return Transmit(command); + return Transmit(command, true, CEC_OPCODE_REPORT_POWER_STATUS); } bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -746,7 +776,7 @@ bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInit cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); - return Transmit(command); + return Transmit(command, true, CEC_OPCODE_DEVICE_VENDOR_ID); } bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress) @@ -756,7 +786,7 @@ bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiat command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF)); command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF)); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion) @@ -765,7 +795,7 @@ bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_CEC_VERSION); command.parameters.PushBack((uint8_t)cecVersion); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress) @@ -775,7 +805,7 @@ bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iIniti command.parameters.PushBack((iPhysicalAddress >> 8) & 0xFF); command.parameters.PushBack(iPhysicalAddress & 0xFF); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState) @@ -784,7 +814,7 @@ bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_MENU_STATUS); command.parameters.PushBack((uint8_t)menuState); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, CStdString strDeviceName) @@ -794,7 +824,7 @@ bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, c for (unsigned int iPtr = 0; iPtr < strDeviceName.length(); iPtr++) command.parameters.PushBack(strDeviceName.at(iPtr)); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage) @@ -809,7 +839,7 @@ bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, for (unsigned int iPtr = 0; iPtr < iLen; iPtr++) command.parameters.PushBack(strMessage[iPtr]); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type) @@ -820,7 +850,7 @@ bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInit command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF)); command.parameters.PushBack((uint8_t) (type)); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -837,7 +867,7 @@ bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_POWER_STATUS); command.parameters.PushBack((uint8_t) state); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId) @@ -849,7 +879,7 @@ bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, command.parameters.PushBack((uint8_t) (((uint64_t)iVendorId >> 8) & 0xFF)); command.parameters.PushBack((uint8_t) ((uint64_t)iVendorId & 0xFF)); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state) @@ -858,7 +888,7 @@ bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiato cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_AUDIO_STATUS); command.parameters.PushBack(state); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state) @@ -867,7 +897,7 @@ bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iI cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_SYSTEM_AUDIO_MODE); command.parameters.PushBack((uint8_t)state); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state) @@ -876,7 +906,7 @@ bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS); command.parameters.PushBack((uint8_t)state); - return Transmit(command); + return Transmit(command, false); } bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state) @@ -885,38 +915,85 @@ bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_DECK_STATUS); command.PushBack((uint8_t)state); - return Transmit(command); + return Transmit(command, false); } -bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key) +bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_PRESSED); command.parameters.PushBack((uint8_t)key); - return Transmit(command); + return Transmit(command, bWait); } -bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination) +bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait /* = true */) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_RELEASE); - return Transmit(command); + return Transmit(command, bWait); } -bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */) +bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* = true */, cec_opcode expectedResponse /* = CEC_OPCODE_NONE */) { + bool bReturn(false); command.transmit_timeout = m_iTransmitTimeout; - CLockObject writeLock(&m_processor->m_transmitMutex); - CLockObject receiveLock(&m_receiveMutex); - if (m_processor->Transmit(command)) { - if (bExpectResponse) - return m_condition.Wait(&m_receiveMutex, m_iTransmitWait); - return true; + uint8_t iTries(0), iMaxTries(command.opcode == CEC_OPCODE_NONE ? 1 : m_iTransmitRetries + 1); + CLockObject writeLock(&m_processor->m_transmitMutex); + CLockObject receiveLock(&m_receiveMutex); + ++m_iUseCounter; + while (!bReturn && ++iTries <= iMaxTries) + { + m_expectedResponse = expectedResponse; + if (m_processor->Transmit(command)) + { + m_processor->AddLog(CEC_LOG_DEBUG, "command transmitted"); + bReturn = bExpectResponse ? + m_condition.Wait(&m_receiveMutex, m_iTransmitWait) : + true; + } + } + --m_iUseCounter; } - return false; + return bReturn; +} + +bool CCECCommandHandler::InitHandler(void) +{ + if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) + { + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + primary->SetPowerStatus(CEC_POWER_STATUS_ON); + primary->SetMenuState(CEC_MENU_STATE_ACTIVATED); + + if (m_processor->GetPrimaryDevice()->GetPhysicalAddress(false) != 0xffff) + { + m_processor->SetActiveSource(); + primary->TransmitMenuState(m_busDevice->GetLogicalAddress()); + m_bHandlerInited = true; + } + } + return true; +} + +void CCECCommandHandler::MarkBusy(void) +{ + CLockObject receiveLock(&m_receiveMutex); + ++m_iUseCounter; +} + +bool CCECCommandHandler::MarkReady(void) +{ + CLockObject receiveLock(&m_receiveMutex); + return m_iUseCounter > 0 ? (--m_iUseCounter == 0) : true; +} + +bool CCECCommandHandler::InUse(void) +{ + CLockObject receiveLock(&m_receiveMutex); + return m_iUseCounter > 0; } diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index e5d19ed..c99d569 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -52,10 +52,10 @@ namespace CEC virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool HandleReceiveFailed(void); - virtual bool InitHandler(void) { return true; } + virtual bool InitHandler(void); virtual uint8_t GetTransmitRetries(void) const { return m_iTransmitRetries; } - virtual bool TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination); + virtual bool TransmitImageViewOn(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination); @@ -77,8 +77,12 @@ namespace CEC virtual bool TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state); virtual bool TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state); virtual bool TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state); - virtual bool TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key); - virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination); + virtual bool TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait = true); + virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait = true); + + virtual void MarkBusy(void); + virtual bool MarkReady(void); + virtual bool InUse(void); protected: virtual bool HandleActiveSource(const cec_command &command); @@ -86,6 +90,7 @@ namespace CEC virtual bool HandleDeviceCecVersion(const cec_command &command); virtual bool HandleDeviceVendorCommandWithId(const cec_command &command); virtual bool HandleDeviceVendorId(const cec_command &command); + virtual bool HandleFeatureAbort(const cec_command &command); virtual bool HandleGetCecVersion(const cec_command &command); virtual bool HandleGiveAudioStatus(const cec_command &command); virtual bool HandleGiveDeckStatus(const cec_command &command); @@ -112,6 +117,7 @@ namespace CEC virtual bool HandleTextViewOn(const cec_command &command); virtual bool HandleUserControlPressed(const cec_command &command); virtual bool HandleUserControlRelease(const cec_command &command); + virtual bool HandleVendorCommand(const cec_command &command) { return true; } virtual void UnhandledCommand(const cec_command &command); virtual unsigned int GetMyDevices(std::vector &devices) const; @@ -122,13 +128,16 @@ namespace CEC virtual bool SetVendorId(const cec_command &command); virtual void SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress); - virtual bool Transmit(cec_command &command, bool bExpectResponse = true); + virtual bool Transmit(cec_command &command, bool bExpectResponse = true, cec_opcode expectedResponse = CEC_OPCODE_NONE); CCECBusDevice *m_busDevice; CCECProcessor *m_processor; int32_t m_iTransmitTimeout; int32_t m_iTransmitWait; int8_t m_iTransmitRetries; + bool m_bHandlerInited; + uint8_t m_iUseCounter; + cec_opcode m_expectedResponse; CMutex m_receiveMutex; CCondition m_condition; }; diff --git a/src/lib/implementations/SLCommandHandler.cpp b/src/lib/implementations/SLCommandHandler.cpp index 0f00717..bc302aa 100644 --- a/src/lib/implementations/SLCommandHandler.cpp +++ b/src/lib/implementations/SLCommandHandler.cpp @@ -35,6 +35,7 @@ #include "../devices/CECPlaybackDevice.h" #include "../CECProcessor.h" #include "../platform/timeutils.h" +#include "../platform/threads.h" using namespace CEC; @@ -51,10 +52,94 @@ CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) : CCECCommandHandler(busDevice), m_bAwaitingReceiveFailed(false), m_bSLEnabled(false), - m_bVendorIdSent(false) + m_bPowerStateReset(false) { - /* TODO set to powered off until we fixed the connect on start loop issue */ - m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary]->m_powerStatus = CEC_POWER_STATUS_STANDBY; + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + + /* imitate LG devices */ + if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) + primary->SetVendorId(CEC_VENDOR_LG, false); + SetLGDeckStatus(); + + /* LG TVs don't always reply to CEC version requests, so just set it to 1.3a */ + if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) + m_busDevice->SetCecVersion(CEC_VERSION_1_3A); + + /* LG devices always return "korean" as language */ + cec_menu_language lang; + lang.device = m_busDevice->GetLogicalAddress(); + snprintf(lang.language, 4, "eng"); + m_busDevice->SetMenuLanguage(lang); +} + + +void CSLCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination) +{ + CCECCommandHandler::HandlePoll(iInitiator, iDestination); + m_bAwaitingReceiveFailed = true; +} + +bool CSLCommandHandler::HandleReceiveFailed(void) +{ + if (m_bAwaitingReceiveFailed) + { + m_bAwaitingReceiveFailed = false; + return false; + } + + return true; +} + +bool CSLCommandHandler::InitHandler(void) +{ + if (m_bHandlerInited) + return true; + m_bHandlerInited = true; + + /* reply with LGs vendor id */ + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) + primary->TransmitVendorID(CECDEVICE_TV, false); + + primary->SetPowerStatus(CEC_POWER_STATUS_STANDBY); + return true; +} + +bool CSLCommandHandler::HandleActiveSource(const cec_command &command) +{ + if (command.parameters.size == 2) + { + uint16_t iAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]); + if (iAddress != m_busDevice->GetPhysicalAddress(false)) + m_bSLEnabled = false; + return m_processor->SetActiveSource(iAddress); + } + + return true; +} + +bool CSLCommandHandler::HandleFeatureAbort(const cec_command &command) +{ + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + if (primary->GetPowerStatus(false) == CEC_POWER_STATUS_ON && !m_bPowerStateReset && !m_bSLEnabled) + { + m_bPowerStateReset = true; + primary->SetPowerStatus(CEC_POWER_STATUS_STANDBY); + } + + return CCECCommandHandler::HandleFeatureAbort(command); +} + +bool CSLCommandHandler::HandleGivePhysicalAddress(const cec_command &command) +{ + if (m_processor->IsStarted() && m_busDevice->MyLogicalAddressContains(command.destination)) + { + CCECBusDevice *device = GetDevice(command.destination); + if (device) + return device->TransmitPhysicalAddress(); + } + + return false; } bool CSLCommandHandler::HandleVendorCommand(const cec_command &command) @@ -87,23 +172,6 @@ bool CSLCommandHandler::HandleVendorCommand(const cec_command &command) return false; } -bool CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command) -{ - if (command.parameters.size == 1) - { - if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE || - command.parameters[0] == CEC_STATUS_REQUEST_ON) - { - TransmitDeckStatus(command.initiator); - } - else - { - CCECCommandHandler::HandleGiveDeckStatus(command); - } - } - return true; -} - void CSLCommandHandler::HandleVendorCommand01(const cec_command &command) { TransmitVendorCommand0205(command.destination, command.initiator); @@ -116,41 +184,25 @@ void CSLCommandHandler::TransmitVendorCommand0205(const cec_logical_address iSou response.PushBack(SL_COMMAND_UNKNOWN_02); response.PushBack(SL_COMMAND_UNKNOWN_03); - Transmit(response); -} - -void CSLCommandHandler::TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination) -{ - m_bSLEnabled = true; - cec_command response; - cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND); - response.PushBack(SL_COMMAND_CONNECT_ACCEPT); - response.PushBack((uint8_t)iSource); - Transmit(response); + Transmit(response, false); } void CSLCommandHandler::HandleVendorCommandPowerOn(const cec_command &command) { - CCECBusDevice *device = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary]; + CCECBusDevice *device = m_processor->GetPrimaryDevice(); if (device) { m_bSLEnabled = true; - device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); + + device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); //XXX device->TransmitPowerState(command.initiator); - device->TransmitVendorID(command.initiator); - TransmitPowerOn(device->GetLogicalAddress(), command.initiator); - } -} + device->SetPowerStatus(CEC_POWER_STATUS_ON); -void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command) -{ - m_bSLEnabled = true; - m_processor->m_busDevices[command.initiator]->SetActiveSource(); - m_processor->m_busDevices[command.destination]->TransmitActiveSource(); - TransmitVendorCommand05(command.destination, command.initiator); - TransmitDeckStatus(command.initiator); + SetLGDeckStatus(); + device->SetActiveSource(); + TransmitImageViewOn(device->GetLogicalAddress(), command.initiator); + } } - void CSLCommandHandler::HandleVendorCommandPowerOnStatus(const cec_command &command) { if (command.destination != CECDEVICE_BROADCAST) @@ -162,155 +214,35 @@ void CSLCommandHandler::HandleVendorCommandPowerOnStatus(const cec_command &comm } } -void CSLCommandHandler::TransmitDeckStatus(const cec_logical_address iDestination) -{ - /* set deck status for the playback device */ - CCECBusDevice *primary = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary]; - if (primary->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) - { - ((CCECPlaybackDevice *)primary)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG); - ((CCECPlaybackDevice *)primary)->TransmitDeckStatus(iDestination); - } -} - -bool CSLCommandHandler::TransmitLGVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination) -{ - cec_command response; - cec_command::Format(response, iInitiator, iDestination, CEC_OPCODE_DEVICE_VENDOR_ID); - response.parameters.PushBack((uint8_t) (((uint64_t)CEC_VENDOR_LG >> 16) & 0xFF)); - response.parameters.PushBack((uint8_t) (((uint64_t)CEC_VENDOR_LG >> 8) & 0xFF)); - response.parameters.PushBack((uint8_t) ((uint64_t)CEC_VENDOR_LG & 0xFF)); - - Transmit(response); - return true; -} - -bool CSLCommandHandler::HandleGiveDeviceVendorId(const cec_command &command) -{ - /* imitate LG devices */ - CCECBusDevice *device = GetDevice(command.destination); - if (device) - device->SetVendorId(CEC_VENDOR_LG); - - return CCECCommandHandler::HandleGiveDeviceVendorId(command); -} - -bool CSLCommandHandler::HandleCommand(const cec_command &command) -{ - bool bHandled(false); - - if (m_processor->IsStarted() && (m_busDevice->MyLogicalAddressContains(command.destination) || - command.destination == CECDEVICE_BROADCAST)) - { - switch(command.opcode) - { - case CEC_OPCODE_VENDOR_COMMAND: - bHandled = HandleVendorCommand(command); - break; - case CEC_OPCODE_FEATURE_ABORT: - { - if (!m_bVendorIdSent) - { - m_bVendorIdSent = true; - TransmitLGVendorId(m_processor->GetLogicalAddresses().primary, CECDEVICE_BROADCAST); - } - } - bHandled = true; - default: - break; - } - } - - if (!bHandled) - bHandled = CCECCommandHandler::HandleCommand(command); - - return bHandled; -} - -void CSLCommandHandler::HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination) +void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command) { - CCECCommandHandler::HandlePoll(iInitiator, iDestination); - m_bAwaitingReceiveFailed = true; -} + m_bSLEnabled = true; + SetLGDeckStatus(); -bool CSLCommandHandler::HandleReceiveFailed(void) -{ - if (m_bAwaitingReceiveFailed) - { - m_bAwaitingReceiveFailed = false; - return false; - } + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); - return true; + primary->SetActiveSource(); + TransmitImageViewOn(primary->GetLogicalAddress(), command.initiator); + TransmitVendorCommand05(primary->GetLogicalAddress(), command.initiator); } -bool CSLCommandHandler::InitHandler(void) +void CSLCommandHandler::TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination) { - m_processor->SetStandardLineTimeout(3); - m_processor->SetRetryLineTimeout(3); - - /* increase the number of retries because the tv is keeping the bus busy at times */ - m_iTransmitWait = 2000; - m_iTransmitRetries = 4; - m_iTransmitTimeout = 500; - - CCECBusDevice *primary = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary]; - if (m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) - { - primary->SetVendorId(CEC_VENDOR_LG, false); - primary->TransmitVendorID(CECDEVICE_TV, false); - } - - if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) - { - /* LG TVs don't always reply to CEC version requests, so just set it to 1.3a */ - m_busDevice->SetCecVersion(CEC_VERSION_1_3A); - } - - /* LG devices always return "korean" as language */ - cec_menu_language lang; - lang.device = m_busDevice->GetLogicalAddress(); - snprintf(lang.language, 4, "eng"); - m_busDevice->SetMenuLanguage(lang); - - if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV) - { - m_processor->SetActiveSource(); - - /* LG TVs only route keypresses when the deck status is set to 0x20 */ - cec_logical_addresses addr = m_processor->GetLogicalAddresses(); - for (uint8_t iPtr = 0; iPtr < 15; iPtr++) - { - CCECBusDevice *device = m_processor->m_busDevices[iPtr]; - - if (addr[iPtr]) - { - if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || - device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)) - { - ((CCECPlaybackDevice *)device)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG); - ((CCECPlaybackDevice *)device)->TransmitDeckStatus(CECDEVICE_TV); - } - } - } - } - - return true; + cec_command response; + cec_command::Format(response, iSource, iDestination, CEC_OPCODE_VENDOR_COMMAND); + response.PushBack(SL_COMMAND_CONNECT_ACCEPT); + response.PushBack((uint8_t)iSource); + Transmit(response, false); } -bool CSLCommandHandler::TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination) +void CSLCommandHandler::SetLGDeckStatus(void) { - if (iDestination != CECDEVICE_BROADCAST && - iDestination != CECDEVICE_TV && - m_processor->m_busDevices[iDestination]->GetVendorId(false) == CEC_VENDOR_LG) - { - cec_command command; - cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_VENDOR_COMMAND); - command.parameters.PushBack((uint8_t)SL_COMMAND_POWER_ON); - command.parameters.PushBack(0x00); - return Transmit(command); - } + /* LG TVs only route keypresses when the deck status is set to 0x20 */ + CCECBusDevice *device = m_processor->GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE); + if (device) + ((CCECPlaybackDevice *)device)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG); - return CCECCommandHandler::TransmitPowerOn(iInitiator, iDestination); + device = m_processor->GetDeviceByType(CEC_DEVICE_TYPE_RECORDING_DEVICE); + if (device) + ((CCECPlaybackDevice *)device)->SetDeckStatus(CEC_DECK_INFO_OTHER_STATUS_LG); } - diff --git a/src/lib/implementations/SLCommandHandler.h b/src/lib/implementations/SLCommandHandler.h index 3a5a779..48674cc 100644 --- a/src/lib/implementations/SLCommandHandler.h +++ b/src/lib/implementations/SLCommandHandler.h @@ -42,28 +42,29 @@ namespace CEC virtual ~CSLCommandHandler(void) {}; virtual cec_vendor_id GetVendorId(void) { return CEC_VENDOR_LG; }; - virtual bool HandleCommand(const cec_command &command); virtual void HandlePoll(const cec_logical_address iInitiator, const cec_logical_address iDestination); virtual bool HandleReceiveFailed(void); virtual bool InitHandler(void); - virtual bool TransmitLGVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination); - virtual bool TransmitPowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination); protected: + virtual bool HandleActiveSource(const cec_command &command); + virtual bool HandleFeatureAbort(const cec_command &command); + virtual bool HandleGivePhysicalAddress(const cec_command &command); + virtual bool HandleVendorCommand(const cec_command &command); + virtual void HandleVendorCommand01(const cec_command &command); + virtual void TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination); + virtual void HandleVendorCommandPowerOn(const cec_command &command); - virtual void HandleVendorCommandSLConnect(const cec_command &command); virtual void HandleVendorCommandPowerOnStatus(const cec_command &command); - virtual void TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination); + virtual void HandleVendorCommandSLConnect(const cec_command &command); virtual void TransmitVendorCommand05(const cec_logical_address iSource, const cec_logical_address iDestination); - virtual void TransmitDeckStatus(const cec_logical_address iDestination); - virtual bool HandleGiveDeviceVendorId(const cec_command &command); - virtual bool HandleVendorCommand(const cec_command &command); - virtual bool HandleGiveDeckStatus(const cec_command &command); + + virtual void SetLGDeckStatus(void); bool m_bAwaitingReceiveFailed; bool m_bSLEnabled; - bool m_bVendorIdSent; + bool m_bPowerStateReset; }; }; diff --git a/src/lib/platform/threads.cpp b/src/lib/platform/threads.cpp index 8ba3919..d168e90 100644 --- a/src/lib/platform/threads.cpp +++ b/src/lib/platform/threads.cpp @@ -35,9 +35,9 @@ using namespace CEC; -CMutex::CMutex(void) +CMutex::CMutex(bool bRecursive /* = true */) { - pthread_mutex_init(&m_mutex, NULL); + pthread_mutex_init(&m_mutex, bRecursive ? GetMutexAttribute() : NULL); } CMutex::~CMutex(void) @@ -60,6 +60,19 @@ void CMutex::Unlock(void) pthread_mutex_unlock(&m_mutex); } +static pthread_mutexattr_t g_mutexAttr; +pthread_mutexattr_t *CMutex::GetMutexAttribute() +{ + static bool bAttributeInitialised = false; + if (!bAttributeInitialised) + { + pthread_mutexattr_init(&g_mutexAttr); + pthread_mutexattr_settype(&g_mutexAttr, PTHREAD_MUTEX_RECURSIVE); + bAttributeInitialised = true; + } + return &g_mutexAttr; +} + CLockObject::CLockObject(CMutex *mutex, bool bTryLock /* = false */) : m_mutex(mutex) { diff --git a/src/lib/platform/threads.h b/src/lib/platform/threads.h index 4161de3..a258081 100644 --- a/src/lib/platform/threads.h +++ b/src/lib/platform/threads.h @@ -56,7 +56,7 @@ namespace CEC class CMutex { public: - CMutex(void); + CMutex(bool bRecursive = true); virtual ~CMutex(void); bool TryLock(void); @@ -64,6 +64,9 @@ namespace CEC void Unlock(void); pthread_mutex_t m_mutex; + + private: + static pthread_mutexattr_t *GetMutexAttribute(); }; class CLockObject