cec: request the active source if it's unknown in CCECProcessor::GetActiveSource()
[deb_libcec.git] / src / lib / CECProcessor.cpp
index cf42233f5f878adc44176424cab48511ed230833..a1603e8243a26b92cbed4d2080639eaa044fdf28 100644 (file)
@@ -59,7 +59,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, libcec_configuration *configur
 {
   CreateBusDevices();
   m_configuration.Clear();
-  m_configuration.serverVersion = CEC_SERVER_VERSION_1_6_1;
+  m_configuration.serverVersion = CEC_SERVER_VERSION_1_6_2;
   SetConfiguration(configuration);
 
   if (m_configuration.tvVendor != CEC_VENDOR_UNKNOWN)
@@ -77,7 +77,7 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, con
     m_iLastTransmission(0)
 {
   m_configuration.Clear();
-  m_configuration.serverVersion    = CEC_SERVER_VERSION_1_6_1;
+  m_configuration.serverVersion    = CEC_SERVER_VERSION_1_6_2;
 
   // client version < 1.5.0
   m_configuration.clientVersion    = (uint32_t)CEC_CLIENT_VERSION_PRE_1_5;
@@ -188,7 +188,17 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint
   if (bReturn)
   {
     m_configuration.iFirmwareVersion = m_communication->GetFirmwareVersion();
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "connected to the CEC adapter. firmware version = %d, client version = %s", m_configuration.iFirmwareVersion, ToString((cec_client_version)m_configuration.clientVersion));
+    m_configuration.iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
+    CStdString strLog;
+    strLog.Format("connected to the CEC adapter. libCEC version = %s, client version = %s, firmware version = %d", ToString((cec_server_version)m_configuration.serverVersion), ToString((cec_client_version)m_configuration.clientVersion), m_configuration.iFirmwareVersion);
+    if (m_configuration.iFirmwareBuildDate > 0)
+    {
+      time_t buildTime = (time_t)m_configuration.iFirmwareBuildDate;
+      strLog.AppendFormat(", firmware build date: %s", asctime(gmtime(&buildTime)));
+      strLog = strLog.Left((int)strLog.length() - 1); // strip \n added by asctime
+      strLog.append(" +0000");
+    }
+    CLibCEC::AddLog(CEC_LOG_NOTICE, strLog);
   }
 
   if (m_configuration.bGetSettingsFromROM == 1)
@@ -210,7 +220,7 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint
 
 bool CCECProcessor::IsInitialised(void)
 {
-  CLockObject lock(m_mutex);
+  CLockObject lock(m_threadMutex);
   return m_bInitialised;
 }
 
@@ -240,6 +250,21 @@ bool CCECProcessor::Initialise(void)
     /* make the primary device the active source if the option is set */
     if (m_configuration.bActivateSource == 1)
       m_busDevices[m_configuration.logicalAddresses.primary]->m_bActiveSource = true;
+
+    /* set the default menu language for devices we control */
+    cec_menu_language language;
+    language.device = m_configuration.logicalAddresses.primary;
+    memcpy(language.language, m_configuration.strDeviceLanguage, 3);
+    language.language[3] = 0;
+
+    for (uint8_t iPtr = 0; iPtr < 16; iPtr++)
+    {
+      if (m_configuration.logicalAddresses[iPtr])
+      {
+        language.device = (cec_logical_address) iPtr;
+        m_busDevices[iPtr]->SetMenuLanguage(language);
+      }
+    }
   }
 
   /* get the vendor id from the TV, so we are using the correct handler */
@@ -377,12 +402,6 @@ bool CCECProcessor::ChangeDeviceType(cec_device_type from, cec_device_type to)
       previousDevice->SetCecVersion(CEC_VERSION_UNKNOWN);
 
       newDevice->SetMenuLanguage(previousDevice->GetMenuLanguage(false));
