Merge branch 'master' into release
authorLars Op den Kamp <lars@opdenkamp.eu>
Thu, 29 Dec 2011 02:11:43 +0000 (03:11 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Thu, 29 Dec 2011 02:11:43 +0000 (03:11 +0100)
24 files changed:
ChangeLog
debian/changelog
include/cec.h
include/cecc.h
project/libCEC.nsi
project/libcec.rc
project/testclient.rc
src/CecSharpTester/AssemblyInfo.cs
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/LibCEC.cpp
src/lib/LibCEC.h
src/lib/LibCECC.cpp
src/lib/devices/CECAudioSystem.cpp
src/lib/devices/CECAudioSystem.h
src/lib/devices/CECBusDevice.cpp
src/lib/devices/CECBusDevice.h
src/lib/devices/CECPlaybackDevice.cpp
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h
src/lib/implementations/SLCommandHandler.cpp
src/lib/implementations/SLCommandHandler.h
src/lib/platform/threads.cpp
src/lib/platform/threads.h

index c24e40090915e5c0880c72a00d24f241c9ee3042..26e76628dbbf196a2aa927043ea8a5a0482347e1 100644 (file)
--- 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 <packaging@pulse-eight.com>  Thu, 29 Dec 2011 03:05:00 +0100
+
 libcec (1.3-1) unstable; urgency=low
 
   * changed/added:
index c24e40090915e5c0880c72a00d24f241c9ee3042..26e76628dbbf196a2aa927043ea8a5a0482347e1 100644 (file)
@@ -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 <packaging@pulse-eight.com>  Thu, 29 Dec 2011 03:05:00 +0100
+
 libcec (1.3-1) unstable; urgency=low
 
   * changed/added:
index 88381c4d54fc81bf816bbd77279f159e091d0fa9..61e4bb315b50668bf1f68bd19b2aae18c440533c 100644 (file)
@@ -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.
index 37bccc187b23aefc856d4dac18d4a32ad6b3cf61..ddb141b714f02f577de6771786f984cbeeab11fb 100644 (file)
@@ -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);
index 591cc1da9ab7a6e609a08c67002aa212fefa454e..36cd65bb6a17eb21d4c6764280e372c38fbc9b21 100644 (file)
@@ -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"
index 1fe06c575219956617b7051aedb1a55d52037348..afac3b1be48cbaea7f2e9df9bc83c41c453ebd30 100644 (file)
Binary files a/project/libcec.rc and b/project/libcec.rc differ
index c63d3c9ebfdb49ffe33cc05778ef8c141e5b6412..e21afdc263c0d09a76bc761888121ee0ffc25725 100644 (file)
Binary files a/project/testclient.rc and b/project/testclient.rc differ
index 058bbb9169a8cba681401639ac10004cbc43b75a..5bddf86f0b4d5fa898b62720fe1e3573918114ab 100644 (file)
@@ -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")]
index 60a6d1921944c1bbb6be47cfb610867003b91e32..6af06649d708a87a3cfe2bfbf129c5fdb6cb4fd8 100644 (file)
@@ -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)
index a0e0e73b8b5e95113305d0f1473acbf326bbf787..13243ab897f5247f24f5130ad620941623b821a5 100644 (file)
@@ -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;
index 0ca0188bfa0b596847beafcfdeb7622cb7b78e18..1366ff6cbcec92b6567ab0648e8a32cdeac3f87a 100644 (file)
@@ -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;
 }
 
index c8917906cf8222a71118c74455afb29ee56e1f89..9c3e8f1002c235bd73f5ea150cb47346f794ab86 100644 (file)
@@ -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);
index 938e0b716daa571893ea52f45f96e17f7ca3f9cf..cbf7b285ec8a8223eb9a2f25fec26ad21e7d2cb7 100644 (file)
@@ -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;
 }
 
index 81a92c39a90707db6bb0e7afed9572b024bf01ab..87b45057d3060d9d2475158d73682f1df6baa167 100644 (file)
@@ -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);
index 291b0ecadc09d39bab87f7d9528aaf5452f75136..dc35ef0f4f436c8cdb6999f4d52f4e50afdfc6e6 100644 (file)
@@ -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; }
 
index 41643a3519263a238d025fe92c6b2adc68750dde..bd68dfc1f8e555fede5920b7bd6a690dbf6c78e4 100644 (file)
@@ -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();
+}
+
 //@}
index b8a9aa94f74a59bc524415c433808a7503d5c45e..30d8329c5c8d711f8f4335b9d86f6019d9e9f9c8 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <cectypes.h>
+#include <set>
 #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<cec_opcode>  m_unsupportedFeatures;
     CMutex                m_mutex;
+    CMutex                m_handlerMutex;
   };
 };
index 4c90b9fa470c734e7e617aad2cf97363b6693300..4969de58c4af45bc442a0953016c3638d1014a1d 100644 (file)
@@ -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);
index 80bc280a3bb9b8af47e7be43582baa8ef9f22111..74f7648aa3ddee09f6ff0cb270aee6f05eae43dc 100644 (file)
@@ -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;
 }
index e5d19ed102097c1a1e7901dd644365ffc60a675c..c99d569ff95f989a4e05e51f42d0a91d14927185 100644 (file)
@@ -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<CCECBusDevice *> &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;
   };
index 0f007176d623f9e83732abbef114790b97446d28..bc302aa8092bad94ee81de56682d9a48b130130a 100644 (file)
@@ -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);
 }
-
index 3a5a779e5195340898b6b08dd6b0a045f98a7086..48674cc995254a80410955ec0b910070c86d4982 100644 (file)
@@ -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;
   };
 };
index 8ba391920feb2695326b52ca6e7467f033771dd1..d168e906a671ddc8e0caab582c9ae30a58bd2853 100644 (file)
@@ -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)
 {
index 4161de3261b12d68d7c4c137dc923ab1281db404..a258081ccef8bbdf6a5bc8f33826fbaf26ae6c84 100644 (file)
@@ -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