send an active source message when the route was set to the physical address that...
[deb_libcec.git] / src / lib / devices / CECBusDevice.cpp
index e3d4cfdeea8876a2d2d36d87f1d85aadab57d717..de75db5760b7e3bff8f3c365cc08ecdc07c8b7cf 100644 (file)
@@ -39,6 +39,7 @@
 #include "lib/implementations/CECCommandHandler.h"
 #include "lib/implementations/SLCommandHandler.h"
 #include "lib/implementations/VLCommandHandler.h"
+#include "lib/implementations/PHCommandHandler.h"
 #include "lib/LibCEC.h"
 #include "lib/CECTypeUtils.h"
 #include "lib/platform/util/timeutils.h"
@@ -75,7 +76,8 @@ CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogi
   m_iHandlerUseCount      (0),
   m_bAwaitingReceiveFailed(false),
   m_bVendorIdRequested    (false),
-  m_waitForResponse       (new CWaitForResponse)
+  m_waitForResponse       (new CWaitForResponse),
+  m_bImageViewOnSent      (false)
 {
   m_handler = new CCECCommandHandler(this);
 
@@ -131,6 +133,9 @@ bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
         case CEC_VENDOR_PANASONIC:
           m_handler = new CVLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
           break;
+        case CEC_VENDOR_PHILIPS:
+          m_handler = new CPHCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
+          break;
         default:
           m_handler = new CCECCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
           break;
@@ -174,11 +179,6 @@ bool CCECBusDevice::HandleCommand(const cec_command &command)
   {
     CLockObject lock(m_mutex);
     m_iLastActive = GetTimeMs();
-
-    /* don't call GetStatus() here, just read the value with the mutex locked */
-    if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC && command.opcode_set == 1)
-      m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
-
     MarkBusy();
   }
 
@@ -615,6 +615,25 @@ void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
   }
 }
 
+void CCECBusDevice::OnImageViewOnSent(bool bSentByLibCEC)
+{
+  CLockObject lock(m_mutex);
+  m_bImageViewOnSent = bSentByLibCEC;
+
+  if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
+  {
+    m_iLastPowerStateUpdate = GetTimeMs();
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON));
+    m_powerStatus = CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON;
+  }
+}
+
+bool CCECBusDevice::ImageViewOnSent(void)
+{
+  CLockObject lock(m_mutex);
+  return m_bImageViewOnSent;
+}
+
 bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
 {
   bool bReturn(false);
@@ -623,8 +642,9 @@ bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool
       !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
   {
     MarkBusy();
-    LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
     bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bWaitForResponse);
+    if (!bReturn)
+      SetPowerStatus(CEC_POWER_STATUS_UNKNOWN);
     MarkReady();
   }
   return bReturn;
@@ -746,7 +766,13 @@ cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bo
     CLockObject lock(m_mutex);
     status = m_deviceStatus;
     bNeedsPoll = !bSuppressPoll &&
-        (bForcePoll || m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN);
+        m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC &&
+            // poll forced
+            (bForcePoll ||
+            // don't know the status
+            m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN ||
+            // always poll the TV if it's marked as not present
+            (m_deviceStatus == CEC_DEVICE_STATUS_NOT_PRESENT && m_iLogicalAddress == CECDEVICE_TV));
   }
 
   if (bNeedsPoll)
@@ -764,6 +790,9 @@ cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bo
 
 void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus, cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */)
 {
+  if (m_iLogicalAddress == CECDEVICE_UNREGISTERED)
+    return;
+
   {
     CLockObject lock(m_mutex);
     switch (newStatus)
@@ -784,12 +813,13 @@ void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus, cec_v
       if (m_deviceStatus != newStatus)
         LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'present'", GetLogicalAddressName(), m_iLogicalAddress);
       m_deviceStatus = newStatus;
+      m_iLastActive = GetTimeMs();
       break;
     case CEC_DEVICE_STATUS_NOT_PRESENT:
       if (m_deviceStatus != newStatus)
       {
         LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'not present'", GetLogicalAddressName(), m_iLogicalAddress);
-        ResetDeviceStatus();
+        ResetDeviceStatus(true);
         m_deviceStatus = newStatus;
       }
       break;
@@ -800,7 +830,7 @@ void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus, cec_v
   }
 }
 