-      cec_menu_language lang;
-      lang.device = previousDevice->GetLogicalAddress();
-      for (unsigned int iPtr = 0; iPtr < 4; iPtr++)
-        lang.language[iPtr] = '?';
-      lang.language[3] = 0;
-      previousDevice->SetMenuLanguage(lang);
 
       newDevice->SetMenuState(previousDevice->GetMenuState());
       previousDevice->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
@@ -390,7 +409,7 @@ bool CCECProcessor::ChangeDeviceType(cec_device_type from, cec_device_type to)
       newDevice->SetOSDName(previousDevice->GetOSDName(false));
       previousDevice->SetOSDName(ToString(previousDevice->GetLogicalAddress()));
 
-      newDevice->SetPhysicalAddress(previousDevice->GetPhysicalAddress(false));
+      newDevice->SetPhysicalAddress(previousDevice->GetPhysicalAddress());
       previousDevice->SetPhysicalAddress(0xFFFF);
 
       newDevice->SetPowerStatus(previousDevice->GetPowerStatus(false));
@@ -506,7 +525,7 @@ bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RE
   }
 
   m_busDevices[addr]->SetActiveSource();
-  if (m_busDevices[addr]->GetPhysicalAddress(false) != 0xFFFF)
+  if (m_busDevices[addr]->GetPhysicalAddress() != 0xFFFF)
     bReturn = m_busDevices[addr]->ActivateSource();
 
   return bReturn;
@@ -517,12 +536,16 @@ bool CCECProcessor::SetActiveSource(uint16_t iStreamPath)
   bool bReturn(false);
 
   // suppress polls when searching for a device
-  CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath, false, true);
+  CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
   if (device)
   {
     device->SetActiveSource();
     bReturn = true;
   }
+  else
+  {
+    CLibCEC::AddLog(CEC_LOG_DEBUG, "device with PA '%04x' not found", iStreamPath);
+  }
 
   return bReturn;
 }
@@ -630,7 +653,7 @@ bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress)
 {
   for (unsigned int iPtr = 0; iPtr < 15; iPtr++)
   {
-    if (m_busDevices[iPtr]->GetPhysicalAddress(false) == iPhysicalAddress)
+    if (m_busDevices[iPtr]->GetPhysicalAddress() == iPhysicalAddress)
       return true;
   }
   return false;
@@ -791,19 +814,19 @@ uint8_t CCECProcessor::MuteAudio(bool bSendRelease /* = true */)
   return status;
 }
 
-CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bRefresh /* = false */, bool bSuppressPoll /* = false */) const
+CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */)
 {
-  if (m_busDevices[m_configuration.logicalAddresses.primary]->GetPhysicalAddress(false) == iPhysicalAddress)
-    return m_busDevices[m_configuration.logicalAddresses.primary];
+  CCECBusDevice *device(NULL);
 
-  CCECBusDevice *device = NULL;
-  for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+  // invalid PA
+  if (iPhysicalAddress == 0xFFFF)
+    return device;
+
+  // check each device until we found a match
+  for (unsigned int iPtr = 0; !device && iPtr < 16; iPtr++)
   {
-    if (m_busDevices[iPtr]->GetPhysicalAddress(bRefresh, bSuppressPoll) == iPhysicalAddress)
-    {
+    if (m_busDevices[iPtr]->GetPhysicalAddress(bSuppressUpdate) == iPhysicalAddress)
       device = m_busDevices[iPtr];
-      break;
-    }
   }
 
   return device;
@@ -860,6 +883,13 @@ bool CCECProcessor::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu
   return false;
 }
 
