cec: send a feature abort again for all unhandled commands, removed statics, refactor...
authorLars Op den Kamp <lars@opdenkamp.eu>
Wed, 9 May 2012 00:16:20 +0000 (02:16 +0200)
committerLars Op den Kamp <lars@opdenkamp.eu>
Thu, 10 May 2012 15:16:12 +0000 (17:16 +0200)
36 files changed:
include/cectypes.h
src/lib/CECClient.cpp [new file with mode: 0644]
src/lib/CECClient.h [new file with mode: 0644]
src/lib/CECInputBuffer.h [new file with mode: 0644]
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/LibCEC.cpp
src/lib/LibCEC.h
src/lib/Makefile.am
src/lib/adapter/AdapterCommunication.h
src/lib/adapter/USBCECAdapterCommands.cpp
src/lib/adapter/USBCECAdapterCommunication.cpp
src/lib/adapter/USBCECAdapterCommunication.h
src/lib/adapter/USBCECAdapterMessage.cpp
src/lib/adapter/USBCECAdapterMessageQueue.cpp
src/lib/adapter/USBCECAdapterMessageQueue.h
src/lib/devices/CECAudioSystem.cpp
src/lib/devices/CECAudioSystem.h
src/lib/devices/CECBusDevice.cpp
src/lib/devices/CECBusDevice.h
src/lib/devices/CECDeviceMap.cpp [new file with mode: 0644]
src/lib/devices/CECDeviceMap.h [new file with mode: 0644]
src/lib/devices/CECPlaybackDevice.cpp
src/lib/devices/CECPlaybackDevice.h
src/lib/devices/CECRecordingDevice.cpp
src/lib/devices/CECRecordingDevice.h
src/lib/devices/CECTV.cpp
src/lib/devices/CECTV.h
src/lib/devices/CECTuner.cpp
src/lib/devices/CECTuner.h
src/lib/implementations/ANCommandHandler.cpp
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h
src/lib/implementations/SLCommandHandler.cpp
src/lib/implementations/SLCommandHandler.h
src/lib/implementations/VLCommandHandler.cpp

index 904db4c59f0dd77c006b8dfe4929ddf61547d054..759eb4fa50c941b24f3eaf27c8d2ecfdd4e6d600 100644 (file)
@@ -908,6 +908,19 @@ typedef struct cec_device_type_list
   cec_device_type types[5]; /**< the list of device types */
 
 #ifdef __cplusplus
+  cec_device_type_list operator+ (const cec_device_type_list &other)
+  {
+    cec_device_type_list retVal;
+    for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+    {
+      if (other.types[iPtr] != CEC_DEVICE_TYPE_RESERVED)
+        retVal.Add(other.types[iPtr]);
+      if (types[iPtr] != CEC_DEVICE_TYPE_RESERVED)
+        retVal.Add(types[iPtr]);
+    }
+    return retVal;
+  }
+
   /*!
    * @deprecated Use Clear() instead.
    * @brief Clear this list.
@@ -950,7 +963,7 @@ typedef struct cec_device_type_list
    * @param type The type to check.
    * @return True when set, false otherwise.
    */
-  bool IsSet(cec_device_type type)
+  bool IsSet(const cec_device_type type) const
   {
     bool bReturn(false);
     for (unsigned int iPtr = 0; !bReturn && iPtr < 5; iPtr++)
@@ -1003,12 +1016,15 @@ typedef struct cec_logical_addresses
   int                 addresses[16]; /**< the list of addresses */
 
 #ifdef __cplusplus
+  cec_logical_addresses(void)          { Clear(); }
+  virtual ~cec_logical_addresses(void) { Clear(); }
+
   /*!
    * @brief Clear this list.
    */
   void Clear(void)
   {
-    primary = CECDEVICE_UNKNOWN;
+    primary = CECDEVICE_UNREGISTERED;
     for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
       addresses[iPtr] = 0;
   }
@@ -1018,7 +1034,7 @@ typedef struct cec_logical_addresses
    */
   bool IsEmpty(void) const
   {
-    return primary == CECDEVICE_UNKNOWN;
+    return primary == CECDEVICE_UNREGISTERED;
   }
 
   /*!
@@ -1040,7 +1056,7 @@ typedef struct cec_logical_addresses
    */
   void Set(cec_logical_address address)
   {
-    if (primary == CECDEVICE_UNKNOWN)
+    if (primary == CECDEVICE_UNREGISTERED)
       primary = address;
 
     addresses[(int) address] = 1;
@@ -1050,10 +1066,10 @@ typedef struct cec_logical_addresses
    * @brief Mark a logical address as 'unset'
    * @param address The logical address to remove from this list.
    */
-  void Unset(cec_logical_address address)
+  void Unset(const cec_logical_address address)
   {
     if (primary == address)
-      primary = CECDEVICE_UNKNOWN;
+      primary = CECDEVICE_UNREGISTERED;
 
     addresses[(int) address] = 0;
   }
@@ -1063,7 +1079,7 @@ typedef struct cec_logical_addresses
    * @param address The address to check.
    * @return True when set, false otherwise.
    */
-  bool IsSet(cec_logical_address address) const { return addresses[(int) address] == 1; }
+  bool IsSet(const cec_logical_address address) const { return addresses[(int) address] == 1; }
 
   /*!
    * @brief Check whether an address is set in this list.
@@ -1084,6 +1100,27 @@ typedef struct cec_logical_addresses
   {
     return !(*this == other);
   }
+
+  cec_logical_addresses operator+ (const cec_logical_addresses &other)
+  {
+    cec_logical_addresses retVal;
+    for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+    {
+      if (other.IsSet((cec_logical_address)iPtr) || IsSet((cec_logical_address)iPtr))
+        retVal.Set((cec_logical_address)iPtr);
+    }
+    return retVal;
+  }
+
+  cec_logical_addresses &operator+= (const cec_logical_addresses &other)
+  {
+    for (unsigned int iPtr = 0; iPtr < 16; iPtr++)
+    {
+      if (other.IsSet((cec_logical_address)iPtr))
+        Set((cec_logical_address)iPtr);
+    }
+    return *this;
+  }
 #endif
 } cec_logical_addresses;
 
diff --git a/src/lib/CECClient.cpp b/src/lib/CECClient.cpp
new file mode 100644 (file)
index 0000000..4cccb60
--- /dev/null
@@ -0,0 +1,1018 @@
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "CECClient.h"
+#include "CECProcessor.h"
+#include "LibCEC.h"
+#include "devices/CECPlaybackDevice.h"
+#include "devices/CECAudioSystem.h"
+#include "devices/CECTV.h"
+
+using namespace CEC;
+using namespace PLATFORM;
+
+#define LIB_CEC     m_processor->GetLib()
+#define ToString(x) LIB_CEC->ToString(x)
+
+CCECClient::CCECClient(CCECProcessor *processor, const libcec_configuration *configuration) :
+    m_processor(processor),
+    m_bInitialised(false),
+    m_bRegistered(false),
+    m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
+    m_buttontime(0)
+{
+  SetConfiguration(configuration);
+}
+
+CCECClient::~CCECClient(void)
+{
+  if (m_processor)
+    m_processor->UnregisterClient(this);
+}
+
+bool CCECClient::IsInitialised(void)
+{
+  CLockObject lock(m_mutex);
+  return m_bInitialised && m_processor;
+}
+
+void CCECClient::SetInitialised(bool bSetTo)
+{
+  CLockObject lock(m_mutex);
+  m_bInitialised = bSetTo;
+}
+
+bool CCECClient::IsRegistered(void)
+{
+  CLockObject lock(m_mutex);
+  return m_bRegistered && m_processor;
+}
+
+void CCECClient::SetRegistered(bool bSetTo)
+{
+  CLockObject lock(m_mutex);
+  m_bRegistered = bSetTo;
+}
+
+bool CCECClient::Initialise(void)
+{
+  if (IsInitialised())
+    return true;
+
+  //TODO do the same for the other devices
+  CCECBusDevice *primary = m_processor->GetDevice(m_configuration.logicalAddresses.primary);
+  if (!primary)
+  {
+    LIB_CEC->AddLog(CEC_LOG_WARNING, "cannot find the primary device (logical address %x)", m_configuration.logicalAddresses.primary);
+    return false;
+  }
+
+  /* only set our OSD name for the primary device */
+  primary->SetOSDName(m_configuration.strDeviceName);
+
+  /* set the default menu language for devices we control */
+  primary->SetMenuLanguage(m_configuration.strDeviceLanguage);
+
+  if (CLibCEC::IsValidPhysicalAddress(m_configuration.iPhysicalAddress))
+  {
+    primary->SetPhysicalAddress(m_configuration.iPhysicalAddress);
+    primary->TransmitPhysicalAddress();
+  }
+  else
+  {
+    SetHDMIPort(m_configuration.baseDevice, m_configuration.iHDMIPort, true);
+  }
+
+  /* make the primary device the active source if the option is set */
+  if (m_configuration.bActivateSource == 1)
+    primary->ActivateSource();
+
+  SetInitialised(true);
+  return true;
+}
+
+bool CCECClient::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */)
+{
+  bool bReturn(false);
+
+  // limit the HDMI port range to 1-15
+  if (iPort < CEC_MIN_HDMI_PORTNUMBER ||
+      iPort > CEC_MAX_HDMI_PORTNUMBER)
+    return bReturn;
+
+  {
+    CLockObject lock(m_mutex);
+    m_configuration.baseDevice = iBaseDevice;
+    m_configuration.iHDMIPort  = iPort;
+  }
+
+  if (!m_processor->IsRunning() && !bForce)
+    return true;
+
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
+
+  uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
+  CCECBusDevice *baseDevice = m_processor->GetDevice(iBaseDevice);
+  if (baseDevice)
+    iPhysicalAddress = baseDevice->GetPhysicalAddress(m_configuration.logicalAddresses.primary);
+
+  if (iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS)
+  {
+    if (iPhysicalAddress == 0)
+      iPhysicalAddress += 0x1000 * iPort;
+    else if (iPhysicalAddress % 0x1000 == 0)
+      iPhysicalAddress += 0x100 * iPort;
+    else if (iPhysicalAddress % 0x100 == 0)
+      iPhysicalAddress += 0x10 * iPort;
+    else if (iPhysicalAddress % 0x10 == 0)
+      iPhysicalAddress += iPort;
+
+    bReturn = true;
+  }
+
+  if (!bReturn)
+  {
+    LIB_CEC->AddLog(CEC_LOG_WARNING, "failed to set the physical address to %04X, setting it to the default value %04X", iPhysicalAddress, CEC_DEFAULT_PHYSICAL_ADDRESS);
+    iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS;
+  }
+
+  SetPhysicalAddress(iPhysicalAddress);
+
+  return bReturn;
+}
+
+bool CCECClient::SetPhysicalAddress(uint16_t iPhysicalAddress)
+{
+  bool bSendActiveView(false);
+  bool bReturn(false);
+  bool bSendUpdate = m_processor->CECInitialised();
+
+  CECDEVICEVEC sendUpdatesTo;
+  {
+    CLockObject lock(m_mutex);
+    m_configuration.iPhysicalAddress = iPhysicalAddress;
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting physical address to '%04X'", iPhysicalAddress);
+
+    bool bWasActiveSource(false);
+    CECDEVICEVEC devices;
+    // TODO
+    m_processor->GetDevices()->GetLibCECControlled(devices);
+
+    for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+    {
+      bWasActiveSource |= (*it)->IsActiveSource();
+      (*it)->MarkAsInactiveSource();
+      (*it)->SetPhysicalAddress(iPhysicalAddress);
+      if (bSendUpdate)
+        sendUpdatesTo.push_back(*it);
+    }
+
+    bSendActiveView = bWasActiveSource && bSendUpdate;
+    bReturn = true;
+  }
+
+  for (CECDEVICEVEC::iterator it = sendUpdatesTo.begin(); it != sendUpdatesTo.end(); it++)
+  {
+    (*it)->TransmitPhysicalAddress();
+    if (bSendActiveView && m_configuration.logicalAddresses.primary == (*it)->GetLogicalAddress())
+    {
+      (*it)->MarkAsActiveSource();
+      if ((*it)->HasValidPhysicalAddress())
+        (*it)->ActivateSource();
+    }
+  }
+
+  if (bReturn)
+  {
+    m_processor->PersistConfiguration(&m_configuration);
+    ConfigurationChanged(m_configuration);
+  }
+
+  return bReturn;
+}
+
+bool CCECClient::FindLogicalAddresses(void)
+{
+  m_configuration.logicalAddresses.Clear();
+
+  if (m_configuration.deviceTypes.IsEmpty())
+  {
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "no device types given");
+    return false;
+  }
+
+  for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
+  {
+    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+      continue;
+
+    cec_logical_address address(CECDEVICE_UNKNOWN);
+    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+      address = FindLogicalAddressRecordingDevice();
+    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
+      address = FindLogicalAddressTuner();
+    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
+      address = FindLogicalAddressPlaybackDevice();
+    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+      address = FindLogicalAddressAudioSystem();
+
+    if (address == CECDEVICE_UNKNOWN)
+    {
+      LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - failed to allocate device '%d', type '%s'", __FUNCTION__, iPtr, ToString(m_configuration.deviceTypes.types[iPtr]));
+      return false;
+    }
+
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - device '%d', type '%s', LA '%X'", __FUNCTION__, iPtr, ToString(m_configuration.deviceTypes.types[iPtr]), address);
+    m_configuration.logicalAddresses.Set(address);
+  }
+
+  return true;
+}
+
+cec_logical_address CCECClient::FindLogicalAddressRecordingDevice(void)
+{
+  cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
+  if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1))
+    retVal = CECDEVICE_RECORDINGDEVICE1;
+  else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2))
+    retVal = CECDEVICE_RECORDINGDEVICE2;
+  else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3))
+    retVal = CECDEVICE_RECORDINGDEVICE3;
+
+  return retVal;
+}
+
+cec_logical_address CCECClient::FindLogicalAddressTuner(void)
+{
+  cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
+  if (m_processor->TryLogicalAddress(CECDEVICE_TUNER1))
+    retVal = CECDEVICE_TUNER1;
+  else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER2))
+    retVal = CECDEVICE_TUNER2;
+  else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER3))
+    retVal = CECDEVICE_TUNER3;
+  else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER4))
+    retVal = CECDEVICE_TUNER4;
+
+  return retVal;
+}
+
+cec_logical_address CCECClient::FindLogicalAddressPlaybackDevice(void)
+{
+  cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
+  if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1))
+    retVal = CECDEVICE_PLAYBACKDEVICE1;
+  else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2))
+    retVal = CECDEVICE_PLAYBACKDEVICE2;
+  else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3))
+    retVal = CECDEVICE_PLAYBACKDEVICE3;
+
+  return retVal;
+}
+
+cec_logical_address CCECClient::FindLogicalAddressAudioSystem(void)
+{
+  cec_logical_address retVal(CECDEVICE_UNKNOWN);
+
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audiosystem'");
+  if (m_processor->TryLogicalAddress(CECDEVICE_AUDIOSYSTEM))
+    retVal = CECDEVICE_AUDIOSYSTEM;
+
+  return retVal;
+}
+
+CCECBusDevice *CCECClient::GetDeviceByType(const cec_device_type type) const
+{
+  // get all devices that match our logical addresses
+  CECDEVICEVEC devices;
+  m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+  // filter the type we need
+  CCECDeviceMap::FilterType(type, devices);
+
+  return devices.empty() ?
+      NULL :
+      *devices.begin();
+}
+
+bool CCECClient::ChangeDeviceType(cec_device_type from, cec_device_type to)
+{
+  bool bChanged(false);
+
+  LIB_CEC->AddLog(CEC_LOG_NOTICE, "changing device type '%s' into '%s'", ToString(from), ToString(to));
+
+  CLockObject lock(m_mutex);
+
+  CCECBusDevice *previousDevice = GetDeviceByType(from);
+  if (!previousDevice)
+    return false;
+
+  m_processor->UnregisterClient(this);
+
+  m_configuration.logicalAddresses.primary = CECDEVICE_UNREGISTERED;
+
+  for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
+  {
+    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
+      continue;
+
+    if (m_configuration.deviceTypes.types[iPtr] == from)
+    {
+      bChanged = true;
+      m_configuration.deviceTypes.types[iPtr] = to;
+    }
+    else if (m_configuration.deviceTypes.types[iPtr] == to && bChanged)
+    {
+      m_configuration.deviceTypes.types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
+    }
+  }
+
+  if (bChanged)
+  {
+    // re-register the client to set the new ackmask
+    if (!m_processor->RegisterClient(this))
+      return false;
+
+    // copy the data from the previous device
+    CCECBusDevice *newDevice = GetDeviceByType(to);
+    if (previousDevice && newDevice)
+    {
+      newDevice->SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+      newDevice->SetCecVersion(previousDevice->GetCecVersion(m_configuration.logicalAddresses.primary, false));
+      newDevice->SetMenuLanguage(previousDevice->GetMenuLanguage(m_configuration.logicalAddresses.primary, false));
+      newDevice->SetMenuState(previousDevice->GetMenuState(m_configuration.logicalAddresses.primary));
+      newDevice->SetOSDName(previousDevice->GetOSDName(m_configuration.logicalAddresses.primary, false));
+      newDevice->SetPhysicalAddress(previousDevice->GetCurrentPhysicalAddress());
+      newDevice->SetPowerStatus(previousDevice->GetPowerStatus(m_configuration.logicalAddresses.primary, false));
+      newDevice->SetVendorId(previousDevice->GetVendorId(m_configuration.logicalAddresses.primary, false));
+
+      if ((from == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || from == CEC_DEVICE_TYPE_RECORDING_DEVICE) &&
+          (to == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || to == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+      {
+        newDevice->AsPlaybackDevice()->SetDeckControlMode(previousDevice->AsPlaybackDevice()->GetDeckControlMode(m_configuration.logicalAddresses.primary));
+        newDevice->AsPlaybackDevice()->SetDeckStatus(previousDevice->AsPlaybackDevice()->GetDeckStatus(m_configuration.logicalAddresses.primary));
+      }
+    }
+
+    // and reset the previous device to the initial state
+    if (previousDevice)
+      previousDevice->ResetDeviceStatus();
+  }
+
+  return true;
+}
+
+bool CCECClient::SetLogicalAddress(cec_logical_address iLogicalAddress)
+{
+  CLockObject lock(m_mutex);
+  if (m_configuration.logicalAddresses.primary != iLogicalAddress)
+  {
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< setting primary logical address to %1x", iLogicalAddress);
+    m_configuration.logicalAddresses.primary = iLogicalAddress;
+    m_configuration.logicalAddresses.Set(iLogicalAddress);
+    return m_processor->RegisterClient(this);
+  }
+
+  return true;
+}
+
+bool CCECClient::Transmit(const cec_command &data)
+{
+  return m_processor ? m_processor->Transmit(data) : false;
+}
+
+bool CCECClient::SendPowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
+{
+  if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
+  {
+    CECDEVICEVEC devices;
+    m_processor->GetDevices()->GetWakeDevices(m_configuration, devices);
+    return m_processor->PowerOnDevices(m_configuration.logicalAddresses.primary, devices);
+  }
+
+  return m_processor->PowerOnDevice(m_configuration.logicalAddresses.primary, address);
+}
+
+bool CCECClient::SendStandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+{
+  if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
+  {
+    CECDEVICEVEC devices;
+    m_processor->GetDevices()->GetPowerOffDevices(m_configuration, devices);
+    return m_processor->StandbyDevices(m_configuration.logicalAddresses.primary, devices);
+  }
+
+  return m_processor->StandbyDevice(m_configuration.logicalAddresses.primary, address);
+}
+
+bool CCECClient::SendSetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
+{
+  bool bReturn(false);
+
+  CCECBusDevice *device(NULL);
+  CECDEVICEVEC devices;
+  m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+  if (type != CEC_DEVICE_TYPE_RESERVED)
+    CCECDeviceMap::FilterType(type, devices);
+
+  // no devices left
+  if (devices.empty())
+    m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+  if (!devices.empty())
+    device = *devices.begin();
+
+  if (device)
+  {
+    bReturn = true;
+    if (m_processor->IsRunning() && device->HasValidPhysicalAddress())
+      bReturn = device->ActivateSource();
+  }
+
+  return bReturn;
+}
+
+CCECPlaybackDevice *CCECClient::GetPlaybackDevice(void)
+{
+  CCECPlaybackDevice *device(NULL);
+  CECDEVICEVEC devices;
+  m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+  CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE, devices);
+
+  // no devices left
+  if (devices.empty())
+  {
+    m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+    CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_RECORDING_DEVICE, devices);
+  }
+
+  if (!devices.empty())
+    device = (*devices.begin())->AsPlaybackDevice();
+
+  return device;
+}
+
+CCECBusDevice *CCECClient::GetPrimaryDevice(void)
+{
+  return m_processor->GetDevice(m_configuration.logicalAddresses.primary);
+}
+
+bool CCECClient::SendSetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
+{
+  bool bReturn(false);
+
+  CCECBusDevice *device = GetPlaybackDevice();
+  if (device)
+  {
+    device->AsPlaybackDevice()->SetDeckControlMode(mode);
+    if (bSendUpdate)
+      bReturn = device->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV);
+    else
+      bReturn = true;
+  }
+
+  return false;
+}
+
+bool CCECClient::SendSetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
+{
+  bool bReturn(false);
+
+  CCECBusDevice *device = GetPlaybackDevice();
+  if (device)
+  {
+    device->AsPlaybackDevice()->SetDeckStatus(info);
+    if (bSendUpdate)
+      bReturn = device->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV);
+    else
+      bReturn = true;
+  }
+
+  return false;
+}
+
+bool CCECClient::SendSetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
+{
+  CECDEVICEVEC devices;
+  m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
+
+  for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+  {
+    (*it)->SetMenuState(state);
+    if (bSendUpdate)
+      (*it)->TransmitMenuState(CECDEVICE_TV);
+  }
+
+  return true;
+}
+
+bool CCECClient::SendSetInactiveView(void)
+{
+  CCECBusDevice *primary = GetPrimaryDevice();
+  if (primary)
+  {
+    primary->MarkAsInactiveSource();
+    return primary->TransmitInactiveSource();
+  }
+  return false;
+}
+
+bool CCECClient::SendSetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage)
+{
+  CCECBusDevice *primary = GetPrimaryDevice();
+  if (primary)
+    return primary->TransmitOSDString(iLogicalAddress, duration, strMessage);
+
+  return false;
+}
+
+cec_version CCECClient::GetDeviceCecVersion(cec_logical_address iAddress)
+{
+  CCECBusDevice *device = m_processor->GetDevice(iAddress);
+  if (device)
+    return device->GetCecVersion(m_configuration.logicalAddresses.primary);
+  return CEC_VERSION_UNKNOWN;
+}
+
+bool CCECClient::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
+{
+  CCECBusDevice *device = m_processor->GetDevice(iAddress);
+  if (device)
+  {
+    *language = device->GetMenuLanguage(m_configuration.logicalAddresses.primary);
+    return (strcmp(language->language, "???") != 0);
+  }
+  return false;
+}
+
+cec_osd_name CCECClient::GetDeviceOSDName(cec_logical_address iAddress)
+{
+  cec_osd_name retVal;
+  retVal.device = iAddress;
+  retVal.name[0] = 0;
+
+  CCECBusDevice *device = m_processor->GetDevice(iAddress);
+  if (device)
+  {
+    CStdString strOSDName = device->GetOSDName(m_configuration.logicalAddresses.primary);
+    snprintf(retVal.name, sizeof(retVal.name), "%s", strOSDName.c_str());
+    retVal.device = iAddress;
+  }
+
+  return retVal;
+}
+
+uint16_t CCECClient::GetDevicePhysicalAddress(cec_logical_address iAddress)
+{
+  CCECBusDevice *device = m_processor->GetDevice(iAddress);
+  if (device)
+    return device->GetPhysicalAddress(m_configuration.logicalAddresses.primary);
+  return CEC_INVALID_PHYSICAL_ADDRESS;
+}
+
+cec_power_status CCECClient::GetDevicePowerStatus(cec_logical_address iAddress)
+{
+  CCECBusDevice *device = m_processor->GetDevice(iAddress);
+  if (device)
+    return device->GetPowerStatus(m_configuration.logicalAddresses.primary);
+  return CEC_POWER_STATUS_UNKNOWN;
+}
+
+uint64_t CCECClient::GetDeviceVendorId(cec_logical_address iAddress)
+{
+  CCECBusDevice *device = m_processor->GetDevice(iAddress);
+  if (device)
+    return device->GetVendorId(m_configuration.logicalAddresses.primary);
+  return CEC_VENDOR_UNKNOWN;
+}
+
+uint8_t CCECClient::SendVolumeUp(bool bSendRelease /* = true */)
+{
+  CCECBusDevice *device = GetPrimaryDevice();
+  CCECAudioSystem *audio = m_processor->GetAudioSystem();
+
+  return device && audio && audio->IsPresent() ?
+      audio->VolumeUp(device->GetLogicalAddress(), bSendRelease) :
+      (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CCECClient::SendVolumeDown(bool bSendRelease /* = true */)
+{
+  CCECBusDevice *device = GetPrimaryDevice();
+  CCECAudioSystem *audio = m_processor->GetAudioSystem();
+
+  return device && audio && audio->IsPresent() ?
+      audio->VolumeDown(device->GetLogicalAddress(), bSendRelease) :
+      (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CCECClient::SendMuteAudio(void)
+{
+  CCECBusDevice *device = GetPrimaryDevice();
+  CCECAudioSystem *audio = m_processor->GetAudioSystem();
+
+  return device && audio && audio->IsPresent() ?
+      audio->MuteAudio(device->GetLogicalAddress()) :
+      (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+bool CCECClient::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
+{
+  CCECBusDevice *device = GetPrimaryDevice();
+  CCECBusDevice *dest = m_processor->GetDevice(iDestination);
+
+  return device && dest ?
+      device->TransmitKeypress(m_configuration.logicalAddresses.primary, key, bWait) :
+      false;
+}
+
+bool CCECClient::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
+{
+  CCECBusDevice *device = GetPrimaryDevice();
+  CCECBusDevice *dest = m_processor->GetDevice(iDestination);
+
+  return device && dest ?
+      device->TransmitKeyRelease(m_configuration.logicalAddresses.primary, bWait) :
+      false;
+}
+
+bool CCECClient::GetCurrentConfiguration(libcec_configuration *configuration)
+{
+  // client version 1.5.0
+  snprintf(configuration->strDeviceName, 13, "%s", m_configuration.strDeviceName);
+  configuration->deviceTypes          = m_configuration.deviceTypes;
+  configuration->bAutodetectAddress   = m_configuration.bAutodetectAddress;
+  configuration->iPhysicalAddress     = m_configuration.iPhysicalAddress;
+  configuration->baseDevice           = m_configuration.baseDevice;
+  configuration->iHDMIPort            = m_configuration.iHDMIPort;
+  configuration->clientVersion        = m_configuration.clientVersion;
+  configuration->serverVersion        = m_configuration.serverVersion;
+  configuration->tvVendor             = m_configuration.tvVendor;
+
+  configuration->bGetSettingsFromROM  = m_configuration.bGetSettingsFromROM;
+  configuration->bUseTVMenuLanguage   = m_configuration.bUseTVMenuLanguage;
+  configuration->bActivateSource      = m_configuration.bActivateSource;
+  configuration->wakeDevices          = m_configuration.wakeDevices;
+  configuration->powerOffDevices      = m_configuration.powerOffDevices;
+  configuration->bPowerOffScreensaver = m_configuration.bPowerOffScreensaver;
+  configuration->bPowerOffOnStandby   = m_configuration.bPowerOffOnStandby;
+
+  // client version 1.5.1
+  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_5_1)
+    configuration->bSendInactiveSource = m_configuration.bSendInactiveSource;
+
+  // client version 1.5.3
+  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_5_3)
+    configuration->logicalAddresses    = m_configuration.logicalAddresses;
+
+  // client version 1.6.0
+  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_0)
+  {
+    configuration->iFirmwareVersion          = m_configuration.iFirmwareVersion;
+    configuration->bPowerOffDevicesOnStandby = m_configuration.bPowerOffDevicesOnStandby;
+    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 CCECClient::SetConfiguration(const libcec_configuration *configuration)
+{
+  bool bReinit(false);
+  bool bIsRunning(m_processor && m_processor->IsRunning());
+
+  if (configuration->callbacks)
+  {
+    m_configuration.callbacks     = configuration->callbacks;
+    m_configuration.callbackParam = configuration->callbackParam;
+  }
+
+  //TODO
+  CCECBusDevice *primary = bIsRunning ? GetPrimaryDevice() : NULL;
+  cec_device_type oldPrimaryType = primary ? primary->GetType() : CEC_DEVICE_TYPE_RECORDING_DEVICE;
+
+  m_configuration.serverVersion  = LIBCEC_VERSION_CURRENT;
+  m_configuration.clientVersion  = configuration->clientVersion;
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using client version '%s'", __FUNCTION__, ToString((cec_client_version)configuration->clientVersion));
+
+  // client version 1.5.0
+
+  // device types
+  bool bDeviceTypeChanged = bIsRunning && m_configuration.deviceTypes != configuration->deviceTypes;
+  m_configuration.deviceTypes = configuration->deviceTypes;
+  if (bDeviceTypeChanged)
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using primary device type '%s'", __FUNCTION__, ToString(configuration->deviceTypes[0]));
+
+  bool bPhysicalAddressChanged(false);
+
+  // autodetect address
+  bool bPhysicalAutodetected(false);
+  if (bIsRunning && configuration->bAutodetectAddress == 1)
+  {
+    uint16_t iPhysicalAddress = m_processor->GetDetectedPhysicalAddress();
+    if (CLibCEC::IsValidPhysicalAddress(iPhysicalAddress))
+    {
+      if (bIsRunning)
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - autodetected physical address '%04X'", __FUNCTION__, iPhysicalAddress);
+      else
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using physical address '%04X'", __FUNCTION__, iPhysicalAddress);
+      bPhysicalAddressChanged = (m_configuration.iPhysicalAddress != iPhysicalAddress);
+      m_configuration.iPhysicalAddress = iPhysicalAddress;
+      m_configuration.iHDMIPort        = CEC_HDMI_PORTNUMBER_NONE;
+      m_configuration.baseDevice       = CECDEVICE_UNKNOWN;
+      bPhysicalAutodetected            = true;
+    }
+  }
+
+  // physical address
+  if (!bPhysicalAutodetected)
+  {
+    uint16_t iPhysicalAddress(CLibCEC::IsValidPhysicalAddress(configuration->iPhysicalAddress) ? configuration->iPhysicalAddress : CEC_PHYSICAL_ADDRESS_TV);
+    bPhysicalAddressChanged = bIsRunning && m_configuration.iPhysicalAddress != iPhysicalAddress;
+    if (bPhysicalAddressChanged)
+    {
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - physical address '%04X'", __FUNCTION__, iPhysicalAddress);
+      m_configuration.iPhysicalAddress = iPhysicalAddress;
+    }
+  }
+
+  bool bHdmiPortChanged(false);
+  if (!bPhysicalAutodetected && !CLibCEC::IsValidPhysicalAddress(configuration->iPhysicalAddress))
+  {
+    // base device
+    bHdmiPortChanged = bIsRunning && m_configuration.baseDevice != configuration->baseDevice;
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using base device '%x'", __FUNCTION__, (int)configuration->baseDevice);
+    m_configuration.baseDevice = configuration->baseDevice;
+
+    // hdmi port
+    bHdmiPortChanged |= bIsRunning && m_configuration.iHDMIPort != configuration->iHDMIPort;
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using HDMI port '%d'", __FUNCTION__, configuration->iHDMIPort);
+    m_configuration.iHDMIPort = configuration->iHDMIPort;
+  }
+  else
+  {
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - resetting HDMI port and base device to defaults", __FUNCTION__);
+    m_configuration.baseDevice = CECDEVICE_UNKNOWN;
+    m_configuration.iHDMIPort  = CEC_HDMI_PORTNUMBER_NONE;
+  }
+
+  bReinit = bPhysicalAddressChanged || bHdmiPortChanged || bDeviceTypeChanged;
+
+  // device name
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using OSD name '%s'", __FUNCTION__, configuration->strDeviceName);
+  snprintf(m_configuration.strDeviceName, 13, "%s", configuration->strDeviceName);
+  if (primary && !primary->GetOSDName(m_configuration.logicalAddresses.primary, false).Equals(m_configuration.strDeviceName))
+  {
+    primary->SetOSDName(m_configuration.strDeviceName);
+    if (!bReinit && bIsRunning)
+      primary->TransmitOSDName(CECDEVICE_TV);
+  }
+
+  // tv vendor id override
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vendor id '%s'", __FUNCTION__, ToString((cec_vendor_id)configuration->tvVendor));
+  if (m_processor && m_configuration.tvVendor != configuration->tvVendor)
+  {
+    m_configuration.tvVendor= configuration->tvVendor;
+    m_processor->GetTV()->SetVendorId((uint64_t)m_configuration.tvVendor);
+  }
+
+  // wake CEC devices
+  if (m_configuration.wakeDevices != configuration->wakeDevices)
+  {
+    m_configuration.wakeDevices = configuration->wakeDevices;
+    if (!bReinit && bIsRunning)
+      SendPowerOnDevices();
+  }
+
+  // just copy these
+  m_configuration.bUseTVMenuLanguage   = configuration->bUseTVMenuLanguage;
+  m_configuration.bActivateSource      = configuration->bActivateSource;
+  m_configuration.bGetSettingsFromROM  = configuration->bGetSettingsFromROM;
+  m_configuration.powerOffDevices      = configuration->powerOffDevices;
+  m_configuration.bPowerOffScreensaver = configuration->bPowerOffScreensaver;
+  m_configuration.bPowerOffOnStandby   = configuration->bPowerOffOnStandby;
+
+  // client version 1.5.1
+  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_5_1)
+    m_configuration.bSendInactiveSource = configuration->bSendInactiveSource;
+
+  // client version 1.6.0
+  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_0)
+  {
+    m_configuration.bPowerOffDevicesOnStandby = configuration->bPowerOffDevicesOnStandby;
+    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);
+
+  if (bIsRunning)
+    m_processor->GetTV()->ReplaceHandler(false);
+
+  bool bReturn(true);
+  if (bReinit || m_configuration.logicalAddresses.IsEmpty())
+  {
+    if (bDeviceTypeChanged)
+      bReturn = ChangeDeviceType(oldPrimaryType, m_configuration.deviceTypes[0]);
+    else if (CLibCEC::IsValidPhysicalAddress(m_configuration.iPhysicalAddress))
+      bReturn = SetPhysicalAddress(m_configuration.iPhysicalAddress);
+    else if (m_configuration.baseDevice != CECDEVICE_UNKNOWN && m_configuration.iHDMIPort != CEC_HDMI_PORTNUMBER_NONE)
+      bReturn = SetHDMIPort(m_configuration.baseDevice, m_configuration.iHDMIPort);
+  }
+  else if (m_configuration.bActivateSource == 1 && bIsRunning && !m_processor->IsActiveSource(m_configuration.logicalAddresses.primary))
+  {
+    // activate the source if we're not already the active source
+    m_processor->SetActiveSource(m_configuration.deviceTypes.types[0]);
+  }
+
+  // persist the configuration
+  if (bIsRunning)
+    m_processor->PersistConfiguration(&m_configuration);
+
+  return bReturn;
+}
+
+void CCECClient::AddCommand(const cec_command &command)
+{
+  CLockObject lock(m_mutex);
+
+  LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> %s (%X) -> %s (%X): %s (%2X)", ToString(command.initiator), command.initiator, ToString(command.destination), command.destination, ToString(command.opcode), command.opcode);
+
+  if (m_configuration.callbacks && m_configuration.callbacks->CBCecCommand)
+    m_configuration.callbacks->CBCecCommand(m_configuration.callbackParam, command);
+  else if (!m_commandBuffer.Push(command))
+    LIB_CEC->AddLog(CEC_LOG_WARNING, "command buffer is full");
+}
+
+int CCECClient::MenuStateChanged(const cec_menu_state newState)
+{
+  CLockObject lock(m_mutex);
+
+  LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> %s: %s", ToString(CEC_OPCODE_MENU_REQUEST), ToString(newState));
+
+  if (m_configuration.callbacks &&
+      m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_2 &&
+      m_configuration.callbacks->CBCecMenuStateChanged)
+    return m_configuration.callbacks->CBCecMenuStateChanged(m_configuration.callbackParam, newState);
+
+  return 0;
+}
+
+void CCECClient::Alert(const libcec_alert type, const libcec_parameter &param)
+{
+  CLockObject lock(m_mutex);
+
+  if (m_configuration.callbacks &&
+      m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_0 &&
+      m_configuration.callbacks->CBCecAlert)
+    m_configuration.callbacks->CBCecAlert(m_configuration.callbackParam, type, param);
+}
+
+void CCECClient::AddLog(const cec_log_message &message)
+{
+  CLockObject lock(m_logMutex);
+  if (m_configuration.callbacks && m_configuration.callbacks->CBCecLogMessage)
+    m_configuration.callbacks->CBCecLogMessage(m_configuration.callbackParam, message);
+  else
+    m_logBuffer.Push(message);
+}
+
+void CCECClient::AddKey(void)
+{
+  CLockObject lock(m_mutex);
+
+  if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
+  {
+    cec_keypress key;
+
+    key.duration = (unsigned int) (GetTimeMs() - m_buttontime);
+    key.keycode = m_iCurrentButton;
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "key released: %1x", key.keycode);
+
+    if (m_configuration.callbacks && m_configuration.callbacks->CBCecKeyPress)
+      m_configuration.callbacks->CBCecKeyPress(m_configuration.callbackParam, key);
+    else
+      m_keyBuffer.Push(key);
+    m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+  }
+
+  m_buttontime = 0;
+}
+
+void CCECClient::AddKey(const cec_keypress &key)
+{
+  CLockObject lock(m_mutex);
+
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %1x", key.keycode);
+
+  if (m_configuration.callbacks && m_configuration.callbacks->CBCecKeyPress)
+    m_configuration.callbacks->CBCecKeyPress(m_configuration.callbackParam, key);
+  else
+    m_keyBuffer.Push(key);
+
+  m_iCurrentButton = key.duration > 0 ? CEC_USER_CONTROL_CODE_UNKNOWN : key.keycode;
+  m_buttontime = key.duration > 0 ? 0 : GetTimeMs();
+}
+
+void CCECClient::SetCurrentButton(cec_user_control_code iButtonCode)
+{
+  /* push keypress to the keybuffer with 0 duration.
+     push another press to the keybuffer with the duration set when the button is released */
+  cec_keypress key;
+  key.duration = 0;
+  key.keycode = iButtonCode;
+
+  AddKey(key);
+}
+
+void CCECClient::CheckKeypressTimeout(void)
+{
+  if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && GetTimeMs() - m_buttontime > CEC_BUTTON_TIMEOUT)
+  {
+    AddKey();
+    m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
+  }
+}
+
+void CCECClient::ConfigurationChanged(const libcec_configuration &config)
+{
+  CLockObject lock(m_mutex);
+
+  if (m_configuration.callbacks &&
+      m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0 &&
+      m_configuration.callbacks->CBCecConfigurationChanged &&
+      m_processor->CECInitialised())
+    m_configuration.callbacks->CBCecConfigurationChanged(m_configuration.callbackParam, config);
+}
+
+bool CCECClient::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
+{
+  CLockObject lock(m_mutex);
+  m_configuration.callbackParam = cbParam;
+  m_configuration.callbacks     = callbacks;
+  return true;
+}
+
+bool CCECClient::GetNextLogMessage(cec_log_message *message)
+{
+  return (m_logBuffer.Pop(*message));
+}
+
+bool CCECClient::GetNextKeypress(cec_keypress *key)
+{
+  return m_keyBuffer.Pop(*key);
+}
+
+bool CCECClient::GetNextCommand(cec_command *command)
+{
+  return m_commandBuffer.Pop(*command);
+}
diff --git a/src/lib/CECClient.h b/src/lib/CECClient.h
new file mode 100644 (file)
index 0000000..0ea111f
--- /dev/null
@@ -0,0 +1,126 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "../../include/cectypes.h"
+#include "platform/threads/mutex.h"
+#include "platform/util/buffer.h"
+
+#include "devices/CECBusDevice.h"
+
+namespace CEC
+{
+  class CCECProcessor;
+
+  class CCECClient
+  {
+  public:
+    CCECClient(CCECProcessor *processor, const libcec_configuration *configuration);
+    virtual ~CCECClient(void);
+
+    // methods for registration in CCECProcessor
+    bool                Initialise(void);
+    void                OnUnregister(void) { SetRegistered(false); SetInitialised(false); }
+    bool                IsInitialised(void);
+    void                SetInitialised(bool bSetTo);
+    bool                IsRegistered(void);
+    void                SetRegistered(bool bSetTo);
+    CCECBusDevice *     GetPrimaryDevice(void);
+    CCECPlaybackDevice *GetPlaybackDevice(void);
+    bool                FindLogicalAddresses(void);
+    bool                ChangeDeviceType(cec_device_type from, cec_device_type to);
+    CCECBusDevice *     GetDeviceByType(const cec_device_type type) const;
+
+    // client-specific part of ICECAdapter
+    bool                EnableCallbacks(void *cbParam, ICECCallbacks *callbacks);
+    bool                GetNextLogMessage(cec_log_message *message);
+    bool                GetNextKeypress(cec_keypress *key);
+    bool                GetNextCommand(cec_command *command);
+    bool                Transmit(const cec_command &data);
+    bool                SetLogicalAddress(cec_logical_address iLogicalAddress);
+    bool                SetPhysicalAddress(uint16_t iPhysicalAddress);
+    bool                SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce = false);
+    bool                SendPowerOnDevices(cec_logical_address address = CECDEVICE_TV);
+    bool                SendStandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST);
+    bool                SendSetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED);
+    bool                SendSetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate = true);
+    bool                SendSetDeckInfo(cec_deck_info info, bool bSendUpdate = true);
+    bool                SendSetInactiveView(void);
+    bool                SendSetMenuState(cec_menu_state state, bool bSendUpdate = true);
+    bool                SendSetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage);
+    cec_version         GetDeviceCecVersion(cec_logical_address iAddress);
+    bool                GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language);
+    uint64_t            GetDeviceVendorId(cec_logical_address iAddress);
+    cec_power_status    GetDevicePowerStatus(cec_logical_address iAddress);
+    uint16_t            GetDevicePhysicalAddress(cec_logical_address iAddress);
+    uint8_t             SendVolumeUp(bool bSendRelease = true);
+    uint8_t             SendVolumeDown(bool bSendRelease = true);
+    uint8_t             SendMuteAudio(void);
+    bool                SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = true);
+    bool                SendKeyRelease(cec_logical_address iDestination, bool bWait = true);
+    cec_osd_name        GetDeviceOSDName(cec_logical_address iAddress);
+
+    // configuration
+    libcec_configuration *GetConfiguration(void) { return &m_configuration; }
+    bool                  GetCurrentConfiguration(libcec_configuration *configuration);
+    bool                  SetConfiguration(const libcec_configuration *configuration);
+
+    // callbacks
+    void AddCommand(const cec_command &command);
+    int  MenuStateChanged(const cec_menu_state newState);
+    void Alert(const libcec_alert type, const libcec_parameter &param);
+    void AddLog(const cec_log_message &message);
+    void AddKey(void);
+    void AddKey(const cec_keypress &key);
+    void SetCurrentButton(cec_user_control_code iButtonCode);
+    void CheckKeypressTimeout(void);
+    void ConfigurationChanged(const libcec_configuration &config);
+
+  protected:
+    cec_logical_address FindLogicalAddressRecordingDevice(void);
+    cec_logical_address FindLogicalAddressTuner(void);
+    cec_logical_address FindLogicalAddressPlaybackDevice(void);
+    cec_logical_address FindLogicalAddressAudioSystem(void);
+
+    CCECProcessor *                         m_processor;
+    libcec_configuration                    m_configuration;
+    bool                                    m_bInitialised;
+    bool                                    m_bRegistered;
+    PLATFORM::CMutex                        m_mutex;
+    PLATFORM::SyncedBuffer<cec_log_message> m_logBuffer;
+    PLATFORM::CMutex                        m_logMutex;
+    PLATFORM::SyncedBuffer<cec_keypress>    m_keyBuffer;
+    PLATFORM::SyncedBuffer<cec_command>     m_commandBuffer;
+    cec_user_control_code                   m_iCurrentButton;
+    int64_t                                 m_buttontime;
+  };
+}
diff --git a/src/lib/CECInputBuffer.h b/src/lib/CECInputBuffer.h
new file mode 100644 (file)
index 0000000..9daf582
--- /dev/null
@@ -0,0 +1,91 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "../../include/cectypes.h"
+#include "platform/threads/mutex.h"
+#include "platform/util/buffer.h"
+
+namespace CEC
+{
+  // a buffer that priotises the input from the TV.
+  // if we need more than this, we'll have to change it into a priority_queue
+  class CCECInputBuffer
+  {
+  public:
+    CCECInputBuffer(void) : m_bHasData(false) {}
+    virtual ~CCECInputBuffer(void)
+    {
+      m_condition.Broadcast();
+    }
+
+    bool Push(const cec_command &command)
+    {
+      bool bReturn(false);
+      PLATFORM::CLockObject lock(m_mutex);
+      if (command.initiator == CECDEVICE_TV)
+        bReturn = m_tvInBuffer.Push(command);
+      else
+        bReturn = m_inBuffer.Push(command);
+
+      m_bHasData |= bReturn;
+      if (m_bHasData)
+        m_condition.Signal();
+
+      return bReturn;
+    }
+
+    bool Pop(cec_command &command, uint16_t iTimeout)
+    {
+      bool bReturn(false);
+      PLATFORM::CLockObject lock(m_mutex);
+      if (m_tvInBuffer.IsEmpty() && m_inBuffer.IsEmpty() &&
+          !m_condition.Wait(m_mutex, m_bHasData, iTimeout))
+        return bReturn;
+
+      if (m_tvInBuffer.Pop(command))
+        bReturn = true;
+      else if (m_inBuffer.Pop(command))
+        bReturn = true;
+
+      m_bHasData = !m_tvInBuffer.IsEmpty() || !m_inBuffer.IsEmpty();
+      return bReturn;
+    }
+
+  private:
+    PLATFORM::CMutex                    m_mutex;
+    PLATFORM::CCondition<volatile bool> m_condition;
+    volatile bool                       m_bHasData;
+    PLATFORM::SyncedBuffer<cec_command> m_tvInBuffer;
+    PLATFORM::SyncedBuffer<cec_command> m_inBuffer;
+  };
+};
index 272723ed48e46567222e92d55ca6f7077167eb31..435177b6e3bceaeb18119fac58e9d6794c2840b4 100644 (file)
@@ -41,6 +41,7 @@
 #include "devices/CECTV.h"
 #include "implementations/CECCommandHandler.h"
 #include "LibCEC.h"
+#include "CECClient.h"
 #include "platform/util/timeutils.h"
 
 using namespace CEC;
@@ -49,111 +50,56 @@ using namespace PLATFORM;
 
 #define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000
 
-CCECProcessor::CCECProcessor(CLibCEC *controller, libcec_configuration *configuration) :
-    m_bConnectionOpened(false),
+#define ToString(x) m_libcec->ToString(x)
+
+CCECProcessor::CCECProcessor(CLibCEC *libcec) :
     m_bInitialised(false),
     m_communication(NULL),
-    m_controller(controller),
+    m_libcec(libcec),
     m_bMonitor(false),
+    m_iPreviousAckMask(0),
     m_iStandardLineTimeout(3),
     m_iRetryLineTimeout(3),
     m_iLastTransmission(0)
 {
-  CreateBusDevices();
-  m_configuration.Clear();
-  m_configuration.serverVersion = LIBCEC_VERSION_CURRENT;
-  SetConfiguration(configuration);
-
-  if (m_configuration.tvVendor != CEC_VENDOR_UNKNOWN)
-    m_busDevices[CECDEVICE_TV]->ReplaceHandler(false);
+  m_busDevices = new CCECDeviceMap(this);
 }
 
-CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types, uint16_t iPhysicalAddress) :
-    m_bConnectionOpened(false),
-    m_bInitialised(false),
-    m_communication(NULL),
-    m_controller(controller),
-    m_bMonitor(false),
-    m_iStandardLineTimeout(3),
-    m_iRetryLineTimeout(3),
-    m_iLastTransmission(0)
+CCECProcessor::~CCECProcessor(void)
 {
-  m_configuration.Clear();
-  m_configuration.serverVersion    = LIBCEC_VERSION_CURRENT;
-
-  // client version < 1.5.0
-  m_configuration.clientVersion    = (uint32_t)CEC_CLIENT_VERSION_PRE_1_5;
-  snprintf(m_configuration.strDeviceName, 13, "%s", strDeviceName);
-  m_configuration.deviceTypes      = types;
-  m_configuration.iPhysicalAddress = iPhysicalAddress;
-  m_configuration.baseDevice       = (cec_logical_address)CEC_DEFAULT_BASE_DEVICE;
-  m_configuration.iHDMIPort        = CEC_DEFAULT_HDMI_PORT;
-
-  if (m_configuration.deviceTypes.IsEmpty())
-    m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
-  CreateBusDevices();
+  Close();
+  delete m_busDevices;
 }
 
-void CCECProcessor::CreateBusDevices(void)
+bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
 {
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
+  CLockObject lock(m_mutex);
+  if (!OpenConnection(strPort, iBaudRate, iTimeoutMs))
+    return false;
+
+  /* create the processor thread */
+  if (!IsRunning())
   {
-    switch(iPtr)
+    if (CreateThread())
+      m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started");
+    else
     {
-    case CECDEVICE_AUDIOSYSTEM:
-      m_busDevices[iPtr] = new CCECAudioSystem(this, (cec_logical_address) iPtr);
-      break;
-    case CECDEVICE_PLAYBACKDEVICE1:
-    case CECDEVICE_PLAYBACKDEVICE2:
-    case CECDEVICE_PLAYBACKDEVICE3:
-      m_busDevices[iPtr] = new CCECPlaybackDevice(this, (cec_logical_address) iPtr);
-      break;
-    case CECDEVICE_RECORDINGDEVICE1:
-    case CECDEVICE_RECORDINGDEVICE2:
-    case CECDEVICE_RECORDINGDEVICE3:
-      m_busDevices[iPtr] = new CCECRecordingDevice(this, (cec_logical_address) iPtr);
-      break;
-    case CECDEVICE_TUNER1:
-    case CECDEVICE_TUNER2:
-    case CECDEVICE_TUNER3:
-    case CECDEVICE_TUNER4:
-      m_busDevices[iPtr] = new CCECTuner(this, (cec_logical_address) iPtr);
-      break;
-    case CECDEVICE_TV:
-      m_busDevices[iPtr] = new CCECTV(this, (cec_logical_address) iPtr);
-      break;
-    default:
-      m_busDevices[iPtr] = new CCECBusDevice(this, (cec_logical_address) iPtr);
-      break;
+      m_libcec->AddLog(CEC_LOG_ERROR, "could not create a processor thread");
+      return false;
     }
   }
-}
 
-CCECProcessor::~CCECProcessor(void)
-{
-  Close();
+  SetCECInitialised(true);
 
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
-  {
-    delete m_busDevices[iPtr];
-    m_busDevices[iPtr] = NULL;
-  }
+  return true;
 }
 
 void CCECProcessor::Close(void)
 {
-  StopThread(false);
-  SetInitialised(false);
+  SetCECInitialised(false);
   StopThread();
 
-  bool bClose(false);
-  {
-    CLockObject lock(m_mutex);
-    bClose = m_bConnectionOpened;
-    m_bConnectionOpened = false;
-  }
-
-  if (bClose && m_communication)
+  if (m_communication)
   {
     delete m_communication;
     m_communication = NULL;
@@ -167,13 +113,13 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint
 
   {
     CLockObject lock(m_mutex);
-    if (m_bConnectionOpened)
+    if (m_communication && m_communication->IsOpen())
     {
-      CLibCEC::AddLog(CEC_LOG_ERROR, "connection already opened");
-      return false;
+      m_libcec->AddLog(CEC_LOG_ERROR, "connection already opened");
+      return true;
     }
-    m_communication = new CUSBCECAdapterCommunication(this, strPort, iBaudRate);
-    m_bConnectionOpened = (m_communication != NULL);
+    else if (!m_communication)
+      m_communication = new CUSBCECAdapterCommunication(this, strPort, iBaudRate);
   }
 
   CTimeout timeout(iTimeoutMs > 0 ? iTimeoutMs : CEC_DEFAULT_TRANSMIT_WAIT);
@@ -182,314 +128,52 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint
   unsigned iConnectTry(0);
   while (timeout.TimeLeft() > 0 && (bReturn = m_communication->Open((timeout.TimeLeft() / CEC_CONNECT_TRIES), false, bStartListening)) == false)
   {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
+    m_libcec->AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
     m_communication->Close();
     CEvent::Sleep(CEC_DEFAULT_CONNECT_RETRY_WAIT);
   }
 
-  if (bReturn)
-  {
-    m_configuration.iFirmwareVersion = m_communication->GetFirmwareVersion();
-    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 != CEC_FW_BUILD_UNKNOWN)
-    {
-      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_communication->IsRunningLatestFirmware())
-  {
-    const char *strUpgradeMessage = "The firmware of this adapter can be upgraded. Please visit http://blog.pulse-eight.com/ for more information.";
-    CLibCEC::AddLog(CEC_LOG_WARNING, strUpgradeMessage);
-    CLibCEC::Alert(CEC_ALERT_SERVICE_DEVICE, libcec_parameter(strUpgradeMessage));
-  }
-  else
-  {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "the adapter is using the latest (known) firmware version");
-  }
-
-  if (m_configuration.bGetSettingsFromROM == 1)
-  {
-    libcec_configuration config;
-    config.Clear();
-    m_communication->GetConfiguration(&config);
-
-    CLockObject lock(m_mutex);
-    if (!config.deviceTypes.IsEmpty())
-      m_configuration.deviceTypes = config.deviceTypes;
-    if (IsValidPhysicalAddress(config.iPhysicalAddress))
-      m_configuration.iPhysicalAddress = config.iPhysicalAddress;
-    snprintf(m_configuration.strDeviceName, 13, "%s", config.strDeviceName);
-  }
+  m_libcec->AddLog(CEC_LOG_NOTICE, "connection opened");
 
   return bReturn;
 }
 
-bool CCECProcessor::IsInitialised(void)
+bool CCECProcessor::CECInitialised(void)
 {
   CLockObject lock(m_threadMutex);
   return m_bInitialised;
 }
 
-void CCECProcessor::SetInitialised(bool bSetTo /* = true */)
+void CCECProcessor::SetCECInitialised(bool bSetTo /* = true */)
 {
   CLockObject lock(m_mutex);
   m_bInitialised = bSetTo;
-}
-
-bool CCECProcessor::Initialise(void)
-{
-  bool bReturn(false);
-  {
-    CLockObject lock(m_mutex);
-    if (!m_configuration.logicalAddresses.IsEmpty())
-      m_configuration.logicalAddresses.Clear();
-
-    if (!FindLogicalAddresses())
-    {
-      CLibCEC::AddLog(CEC_LOG_ERROR, "could not detect our logical addresses");
-      return bReturn;
-    }
-
-    /* only set our OSD name for the primary device */
-    m_busDevices[m_configuration.logicalAddresses.primary]->m_strDeviceName = m_configuration.strDeviceName;
-
-    /* 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 = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; 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 */
-  m_busDevices[CECDEVICE_TV]->GetVendorId();
-
-  if (IsValidPhysicalAddress(m_configuration.iPhysicalAddress))
-  {
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "setting the physical address to %04X", m_configuration.iPhysicalAddress);
-    m_busDevices[m_configuration.logicalAddresses.primary]->m_iPhysicalAddress = m_configuration.iPhysicalAddress;
-    if ((bReturn = m_busDevices[m_configuration.logicalAddresses.primary]->TransmitPhysicalAddress()) == false)
-      CLibCEC::AddLog(CEC_LOG_ERROR, "unable to set the physical address to %04X", m_configuration.iPhysicalAddress);
-  }
-  else
-  {
-    if (!SetHDMIPort(m_configuration.baseDevice, m_configuration.iHDMIPort, true))
-      CLibCEC::AddLog(CEC_LOG_ERROR, "unable to set HDMI port %d on %s (%x)", m_configuration.iHDMIPort, ToString(m_configuration.baseDevice), (uint8_t)m_configuration.baseDevice);
-    bReturn = true;
-  }
-
-  if (bReturn && m_configuration.bActivateSource == 1)
-    m_busDevices[m_configuration.logicalAddresses.primary]->ActivateSource();
-
-  SetInitialised(bReturn);
-  if (bReturn)
-    CLibCEC::ConfigurationChanged(m_configuration);
-
-  return bReturn;
-}
-
-bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
-{
-  bool bReturn(false);
-
-  {
-    CLockObject lock(m_mutex);
-    if (!OpenConnection(strPort, iBaudRate, iTimeoutMs))
-      return bReturn;
-
-    /* create the processor thread */
-    if (!CreateThread())
-    {
-      CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a processor thread");
-      return bReturn;
-    }
-  }
-
-  if ((bReturn = Initialise()) == false)
-  {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a processor thread");
-    StopThread(true);
-  }
-  else
-  {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
-  }
-
-  return bReturn;
+  if (!bSetTo)
+    UnregisterClients();
 }
 
 bool CCECProcessor::TryLogicalAddress(cec_logical_address address)
 {
-  if (m_busDevices[address]->TryLogicalAddress())
-  {
-    m_configuration.logicalAddresses.Set(address);
-    return true;
-  }
-
-  return false;
-}
-
-bool CCECProcessor::FindLogicalAddressRecordingDevice(void)
-{
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
-  return TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1) ||
-      TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2) ||
-      TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3);
-}
-
-bool CCECProcessor::FindLogicalAddressTuner(void)
-{
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
-  return TryLogicalAddress(CECDEVICE_TUNER1) ||
-      TryLogicalAddress(CECDEVICE_TUNER2) ||
-      TryLogicalAddress(CECDEVICE_TUNER3) ||
-      TryLogicalAddress(CECDEVICE_TUNER4);
-}
-
-bool CCECProcessor::FindLogicalAddressPlaybackDevice(void)
-{
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
-  return TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1) ||
-      TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2) ||
-      TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3);
-}
-
-bool CCECProcessor::FindLogicalAddressAudioSystem(void)
-{
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audio'");
-  return TryLogicalAddress(CECDEVICE_AUDIOSYSTEM);
-}
-
-bool CCECProcessor::ChangeDeviceType(cec_device_type from, cec_device_type to)
-{
-  bool bChanged(false);
-
-  CLibCEC::AddLog(CEC_LOG_NOTICE, "changing device type '%s' into '%s'", ToString(from), ToString(to));
-
-  CLockObject lock(m_mutex);
-  CCECBusDevice *previousDevice = GetDeviceByType(from);
-  m_configuration.logicalAddresses.primary = CECDEVICE_UNKNOWN;
-
-  for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
-  {
-    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
-      continue;
-
-    if (m_configuration.deviceTypes.types[iPtr] == from)
-    {
-      bChanged = true;
-      m_configuration.deviceTypes.types[iPtr] = to;
-    }
-    else if (m_configuration.deviceTypes.types[iPtr] == to && bChanged)
-    {
-      m_configuration.deviceTypes.types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
-    }
-  }
-
-  if (bChanged)
-  {
-    FindLogicalAddresses();
-
-    CCECBusDevice *newDevice = GetDeviceByType(to);
-    if (previousDevice && newDevice)
-    {
-      newDevice->SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
-      previousDevice->SetDeviceStatus(CEC_DEVICE_STATUS_NOT_PRESENT);
-
-      newDevice->SetCecVersion(previousDevice->GetCecVersion(false));
-      previousDevice->SetCecVersion(CEC_VERSION_UNKNOWN);
-
-      newDevice->SetMenuLanguage(previousDevice->GetMenuLanguage(false));
-
-      newDevice->SetMenuState(previousDevice->GetMenuState());
-      previousDevice->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
-
-      newDevice->SetOSDName(previousDevice->GetOSDName(false));
-      previousDevice->SetOSDName(ToString(previousDevice->GetLogicalAddress()));
-
-      newDevice->SetPhysicalAddress(previousDevice->GetPhysicalAddress());
-      previousDevice->SetPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
-
-      newDevice->SetPowerStatus(previousDevice->GetPowerStatus(false));
-      previousDevice->SetPowerStatus(CEC_POWER_STATUS_UNKNOWN);
-
-      newDevice->SetVendorId(previousDevice->GetVendorId(false));
-      previousDevice->SetVendorId(CEC_VENDOR_UNKNOWN);
-
-      if ((from == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || from == CEC_DEVICE_TYPE_RECORDING_DEVICE) &&
-          (to == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || to == CEC_DEVICE_TYPE_RECORDING_DEVICE))
-      {
-        ((CCECPlaybackDevice *) newDevice)->SetDeckControlMode(((CCECPlaybackDevice *) previousDevice)->GetDeckControlMode());
-        ((CCECPlaybackDevice *) previousDevice)->SetDeckControlMode(CEC_DECK_CONTROL_MODE_STOP);
-
-        ((CCECPlaybackDevice *) newDevice)->SetDeckStatus(((CCECPlaybackDevice *) previousDevice)->GetDeckStatus());
-        ((CCECPlaybackDevice *) previousDevice)->SetDeckStatus(CEC_DECK_INFO_STOP);
-      }
-    }
-  }
-
-  return true;
-}
-
-bool CCECProcessor::FindLogicalAddresses(void)
-{
-  bool bReturn(true);
-  m_configuration.logicalAddresses.Clear();
-
-  if (m_configuration.deviceTypes.IsEmpty())
+  CCECBusDevice *device = m_busDevices->At(address);
+  if (device)
   {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "no device types set");
-    return false;
-  }
+    if (device->IsPresent() || device->IsHandledByLibCEC())
+      return false;
 
-  for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
-  {
-    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
-      continue;
-
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - device %d: type %d", __FUNCTION__, iPtr, m_configuration.deviceTypes.types[iPtr]);
-
-    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
-      bReturn &= FindLogicalAddressRecordingDevice();
-    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
-      bReturn &= FindLogicalAddressTuner();
-    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
-      bReturn &= FindLogicalAddressPlaybackDevice();
-    if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
-      bReturn &= FindLogicalAddressAudioSystem();
+    SetAckMask(0);
+    return device->TryLogicalAddress();
   }
 
-  if (bReturn)
-    SetAckMask(m_configuration.logicalAddresses.AckMask());
-
-  return bReturn;
+  return false;
 }
 
 void CCECProcessor::ReplaceHandlers(void)
 {
-  if (!IsInitialised())
+  if (!CECInitialised())
     return;
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++)
-    m_busDevices[iPtr]->ReplaceHandler(m_bInitialised);
+
+  for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
+    it->second->ReplaceHandler(true);
 }
 
 bool CCECProcessor::OnCommandReceived(const cec_command &command)
@@ -499,7 +183,7 @@ bool CCECProcessor::OnCommandReceived(const cec_command &command)
 
 void *CCECProcessor::Process(void)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
+  m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started");
 
   cec_command command;
   command.Clear();
@@ -509,456 +193,150 @@ void *CCECProcessor::Process(void)
     if (m_inBuffer.Pop(command, CEC_PROCESSOR_SIGNAL_WAIT_TIME))
       ParseCommand(command);
 
-    if (IsInitialised())
-    {
-      ReplaceHandlers();
-
-      m_controller->CheckKeypressTimeout();
-    }
-  }
-
-  return NULL;
-}
-
-bool CCECProcessor::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
-{
-  bool bReturn(false);
-
-  if (!IsRunning())
-    return bReturn;
-
-  cec_logical_address addr = m_configuration.logicalAddresses.primary;
-
-  if (type != CEC_DEVICE_TYPE_RESERVED)
-  {
-    for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++)
-    {
-      if (m_configuration.logicalAddresses[iPtr] && m_busDevices[iPtr]->m_type == type)
-      {
-        addr = (cec_logical_address) iPtr;
-        break;
-      }
-    }
-  }
-
-  m_busDevices[addr]->SetActiveSource();
-  if (IsValidPhysicalAddress(m_busDevices[addr]->GetPhysicalAddress()))
-    bReturn = m_busDevices[addr]->ActivateSource();
-
-  return bReturn;
-}
-
-bool CCECProcessor::SetActiveSource(uint16_t iStreamPath)
-{
-  bool bReturn(false);
-
-  // suppress polls when searching for a device
-  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;
-}
-
-void CCECProcessor::SetStandardLineTimeout(uint8_t iTimeout)
-{
-  CLockObject lock(m_mutex);
-  m_iStandardLineTimeout = iTimeout;
-}
-
-void CCECProcessor::SetRetryLineTimeout(uint8_t iTimeout)
-{
-  CLockObject lock(m_mutex);
-  m_iRetryLineTimeout = iTimeout;
-}
-
-bool CCECProcessor::SetActiveView(void)
-{
-  CLibCEC::AddLog(CEC_LOG_WARNING, "deprecated method %s called", __FUNCTION__);
-  return SetActiveSource(m_configuration.deviceTypes.IsEmpty() ? CEC_DEVICE_TYPE_RESERVED : m_configuration.deviceTypes[0]);
-}
-
-bool CCECProcessor::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
-{
-  bool bReturn(false);
-
-  CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
-  if (device)
-  {
-    ((CCECPlaybackDevice *) device)->SetDeckControlMode(mode);
-    if (bSendUpdate)
-      ((CCECPlaybackDevice *) device)->TransmitDeckStatus(CECDEVICE_TV);
-    bReturn = true;
-  }
-
-  return bReturn;
-}
-
-bool CCECProcessor::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
-{
-  bool bReturn(false);
-
-  CCECBusDevice *device = GetDeviceByType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
-  if (device)
-  {
-    ((CCECPlaybackDevice *) device)->SetDeckStatus(info);
-    if (bSendUpdate)
-      ((CCECPlaybackDevice *) device)->TransmitDeckStatus(CECDEVICE_TV);
-    bReturn = true;
-  }
-
-  return bReturn;
-}
-
-bool CCECProcessor::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce /* = false */)
-{
-  bool bReturn(false);
-
-  // limit the HDMI port range to 1-15
-  if (iPort < CEC_MIN_HDMI_PORTNUMBER ||
-      iPort > CEC_MAX_HDMI_PORTNUMBER)
-    return bReturn;
-
-  {
-    CLockObject lock(m_mutex);
-    m_configuration.baseDevice = iBaseDevice;
-    m_configuration.iHDMIPort  = iPort;
-  }
-
-  if (!IsRunning() && !bForce)
-    return true;
-
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
-
-  uint16_t iPhysicalAddress(0);
-  if (iBaseDevice > CECDEVICE_TV)
-    iPhysicalAddress = m_busDevices[iBaseDevice]->GetPhysicalAddress(false);
-
-  if (iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS)
-  {
-    if (iPhysicalAddress == 0)
-      iPhysicalAddress += 0x1000 * iPort;
-    else if (iPhysicalAddress % 0x1000 == 0)
-      iPhysicalAddress += 0x100 * iPort;
-    else if (iPhysicalAddress % 0x100 == 0)
-      iPhysicalAddress += 0x10 * iPort;
-    else if (iPhysicalAddress % 0x10 == 0)
-      iPhysicalAddress += iPort;
-
-    bReturn = true;
-  }
-
-  if (!bReturn)
-  {
-    CLibCEC::AddLog(CEC_LOG_WARNING, "failed to set the physical address to %04X, setting it to the default value %04X", iPhysicalAddress, CEC_DEFAULT_PHYSICAL_ADDRESS);
-    iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS;
-  }
-
-  SetPhysicalAddress(iPhysicalAddress);
-
-  return bReturn;
-}
-
-bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress)
-{
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
-  {
-    if (m_busDevices[iPtr]->GetPhysicalAddress() == iPhysicalAddress)
-      return true;
-  }
-  return false;
-}
-
-bool CCECProcessor::TransmitInactiveSource(void)
-{
-  if (!IsRunning())
-    return false;
-
-  if (!m_configuration.logicalAddresses.IsEmpty() && m_busDevices[m_configuration.logicalAddresses.primary])
-    return m_busDevices[m_configuration.logicalAddresses.primary]->TransmitInactiveSource();
-  return false;
-}
-
-void CCECProcessor::LogOutput(const cec_command &data)
-{
-  CStdString strTx;
-  strTx.Format("<< %02x", ((uint8_t)data.initiator << 4) + (uint8_t)data.destination);
-  if (data.opcode_set)
-      strTx.AppendFormat(":%02x", (uint8_t)data.opcode);
-
-  for (uint8_t iPtr = 0; iPtr < data.parameters.size; iPtr++)
-    strTx.AppendFormat(":%02x", data.parameters[iPtr]);
-  CLibCEC::AddLog(CEC_LOG_TRAFFIC, strTx.c_str());
-}
-
-bool CCECProcessor::SetLogicalAddress(cec_logical_address iLogicalAddress)
-{
-  CLockObject lock(m_mutex);
-  if (m_configuration.logicalAddresses.primary != iLogicalAddress)
-  {
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< setting primary logical address to %1x", iLogicalAddress);
-    m_configuration.logicalAddresses.primary = iLogicalAddress;
-    m_configuration.logicalAddresses.Set(iLogicalAddress);
-    return SetAckMask(m_configuration.logicalAddresses.AckMask());
-  }
-
-  return true;
-}
-
-bool CCECProcessor::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
-{
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
-  {
-    if (m_configuration.logicalAddresses[iPtr])
-      m_busDevices[iPtr]->SetMenuState(state);
-  }
-
-  if (bSendUpdate)
-    m_busDevices[m_configuration.logicalAddresses.primary]->TransmitMenuState(CECDEVICE_TV);
-
-  return true;
-}
-
-bool CCECProcessor::SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpdate /* = true */)
-{
-  bool bSendActiveView(false);
-  bool bReturn(false);
-  cec_logical_addresses sendUpdatesTo;
-  sendUpdatesTo.Clear();
-
-  {
-    CLockObject lock(m_mutex);
-    m_configuration.iPhysicalAddress = iPhysicalAddress;
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "setting physical address to '%04X'", iPhysicalAddress);
-
-    if (!m_configuration.logicalAddresses.IsEmpty())
-    {
-      bool bWasActiveSource(false);
-      for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
-        if (m_configuration.logicalAddresses[iPtr])
-        {
-          bWasActiveSource |= m_busDevices[iPtr]->IsActiveSource();
-          m_busDevices[iPtr]->SetInactiveSource();
-          m_busDevices[iPtr]->SetPhysicalAddress(iPhysicalAddress);
-          if (bSendUpdate)
-            sendUpdatesTo.Set((cec_logical_address)iPtr);
-        }
-
-      bSendActiveView = bWasActiveSource && bSendUpdate;
-      bReturn = true;
-    }
-  }
-
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
-    if (sendUpdatesTo[iPtr])
-      m_busDevices[iPtr]->TransmitPhysicalAddress();
-
-  if (bSendActiveView)
-    SetActiveView();
-
-  if (bReturn)
-  {
-    libcec_configuration config;
-    {
-      CLockObject lock(m_mutex);
-      config = m_configuration;
-    }
-
-    PersistConfiguration(&config);
-    CLibCEC::ConfigurationChanged(config);
-  }
-
-  return bReturn;
-}
-
-bool CCECProcessor::SwitchMonitoring(bool bEnable)
-{
-  CLibCEC::AddLog(CEC_LOG_NOTICE, "== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
-
-  {
-    CLockObject lock(m_mutex);
-    m_bMonitor = bEnable;
-  }
-
-  if (bEnable)
-    return SetAckMask(0);
-  else
-    return SetAckMask(m_configuration.logicalAddresses.AckMask());
-}
-
-bool CCECProcessor::PollDevice(cec_logical_address iAddress)
-{
-  if (iAddress != CECDEVICE_UNKNOWN && m_busDevices[iAddress])
-  {
-    return m_configuration.logicalAddresses.primary == CECDEVICE_UNKNOWN ?
-        m_busDevices[iAddress]->TransmitPoll(iAddress) :
-        m_busDevices[m_configuration.logicalAddresses.primary]->TransmitPoll(iAddress);
-  }
-  return false;
-}
-
-uint8_t CCECProcessor::VolumeUp(bool bSendRelease /* = true */)
-{
-  uint8_t status(CEC_AUDIO_VOLUME_STATUS_UNKNOWN);
-  if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
-    status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeUp(bSendRelease);
-
-  return status;
-}
-
-uint8_t CCECProcessor::VolumeDown(bool bSendRelease /* = true */)
-{
-  uint8_t status(CEC_AUDIO_VOLUME_STATUS_UNKNOWN);
-  if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
-    status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->VolumeDown(bSendRelease);
-
-  return status;
-}
-
-uint8_t CCECProcessor::MuteAudio(bool bSendRelease /* = true */)
-{
-  uint8_t status(CEC_AUDIO_VOLUME_STATUS_UNKNOWN);
-  if (IsPresentDevice(CECDEVICE_AUDIOSYSTEM))
-    status = ((CCECAudioSystem *)m_busDevices[CECDEVICE_AUDIOSYSTEM])->MuteAudio(bSendRelease);
-
-  return status;
-}
-
-CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */)
-{
-  CCECBusDevice *device(NULL);
+    if (CECInitialised())
+    {
+      ReplaceHandlers();
 
-  // check each device until we found a match
-  for (uint8_t iPtr = CECDEVICE_TV; !device && iPtr < CECDEVICE_BROADCAST; iPtr++)
-  {
-    if (m_busDevices[iPtr]->GetPhysicalAddress(bSuppressUpdate) == iPhysicalAddress)
-      device = m_busDevices[iPtr];
+      m_libcec->CheckKeypressTimeout();
+    }
   }
 
-  return device;
+  return NULL;
 }
 
-CCECBusDevice *CCECProcessor::GetDeviceByType(cec_device_type type) const
+bool CCECProcessor::SetActiveSource(uint16_t iStreamPath)
 {
-  CCECBusDevice *device = NULL;
+  bool bReturn(false);
 
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
-  {
-    if (m_busDevices[iPtr]->m_type == type && m_configuration.logicalAddresses[iPtr])
-    {
-      device = m_busDevices[iPtr];
-      break;
-    }
-  }
+  CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamPath);
+  if (device)
+    bReturn = device->ActivateSource();
+  else
+    m_libcec->AddLog(CEC_LOG_DEBUG, "device with PA '%04x' not found", iStreamPath);
 
-  return device;
+  return bReturn;
 }
 
-CCECBusDevice *CCECProcessor::GetPrimaryDevice(void) const
+void CCECProcessor::SetStandardLineTimeout(uint8_t iTimeout)
 {
-  CCECBusDevice *device(NULL);
-  cec_logical_address primary = m_configuration.logicalAddresses.primary;
-  if (primary != CECDEVICE_UNKNOWN)
-    device = m_busDevices[primary];
-  return device;
+  CLockObject lock(m_mutex);
+  m_iStandardLineTimeout = iTimeout;
 }
 
-cec_version CCECProcessor::GetDeviceCecVersion(cec_logical_address iAddress)
+void CCECProcessor::SetRetryLineTimeout(uint8_t iTimeout)
 {
-  return m_busDevices[iAddress]->GetCecVersion();
+  CLockObject lock(m_mutex);
+  m_iRetryLineTimeout = iTimeout;
 }
 
-cec_osd_name CCECProcessor::GetDeviceOSDName(cec_logical_address iAddress)
+bool CCECProcessor::PhysicalAddressInUse(uint16_t iPhysicalAddress)
 {
-  CStdString strOSDName = m_busDevices[iAddress]->GetOSDName();
-  cec_osd_name retVal;
+  CCECBusDevice *device = GetDeviceByPhysicalAddress(iPhysicalAddress);
+  return device != NULL;
+}
 
-  snprintf(retVal.name, sizeof(retVal.name), "%s", strOSDName.c_str());
-  retVal.device = iAddress;
+void CCECProcessor::LogOutput(const cec_command &data)
+{
+  CStdString strTx;
+  strTx.Format("<< %02x", ((uint8_t)data.initiator << 4) + (uint8_t)data.destination);
+  if (data.opcode_set)
+      strTx.AppendFormat(":%02x", (uint8_t)data.opcode);
 
-  return retVal;
+  for (uint8_t iPtr = 0; iPtr < data.parameters.size; iPtr++)
+    strTx.AppendFormat(":%02x", data.parameters[iPtr]);
+  m_libcec->AddLog(CEC_LOG_TRAFFIC, strTx.c_str());
 }
 
-bool CCECProcessor::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
+bool CCECProcessor::SwitchMonitoring(bool bEnable)
 {
-  if (m_busDevices[iAddress])
+  m_libcec->AddLog(CEC_LOG_NOTICE, "== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
+
   {
-    *language = m_busDevices[iAddress]->GetMenuLanguage();
-    return (strcmp(language->language, "???") != 0);
+    CLockObject lock(m_mutex);
+    m_bMonitor = bEnable;
+    m_iPreviousAckMask = m_communication->GetAckMask();
   }
-  return false;
-}
 
-CStdString CCECProcessor::GetDeviceName(void) const
-{
-  CStdString strName;
-  strName = m_configuration.strDeviceName;
-  return strName;
+  if (bEnable)
+    return SetAckMask(0);
+  else
+    return SetAckMask(m_iPreviousAckMask);
 }
 
-uint64_t CCECProcessor::GetDeviceVendorId(cec_logical_address iAddress)
+bool CCECProcessor::PollDevice(cec_logical_address iAddress)
 {
-  if (m_busDevices[iAddress])
-    return m_busDevices[iAddress]->GetVendorId();
+  CCECBusDevice *device = m_busDevices->At(iAddress);
+  CCECBusDevice *primary = GetPrimaryDevice();
+  if (device)
+  {
+    return primary ?
+        primary->TransmitPoll(iAddress) :
+        device->TransmitPoll(iAddress);
+  }
   return false;
 }
 
-uint16_t CCECProcessor::GetDevicePhysicalAddress(cec_logical_address iAddress)
+CCECBusDevice *CCECProcessor::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */)
 {
-  if (m_busDevices[iAddress])
-    return m_busDevices[iAddress]->GetPhysicalAddress(false);
-  return false;
+  return m_busDevices ?
+      m_busDevices->GetDeviceByPhysicalAddress(iPhysicalAddress, bSuppressUpdate) :
+      NULL;
 }
 
-cec_power_status CCECProcessor::GetDevicePowerStatus(cec_logical_address iAddress)
+CCECBusDevice *CCECProcessor::GetDevice(cec_logical_address address) const
 {
-  if (m_busDevices[iAddress])
-    return m_busDevices[iAddress]->GetPowerStatus();
-  return CEC_POWER_STATUS_UNKNOWN;
+  return m_busDevices ?
+      m_busDevices->At(address) :
+      NULL;
 }
 
 cec_logical_address CCECProcessor::GetActiveSource(bool bRequestActiveSource /* = true */)
 {
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_PLAYBACKDEVICE3; iPtr++)
-  {
-    if (m_busDevices[iPtr]->IsActiveSource())
-      return (cec_logical_address)iPtr;
-  }
+  // get the device that is marked as active source from the device map
+  CCECBusDevice *activeSource = m_busDevices->GetActiveSource();
+  if (activeSource)
+    return activeSource->GetLogicalAddress();
 
-  if (bRequestActiveSource && m_configuration.logicalAddresses.primary != CECDEVICE_UNKNOWN)
+  if (bRequestActiveSource)
   {
-    CCECBusDevice *primary = m_busDevices[m_configuration.logicalAddresses.primary];
+    // request the active source from the bus
+    CCECBusDevice *primary = GetPrimaryDevice();
     if (primary)
+    {
       primary->RequestActiveSource();
-
-    return GetActiveSource(false);
+      return GetActiveSource(false);
+    }
   }
 
+  // unknown or none
   return CECDEVICE_UNKNOWN;
 }
 
 bool CCECProcessor::IsActiveSource(cec_logical_address iAddress)
 {
-  return iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST ?
-    m_busDevices[iAddress]->IsActiveSource() :
-    false;
+  CCECBusDevice *device = m_busDevices->At(iAddress);
+  return device && device->IsActiveSource();
 }
 
 bool CCECProcessor::Transmit(const cec_command &data)
 {
-  if (m_configuration.logicalAddresses[(uint8_t)data.destination])
+  CCECBusDevice *initiator = m_busDevices->At(data.initiator);
+  if (!initiator)
   {
-    CLibCEC::AddLog(CEC_LOG_WARNING, "not sending data to myself!");
+    m_libcec->AddLog(CEC_LOG_WARNING, "invalid initiator");
     return false;
   }
 
+  if (data.destination != CECDEVICE_BROADCAST)
+  {
+    CCECBusDevice *destination = m_busDevices->At(data.destination);
+    if (destination && destination->IsHandledByLibCEC())
+    {
+      m_libcec->AddLog(CEC_LOG_WARNING, "not sending data to myself!");
+      return false;
+    }
+  }
+
   uint8_t iMaxTries(0);
   {
     CLockObject lock(m_mutex);
@@ -968,10 +346,10 @@ bool CCECProcessor::Transmit(const cec_command &data)
     m_iLastTransmission = GetTimeMs();
     if (!m_communication || !m_communication->IsOpen())
     {
-      CLibCEC::AddLog(CEC_LOG_ERROR, "cannot transmit command: connection closed");
+      m_libcec->AddLog(CEC_LOG_ERROR, "cannot transmit command: connection closed");
       return false;
     }
-    iMaxTries = m_busDevices[data.initiator]->GetHandler()->GetTransmitRetries() + 1;
+    iMaxTries = initiator->GetHandler()->GetTransmitRetries() + 1;
   }
 
   bool bRetry(true);
@@ -981,7 +359,7 @@ bool CCECProcessor::Transmit(const cec_command &data)
 
   while (bRetry && ++iTries < iMaxTries)
   {
-    if (m_busDevices[data.initiator]->IsUnsupportedFeature(data.opcode))
+    if (initiator->IsUnsupportedFeature(data.opcode))
       return false;
 
     adapterState = m_communication->Write(data, bRetry, iLineTimeout);
@@ -991,13 +369,12 @@ bool CCECProcessor::Transmit(const cec_command &data)
   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 */)
+void CCECProcessor::TransmitAbort(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
+  m_libcec->AddLog(CEC_LOG_DEBUG, "<< transmitting abort message");
 
   cec_command command;
-  // TODO
-  cec_command::Format(command, m_configuration.logicalAddresses.primary, address, CEC_OPCODE_FEATURE_ABORT);
+  cec_command::Format(command, source, destination, CEC_OPCODE_FEATURE_ABORT);
   command.parameters.PushBack((uint8_t)opcode);
   command.parameters.PushBack((uint8_t)reason);
 
@@ -1012,45 +389,33 @@ void CCECProcessor::ParseCommand(const cec_command &command)
     dataStr.AppendFormat(":%02x", command.opcode);
   for (uint8_t iPtr = 0; iPtr < command.parameters.size; iPtr++)
     dataStr.AppendFormat(":%02x", (unsigned int)command.parameters[iPtr]);
-  CLibCEC::AddLog(CEC_LOG_TRAFFIC, dataStr.c_str());
-
-  if (!m_bMonitor && command.initiator >= CECDEVICE_TV && command.initiator <= CECDEVICE_BROADCAST)
-    m_busDevices[(uint8_t)command.initiator]->HandleCommand(command);
-}
+  m_libcec->AddLog(CEC_LOG_TRAFFIC, dataStr.c_str());
 
-cec_logical_addresses CCECProcessor::GetActiveDevices(void)
-{
-  cec_logical_addresses addresses;
-  addresses.Clear();
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
+  if (!m_bMonitor)
   {
-    if (m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
-      addresses.Set((cec_logical_address) iPtr);
+    CCECBusDevice *device = m_busDevices->At(command.initiator);
+    if (device)
+      device->HandleCommand(command);
   }
-  return addresses;
 }
 
 bool CCECProcessor::IsPresentDevice(cec_logical_address address)
 {
-  return m_busDevices[address]->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
+  CCECBusDevice *device = m_busDevices->At(address);
+  return device && device->GetStatus() == CEC_DEVICE_STATUS_PRESENT;
 }
 
 bool CCECProcessor::IsPresentDeviceType(cec_device_type type)
 {
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
-  {
-    if (m_busDevices[iPtr]->GetType() == type && m_busDevices[iPtr]->GetStatus() == CEC_DEVICE_STATUS_PRESENT)
-      return true;
-  }
-
-  return false;
+  CECDEVICEVEC devices;
+  m_busDevices->GetByType(type, devices);
+  CCECDeviceMap::FilterActive(devices);
+  return !devices.empty();
 }
 
-uint16_t CCECProcessor::GetPhysicalAddress(void) const
+uint16_t CCECProcessor::GetDetectedPhysicalAddress(void) const
 {
-  if (!m_configuration.logicalAddresses.IsEmpty() && m_busDevices[m_configuration.logicalAddresses.primary])
-    return m_busDevices[m_configuration.logicalAddresses.primary]->GetPhysicalAddress();
-  return false;
+  return m_communication ? m_communication->GetPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
 }
 
 bool CCECProcessor::SetAckMask(uint16_t iMask)
@@ -1058,769 +423,312 @@ bool CCECProcessor::SetAckMask(uint16_t iMask)
   return m_communication ? m_communication->SetAckMask(iMask) : false;
 }
 
-bool CCECProcessor::TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
+bool CCECProcessor::StandbyDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices)
 {
-  return m_busDevices[iDestination]->TransmitKeypress(key, bWait);
+  bool bReturn(true);
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+    bReturn &= (*it)->Standby(initiator);
+  return bReturn;
 }
 
-bool CCECProcessor::TransmitKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
+bool CCECProcessor::StandbyDevice(const cec_logical_address initiator, cec_logical_address address)
 {
-  return m_busDevices[iDestination]->TransmitKeyRelease(bWait);
+  CCECBusDevice *device = m_busDevices->At(address);
+  return device ? device->Standby(initiator) : false;
 }
 
-bool CCECProcessor::EnablePhysicalAddressDetection(void)
+bool CCECProcessor::PowerOnDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices)
 {
-  CLibCEC::AddLog(CEC_LOG_WARNING, "deprecated method %s called", __FUNCTION__);
-  uint16_t iPhysicalAddress = m_communication->GetPhysicalAddress();
-  if (IsValidPhysicalAddress(iPhysicalAddress))
-  {
-    m_configuration.bAutodetectAddress = 1;
-    m_configuration.iPhysicalAddress   = iPhysicalAddress;
-    m_configuration.baseDevice         = CECDEVICE_UNKNOWN;
-    m_configuration.iHDMIPort          = CEC_HDMI_PORTNUMBER_NONE;
-    return SetPhysicalAddress(iPhysicalAddress);
-  }
-  return false;
+  bool bReturn(true);
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+    bReturn &= (*it)->PowerOn(initiator);
+  return bReturn;
 }
 
-bool CCECProcessor::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+bool CCECProcessor::PowerOnDevice(const cec_logical_address initiator, cec_logical_address address)
 {
-  if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
-  {
-    bool bReturn(true);
-    for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; 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;
-  }
-
-  return m_busDevices[address]->Standby();
+  CCECBusDevice *device = m_busDevices->At(address);
+  return device ? device->PowerOn(initiator) : false;
 }
 
-bool CCECProcessor::PowerOnDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */)
 {
-  if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
+  bool bReturn(false);
+  if (!m_communication && strPort)
   {
-    bool bReturn(true);
-    for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
+    IAdapterCommunication *comm = new CUSBCECAdapterCommunication(this, strPort);
+    CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
+    int iConnectTry(0);
+    while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
+    {
+      m_libcec->AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
+      comm->Close();
+      Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
+    }
+    if (comm->IsOpen())
     {
-      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();
-      }
+      bReturn = comm->StartBootloader();
+      delete comm;
     }
     return bReturn;
   }
-
-  return m_busDevices[address]->PowerOn();
-}
-
-const char *CCECProcessor::ToString(const cec_device_type type)
-{
-  switch (type)
+  else
   {
-  case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
-    return "audio system";
-  case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
-    return "playback device";
-  case CEC_DEVICE_TYPE_RECORDING_DEVICE:
-      return "recording device";
-  case CEC_DEVICE_TYPE_RESERVED:
-      return "reserved";
-  case CEC_DEVICE_TYPE_TUNER:
-      return "tuner";
-  case CEC_DEVICE_TYPE_TV:
-      return "TV";
-  default:
-    return "unknown";
+    m_communication->StartBootloader();
+    Close();
+    bReturn = true;
   }
-}
 
-const char *CCECProcessor::ToString(const cec_menu_state state)
-{
-  switch (state)
-  {
-  case CEC_MENU_STATE_ACTIVATED:
-    return "activated";
-  case CEC_MENU_STATE_DEACTIVATED:
-    return "deactivated";
-  default:
-    return "unknown";
-  }
+  return bReturn;
 }
 
-const char *CCECProcessor::ToString(const cec_version version)
+bool CCECProcessor::PingAdapter(void)
 {
-  switch (version)
-  {
-  case CEC_VERSION_1_2:
-    return "1.2";
-  case CEC_VERSION_1_2A:
-    return "1.2a";
-  case CEC_VERSION_1_3:
-    return "1.3";
-  case CEC_VERSION_1_3A:
-    return "1.3a";
-  case CEC_VERSION_1_4:
-    return "1.4";
-  default:
-    return "unknown";
-  }
+  return m_communication->PingAdapter();
 }
 
-const char *CCECProcessor::ToString(const cec_power_status status)
+void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
 {
-  switch (status)
-  {
-  case CEC_POWER_STATUS_ON:
-    return "on";
-  case CEC_POWER_STATUS_STANDBY:
-    return "standby";
-  case CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY:
-    return "in transition from on to standby";
-  case CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON:
-    return "in transition from standby to on";
-  default:
-    return "unknown";
-  }
+  CCECBusDevice *device = m_busDevices->At(destination);
+  if (device)
+    device->HandlePollFrom(initiator);
 }
 
-const char *CCECProcessor::ToString(const cec_logical_address address)
+bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
 {
-  switch(address)
-  {
-  case CECDEVICE_AUDIOSYSTEM:
-    return "Audio";
-  case CECDEVICE_BROADCAST:
-    return "Broadcast";
-  case CECDEVICE_FREEUSE:
-    return "Free use";
-  case CECDEVICE_PLAYBACKDEVICE1:
-    return "Playback 1";
-  case CECDEVICE_PLAYBACKDEVICE2:
-    return "Playback 2";
-  case CECDEVICE_PLAYBACKDEVICE3:
-    return "Playback 3";
-  case CECDEVICE_RECORDINGDEVICE1:
-    return "Recorder 1";
-  case CECDEVICE_RECORDINGDEVICE2:
-    return "Recorder 2";
-  case CECDEVICE_RECORDINGDEVICE3:
-    return "Recorder 3";
-  case CECDEVICE_RESERVED1:
-    return "Reserved 1";
-  case CECDEVICE_RESERVED2:
-    return "Reserved 2";
-  case CECDEVICE_TUNER1:
-    return "Tuner 1";
-  case CECDEVICE_TUNER2:
-    return "Tuner 2";
-  case CECDEVICE_TUNER3:
-    return "Tuner 3";
-  case CECDEVICE_TUNER4:
-    return "Tuner 4";
-  case CECDEVICE_TV:
-    return "TV";
-  default:
-    return "unknown";
-  }
+  CCECBusDevice *device = m_busDevices->At(initiator);
+  return !device || !device->HandleReceiveFailed();
 }
 
-const char *CCECProcessor::ToString(const cec_deck_control_mode mode)
+bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress)
 {
-  switch (mode)
-  {
-  case CEC_DECK_CONTROL_MODE_SKIP_FORWARD_WIND:
-    return "skip forward wind";
-  case CEC_DECK_CONTROL_MODE_EJECT:
-    return "eject";
-  case CEC_DECK_CONTROL_MODE_SKIP_REVERSE_REWIND:
-    return "reverse rewind";
-  case CEC_DECK_CONTROL_MODE_STOP:
-    return "stop";
-  default:
-    return "unknown";
-  }
+  // stream path changes are sent by the TV
+  return GetTV()->GetHandler()->TransmitSetStreamPath(iPhysicalAddress);
 }
 
-const char *CCECProcessor::ToString(const cec_deck_info status)
+bool CCECProcessor::CanPersistConfiguration(void)
 {
-  switch (status)
-  {
-  case CEC_DECK_INFO_PLAY:
-    return "play";
-  case CEC_DECK_INFO_RECORD:
-    return "record";
-  case CEC_DECK_INFO_PLAY_REVERSE:
-    return "play reverse";
-  case CEC_DECK_INFO_STILL:
-    return "still";
-  case CEC_DECK_INFO_SLOW:
-    return "slow";
-  case CEC_DECK_INFO_SLOW_REVERSE:
-    return "slow reverse";
-  case CEC_DECK_INFO_FAST_FORWARD:
-    return "fast forward";
-  case CEC_DECK_INFO_FAST_REVERSE:
-    return "fast reverse";
-  case CEC_DECK_INFO_NO_MEDIA:
-    return "no media";
-  case CEC_DECK_INFO_STOP:
-    return "stop";
-  case CEC_DECK_INFO_SKIP_FORWARD_WIND:
-    return "info skip forward wind";
-  case CEC_DECK_INFO_SKIP_REVERSE_REWIND:
-    return "info skip reverse rewind";
-  case CEC_DECK_INFO_INDEX_SEARCH_FORWARD:
-    return "info index search forward";
-  case CEC_DECK_INFO_INDEX_SEARCH_REVERSE:
-    return "info index search reverse";
-  case CEC_DECK_INFO_OTHER_STATUS:
-    return "other";
-  case CEC_DECK_INFO_OTHER_STATUS_LG:
-    return "LG other";
-  default:
-    return "unknown";
-  }
+  return m_communication ? m_communication->GetFirmwareVersion() >= 2 : false;
 }
 
-const char *CCECProcessor::ToString(const cec_opcode opcode)
+bool CCECProcessor::PersistConfiguration(libcec_configuration *configuration)
 {
-  switch (opcode)
-  {
-  case CEC_OPCODE_ACTIVE_SOURCE:
-    return "active source";
-  case CEC_OPCODE_IMAGE_VIEW_ON:
-    return "image view on";
-  case CEC_OPCODE_TEXT_VIEW_ON:
-    return "text view on";
-  case CEC_OPCODE_INACTIVE_SOURCE:
-    return "inactive source";
-  case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
-    return "request active source";
-  case CEC_OPCODE_ROUTING_CHANGE:
-    return "routing change";
-  case CEC_OPCODE_ROUTING_INFORMATION:
-    return "routing information";
-  case CEC_OPCODE_SET_STREAM_PATH:
-    return "set stream path";
-  case CEC_OPCODE_STANDBY:
-    return "standby";
-  case CEC_OPCODE_RECORD_OFF:
-    return "record off";
-  case CEC_OPCODE_RECORD_ON:
-    return "record on";
-  case CEC_OPCODE_RECORD_STATUS:
-    return "record status";
-  case CEC_OPCODE_RECORD_TV_SCREEN:
-    return "record tv screen";
-  case CEC_OPCODE_CLEAR_ANALOGUE_TIMER:
-    return "clear analogue timer";
-  case CEC_OPCODE_CLEAR_DIGITAL_TIMER:
-    return "clear digital timer";
-  case CEC_OPCODE_CLEAR_EXTERNAL_TIMER:
-    return "clear external timer";
-  case CEC_OPCODE_SET_ANALOGUE_TIMER:
-    return "set analogue timer";
-  case CEC_OPCODE_SET_DIGITAL_TIMER:
-    return "set digital timer";
-  case CEC_OPCODE_SET_EXTERNAL_TIMER:
-    return "set external timer";
-  case CEC_OPCODE_SET_TIMER_PROGRAM_TITLE:
-    return "set timer program title";
-  case CEC_OPCODE_TIMER_CLEARED_STATUS:
-    return "timer cleared status";
-  case CEC_OPCODE_TIMER_STATUS:
-    return "timer status";
-  case CEC_OPCODE_CEC_VERSION:
-    return "cec version";
-  case CEC_OPCODE_GET_CEC_VERSION:
-    return "get cec version";
-  case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
-    return "give physical address";
-  case CEC_OPCODE_GET_MENU_LANGUAGE:
-    return "get menu language";
-  case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
-    return "report physical address";
-  case CEC_OPCODE_SET_MENU_LANGUAGE:
-    return "set menu language";
-  case CEC_OPCODE_DECK_CONTROL:
-    return "deck control";
-  case CEC_OPCODE_DECK_STATUS:
-    return "deck status";
-  case CEC_OPCODE_GIVE_DECK_STATUS:
-    return "give deck status";
-  case CEC_OPCODE_PLAY:
-    return "play";
-  case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS:
-    return "give tuner status";
-  case CEC_OPCODE_SELECT_ANALOGUE_SERVICE:
-    return "select analogue service";
-  case CEC_OPCODE_SELECT_DIGITAL_SERVICE:
-    return "set digital service";
-  case CEC_OPCODE_TUNER_DEVICE_STATUS:
-    return "tuner device status";
-  case CEC_OPCODE_TUNER_STEP_DECREMENT:
-    return "tuner step decrement";
-  case CEC_OPCODE_TUNER_STEP_INCREMENT:
-    return "tuner step increment";
-  case CEC_OPCODE_DEVICE_VENDOR_ID:
-    return "device vendor id";
-  case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
-    return "give device vendor id";
-  case CEC_OPCODE_VENDOR_COMMAND:
-    return "vendor command";
-  case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
-    return "vendor command with id";
-  case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
-    return "vendor remote button down";
-  case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
-    return "vendor remote button up";
-  case CEC_OPCODE_SET_OSD_STRING:
-    return "set osd string";
-  case CEC_OPCODE_GIVE_OSD_NAME:
-    return "give osd name";
-  case CEC_OPCODE_SET_OSD_NAME:
-    return "set osd name";
-  case CEC_OPCODE_MENU_REQUEST:
-    return "menu request";
-  case CEC_OPCODE_MENU_STATUS:
-    return "menu status";
-  case CEC_OPCODE_USER_CONTROL_PRESSED:
-    return "user control pressed";
-  case CEC_OPCODE_USER_CONTROL_RELEASE:
-    return "user control release";
-  case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
-    return "give device power status";
-  case CEC_OPCODE_REPORT_POWER_STATUS:
-    return "report power status";
-  case CEC_OPCODE_FEATURE_ABORT:
-    return "feature abort";
-  case CEC_OPCODE_ABORT:
-    return "abort";
-  case CEC_OPCODE_GIVE_AUDIO_STATUS:
-    return "give audio status";
-  case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
-    return "give audio mode status";
-  case CEC_OPCODE_REPORT_AUDIO_STATUS:
-    return "report audio status";
-  case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
-    return "set system audio mode";
-  case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
-    return "system audio mode request";
-  case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
-    return "system audio mode status";
-  case CEC_OPCODE_SET_AUDIO_RATE:
-    return "set audio rate";
-  case CEC_OPCODE_START_ARC:
-    return "start ARC";
-  case CEC_OPCODE_REPORT_ARC_STARTED:
-    return "report ARC started";
-  case CEC_OPCODE_REPORT_ARC_ENDED:
-    return "report ARC ended";
-  case CEC_OPCODE_REQUEST_ARC_START:
-    return "request ARC start";
-  case CEC_OPCODE_REQUEST_ARC_END:
-    return "request ARC end";
-  case CEC_OPCODE_END_ARC:
-    return "end ARC";
-  case CEC_OPCODE_CDC:
-    return "CDC";
-  case CEC_OPCODE_NONE:
-    return "poll";
-  default:
-    return "UNKNOWN";
-  }
+  return m_communication ? m_communication->PersistConfiguration(configuration) : false;
 }
 
-const char *CCECProcessor::ToString(const cec_system_audio_status mode)
+void CCECProcessor::RescanActiveDevices(void)
 {
-  switch(mode)
-  {
-  case CEC_SYSTEM_AUDIO_STATUS_ON:
-    return "on";
-  case CEC_SYSTEM_AUDIO_STATUS_OFF:
-    return "off";
-  default:
-    return "unknown";
-  }
+  for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
+    it->second->GetStatus(true);
 }
 
-const char *CCECProcessor::ToString(const cec_audio_status UNUSED(status))
+bool CCECProcessor::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
 {
-  // TODO this is a mask
-  return "TODO";
-}
+  if (!OpenConnection(strPort, CEC_SERIAL_DEFAULT_BAUDRATE, iTimeoutMs, false))
+    return false;
 
-const char *CCECProcessor::ToString(const cec_vendor_id vendor)
-{
-  switch (vendor)
-  {
-  case CEC_VENDOR_SAMSUNG:
-    return "Samsung";
-  case CEC_VENDOR_LG:
-    return "LG";
-  case CEC_VENDOR_PANASONIC:
-    return "Panasonic";
-  case CEC_VENDOR_PIONEER:
-    return "Pioneer";
-  case CEC_VENDOR_ONKYO:
-    return "Onkyo";
-  case CEC_VENDOR_YAMAHA:
-    return "Yamaha";
-  case CEC_VENDOR_PHILIPS:
-    return "Philips";
-  case CEC_VENDOR_SONY:
-    return "Sony";
-  case CEC_VENDOR_TOSHIBA:
-    return "Toshiba";
-  default:
-    return "Unknown";
-  }
-}
+  config->iFirmwareVersion   = m_communication->GetFirmwareVersion();
+  config->iPhysicalAddress   = m_communication->GetPhysicalAddress();
+  config->iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
 
-const char *CCECProcessor::ToString(const cec_client_version version)
-{
-  switch (version)
-  {
-  case CEC_CLIENT_VERSION_PRE_1_5:
-    return "pre-1.5";
-  case CEC_CLIENT_VERSION_1_5_0:
-    return "1.5.0";
-  case CEC_CLIENT_VERSION_1_5_1:
-    return "1.5.1";
-  case CEC_CLIENT_VERSION_1_5_2:
-    return "1.5.2";
-  case CEC_CLIENT_VERSION_1_5_3:
-    return "1.5.3";
-  case CEC_CLIENT_VERSION_1_6_0:
-    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";
-  }
+  return true;
 }
 
-const char *CCECProcessor::ToString(const cec_server_version version)
+bool CCECProcessor::TransmitPendingActiveSourceCommands(void)
 {
-  switch (version)
-  {
-  case CEC_SERVER_VERSION_PRE_1_5:
-    return "pre-1.5";
-  case CEC_SERVER_VERSION_1_5_0:
-    return "1.5.0";
-  case CEC_SERVER_VERSION_1_5_1:
-    return "1.5.1";
-  case CEC_SERVER_VERSION_1_5_2:
-    return "1.5.2";
-  case CEC_SERVER_VERSION_1_5_3:
-    return "1.5.3";
-  case CEC_SERVER_VERSION_1_6_0:
-    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";
-  }
+  bool bReturn(true);
+  for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
+    bReturn &= it->second->TransmitPendingActiveSourceCommands();
+  return bReturn;
 }
 
-bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */)
+CCECTV *CCECProcessor::GetTV(void) const
 {
-  bool bReturn(false);
-  if (!m_communication && strPort)
-  {
-    IAdapterCommunication *comm = new CUSBCECAdapterCommunication(this, strPort);
-    CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
-    int iConnectTry(0);
-    while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
-    {
-      CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry);
-      comm->Close();
-      Sleep(CEC_DEFAULT_TRANSMIT_RETRY_WAIT);
-    }
-    if (comm->IsOpen())
-    {
-      bReturn = comm->StartBootloader();
-      delete comm;
-    }
-    return bReturn;
-  }
-  else
-  {
-    m_communication->StartBootloader();
-    Close();
-    bReturn = true;
-  }
-
-  return bReturn;
+  return CCECBusDevice::AsTV(m_busDevices->At(CECDEVICE_TV));
 }
 
-bool CCECProcessor::PingAdapter(void)
+CCECAudioSystem *CCECProcessor::GetAudioSystem(void) const
 {
-  return m_communication->PingAdapter();
+  return CCECBusDevice::AsAudioSystem(m_busDevices->At(CECDEVICE_AUDIOSYSTEM));
 }
 
-void CCECProcessor::HandlePoll(cec_logical_address initiator, cec_logical_address destination)
+CCECPlaybackDevice *CCECProcessor::GetPlaybackDevice(cec_logical_address address) const
 {
-  if (destination < CECDEVICE_BROADCAST)
-    m_busDevices[destination]->HandlePollFrom(initiator);
+  return CCECBusDevice::AsPlaybackDevice(m_busDevices->At(address));
 }
 
-bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
+CCECRecordingDevice *CCECProcessor::GetRecordingDevice(cec_logical_address address) const
 {
-  return !m_busDevices[initiator]->HandleReceiveFailed();
+  return CCECBusDevice::AsRecordingDevice(m_busDevices->At(address));
 }
 
-bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress)
+CCECTuner *CCECProcessor::GetTuner(cec_logical_address address) const
 {
-  // stream path changes are sent by the TV
-  return m_busDevices[CECDEVICE_TV]->GetHandler()->TransmitSetStreamPath(iPhysicalAddress);
+  return CCECBusDevice::AsTuner(m_busDevices->At(address));
 }
 
-bool CCECProcessor::SetConfiguration(const libcec_configuration *configuration)
+bool CCECProcessor::RegisterClient(CCECClient *client)
 {
-  bool bReinit(false);
-  CCECBusDevice *primary = IsRunning() ? GetPrimaryDevice() : NULL;
-  cec_device_type oldPrimaryType = primary ? primary->GetType() : CEC_DEVICE_TYPE_RECORDING_DEVICE;
-  m_configuration.clientVersion  = configuration->clientVersion;
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using client version '%s'", __FUNCTION__, ToString((cec_client_version)configuration->clientVersion));
+  if (!client)
+    return false;
 
-  // client version 1.5.0
+  libcec_configuration &configuration = *client->GetConfiguration();
+  m_libcec->AddLog(CEC_LOG_NOTICE, "registering new CEC client - v%s", ToString((cec_client_version)configuration.clientVersion));
 
-  // device types
-  bool bDeviceTypeChanged = IsRunning () && m_configuration.deviceTypes != configuration->deviceTypes;
-  m_configuration.deviceTypes = configuration->deviceTypes;
-  if (bDeviceTypeChanged)
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using primary device type '%s'", __FUNCTION__, ToString(configuration->deviceTypes[0]));
+  client->SetRegistered(false);
+  client->SetInitialised(false);
 
-  bool bPhysicalAddressChanged(false);
+  uint16_t iPreviousMask(m_communication->GetAckMask());
 
-  // autodetect address
-  bool bPhysicalAutodetected(false);
-  if (IsRunning() && configuration->bAutodetectAddress == 1)
+  // find logical addresses for this client
+  if (!client->FindLogicalAddresses())
   {
-    uint16_t iPhysicalAddress = m_communication->GetPhysicalAddress();
-    if (IsValidPhysicalAddress(iPhysicalAddress))
-    {
-      if (IsRunning())
-        CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - autodetected physical address '%04X'", __FUNCTION__, iPhysicalAddress);
-      else
-        CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using physical address '%04X'", __FUNCTION__, iPhysicalAddress);
-      bPhysicalAddressChanged = (m_configuration.iPhysicalAddress != iPhysicalAddress);
-      m_configuration.iPhysicalAddress = iPhysicalAddress;
-      m_configuration.iHDMIPort        = CEC_HDMI_PORTNUMBER_NONE;
-      m_configuration.baseDevice       = CECDEVICE_UNKNOWN;
-      bPhysicalAutodetected            = true;
-    }
+    SetAckMask(iPreviousMask);
+    return false;
   }
 
-  // physical address
-  if (!bPhysicalAutodetected)
+  // register this client on the new addresses
+  CECDEVICEVEC devices;
+  m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
   {
-    uint16_t iPhysicalAddress(IsValidPhysicalAddress(configuration->iPhysicalAddress) ? configuration->iPhysicalAddress : CEC_PHYSICAL_ADDRESS_TV);
-    bPhysicalAddressChanged = IsRunning() && m_configuration.iPhysicalAddress != iPhysicalAddress;
-    if (bPhysicalAddressChanged)
-    {
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - physical address '%04X'", __FUNCTION__, iPhysicalAddress);
-      m_configuration.iPhysicalAddress = iPhysicalAddress;
-    }
+    CLockObject lock(m_mutex);
+    m_clients.erase((*it)->GetLogicalAddress());
+    m_clients.insert(make_pair<cec_logical_address, CCECClient *>((*it)->GetLogicalAddress(), client));
+    client->SetRegistered(true);
   }
 
-  bool bHdmiPortChanged(false);
-  if (!bPhysicalAutodetected && !IsValidPhysicalAddress(configuration->iPhysicalAddress))
-  {
-    // base device
-    bHdmiPortChanged = IsRunning() && m_configuration.baseDevice != configuration->baseDevice;
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using base device '%x'", __FUNCTION__, (int)configuration->baseDevice);
-    m_configuration.baseDevice = configuration->baseDevice;
-
-    // hdmi port
-    bHdmiPortChanged |= IsRunning() && m_configuration.iHDMIPort != configuration->iHDMIPort;
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using HDMI port '%d'", __FUNCTION__, configuration->iHDMIPort);
-    m_configuration.iHDMIPort = configuration->iHDMIPort;
-  }
-  else
+  // get the settings from the rom
+  if (configuration.bGetSettingsFromROM == 1)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - resetting HDMI port and base device to defaults", __FUNCTION__);
-    m_configuration.baseDevice = CECDEVICE_UNKNOWN;
-    m_configuration.iHDMIPort  = CEC_HDMI_PORTNUMBER_NONE;
-  }
-
-  bReinit = bPhysicalAddressChanged || bHdmiPortChanged || bDeviceTypeChanged;
+    libcec_configuration config;
+    m_communication->GetConfiguration(&config);
 
-  // device name
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - using OSD name '%s'", __FUNCTION__, configuration->strDeviceName);
-  snprintf(m_configuration.strDeviceName, 13, "%s", configuration->strDeviceName);
-  if (primary && !primary->GetOSDName().Equals(m_configuration.strDeviceName))
-  {
-    primary->SetOSDName(m_configuration.strDeviceName);
-    if (!bReinit && IsRunning())
-      primary->TransmitOSDName(CECDEVICE_TV);
+    CLockObject lock(m_mutex);
+    if (!config.deviceTypes.IsEmpty())
+      configuration.deviceTypes = config.deviceTypes;
+    if (CLibCEC::IsValidPhysicalAddress(config.iPhysicalAddress))
+      configuration.iPhysicalAddress = config.iPhysicalAddress;
+    snprintf(configuration.strDeviceName, 13, "%s", config.strDeviceName);
   }
 
-  // tv vendor id override
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - vendor id '%s'", __FUNCTION__, ToString((cec_vendor_id)configuration->tvVendor));
-  if (m_configuration.tvVendor != configuration->tvVendor)
-  {
-    m_configuration.tvVendor= configuration->tvVendor;
-    m_busDevices[CECDEVICE_TV]->SetVendorId((uint64_t)m_configuration.tvVendor);
-  }
+  // set the new ack mask
+  bool bReturn = SetAckMask(GetLogicalAddresses().AckMask()) &&
+      client->Initialise();
 
-  // wake CEC devices
-  if (m_configuration.wakeDevices != configuration->wakeDevices)
+  // set the firmware version and build date
+  configuration.iFirmwareVersion = m_communication->GetFirmwareVersion();
+  configuration.iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
+
+  CStdString strLog;
+  if (bReturn)
+    strLog = "CEC client registered.";
+  else
+    strLog = "failed to register the CEC client.";
+  strLog.AppendFormat(" libCEC version = %s, client version = %s, firmware version = %d", ToString((cec_server_version)configuration.serverVersion), ToString((cec_client_version)configuration.clientVersion), configuration.iFirmwareVersion);
+  if (configuration.iFirmwareBuildDate != CEC_FW_BUILD_UNKNOWN)
   {
-    m_configuration.wakeDevices = configuration->wakeDevices;
-    if (!bReinit && IsRunning())
-      PowerOnDevices();
+    time_t buildTime = (time_t)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");
   }
 
-  // just copy these
-  m_configuration.bUseTVMenuLanguage   = configuration->bUseTVMenuLanguage;
-  m_configuration.bActivateSource      = configuration->bActivateSource;
-  m_configuration.bGetSettingsFromROM  = configuration->bGetSettingsFromROM;
-  m_configuration.powerOffDevices      = configuration->powerOffDevices;
-  m_configuration.bPowerOffScreensaver = configuration->bPowerOffScreensaver;
-  m_configuration.bPowerOffOnStandby   = configuration->bPowerOffOnStandby;
-
-  // client version 1.5.1
-  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_5_1)
-    m_configuration.bSendInactiveSource = configuration->bSendInactiveSource;
+  m_libcec->AddLog(bReturn ? CEC_LOG_NOTICE : CEC_LOG_ERROR, strLog);
 
-  // client version 1.6.0
-  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_0)
+  if (bReturn)
   {
-    m_configuration.bPowerOffDevicesOnStandby = configuration->bPowerOffDevicesOnStandby;
-    m_configuration.bShutdownOnStandby        = configuration->bShutdownOnStandby;
+    strLog = "Using logical address(es): ";
+    CECDEVICEVEC devices;
+    m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
+    for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+      strLog.AppendFormat("%s (%X) ", (*it)->GetLogicalAddressName(), (*it)->GetLogicalAddress());
+    m_libcec->AddLog(CEC_LOG_NOTICE, strLog);
   }
 
-  // client version 1.6.2
-  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_2)
+  // display a warning if the firmware can be upgraded
+  if (!m_communication->IsRunningLatestFirmware())
   {
-    memcpy(m_configuration.strDeviceLanguage, configuration->strDeviceLanguage, 3);
+    const char *strUpgradeMessage = "The firmware of this adapter can be upgraded. Please visit http://blog.pulse-eight.com/ for more information.";
+    m_libcec->AddLog(CEC_LOG_WARNING, strUpgradeMessage);
+    client->Alert(CEC_ALERT_SERVICE_DEVICE, libcec_parameter(strUpgradeMessage));
   }
-
-  // ensure that there is at least 1 device type set
-  if (m_configuration.deviceTypes.IsEmpty())
-    m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
-
-  bool bReturn(true);
-  if (bReinit || m_configuration.logicalAddresses.IsEmpty())
+  else
   {
-    if (bDeviceTypeChanged)
-      bReturn = ChangeDeviceType(oldPrimaryType, m_configuration.deviceTypes[0]);
-    else if (IsValidPhysicalAddress(m_configuration.iPhysicalAddress))
-      bReturn = SetPhysicalAddress(m_configuration.iPhysicalAddress);
-    else if (m_configuration.baseDevice != CECDEVICE_UNKNOWN && m_configuration.iHDMIPort != CEC_HDMI_PORTNUMBER_NONE)
-      bReturn = SetHDMIPort(m_configuration.baseDevice, m_configuration.iHDMIPort);
+    m_libcec->AddLog(CEC_LOG_DEBUG, "the adapter is using the latest (known) firmware version");
   }
-  else if (m_configuration.bActivateSource == 1 && IsRunning() && !IsActiveSource(m_configuration.logicalAddresses.primary))
+
+  if (bReturn)
   {
-    // activate the source if we're not already the active source
-    SetActiveSource(m_configuration.deviceTypes.types[0]);
+    /* get the vendor id from the TV, so we are using the correct handler */
+    GetTV()->GetVendorId(configuration.logicalAddresses.primary);
   }
 
-  // persist the configuration
-  if (IsRunning())
-    m_communication->PersistConfiguration(&m_configuration);
-
   return bReturn;
 }
 
-bool CCECProcessor::GetCurrentConfiguration(libcec_configuration *configuration)
+void CCECProcessor::UnregisterClient(CCECClient *client)
 {
-  // client version 1.5.0
-  snprintf(configuration->strDeviceName, 13, "%s", m_configuration.strDeviceName);
-  configuration->deviceTypes          = m_configuration.deviceTypes;
-  configuration->bAutodetectAddress   = m_configuration.bAutodetectAddress;
-  configuration->iPhysicalAddress     = m_configuration.iPhysicalAddress;
-  configuration->baseDevice           = m_configuration.baseDevice;
-  configuration->iHDMIPort            = m_configuration.iHDMIPort;
-  configuration->clientVersion        = m_configuration.clientVersion;
-  configuration->serverVersion        = m_configuration.serverVersion;
-  configuration->tvVendor             = m_configuration.tvVendor;
-
-  configuration->bGetSettingsFromROM  = m_configuration.bGetSettingsFromROM;
-  configuration->bUseTVMenuLanguage   = m_configuration.bUseTVMenuLanguage;
-  configuration->bActivateSource      = m_configuration.bActivateSource;
-  configuration->wakeDevices          = m_configuration.wakeDevices;
-  configuration->powerOffDevices      = m_configuration.powerOffDevices;
-  configuration->bPowerOffScreensaver = m_configuration.bPowerOffScreensaver;
-  configuration->bPowerOffOnStandby   = m_configuration.bPowerOffOnStandby;
-
-  // client version 1.5.1
-  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_5_1)
-    configuration->bSendInactiveSource = m_configuration.bSendInactiveSource;
-
-  // client version 1.5.3
-  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_5_3)
-    configuration->logicalAddresses    = m_configuration.logicalAddresses;
-
-  // client version 1.6.0
-  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_0)
-  {
-    configuration->iFirmwareVersion          = m_configuration.iFirmwareVersion;
-    configuration->bPowerOffDevicesOnStandby = m_configuration.bPowerOffDevicesOnStandby;
-    configuration->bShutdownOnStandby        = m_configuration.bShutdownOnStandby;
-  }
-
-  // client version 1.6.2
-  if (configuration->clientVersion >= CEC_CLIENT_VERSION_1_6_2)
+  CLockObject lock(m_mutex);
+  libcec_configuration &configuration = *client->GetConfiguration();
+  CECDEVICEVEC devices;
+  m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
   {
-    memcpy(configuration->strDeviceLanguage, m_configuration.strDeviceLanguage, 3);
-    configuration->iFirmwareBuildDate      = m_configuration.iFirmwareBuildDate;
+    map<cec_logical_address, CCECClient *>::iterator entry = m_clients.find((*it)->GetLogicalAddress());
+    if (entry != m_clients.end())
+      m_clients.erase(entry);
   }
-  return true;
 }
 
-bool CCECProcessor::CanPersistConfiguration(void)
+void CCECProcessor::UnregisterClients(void)
 {
-  return m_communication ? m_communication->GetFirmwareVersion() >= 2 : false;
+  CLockObject lock(m_mutex);
+  for (map<cec_logical_address, CCECClient *>::iterator client = m_clients.begin(); client != m_clients.end(); client++)
+    client->second->OnUnregister();
+  m_clients.clear();
 }
 
-bool CCECProcessor::PersistConfiguration(libcec_configuration *configuration)
+CCECClient *CCECProcessor::GetClient(const cec_logical_address address)
 {
-  return m_communication ? m_communication->PersistConfiguration(configuration) : false;
+  CLockObject lock(m_mutex);
+  map<cec_logical_address, CCECClient *>::const_iterator client = m_clients.find(address);
+  if (client != m_clients.end())
+    return client->second;
+  return NULL;
 }
 
-void CCECProcessor::RescanActiveDevices(void)
+CCECClient *CCECProcessor::GetPrimaryClient(void)
 {
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
-    m_busDevices[iPtr]->GetStatus(true);
+  CLockObject lock(m_mutex);
+  map<cec_logical_address, CCECClient *>::const_iterator client = m_clients.begin();
+  if (client != m_clients.end())
+    return client->second;
+  return NULL;
 }
 
-bool CCECProcessor::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
+CCECBusDevice *CCECProcessor::GetPrimaryDevice(void) const
 {
-  if (!OpenConnection(strPort, CEC_SERIAL_DEFAULT_BAUDRATE, iTimeoutMs, false))
-    return false;
-
-  config->iFirmwareVersion   = m_communication->GetFirmwareVersion();
-  config->iPhysicalAddress   = m_communication->GetPhysicalAddress();
-  config->iFirmwareBuildDate = m_communication->GetFirmwareBuildDate();
+  return m_busDevices->At(GetLogicalAddress());
+}
 
-  return true;
+cec_logical_address CCECProcessor::GetLogicalAddress(void) const
+{
+  cec_logical_addresses addresses = GetLogicalAddresses();
+  return addresses.primary;
 }
 
-bool CCECProcessor::TransmitPendingActiveSourceCommands(void)
+cec_logical_addresses CCECProcessor::GetLogicalAddresses(void) const
 {
-  bool bReturn(true);
-  for (uint8_t iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
-    bReturn &= m_busDevices[iPtr]->TransmitPendingActiveSourceCommands();
-  return bReturn;
+  cec_logical_addresses addresses;
+  for (map<cec_logical_address, CCECClient *>::const_iterator client = m_clients.begin(); client != m_clients.end(); client++)
+    addresses.Set(client->first);
+
+  return addresses;
 }
 
-bool CCECProcessor::IsValidPhysicalAddress(uint16_t iPhysicalAddress)
+bool CCECProcessor::IsHandledByLibCEC(const cec_logical_address address) const
 {
-  return iPhysicalAddress >= CEC_MIN_PHYSICAL_ADDRESS &&
-         iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS;
+  CCECBusDevice *device = GetDevice(address);
+  return device && device->IsHandledByLibCEC();
 }
index 3986862fe719f3f2730c56bd5cb1840cd700d4af..48154fe9842de770fe692dbe73789bf313e7f970 100644 (file)
 
 #include <string>
 #include "../../include/cectypes.h"
+
 #include "platform/threads/threads.h"
 #include "platform/util/buffer.h"
+
 #include "adapter/AdapterCommunication.h"
+#include "devices/CECDeviceMap.h"
+#include "CECInputBuffer.h"
 
 namespace CEC
 {
   class CLibCEC;
   class IAdapterCommunication;
   class CCECBusDevice;
-
-  // a buffer that priotises the input from the TV.
-  // if we need more than this, we'll have to change it into a priority_queue
-  class CCECInputBuffer
-  {
-  public:
-    CCECInputBuffer(void) : m_bHasData(false) {}
-    virtual ~CCECInputBuffer(void)
-    {
-      m_condition.Broadcast();
-    }
-
-    bool Push(const cec_command &command)
-    {
-      bool bReturn(false);
-      PLATFORM::CLockObject lock(m_mutex);
-      if (command.initiator == CECDEVICE_TV)
-        bReturn = m_tvInBuffer.Push(command);
-      else
-        bReturn = m_inBuffer.Push(command);
-
-      m_bHasData |= bReturn;
-      if (m_bHasData)
-        m_condition.Signal();
-
-      return bReturn;
-    }
-
-    bool Pop(cec_command &command, uint16_t iTimeout)
-    {
-      bool bReturn(false);
-      PLATFORM::CLockObject lock(m_mutex);
-      if (m_tvInBuffer.IsEmpty() && m_inBuffer.IsEmpty() &&
-          !m_condition.Wait(m_mutex, m_bHasData, iTimeout))
-        return bReturn;
-
-      if (m_tvInBuffer.Pop(command))
-        bReturn = true;
-      else if (m_inBuffer.Pop(command))
-        bReturn = true;
-
-      m_bHasData = !m_tvInBuffer.IsEmpty() || !m_inBuffer.IsEmpty();
-      return bReturn;
-    }
-
-  private:
-    PLATFORM::CMutex                    m_mutex;
-    PLATFORM::CCondition<volatile bool> m_condition;
-    volatile bool                       m_bHasData;
-    PLATFORM::SyncedBuffer<cec_command> m_tvInBuffer;
-    PLATFORM::SyncedBuffer<cec_command> m_inBuffer;
-  };
+  class CCECAudioSystem;
+  class CCECPlaybackDevice;
+  class CCECRecordingDevice;
+  class CCECTuner;
+  class CCECTV;
+  class CCECClient;
 
   class CCECProcessor : public PLATFORM::CThread, public IAdapterCommunicationCallback
   {
     public:
-      CCECProcessor(CLibCEC *controller, const char *strDeviceName, const cec_device_type_list &types, uint16_t iPhysicalAddress);
-      CCECProcessor(CLibCEC *controller, libcec_configuration *configuration);
+      CCECProcessor(CLibCEC *libcec);
       virtual ~CCECProcessor(void);
 
       bool Start(const char *strPort, uint16_t iBaudRate = CEC_SERIAL_DEFAULT_BAUDRATE, uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT);
       void *Process(void);
       void Close(void);
 
+      bool RegisterClient(CCECClient *client);
+      void UnregisterClient(CCECClient *client);
+      void UnregisterClients(void);
+      CCECClient *GetPrimaryClient(void);
+      CCECClient *GetClient(const cec_logical_address address);
+
       bool                  OnCommandReceived(const cec_command &command);
 
       bool                  IsMonitoring(void) const { return m_bMonitor; }
+      CCECBusDevice *       GetDevice(cec_logical_address address) const;
+      CCECAudioSystem *     GetAudioSystem(void) const;
+      CCECPlaybackDevice *  GetPlaybackDevice(cec_logical_address address) const;
+      CCECRecordingDevice * GetRecordingDevice(cec_logical_address address) const;
+      CCECTuner *           GetTuner(cec_logical_address address) const;
+      CCECTV *              GetTV(void) const;
+
       CCECBusDevice *       GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate = true);
-      CCECBusDevice *       GetDeviceByType(cec_device_type type) const;
       CCECBusDevice *       GetPrimaryDevice(void) const;
-      cec_version           GetDeviceCecVersion(cec_logical_address iAddress);
-      bool                  GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language);
-      CStdString            GetDeviceName(void) const;
-      cec_osd_name          GetDeviceOSDName(cec_logical_address iAddress);
-      uint64_t              GetDeviceVendorId(cec_logical_address iAddress);
-      cec_power_status      GetDevicePowerStatus(cec_logical_address iAddress);
-      cec_logical_address   GetLogicalAddress(void) const { return m_configuration.logicalAddresses.primary; }
-      cec_logical_addresses GetLogicalAddresses(void) const { return m_configuration.logicalAddresses; }
-      cec_logical_addresses GetActiveDevices(void);
-      uint16_t              GetDevicePhysicalAddress(cec_logical_address iAddress);
-      bool                  HasLogicalAddress(cec_logical_address address) const { return m_configuration.logicalAddresses.IsSet(address); }
+      cec_logical_address   GetLogicalAddress(void) const;
+      cec_logical_addresses GetLogicalAddresses(void) const;
       bool                  IsPresentDevice(cec_logical_address address);
       bool                  IsPresentDeviceType(cec_device_type type);
-      uint16_t              GetPhysicalAddress(void) const;
+      uint16_t              GetDetectedPhysicalAddress(void) const;
       uint64_t              GetLastTransmission(void) const { return m_iLastTransmission; }
       cec_logical_address   GetActiveSource(bool bRequestActiveSource = true);
       bool                  IsActiveSource(cec_logical_address iAddress);
-      bool                  IsInitialised(void);
+      bool                  CECInitialised(void);
       bool                  SetStreamPath(uint16_t iPhysicalAddress);
-      cec_client_version    GetClientVersion(void) const { return (cec_client_version)m_configuration.clientVersion; };
-      bool                  StandbyDevices(cec_logical_address address = CECDEVICE_BROADCAST);
-      bool                  PowerOnDevices(cec_logical_address address = CECDEVICE_BROADCAST);
 
-      bool SetActiveView(void);
-      bool SetActiveSource(cec_device_type type = CEC_DEVICE_TYPE_RESERVED);
-      bool SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate = true);
+      bool                  StandbyDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices);
+      bool                  StandbyDevice(const cec_logical_address initiator, cec_logical_address address);
+      bool                  PowerOnDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices);
+      bool                  PowerOnDevice(const cec_logical_address initiator, cec_logical_address address);
+
       bool SetDeckInfo(cec_deck_info info, bool bSendUpdate = true);
-      bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort, bool bForce = false);
-      bool TransmitInactiveSource(void);
-      bool SetLogicalAddress(cec_logical_address iLogicalAddress);
-      bool SetMenuState(cec_menu_state state, bool bSendUpdate = true);
-      bool SetPhysicalAddress(uint16_t iPhysicalAddress, bool bSendUpdate = true);
       bool SetActiveSource(uint16_t iStreamPath);
       bool SwitchMonitoring(bool bEnable);
       bool PollDevice(cec_logical_address iAddress);
-      uint8_t VolumeUp(bool bSendRelease = true);
-      uint8_t VolumeDown(bool bSendRelease = true);
-      uint8_t MuteAudio(bool bSendRelease = true);
-      bool TransmitKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = true);
-      bool TransmitKeyRelease(cec_logical_address iDestination, bool bWait = true);
-      bool EnablePhysicalAddressDetection(void);
       void SetStandardLineTimeout(uint8_t iTimeout);
       void SetRetryLineTimeout(uint8_t iTimeout);
-      bool GetCurrentConfiguration(libcec_configuration *configuration);
-      bool SetConfiguration(const libcec_configuration *configuration);
       bool CanPersistConfiguration(void);
       bool PersistConfiguration(libcec_configuration *configuration);
       void RescanActiveDevices(void);
 
       bool SetLineTimeout(uint8_t iTimeout);
 
-      const char *ToString(const cec_device_type type);
-      const char *ToString(const cec_menu_state state);
-      const char *ToString(const cec_version version);
-      const char *ToString(const cec_power_status status);
-      const char *ToString(const cec_logical_address address);
-      const char *ToString(const cec_deck_control_mode mode);
-      const char *ToString(const cec_deck_info status);
-      const char *ToString(const cec_opcode opcode);
-      const char *ToString(const cec_system_audio_status mode);
-      const char *ToString(const cec_audio_status status);
-      const char *ToString(const cec_vendor_id vendor);
-      const char *ToString(const cec_client_version version);
-      const char *ToString(const cec_server_version version);
-
-      static bool IsValidPhysicalAddress(uint16_t iPhysicalAddress);
-
       bool Transmit(const cec_command &data);
-      void TransmitAbort(cec_logical_address address, cec_opcode opcode, cec_abort_reason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
-
-      bool ChangeDeviceType(cec_device_type from, cec_device_type to);
-      bool FindLogicalAddresses(void);
-      bool SetAckMask(uint16_t iMask);
+      void TransmitAbort(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_abort_reason reason = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
 
       bool StartBootloader(const char *strPort = NULL);
       bool PingAdapter(void);
@@ -195,37 +121,34 @@ namespace CEC
 
       bool TransmitPendingActiveSourceCommands(void);
 
-      CCECBusDevice *  m_busDevices[16];
+      CCECDeviceMap *GetDevices(void) const { return m_busDevices; }
+      CLibCEC *GetLib(void) const { return m_libcec; }
 
+      bool IsHandledByLibCEC(const cec_logical_address address) const;
+
+      bool TryLogicalAddress(cec_logical_address address);
   private:
       bool OpenConnection(const char *strPort, uint16_t iBaudRate, uint32_t iTimeoutMs, bool bStartListening = true);
-      bool Initialise(void);
-      void SetInitialised(bool bSetTo = true);
-      void CreateBusDevices(void);
+      void SetCECInitialised(bool bSetTo = true);
 
       void ReplaceHandlers(void);
       bool PhysicalAddressInUse(uint16_t iPhysicalAddress);
-      bool TryLogicalAddress(cec_logical_address address);
-      bool FindLogicalAddressRecordingDevice(void);
-      bool FindLogicalAddressTuner(void);
-      bool FindLogicalAddressPlaybackDevice(void);
-      bool FindLogicalAddressAudioSystem(void);
+      bool SetAckMask(uint16_t iMask);
 
       void LogOutput(const cec_command &data);
       void ParseCommand(const cec_command &command);
 
-      bool                                m_bConnectionOpened;
-      bool                                m_bInitialised;
-      PLATFORM::CMutex                    m_mutex;
-      IAdapterCommunication *             m_communication;
-      CLibCEC*                            m_controller;
-      bool                                m_bMonitor;
-      cec_keypress                        m_previousKey;
-      PLATFORM::CThread *                 m_busScan;
-      uint8_t                             m_iStandardLineTimeout;
-      uint8_t                             m_iRetryLineTimeout;
-      uint64_t                            m_iLastTransmission;
-      CCECInputBuffer                     m_inBuffer;
-      libcec_configuration                m_configuration;
+      bool                                        m_bInitialised;
+      PLATFORM::CMutex                            m_mutex;
+      IAdapterCommunication *                     m_communication;
+      CLibCEC*                                    m_libcec;
+      bool                                        m_bMonitor;
+      uint16_t                                    m_iPreviousAckMask;
+      uint8_t                                     m_iStandardLineTimeout;
+      uint8_t                                     m_iRetryLineTimeout;
+      uint64_t                                    m_iLastTransmission;
+      CCECInputBuffer                             m_inBuffer;
+      CCECDeviceMap *                             m_busDevices;
+      std::map<cec_logical_address, CCECClient *> m_clients;
   };
 };
index 88e93e0dcd07a2d3ae2c366c46d068219b8faa54..f8607004e50c257ed01a3ebc50c485ab2c89d2fb 100644 (file)
 #include "adapter/USBCECAdapterDetection.h"
 #include "adapter/USBCECAdapterCommunication.h"
 #include "CECProcessor.h"
+#include "devices/CECAudioSystem.h"
 #include "devices/CECBusDevice.h"
+#include "devices/CECPlaybackDevice.h"
+#include "devices/CECTV.h"
 #include "platform/util/timeutils.h"
 #include "platform/util/StdString.h"
 
+#include "CECClient.h"
+
 using namespace std;
 using namespace CEC;
 using namespace PLATFORM;
 
-CLibCEC::CLibCEC(const char *strDeviceName, cec_device_type_list types, uint16_t iPhysicalAddress /* = 0 */) :
-    m_iStartTime(GetTimeMs()),
-    m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
-    m_buttontime(0),
-    m_callbacks(NULL),
-    m_cbParam(NULL)
-{
-  m_cec = new CCECProcessor(this, strDeviceName, types, iPhysicalAddress);
-}
-
-CLibCEC::CLibCEC(libcec_configuration *configuration) :
-    m_iStartTime(GetTimeMs()),
-    m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
-    m_buttontime(0),
-    m_callbacks(configuration->callbacks),
-    m_cbParam(configuration->callbackParam)
+CLibCEC::CLibCEC(void) :
+    m_client(NULL),
+    m_iStartTime(GetTimeMs())
 {
-  m_cec = new CCECProcessor(this, configuration);
+  m_cec = new CCECProcessor(this);
 }
 
 CLibCEC::~CLibCEC(void)
 {
+  delete m_client;
+  m_client = NULL;
   delete m_cec;
+  m_cec = NULL;
 }
 
 bool CLibCEC::Open(const char *strPort, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
@@ -82,35 +77,36 @@ bool CLibCEC::Open(const char *strPort, uint32_t iTimeoutMs /* = CEC_DEFAULT_CON
     return false;
   }
 
+  for (vector<CCECClient *>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+  {
+    if (!m_cec->RegisterClient(*it))
+    {
+      AddLog(CEC_LOG_ERROR, "failed to register a CEC client");
+      return false;
+    }
+  }
+
   return true;
 }
 
 void CLibCEC::Close(void)
 {
-  if (m_cec)
-    m_cec->Close();
-}
+  m_clients.clear();
 
-bool CLibCEC::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
-{
-  CLockObject lock(m_mutex);
+  if (m_client)
+  {
+    delete m_client;
+    m_client = NULL;
+  }
   if (m_cec)
   {
-    m_cbParam   = cbParam;
-    m_callbacks = callbacks;
+    delete m_cec;
+    m_cec = NULL;
   }
-  return false;
 }
 
 int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
 {
-  CStdString strDebug;
-  if (strDevicePath)
-    strDebug.Format("trying to autodetect the com port for device path '%s'", strDevicePath);
-  else
-    strDebug.Format("trying to autodetect all CEC adapters");
-  AddLog(CEC_LOG_DEBUG, strDebug);
-
   return CUSBCECAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
 }
 
@@ -124,639 +120,876 @@ bool CLibCEC::StartBootloader(void)
   return m_cec ? m_cec->StartBootloader() : false;
 }
 
-bool CLibCEC::GetNextLogMessage(cec_log_message *message)
-{
-  return (m_logBuffer.Pop(*message));
-}
-
-bool CLibCEC::GetNextKeypress(cec_keypress *key)
-{
-  return m_keyBuffer.Pop(*key);
-}
-
-bool CLibCEC::GetNextCommand(cec_command *command)
-{
-  return m_commandBuffer.Pop(*command);
-}
-
-bool CLibCEC::Transmit(const cec_command &data)
-{
-  return m_cec ? m_cec->Transmit(data) : false;
-}
-
-bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress)
-{
-  return m_cec ? m_cec->SetLogicalAddress(iLogicalAddress) : false;
-}
-
-bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
-{
-  return m_cec ? m_cec->SetPhysicalAddress(iPhysicalAddress) : false;
-}
-
-bool CLibCEC::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort /* = CEC_DEFAULT_HDMI_PORT */)
+bool CLibCEC::SwitchMonitoring(bool bEnable)
 {
-  return m_cec ? m_cec->SetHDMIPort(iBaseDevice, iPort) : false;
+  return m_cec ? m_cec->SwitchMonitoring(bEnable) : false;
 }
 
-bool CLibCEC::EnablePhysicalAddressDetection(void)
+cec_logical_address CLibCEC::GetActiveSource(void)
 {
-  return m_cec ? m_cec->EnablePhysicalAddressDetection() : false;
+  return m_cec ? m_cec->GetActiveSource() : CECDEVICE_UNKNOWN;
 }
 
-bool CLibCEC::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
+bool CLibCEC::IsActiveSource(cec_logical_address iAddress)
 {
-  return m_cec && address >= CECDEVICE_TV && address <= CECDEVICE_BROADCAST ? m_cec->PowerOnDevices(address) : false;
+  return m_cec ? m_cec->IsActiveSource(iAddress) : false;
 }
 
-bool CLibCEC::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
+bool CLibCEC::PollDevice(cec_logical_address iAddress)
 {
-  return m_cec && address >= CECDEVICE_TV && address <= CECDEVICE_BROADCAST ? m_cec->StandbyDevices(address) : false;
+  return m_cec ? m_cec->PollDevice(iAddress) : false;
 }
 
-bool CLibCEC::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
+cec_logical_addresses CLibCEC::GetActiveDevices(void)
 {
-  return m_cec ? m_cec->SetActiveSource(type) : false;
+  CECDEVICEVEC activeDevices;
+  if (m_cec)
+    m_cec->GetDevices()->GetActive(activeDevices);
+  return CCECDeviceMap::ToLogicalAddresses(activeDevices);
 }
 
-bool CLibCEC::SetActiveView(void)
+bool CLibCEC::IsActiveDevice(cec_logical_address iAddress)
 {
-  return m_cec ? m_cec->SetActiveView() : false;
+  cec_logical_addresses activeDevices = GetActiveDevices();
+  return activeDevices.IsSet(iAddress);
 }
 
-bool CLibCEC::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
+bool CLibCEC::IsActiveDeviceType(cec_device_type type)
 {
-  return m_cec ? m_cec->SetDeckControlMode(mode, bSendUpdate) : false;
+  CECDEVICEVEC activeDevices;
+  if (m_cec)
+    m_cec->GetDevices()->GetActive(activeDevices);
+  CCECDeviceMap::FilterType(type, activeDevices);
+  return !activeDevices.empty();
 }
 
-bool CLibCEC::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
+bool CLibCEC::SetStreamPath(cec_logical_address iAddress)
 {
-  return m_cec ? m_cec->SetDeckInfo(info, bSendUpdate) : false;
+  uint16_t iPhysicalAddress = GetDevicePhysicalAddress(iAddress);
+  if (iPhysicalAddress != CEC_INVALID_PHYSICAL_ADDRESS)
+    return SetStreamPath(iPhysicalAddress);
+  return false;
 }
 
-bool CLibCEC::SetInactiveView(void)
+bool CLibCEC::SetStreamPath(uint16_t iPhysicalAddress)
 {
-  return m_cec ? m_cec->TransmitInactiveSource() : false;
+  return m_cec->SetStreamPath(iPhysicalAddress);
 }
 
-bool CLibCEC::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
+bool CLibCEC::IsLibCECActiveSource(void)
 {
-  return m_cec ? m_cec->SetMenuState(state, bSendUpdate) : false;
+  bool bReturn(false);
+  if (m_cec)
+  {
+    cec_logical_address activeSource = m_cec->GetActiveSource();
+    CCECBusDevice *device = m_cec->GetDevice(activeSource);
+    if (device)
+      bReturn = device->IsHandledByLibCEC();
+  }
+  return bReturn;
 }
 
-bool CLibCEC::SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage)
+bool CLibCEC::CanPersistConfiguration(void)
 {
-  return m_cec && iLogicalAddress >= CECDEVICE_TV && iLogicalAddress <= CECDEVICE_BROADCAST ?
-      m_cec->m_busDevices[m_cec->GetLogicalAddress()]->TransmitOSDString(iLogicalAddress, duration, strMessage) :
-      false;
+  return m_cec->CanPersistConfiguration();
 }
 
-bool CLibCEC::SwitchMonitoring(bool bEnable)
+bool CLibCEC::PersistConfiguration(libcec_configuration *configuration)
 {
-  return m_cec ? m_cec->SwitchMonitoring(bEnable) : false;
+  return m_cec->PersistConfiguration(configuration);
 }
 
-cec_version CLibCEC::GetDeviceCecVersion(cec_logical_address iAddress)
+void CLibCEC::RescanActiveDevices(void)
 {
-  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
-    return m_cec->GetDeviceCecVersion(iAddress);
-  return CEC_VERSION_UNKNOWN;
+  return m_cec->RescanActiveDevices();
 }
 
-bool CLibCEC::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
+bool CLibCEC::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
 {
-  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
-    return m_cec->GetDeviceMenuLanguage(iAddress, language);
-  return false;
+  return m_client ? m_client->EnableCallbacks(cbParam, callbacks) : false;
 }
 
-uint64_t CLibCEC::GetDeviceVendorId(cec_logical_address iAddress)
+bool CLibCEC::GetCurrentConfiguration(libcec_configuration *configuration)
 {
-  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
-    return m_cec->GetDeviceVendorId(iAddress);
-  return 0;
+  return m_client ? m_client->GetCurrentConfiguration(configuration) : false;
 }
 
-uint16_t CLibCEC::GetDevicePhysicalAddress(cec_logical_address iAddress)
+bool CLibCEC::SetConfiguration(const libcec_configuration *configuration)
 {
-  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
-    return m_cec->GetDevicePhysicalAddress(iAddress);
-  return 0;
+  return m_client ? m_client->SetConfiguration(configuration) : false;
 }
 
-cec_logical_address CLibCEC::GetActiveSource(void)
+bool CLibCEC::Transmit(const cec_command &data)
 {
-  return m_cec ? m_cec->GetActiveSource() : CECDEVICE_UNKNOWN;
+  return m_client ? m_client->Transmit(data) : false;
 }
 
-bool CLibCEC::IsActiveSource(cec_logical_address iAddress)
+bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress)
 {
-  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
-    return m_cec->IsActiveSource(iAddress);
-  return false;
+  return m_client ? m_client->SetLogicalAddress(iLogicalAddress) : false;
 }
 
-cec_power_status CLibCEC::GetDevicePowerStatus(cec_logical_address iAddress)
+bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
 {
-  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
-    return m_cec->GetDevicePowerStatus(iAddress);
-  return CEC_POWER_STATUS_UNKNOWN;
+  return m_client ? m_client->SetPhysicalAddress(iPhysicalAddress) : false;
 }
 
-bool CLibCEC::PollDevice(cec_logical_address iAddress)
+bool CLibCEC::SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort /* = CEC_DEFAULT_HDMI_PORT */)
 {
-  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
-    return m_cec->PollDevice(iAddress);
-  return false;
+  return m_client ? m_client->SetHDMIPort(iBaseDevice, iPort) : false;
 }
 
-cec_logical_addresses CLibCEC::GetActiveDevices(void)
+bool CLibCEC::PowerOnDevices(cec_logical_address address /* = CECDEVICE_TV */)
 {
-  cec_logical_addresses addresses;
-  addresses.Clear();
-  if (m_cec)
-    addresses = m_cec->GetActiveDevices();
-  return addresses;
+  return m_client ? m_client->SendPowerOnDevices(address) : false;
 }
 
-bool CLibCEC::IsActiveDevice(cec_logical_address iAddress)
+bool CLibCEC::StandbyDevices(cec_logical_address address /* = CECDEVICE_BROADCAST */)
 {
-  if (m_cec && iAddress >= CECDEVICE_TV && iAddress < CECDEVICE_BROADCAST)
-    return m_cec->IsPresentDevice(iAddress);
-  return false;
+  return m_client ? m_client->SendStandbyDevices(address) : false;
 }
 
-bool CLibCEC::IsActiveDeviceType(cec_device_type type)
+bool CLibCEC::SetActiveSource(cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
 {
-  if (m_cec && type >= CEC_DEVICE_TYPE_TV && type <= CEC_DEVICE_TYPE_AUDIO_SYSTEM)
-    return m_cec->IsPresentDeviceType(type);
-  return false;
+  return m_client ? m_client->SendSetActiveSource(type) : false;
 }
 
-uint8_t CLibCEC::VolumeUp(bool bSendRelease /* = true */)
+bool CLibCEC::SetDeckControlMode(cec_deck_control_mode mode, bool bSendUpdate /* = true */)
 {
-  if (m_cec)
-    return m_cec->VolumeUp(bSendRelease);
-  return 0;
+  return m_client ? m_client->SendSetDeckControlMode(mode, bSendUpdate) : false;
 }
 
-uint8_t CLibCEC::VolumeDown(bool bSendRelease /* = true */)
+bool CLibCEC::SetDeckInfo(cec_deck_info info, bool bSendUpdate /* = true */)
 {
-  if (m_cec)
-    return m_cec->VolumeDown(bSendRelease);
-  return 0;
+  return m_client ? m_client->SendSetDeckInfo(info, bSendUpdate) : false;
 }
 
-
-uint8_t CLibCEC::MuteAudio(bool bSendRelease /* = true */)
+bool CLibCEC::SetInactiveView(void)
 {
-  if (m_cec)
-    return m_cec->MuteAudio(bSendRelease);
-  return 0;
+  return m_client ? m_client->SendSetInactiveView() : false;
 }
 
-bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
+bool CLibCEC::SetMenuState(cec_menu_state state, bool bSendUpdate /* = true */)
 {
-  if (m_cec)
-    return m_cec->TransmitKeypress(iDestination, key, bWait);
-  return false;
+  return m_client ? m_client->SendSetMenuState(state, bSendUpdate) : false;
 }
 
-bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
+bool CLibCEC::SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage)
 {
-  if (m_cec)
-    return m_cec->TransmitKeyRelease(iDestination, bWait);
-  return false;
+  return m_client ? m_client->SendSetOSDString(iLogicalAddress, duration, strMessage) : false;
 }
 
-cec_osd_name CLibCEC::GetDeviceOSDName(cec_logical_address iAddress)
+cec_version CLibCEC::GetDeviceCecVersion(cec_logical_address iAddress)
 {
-  cec_osd_name retVal;
-  retVal.device = iAddress;
-  retVal.name[0] = 0;
-
-  if (m_cec)
-    retVal = m_cec->GetDeviceOSDName(iAddress);
-
-  return retVal;
+  return m_client ? m_client->GetDeviceCecVersion(iAddress) : CEC_VERSION_UNKNOWN;
 }
 
-void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
+bool CLibCEC::GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language)
 {
-  CStdString strLog;
-
-  va_list argList;
-  va_start(argList, strFormat);
-  strLog.FormatV(strFormat, argList);
-  va_end(argList);
-
-  CLibCEC *instance = CLibCEC::GetInstance();
-  if (!instance)
-    return;
-  CLockObject lock(instance->m_logMutex);
-
-  cec_log_message message;
-  message.level = level;
-  message.time = GetTimeMs() - instance->m_iStartTime;
-  snprintf(message.message, sizeof(message.message), "%s", strLog.c_str());
-
-  if (instance->m_callbacks && instance->m_callbacks->CBCecLogMessage)
-    instance->m_callbacks->CBCecLogMessage(instance->m_cbParam, message);
-  else
-    instance->m_logBuffer.Push(message);
+  return m_client ? m_client->GetDeviceMenuLanguage(iAddress, language) : false;
 }
 
-void CLibCEC::AddKey(const cec_keypress &key)
+uint64_t CLibCEC::GetDeviceVendorId(cec_logical_address iAddress)
 {
-  CLibCEC *instance = CLibCEC::GetInstance();
-  if (!instance)
-    return;
-  CLockObject lock(instance->m_mutex);
-
-  AddLog(CEC_LOG_DEBUG, "key pressed: %1x", key.keycode);
-
-  if (instance->m_callbacks && instance->m_callbacks->CBCecKeyPress)
-    instance->m_callbacks->CBCecKeyPress(instance->m_cbParam, key);
-  else
-    instance->m_keyBuffer.Push(key);
-
-  instance->m_iCurrentButton = key.duration > 0 ? CEC_USER_CONTROL_CODE_UNKNOWN : key.keycode;
-  instance->m_buttontime = key.duration > 0 ? 0 : GetTimeMs();
+  return m_client ? m_client->GetDeviceVendorId(iAddress) : (uint64_t)CEC_VENDOR_UNKNOWN;
 }
 
-void CLibCEC::ConfigurationChanged(const libcec_configuration &config)
+uint16_t CLibCEC::GetDevicePhysicalAddress(cec_logical_address iAddress)
 {
-  CLibCEC *instance = CLibCEC::GetInstance();
-  CLockObject lock(instance->m_mutex);
-
-  if (instance->m_callbacks &&
-      config.clientVersion >= CEC_CLIENT_VERSION_1_5_0 &&
-      instance->m_callbacks->CBCecConfigurationChanged &&
-      instance->m_cec->IsInitialised())
-    instance->m_callbacks->CBCecConfigurationChanged(instance->m_cbParam, config);
+  return m_client ? m_client->GetDevicePhysicalAddress(iAddress) : CEC_INVALID_PHYSICAL_ADDRESS;
 }
 
-void CLibCEC::SetCurrentButton(cec_user_control_code iButtonCode)
+cec_power_status CLibCEC::GetDevicePowerStatus(cec_logical_address iAddress)
 {
-  /* push keypress to the keybuffer with 0 duration.
-     push another press to the keybuffer with the duration set when the button is released */
-  cec_keypress key;
-  key.duration = 0;
-  key.keycode = iButtonCode;
-
-  AddKey(key);
+  return m_client ? m_client->GetDevicePowerStatus(iAddress) : CEC_POWER_STATUS_UNKNOWN;
 }
 
-void CLibCEC::AddKey(void)
+uint8_t CLibCEC::VolumeUp(bool bSendRelease /* = true */)
 {
-  CLibCEC *instance = CLibCEC::GetInstance();
-  if (!instance)
-    return;
-  CLockObject lock(instance->m_mutex);
-
-  if (instance->m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
-  {
-    cec_keypress key;
-
-    key.duration = (unsigned int) (GetTimeMs() - instance->m_buttontime);
-    key.keycode = instance->m_iCurrentButton;
-    AddLog(CEC_LOG_DEBUG, "key released: %1x", key.keycode);
-
-    if (instance->m_callbacks && instance->m_callbacks->CBCecKeyPress)
-      instance->m_callbacks->CBCecKeyPress(instance->m_cbParam, key);
-    else
-      instance->m_keyBuffer.Push(key);
-    instance->m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
-  }
-  instance->m_buttontime = 0;
+  return m_client ? m_client->SendVolumeUp(bSendRelease) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
 }
 
-void CLibCEC::AddCommand(const cec_command &command)
+uint8_t CLibCEC::VolumeDown(bool bSendRelease /* = true */)
 {
-  CLibCEC *instance = CLibCEC::GetInstance();
-  if (!instance)
-    return;
-  CLockObject lock(instance->m_mutex);
-
-  AddLog(CEC_LOG_NOTICE, ">> %s (%X) -> %s (%X): %s (%2X)", instance->m_cec->ToString(command.initiator), command.initiator, instance->m_cec->ToString(command.destination), command.destination, instance->m_cec->ToString(command.opcode), command.opcode);
-
-  if (instance->m_callbacks && instance->m_callbacks->CBCecCommand)
-    instance->m_callbacks->CBCecCommand(instance->m_cbParam, command);
-  else if (!instance->m_commandBuffer.Push(command))
-    AddLog(CEC_LOG_WARNING, "command buffer is full");
+  return m_client ? m_client->SendVolumeDown(bSendRelease) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
 }
 
-void CLibCEC::Alert(const libcec_alert type, const libcec_parameter &param)
+uint8_t CLibCEC::MuteAudio(bool UNUSED(bSendRelease) /* = true */)
 {
-  CLibCEC *instance = CLibCEC::GetInstance();
-  if (!instance)
-    return;
-  CLockObject lock(instance->m_mutex);
-
-  libcec_configuration config;
-  instance->GetCurrentConfiguration(&config);
-
-  if (instance->m_callbacks &&
-      config.clientVersion >= CEC_CLIENT_VERSION_1_6_0 &&
-      instance->m_cec->IsInitialised() &&
-      instance->m_callbacks->CBCecAlert)
-    instance->m_callbacks->CBCecAlert(instance->m_cbParam, type, param);
-
-  if (type == CEC_ALERT_CONNECTION_LOST)
-    instance->Close();
+  return m_client ? m_client->SendMuteAudio() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
 }
 
-void CLibCEC::CheckKeypressTimeout(void)
+bool CLibCEC::SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */)
 {
-  if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && GetTimeMs() - m_buttontime > CEC_BUTTON_TIMEOUT)
-  {
-    AddKey();
-    m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
-  }
+  return m_client ? m_client->SendKeypress(iDestination, key, bWait) : false;
 }
 
-int CLibCEC::MenuStateChanged(const cec_menu_state newState)
+bool CLibCEC::SendKeyRelease(cec_logical_address iDestination, bool bWait /* = true */)
 {
-  int iReturn(0);
-
-  CLibCEC *instance = CLibCEC::GetInstance();
-  if (!instance)
-    return iReturn;
-  CLockObject lock(instance->m_mutex);
-
-  AddLog(CEC_LOG_NOTICE, ">> %s: %s", instance->m_cec->ToString(CEC_OPCODE_MENU_REQUEST), instance->m_cec->ToString(newState));
-
-  libcec_configuration config;
-  instance->GetCurrentConfiguration(&config);
-
-  if (instance->m_callbacks &&
-      config.clientVersion >= CEC_CLIENT_VERSION_1_6_2 &&
-      instance->m_callbacks->CBCecMenuStateChanged)
-    iReturn = instance->m_callbacks->CBCecMenuStateChanged(instance->m_cbParam, newState);
-
-  return iReturn;
+  return m_client ? m_client->SendKeyRelease(iDestination, bWait) : false;
 }
 
-bool CLibCEC::SetStreamPath(cec_logical_address iAddress)
+cec_osd_name CLibCEC::GetDeviceOSDName(cec_logical_address iAddress)
 {
-  uint16_t iPhysicalAddress = GetDevicePhysicalAddress(iAddress);
-  if (iPhysicalAddress != CEC_INVALID_PHYSICAL_ADDRESS)
-    return SetStreamPath(iPhysicalAddress);
-  return false;
+  cec_osd_name retVal;
+  if (m_client)
+    retVal = m_client->GetDeviceOSDName(iAddress);
+  return retVal;
 }
 
-bool CLibCEC::SetStreamPath(uint16_t iPhysicalAddress)
+cec_logical_addresses CLibCEC::GetLogicalAddresses(void)
 {
-  return m_cec->SetStreamPath(iPhysicalAddress);
+  cec_logical_addresses addresses;
+  if (m_cec)
+    addresses = m_cec->GetLogicalAddresses();
+  return addresses;
 }
 
-cec_logical_addresses CLibCEC::GetLogicalAddresses(void)
+bool CLibCEC::GetNextLogMessage(cec_log_message *message)
 {
-  cec_logical_addresses addr = m_cec->GetLogicalAddresses();
-  return addr;
+  return m_client ? m_client->GetNextLogMessage(message) : false;
 }
 
-static CLibCEC *g_libCEC_instance(NULL);
-CLibCEC *CLibCEC::GetInstance(void)
+bool CLibCEC::GetNextKeypress(cec_keypress *key)
 {
-  return g_libCEC_instance;
+  return m_client ? m_client->GetNextKeypress(key) : false;
 }
 
-void CLibCEC::SetInstance(CLibCEC *instance)
+bool CLibCEC::GetNextCommand(cec_command *command)
 {
-  if (g_libCEC_instance)
-    delete g_libCEC_instance;
-  g_libCEC_instance = instance;
+  return m_client ? m_client->GetNextCommand(command) : false;
 }
 
-void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types, uint16_t UNUSED(iPhysicalAddress) /* = 0 */)
+cec_device_type CLibCEC::GetType(cec_logical_address address)
 {
-  CLibCEC *lib = new CLibCEC(strDeviceName, types);
-  CLibCEC::SetInstance(lib);
-  return static_cast< void* > (lib);
+  switch (address)
+  {
+    case CECDEVICE_AUDIOSYSTEM:
+      return CEC_DEVICE_TYPE_AUDIO_SYSTEM;
+    case CECDEVICE_PLAYBACKDEVICE1:
+    case CECDEVICE_PLAYBACKDEVICE2:
+    case CECDEVICE_PLAYBACKDEVICE3:
+      return CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
+    case CECDEVICE_RECORDINGDEVICE1:
+    case CECDEVICE_RECORDINGDEVICE2:
+    case CECDEVICE_RECORDINGDEVICE3:
+      return CEC_DEVICE_TYPE_RECORDING_DEVICE;
+    case CECDEVICE_TUNER1:
+    case CECDEVICE_TUNER2:
+    case CECDEVICE_TUNER3:
+    case CECDEVICE_TUNER4:
+      return CEC_DEVICE_TYPE_TUNER;
+    case CECDEVICE_TV:
+      return CEC_DEVICE_TYPE_TV;
+    default:
+      return CEC_DEVICE_TYPE_RESERVED;
+  }
 }
 
-void * CECInitialise(libcec_configuration *configuration)
+uint16_t CLibCEC::GetMaskForType(cec_logical_address address)
 {
-  CLibCEC *lib = new CLibCEC(configuration);
-  CLibCEC::SetInstance(lib);
-  lib->GetCurrentConfiguration(configuration);
-  return static_cast< void* > (lib);
+  return GetMaskForType(GetType(address));
 }
 
-bool CECStartBootloader(void)
+uint16_t CLibCEC::GetMaskForType(cec_device_type type)
 {
-  bool bReturn(false);
-  cec_adapter deviceList[1];
-  if (CUSBCECAdapterDetection::FindAdapters(deviceList, 1) > 0)
+  switch (type)
   {
-    CUSBCECAdapterCommunication comm(NULL, deviceList[0].comm);
-    CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
-    while (timeout.TimeLeft() > 0 && (bReturn = comm.Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
+    case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
     {
-      comm.Close();
-      CEvent::Sleep(500);
+      cec_logical_addresses addr;
+      addr.Clear();
+      addr.Set(CECDEVICE_AUDIOSYSTEM);
+      return addr.AckMask();
     }
-    if (comm.IsOpen())
-      bReturn = comm.StartBootloader();
+    case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
+    {
+      cec_logical_addresses addr;
+      addr.Clear();
+      addr.Set(CECDEVICE_PLAYBACKDEVICE1);
+      addr.Set(CECDEVICE_PLAYBACKDEVICE2);
+      addr.Set(CECDEVICE_PLAYBACKDEVICE3);
+      return addr.AckMask();
+    }
+    case CEC_DEVICE_TYPE_RECORDING_DEVICE:
+    {
+      cec_logical_addresses addr;
+      addr.Clear();
+      addr.Set(CECDEVICE_RECORDINGDEVICE1);
+      addr.Set(CECDEVICE_RECORDINGDEVICE2);
+      addr.Set(CECDEVICE_RECORDINGDEVICE3);
+      return addr.AckMask();
+    }
+    case CEC_DEVICE_TYPE_TUNER:
+    {
+      cec_logical_addresses addr;
+      addr.Clear();
+      addr.Set(CECDEVICE_TUNER1);
+      addr.Set(CECDEVICE_TUNER2);
+      addr.Set(CECDEVICE_TUNER3);
+      addr.Set(CECDEVICE_TUNER4);
+      return addr.AckMask();
+    }
+    case CEC_DEVICE_TYPE_TV:
+    {
+      cec_logical_addresses addr;
+      addr.Clear();
+      addr.Set(CECDEVICE_TV);
+      return addr.AckMask();
+    }
+    default:
+      return 0;
   }
+}
 
-  return bReturn;
+bool CLibCEC::IsValidPhysicalAddress(uint16_t iPhysicalAddress)
+{
+  return iPhysicalAddress >= CEC_MIN_PHYSICAL_ADDRESS &&
+         iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS;
 }
 
-void CECDestroy(CEC::ICECAdapter *UNUSED(instance))
+const char *CLibCEC::ToString(const cec_device_type type)
 {
-  CLibCEC::SetInstance(NULL);
+  switch (type)
+  {
+  case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
+    return "audio system";
+  case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
+    return "playback device";
+  case CEC_DEVICE_TYPE_RECORDING_DEVICE:
+      return "recording device";
+  case CEC_DEVICE_TYPE_RESERVED:
+      return "reserved";
+  case CEC_DEVICE_TYPE_TUNER:
+      return "tuner";
+  case CEC_DEVICE_TYPE_TV:
+      return "TV";
+  default:
+    return "unknown";
+  }
 }
 
 const char *CLibCEC::ToString(const cec_menu_state state)
 {
-  return m_cec->ToString(state);
+  switch (state)
+  {
+  case CEC_MENU_STATE_ACTIVATED:
+    return "activated";
+  case CEC_MENU_STATE_DEACTIVATED:
+    return "deactivated";
+  default:
+    return "unknown";
+  }
 }
 
 const char *CLibCEC::ToString(const cec_version version)
 {
-  return m_cec->ToString(version);
+  switch (version)
+  {
+  case CEC_VERSION_1_2:
+    return "1.2";
+  case CEC_VERSION_1_2A:
+    return "1.2a";
+  case CEC_VERSION_1_3:
+    return "1.3";
+  case CEC_VERSION_1_3A:
+    return "1.3a";
+  case CEC_VERSION_1_4:
+    return "1.4";
+  default:
+    return "unknown";
+  }
 }
 
 const char *CLibCEC::ToString(const cec_power_status status)
 {
-  return m_cec->ToString(status);
+  switch (status)
+  {
+  case CEC_POWER_STATUS_ON:
+    return "on";
+  case CEC_POWER_STATUS_STANDBY:
+    return "standby";
+  case CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY:
+    return "in transition from on to standby";
+  case CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON:
+    return "in transition from standby to on";
+  default:
+    return "unknown";
+  }
 }
 
 const char *CLibCEC::ToString(const cec_logical_address address)
 {
-  return m_cec->ToString(address);
+  switch(address)
+  {
+  case CECDEVICE_AUDIOSYSTEM:
+    return "Audio";
+  case CECDEVICE_BROADCAST:
+    return "Broadcast";
+  case CECDEVICE_FREEUSE:
+    return "Free use";
+  case CECDEVICE_PLAYBACKDEVICE1:
+    return "Playback 1";
+  case CECDEVICE_PLAYBACKDEVICE2:
+    return "Playback 2";
+  case CECDEVICE_PLAYBACKDEVICE3:
+    return "Playback 3";
+  case CECDEVICE_RECORDINGDEVICE1:
+    return "Recorder 1";
+  case CECDEVICE_RECORDINGDEVICE2:
+    return "Recorder 2";
+  case CECDEVICE_RECORDINGDEVICE3:
+    return "Recorder 3";
+  case CECDEVICE_RESERVED1:
+    return "Reserved 1";
+  case CECDEVICE_RESERVED2:
+    return "Reserved 2";
+  case CECDEVICE_TUNER1:
+    return "Tuner 1";
+  case CECDEVICE_TUNER2:
+    return "Tuner 2";
+  case CECDEVICE_TUNER3:
+    return "Tuner 3";
+  case CECDEVICE_TUNER4:
+    return "Tuner 4";
+  case CECDEVICE_TV:
+    return "TV";
+  default:
+    return "unknown";
+  }
 }
 
 const char *CLibCEC::ToString(const cec_deck_control_mode mode)
 {
-  return m_cec->ToString(mode);
+  switch (mode)
+  {
+  case CEC_DECK_CONTROL_MODE_SKIP_FORWARD_WIND:
+    return "skip forward wind";
+  case CEC_DECK_CONTROL_MODE_EJECT:
+    return "eject";
+  case CEC_DECK_CONTROL_MODE_SKIP_REVERSE_REWIND:
+    return "reverse rewind";
+  case CEC_DECK_CONTROL_MODE_STOP:
+    return "stop";
+  default:
+    return "unknown";
+  }
 }
 
 const char *CLibCEC::ToString(const cec_deck_info status)
 {
-  return m_cec->ToString(status);
+  switch (status)
+  {
+  case CEC_DECK_INFO_PLAY:
+    return "play";
+  case CEC_DECK_INFO_RECORD:
+    return "record";
+  case CEC_DECK_INFO_PLAY_REVERSE:
+    return "play reverse";
+  case CEC_DECK_INFO_STILL:
+    return "still";
+  case CEC_DECK_INFO_SLOW:
+    return "slow";
+  case CEC_DECK_INFO_SLOW_REVERSE:
+    return "slow reverse";
+  case CEC_DECK_INFO_FAST_FORWARD:
+    return "fast forward";
+  case CEC_DECK_INFO_FAST_REVERSE:
+    return "fast reverse";
+  case CEC_DECK_INFO_NO_MEDIA:
+    return "no media";
+  case CEC_DECK_INFO_STOP:
+    return "stop";
+  case CEC_DECK_INFO_SKIP_FORWARD_WIND:
+    return "info skip forward wind";
+  case CEC_DECK_INFO_SKIP_REVERSE_REWIND:
+    return "info skip reverse rewind";
+  case CEC_DECK_INFO_INDEX_SEARCH_FORWARD:
+    return "info index search forward";
+  case CEC_DECK_INFO_INDEX_SEARCH_REVERSE:
+    return "info index search reverse";
+  case CEC_DECK_INFO_OTHER_STATUS:
+    return "other";
+  case CEC_DECK_INFO_OTHER_STATUS_LG:
+    return "LG other";
+  default:
+    return "unknown";
+  }
 }
 
 const char *CLibCEC::ToString(const cec_opcode opcode)
 {
-  return m_cec->ToString(opcode);
+  switch (opcode)
+  {
+  case CEC_OPCODE_ACTIVE_SOURCE:
+    return "active source";
+  case CEC_OPCODE_IMAGE_VIEW_ON:
+    return "image view on";
+  case CEC_OPCODE_TEXT_VIEW_ON:
+    return "text view on";
+  case CEC_OPCODE_INACTIVE_SOURCE:
+    return "inactive source";
+  case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
+    return "request active source";
+  case CEC_OPCODE_ROUTING_CHANGE:
+    return "routing change";
+  case CEC_OPCODE_ROUTING_INFORMATION:
+    return "routing information";
+  case CEC_OPCODE_SET_STREAM_PATH:
+    return "set stream path";
+  case CEC_OPCODE_STANDBY:
+    return "standby";
+  case CEC_OPCODE_RECORD_OFF:
+    return "record off";
+  case CEC_OPCODE_RECORD_ON:
+    return "record on";
+  case CEC_OPCODE_RECORD_STATUS:
+    return "record status";
+  case CEC_OPCODE_RECORD_TV_SCREEN:
+    return "record tv screen";
+  case CEC_OPCODE_CLEAR_ANALOGUE_TIMER:
+    return "clear analogue timer";
+  case CEC_OPCODE_CLEAR_DIGITAL_TIMER:
+    return "clear digital timer";
+  case CEC_OPCODE_CLEAR_EXTERNAL_TIMER:
+    return "clear external timer";
+  case CEC_OPCODE_SET_ANALOGUE_TIMER:
+    return "set analogue timer";
+  case CEC_OPCODE_SET_DIGITAL_TIMER:
+    return "set digital timer";
+  case CEC_OPCODE_SET_EXTERNAL_TIMER:
+    return "set external timer";
+  case CEC_OPCODE_SET_TIMER_PROGRAM_TITLE:
+    return "set timer program title";
+  case CEC_OPCODE_TIMER_CLEARED_STATUS:
+    return "timer cleared status";
+  case CEC_OPCODE_TIMER_STATUS:
+    return "timer status";
+  case CEC_OPCODE_CEC_VERSION:
+    return "cec version";
+  case CEC_OPCODE_GET_CEC_VERSION:
+    return "get cec version";
+  case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
+    return "give physical address";
+  case CEC_OPCODE_GET_MENU_LANGUAGE:
+    return "get menu language";
+  case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
+    return "report physical address";
+  case CEC_OPCODE_SET_MENU_LANGUAGE:
+    return "set menu language";
+  case CEC_OPCODE_DECK_CONTROL:
+    return "deck control";
+  case CEC_OPCODE_DECK_STATUS:
+    return "deck status";
+  case CEC_OPCODE_GIVE_DECK_STATUS:
+    return "give deck status";
+  case CEC_OPCODE_PLAY:
+    return "play";
+  case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS:
+    return "give tuner status";
+  case CEC_OPCODE_SELECT_ANALOGUE_SERVICE:
+    return "select analogue service";
+  case CEC_OPCODE_SELECT_DIGITAL_SERVICE:
+    return "set digital service";
+  case CEC_OPCODE_TUNER_DEVICE_STATUS:
+    return "tuner device status";
+  case CEC_OPCODE_TUNER_STEP_DECREMENT:
+    return "tuner step decrement";
+  case CEC_OPCODE_TUNER_STEP_INCREMENT:
+    return "tuner step increment";
+  case CEC_OPCODE_DEVICE_VENDOR_ID:
+    return "device vendor id";
+  case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
+    return "give device vendor id";
+  case CEC_OPCODE_VENDOR_COMMAND:
+    return "vendor command";
+  case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
+    return "vendor command with id";
+  case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
+    return "vendor remote button down";
+  case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
+    return "vendor remote button up";
+  case CEC_OPCODE_SET_OSD_STRING:
+    return "set osd string";
+  case CEC_OPCODE_GIVE_OSD_NAME:
+    return "give osd name";
+  case CEC_OPCODE_SET_OSD_NAME:
+    return "set osd name";
+  case CEC_OPCODE_MENU_REQUEST:
+    return "menu request";
+  case CEC_OPCODE_MENU_STATUS:
+    return "menu status";
+  case CEC_OPCODE_USER_CONTROL_PRESSED:
+    return "user control pressed";
+  case CEC_OPCODE_USER_CONTROL_RELEASE:
+    return "user control release";
+  case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
+    return "give device power status";
+  case CEC_OPCODE_REPORT_POWER_STATUS:
+    return "report power status";
+  case CEC_OPCODE_FEATURE_ABORT:
+    return "feature abort";
+  case CEC_OPCODE_ABORT:
+    return "abort";
+  case CEC_OPCODE_GIVE_AUDIO_STATUS:
+    return "give audio status";
+  case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
+    return "give audio mode status";
+  case CEC_OPCODE_REPORT_AUDIO_STATUS:
+    return "report audio status";
+  case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
+    return "set system audio mode";
+  case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
+    return "system audio mode request";
+  case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
+    return "system audio mode status";
+  case CEC_OPCODE_SET_AUDIO_RATE:
+    return "set audio rate";
+  case CEC_OPCODE_START_ARC:
+    return "start ARC";
+  case CEC_OPCODE_REPORT_ARC_STARTED:
+    return "report ARC started";
+  case CEC_OPCODE_REPORT_ARC_ENDED:
+    return "report ARC ended";
+  case CEC_OPCODE_REQUEST_ARC_START:
+    return "request ARC start";
+  case CEC_OPCODE_REQUEST_ARC_END:
+    return "request ARC end";
+  case CEC_OPCODE_END_ARC:
+    return "end ARC";
+  case CEC_OPCODE_CDC:
+    return "CDC";
+  case CEC_OPCODE_NONE:
+    return "poll";
+  default:
+    return "UNKNOWN";
+  }
 }
 
 const char *CLibCEC::ToString(const cec_system_audio_status mode)
 {
-  return m_cec->ToString(mode);
+  switch(mode)
+  {
+  case CEC_SYSTEM_AUDIO_STATUS_ON:
+    return "on";
+  case CEC_SYSTEM_AUDIO_STATUS_OFF:
+    return "off";
+  default:
+    return "unknown";
+  }
 }
 
-const char *CLibCEC::ToString(const cec_audio_status status)
+const char *CLibCEC::ToString(const cec_audio_status UNUSED(status))
 {
-  return m_cec->ToString(status);
+  // TODO this is a mask
+  return "TODO";
 }
 
 const char *CLibCEC::ToString(const cec_vendor_id vendor)
 {
-  return m_cec->ToString(vendor);
+  switch (vendor)
+  {
+  case CEC_VENDOR_SAMSUNG:
+    return "Samsung";
+  case CEC_VENDOR_LG:
+    return "LG";
+  case CEC_VENDOR_PANASONIC:
+    return "Panasonic";
+  case CEC_VENDOR_PIONEER:
+    return "Pioneer";
+  case CEC_VENDOR_ONKYO:
+    return "Onkyo";
+  case CEC_VENDOR_YAMAHA:
+    return "Yamaha";
+  case CEC_VENDOR_PHILIPS:
+    return "Philips";
+  case CEC_VENDOR_SONY:
+    return "Sony";
+  case CEC_VENDOR_TOSHIBA:
+    return "Toshiba";
+  default:
+    return "Unknown";
+  }
 }
 
 const char *CLibCEC::ToString(const cec_client_version version)
 {
-  return m_cec->ToString(version);
+  switch (version)
+  {
+  case CEC_CLIENT_VERSION_PRE_1_5:
+    return "pre-1.5";
+  case CEC_CLIENT_VERSION_1_5_0:
+    return "1.5.0";
+  case CEC_CLIENT_VERSION_1_5_1:
+    return "1.5.1";
+  case CEC_CLIENT_VERSION_1_5_2:
+    return "1.5.2";
+  case CEC_CLIENT_VERSION_1_5_3:
+    return "1.5.3";
+  case CEC_CLIENT_VERSION_1_6_0:
+    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";
+  }
 }
 
 const char *CLibCEC::ToString(const cec_server_version version)
 {
-  return m_cec->ToString(version);
+  switch (version)
+  {
+  case CEC_SERVER_VERSION_PRE_1_5:
+    return "pre-1.5";
+  case CEC_SERVER_VERSION_1_5_0:
+    return "1.5.0";
+  case CEC_SERVER_VERSION_1_5_1:
+    return "1.5.1";
+  case CEC_SERVER_VERSION_1_5_2:
+    return "1.5.2";
+  case CEC_SERVER_VERSION_1_5_3:
+    return "1.5.3";
+  case CEC_SERVER_VERSION_1_6_0:
+    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";
+  }
 }
 
-const char *CLibCEC::ToString(const cec_device_type type)
+void CLibCEC::CheckKeypressTimeout(void)
 {
-  return m_cec->ToString(type);
+  // check all clients
+  for (vector<CCECClient *>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+    (*it)->CheckKeypressTimeout();
 }
 
-bool CLibCEC::GetCurrentConfiguration(libcec_configuration *configuration)
+void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
 {
-  return m_cec->GetCurrentConfiguration(configuration);
+  CStdString strLog;
+
+  va_list argList;
+  va_start(argList, strFormat);
+  strLog.FormatV(strFormat, argList);
+  va_end(argList);
+
+  cec_log_message message;
+  message.level = level;
+  message.time = GetTimeMs() - m_iStartTime;
+  snprintf(message.message, sizeof(message.message), "%s", strLog.c_str());
+
+  // send the message to all clients
+  for (vector<CCECClient *>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+    (*it)->AddLog(message);
 }
 
-bool CLibCEC::SetConfiguration(const libcec_configuration *configuration)
+void CLibCEC::Alert(const libcec_alert type, const libcec_parameter &param)
 {
-  return m_cec->SetConfiguration(configuration);
+  // send the alert to all clients
+  for (vector<CCECClient *>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+    (*it)->Alert(type, param);
 }
 
-bool CLibCEC::CanPersistConfiguration(void)
+bool CLibCEC::SetActiveView(void)
 {
-  return m_cec->CanPersistConfiguration();
+  AddLog(CEC_LOG_WARNING, "deprecated method %s called", __FUNCTION__);
+  return SetActiveSource();
 }
 
-bool CLibCEC::PersistConfiguration(libcec_configuration *configuration)
+bool CLibCEC::EnablePhysicalAddressDetection(void)
 {
-  return m_cec->PersistConfiguration(configuration);
+  AddLog(CEC_LOG_WARNING, "deprecated method %s called", __FUNCTION__);
+  return true;
 }
 
-void CLibCEC::RescanActiveDevices(void)
+CCECClient *CLibCEC::RegisterClient(libcec_configuration *configuration)
 {
-  return m_cec->RescanActiveDevices();
+  if (!m_cec)
+    return NULL;
+
+  CCECClient *newClient = new CCECClient(m_cec, configuration);
+  if (!newClient)
+    return NULL;
+
+  m_clients.push_back(newClient);
+  if (!m_client)
+    m_client = newClient;
+
+  if (m_cec->IsRunning())
+    m_cec->RegisterClient(newClient);
+
+  return m_client;
 }
 
-bool CLibCEC::IsLibCECActiveSource(void)
+void CLibCEC::UnregisterClients(void)
 {
-  bool bReturn(false);
-  if (m_cec)
-  {
-    cec_logical_address activeSource = m_cec->GetActiveSource();
-    if (activeSource != CECDEVICE_UNKNOWN)
-      bReturn = m_cec->m_busDevices[activeSource]->GetStatus(false) == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC;
-  }
-  return bReturn;
+  m_clients.clear();
+  delete m_client;
+  m_client = NULL;
 }
 
-cec_device_type CLibCEC::GetType(cec_logical_address address)
+void * CECInitialise(libcec_configuration *configuration)
 {
-  switch (address)
-  {
-    case CECDEVICE_AUDIOSYSTEM:
-      return CEC_DEVICE_TYPE_AUDIO_SYSTEM;
-    case CECDEVICE_PLAYBACKDEVICE1:
-    case CECDEVICE_PLAYBACKDEVICE2:
-    case CECDEVICE_PLAYBACKDEVICE3:
-      return CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
-    case CECDEVICE_RECORDINGDEVICE1:
-    case CECDEVICE_RECORDINGDEVICE2:
-    case CECDEVICE_RECORDINGDEVICE3:
-      return CEC_DEVICE_TYPE_RECORDING_DEVICE;
-    case CECDEVICE_TUNER1:
-    case CECDEVICE_TUNER2:
-    case CECDEVICE_TUNER3:
-    case CECDEVICE_TUNER4:
-      return CEC_DEVICE_TYPE_TUNER;
-    case CECDEVICE_TV:
-      return CEC_DEVICE_TYPE_TV;
-    default:
-      return CEC_DEVICE_TYPE_RESERVED;
-  }
+  if (!configuration)
+    return NULL;
+
+  CLibCEC *lib = new CLibCEC;
+  if (lib)
+    lib->RegisterClient(configuration);
+
+  return static_cast< void* > (lib);
 }
 
-uint16_t CLibCEC::GetMaskForType(cec_logical_address address)
+void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types, uint16_t iPhysicalAddress /* = 0 */)
 {
-  return GetMaskForType(GetType(address));
+  libcec_configuration configuration;
+  configuration.serverVersion = LIBCEC_VERSION_CURRENT;
+
+  // client version < 1.5.0
+  snprintf(configuration.strDeviceName, 13, "%s", strDeviceName);
+  configuration.deviceTypes      = types;
+  configuration.iPhysicalAddress = iPhysicalAddress;
+
+  if (configuration.deviceTypes.IsEmpty())
+    configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+
+  return CECInitialise(&configuration);
 }
 
-uint16_t CLibCEC::GetMaskForType(cec_device_type type)
+bool CECStartBootloader(void)
 {
-  switch (type)
+  bool bReturn(false);
+  cec_adapter deviceList[1];
+  if (CUSBCECAdapterDetection::FindAdapters(deviceList, 1) > 0)
   {
-    case CEC_DEVICE_TYPE_AUDIO_SYSTEM:
-    {
-      cec_logical_addresses addr;
-      addr.Clear();
-      addr.Set(CECDEVICE_AUDIOSYSTEM);
-      return addr.AckMask();
-    }
-    case CEC_DEVICE_TYPE_PLAYBACK_DEVICE:
-    {
-      cec_logical_addresses addr;
-      addr.Clear();
-      addr.Set(CECDEVICE_PLAYBACKDEVICE1);
-      addr.Set(CECDEVICE_PLAYBACKDEVICE2);
-      addr.Set(CECDEVICE_PLAYBACKDEVICE3);
-      return addr.AckMask();
-    }
-    case CEC_DEVICE_TYPE_RECORDING_DEVICE:
-    {
-      cec_logical_addresses addr;
-      addr.Clear();
-      addr.Set(CECDEVICE_RECORDINGDEVICE1);
-      addr.Set(CECDEVICE_RECORDINGDEVICE2);
-      addr.Set(CECDEVICE_RECORDINGDEVICE3);
-      return addr.AckMask();
-    }
-    case CEC_DEVICE_TYPE_TUNER:
-    {
-      cec_logical_addresses addr;
-      addr.Clear();
-      addr.Set(CECDEVICE_TUNER1);
-      addr.Set(CECDEVICE_TUNER2);
-      addr.Set(CECDEVICE_TUNER3);
-      addr.Set(CECDEVICE_TUNER4);
-      return addr.AckMask();
-    }
-    case CEC_DEVICE_TYPE_TV:
+    CUSBCECAdapterCommunication comm(NULL, deviceList[0].comm);
+    CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT);
+    while (timeout.TimeLeft() > 0 && (bReturn = comm.Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false)
     {
-      cec_logical_addresses addr;
-      addr.Clear();
-      addr.Set(CECDEVICE_TV);
-      return addr.AckMask();
+      comm.Close();
+      CEvent::Sleep(500);
     }
-    default:
-      return 0;
+    if (comm.IsOpen())
+      bReturn = comm.StartBootloader();
   }
+
+  return bReturn;
+}
+
+void CECDestroy(CEC::ICECAdapter *instance)
+{
+  delete instance;
 }
 
 bool CLibCEC::GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */)
 {
   if (m_cec->IsRunning())
     return false;
-  
+
   return m_cec->GetDeviceInformation(strPort, config, iTimeoutMs);
 }
index 563cec1ca1c0a0d7db8561280e2247a2a05c055d..6b23dacc55f2c84c487bc069690ccfddd303df7e 100644 (file)
@@ -39,18 +39,18 @@ namespace CEC
 {
   class CAdapterCommunication;
   class CCECProcessor;
+  class CCECClient;
 
   class CLibCEC : public ICECAdapter
   {
     public:
+      CLibCEC(void);
+      virtual ~CLibCEC(void);
+
     /*!
      * ICECAdapter implementation
      */
     //@{
-      CLibCEC(const char *strDeviceName, cec_device_type_list types, uint16_t iPhysicalAddress = 0);
-      CLibCEC(libcec_configuration *configuration);
-      virtual ~CLibCEC(void);
-
       bool Open(const char *strPort, uint32_t iTimeout = CEC_DEFAULT_CONNECT_TIMEOUT);
       void Close(void);
       bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks);
@@ -80,11 +80,14 @@ namespace CEC
       bool SetMenuState(cec_menu_state state, bool bSendUpdate = true);
       bool SetOSDString(cec_logical_address iLogicalAddress, cec_display_control duration, const char *strMessage);
       bool SwitchMonitoring(bool bEnable);
+
       cec_version GetDeviceCecVersion(cec_logical_address iAddress);
       bool GetDeviceMenuLanguage(cec_logical_address iAddress, cec_menu_language *language);
       uint64_t GetDeviceVendorId(cec_logical_address iAddress);
       uint16_t GetDevicePhysicalAddress(cec_logical_address iAddress);
       cec_power_status GetDevicePowerStatus(cec_logical_address iAddress);
+      cec_osd_name GetDeviceOSDName(cec_logical_address iAddress);
+
       bool PollDevice(cec_logical_address iAddress);
       cec_logical_addresses GetActiveDevices(void);
       bool IsActiveDevice(cec_logical_address iAddress);
@@ -95,7 +98,6 @@ namespace CEC
       uint8_t MuteAudio(bool bSendRelease = true);
       bool SendKeypress(cec_logical_address iDestination, cec_user_control_code key, bool bWait = true);
       bool SendKeyRelease(cec_logical_address iDestination, bool bWait = true);
-      cec_osd_name GetDeviceOSDName(cec_logical_address iAddress);
       bool EnablePhysicalAddressDetection(void);
       cec_logical_address GetActiveSource(void);
       bool IsActiveSource(cec_logical_address iAddress);
@@ -123,37 +125,27 @@ namespace CEC
       const char *ToString(const cec_server_version version);
       const char *ToString(const cec_device_type type);
 
+      static bool IsValidPhysicalAddress(uint16_t iPhysicalAddress);
+
       static cec_device_type GetType(cec_logical_address address);
       static uint16_t GetMaskForType(cec_logical_address address);
       static uint16_t GetMaskForType(cec_device_type type);
 
       bool GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs = CEC_DEFAULT_CONNECT_TIMEOUT);
     //@}
+      void AddLog(const cec_log_level level, const char *strFormat, ...);
 
-      static void AddLog(const cec_log_level level, const char *strFormat, ...);
-      static void AddKey(void);
-      static void AddKey(const cec_keypress &key);
-      static void AddCommand(const cec_command &command);
-      static void ConfigurationChanged(const libcec_configuration &config);
-      static void SetCurrentButton(cec_user_control_code iButtonCode);
       void CheckKeypressTimeout(void);
-      static int MenuStateChanged(const cec_menu_state newState);
-      static void Alert(const libcec_alert type, const libcec_parameter &param);
+      void Alert(const libcec_alert type, const libcec_parameter &param);
 
-      static CLibCEC *GetInstance(void);
-      static void SetInstance(CLibCEC *instance);
-
-      CCECProcessor *                         m_cec;
+      CCECClient *RegisterClient(libcec_configuration *configuration);
+      void UnregisterClients(void);
     protected:
-      int64_t                                 m_iStartTime;
-      cec_user_control_code                   m_iCurrentButton;
-      int64_t                                 m_buttontime;
-      PLATFORM::SyncedBuffer<cec_log_message> m_logBuffer;
-      PLATFORM::SyncedBuffer<cec_keypress>    m_keyBuffer;
-      PLATFORM::SyncedBuffer<cec_command>     m_commandBuffer;
-      ICECCallbacks *                         m_callbacks;
-      void *                                  m_cbParam;
-      PLATFORM::CMutex                        m_mutex;
-      PLATFORM::CMutex                        m_logMutex;
+      CCECProcessor *           m_cec;
+      CCECClient *              m_client;
+
+      int64_t                   m_iStartTime;
+      PLATFORM::CMutex          m_mutex;
+      std::vector<CCECClient *> m_clients;
   };
 };
index 60d6d2d43069a24c9a6579c1cd0f4d5bf4ac7566..19f5e6f7a2dc03fd300dccbea40c68f1c3b32c5f 100644 (file)
@@ -11,6 +11,7 @@ pkgconfig_DATA = libcec.pc
 libcec_la_SOURCES = CECProcessor.cpp \
                     LibCEC.cpp \
                     LibCECC.cpp \
+                    CECClient.cpp \
                     adapter/USBCECAdapterCommands.cpp \
                     adapter/USBCECAdapterCommunication.cpp \
                     adapter/USBCECAdapterDetection.cpp \
@@ -18,6 +19,7 @@ libcec_la_SOURCES = CECProcessor.cpp \
                     adapter/USBCECAdapterMessageQueue.cpp \
                     devices/CECAudioSystem.cpp \
                     devices/CECBusDevice.cpp \
+                    devices/CECDeviceMap.cpp \
                     devices/CECPlaybackDevice.cpp \
                     devices/CECRecordingDevice.cpp \
                     devices/CECTuner.cpp \
index f8dc4bc23f5122ada19a2e7f829868233649181b..889c87b8716c98b3fe347f61c76ce7f5209438ef 100644 (file)
@@ -36,6 +36,8 @@
 
 namespace CEC
 {
+  class CLibCEC;
+
   class IAdapterCommunicationCallback
   {
   public:
@@ -62,6 +64,8 @@ namespace CEC
      * @return True when this is an error, false otherwise.
      */
     virtual bool HandleReceiveFailed(cec_logical_address initiator) = 0;
+
+    virtual CLibCEC *GetLib(void) const = 0;
   };
 
   class IAdapterCommunication
@@ -126,6 +130,7 @@ namespace CEC
      * @return True when set, false otherwise.
      */
     virtual bool SetAckMask(uint16_t iMask) = 0;
+    virtual uint16_t GetAckMask(void) = 0;
 
     /*!
      * @brief Check whether the CEC adapter responds
@@ -177,7 +182,6 @@ namespace CEC
      */
     virtual uint16_t GetPhysicalAddress(void) = 0;
 
-  protected:
     IAdapterCommunicationCallback *m_callback;
   };
 };
index 0374dbee60b19f662f693a6bbf430d57a93f1f28..62a011a6279b74345e7001967ac7bae432371d2e 100644 (file)
@@ -37,6 +37,9 @@
 using namespace CEC;
 using namespace PLATFORM;
 
+#define LIB_CEC     m_comm->m_callback->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
 CUSBCECAdapterCommands::CUSBCECAdapterCommands(CUSBCECAdapterCommunication *comm) :
     m_comm(comm),
     m_bSettingsRetrieved(false),
@@ -73,20 +76,20 @@ uint16_t CUSBCECAdapterCommands::RequestFirmwareVersion(void)
 
   while (m_persistedConfiguration.iFirmwareVersion == CEC_FW_VERSION_UNKNOWN && iFwVersionTry++ < 3)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting the firmware version");
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting the firmware version");
     cec_datapacket response = RequestSetting(MSGCODE_FIRMWARE_VERSION);
     if (response.size == 2)
       m_persistedConfiguration.iFirmwareVersion = (response[0] << 8 | response[1]);
     else
     {
-      CLibCEC::AddLog(CEC_LOG_WARNING, "the adapter did not respond with a correct firmware version (try %d)", iFwVersionTry);
+      LIB_CEC->AddLog(CEC_LOG_WARNING, "the adapter did not respond with a correct firmware version (try %d)", iFwVersionTry);
       CEvent::Sleep(500);
     }
   }
 
   if (m_persistedConfiguration.iFirmwareVersion == CEC_FW_VERSION_UNKNOWN)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "defaulting to firmware version 1");
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "defaulting to firmware version 1");
     m_persistedConfiguration.iFirmwareVersion = 1;
   }
 
@@ -95,13 +98,13 @@ uint16_t CUSBCECAdapterCommands::RequestFirmwareVersion(void)
 
 bool CUSBCECAdapterCommands::RequestSettingAutoEnabled(void)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting autonomous mode setting");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting autonomous mode setting");
 
   cec_datapacket response = RequestSetting(MSGCODE_GET_AUTO_ENABLED);
   if (response.size == 1)
   {
     m_bSettingAutoEnabled = response[0] == 1;
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted autonomous mode setting: '%s'", m_bSettingAutoEnabled ? "enabled" : "disabled");
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted autonomous mode setting: '%s'", m_bSettingAutoEnabled ? "enabled" : "disabled");
     return true;
   }
   return false;
@@ -109,13 +112,13 @@ bool CUSBCECAdapterCommands::RequestSettingAutoEnabled(void)
 
 bool CUSBCECAdapterCommands::RequestSettingCECVersion(void)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting CEC version setting");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting CEC version setting");
 
   cec_datapacket response = RequestSetting(MSGCODE_GET_HDMI_VERSION);
   if (response.size == 1)
   {
     m_settingCecVersion = (cec_version)response[0];
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted CEC version setting: '%s'", CLibCEC::GetInstance()->ToString(m_settingCecVersion));
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted CEC version setting: '%s'", ToString(m_settingCecVersion));
     return true;
   }
   return false;
@@ -125,7 +128,7 @@ uint32_t CUSBCECAdapterCommands::RequestBuildDate(void)
 {
   if (m_iBuildDate == CEC_FW_BUILD_UNKNOWN)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting firmware build date");
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting firmware build date");
 
     cec_datapacket response = RequestSetting(MSGCODE_GET_BUILDDATE);
     if (response.size == 4)
@@ -136,13 +139,13 @@ uint32_t CUSBCECAdapterCommands::RequestBuildDate(void)
 
 bool CUSBCECAdapterCommands::RequestSettingDefaultLogicalAddress(void)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting default logical address setting");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting default logical address setting");
 
   cec_datapacket response = RequestSetting(MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS);
   if (response.size == 1)
   {
     m_persistedConfiguration.logicalAddresses.primary = (cec_logical_address)response[0];
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted logical address setting: '%s'", CLibCEC::GetInstance()->ToString(m_persistedConfiguration.logicalAddresses.primary));
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted logical address setting: '%s'", ToString(m_persistedConfiguration.logicalAddresses.primary));
     return true;
   }
   return false;
@@ -150,29 +153,29 @@ bool CUSBCECAdapterCommands::RequestSettingDefaultLogicalAddress(void)
 
 bool CUSBCECAdapterCommands::RequestSettingDeviceType(void)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting device type setting");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting device type setting");
   m_persistedConfiguration.deviceTypes.Clear();
 
   cec_datapacket response = RequestSetting(MSGCODE_GET_DEVICE_TYPE);
   if (response.size == 1)
   {
     m_persistedConfiguration.deviceTypes.Add((cec_device_type)response[0]);
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted device type setting: '%s'", CLibCEC::GetInstance()->ToString((cec_device_type)response[0]));
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted device type setting: '%s'", ToString((cec_device_type)response[0]));
     return true;
   }
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "no persisted device type setting");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "no persisted device type setting");
   return false;
 }
 
 bool CUSBCECAdapterCommands::RequestSettingLogicalAddressMask(void)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting logical address mask setting");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting logical address mask setting");
 
   cec_datapacket response = RequestSetting(MSGCODE_GET_LOGICAL_ADDRESS_MASK);
   if (response.size == 2)
   {
     m_iSettingLAMask = ((uint16_t)response[0] << 8) | ((uint16_t)response[1]);
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted logical address mask setting: '%x'", m_iSettingLAMask);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted logical address mask setting: '%x'", m_iSettingLAMask);
     return true;
   }
   return false;
@@ -180,13 +183,13 @@ bool CUSBCECAdapterCommands::RequestSettingLogicalAddressMask(void)
 
 bool CUSBCECAdapterCommands::RequestSettingOSDName(void)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting OSD name setting");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting OSD name setting");
 
   memset(m_persistedConfiguration.strDeviceName, 0, 13);
   cec_datapacket response = RequestSetting(MSGCODE_GET_OSD_NAME);
   if (response.size == 0)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "no persisted device name setting");
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "no persisted device name setting");
     return false;
   }
 
@@ -196,22 +199,22 @@ bool CUSBCECAdapterCommands::RequestSettingOSDName(void)
   buf[response.size] = 0;
 
   snprintf(m_persistedConfiguration.strDeviceName, 13, "%s", buf);
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted device name setting: '%s'", buf);
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted device name setting: '%s'", buf);
   return true;
 }
 
 bool CUSBCECAdapterCommands::RequestSettingPhysicalAddress(void)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "requesting physical address setting");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "requesting physical address setting");
 
   cec_datapacket response = RequestSetting(MSGCODE_GET_PHYSICAL_ADDRESS);
   if (response.size == 2)
   {
     m_persistedConfiguration.iPhysicalAddress = ((uint16_t)response[0] << 8) | ((uint16_t)response[1]);
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "using persisted physical address setting: '%4x'", m_persistedConfiguration.iPhysicalAddress);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "using persisted physical address setting: '%4x'", m_persistedConfiguration.iPhysicalAddress);
     return true;
   }
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "no persisted physical address setting");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "no persisted physical address setting");
   return false;
 }
 
@@ -222,12 +225,12 @@ bool CUSBCECAdapterCommands::SetSettingAutoEnabled(bool enabled)
   /* check whether this value was changed */
   if (m_bSettingAutoEnabled == enabled)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "autonomous mode setting unchanged (%s)", enabled ? "on" : "off");
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "autonomous mode setting unchanged (%s)", enabled ? "on" : "off");
     return bReturn;
   }
 
   m_bNeedsWrite = true;
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "turning autonomous mode %s", enabled ? "on" : "off");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "turning autonomous mode %s", enabled ? "on" : "off");
 
   CCECAdapterMessage params;
   params.PushEscaped(enabled ? 1 : 0);
@@ -248,12 +251,12 @@ bool CUSBCECAdapterCommands::SetSettingDeviceType(cec_device_type type)
   /* check whether this value was changed */
   if (m_persistedConfiguration.deviceTypes.types[0] == type)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "device type setting unchanged (%X)", (uint8_t)type);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "device type setting unchanged (%X)", (uint8_t)type);
     return bReturn;
   }
 
   m_bNeedsWrite = true;
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the device type to %X (previous: %X)", (uint8_t)type, (uint8_t)m_persistedConfiguration.deviceTypes.types[0]);
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the device type to %X (previous: %X)", (uint8_t)type, (uint8_t)m_persistedConfiguration.deviceTypes.types[0]);
 
   CCECAdapterMessage params;
   params.PushEscaped((uint8_t)type);
@@ -271,12 +274,12 @@ bool CUSBCECAdapterCommands::SetSettingDefaultLogicalAddress(cec_logical_address
   /* check whether this value was changed */
   if (m_persistedConfiguration.logicalAddresses.primary == address)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "logical address setting unchanged (%X)", (uint8_t)address);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address setting unchanged (%X)", (uint8_t)address);
     return bReturn;
   }
 
   m_bNeedsWrite = true;
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the default logical address to %X (previous: %X)", (uint8_t)address, (uint8_t)m_persistedConfiguration.logicalAddresses.primary);
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the default logical address to %X (previous: %X)", (uint8_t)address, (uint8_t)m_persistedConfiguration.logicalAddresses.primary);
 
   CCECAdapterMessage params;
   params.PushEscaped((uint8_t)address);
@@ -297,12 +300,12 @@ bool CUSBCECAdapterCommands::SetSettingLogicalAddressMask(uint16_t iMask)
   /* check whether this value was changed */
   if (m_iSettingLAMask == iMask)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "logical address mask setting unchanged (%2X)", iMask);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address mask setting unchanged (%2X)", iMask);
     return bReturn;
   }
 
   m_bNeedsWrite = true;
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the logical address mask to %2X (previous: %2X)", iMask, m_iSettingLAMask);
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the logical address mask to %2X (previous: %2X)", iMask, m_iSettingLAMask);
 
   CCECAdapterMessage params;
   params.PushEscaped(iMask >> 8);
@@ -324,12 +327,12 @@ bool CUSBCECAdapterCommands::SetSettingPhysicalAddress(uint16_t iPhysicalAddress
   /* check whether this value was changed */
   if (m_persistedConfiguration.iPhysicalAddress == iPhysicalAddress)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "physical address setting unchanged (%04X)", iPhysicalAddress);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "physical address setting unchanged (%04X)", iPhysicalAddress);
     return bReturn;
   }
 
   m_bNeedsWrite = true;
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the physical address to %04X (previous: %04X)", iPhysicalAddress, m_persistedConfiguration.iPhysicalAddress);
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the physical address to %04X (previous: %04X)", iPhysicalAddress, m_persistedConfiguration.iPhysicalAddress);
 
   CCECAdapterMessage params;
   params.PushEscaped(iPhysicalAddress >> 8);
@@ -351,12 +354,12 @@ bool CUSBCECAdapterCommands::SetSettingCECVersion(cec_version version)
   /* check whether this value was changed */
   if (m_settingCecVersion == version)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "CEC version setting unchanged (%s)", CLibCEC::GetInstance()->ToString(version));
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "CEC version setting unchanged (%s)", ToString(version));
     return bReturn;
   }
 
   m_bNeedsWrite = true;
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the CEC version to %s (previous: %s)", CLibCEC::GetInstance()->ToString(version), CLibCEC::GetInstance()->ToString(m_settingCecVersion));
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the CEC version to %s (previous: %s)", ToString(version), ToString(m_settingCecVersion));
 
   CCECAdapterMessage params;
   params.PushEscaped((uint8_t)version);
@@ -377,11 +380,11 @@ bool CUSBCECAdapterCommands::SetSettingOSDName(const char *strOSDName)
   /* check whether this value was changed */
   if (!strcmp(m_persistedConfiguration.strDeviceName, strOSDName))
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "OSD name setting unchanged (%s)", strOSDName);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "OSD name setting unchanged (%s)", strOSDName);
     return bReturn;
   }
 
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the OSD name to %s (previous: %s)", strOSDName, m_persistedConfiguration.strDeviceName);
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the OSD name to %s (previous: %s)", strOSDName, m_persistedConfiguration.strDeviceName);
 
   CCECAdapterMessage params;
   for (size_t iPtr = 0; iPtr < strlen(strOSDName); iPtr++)
@@ -401,7 +404,7 @@ bool CUSBCECAdapterCommands::WriteEEPROM(void)
   if (!m_bNeedsWrite)
     return true;
 
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "writing settings in the EEPROM");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "writing settings in the EEPROM");
 
   CCECAdapterMessage params;
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_WRITE_EEPROM, params);
@@ -434,7 +437,7 @@ bool CUSBCECAdapterCommands::RequestSettings(void)
 {
   if (m_persistedConfiguration.iFirmwareVersion < 2)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - firmware version %d does not have any eeprom settings", __FUNCTION__, m_persistedConfiguration.iFirmwareVersion);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - firmware version %d does not have any eeprom settings", __FUNCTION__, m_persistedConfiguration.iFirmwareVersion);
     // settings can only be persisted with firmware v2+
     return false;
   }
@@ -491,7 +494,7 @@ bool CUSBCECAdapterCommands::GetConfiguration(libcec_configuration *configuratio
 
 bool CUSBCECAdapterCommands::PingAdapter(void)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "sending ping");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending ping");
 
   CCECAdapterMessage params;
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_PING, params);
@@ -502,7 +505,7 @@ bool CUSBCECAdapterCommands::PingAdapter(void)
 
 bool CUSBCECAdapterCommands::SetAckMask(uint16_t iMask)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "setting ackmask to %2x", iMask);
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting ackmask to %2x", iMask);
 
   CCECAdapterMessage params;
   params.PushEscaped(iMask >> 8);
@@ -515,7 +518,7 @@ bool CUSBCECAdapterCommands::SetAckMask(uint16_t iMask)
 
 bool CUSBCECAdapterCommands::StartBootloader(void)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "starting the bootloader");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "starting the bootloader");
 
   CCECAdapterMessage params;
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_START_BOOTLOADER, params);
@@ -526,7 +529,7 @@ bool CUSBCECAdapterCommands::StartBootloader(void)
 
 bool CUSBCECAdapterCommands::SetLineTimeout(uint8_t iTimeout)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "setting the line timeout to %d", iTimeout);
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting the line timeout to %d", iTimeout);
   CCECAdapterMessage params;
   params.PushEscaped(iTimeout);
   CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_TRANSMIT_IDLETIME, params);
@@ -537,7 +540,7 @@ bool CUSBCECAdapterCommands::SetLineTimeout(uint8_t iTimeout)
 
 bool CUSBCECAdapterCommands::SetControlledMode(bool controlled)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "turning controlled mode %s", controlled ? "on" : "off");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "turning controlled mode %s", controlled ? "on" : "off");
 
   CCECAdapterMessage params;
   params.PushEscaped(controlled ? 1 : 0);
index 6c548b00ad2eab495083b57ed76295c290b1d71d..b08801fae211a27d4756a586efb673e0c16f7d46 100644 (file)
@@ -49,6 +49,8 @@ using namespace PLATFORM;
 // firmware date Thu Apr 26 20:14:49 2012 +0000
 #define CEC_LATEST_ADAPTER_FW_DATE    0x4F99ACB9
 
+#define LIB_CEC m_callback->GetLib()
+
 CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCallback *callback, const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */) :
     IAdapterCommunication(callback),
     m_port(NULL),
@@ -57,7 +59,8 @@ CUSBCECAdapterCommunication::CUSBCECAdapterCommunication(IAdapterCommunicationCa
     m_bInitialised(false),
     m_pingThread(NULL),
     m_commands(NULL),
-    m_adapterMessageQueue(NULL)
+    m_adapterMessageQueue(NULL),
+    m_iAckMask(0xFFFF)
 {
   for (unsigned int iPtr = CECDEVICE_TV; iPtr < CECDEVICE_BROADCAST; iPtr++)
     m_bWaitingForAck[iPtr] = false;
@@ -81,14 +84,14 @@ bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONN
     /* we need the port settings here */
     if (!m_port)
     {
-      CLibCEC::AddLog(CEC_LOG_ERROR, "port is NULL");
+      LIB_CEC->AddLog(CEC_LOG_ERROR, "port is NULL");
       return bConnectionOpened;
     }
 
     /* return true when the port is already open */
     if (IsOpen())
     {
-      CLibCEC::AddLog(CEC_LOG_WARNING, "port is already open");
+      LIB_CEC->AddLog(CEC_LOG_WARNING, "port is already open");
       return true;
     }
 
@@ -118,23 +121,23 @@ bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONN
     /* return false when we couldn't connect */
     if (!bConnectionOpened)
     {
-      CLibCEC::AddLog(CEC_LOG_ERROR, strError);
+      LIB_CEC->AddLog(CEC_LOG_ERROR, strError);
       return false;
     }
 
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "connection opened, clearing any previous input and waiting for active transmissions to end before starting");
     ClearInputBytes();
   }
 
   if (!CreateThread())
   {
     bConnectionOpened = false;
-    CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a communication thread");
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "could not create a communication thread");
   }
   else if (!bSkipChecks && !CheckAdapter())
   {
     bConnectionOpened = false;
-    CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter failed to pass basic checks");
   }
   else if (bStartListening)
   {
@@ -148,7 +151,7 @@ bool CUSBCECAdapterCommunication::Open(uint32_t iTimeoutMs /* = CEC_DEFAULT_CONN
     else
     {
       bConnectionOpened = false;
-      CLibCEC::AddLog(CEC_LOG_ERROR, "could not create a ping thread");
+      LIB_CEC->AddLog(CEC_LOG_ERROR, "could not create a ping thread");
     }
   }
 
@@ -168,7 +171,7 @@ void CUSBCECAdapterCommunication::Close(void)
   /* set the ackmask to 0 before closing the connection */
   if (IsRunning() && m_port->IsOpen() && m_port->GetErrorNumber() == 0)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - closing the connection", __FUNCTION__);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - closing the connection", __FUNCTION__);
     SetAckMask(0);
     if (m_commands->GetFirmwareVersion() >= 2)
       SetControlledMode(false);
@@ -187,7 +190,7 @@ void CUSBCECAdapterCommunication::Close(void)
     m_port->Close();
 
   libcec_parameter param;
-  CLibCEC::Alert(CEC_ALERT_CONNECTION_LOST, param);
+  LIB_CEC->Alert(CEC_ALERT_CONNECTION_LOST, param);
 }
 
 cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &data, bool &bRetry, uint8_t iLineTimeout)
@@ -214,7 +217,7 @@ cec_adapter_message_state CUSBCECAdapterCommunication::Write(const cec_command &
 void *CUSBCECAdapterCommunication::Process(void)
 {
   CCECAdapterMessage msg;
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread started");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "communication thread started");
 
   while (!IsStopped())
   {
@@ -227,7 +230,7 @@ void *CUSBCECAdapterCommunication::Process(void)
   }
 
   m_adapterMessageQueue->Clear();
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "communication thread ended");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "communication thread ended");
   return NULL;
 }
 
@@ -310,7 +313,7 @@ bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage *message)
   CLockObject adapterLock(m_mutex);
   if (!m_port->IsOpen())
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': the connection is closed", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str());
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': the connection is closed", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str());
     message->state = ADAPTER_MESSAGE_STATE_ERROR;
     return false;
   }
@@ -318,13 +321,13 @@ bool CUSBCECAdapterCommunication::WriteToDevice(CCECAdapterMessage *message)
   /* write the message */
   if (m_port->Write(message->packet.data, message->Size()) != (ssize_t) message->Size())
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': %s", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str(), m_port->GetError().c_str());
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "error writing command '%s' to serial port '%s': %s", CCECAdapterMessage::ToString(message->Message()), m_port->GetName().c_str(), m_port->GetError().c_str());
     message->state = ADAPTER_MESSAGE_STATE_ERROR;
     Close();
     return false;
   }
 
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "command '%s' sent", message->IsTranmission() ? "CEC transmission" : CCECAdapterMessage::ToString(message->Message()));
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "command '%s' sent", message->IsTranmission() ? "CEC transmission" : CCECAdapterMessage::ToString(message->Message()));
   message->state = ADAPTER_MESSAGE_STATE_SENT;
   return true;
 }
@@ -346,7 +349,7 @@ bool CUSBCECAdapterCommunication::ReadFromDevice(uint32_t iTimeout, size_t iSize
 
     if (m_port->GetErrorNumber())
     {
-      CLibCEC::AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
+      LIB_CEC->AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str());
       m_port->Close();
       return false;
     }
@@ -391,7 +394,7 @@ CCECAdapterMessage *CUSBCECAdapterCommunication::SendCommand(cec_adapter_message
       /* if the controller reported that the command was rejected, and we didn't send the command
          to set controlled mode, then the controller probably switched to auto mode. set controlled
          mode and retry */
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "setting controlled mode and retrying");
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting controlled mode and retrying");
       delete output;
       if (SetControlledMode(true))
         return SendCommand(msgCode, params, true);
@@ -411,7 +414,7 @@ bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = CEC_DEFA
   unsigned iPingTry(0);
   while (timeout.TimeLeft() > 0 && (bPinged = PingAdapter()) == false)
   {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry);
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to a ping (try %d)", ++iPingTry);
     CEvent::Sleep(500);
   }
 
@@ -423,7 +426,7 @@ bool CUSBCECAdapterCommunication::CheckAdapter(uint32_t iTimeoutMs /* = CEC_DEFA
     bool bControlled(false);
     while (timeout.TimeLeft() > 0 && (bControlled = SetControlledMode(true)) == false)
     {
-      CLibCEC::AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry);
+      LIB_CEC->AddLog(CEC_LOG_ERROR, "the adapter did not respond correctly to setting controlled mode (try %d)", ++iControlledTry);
       CEvent::Sleep(500);
     }
     bReturn = bControlled;
@@ -473,7 +476,21 @@ bool CUSBCECAdapterCommunication::StartBootloader(void)
 
 bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
 {
-  return m_port->IsOpen() ? m_commands->SetAckMask(iMask) : false;
+  if (m_iAckMask == iMask)
+    return true;
+
+  if (m_port && m_port->IsOpen() && m_commands->SetAckMask(iMask))
+  {
+    m_iAckMask = iMask;
+    return true;
+  }
+
+  return false;
+}
+
+uint16_t CUSBCECAdapterCommunication::GetAckMask(void)
+{
+  return m_iAckMask;
 }
 
 bool CUSBCECAdapterCommunication::PingAdapter(void)
@@ -546,7 +563,7 @@ void *CAdapterPingThread::Process(void)
       if (iFailedCounter == 3)
       {
         /* failed to ping the adapter 3 times in a row. something must be wrong with the connection */
-        CLibCEC::AddLog(CEC_LOG_ERROR, "failed to ping the adapter 3 times in a row. closing the connection.");
+        m_com->LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to ping the adapter 3 times in a row. closing the connection.");
         m_com->StopThread(false);
         break;
       }
index cfe294480495033b71e96ddb4e580e552d57c226..8d8476ab235e44b0e3ac130cefc0d054d32a4403 100644 (file)
@@ -74,6 +74,7 @@ namespace CEC
 
     bool StartBootloader(void);
     bool SetAckMask(uint16_t iMask);
+    uint16_t GetAckMask(void);
     bool PingAdapter(void);
     uint16_t GetFirmwareVersion(void);
     uint32_t GetFirmwareBuildDate(void);
@@ -165,6 +166,7 @@ namespace CEC
     CAdapterPingThread *                         m_pingThread;           /**< ping thread, that pings the adapter every 15 seconds */
     CUSBCECAdapterCommands *                     m_commands;             /**< commands that can be sent to the adapter */
     CCECAdapterMessageQueue *                    m_adapterMessageQueue;  /**< the incoming and outgoing message queue */
+    uint16_t                                     m_iAckMask;
   };
 
   class CAdapterPingThread : public PLATFORM::CThread
index aef61b2b924f0652129de7b7688f6a62f404d393..8ef5662fdf560e56ac33c4b35fe24d457a706427 100644 (file)
@@ -298,7 +298,7 @@ bool CCECAdapterMessage::PushReceivedByte(uint8_t byte)
   {
     if (HasStartMessage())
     {
-      CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
+      //TODO CLibCEC::AddLog(CEC_LOG_WARNING, "received MSGSTART before MSGEND, removing previous buffer contents");
       Clear();
     }
     PushBack(byte);
index a270a78235792a39a81a6fd746088c7155cea175..45b348c8752af10aed323f993fc118fd918a6c45 100644 (file)
@@ -41,7 +41,8 @@ using namespace std;
 
 #define MESSAGE_QUEUE_SIGNAL_WAIT_TIME 1000
 
-CCECAdapterMessageQueueEntry::CCECAdapterMessageQueueEntry(CCECAdapterMessage *message) :
+CCECAdapterMessageQueueEntry::CCECAdapterMessageQueueEntry(CCECAdapterMessageQueue *queue, CCECAdapterMessage *message) :
+    m_queue(queue),
     m_message(message),
     m_iPacketsLeft(message->IsTranmission() ? message->Size() / 4 : 1),
     m_bSucceeded(false),
@@ -150,7 +151,7 @@ bool CCECAdapterMessageQueueEntry::MessageReceivedCommandAccepted(const CCECAdap
       strLog.Format("%s - command accepted", ToString());
       if (m_iPacketsLeft > 0)
         strLog.AppendFormat(" - waiting for %d more", m_iPacketsLeft);
-      CLibCEC::AddLog(CEC_LOG_DEBUG, strLog);
+      m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, strLog);
 
       /* no more packets left and not a transmission, so we're done */
       if (!m_message->IsTranmission() && m_iPacketsLeft == 0)
@@ -176,7 +177,7 @@ bool CCECAdapterMessageQueueEntry::MessageReceivedTransmitSucceeded(const CCECAd
     if (m_iPacketsLeft == 0)
     {
       /* transmission succeeded, so we're done */
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - transmit succeeded", ToString());
+      m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "%s - transmit succeeded", ToString());
       m_message->state = ADAPTER_MESSAGE_STATE_SENT_ACKED;
       m_message->response = message.packet;
     }
@@ -184,7 +185,7 @@ bool CCECAdapterMessageQueueEntry::MessageReceivedTransmitSucceeded(const CCECAd
     {
       /* error, we expected more acks
          since the messages are processed in order, this should not happen, so this is an error situation */
-      CLibCEC::AddLog(CEC_LOG_WARNING, "%s - received 'transmit succeeded' but not enough 'command accepted' messages (%d left)", ToString(), m_iPacketsLeft);
+      m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_WARNING, "%s - received 'transmit succeeded' but not enough 'command accepted' messages (%d left)", ToString(), m_iPacketsLeft);
       m_message->state = ADAPTER_MESSAGE_STATE_ERROR;
     }
   }
@@ -198,7 +199,7 @@ bool CCECAdapterMessageQueueEntry::MessageReceivedResponse(const CCECAdapterMess
 {
   {
     CLockObject lock(m_mutex);
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s - received response - %s", ToString(), message.ToString().c_str());
+    m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "%s - received response - %s", ToString(), message.ToString().c_str());
     m_message->response = message.packet;
     if (m_message->IsTranmission())
       m_message->state = message.Message() == MSGCODE_TRANSMIT_SUCCEEDED ? ADAPTER_MESSAGE_STATE_SENT_ACKED : ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
@@ -263,7 +264,7 @@ void CCECAdapterMessageQueue::MessageReceived(const CCECAdapterMessage &msg)
   {
     /* the message wasn't handled */
     bool bIsError(m_com->HandlePoll(msg));
-    CLibCEC::AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
+    m_com->m_callback->GetLib()->AddLog(bIsError ? CEC_LOG_WARNING : CEC_LOG_DEBUG, msg.ToString());
 
     /* push this message to the current frame */
     if (!bIsError && msg.PushToCecCommand(m_currentCECFrame))
@@ -312,7 +313,7 @@ bool CCECAdapterMessageQueue::Write(CCECAdapterMessage *msg)
     m_com->SetLineTimeout(msg->lineTimeout);
   }
 
-  CCECAdapterMessageQueueEntry *entry = new CCECAdapterMessageQueueEntry(msg);
+  CCECAdapterMessageQueueEntry *entry = new CCECAdapterMessageQueueEntry(this, msg);
   uint64_t iEntryId(0);
   /* add to the wait for ack queue */
   if (msg->Message() != MSGCODE_START_BOOTLOADER)
@@ -330,7 +331,7 @@ bool CCECAdapterMessageQueue::Write(CCECAdapterMessage *msg)
   {
     if (!entry->Wait(msg->transmit_timeout <= 5 ? CEC_DEFAULT_TRANSMIT_WAIT : msg->transmit_timeout))
     {
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "command '%s' was not acked by the controller", CCECAdapterMessage::ToString(msg->Message()));
+      m_com->m_callback->GetLib()->AddLog(CEC_LOG_DEBUG, "command '%s' was not acked by the controller", CCECAdapterMessage::ToString(msg->Message()));
       msg->state = ADAPTER_MESSAGE_STATE_SENT_NOT_ACKED;
       bReturn = false;
     }
index e476e26660382a9359d12fc822054d99114e9c10..4646fe497cdeb7a56883ad291ed877ad8fb050d1 100644 (file)
 namespace CEC
 {
   class CUSBCECAdapterCommunication;
+  class CCECAdapterMessageQueue;
 
   class CCECAdapterMessageQueueEntry
   {
   public:
-    CCECAdapterMessageQueueEntry(CCECAdapterMessage *message);
+    CCECAdapterMessageQueueEntry(CCECAdapterMessageQueue *queue, CCECAdapterMessage *message);
     virtual ~CCECAdapterMessageQueueEntry(void);
 
     /*!
@@ -112,6 +113,7 @@ namespace CEC
      */
     void Signal(void);
 
+    CCECAdapterMessageQueue *  m_queue;
     CCECAdapterMessage *       m_message;      /**< the message that was sent */
     uint8_t                    m_iPacketsLeft; /**< the amount of acks that we're waiting on */
     bool                       m_bSucceeded;   /**< true when the command received a response, false otherwise */
@@ -123,6 +125,7 @@ namespace CEC
   class CCECAdapterMessageQueue : public PLATFORM::CThread
   {
     friend class CUSBCECAdapterCommunication;
+    friend class CCECAdapterMessageQueueEntry;
 
   public:
     /*!
index 7e33597a7a974b0dbd0b778465a97540033f4f7d..d3c674c5265f57c321fd65db0f853d0a3f4f716c 100644 (file)
@@ -38,7 +38,8 @@
 using namespace CEC;
 using namespace PLATFORM;
 
-#define ToString(p) m_processor->ToString(p)
+#define LIB_CEC     m_processor->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
 
 CCECAudioSystem::CCECAudioSystem(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
     CCECBusDevice(processor, address, iPhysicalAddress),
@@ -53,7 +54,7 @@ bool CCECAudioSystem::SetAudioStatus(uint8_t status)
   CLockObject lock(m_mutex);
   if (m_audioStatus != status)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): audio status changed from %2x to %2x", GetLogicalAddressName(), m_iLogicalAddress, m_audioStatus, status);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): audio status changed from %2x to %2x", GetLogicalAddressName(), m_iLogicalAddress, m_audioStatus, status);
     m_audioStatus = status;
     return true;
   }
@@ -66,7 +67,7 @@ bool CCECAudioSystem::SetSystemAudioModeStatus(const cec_system_audio_status mod
   CLockObject lock(m_mutex);
   if (m_systemAudioStatus != mode)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): system audio mode status changed from %s to %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_systemAudioStatus), ToString(mode));
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): system audio mode status changed from %s to %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_systemAudioStatus), ToString(mode));
     m_systemAudioStatus = mode;
     return true;
   }
@@ -79,7 +80,7 @@ bool CCECAudioSystem::TransmitAudioStatus(cec_logical_address dest)
   uint8_t state;
   {
     CLockObject lock(m_mutex);
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %x -> %x: audio status '%2x'", m_iLogicalAddress, dest, m_audioStatus);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %x -> %x: audio status '%2x'", m_iLogicalAddress, dest, m_audioStatus);
     state = m_audioStatus;
   }
 
@@ -91,7 +92,7 @@ bool CCECAudioSystem::TransmitSetSystemAudioMode(cec_logical_address dest)
   cec_system_audio_status state;
   {
     CLockObject lock(m_mutex);
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %x -> %x: set system audio mode '%2x'", m_iLogicalAddress, dest, m_audioStatus);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %x -> %x: set system audio mode '%2x'", m_iLogicalAddress, dest, m_audioStatus);
     state = m_systemAudioStatus;
   }
 
@@ -103,35 +104,37 @@ bool CCECAudioSystem::TransmitSystemAudioModeStatus(cec_logical_address dest)
   cec_system_audio_status state;
   {
     CLockObject lock(m_mutex);
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %x -> %x: system audio mode '%s'", m_iLogicalAddress, dest, ToString(m_systemAudioStatus));
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %x -> %x: system audio mode '%s'", m_iLogicalAddress, dest, ToString(m_systemAudioStatus));
     state = m_systemAudioStatus;
   }
 
   return m_handler->TransmitSystemAudioModeStatus(m_iLogicalAddress, dest, state);
 }
 
-uint8_t CCECAudioSystem::VolumeUp(bool bSendRelease /* = true */)
+uint8_t CCECAudioSystem::VolumeUp(const cec_logical_address source, bool bSendRelease /* = true */)
 {
-  if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_UP) && bSendRelease)
-    TransmitKeyRelease();
+  TransmitKeypress(source, CEC_USER_CONTROL_CODE_VOLUME_UP);
+  if (bSendRelease)
+    TransmitKeyRelease(source);
 
   CLockObject lock(m_mutex);
   return m_audioStatus;
 }
 
-uint8_t CCECAudioSystem::VolumeDown(bool bSendRelease /* = true */)
+uint8_t CCECAudioSystem::VolumeDown(const cec_logical_address source, bool bSendRelease /* = true */)
 {
-  if (TransmitKeypress(CEC_USER_CONTROL_CODE_VOLUME_DOWN) && bSendRelease)
-    TransmitKeyRelease();
+  TransmitKeypress(source, CEC_USER_CONTROL_CODE_VOLUME_DOWN);
+  if (bSendRelease)
+    TransmitKeyRelease(source);
 
   CLockObject lock(m_mutex);
   return m_audioStatus;
 }
 
-uint8_t CCECAudioSystem::MuteAudio(bool bSendRelease /* = true */)
+uint8_t CCECAudioSystem::MuteAudio(const cec_logical_address source)
 {
-  if (TransmitKeypress(CEC_USER_CONTROL_CODE_MUTE) && bSendRelease)
-    TransmitKeyRelease();
+  TransmitKeypress(source, CEC_USER_CONTROL_CODE_MUTE);
+  TransmitKeyRelease(source);
 
   CLockObject lock(m_mutex);
   return m_audioStatus;
index a340ad88ce8541d302ab1ad1fdb9e6c8554493a8..e2e3cd219030f0aa2c85ffa587321f499062fa58 100644 (file)
@@ -47,9 +47,9 @@ namespace CEC
     bool TransmitSetSystemAudioMode(cec_logical_address dest);
     bool TransmitSystemAudioModeStatus(cec_logical_address dest);
 
-    uint8_t VolumeUp(bool bSendRelease = true);
-    uint8_t VolumeDown(bool bSendRelease = true);
-    uint8_t MuteAudio(bool bSendRelease = true);
+    uint8_t VolumeUp(const cec_logical_address source, bool bSendRelease = true);
+    uint8_t VolumeDown(const cec_logical_address source, bool bSendRelease = true);
+    uint8_t MuteAudio(const cec_logical_address source);
 
     bool TransmitActiveSource(void) { return false; }
 
index 7e63a67ff8808d6da91a3835a4a590cccd68d65b..ca66a464e1d2c7da17a2cf5b045420cae2dabfda 100644 (file)
 #include "../LibCEC.h"
 #include "../platform/util/timeutils.h"
 
+#include "CECAudioSystem.h"
+#include "CECPlaybackDevice.h"
+#include "CECRecordingDevice.h"
+#include "CECTuner.h"
+#include "CECTV.h"
+
+using namespace std;
 using namespace CEC;
 using namespace PLATFORM;
 
-#define ToString(p) m_processor->ToString(p)
+#define LIB_CEC     m_processor->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
 
 CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
   m_type                  (CEC_DEVICE_TYPE_RESERVED),
@@ -78,6 +86,62 @@ CCECBusDevice::~CCECBusDevice(void)
   delete m_handler;
 }
 
+bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
+{
+  bool bInitHandler(false);
+  {
+    CTryLockObject lock(m_mutex);
+    if (!lock.IsLocked())
+      return false;
+
+    CLockObject handlerLock(m_handlerMutex);
+    if (m_iHandlerUseCount > 0)
+      return false;
+
+    MarkBusy();
+
+    if (m_vendor != m_handler->GetVendorId())
+    {
+      if (CCECCommandHandler::HasSpecificHandler(m_vendor))
+      {
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
+        delete m_handler;
+
+        switch (m_vendor)
+        {
+        case CEC_VENDOR_SAMSUNG:
+          m_handler = new CANCommandHandler(this);
+          break;
+        case CEC_VENDOR_LG:
+          m_handler = new CSLCommandHandler(this);
+          break;
+        case CEC_VENDOR_PANASONIC:
+          m_handler = new CVLCommandHandler(this);
+          break;
+        default:
+          m_handler = new CCECCommandHandler(this);
+          break;
+        }
+
+        m_handler->SetVendorId(m_vendor);
+        bInitHandler = true;
+      }
+    }
+  }
+
+  if (bInitHandler)
+  {
+    m_handler->InitHandler();
+
+    if (bActivateSource && IsHandledByLibCEC() && IsActiveSource())
+      m_handler->ActivateSource();
+  }
+
+  MarkReady();
+
+  return true;
+}
+
 bool CCECBusDevice::HandleCommand(const cec_command &command)
 {
   bool bHandled(false);
@@ -98,13 +162,13 @@ bool CCECBusDevice::HandleCommand(const cec_command &command)
   bHandled = m_handler->HandleCommand(command);
 
   /* change status to present */
-  if (bHandled)
+  if (bHandled && GetLogicalAddress() != CECDEVICE_BROADCAST)
   {
     CLockObject lock(m_mutex);
     if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
     {
       if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT)
-        CLibCEC::AddLog(CEC_LOG_DEBUG, "device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
       m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
     }
   }
@@ -113,44 +177,76 @@ bool CCECBusDevice::HandleCommand(const cec_command &command)
   return bHandled;
 }
 
-bool CCECBusDevice::PowerOn(void)
+const char* CCECBusDevice::GetLogicalAddressName(void) const
 {
-  bool bReturn(false);
-  GetVendorId(); // ensure that we got the vendor id, because the implementations vary per vendor
+  return ToString(m_iLogicalAddress);
+}
+
+bool CCECBusDevice::IsPresent(void)
+{
+  CLockObject lock(m_mutex);
+  return m_deviceStatus == CEC_DEVICE_STATUS_PRESENT;
+}
+
+bool CCECBusDevice::IsHandledByLibCEC(void)
+{
+  CLockObject lock(m_mutex);
+  return m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC;
+}
+
+void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
+{
+  // some commands should never be marked as unsupported
+  if (opcode == CEC_OPCODE_VENDOR_COMMAND ||
+      opcode == CEC_OPCODE_VENDOR_COMMAND_WITH_ID ||
+      opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN ||
+      opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP ||
+      opcode == CEC_OPCODE_ABORT ||
+      opcode == CEC_OPCODE_FEATURE_ABORT ||
+      opcode == CEC_OPCODE_NONE)
+    return;
 
-  MarkBusy();
-  cec_power_status currentStatus = GetPowerStatus(false);
-  if (currentStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
-    currentStatus != CEC_POWER_STATUS_ON)
   {
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-    if (m_handler->PowerOn(GetMyLogicalAddress(), m_iLogicalAddress))
+    CLockObject lock(m_mutex);
+    if (m_unsupportedFeatures.find(opcode) == m_unsupportedFeatures.end())
     {
-      SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
-      bReturn = true;
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking opcode '%s' as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
+      m_unsupportedFeatures.insert(opcode);
     }
   }
-  else
-  {
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
-  }
 
+  // signal threads that are waiting for a reponse
+  MarkBusy();
+  m_handler->SignalOpcode(cec_command::GetResponseOpcode(opcode));
+  MarkReady();
+}
+
+bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode)
+{
+  CLockObject lock(m_mutex);
+  bool bUnsupported = (m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end());
+  if (bUnsupported)
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "'%s' is marked as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
+  return bUnsupported;
+}
+
+bool CCECBusDevice::TransmitKeypress(const cec_logical_address initiator, cec_user_control_code key, bool bWait /* = true */)
+{
+  MarkBusy();
+  bool bReturn = m_handler->TransmitKeypress(initiator, m_iLogicalAddress, key, bWait);
   MarkReady();
   return bReturn;
 }
 
-bool CCECBusDevice::Standby(void)
+bool CCECBusDevice::TransmitKeyRelease(const cec_logical_address initiator, bool bWait /* = true */)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
   MarkBusy();
-  bool bReturn = m_handler->TransmitStandby(GetMyLogicalAddress(), m_iLogicalAddress);
+  bool bReturn = m_handler->TransmitKeyRelease(initiator, m_iLogicalAddress, bWait);
   MarkReady();
   return bReturn;
 }
 
-/** @name Getters */
-//@{
-cec_version CCECBusDevice::GetCecVersion(bool bUpdate /* = false */)
+cec_version CCECBusDevice::GetCecVersion(const cec_logical_address initiator, bool bUpdate /* = false */)
 {
   bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
   bool bRequestUpdate(false);
@@ -162,51 +258,53 @@ cec_version CCECBusDevice::GetCecVersion(bool bUpdate /* = false */)
 
   if (bRequestUpdate)
   {
-    CheckVendorIdRequested();
-    RequestCecVersion();
+    CheckVendorIdRequested(initiator);
+    RequestCecVersion(initiator);
   }
 
   CLockObject lock(m_mutex);
   return m_cecVersion;
 }
 
-bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
+void CCECBusDevice::SetCecVersion(const cec_version newVersion)
 {
-  bool bReturn(false);
-
-  if (MyLogicalAddressContains(m_iLogicalAddress))
-  {
-    MarkBusy();
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting active source");
-
-    bReturn = m_handler->TransmitRequestActiveSource(GetMyLogicalAddress(), bWaitForResponse);
-    MarkReady();
-  }
-  return bReturn;
+  CLockObject lock(m_mutex);
+  if (m_cecVersion != newVersion)
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): CEC version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(newVersion));
+  m_cecVersion = newVersion;
 }
 
-bool CCECBusDevice::RequestCecVersion(bool bWaitForResponse /* = true */)
+bool CCECBusDevice::RequestCecVersion(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
 {
   bool bReturn(false);
 
-  if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+  if (!IsHandledByLibCEC() &&
       !IsUnsupportedFeature(CEC_OPCODE_GET_CEC_VERSION))
   {
     MarkBusy();
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-
-    bReturn = m_handler->TransmitRequestCecVersion(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    bReturn = m_handler->TransmitRequestCecVersion(initiator, m_iLogicalAddress, bWaitForResponse);
     MarkReady();
   }
   return bReturn;
 }
 
-const char* CCECBusDevice::GetLogicalAddressName(void) const
+bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination)
 {
-  return ToString(m_iLogicalAddress);
+  cec_version version;
+  {
+    CLockObject lock(m_mutex);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_cecVersion));
+    version = m_cecVersion;
+  }
+
+  MarkBusy();
+  bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, destination, version);
+  MarkReady();
+  return bReturn;
 }
 
-cec_menu_language &CCECBusDevice::GetMenuLanguage(bool bUpdate /* = false */)
+cec_menu_language &CCECBusDevice::GetMenuLanguage(const cec_logical_address initiator, bool bUpdate /* = false */)
 {
   bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
   bool bRequestUpdate(false);
@@ -218,46 +316,95 @@ cec_menu_language &CCECBusDevice::GetMenuLanguage(bool bUpdate /* = false */)
 
   if (bRequestUpdate)
   {
-    CheckVendorIdRequested();
-    RequestMenuLanguage();
+    CheckVendorIdRequested(initiator);
+    RequestMenuLanguage(initiator);
   }
 
   CLockObject lock(m_mutex);
   return m_menuLanguage;
 }
 
-bool CCECBusDevice::RequestMenuLanguage(bool bWaitForResponse /* = true */)
+void CCECBusDevice::SetMenuLanguage(const char *strLanguage)
+{
+  if (!strLanguage)
+    return;
+
+  CLockObject lock(m_mutex);
+  if (strcmp(strLanguage, m_menuLanguage.language))
+  {
+    memcpy(m_menuLanguage.language, strLanguage, 3);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu language set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, m_menuLanguage.language);
+  }
+}
+
+void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
+{
+  if (language.device == m_iLogicalAddress)
+    SetMenuLanguage(language.language);
+}
+
+bool CCECBusDevice::RequestMenuLanguage(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
 {
   bool bReturn(false);
 
-  if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+  if (!IsHandledByLibCEC() &&
       !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE))
   {
     MarkBusy();
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-    bReturn = m_handler->TransmitRequestMenuLanguage(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    bReturn = m_handler->TransmitRequestMenuLanguage(initiator, m_iLogicalAddress, bWaitForResponse);
     MarkReady();
   }
   return bReturn;
 }
 
-cec_menu_state CCECBusDevice::GetMenuState(void)
+bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destination)
 {
-  CLockObject lock(m_mutex);
-  return m_menuState;
-}
+  bool bReturn(false);
+  cec_menu_language language;
+  {
+    CLockObject lock(m_mutex);
+    language = m_menuLanguage;
+  }
 
-cec_logical_address CCECBusDevice::GetMyLogicalAddress(void) const
-{
-  return m_processor->GetLogicalAddress();
+  char lang[3];
+  {
+    CLockObject lock(m_mutex);
+    lang[0] = language.language[0];
+    lang[1] = language.language[1];
+    lang[2] = language.language[2];
+  }
+
+  MarkBusy();
+  if (lang[0] == '?' && lang[1] == '?' && lang[2] == '?')
+  {
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): Menu language feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
+    m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+    bReturn = true;
+  }
+  else
+  {
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): Menu language '%s'", GetLogicalAddressName(), m_iLogicalAddress, lang);
+    bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang);
+  }
+  MarkReady();
+  return bReturn;
 }
 
-uint16_t CCECBusDevice::GetMyPhysicalAddress(void) const
+bool CCECBusDevice::TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage)
 {
-  return m_processor->GetPhysicalAddress();
+  bool bReturn(false);
+  if (!m_processor->GetDevice(destination)->IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING))
+  {
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, strMessage);
+    MarkBusy();
+    bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, destination, duration, strMessage);
+    MarkReady();
+  }
+  return bReturn;
 }
 
-CStdString CCECBusDevice::GetOSDName(bool bUpdate /* = false */)
+CStdString CCECBusDevice::GetOSDName(const cec_logical_address initiator, bool bUpdate /* = false */)
 {
   bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
   bool bRequestUpdate(false);
@@ -270,30 +417,67 @@ CStdString CCECBusDevice::GetOSDName(bool bUpdate /* = false */)
 
   if (bRequestUpdate)
   {
-    CheckVendorIdRequested();
-    RequestOSDName();
+    CheckVendorIdRequested(initiator);
+    RequestOSDName(initiator);
   }
 
   CLockObject lock(m_mutex);
   return m_strDeviceName;
 }
 
-bool CCECBusDevice::RequestOSDName(bool bWaitForResponse /* = true */)
+void CCECBusDevice::SetOSDName(CStdString strName)
+{
+  CLockObject lock(m_mutex);
+  if (m_strDeviceName != strName)
+  {
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName.c_str());
+    m_strDeviceName = strName;
+  }
+}
+
+bool CCECBusDevice::RequestOSDName(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
 {
   bool bReturn(false);
 
-  if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+  if (!IsHandledByLibCEC() &&
       !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
   {
     MarkBusy();
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-    bReturn = m_handler->TransmitRequestOSDName(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    bReturn = m_handler->TransmitRequestOSDName(initiator, m_iLogicalAddress, bWaitForResponse);
     MarkReady();
   }
   return bReturn;
 }
 
-uint16_t CCECBusDevice::GetPhysicalAddress(bool bSuppressUpdate /* = true */)
+bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination)
+{
+  CStdString strDeviceName;
+  {
+    CLockObject lock(m_mutex);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, m_strDeviceName.c_str());
+    strDeviceName = m_strDeviceName;
+  }
+
+  MarkBusy();
+  bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName);
+  MarkReady();
+  return bReturn;
+}
+
+bool CCECBusDevice::HasValidPhysicalAddress(void)
+{
+  CLockObject lock(m_mutex);
+  return CLibCEC::IsValidPhysicalAddress(m_iPhysicalAddress);
+}
+
+uint16_t CCECBusDevice::GetCurrentPhysicalAddress(void)
+{
+  CLockObject lock(m_mutex);
+  return m_iPhysicalAddress;
+}
+
+uint16_t CCECBusDevice::GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate /* = false */)
 {
   if (!bSuppressUpdate)
   {
@@ -306,9 +490,9 @@ uint16_t CCECBusDevice::GetPhysicalAddress(bool bSuppressUpdate /* = true */)
 
     if (bRequestUpdate)
     {
-      CheckVendorIdRequested();
-      if (!RequestPhysicalAddress())
-        CLibCEC::AddLog(CEC_LOG_ERROR, "failed to request the physical address");
+      CheckVendorIdRequested(initiator);
+      if (!RequestPhysicalAddress(initiator))
+        LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to request the physical address");
     }
   }
 
@@ -316,21 +500,58 @@ uint16_t CCECBusDevice::GetPhysicalAddress(bool bSuppressUpdate /* = true */)
   return m_iPhysicalAddress;
 }
 
-bool CCECBusDevice::RequestPhysicalAddress(bool bWaitForResponse /* = true */)
+bool CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
+{
+  CLockObject lock(m_mutex);
+  if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
+  {
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
+    m_iPhysicalAddress = iNewAddress;
+  }
+  return true;
+}
+
+bool CCECBusDevice::RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
 {
   bool bReturn(false);
 
-  if (!MyLogicalAddressContains(m_iLogicalAddress))
+  if (!IsHandledByLibCEC())
   {
     MarkBusy();
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-    bReturn = m_handler->TransmitRequestPhysicalAddress(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    bReturn = m_handler->TransmitRequestPhysicalAddress(initiator, m_iLogicalAddress, bWaitForResponse);
     MarkReady();
   }
   return bReturn;
 }
 
-cec_power_status CCECBusDevice::GetPowerStatus(bool bUpdate /* = false */)
+bool CCECBusDevice::TransmitPhysicalAddress(void)
+{
+  uint16_t iPhysicalAddress;
+  cec_device_type type;
+  {
+    CLockObject lock(m_mutex);
+    if (m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS)
+      return false;
+
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+    iPhysicalAddress = m_iPhysicalAddress;
+    type = m_type;
+  }
+
+  MarkBusy();
+  bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
+  MarkReady();
+  return bReturn;
+}
+
+cec_power_status CCECBusDevice::GetCurrentPowerStatus(void)
+{
+  CLockObject lock(m_mutex);
+  return m_powerStatus;
+}
+
+cec_power_status CCECBusDevice::GetPowerStatus(const cec_logical_address initiator, bool bUpdate /* = false */)
 {
   bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
   bool bRequestUpdate(false);
@@ -345,55 +566,108 @@ cec_power_status CCECBusDevice::GetPowerStatus(bool bUpdate /* = false */)
 
   if (bRequestUpdate)
   {
-    CheckVendorIdRequested();
-    RequestPowerStatus();
+    CheckVendorIdRequested(initiator);
+    RequestPowerStatus(initiator);
   }
 
   CLockObject lock(m_mutex);
   return m_powerStatus;
 }
 
-bool CCECBusDevice::RequestPowerStatus(bool bWaitForResponse /* = true */)
+void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
+{
+  CLockObject lock(m_mutex);
+  if (m_powerStatus != powerStatus)
+  {
+    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(powerStatus));
+    m_powerStatus = powerStatus;
+  }
+}
+
+bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
 {
   bool bReturn(false);
 
-  if (!MyLogicalAddressContains(m_iLogicalAddress) &&
+  if (!IsHandledByLibCEC() &&
       !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
   {
     MarkBusy();
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-    bReturn = m_handler->TransmitRequestPowerStatus(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bWaitForResponse);
     MarkReady();
   }
   return bReturn;
 }
 
-cec_vendor_id CCECBusDevice::GetVendorId(bool bUpdate /* = false */)
+bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination)
 {
-  bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
-  bool bRequestUpdate(false);
+  cec_power_status state;
   {
     CLockObject lock(m_mutex);
-    bRequestUpdate = (bIsPresent &&
-        (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_powerStatus));
+    state = m_powerStatus;
   }
 
-  if (bRequestUpdate)
-    RequestVendorId();
-
-  CLockObject lock(m_mutex);
+  MarkBusy();
+  bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state);
+  MarkReady();
+  return bReturn;
+}
+
+cec_vendor_id CCECBusDevice::GetCurrentVendorId(void)
+{
+  CLockObject lock(m_mutex);
   return m_vendor;
 }
 
-bool CCECBusDevice::RequestVendorId(bool bWaitForResponse /* = true */)
+cec_vendor_id CCECBusDevice::GetVendorId(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+  bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+  bool bRequestUpdate(false);
+  {
+    CLockObject lock(m_mutex);
+    bRequestUpdate = (bIsPresent &&
+        (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
+  }
+
+  if (bRequestUpdate)
+    RequestVendorId(initiator);
+
+  CLockObject lock(m_mutex);
+  return m_vendor;
+}
+
+const char *CCECBusDevice::GetVendorName(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+  return ToString(GetVendorId(initiator, bUpdate));
+}
+
+bool CCECBusDevice::SetVendorId(uint64_t iVendorId)
+{
+  bool bVendorChanged(false);
+
+  {
+    CLockObject lock(m_mutex);
+    bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
+    m_vendor = (cec_vendor_id)iVendorId;
+  }
+
+  if (bVendorChanged)
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
+
+  return bVendorChanged;
+}
+
+bool CCECBusDevice::RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
 {
   bool bReturn(false);
 
-  if (!MyLogicalAddressContains(m_iLogicalAddress) && GetMyLogicalAddress() != CECDEVICE_UNKNOWN)
+  if (!IsHandledByLibCEC() && initiator != CECDEVICE_UNKNOWN)
   {
     MarkBusy();
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
-    bReturn = m_handler->TransmitRequestVendorId(GetMyLogicalAddress(), m_iLogicalAddress, bWaitForResponse);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    bReturn = m_handler->TransmitRequestVendorId(initiator, m_iLogicalAddress, bWaitForResponse);
     MarkReady();
 
     if (bWaitForResponse)
@@ -402,75 +676,32 @@ bool CCECBusDevice::RequestVendorId(bool bWaitForResponse /* = true */)
   return bReturn;
 }
 
-const char *CCECBusDevice::GetVendorName(bool bUpdate /* = false */)
-{
-  return ToString(GetVendorId(bUpdate));
-}
-
-bool CCECBusDevice::MyLogicalAddressContains(cec_logical_address address) const
+bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort /* = true */)
 {
-  return m_processor->HasLogicalAddress(address);
-}
+  bool bReturn(false);
+  uint64_t iVendorId;
+  {
+    CLockObject lock(m_mutex);
+    iVendorId = (uint64_t)m_vendor;
+  }
 
-bool CCECBusDevice::NeedsPoll(void)
-{
-  bool bSendPoll(false);
-  switch (m_iLogicalAddress)
+  MarkBusy();
+  if (iVendorId == CEC_VENDOR_UNKNOWN)
   {
-  case CECDEVICE_PLAYBACKDEVICE3:
-    {
-      cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_PLAYBACKDEVICE2]->GetStatus();
-      bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
-    }
-    break;
-  case CECDEVICE_PLAYBACKDEVICE2:
-    {
-      cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_PLAYBACKDEVICE1]->GetStatus();
-      bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
-    }
-    break;
-  case CECDEVICE_RECORDINGDEVICE3:
-    {
-      cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_RECORDINGDEVICE2]->GetStatus();
-      bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
-    }
-    break;
-  case CECDEVICE_RECORDINGDEVICE2:
-    {
-      cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_RECORDINGDEVICE1]->GetStatus();
-      bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
-    }
-    break;
-  case CECDEVICE_TUNER4:
-    {
-      cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_TUNER3]->GetStatus();
-      bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
-    }
-    break;
-  case CECDEVICE_TUNER3:
-    {
-      cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_TUNER2]->GetStatus();
-      bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
-    }
-    break;
-  case CECDEVICE_TUNER2:
+    if (bSendAbort)
     {
-      cec_bus_device_status status = m_processor->m_busDevices[CECDEVICE_TUNER1]->GetStatus();
-      bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+      LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
+      m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+      bReturn = true;
     }
-    break;
-  case CECDEVICE_AUDIOSYSTEM:
-  case CECDEVICE_PLAYBACKDEVICE1:
-  case CECDEVICE_RECORDINGDEVICE1:
-  case CECDEVICE_TUNER1:
-  case CECDEVICE_TV:
-    bSendPoll = true;
-    break;
-  default:
-    break;
   }
-
-  return bSendPoll;
+  else
+  {
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString((cec_vendor_id)iVendorId), iVendorId);
+    bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
+  }
+  MarkReady();
+  return bReturn;
 }
 
 cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bool bSuppressPoll /* = false */)
@@ -498,106 +729,6 @@ cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bo
   return status;
 }
 
-//@}
-
-/** @name Setters */
-//@{
-void CCECBusDevice::SetCecVersion(const cec_version newVersion)
-{
-  if (m_cecVersion != newVersion)
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s (%X): CEC version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(newVersion));
-  m_cecVersion = newVersion;
-}
-
-void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
-{
-  CLockObject lock(m_mutex);
-  if (language.device == m_iLogicalAddress &&
-      strcmp(language.language, m_menuLanguage.language))
-  {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu language set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, language.language);
-    m_menuLanguage = language;
-  }
-}
-
-void CCECBusDevice::SetOSDName(CStdString strName)
-{
-  CLockObject lock(m_mutex);
-  if (m_strDeviceName != strName)
-  {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName.c_str());
-    m_strDeviceName = strName;
-  }
-}
-
-void CCECBusDevice::SetMenuState(const cec_menu_state state)
-{
-  CLockObject lock(m_mutex);
-  if (m_menuState != state)
-  {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
-    m_menuState = state;
-  }
-}
-
-void CCECBusDevice::SetInactiveSource(void)
-{
-  {
-    CLockObject lock(m_mutex);
-    if (m_bActiveSource)
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
-    m_bActiveSource = false;
-  }
-}
-
-void CCECBusDevice::SetActiveSource(void)
-{
-  CLockObject lock(m_mutex);
-  if (!m_bActiveSource)
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
-  else
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
-
-  for (int iPtr = 0; iPtr < 16; iPtr++)
-    if (iPtr != m_iLogicalAddress)
-      m_processor->m_busDevices[iPtr]->SetInactiveSource();
-
-  m_bActiveSource = true;
-  SetPowerStatus(CEC_POWER_STATUS_ON);
-}
-
-bool CCECBusDevice::TryLogicalAddress(void)
-{
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
-
-  m_processor->SetAckMask(0);
-  if (!TransmitPoll(m_iLogicalAddress))
-  {
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
-    SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
-
-    return true;
-  }
-
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
-  SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
-  return false;
-}
-
-void CCECBusDevice::ResetDeviceStatus(void)
-{
-  CLockObject lock(m_mutex);
-  SetPowerStatus   (CEC_POWER_STATUS_UNKNOWN);
-  SetVendorId      (CEC_VENDOR_UNKNOWN);
-  SetMenuState     (CEC_MENU_STATE_ACTIVATED);
-  SetCecVersion    (CEC_VERSION_UNKNOWN);
-  SetStreamPath    (CEC_INVALID_PHYSICAL_ADDRESS);
-  SetOSDName       (ToString(m_iLogicalAddress));
-  SetInactiveSource();
-  m_iLastActive = 0;
-  m_unsupportedFeatures.clear();
-}
-
 void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
 {
   {
@@ -606,175 +737,190 @@ void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
     {
     case CEC_DEVICE_STATUS_UNKNOWN:
       if (m_deviceStatus != newStatus)
-        CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'unknown'", ToString(m_iLogicalAddress));
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'unknown'", ToString(m_iLogicalAddress));
       ResetDeviceStatus();
       m_deviceStatus = newStatus;
       break;
     case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
       if (m_deviceStatus != newStatus)
-        CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'handled by libCEC'", ToString(m_iLogicalAddress));
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'handled by libCEC'", ToString(m_iLogicalAddress));
       SetPowerStatus   (CEC_POWER_STATUS_ON);
       SetVendorId      (CEC_VENDOR_UNKNOWN);
       SetMenuState     (CEC_MENU_STATE_ACTIVATED);
       SetCecVersion    (CEC_VERSION_1_3A);
       SetStreamPath    (CEC_INVALID_PHYSICAL_ADDRESS);
-      SetInactiveSource();
+      MarkAsInactiveSource();
       m_iLastActive   = 0;
       m_deviceStatus  = newStatus;
       break;
     case CEC_DEVICE_STATUS_PRESENT:
       if (m_deviceStatus != newStatus)
-        CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'present'", ToString(m_iLogicalAddress));
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'present'", ToString(m_iLogicalAddress));
       m_deviceStatus = newStatus;
       break;
     case CEC_DEVICE_STATUS_NOT_PRESENT:
       if (m_deviceStatus != newStatus)
       {
-        CLibCEC::AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'not present'", ToString(m_iLogicalAddress));
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'not present'", ToString(m_iLogicalAddress));
         ResetDeviceStatus();
         m_deviceStatus = newStatus;
       }
       break;
     }
   }
-
-  if (newStatus == CEC_DEVICE_STATUS_PRESENT)
-    RequestVendorId(false);
 }
 
-void CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
+void CCECBusDevice::ResetDeviceStatus(void)
 {
   CLockObject lock(m_mutex);
-  if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
-  {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
-    m_iPhysicalAddress = iNewAddress;
-  }
+  SetPowerStatus   (CEC_POWER_STATUS_UNKNOWN);
+  SetVendorId      (CEC_VENDOR_UNKNOWN);
+  SetMenuState     (CEC_MENU_STATE_ACTIVATED);
+  SetCecVersion    (CEC_VERSION_UNKNOWN);
+  SetStreamPath    (CEC_INVALID_PHYSICAL_ADDRESS);
+  SetOSDName       (ToString(m_iLogicalAddress));
+  MarkAsInactiveSource();
+  m_iLastActive = 0;
+  m_bVendorIdRequested = false;
+  m_unsupportedFeatures.clear();
 }
 
-void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
+bool CCECBusDevice::TransmitPoll(const cec_logical_address dest)
 {
-  CLockObject lock(m_mutex);
-  if (iNewAddress != m_iStreamPath)
-  {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
-    m_iStreamPath = iNewAddress;
-  }
+  bool bReturn(false);
+  cec_logical_address destination(dest);
+  if (destination == CECDEVICE_UNKNOWN)
+    destination = m_iLogicalAddress;
 
-  CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
-  if (device)
+  CCECBusDevice *destDevice = m_processor->GetDevice(destination);
+  if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+    return bReturn;
+
+  MarkBusy();
+  LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
+  bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination);
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
+
+  CLockObject lock(m_mutex);
+  if (bReturn)
   {
-    // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
-    device->SetActiveSource();
+    m_iLastActive = GetTimeMs();
+    destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
   }
   else
+    destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
+
+  MarkReady();
+  return bReturn;
+}
+
+void CCECBusDevice::HandlePoll(const cec_logical_address destination)
+{
+  if (destination >= 0 && destination < CECDEVICE_BROADCAST)
   {
-    // try to find the device with the old address, and mark it as inactive when found
-    device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
+    CCECBusDevice *device = m_processor->GetDevice(destination);
     if (device)
-      device->SetInactiveSource();
+      device->HandlePollFrom(m_iLogicalAddress);
   }
 }
 
-void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
+void CCECBusDevice::HandlePollFrom(const cec_logical_address initiator)
 {
-  CLockObject lock(m_mutex);
-  if (m_powerStatus != powerStatus)
-  {
-    m_iLastPowerStateUpdate = GetTimeMs();
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
-    m_powerStatus = powerStatus;
-  }
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
+  m_bAwaitingReceiveFailed = true;
 }
 
-void CCECBusDevice::MarkBusy(void)
+bool CCECBusDevice::HandleReceiveFailed(void)
 {
-  CLockObject handlerLock(m_handlerMutex);
-  ++m_iHandlerUseCount;
+  bool bReturn = m_bAwaitingReceiveFailed;
+  m_bAwaitingReceiveFailed = false;
+  return bReturn;
 }
 
-void CCECBusDevice::MarkReady(void)
+cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
 {
-  CLockObject handlerLock(m_handlerMutex);
-  if (m_iHandlerUseCount > 0)
-    --m_iHandlerUseCount;
+  CLockObject lock(m_mutex);
+  return m_menuState;
 }
 
-bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
+void CCECBusDevice::SetMenuState(const cec_menu_state state)
 {
-  bool bInitHandler(false);
+  CLockObject lock(m_mutex);
+  if (m_menuState != state)
   {
-    CTryLockObject lock(m_mutex);
-    if (!lock.IsLocked())
-      return false;
-
-    CLockObject handlerLock(m_handlerMutex);
-    if (m_iHandlerUseCount > 0)
-      return false;
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
+    m_menuState = state;
+  }
+}
 
-    MarkBusy();
+bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest)
+{
+  cec_menu_state menuState;
+  {
+    CLockObject lock(m_mutex);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
+    menuState = m_menuState;
+  }
 
-    if (m_vendor != m_handler->GetVendorId())
-    {
-      if (CCECCommandHandler::HasSpecificHandler(m_vendor))
-      {
-        CLibCEC::AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
-        delete m_handler;
+  MarkBusy();
+  bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
+  MarkReady();
+  return bReturn;
+}
 
-        switch (m_vendor)
-        {
-        case CEC_VENDOR_SAMSUNG:
-          m_handler = new CANCommandHandler(this);
-          break;
-        case CEC_VENDOR_LG:
-          m_handler = new CSLCommandHandler(this);
-          break;
-        case CEC_VENDOR_PANASONIC:
-          m_handler = new CVLCommandHandler(this);
-          break;
-        default:
-          m_handler = new CCECCommandHandler(this);
-          break;
-        }
+bool CCECBusDevice::ActivateSource(void)
+{
+  MarkAsActiveSource();
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
+  MarkBusy();
+  bool bReturn = m_handler->ActivateSource();
+  MarkReady();
+  return bReturn;
+}
 
-        m_handler->SetVendorId(m_vendor);
-        bInitHandler = true;
-      }
-    }
-  }
+bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
+{
+  bool bReturn(false);
 
-  if (bInitHandler)
+  if (IsHandledByLibCEC())
   {
-    m_handler->InitHandler();
+    MarkBusy();
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting active source");
 
-    if (bActivateSource && m_processor->GetLogicalAddresses().IsSet(m_iLogicalAddress) && m_processor->IsInitialised() && IsActiveSource())
-      m_handler->ActivateSource();
+    bReturn = m_handler->TransmitRequestActiveSource(m_iLogicalAddress, bWaitForResponse);
+    MarkReady();
   }
+  return bReturn;
+}
 
-  MarkReady();
+void CCECBusDevice::MarkAsActiveSource(void)
+{
+  CLockObject lock(m_mutex);
+  if (!m_bActiveSource)
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
+  else
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
 
-  return true;
+  CECDEVICEVEC devices;
+  m_processor->GetDevices()->Get(devices);
+  for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
+    if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
+      (*it)->MarkAsInactiveSource();
+
+  m_bActiveSource = true;
+  SetPowerStatus(CEC_POWER_STATUS_ON);
 }
 
-bool CCECBusDevice::SetVendorId(uint64_t iVendorId)
+void CCECBusDevice::MarkAsInactiveSource(void)
 {
-  bool bVendorChanged(false);
-
   {
     CLockObject lock(m_mutex);
-    bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
-    m_vendor = (cec_vendor_id)iVendorId;
+    if (m_bActiveSource)
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+    m_bActiveSource = false;
   }
-
-  if (bVendorChanged)
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
-
-  return bVendorChanged;
 }
-//@}
 
-/** @name Transmit methods */
-//@{
 bool CCECBusDevice::TransmitActiveSource(void)
 {
   bool bSendActiveSource(false);
@@ -782,14 +928,14 @@ bool CCECBusDevice::TransmitActiveSource(void)
   {
     CLockObject lock(m_mutex);
     if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
     else if (m_bActiveSource)
     {
-      CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+      LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
       bSendActiveSource = true;
     }
     else
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
   }
 
   if (bSendActiveSource)
@@ -803,28 +949,13 @@ bool CCECBusDevice::TransmitActiveSource(void)
   return false;
 }
 
-bool CCECBusDevice::TransmitCECVersion(cec_logical_address dest)
-{
-  cec_version version;
-  {
-    CLockObject lock(m_mutex);
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_cecVersion));
-    version = m_cecVersion;
-  }
-
-  MarkBusy();
-  bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, dest, version);
-  MarkReady();
-  return bReturn;
-}
-
 bool CCECBusDevice::TransmitImageViewOn(void)
 {
   {
     CLockObject lock(m_mutex);
     if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
     {
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
       return false;
     }
   }
@@ -840,7 +971,7 @@ bool CCECBusDevice::TransmitInactiveSource(void)
   uint16_t iPhysicalAddress;
   {
     CLockObject lock(m_mutex);
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
     iPhysicalAddress = m_iPhysicalAddress;
   }
 
@@ -850,275 +981,240 @@ bool CCECBusDevice::TransmitInactiveSource(void)
   return bReturn;
 }
 
-bool CCECBusDevice::TransmitMenuState(cec_logical_address dest)
+bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
 {
-  cec_menu_state menuState;
-  {
-    CLockObject lock(m_mutex);
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
-    menuState = m_menuState;
-  }
-
   MarkBusy();
-  bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
+  bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
   MarkReady();
   return bReturn;
 }
 
-bool CCECBusDevice::TransmitOSDName(cec_logical_address dest)
+void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
 {
-  CStdString strDeviceName;
+  CLockObject lock(m_mutex);
+  if (iNewAddress != m_iStreamPath)
   {
-    CLockObject lock(m_mutex);
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, m_strDeviceName.c_str());
-    strDeviceName = m_strDeviceName;
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
+    m_iStreamPath = iNewAddress;
   }
 
-  MarkBusy();
-  bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, dest, strDeviceName);
-  MarkReady();
-  return bReturn;
-}
-
-bool CCECBusDevice::TransmitOSDString(cec_logical_address dest, cec_display_control duration, const char *strMessage)
-{
-  bool bReturn(false);
-  if (!m_processor->m_busDevices[dest]->IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING))
+  CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
+  if (device)
   {
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, strMessage);
-    MarkBusy();
-    bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, dest, duration, strMessage);
-    MarkReady();
+    // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
+    device->MarkAsActiveSource();
   }
-  return bReturn;
-}
-
-bool CCECBusDevice::TransmitPhysicalAddress(void)
-{
-  uint16_t iPhysicalAddress;
-  cec_device_type type;
+  else
   {
-    CLockObject lock(m_mutex);
-    if (m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS)
-      return false;
-
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
-    iPhysicalAddress = m_iPhysicalAddress;
-    type = m_type;
+    // try to find the device with the old address, and mark it as inactive when found
+    device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
+    if (device)
+      device->MarkAsInactiveSource();
   }
-
-  MarkBusy();
-  bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
-  MarkReady();
-  return bReturn;
 }
 
-bool CCECBusDevice::TransmitSetMenuLanguage(cec_logical_address dest)
+bool CCECBusDevice::PowerOn(const cec_logical_address initiator)
 {
   bool bReturn(false);
-  cec_menu_language language = GetMenuLanguage();
-
-  char lang[3];
-  {
-    CLockObject lock(m_mutex);
-    lang[0] = language.language[0];
-    lang[1] = language.language[1];
-    lang[2] = language.language[2];
-  }
+  GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
 
   MarkBusy();
-  if (lang[0] == '?' && lang[1] == '?' && lang[2] == '?')
+  cec_power_status currentStatus = GetPowerStatus(initiator, false);
+  if (currentStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
+    currentStatus != CEC_POWER_STATUS_ON)
   {
-      CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): Menu language feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
-      m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    if (m_handler->PowerOn(initiator, m_iLogicalAddress))
+    {
+      SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
       bReturn = true;
+    }
   }
   else
   {
-      CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): Menu language '%s'", GetLogicalAddressName(), m_iLogicalAddress, lang);
-      bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang);
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
   }
+
   MarkReady();
   return bReturn;
 }
 
-bool CCECBusDevice::TransmitPoll(cec_logical_address dest)
+bool CCECBusDevice::Standby(const cec_logical_address initiator)
 {
-  bool bReturn(false);
-  if (dest == CECDEVICE_UNKNOWN)
-    dest = m_iLogicalAddress;
-
-  CCECBusDevice *destDevice = m_processor->m_busDevices[dest];
-  if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
-    return bReturn;
+  GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
 
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
   MarkBusy();
-  CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
-  bReturn = m_handler->TransmitPoll(m_iLogicalAddress, dest);
-  CLibCEC::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;
-
+  bool bReturn = m_handler->TransmitStandby(initiator, m_iLogicalAddress);
   MarkReady();
   return bReturn;
 }
 
-bool CCECBusDevice::TransmitPowerState(cec_logical_address dest)
+bool CCECBusDevice::NeedsPoll(void)
 {
-  cec_power_status state;
+  bool bSendPoll(false);
+  cec_logical_address pollAddress(CECDEVICE_UNKNOWN);
+  switch (m_iLogicalAddress)
   {
-    CLockObject lock(m_mutex);
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_powerStatus));
-    state = m_powerStatus;
+  case CECDEVICE_PLAYBACKDEVICE3:
+    pollAddress = CECDEVICE_PLAYBACKDEVICE2;
+    break;
+  case CECDEVICE_PLAYBACKDEVICE2:
+    pollAddress = CECDEVICE_PLAYBACKDEVICE1;
+    break;
+  case CECDEVICE_RECORDINGDEVICE3:
+    pollAddress = CECDEVICE_RECORDINGDEVICE2;
+    break;
+  case CECDEVICE_RECORDINGDEVICE2:
+    pollAddress = CECDEVICE_RECORDINGDEVICE1;
+    break;
+  case CECDEVICE_TUNER4:
+    pollAddress = CECDEVICE_TUNER3;
+    break;
+  case CECDEVICE_TUNER3:
+    pollAddress = CECDEVICE_TUNER2;
+    break;
+  case CECDEVICE_TUNER2:
+    pollAddress = CECDEVICE_TUNER1;
+    break;
+  case CECDEVICE_AUDIOSYSTEM:
+  case CECDEVICE_PLAYBACKDEVICE1:
+  case CECDEVICE_RECORDINGDEVICE1:
+  case CECDEVICE_TUNER1:
+  case CECDEVICE_TV:
+    bSendPoll = true;
+    break;
+  default:
+    break;
   }
 
-  MarkBusy();
-  bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, dest, state);
-  MarkReady();
-  return bReturn;
+  if (!bSendPoll && pollAddress != CECDEVICE_UNKNOWN)
+  {
+    CCECBusDevice *device = m_processor->GetDevice(pollAddress);
+    if (device)
+    {
+      cec_bus_device_status status = device->GetStatus();
+      bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+    }
+    else
+    {
+      bSendPoll = true;
+    }
+  }
+
+  return bSendPoll;
 }
 
-bool CCECBusDevice::TransmitVendorID(cec_logical_address dest, bool bSendAbort /* = true */)
+void CCECBusDevice::CheckVendorIdRequested(const cec_logical_address initiator)
 {
-  bool bReturn(false);
-  uint64_t iVendorId;
+  bool bRequestVendorId(false);
   {
     CLockObject lock(m_mutex);
-    iVendorId = (uint64_t)m_vendor;
+    bRequestVendorId = !m_bVendorIdRequested;
+    m_bVendorIdRequested = true;
   }
 
-  MarkBusy();
-  if (iVendorId == CEC_VENDOR_UNKNOWN)
-  {
-    if (bSendAbort)
-    {
-      CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
-      m_processor->TransmitAbort(dest, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
-      bReturn = true;
-    }
-  }
-  else
+  if (bRequestVendorId)
   {
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString((cec_vendor_id)iVendorId), iVendorId);
-    bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
+    ReplaceHandler(false);
+    GetVendorId(initiator);
   }
-  MarkReady();
-  return bReturn;
 }
+//@}
 
-bool CCECBusDevice::TransmitKeypress(cec_user_control_code key, bool bWait /* = true */)
+CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
 {
-  MarkBusy();
-  bool bReturn = m_handler->TransmitKeypress(m_processor->GetLogicalAddress(), m_iLogicalAddress, key, bWait);
-  MarkReady();
-  return bReturn;
+  return AsAudioSystem(this);
 }
 
-bool CCECBusDevice::TransmitKeyRelease(bool bWait /* = true */)
+CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
 {
-  MarkBusy();
-  bool bReturn = m_handler->TransmitKeyRelease(m_processor->GetLogicalAddress(), m_iLogicalAddress, bWait);
-  MarkReady();
-  return bReturn;
+  return AsPlaybackDevice(this);
 }
 
-bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode)
+CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
 {
-  CLockObject lock(m_mutex);
-  bool bUnsupported = (m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end());
-  if (bUnsupported)
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "'%s' is marked as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
-  return bUnsupported;
+  return AsRecordingDevice(this);
 }
 
-void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
+CCECTuner *CCECBusDevice::AsTuner(void)
 {
-  // some commands should never be marked as unsupported
-  if (opcode == CEC_OPCODE_VENDOR_COMMAND ||
-      opcode == CEC_OPCODE_VENDOR_COMMAND_WITH_ID ||
-      opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN ||
-      opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP ||
-      opcode == CEC_OPCODE_ABORT ||
-      opcode == CEC_OPCODE_FEATURE_ABORT ||
-      opcode == CEC_OPCODE_NONE)
-    return;
+  return AsTuner(this);
+}
 
-  {
-    CLockObject lock(m_mutex);
-    if (m_unsupportedFeatures.find(opcode) == m_unsupportedFeatures.end())
-    {
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "marking opcode '%s' as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
-      m_unsupportedFeatures.insert(opcode);
-    }
-  }
+CCECTV *CCECBusDevice::AsTV(void)
+{
+  return AsTV(this);
+}
 
-  // signal threads that are waiting for a reponse
-  MarkBusy();
-  m_handler->SignalOpcode(cec_command::GetResponseOpcode(opcode));
-  MarkReady();
+CCECAudioSystem *CCECBusDevice::AsAudioSystem(CCECBusDevice *device)
+{
+  if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
+    return static_cast<CCECAudioSystem *>(device);
+  return NULL;
 }
 
-bool CCECBusDevice::ActivateSource(void)
+CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(CCECBusDevice *device)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
-  MarkBusy();
-  bool bReturn = m_handler->ActivateSource();
-  MarkReady();
-  return bReturn;
+  if (device &&
+      (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
+       device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
+    return static_cast<CCECPlaybackDevice *>(device);
+  return NULL;
 }
 
-void CCECBusDevice::HandlePoll(cec_logical_address destination)
+CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(CCECBusDevice *device)
 {
-  if (destination >= 0 && destination < CECDEVICE_BROADCAST)
-  {
-    CCECBusDevice *device = m_processor->m_busDevices[destination];
-    if (device)
-      device->HandlePollFrom(m_iLogicalAddress);
-  }
+  if (device && device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
+    return static_cast<CCECRecordingDevice *>(device);
+  return NULL;
 }
 
-void CCECBusDevice::HandlePollFrom(cec_logical_address initiator)
+CCECTuner *CCECBusDevice::AsTuner(CCECBusDevice *device)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
-  m_bAwaitingReceiveFailed = true;
+  if (device && device->GetType() == CEC_DEVICE_TYPE_TUNER)
+    return static_cast<CCECTuner *>(device);
+  return NULL;
 }
 
-bool CCECBusDevice::HandleReceiveFailed(void)
+CCECTV *CCECBusDevice::AsTV(CCECBusDevice *device)
 {
-  bool bReturn = m_bAwaitingReceiveFailed;
-  m_bAwaitingReceiveFailed = false;
-  return bReturn;
+  if (device && device->GetType() == CEC_DEVICE_TYPE_TV)
+    return static_cast<CCECTV *>(device);
+  return NULL;
 }
 
-void CCECBusDevice::CheckVendorIdRequested(void)
+void CCECBusDevice::MarkBusy(void)
 {
-  bool bRequestVendorId(false);
-  {
-    CLockObject lock(m_mutex);
-    bRequestVendorId = !m_bVendorIdRequested;
-    m_bVendorIdRequested = true;
-  }
+  CLockObject handlerLock(m_handlerMutex);
+  ++m_iHandlerUseCount;
+}
 
-  if (bRequestVendorId)
+void CCECBusDevice::MarkReady(void)
+{
+  CLockObject handlerLock(m_handlerMutex);
+  if (m_iHandlerUseCount > 0)
+    --m_iHandlerUseCount;
+}
+
+bool CCECBusDevice::TryLogicalAddress(void)
+{
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
+
+  if (!TransmitPoll(m_iLogicalAddress))
   {
-    ReplaceHandler(false);
-    GetVendorId();
+    LIB_CEC->AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
+    SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
+
+    return true;
   }
+
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
+  SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
+  return false;
 }
 
-bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
+CCECClient *CCECBusDevice::GetClient(void)
 {
-  MarkBusy();
-  bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
-  MarkReady();
-  return bReturn;
+  return m_processor->GetClient(m_iLogicalAddress);
 }
-
-//@}
index 95b1bad34155c40b07d10420fc834d4d8cafea3b..e93f1d34443201407a0d6a8b1ac182a380874217 100644 (file)
 
 namespace CEC
 {
+  class CCECClient;
   class CCECProcessor;
   class CCECCommandHandler;
+  class CCECAudioSystem;
+  class CCECPlaybackDevice;
+  class CCECRecordingDevice;
+  class CCECTuner;
+  class CCECTV;
 
   class CCECBusDevice
   {
@@ -49,83 +55,108 @@ namespace CEC
     CCECBusDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
     virtual ~CCECBusDevice(void);
 
-    virtual bool HandleCommand(const cec_command &command);
-    virtual bool PowerOn(void);
-    virtual bool Standby(void);
-
-    virtual cec_version           GetCecVersion(bool bUpdate = false);
-    virtual CCECCommandHandler *  GetHandler(void) const { return m_handler; };
-    virtual uint64_t              GetLastActive(void) const { return m_iLastActive; }
+    virtual bool                  ReplaceHandler(bool bActivateSource = true);
+    virtual CCECCommandHandler *  GetHandler(void) const        { return m_handler; };
+    virtual CCECProcessor *       GetProcessor(void) const      { return m_processor; }
+    virtual uint64_t              GetLastActive(void) const     { return m_iLastActive; }
+    virtual cec_device_type       GetType(void) const           { return m_type; }
     virtual cec_logical_address   GetLogicalAddress(void) const { return m_iLogicalAddress; }
     virtual const char*           GetLogicalAddressName(void) const;
-    virtual cec_menu_language &   GetMenuLanguage(bool bUpdate = false);
-    virtual cec_menu_state        GetMenuState(void);
-    virtual cec_logical_address   GetMyLogicalAddress(void) const;
-    virtual uint16_t              GetMyPhysicalAddress(void) const;
-    virtual CStdString            GetOSDName(bool bUpdate = false);
-    virtual uint16_t              GetPhysicalAddress(bool bSuppressUpdate = true);
-    virtual cec_power_status      GetPowerStatus(bool bUpdate = false);
-    virtual CCECProcessor *       GetProcessor(void) const { return m_processor; }
-    virtual cec_device_type       GetType(void) const { return m_type; }
-    virtual cec_vendor_id         GetVendorId(bool bUpdate = false);
-    virtual const char *          GetVendorName(bool bUpdate = false);
-    virtual bool                  MyLogicalAddressContains(cec_logical_address address) const;
-    virtual cec_bus_device_status GetStatus(bool bForcePoll = false, bool bSuppressPoll = false);
-    virtual bool                  IsActiveSource(void) const { return m_bActiveSource; }
+    virtual bool                  IsPresent(void);
+    virtual bool                  IsHandledByLibCEC(void);
+
+    virtual bool                  HandleCommand(const cec_command &command);
     virtual bool                  IsUnsupportedFeature(cec_opcode opcode);
     virtual void                  SetUnsupportedFeature(cec_opcode opcode);
-    virtual void                  HandlePoll(cec_logical_address destination);
-    virtual void                  HandlePollFrom(cec_logical_address initiator);
+
+    virtual bool                  TransmitKeypress(const cec_logical_address initiator, cec_user_control_code key, bool bWait = true);
+    virtual bool                  TransmitKeyRelease(const cec_logical_address initiator, bool bWait = true);
+
+    virtual cec_version           GetCecVersion(const cec_logical_address initiator, bool bUpdate = false);
+    virtual void                  SetCecVersion(const cec_version newVersion);
+    virtual bool                  RequestCecVersion(const cec_logical_address initiator, bool bWaitForResponse = true);
+    virtual bool                  TransmitCECVersion(const cec_logical_address destination);
+
+    virtual cec_menu_language &   GetMenuLanguage(const cec_logical_address initiator, bool bUpdate = false);
+    virtual void                  SetMenuLanguage(const char *strLanguage);
+    virtual void                  SetMenuLanguage(const cec_menu_language &menuLanguage);
+    virtual bool                  RequestMenuLanguage(const cec_logical_address initiator, bool bWaitForResponse = true);
+    virtual bool                  TransmitSetMenuLanguage(const cec_logical_address destination);
+
+    virtual bool                  TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage);
+
+    virtual CStdString            GetOSDName(const cec_logical_address initiator, bool bUpdate = false);
+    virtual void                  SetOSDName(CStdString strName);
+    virtual bool                  RequestOSDName(const cec_logical_address source, bool bWaitForResponse = true);
+    virtual bool                  TransmitOSDName(const cec_logical_address destination);
+
+    virtual uint16_t              GetCurrentPhysicalAddress(void);
+    virtual bool                  HasValidPhysicalAddress(void);
+    virtual uint16_t              GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate = false);
+    virtual bool                  SetPhysicalAddress(uint16_t iNewAddress);
+    virtual bool                  RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse = true);
+    virtual bool                  TransmitPhysicalAddress(void);
+
+    virtual cec_power_status      GetCurrentPowerStatus(void);
+    virtual cec_power_status      GetPowerStatus(const cec_logical_address initiator, bool bUpdate = false);
+    virtual void                  SetPowerStatus(const cec_power_status powerStatus);
+    virtual bool                  RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse = true);
+    virtual bool                  TransmitPowerState(const cec_logical_address destination);
+
+    virtual cec_vendor_id         GetCurrentVendorId(void);
+    virtual cec_vendor_id         GetVendorId(const cec_logical_address initiator, bool bUpdate = false);
+    virtual const char *          GetVendorName(const cec_logical_address initiator, bool bUpdate = false);
+    virtual bool                  SetVendorId(uint64_t iVendorId);
+    virtual bool                  RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse = true);
+    virtual bool                  TransmitVendorID(const cec_logical_address destination, bool bSendAbort = true);
+
+    virtual cec_bus_device_status GetCurrentStatus(void) { return GetStatus(false, true); }
+    virtual cec_bus_device_status GetStatus(bool bForcePoll = false, bool bSuppressPoll = false);
+    virtual void                  SetDeviceStatus(const cec_bus_device_status newStatus);
+    virtual void                  ResetDeviceStatus(void);
+    virtual bool                  TransmitPoll(const cec_logical_address destination);
+    virtual void                  HandlePoll(const cec_logical_address destination);
+    virtual void                  HandlePollFrom(const cec_logical_address initiator);
     virtual bool                  HandleReceiveFailed(void);
 
-    virtual void SetInactiveSource(void);
-    virtual void SetActiveSource(void);
-    virtual bool TryLogicalAddress(void);
-    virtual bool ActivateSource(void);
-
-    virtual void SetDeviceStatus(const cec_bus_device_status newStatus);
-    virtual void SetPhysicalAddress(uint16_t iNewAddress);
-    virtual void SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress = CEC_INVALID_PHYSICAL_ADDRESS);
-    virtual void SetCecVersion(const cec_version newVersion);
-    virtual void SetMenuLanguage(const cec_menu_language &menuLanguage);
-    virtual void SetOSDName(CStdString strName);
-    virtual void SetMenuState(const cec_menu_state state);
-    virtual bool SetVendorId(uint64_t iVendorId);
-    virtual void SetPowerStatus(const cec_power_status powerStatus);
-
-    virtual bool TransmitActiveSource(void);
-    virtual bool TransmitCECVersion(cec_logical_address dest);
-    virtual bool TransmitImageViewOn(void);
-    virtual bool TransmitInactiveSource(void);
-    virtual bool TransmitMenuState(cec_logical_address dest);
-    virtual bool TransmitOSDName(cec_logical_address dest);
-    virtual bool TransmitOSDString(cec_logical_address dest, cec_display_control duration, const char *strMessage);
-    virtual bool TransmitPhysicalAddress(void);
-    virtual bool TransmitSetMenuLanguage(cec_logical_address dest);
-    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, bool bWait = true);
-    virtual bool TransmitKeyRelease(bool bWait = true);
-
-    bool ReplaceHandler(bool bActivateSource = true);
-    virtual bool TransmitPendingActiveSourceCommands(void);
-
-    virtual bool RequestActiveSource(bool bWaitForResponse = true);
+    virtual cec_menu_state        GetMenuState(const cec_logical_address initiator);
+    virtual void                  SetMenuState(const cec_menu_state state);
+    virtual bool                  TransmitMenuState(const cec_logical_address destination);
+
+    virtual bool                  ActivateSource(void);
+    virtual bool                  IsActiveSource(void) const    { return m_bActiveSource; }
+    virtual bool                  RequestActiveSource(bool bWaitForResponse = true);
+    virtual void                  MarkAsActiveSource(void);
+    virtual void                  MarkAsInactiveSource(void);
+    virtual bool                  TransmitActiveSource(void);
+    virtual bool                  TransmitImageViewOn(void);
+    virtual bool                  TransmitInactiveSource(void);
+    virtual bool                  TransmitPendingActiveSourceCommands(void);
+    virtual void                  SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress = CEC_INVALID_PHYSICAL_ADDRESS);
+
+    virtual bool                  PowerOn(const cec_logical_address initiator);
+    virtual bool                  Standby(const cec_logical_address initiator);
+
+    virtual bool                  TryLogicalAddress(void);
+
+    CCECClient *                  GetClient(void);
+
+           CCECAudioSystem *      AsAudioSystem(void);
+    static CCECAudioSystem *      AsAudioSystem(CCECBusDevice *device);
+           CCECPlaybackDevice *   AsPlaybackDevice(void);
+    static CCECPlaybackDevice *   AsPlaybackDevice(CCECBusDevice *device);
+           CCECRecordingDevice *  AsRecordingDevice(void);
+    static CCECRecordingDevice *  AsRecordingDevice(CCECBusDevice *device);
+           CCECTuner *            AsTuner(void);
+    static CCECTuner *            AsTuner(CCECBusDevice *device);
+           CCECTV *               AsTV(void);
+    static CCECTV *               AsTV(CCECBusDevice *device);
 
   protected:
-    void ResetDeviceStatus(void);
-    void CheckVendorIdRequested(void);
+    void CheckVendorIdRequested(const cec_logical_address source);
     void MarkBusy(void);
     void MarkReady(void);
 
-    bool RequestCecVersion(bool bWaitForResponse = true);
-    bool RequestMenuLanguage(bool bWaitForResponse = true);
-    bool RequestPowerStatus(bool bWaitForResponse = true);
-    bool RequestVendorId(bool bWaitForResponse = true);
-    bool RequestPhysicalAddress(bool bWaitForResponse = true);
-    bool RequestOSDName(bool bWaitForResponse = true);
-
     bool NeedsPoll(void);
 
     cec_device_type       m_type;
diff --git a/src/lib/devices/CECDeviceMap.cpp b/src/lib/devices/CECDeviceMap.cpp
new file mode 100644 (file)
index 0000000..2603e33
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "CECDeviceMap.h"
+#include "CECAudioSystem.h"
+#include "CECPlaybackDevice.h"
+#include "CECRecordingDevice.h"
+#include "CECTuner.h"
+#include "CECTV.h"
+#include "CECProcessor.h"
+
+using namespace std;
+using namespace CEC;
+
+CCECDeviceMap::CCECDeviceMap(CCECProcessor *processor) :
+    m_processor(processor)
+{
+  for (uint8_t iPtr = CECDEVICE_TV; iPtr <= CECDEVICE_BROADCAST; iPtr++)
+  {
+    switch(iPtr)
+    {
+    case CECDEVICE_AUDIOSYSTEM:
+      m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECAudioSystem(processor, (cec_logical_address) iPtr)));
+      break;
+    case CECDEVICE_PLAYBACKDEVICE1:
+    case CECDEVICE_PLAYBACKDEVICE2:
+    case CECDEVICE_PLAYBACKDEVICE3:
+      m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECPlaybackDevice(processor, (cec_logical_address) iPtr)));
+      break;
+    case CECDEVICE_RECORDINGDEVICE1:
+    case CECDEVICE_RECORDINGDEVICE2:
+    case CECDEVICE_RECORDINGDEVICE3:
+      m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECRecordingDevice(processor, (cec_logical_address) iPtr)));
+      break;
+    case CECDEVICE_TUNER1:
+    case CECDEVICE_TUNER2:
+    case CECDEVICE_TUNER3:
+    case CECDEVICE_TUNER4:
+      m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECTuner(processor, (cec_logical_address) iPtr)));
+      break;
+    case CECDEVICE_TV:
+      m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECTV(processor, (cec_logical_address) iPtr)));
+      break;
+    default:
+      m_busDevices.insert(make_pair<cec_logical_address, CCECBusDevice *>((cec_logical_address)iPtr, new CCECBusDevice(processor, (cec_logical_address) iPtr)));
+      break;
+    }
+  }
+}
+CCECDeviceMap::~CCECDeviceMap(void)
+{
+  Clear();
+}
+
+CECDEVICEMAP::iterator CCECDeviceMap::Begin(void)
+{
+  return m_busDevices.begin();
+}
+
+CECDEVICEMAP::iterator CCECDeviceMap::End(void)
+{
+  return m_busDevices.end();
+}
+
+void CCECDeviceMap::ResetDeviceStatus(void)
+{
+  for (CECDEVICEMAP::iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+    it->second->ResetDeviceStatus();
+}
+
+CCECBusDevice *CCECDeviceMap::operator[] (cec_logical_address iAddress) const
+{
+  return At(iAddress);
+}
+
+CCECBusDevice *CCECDeviceMap::operator[] (uint8_t iAddress) const
+{
+  return At(iAddress);
+}
+
+CCECBusDevice *CCECDeviceMap::At(cec_logical_address iAddress) const
+{
+  return At((uint8_t) iAddress);
+}
+
+CCECBusDevice *CCECDeviceMap::At(uint8_t iAddress) const
+{
+  CECDEVICEMAP::const_iterator it = m_busDevices.find((cec_logical_address)iAddress);
+  if (it != m_busDevices.end())
+    return it->second;
+  return NULL;
+}
+
+void CCECDeviceMap::Clear(void)
+{
+  for (CECDEVICEMAP::iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+    delete it->second;
+  m_busDevices.clear();
+}
+
+CCECBusDevice *CCECDeviceMap::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate /* = true */)
+{
+  CCECBusDevice *device(NULL);
+
+  // check each device until we found a match
+  for (CECDEVICEMAP::iterator it = m_busDevices.begin(); !device && it != m_busDevices.end(); it++)
+  {
+    if (it->second->GetPhysicalAddress(m_processor->GetLogicalAddress(), bSuppressUpdate) == iPhysicalAddress)
+      device = it->second;
+  }
+
+  return device;
+}
+
+void CCECDeviceMap::Get(CECDEVICEVEC &devices) const
+{
+  for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+    devices.push_back(it->second);
+}
+
+void CCECDeviceMap::GetByLogicalAddresses(CECDEVICEVEC &devices, const cec_logical_addresses &addresses)
+{
+  for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+  {
+    if (addresses.IsSet(it->first))
+      devices.push_back(it->second);
+  }
+}
+
+void CCECDeviceMap::GetByType(const cec_device_type type, CECDEVICEVEC &devices) const
+{
+  for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+    if (it->second->GetType() == type)
+      devices.push_back(it->second);
+}
+
+void CCECDeviceMap::GetLibCECControlled(CECDEVICEVEC &devices) const
+{
+  for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+    if (it->second->IsHandledByLibCEC())
+      devices.push_back(it->second);
+}
+
+void CCECDeviceMap::GetActive(CECDEVICEVEC &devices) const
+{
+  for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+  {
+    cec_bus_device_status status = it->second->GetStatus();
+    if (status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC ||
+        status == CEC_DEVICE_STATUS_PRESENT)
+      devices.push_back(it->second);
+  }
+}
+
+void CCECDeviceMap::GetPowerOffDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const
+{
+  for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+  {
+    if (configuration.powerOffDevices[it->first])
+      devices.push_back(it->second);
+  }
+}
+
+void CCECDeviceMap::GetWakeDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const
+{
+  for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+  {
+    if (configuration.wakeDevices[it->first])
+      devices.push_back(it->second);
+  }
+}
+
+CCECBusDevice *CCECDeviceMap::GetActiveSource(void) const
+{
+  for (CECDEVICEMAP::const_iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++)
+  {
+    if (it->second->IsActiveSource())
+      return it->second;
+  }
+  return NULL;
+}
+
+void CCECDeviceMap::FilterLibCECControlled(CECDEVICEVEC &devices)
+{
+  CECDEVICEVEC newDevices;
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+  {
+    if ((*it)->IsHandledByLibCEC())
+      newDevices.push_back(*it);
+  }
+  devices = newDevices;
+}
+
+void CCECDeviceMap::FilterActive(CECDEVICEVEC &devices)
+{
+  CECDEVICEVEC newDevices;
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+  {
+    cec_bus_device_status status = (*it)->GetCurrentStatus();
+    if (status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC ||
+        status == CEC_DEVICE_STATUS_PRESENT)
+      newDevices.push_back(*it);
+  }
+  devices = newDevices;
+}
+
+void CCECDeviceMap::FilterTypes(const cec_device_type_list &types, CECDEVICEVEC &devices)
+{
+  CECDEVICEVEC newDevices;
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+  {
+    if (types.IsSet((*it)->GetType()))
+      newDevices.push_back(*it);
+  }
+  devices = newDevices;
+}
+
+void CCECDeviceMap::FilterType(const cec_device_type type, CECDEVICEVEC &devices)
+{
+  CECDEVICEVEC newDevices;
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+  {
+    if ((*it)->GetType() == type)
+      newDevices.push_back(*it);
+  }
+  devices = newDevices;
+}
+
+cec_logical_addresses CCECDeviceMap::ToLogicalAddresses(const CECDEVICEVEC &devices)
+{
+  cec_logical_addresses addresses;
+  for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
+    addresses.Set((*it)->GetLogicalAddress());
+  return addresses;
+}
diff --git a/src/lib/devices/CECDeviceMap.h b/src/lib/devices/CECDeviceMap.h
new file mode 100644 (file)
index 0000000..128f574
--- /dev/null
@@ -0,0 +1,83 @@
+#pragma once
+/*
+ * This file is part of the libCEC(R) library.
+ *
+ * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited.  All rights reserved.
+ * libCEC(R) is an original work, containing original code.
+ *
+ * libCEC(R) is a trademark of Pulse-Eight Limited.
+ *
+ * This program is dual-licensed; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * Alternatively, you can license this library under a commercial license,
+ * please contact Pulse-Eight Licensing for more information.
+ *
+ * For more information contact:
+ * Pulse-Eight Licensing       <license@pulse-eight.com>
+ *     http://www.pulse-eight.com/
+ *     http://www.pulse-eight.net/
+ */
+
+#include "../../../include/cectypes.h"
+#include <map>
+#include <vector>
+
+namespace CEC
+{
+  class CCECBusDevice;
+
+  typedef std::map<cec_logical_address, CCECBusDevice *> CECDEVICEMAP;
+  typedef std::vector<CCECBusDevice *>                   CECDEVICEVEC;
+
+  class CCECProcessor;
+
+  class CCECDeviceMap
+  {
+  public:
+    CCECDeviceMap(CCECProcessor *processor);
+    virtual ~CCECDeviceMap(void);
+    CECDEVICEMAP::iterator  Begin(void);
+    CECDEVICEMAP::iterator  End(void);
+    void                    ResetDeviceStatus(void);
+    CCECBusDevice *         operator[] (cec_logical_address iAddress) const;
+    CCECBusDevice *         operator[] (uint8_t iAddress) const;
+    CCECBusDevice *         At(cec_logical_address iAddress) const;
+    CCECBusDevice *         At(uint8_t iAddress) const;
+    CCECBusDevice *         GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress, bool bSuppressUpdate = true);
+
+    void Get(CECDEVICEVEC &devices) const;
+    void GetLibCECControlled(CECDEVICEVEC &devices) const;
+    void GetByLogicalAddresses(CECDEVICEVEC &devices, const cec_logical_addresses &addresses);
+    void GetActive(CECDEVICEVEC &devices) const;
+    void GetByType(const cec_device_type type, CECDEVICEVEC &devices) const;
+
+    void GetPowerOffDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const;
+    void GetWakeDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const;
+
+    CCECBusDevice *GetActiveSource(void) const;
+
+    static void FilterLibCECControlled(CECDEVICEVEC &devices);
+    static void FilterActive(CECDEVICEVEC &devices);
+    static void FilterTypes(const cec_device_type_list &types, CECDEVICEVEC &devices);
+    static void FilterType(const cec_device_type type, CECDEVICEVEC &devices);
+    static cec_logical_addresses ToLogicalAddresses(const CECDEVICEVEC &devices);
+  private:
+    void Clear(void);
+
+    CECDEVICEMAP   m_busDevices;
+    CCECProcessor *m_processor;
+  };
+}
index 522b88f49a572d3042794e1be1e4ac3b452bb2a7..d1ac742c0ec39d4673c7dd343ea327fdffb3a014 100644 (file)
@@ -38,7 +38,7 @@
 using namespace CEC;
 using namespace PLATFORM;
 
-#define ToString(p) m_processor->ToString(p)
+#define ToString(p) m_processor->GetLib()->ToString(p)
 
 CCECPlaybackDevice::CCECPlaybackDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
     CCECBusDevice(processor, address, iPhysicalAddress),
@@ -48,7 +48,7 @@ CCECPlaybackDevice::CCECPlaybackDevice(CCECProcessor *processor, cec_logical_add
   m_type = CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
 }
 
-cec_deck_info CCECPlaybackDevice::GetDeckStatus(void)
+cec_deck_info CCECPlaybackDevice::GetDeckStatus(const cec_logical_address UNUSED(initiator))
 {
   CLockObject lock(m_mutex);
   return m_deckStatus;
@@ -59,12 +59,12 @@ void CCECPlaybackDevice::SetDeckStatus(cec_deck_info deckStatus)
   CLockObject lock(m_mutex);
   if (m_deckStatus != deckStatus)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): deck status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckStatus), ToString(deckStatus));
+    m_processor->GetLib()->AddLog(CEC_LOG_DEBUG, ">> %s (%X): deck status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckStatus), ToString(deckStatus));
     m_deckStatus = deckStatus;
   }
 }
 
-cec_deck_control_mode CCECPlaybackDevice::GetDeckControlMode(void)
+cec_deck_control_mode CCECPlaybackDevice::GetDeckControlMode(const cec_logical_address UNUSED(initiator))
 {
   CLockObject lock(m_mutex);
   return m_deckControlMode;
@@ -75,7 +75,7 @@ void CCECPlaybackDevice::SetDeckControlMode(cec_deck_control_mode mode)
   CLockObject lock(m_mutex);
   if (m_deckControlMode != mode)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %s (%X): deck control mode changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckControlMode), ToString(mode));
+    m_processor->GetLib()->AddLog(CEC_LOG_DEBUG, ">> %s (%X): deck control mode changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_deckControlMode), ToString(mode));
     m_deckControlMode = mode;
   }
 }
@@ -85,9 +85,17 @@ bool CCECPlaybackDevice::TransmitDeckStatus(cec_logical_address dest)
   cec_deck_info state;
   {
     CLockObject lock(m_mutex);
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): deck status '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_deckStatus));
+    m_processor->GetLib()->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): deck status '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_deckStatus));
     state = m_deckStatus;
   }
 
   return m_handler->TransmitDeckStatus(m_iLogicalAddress, dest, state);
 }
+
+void CCECPlaybackDevice::ResetDeviceStatus(void)
+{
+  CLockObject lock(m_mutex);
+  m_deckStatus      = CEC_DECK_INFO_STOP;
+  m_deckControlMode = CEC_DECK_CONTROL_MODE_STOP;
+  CCECBusDevice::ResetDeviceStatus();
+}
index 414f8478517562b71366d592fdc5f60222827aaf..c21bf30f206a8ea107a19c0309692d2f108faed9 100644 (file)
@@ -41,14 +41,16 @@ namespace CEC
     CCECPlaybackDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
     virtual ~CCECPlaybackDevice(void) {};
 
-    cec_deck_info GetDeckStatus(void);
-    cec_deck_control_mode GetDeckControlMode(void);
+    cec_deck_info GetDeckStatus(const cec_logical_address initiator);
+    cec_deck_control_mode GetDeckControlMode(const cec_logical_address initiator);
 
     void SetDeckStatus(cec_deck_info deckStatus);
     void SetDeckControlMode(cec_deck_control_mode mode);
 
     bool TransmitDeckStatus(cec_logical_address dest);
 
+    virtual void ResetDeviceStatus(void);
+
   protected:
     cec_deck_info         m_deckStatus;
     cec_deck_control_mode m_deckControlMode;
index c5f4535af4254b7b83028e63b011c5138bb5b154..2a82902b4d63286e598ad25bf1d2cb8d48bda4ea 100644 (file)
 #include "CECRecordingDevice.h"
 
 using namespace CEC;
+using namespace PLATFORM;
 
 CCECRecordingDevice::CCECRecordingDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
-    CCECBusDevice(processor, address, iPhysicalAddress),
-    m_playbackDevice(processor, address, iPhysicalAddress),
+    CCECPlaybackDevice(processor, address, iPhysicalAddress),
     m_tuner(processor, address, iPhysicalAddress)
 {
   m_type = CEC_DEVICE_TYPE_RECORDING_DEVICE;
 }
 
-cec_deck_info CCECRecordingDevice::GetDeckStatus(void)
+void CCECRecordingDevice::ResetDeviceStatus(void)
 {
-  return m_playbackDevice.GetDeckStatus();
-}
-
-cec_deck_control_mode CCECRecordingDevice::GetDeckControlMode(void)
-{
-  return m_playbackDevice.GetDeckControlMode();
-}
-
-void CCECRecordingDevice::SetDeckStatus(cec_deck_info deckStatus)
-{
-  m_playbackDevice.SetDeckStatus(deckStatus);
-}
-
-void CCECRecordingDevice::SetDeckControlMode(cec_deck_control_mode mode)
-{
-  m_playbackDevice.SetDeckControlMode(mode);
-}
-
-bool CCECRecordingDevice::TransmitDeckStatus(cec_logical_address dest)
-{
-  return m_playbackDevice.TransmitDeckStatus(dest);
+  CLockObject lock(m_mutex);
+  m_tuner.ResetDeviceStatus();
+  CCECPlaybackDevice::ResetDeviceStatus();
 }
index f64b95b357a88683691fc6a9dcaf8004effa4a5d..f37c37b1a02fd62b9f5222bf9b96fb2b849bbd3c 100644 (file)
 
 namespace CEC
 {
-  class CCECRecordingDevice : public CCECBusDevice
+  class CCECRecordingDevice : public CCECPlaybackDevice
   {
   public:
     CCECRecordingDevice(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
     virtual ~CCECRecordingDevice(void) {};
 
-    /* playback device methods */
-    cec_deck_info GetDeckStatus(void);
-    cec_deck_control_mode GetDeckControlMode(void);
-
-    void SetDeckStatus(cec_deck_info deckStatus);
-    void SetDeckControlMode(cec_deck_control_mode mode);
-
-    bool TransmitDeckStatus(cec_logical_address dest);
-
-    /* tuner methods */
-    //TODO
+    virtual void ResetDeviceStatus(void);
 
+    /* TODO: tuner methods */
   protected:
-    CCECPlaybackDevice m_playbackDevice;
     CCECTuner          m_tuner;
   };
 }
index 5c2e909f26296ed7f8972c02e43e6640480afc08..b26dbdc8451fa4f857d0178b3edb34458085c68c 100644 (file)
 #include "CECTV.h"
 
 using namespace CEC;
+using namespace PLATFORM;
 
 CCECTV::CCECTV(CCECProcessor *processor, cec_logical_address address) :
     CCECBusDevice(processor, address, CEC_PHYSICAL_ADDRESS_TV)
 {
   m_type = CEC_DEVICE_TYPE_TV;
 }
+
+void CCECTV::ResetDeviceStatus(void)
+{
+  CLockObject lock(m_mutex);
+  CCECBusDevice::ResetDeviceStatus();
+}
index e712e96b8818f9eedf1b3d6cf03705dfe7df254a..293f5e8004d3704705fa441874f055b969f9160c 100644 (file)
@@ -40,5 +40,7 @@ namespace CEC
   public:
     CCECTV(CCECProcessor *processor, cec_logical_address address);
     virtual ~CCECTV(void) {};
+
+    virtual void ResetDeviceStatus(void);
   };
 }
index feb35e4b5bd92834c3099efcbac1b92ee7637409..4721c1a5a35010be3396a04c573960e37a605694 100644 (file)
 #include "CECTuner.h"
 
 using namespace CEC;
+using namespace PLATFORM;
 
 CCECTuner::CCECTuner(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
     CCECBusDevice(processor, address, iPhysicalAddress)
 {
-  m_type          = CEC_DEVICE_TYPE_TUNER;
+  m_type = CEC_DEVICE_TYPE_TUNER;
+}
+
+void CCECTuner::ResetDeviceStatus(void)
+{
+  CLockObject lock(m_mutex);
+  CCECBusDevice::ResetDeviceStatus();
 }
index ad65efdf65ae729a0740ac7b4eeecdc9435d7976..e9ce44c7809facd3190120c6bd53ea714106ad43 100644 (file)
@@ -40,5 +40,7 @@ namespace CEC
   public:
     CCECTuner(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS);
     virtual ~CCECTuner(void) {};
+
+    virtual void ResetDeviceStatus(void);
   };
 }
index 182f0acc76444d10769062f8413cac767b3f5cad..2a4dc0d064dece6f48aecbe5986e0bbe143ef383 100644 (file)
 #include "../devices/CECBusDevice.h"
 #include "../CECProcessor.h"
 #include "../LibCEC.h"
+#include "../CECClient.h"
 
 using namespace CEC;
 
+#define LIB_CEC     m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
 CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice) :
     CCECCommandHandler(busDevice)
 {
@@ -48,6 +52,8 @@ bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
 {
   if (m_processor->IsRunning() && command.parameters.size > 0)
   {
+    CCECClient *client = m_processor->GetClient(command.destination);
+
     cec_keypress key;
     key.duration = CEC_BUTTON_TIMEOUT;
     key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
@@ -55,7 +61,7 @@ bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
     switch (command.parameters[0])
     {
     case CEC_USER_CONTROL_CODE_AN_RETURN:
-      key.keycode = m_processor->GetClientVersion() >= CEC_CLIENT_VERSION_1_5_0 ?
+      key.keycode = client && client->GetConfiguration()->clientVersion >= CEC_CLIENT_VERSION_1_5_0 ?
         CEC_USER_CONTROL_CODE_AN_RETURN :
         CEC_USER_CONTROL_CODE_EXIT;
       break;
@@ -66,8 +72,8 @@ bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
       break;
     }
 
-    if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN)
-      CLibCEC::AddKey(key);
+    if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN && client)
+      client->AddKey(key);
   }
 
   return true;
@@ -76,7 +82,7 @@ bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
 bool CANCommandHandler::HandleCommand(const cec_command &command)
 {
   bool bHandled(false);
-  if (m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsHandledByLibCEC(command.destination))
   {
     switch(command.opcode)
     {
index 449c589e27154805350ab8dee9cbb06204bd2f40..ad4349efb608141e6df52aac04216daac46e3fff 100644 (file)
@@ -34,6 +34,7 @@
 #include "../devices/CECBusDevice.h"
 #include "../devices/CECAudioSystem.h"
 #include "../devices/CECPlaybackDevice.h"
+#include "../CECClient.h"
 #include "../CECProcessor.h"
 #include "../LibCEC.h"
 
@@ -41,6 +42,9 @@ using namespace CEC;
 using namespace std;
 using namespace PLATFORM;
 
+#define LIB_CEC     m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
 CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) :
     m_busDevice(busDevice),
     m_processor(m_busDevice->GetProcessor()),
@@ -66,7 +70,9 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
 
   bool bHandled(true);
 
-  CLibCEC::AddCommand(command);
+  CCECClient *client = m_busDevice->GetClient();
+  if (client)
+    client->AddCommand(command);
 
   switch(command.opcode)
   {
@@ -80,19 +86,19 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
     HandleSetMenuLanguage(command);
     break;
   case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleGivePhysicalAddress(command);
     break;
   case CEC_OPCODE_GET_MENU_LANGUAGE:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleGiveMenuLanguage(command);
     break;
   case CEC_OPCODE_GIVE_OSD_NAME:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleGiveOSDName(command);
     break;
   case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleGiveDeviceVendorId(command);
     break;
   case CEC_OPCODE_DEVICE_VENDOR_ID:
@@ -102,42 +108,42 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
     HandleDeviceVendorCommandWithId(command);
     break;
   case CEC_OPCODE_GIVE_DECK_STATUS:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleGiveDeckStatus(command);
     break;
   case CEC_OPCODE_DECK_CONTROL:
     HandleDeckControl(command);
     break;
   case CEC_OPCODE_MENU_REQUEST:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleMenuRequest(command);
     break;
   case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleGiveDevicePowerStatus(command);
     break;
   case CEC_OPCODE_GET_CEC_VERSION:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleGetCecVersion(command);
     break;
   case CEC_OPCODE_USER_CONTROL_PRESSED:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleUserControlPressed(command);
     break;
   case CEC_OPCODE_USER_CONTROL_RELEASE:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleUserControlRelease(command);
     break;
   case CEC_OPCODE_GIVE_AUDIO_STATUS:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleGiveAudioStatus(command);
     break;
   case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleGiveSystemAudioModeStatus(command);
     break;
   case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleSystemAudioModeRequest(command);
     break;
   case CEC_OPCODE_REPORT_AUDIO_STATUS:
@@ -150,7 +156,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
     HandleSetSystemAudioMode(command);
     break;
   case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleRequestActiveSource(command);
     break;
   case CEC_OPCODE_SET_STREAM_PATH:
@@ -163,7 +169,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
     HandleRoutingInformation(command);
     break;
   case CEC_OPCODE_STANDBY:
-    if (m_processor->IsInitialised())
+    if (m_processor->CECInitialised())
       HandleStandby(command);
     break;
   case CEC_OPCODE_ACTIVE_SOURCE:
@@ -188,13 +194,14 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command)
     HandleVendorCommand(command);
     break;
   default:
-    UnhandledCommand(command);
     bHandled = false;
     break;
   }
 
   if (bHandled)
     m_waitForResponse->Received((command.opcode == CEC_OPCODE_FEATURE_ABORT && command.parameters.size > 0) ? (cec_opcode)command.parameters[0] : command.opcode);
+  else
+    UnhandledCommand(command);
 
   return bHandled;
 }
@@ -204,7 +211,9 @@ bool CCECCommandHandler::HandleActiveSource(const cec_command &command)
   if (command.parameters.size == 2)
   {
     uint16_t iAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
-    return m_processor->SetActiveSource(iAddress);
+    CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iAddress);
+    if (device)
+      device->MarkAsActiveSource();
   }
 
   return true;
@@ -236,8 +245,8 @@ bool CCECCommandHandler::HandleDeviceCecVersion(const cec_command &command)
 
 bool CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
-    m_processor->TransmitAbort(command.initiator, command.opcode, CEC_ABORT_REASON_REFUSED);
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
+    m_processor->TransmitAbort(m_busDevice->GetLogicalAddress(), command.initiator, command.opcode, CEC_ABORT_REASON_REFUSED);
 
   return true;
 }
@@ -252,13 +261,13 @@ bool CCECCommandHandler::HandleFeatureAbort(const cec_command &command)
   if (command.parameters.size == 2 &&
         (command.parameters[1] == CEC_ABORT_REASON_UNRECOGNIZED_OPCODE ||
          command.parameters[1] == CEC_ABORT_REASON_REFUSED))
-    m_processor->m_busDevices[command.initiator]->SetUnsupportedFeature((cec_opcode)command.parameters[0]);
+    m_processor->GetDevice(command.initiator)->SetUnsupportedFeature((cec_opcode)command.parameters[0]);
   return true;
 }
 
 bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device)
@@ -270,7 +279,7 @@ bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
 
 bool CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
@@ -282,7 +291,7 @@ bool CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
 
 bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
@@ -294,7 +303,7 @@ bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
 
 bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device)
@@ -306,7 +315,7 @@ bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
 
 bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device)
@@ -318,7 +327,7 @@ bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
 
 bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device)
@@ -330,7 +339,7 @@ bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
 
 bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device)
@@ -342,7 +351,7 @@ bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
 
 bool CCECCommandHandler::HandleGiveMenuLanguage(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device)
@@ -354,7 +363,7 @@ bool CCECCommandHandler::HandleGiveMenuLanguage(const cec_command &command)
 
 bool CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
@@ -366,26 +375,30 @@ bool CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &comm
 
 bool CCECCommandHandler::HandleImageViewOn(const cec_command &command)
 {
-  m_processor->m_busDevices[command.initiator]->SetActiveSource();
+  m_processor->GetDevice(command.initiator)->MarkAsActiveSource();
   return true;
 }
 
 bool CCECCommandHandler::HandleMenuRequest(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device)
     {
-      if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_ACTIVATE)
+      CCECClient *client = device->GetClient();
+      if (client)
       {
-        if (CLibCEC::MenuStateChanged(CEC_MENU_STATE_ACTIVATED) == 1)
-          device->SetMenuState(CEC_MENU_STATE_ACTIVATED);
-      }
-      else if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_DEACTIVATE)
-      {
-        if (CLibCEC::MenuStateChanged(CEC_MENU_STATE_DEACTIVATED) == 1)
-          device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
+        if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_ACTIVATE)
+        {
+          if (client->MenuStateChanged(CEC_MENU_STATE_ACTIVATED) == 1)
+            device->SetMenuState(CEC_MENU_STATE_ACTIVATED);
+        }
+        else if (command.parameters[0] == CEC_MENU_REQUEST_TYPE_DEACTIVATE)
+        {
+          if (client->MenuStateChanged(CEC_MENU_STATE_DEACTIVATED) == 1)
+            device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
+        }
       }
       return device->TransmitMenuState(command.initiator);
     }
@@ -439,8 +452,8 @@ bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
 {
   if (m_processor->IsRunning())
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %i requests active source", (uint8_t) command.initiator);
-    m_processor->m_busDevices[command.initiator]->SetPowerStatus(CEC_POWER_STATUS_ON);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i requests active source", (uint8_t) command.initiator);
+    m_processor->GetDevice(command.initiator)->SetPowerStatus(CEC_POWER_STATUS_ON);
 
     vector<CCECBusDevice *> devices;
     for (size_t iDevicePtr = 0; iDevicePtr < GetMyDevices(devices); iDevicePtr++)
@@ -470,7 +483,9 @@ bool CCECCommandHandler::HandleRoutingInformation(const cec_command &command)
   if (command.parameters.size == 2)
   {
     uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
-    m_processor->SetActiveSource(iNewAddress);
+    CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
+    if (device)
+      device->MarkAsActiveSource();
   }
 
   return false;
@@ -521,26 +536,19 @@ bool CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
   if (m_processor->IsRunning() && command.parameters.size >= 2)
   {
     uint16_t iStreamAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
-    CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %i sets stream path to physical address %04x", command.initiator, iStreamAddress);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i sets stream path to physical address %04x", command.initiator, iStreamAddress);
 
     /* one of the device handled by libCEC has been made active */
     CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress);
-    if (device && m_busDevice->MyLogicalAddressContains(device->GetLogicalAddress()))
-    {
-      device->SetActiveSource();
-      device->TransmitImageViewOn();
-      device->TransmitActiveSource();
-
-      device->SetMenuState(CEC_MENU_STATE_ACTIVATED);
-      device->TransmitMenuState(command.initiator);
-    }
+    if (device && device->IsHandledByLibCEC())
+      device->ActivateSource();
   }
   return false;
 }
 
 bool CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
@@ -552,7 +560,7 @@ bool CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command
         uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
         CCECBusDevice *newActiveDevice = GetDeviceByPhysicalAddress(iNewAddress);
         if (newActiveDevice)
-          newActiveDevice->SetActiveSource();
+          newActiveDevice->MarkAsActiveSource();
         return ((CCECAudioSystem *) device)->TransmitSetSystemAudioMode(command.initiator);
       }
       else
@@ -606,25 +614,31 @@ bool CCECCommandHandler::HandleSetSystemAudioMode(const cec_command &command)
 
 bool CCECCommandHandler::HandleTextViewOn(const cec_command &command)
 {
-  m_processor->m_busDevices[command.initiator]->SetActiveSource();
+  m_processor->GetDevice(command.initiator)->MarkAsActiveSource();
   return true;
 }
 
 bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
 {
   if (m_processor->IsRunning() &&
-      m_busDevice->MyLogicalAddressContains(command.destination) &&
+      m_processor->IsHandledByLibCEC(command.destination) &&
       command.parameters.size > 0)
   {
-    CLibCEC::AddKey();
+    CCECBusDevice *device = GetDevice(command.destination);
+    if (!device)
+      return true;
+
+    CCECClient *client = device->GetClient();
+    if (client)
+      client->AddKey();
+
     if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
-      CLibCEC::SetCurrentButton((cec_user_control_code) command.parameters[0]);
+      client->SetCurrentButton((cec_user_control_code) command.parameters[0]);
 
     if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER ||
         command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION)
     {
       bool bPowerOn(true);
-      CCECBusDevice *device = GetDevice(command.destination);
       if (!device)
         return true;
 
@@ -632,23 +646,17 @@ bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
       // assume CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION does not
       if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER)
       {
-        cec_power_status status = device->GetPowerStatus();
+        cec_power_status status = device->GetCurrentPowerStatus();
         bPowerOn = !(status == CEC_POWER_STATUS_ON || status == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
       }
 
       if (bPowerOn)
       {
-        device->SetActiveSource();
-        device->TransmitImageViewOn();
-        device->TransmitActiveSource();
-
-        if (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
-            device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
-          ((CCECPlaybackDevice *)device)->TransmitDeckStatus(command.initiator);
+        device->ActivateSource();
       }
       else
       {
-        device->SetInactiveSource();
+        device->MarkAsInactiveSource();
         device->TransmitInactiveSource();
         device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
       }
@@ -661,9 +669,9 @@ bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
 
 bool CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
-    CLibCEC::AddKey();
-
+  CCECClient *client = m_processor->GetClient(command.destination);
+  if (client)
+    client->AddKey();
   return true;
 }
 
@@ -674,7 +682,10 @@ bool CCECCommandHandler::HandleVendorCommand(const cec_command & UNUSED(command)
 
 void CCECCommandHandler::UnhandledCommand(const cec_command &command)
 {
-  CLibCEC::AddLog(CEC_LOG_DEBUG, "unhandled command with opcode %02x from address %d", command.opcode, command.initiator);
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "unhandled command with opcode %02x from address %d", command.opcode, command.initiator);
+
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
+    m_processor->TransmitAbort(m_busDevice->GetLogicalAddress(), command.initiator, command.opcode, CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
 }
 
 size_t CCECCommandHandler::GetMyDevices(vector<CCECBusDevice *> &devices) const
@@ -696,12 +707,7 @@ size_t CCECCommandHandler::GetMyDevices(vector<CCECBusDevice *> &devices) const
 
 CCECBusDevice *CCECCommandHandler::GetDevice(cec_logical_address iLogicalAddress) const
 {
-  CCECBusDevice *device = NULL;
-
-  if (iLogicalAddress >= CECDEVICE_TV && iLogicalAddress <= CECDEVICE_BROADCAST)
-    device = m_processor->m_busDevices[iLogicalAddress];
-
-  return device;
+  return m_processor->GetDevice(iLogicalAddress);
 }
 
 CCECBusDevice *CCECCommandHandler::GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const
@@ -709,17 +715,12 @@ CCECBusDevice *CCECCommandHandler::GetDeviceByPhysicalAddress(uint16_t iPhysical
   return m_processor->GetDeviceByPhysicalAddress(iPhysicalAddress);
 }
 
-CCECBusDevice *CCECCommandHandler::GetDeviceByType(cec_device_type type) const
-{
-  return m_processor->GetDeviceByType(type);
-}
-
 bool CCECCommandHandler::SetVendorId(const cec_command &command)
 {
   bool bChanged(false);
   if (command.parameters.size < 3)
   {
-    CLibCEC::AddLog(CEC_LOG_WARNING, "invalid vendor ID received");
+    LIB_CEC->AddLog(CEC_LOG_WARNING, "invalid vendor ID received");
     return bChanged;
   }
 
@@ -735,16 +736,22 @@ bool CCECCommandHandler::SetVendorId(const cec_command &command)
 
 void CCECCommandHandler::SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress)
 {
-  if (!m_busDevice->MyLogicalAddressContains(iAddress))
+  if (!m_processor->IsHandledByLibCEC(iAddress))
   {
-    bool bOurAddress(m_processor->GetPhysicalAddress() == iNewAddress);
+    CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
+    bool bOurAddress(device && device->GetLogicalAddress() != m_busDevice->GetLogicalAddress() &&
+        device->IsHandledByLibCEC());
+
     GetDevice(iAddress)->SetPhysicalAddress(iNewAddress);
+
     if (bOurAddress)
     {
       /* another device reported the same physical address as ours
        * since we don't have physical address detection yet, we'll just use the
        * given address, increased by 0x100 for now */
-      m_processor->SetPhysicalAddress(iNewAddress + 0x100);
+      CCECClient *client = device->GetClient();
+      if (client)
+        client->SetPhysicalAddress(iNewAddress + 0x100);
     }
   }
 }
@@ -1016,7 +1023,7 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* =
 
   if (command.initiator == CECDEVICE_UNKNOWN)
   {
-    CLibCEC::AddLog(CEC_LOG_ERROR, "not transmitting a command without a valid initiator");
+    LIB_CEC->AddLog(CEC_LOG_ERROR, "not transmitting a command without a valid initiator");
     return bReturn;
   }
 
@@ -1026,11 +1033,11 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* =
     {
       if ((bReturn = m_processor->Transmit(command)) == true)
       {
-        CLibCEC::AddLog(CEC_LOG_DEBUG, "command transmitted");
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "command transmitted");
         if (bExpectResponse)
         {
           bReturn = m_waitForResponse->Wait(expectedResponse);
-          CLibCEC::AddLog(CEC_LOG_DEBUG, bReturn ? "expected response received (%X: %s)" : "expected response not received (%X: %s)", (int)expectedResponse, m_processor->ToString(expectedResponse));
+          LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? "expected response received (%X: %s)" : "expected response not received (%X: %s)", (int)expectedResponse, ToString(expectedResponse));
         }
       }
     }
@@ -1042,7 +1049,7 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* =
 bool CCECCommandHandler::ActivateSource(void)
 {
   if (m_busDevice->IsActiveSource() &&
-    m_busDevice->GetStatus(false) == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+    m_busDevice->IsHandledByLibCEC())
   {
     m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON);
     m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED);
index 24f62658b9009c419e07d057a923cc4aa5a6faaa..1bced84ff8fc469b17a004aa70891233913a1f78 100644 (file)
@@ -203,7 +203,6 @@ namespace CEC
     virtual size_t GetMyDevices(std::vector<CCECBusDevice *> &devices) const;
     virtual CCECBusDevice *GetDevice(cec_logical_address iLogicalAddress) const;
     virtual CCECBusDevice *GetDeviceByPhysicalAddress(uint16_t iPhysicalAddress) const;
-    virtual CCECBusDevice *GetDeviceByType(cec_device_type type) const;
 
     virtual bool SetVendorId(const cec_command &command);
     virtual void SetPhysicalAddress(cec_logical_address iAddress, uint16_t iNewAddress);
index b9103ec5f59da75a037aee61f68a68c9986bde46..e1632ee5d7e68faff2753fa5640658587570fc50 100644 (file)
@@ -53,6 +53,9 @@ using namespace PLATFORM;
 #define SL_COMMAND_CONNECT_REQUEST      0x04
 #define SL_COMMAND_SET_DEVICE_MODE      0x05
 
+#define LIB_CEC     m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
 CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) :
     CCECCommandHandler(busDevice),
     m_bSLEnabled(false),
@@ -99,37 +102,17 @@ bool CSLCommandHandler::InitHandler(void)
   return true;
 }
 
-bool CSLCommandHandler::ActivateSource(void)
-{
-  if (!m_processor->GetPrimaryDevice()->IsActiveSource())
-  {
-    CLibCEC::AddLog(CEC_LOG_NOTICE, "not activating the source because we're not marked as active");
-    return true;
-  }
-
-  {
-    CLockObject lock(m_SLMutex);
-    m_bActiveSourceSent = true;
-  }
-
-  CCECBusDevice *primary = m_processor->GetPrimaryDevice();
-  primary->SetActiveSource();
-  primary->SetPowerStatus(CEC_POWER_STATUS_ON);
-  primary->TransmitPowerState(CECDEVICE_TV);
-  primary->TransmitImageViewOn();
-  primary->TransmitActiveSource();
-  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]);
     CCECBusDevice *primary = m_processor->GetPrimaryDevice();
-    bool bSendPowerOffState(iAddress != primary->GetPhysicalAddress() && primary->IsActiveSource());
+    bool bSendPowerOffState(iAddress != primary->GetCurrentPhysicalAddress() && primary->IsActiveSource());
 
-    m_processor->SetActiveSource(iAddress);
+    CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iAddress);
+    if (device)
+      device->MarkAsActiveSource();
     if (bSendPowerOffState)
     {
       {
@@ -151,7 +134,7 @@ bool CSLCommandHandler::HandleDeviceVendorId(const cec_command &command)
   if (!SLInitialised() && command.initiator == CECDEVICE_TV)
   {
     cec_command response;
-    cec_command::Format(response, m_processor->GetLogicalAddress(), command.initiator, CEC_OPCODE_FEATURE_ABORT);
+    cec_command::Format(response, command.destination, command.initiator, CEC_OPCODE_FEATURE_ABORT);
     return Transmit(response);
   }
   return true;
@@ -159,7 +142,7 @@ bool CSLCommandHandler::HandleDeviceVendorId(const cec_command &command)
 
 bool CSLCommandHandler::HandleVendorCommand(const cec_command &command)
 {
-  if (!m_busDevice->MyLogicalAddressContains(command.destination))
+  if (!m_processor->IsHandledByLibCEC(command.destination))
     return true;
 
   if (command.parameters.size == 1 &&
@@ -215,7 +198,7 @@ void CSLCommandHandler::HandleVendorCommandPowerOn(const cec_command &command)
   if (device)
   {
     SetSLInitialised();
-    device->SetActiveSource();
+    device->MarkAsActiveSource();
     device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
     device->TransmitPowerState(command.initiator);
 
@@ -233,17 +216,20 @@ void CSLCommandHandler::HandleVendorCommandPowerOnStatus(const cec_command &comm
 {
   if (command.destination != CECDEVICE_BROADCAST)
   {
-    CCECBusDevice *device = m_processor->m_busDevices[m_processor->GetLogicalAddresses().primary];
-    device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
-    device->TransmitPowerState(command.initiator);
-    device->SetPowerStatus(CEC_POWER_STATUS_ON);
+    CCECBusDevice *device = m_processor->GetPrimaryDevice();
+    if (device)
+    {
+      device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+      device->TransmitPowerState(command.initiator);
+      device->SetPowerStatus(CEC_POWER_STATUS_ON);
+    }
   }
 }
 
 void CSLCommandHandler::HandleVendorCommandSLConnect(const cec_command &command)
 {
   SetSLInitialised();
-  TransmitVendorCommandSetDeviceMode(m_processor->GetLogicalAddress(), command.initiator, CEC_DEVICE_TYPE_RECORDING_DEVICE);
+  TransmitVendorCommandSetDeviceMode(command.destination, command.initiator, CEC_DEVICE_TYPE_RECORDING_DEVICE);
 
   ActivateSource();
 }
@@ -259,7 +245,7 @@ void CSLCommandHandler::TransmitVendorCommandSetDeviceMode(const cec_logical_add
 
 bool CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
 {
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination))
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
@@ -289,10 +275,10 @@ bool CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
 bool CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
 {
   bool bReturn(false);
-  if (m_processor->IsRunning() && m_busDevice->MyLogicalAddressContains(command.destination) && command.initiator == CECDEVICE_TV)
+  if (m_processor->IsRunning() && m_processor->IsHandledByLibCEC(command.destination) && command.initiator == CECDEVICE_TV)
   {
     CCECBusDevice *device = GetDevice(command.destination);
-    if (device && device->GetPowerStatus(false) != CEC_POWER_STATUS_ON)
+    if (device && device->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON)
     {
       bReturn = device->TransmitPowerState(command.initiator);
       device->SetPowerStatus(CEC_POWER_STATUS_ON);
@@ -308,7 +294,7 @@ bool CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
       else if (m_resetPowerState.IsSet() && m_resetPowerState.TimeLeft() > 0)
       {
         /* TODO assume that we've bugged out. the return button no longer works after this */
-        CLibCEC::AddLog(CEC_LOG_WARNING, "FIXME: LG seems to have bugged out. resetting to 'in transition standby to on'. the return button will not work");
+        LIB_CEC->AddLog(CEC_LOG_WARNING, "FIXME: LG seems to have bugged out. resetting to 'in transition standby to on'. the return button will not work");
         {
           CLockObject lock(m_SLMutex);
           m_bActiveSourceSent = false;
@@ -334,7 +320,7 @@ bool CSLCommandHandler::HandleRequestActiveSource(const cec_command &command)
   if (m_processor->IsRunning())
   {
     if (ActiveSourceSent())
-      CLibCEC::AddLog(CEC_LOG_DEBUG, ">> %i requests active source, ignored", (uint8_t) command.initiator);
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i requests active source, ignored", (uint8_t) command.initiator);
     else
       ActivateSource();
     return true;
@@ -344,7 +330,7 @@ bool CSLCommandHandler::HandleRequestActiveSource(const cec_command &command)
 
 bool CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
 {
-  if (command.parameters.size == 0 && m_processor->GetPrimaryDevice()->GetPowerStatus() == CEC_POWER_STATUS_ON && !SLInitialised() &&
+  if (command.parameters.size == 0 && m_processor->GetPrimaryDevice()->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON && !SLInitialised() &&
       command.initiator == CECDEVICE_TV)
   {
     m_processor->GetPrimaryDevice()->TransmitPowerState(command.initiator);
@@ -367,7 +353,7 @@ bool CSLCommandHandler::HandleStandby(const cec_command &command)
 
 void CSLCommandHandler::ResetSLState(void)
 {
-  CLibCEC::AddLog(CEC_LOG_NOTICE, "resetting SL initialised state");
+  LIB_CEC->AddLog(CEC_LOG_NOTICE, "resetting SL initialised state");
   CLockObject lock(m_SLMutex);
   m_bSLEnabled = false;
   m_bActiveSourceSent = false;
@@ -376,7 +362,7 @@ void CSLCommandHandler::ResetSLState(void)
 
 void CSLCommandHandler::SetSLInitialised(void)
 {
-  CLibCEC::AddLog(CEC_LOG_NOTICE, "SL initialised");
+  LIB_CEC->AddLog(CEC_LOG_NOTICE, "SL initialised");
   CLockObject lock(m_SLMutex);
   m_bSLEnabled = true;
 }
index fefb8b387dea30d8bf49b477279b19ee08847e9e..0eb6c8656e25170519279e9035c0bce66930da89 100644 (file)
@@ -43,7 +43,6 @@ namespace CEC
     virtual ~CSLCommandHandler(void) {};
 
     bool InitHandler(void);
-    bool ActivateSource(void);
 
   protected:
     bool HandleActiveSource(const cec_command &command);
index e8cf7c8c4d01f0aede754d5c2c71f76d94185c50..59eb5747cb6cc9693415286f836337647c5e1aab 100644 (file)
@@ -34,6 +34,7 @@
 #include "../devices/CECBusDevice.h"
 #include "../CECProcessor.h"
 #include "../LibCEC.h"
+#include "../CECClient.h"
 
 #define VL_POWER_CHANGE 0x20
 #define VL_POWERED_UP   0x00
@@ -42,6 +43,9 @@
 using namespace CEC;
 using namespace PLATFORM;
 
+#define LIB_CEC     m_busDevice->GetProcessor()->GetLib()
+#define ToString(p) LIB_CEC->ToString(p)
+
 CVLCommandHandler::CVLCommandHandler(CCECBusDevice *busDevice) :
     CCECCommandHandler(busDevice),
     m_bActiveSourcePending(false),
@@ -65,7 +69,7 @@ bool CVLCommandHandler::InitHandler(void)
 {
   CCECBusDevice *primary = m_processor->GetPrimaryDevice();
   if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
-    return m_processor->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+    return m_processor->GetPrimaryClient()->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
 
   return CCECCommandHandler::InitHandler();
 }
@@ -78,7 +82,7 @@ bool CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &comma
   {
     if (command.parameters.At(4) == VL_POWERED_UP)
     {
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "TV powered up");
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV powered up");
       {
         CLockObject lock(m_mutex);
         m_bPowerUpEventReceived = true;
@@ -86,9 +90,9 @@ bool CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &comma
       m_processor->TransmitPendingActiveSourceCommands();
     }
     else if (command.parameters.At(4) == VL_POWERED_DOWN)
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "TV powered down");
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV powered down");
     else if (command.parameters.At(4) == VL_POWERED_DOWN)
-      CLibCEC::AddLog(CEC_LOG_DEBUG, "unknown vendor command");
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "unknown vendor command");
 
     return true;
   }
@@ -100,8 +104,8 @@ bool CVLCommandHandler::TransmitActiveSource(const cec_logical_address iInitiato
 {
   bool bPowerUpEventReceived(false);
 
-  CCECBusDevice *tv = m_processor->m_busDevices[CECDEVICE_TV];
-  if (tv && tv->GetVendorId(false) == CEC_VENDOR_PANASONIC)
+  CCECBusDevice *tv = m_processor->GetDevice(CECDEVICE_TV);
+  if (tv && tv->GetCurrentVendorId() == CEC_VENDOR_PANASONIC)
   {
     CVLCommandHandler *handler = static_cast<CVLCommandHandler *>(tv->GetHandler());
     bPowerUpEventReceived = handler ? handler->PowerUpEventReceived() : false;
@@ -132,8 +136,8 @@ bool CVLCommandHandler::TransmitPendingActiveSourceCommands(void)
 
   if (bTransmitCommand)
   {
-    CLibCEC::AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
-    return CCECCommandHandler::TransmitActiveSource(m_busDevice->GetLogicalAddress(), m_busDevice->GetPhysicalAddress());
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
+    return CCECCommandHandler::TransmitActiveSource(m_busDevice->GetLogicalAddress(), m_busDevice->GetCurrentPhysicalAddress());
   }
   return true;
 }
@@ -146,7 +150,7 @@ bool CVLCommandHandler::PowerUpEventReceived(void)
       return true;
   }
 
-  cec_power_status powerStatus = m_busDevice->GetPowerStatus();
+  cec_power_status powerStatus = m_busDevice->GetCurrentPowerStatus();
 
   CLockObject lock(m_mutex);
   m_bPowerUpEventReceived = (powerStatus == CEC_POWER_STATUS_ON);