-void CCECBusDevice::ResetDeviceStatus(void)
+void CCECBusDevice::ResetDeviceStatus(bool bClientUnregistered /* = false */)
 {
   CLockObject lock(m_mutex);
   SetPowerStatus   (CEC_POWER_STATUS_UNKNOWN);
@@ -809,7 +839,7 @@ void CCECBusDevice::ResetDeviceStatus(void)
   SetCecVersion    (CEC_VERSION_UNKNOWN);
   SetStreamPath    (CEC_INVALID_PHYSICAL_ADDRESS);
   SetOSDName       (ToString(m_iLogicalAddress));
-  MarkAsInactiveSource();
+  MarkAsInactiveSource(bClientUnregistered);
 
   m_iLastActive = 0;
   m_bVendorIdRequested = false;
@@ -821,7 +851,7 @@ void CCECBusDevice::ResetDeviceStatus(void)
   m_deviceStatus = CEC_DEVICE_STATUS_UNKNOWN;
 }
 
-bool CCECBusDevice::TransmitPoll(const cec_logical_address dest, bool bIsReply)
+bool CCECBusDevice::TransmitPoll(const cec_logical_address dest, bool bUpdateDeviceStatus)
 {
   bool bReturn(false);
   cec_logical_address destination(dest);
@@ -834,17 +864,11 @@ bool CCECBusDevice::TransmitPoll(const cec_logical_address dest, bool bIsReply)
 
   MarkBusy();
   LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
-  bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination, bIsReply);
+  bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination, false);
   LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
 
-  CLockObject lock(m_mutex);
-  if (bReturn)
-  {
-    m_iLastActive = GetTimeMs();
-    destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
-  }
-  else
-    destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
+  if (bUpdateDeviceStatus)
+    destDevice->SetDeviceStatus(bReturn ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT);
 
   MarkReady();
   return bReturn;
@@ -959,6 +983,10 @@ void CCECBusDevice::MarkAsActiveSource(void)
     m_bActiveSource = true;
   }
 
+  CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+  if (tv)
+    tv->OnImageViewOnSent(false);
+
   // mark other devices as inactive sources
   CECDEVICEVEC devices;
   m_processor->GetDevices()->Get(devices);
@@ -968,13 +996,15 @@ void CCECBusDevice::MarkAsActiveSource(void)
 
   if (bWasActivated)
   {
+    if (IsHandledByLibCEC())
+      m_processor->SetActiveSource(true, false);
     CCECClient *client = GetClient();
     if (client)
       client->SourceActivated(m_iLogicalAddress);
   }
 }
 
-void CCECBusDevice::MarkAsInactiveSource(void)
+void CCECBusDevice::MarkAsInactiveSource(bool bClientUnregistered /* = false */)
 {
   bool bWasDeactivated(false);
   {
@@ -989,6 +1019,8 @@ void CCECBusDevice::MarkAsInactiveSource(void)
 
   if (bWasDeactivated)
   {
+    if (IsHandledByLibCEC())
+      m_processor->SetActiveSource(false, bClientUnregistered);
     CCECClient *client = GetClient();
     if (client)
       client->SourceDeactivated(m_iLogicalAddress);
@@ -1043,10 +1075,27 @@ bool CCECBusDevice::TransmitImageViewOn(void)
     }
   }
 
+  CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+  if (!tv)
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - couldn't get TV instance", __FUNCTION__);
+    return false;
+  }
+
+  if (tv->ImageViewOnSent())
+  {
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - 'image view on' already sent", __FUNCTION__);
+    return true;
+  }
+
   bool bImageViewOnSent(false);
   MarkBusy();
   bImageViewOnSent = m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
   MarkReady();
+
+  if (bImageViewOnSent)
+    tv->OnImageViewOnSent(true);
+
   return bImageViewOnSent;
 }
 
@@ -1073,8 +1122,35 @@ bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
   return bReturn;
 }
 
+void CCECBusDevice::SetActiveRoute(uint16_t iRoute)
+{
+  SetPowerStatus(CEC_POWER_STATUS_ON);
+
+  CCECDeviceMap* map = m_processor->GetDevices();
+  if (!map)
+    return;
+
+  CCECBusDevice* previouslyActive = map->GetActiveSource();
+  if (!previouslyActive)
+    return;
+
+  CECDEVICEVEC devices;
+  m_processor->GetDevices()->GetChildrenOf(devices, this);
+
+  for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+  {
+    if ((*it)->GetCurrentPhysicalAddress() == iRoute && (*it)->IsHandledByLibCEC())
+      (*it)->ActivateSource();
+    else if (!CCECTypeUtils::PhysicalAddressIsIncluded(iRoute, (*it)->GetCurrentPhysicalAddress()))
+      (*it)->MarkAsInactiveSource();
+  }
+}
+
 void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
 {
+  if (iNewAddress != CEC_INVALID_PHYSICAL_ADDRESS)
+    SetPowerStatus(CEC_POWER_STATUS_ON);
+
   CLockObject lock(m_mutex);
   if (iNewAddress != m_iStreamPath)
   {