+CStdString CCECProcessor::GetDeviceName(void) const
+{
+  CStdString strName;
+  strName = m_configuration.strDeviceName;
+  return strName;
+}
+
 uint64_t CCECProcessor::GetDeviceVendorId(cec_logical_address iAddress)
 {
   if (m_busDevices[iAddress])
@@ -881,7 +911,7 @@ cec_power_status CCECProcessor::GetDevicePowerStatus(cec_logical_address iAddres
   return CEC_POWER_STATUS_UNKNOWN;
 }
 
-cec_logical_address CCECProcessor::GetActiveSource(void)
+cec_logical_address CCECProcessor::GetActiveSource(bool bRequestActiveSource /* = true */)
 {
   for (uint8_t iPtr = 0; iPtr <= 11; iPtr++)
   {
@@ -889,6 +919,15 @@ cec_logical_address CCECProcessor::GetActiveSource(void)
       return (cec_logical_address)iPtr;
   }
 
+  if (bRequestActiveSource && m_configuration.logicalAddresses.primary != CECDEVICE_UNKNOWN)
+  {
+    CCECBusDevice *primary = m_busDevices[m_configuration.logicalAddresses.primary];
+    if (primary)
+      primary->RequestActiveSource();
+
+    return GetActiveSource(false);
+  }
+
   return CECDEVICE_UNKNOWN;
 }
 
@@ -922,8 +961,21 @@ bool CCECProcessor::Transmit(const cec_command &data)
     iMaxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
   }
 
-  return m_communication->Write(data, iMaxTries, m_iStandardLineTimeout, m_iRetryLineTimeout)
-      == ADAPTER_MESSAGE_STATE_SENT_ACKED;
+  bool bRetry(true);
+  uint8_t iTries(0);
+  uint8_t iLineTimeout = m_iStandardLineTimeout;
+  cec_adapter_message_state adapterState = ADAPTER_MESSAGE_STATE_UNKNOWN;
+
+  while (bRetry && ++iTries < iMaxTries)
+  {
+    if (m_busDevices[data.initiator]->IsUnsupportedFeature(data.opcode))
+      return false;
+
+    adapterState = m_communication->Write(data, bRetry, iLineTimeout);
+    iLineTimeout = m_iRetryLineTimeout;
+  }
+
+  return adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED;
 }
 
 void CCECProcessor::TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
@@ -984,13 +1036,13 @@ bool CCECProcessor::IsPresentDeviceType(cec_device_type type)
 uint16_t CCECProcessor::GetPhysicalAddress(void) const
 {
   if (!m_configuration.logicalAddresses.IsEmpty() && m_busDevices[m_configuration.logicalAddresses.primary])
-    return m_busDevices[m_configuration.logicalAddresses.primary]->GetPhysicalAddress(false);
+    return m_busDevices[m_configuration.logicalAddresses.primary]->GetPhysicalAddress();
   return false;
 }
 
 bool CCECProcessor::SetAckMask(uint16_t iMask)
 {
-  return m_communication->SetAckMask(iMask);
+  return m_communication ? m_communication->SetAckMask(iMask) : false;
 }
 
 bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
@@ -1026,7 +1078,10 @@ bool CCECProcessor::StandbyDevices(cec_logical_address address /* = CECDEVICE_BR
     for (uint8_t iPtr = 0; iPtr <= 0xF; iPtr++)
     {
       if (m_configuration.powerOffDevices[iPtr])
+      {
+        CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - putting '%s' in standby mode", __FUNCTION__, ToString((cec_logical_address)iPtr));
         bReturn &= m_busDevices[iPtr]->Standby();
+      }
     }
     return bReturn;
   }
@@ -1041,8 +1096,11 @@ bool CCECProcessor::PowerOnDevices(cec_logical_address address /* = CECDEVICE_BR
     bool bReturn(true);
     for (uint8_t iPtr = 0; iPtr <= 0xF; iPtr++)
     {
-      if (m_configuration.powerOffDevices[iPtr])
+      if (m_configuration.wakeDevices[iPtr])
+      {
+        CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - powering on '%s'", __FUNCTION__, ToString((cec_logical_address)iPtr));
         bReturn &= m_busDevices[iPtr]->PowerOn();
+      }
     }
     return bReturn;
   }
@@ -1416,6 +1474,8 @@ const char *CCECProcessor::ToString(const cec_client_version version)
     return "1.6.0";
   case CEC_CLIENT_VERSION_1_6_1:
     return "1.6.1";
+  case CEC_CLIENT_VERSION_1_6_2:
+    return "1.6.2";
   default:
     return "Unknown";
   }
@@ -1439,56 +1499,13 @@ const char *CCECProcessor::ToString(const cec_server_version version)
     return "1.6.0";
   case CEC_SERVER_VERSION_1_6_1:
     return "1.6.1";
+  case CEC_SERVER_VERSION_1_6_2:
+    return "1.6.2";
   default:
     return "Unknown";
   }
 }
 
-void *CCECBusScan::Process(void)
-{
-  CCECBusDevice *device(NULL);
-  uint8_t iCounter(0);
-
-  while (!IsStopped())
-  {
-    if (++iCounter < 10)
-    {
-      Sleep(1000);
-      continue;
-    }
-    for (unsigned int iPtr = 0; iPtr <= 11 && !IsStopped(); iPtr++)
-    {
-      device = m_processor->m_busDevices[iPtr];
-      WaitUntilIdle();
-      if (device && device->GetStatus(true) == CEC_DEVICE_STATUS_PRESENT)
-      {
-        WaitUntilIdle();
-        if (!IsStopped())
-          device->GetVendorId();
-
-        WaitUntilIdle();
-        if (!IsStopped())
-          device->GetPowerStatus(true);
-      }
-    }
-  }
-
-  return NULL;
-}
-
-void CCECBusScan::WaitUntilIdle(void)
-{
-  if (IsStopped())
-    return;
-
-  int32_t iWaitTime = 3000 - (int32_t)(GetTimeMs() - m_processor->GetLastTransmission());
-  while (iWaitTime > 0)
-  {
-    Sleep(iWaitTime);
-    iWaitTime = 3000 - (int32_t)(GetTimeMs() - m_processor->GetLastTransmission());
-  }
-}
-
 bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */)
 {
   if (!m_communication && strPort)
@@ -1654,6 +1671,12 @@ bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
     m_configuration.bShutdownOnStandby        = configuration->bShutdownOnStandby;
   }
 
+  // client version 1.6.2
+  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_2)
+  {
+    memcpy(m_configuration.strDeviceLanguage, configuration->strDeviceLanguage, 3);
+  }
+
   // ensure that there is at least 1 device type set
   if (m_configuration.deviceTypes.IsEmpty())
     m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
@@ -1717,22 +1740,28 @@ bool CCECProcessor::GetCurrentConfiguration(libcec_configuration *configuration)
     configuration->bShutdownOnStandby        = m_configuration.bShutdownOnStandby;
   }
 
+  // client version 1.6.2
+  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_2)
+  {
+    memcpy(configuration->strDeviceLanguage, m_configuration.strDeviceLanguage, 3);
+    configuration->iFirmwareBuildDate      = m_configuration.iFirmwareBuildDate;
+  }
   return true;
 }
 
 bool CCECProcessor::CanPersistConfiguration(void)
 {
-  return m_communication->GetFirmwareVersion() >= 2;
+  return m_communication ? m_communication->GetFirmwareVersion() >= 2 : false;
 }
 
 bool CCECProcessor::PersistConfiguration(libcec_configuration *configuration)
 {
-  return m_communication->PersistConfiguration(configuration);
+  return m_communication ? m_communication->PersistConfiguration(configuration) : false;
 }
 
 void CCECProcessor::RescanActiveDevices(void)
 {
-  for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+  for (unsigned int iPtr = 0; iPtr < CECDEVICE_BROADCAST; iPtr++)
     m_busDevices[iPtr]->GetStatus(true);
 }
 
@@ -1748,3 +1777,11 @@ bool CCECProcessor::GetDeviceInformation(const char *strPort, libcec_configurati
   m_communication = NULL;
   return true;
 }
+
+bool CCECProcessor::TransmitPendingActiveSourceCommands(void)
+{
+  bool bReturn(true);
+  for (unsigned int iPtr = 0; iPtr < CECDEVICE_BROADCAST; iPtr++)
+    bReturn &= m_busDevices[iPtr]->TransmitPendingActiveSourceCommands();
+  return bReturn;
+}