Merge branch 'development'
authorLars Op den Kamp <lars@opdenkamp.eu>
Wed, 27 Jun 2012 08:30:25 +0000 (10:30 +0200)
committerLars Op den Kamp <lars@opdenkamp.eu>
Wed, 27 Jun 2012 08:30:25 +0000 (10:30 +0200)
49 files changed:
ChangeLog
configure.ac
debian/changelog
debian/control
debian/control.hardy
include/cec.h
include/cectypes.h
project/LibCecSharp.vcproj
project/cec-config.rc
project/libcec.rc
project/testclient.rc
src/CecSharpTester/CecSharpClient.cs
src/CecSharpTester/Properties/AssemblyInfo.cs
src/LibCecSharp/AssemblyInfo.cpp
src/LibCecSharp/CecSharpTypes.h
src/LibCecSharp/LibCecSharp.cpp
src/cec-config-gui/CecConfigGUI.cs
src/cec-config-gui/Properties/AssemblyInfo.cs
src/cec-config/Makefile.am
src/cec-config/cec-config.cpp
src/lib/CECClient.cpp
src/lib/CECClient.h
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/CECTypeUtils.h
src/lib/LibCEC.cpp
src/lib/LibCEC.h
src/lib/Makefile.am
src/lib/adapter/USBCECAdapterCommunication.cpp
src/lib/adapter/USBCECAdapterDetection.cpp
src/lib/adapter/USBCECAdapterDetection.h
src/lib/adapter/USBCECAdapterMessageQueue.h
src/lib/devices/CECBusDevice.cpp
src/lib/devices/CECBusDevice.h
src/lib/implementations/ANCommandHandler.cpp
src/lib/implementations/ANCommandHandler.h
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h
src/lib/implementations/RLCommandHandler.cpp
src/lib/implementations/RLCommandHandler.h
src/lib/implementations/SLCommandHandler.cpp
src/lib/implementations/SLCommandHandler.h
src/lib/implementations/VLCommandHandler.cpp
src/lib/implementations/VLCommandHandler.h
src/lib/platform/os.h
src/lib/platform/threads/mutex.h
src/lib/platform/windows/os-edid.cpp
src/testclient/Makefile.am
src/testclient/main.cpp

index 3d69d4f3cd1d3f0b7f2075574dfe411cb8dbde92..b8b13b9f08a753946763ec6b1ddd1646435318af 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,62 @@
+libcec (1.7.2-1) unstable; urgency=low
+
+  * changed/added:
+    * display a warning message if libCEC was not compiled with adapter
+      detection for the target platform
+    * panasonic: added a vendor command for panasonic that will enable routing
+      of some more buttons on the remote (guide, text, ...)
+    * standby command won't be forwarded more than once every 10 seconds
+    * added vendor ids for Akai, AOC, Benq, Daewoo, Grundig, Medion, Sharp and
+      Vizio
+    * cec-client: don't display debug output by default in 'cec-client -l'
+
+  * interface changes:
+    * added a callback for clients that is called when a source is
+      (de)activated, so the client can respond to this action
+    * added cec_command::PushArray()
+
+  * fixed:
+    * command forwarding. fixes player not going into standby mode
+    * missing virtual keyword in CCECCommandHandler::
+      GetReplacementDeviceType()
+    * replace the handler (if needed) in GetHandler()
+    * reply with abort reason 'invalid operand' to vendor commands that we
+      don't understand
+    * changed all Handle...() commands to return a cec_abort_reason and send
+      the correct abort reason to the initiator as a response to directly
+      addressed messages
+    * changed 'couldn't change the ackmask: the connection is closed' into a
+      debug message
+    * don't send active source commands when the physical address is invalid or
+      unknown
+    * set the power status of a device to 'powered on' after it sends a stream
+      path change. can save an unneeded power state update request
+    * removed dupe code around delayed activate source commands. check for
+      delayed active source commands every 5 seconds instead of 15 seconds.
+    * panasonic: reset m_bPowerUpEventReceived in CVLCommandHandler when the
+      device lets us know it went into standby mode. fixes possibly failed
+      active source switches after it succeeded once
+    * panasonic: fixed delayed source switch for panasonic
+    * panasonic: mark the tv as powered up once it sends the audiomode request
+    * set the physical address of each device controlled by a CCECClient if
+      it's valid
+    * Windows could get stuck in a loop in case there an error occured while
+      reading registry entries
+    * ABI fixes (binary compat with v1.2 for Windows and v1.5.2 for others)
+    * replace the handler directly after getting the vendor id of a device when
+      registering a client
+    * copy the class member values of the old handler when creating a new
+      command handler, or a delayed activate source will get lost when the
+      handler is switched
+    * cec-client: wrong client version
+    * Makefile cleanups. don't link cec-client and cec-config against libudev
+      and liblockdev
+    * pin libcec to the same version as libcec1
+    * LibCecSharp: update the local configuration after connecting
+    * LibCecSharp: better handling of callbacks
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Wed, 27 Jun 2012 02:06:00 +0100
+
 libcec (1.7.1-1) unstable; urgency=low
 
   * changed/added:
index ba40f03f9443def488fb922592c5ce9e97123da4..3098d003fcf7889fa6758095f2a07c8f61a841c0 100644 (file)
@@ -1,15 +1,44 @@
-AC_INIT([libcec], 1:7:0)
+AC_PREREQ(2.59)
+AC_INIT([libcec], [1:7:0], [http://libcec.pulse-eight.com/])
 AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
 
 AC_PROG_CXX
 AC_PROG_LIBTOOL
 
+# search for pthread, required by all targets
+AC_SEARCH_LIBS([pthread_create],[pthread],,
+  AC_MSG_ERROR("required library 'pthread' is missing"))
+
+# search for dlopen, required by all targets
+AC_SEARCH_LIBS([dlopen], [dl],
+  [test "$ac_cv_search_dlopen" = "none required" || LIBS_DL=$ac_cv_search_dlopen],
+  AC_MSG_ERROR("required library 'dl' is missing"))
+
+
+# platform specific libs, required by all targets
+case "${host}" in
+  *-*-linux*)
+    LIBS+=" -lrt"
+    ;;
+  *-apple-darwin*)
+    ;;
+  *-freebsd*)
+    ;;
+esac
+
+libs_client=$LIBS
+
+# search for udev and lockdev, only required by libCEC
 has_libudev="yes"
 case "${host}" in
   *-*-linux*)
-    PKG_CHECK_MODULES([UDEV],[libudev],,[has_libudev="no"]; AC_MSG_WARN("library 'udev' is missing - adapter detection will not be available"))
-    AC_CHECK_HEADER(lockdev.h,, AC_MSG_ERROR("required library 'liblockdev' is missing"))
-    LIBS+=" -lrt -llockdev"
+    PKG_CHECK_MODULES([UDEV],[libudev],,
+      [has_libudev="no"]; AC_MSG_WARN("library 'udev' is missing - adapter detection will not be available"))
+
+    AC_CHECK_HEADER(lockdev.h,,
+      AC_MSG_ERROR("required library 'liblockdev' is missing"))
+
+    LIBS+=" -llockdev"
     ;;
   *-apple-darwin*)
     has_libudev="no";
@@ -20,23 +49,20 @@ case "${host}" in
     ;;
 esac
 
+# mark udev as available if it was found, so we can include adapter autodetection code
 if test "x$has_libudev" != "xno"; then
   INCLUDES="$INCLUDES $UDEV_CFLAGS";LIBS="$LIBS $UDEV_LIBS"
   AC_DEFINE([HAVE_LIBUDEV],[1],["Define to 1 if libudev is installed"])
   REQUIRES="udev"
 fi
 
-AC_SEARCH_LIBS([pthread_create],[pthread],, AC_MSG_ERROR("required library 'pthread' is missing"))
-
-libs_pre_dl=$LIBS
-  AC_SEARCH_LIBS(dlopen, [dl],
-    [test "$ac_cv_search_dlopen" = "none required" || LIBS_DL=$ac_cv_search_dlopen],
-    AC_MSG_ERROR("required library 'dl' is missing"))
-  AC_SUBST([LIBS_DL])
-LIBS=$libs_pre_dl
+LIBS_LIBCEC=$LIBS
+LIBS=$libs_client
 
 CXXFLAGS="-fPIC -Wall -Wextra -Wno-missing-field-initializers $CXXFLAGS"
 
-AC_SUBST(REQUIRES)
+AC_SUBST([REQUIRES])
+AC_SUBST([LIBS])
+AC_SUBST([LIBS_LIBCEC])
 AC_CONFIG_FILES([src/lib/libcec.pc])
 AC_OUTPUT([Makefile src/lib/Makefile src/testclient/Makefile src/cec-config/Makefile])
index 3d69d4f3cd1d3f0b7f2075574dfe411cb8dbde92..b8b13b9f08a753946763ec6b1ddd1646435318af 100644 (file)
@@ -1,3 +1,62 @@
+libcec (1.7.2-1) unstable; urgency=low
+
+  * changed/added:
+    * display a warning message if libCEC was not compiled with adapter
+      detection for the target platform
+    * panasonic: added a vendor command for panasonic that will enable routing
+      of some more buttons on the remote (guide, text, ...)
+    * standby command won't be forwarded more than once every 10 seconds
+    * added vendor ids for Akai, AOC, Benq, Daewoo, Grundig, Medion, Sharp and
+      Vizio
+    * cec-client: don't display debug output by default in 'cec-client -l'
+
+  * interface changes:
+    * added a callback for clients that is called when a source is
+      (de)activated, so the client can respond to this action
+    * added cec_command::PushArray()
+
+  * fixed:
+    * command forwarding. fixes player not going into standby mode
+    * missing virtual keyword in CCECCommandHandler::
+      GetReplacementDeviceType()
+    * replace the handler (if needed) in GetHandler()
+    * reply with abort reason 'invalid operand' to vendor commands that we
+      don't understand
+    * changed all Handle...() commands to return a cec_abort_reason and send
+      the correct abort reason to the initiator as a response to directly
+      addressed messages
+    * changed 'couldn't change the ackmask: the connection is closed' into a
+      debug message
+    * don't send active source commands when the physical address is invalid or
+      unknown
+    * set the power status of a device to 'powered on' after it sends a stream
+      path change. can save an unneeded power state update request
+    * removed dupe code around delayed activate source commands. check for
+      delayed active source commands every 5 seconds instead of 15 seconds.
+    * panasonic: reset m_bPowerUpEventReceived in CVLCommandHandler when the
+      device lets us know it went into standby mode. fixes possibly failed
+      active source switches after it succeeded once
+    * panasonic: fixed delayed source switch for panasonic
+    * panasonic: mark the tv as powered up once it sends the audiomode request
+    * set the physical address of each device controlled by a CCECClient if
+      it's valid
+    * Windows could get stuck in a loop in case there an error occured while
+      reading registry entries
+    * ABI fixes (binary compat with v1.2 for Windows and v1.5.2 for others)
+    * replace the handler directly after getting the vendor id of a device when
+      registering a client
+    * copy the class member values of the old handler when creating a new
+      command handler, or a delayed activate source will get lost when the
+      handler is switched
+    * cec-client: wrong client version
+    * Makefile cleanups. don't link cec-client and cec-config against libudev
+      and liblockdev
+    * pin libcec to the same version as libcec1
+    * LibCecSharp: update the local configuration after connecting
+    * LibCecSharp: better handling of callbacks
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Wed, 27 Jun 2012 02:06:00 +0100
+
 libcec (1.7.1-1) unstable; urgency=low
 
   * changed/added:
index e28796f1cde00fbcb8d15b5907e920fd1cc81cba..511fb0c227c5e235066491a92870d5c928258b12 100644 (file)
@@ -47,6 +47,6 @@ Description: USB CEC Adaptor communication Library (utility programs)
 
 Package: libcec
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libcec1
+Depends: ${shlibs:Depends}, ${misc:Depends}, libcec1 (= ${binary:Version})
 Description: Transitional package libcec.
 
index ed58c3530ad608ab60c0f35c80f033fd8d5f7ae1..e92e1b2498091f636697f3dca5da9812e379badf 100644 (file)
@@ -46,6 +46,6 @@ Description: USB CEC Adaptor communication Library (utility programs)
 
 Package: libcec
 Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, libcec1
+Depends: ${shlibs:Depends}, ${misc:Depends}, libcec1 (= ${binary:Version})
 Description: Transitional package libcec.
 
index 8b335c1c32043f45c1d83cddada755674ac4faa2..de7129de31b180ad5d57a2df083ed6e9e457f80c 100644 (file)
@@ -36,7 +36,7 @@
 
 #include "cectypes.h"
 
-#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_1_7_0
+#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_1_7_1
 
 namespace CEC
 {
@@ -60,6 +60,9 @@ namespace CEC
      */
     virtual void Close(void) = 0;
 
+// XXX XBMC Eden for Windows has been built against 1.2.0 and Ubuntu against 1.5.2
+// we accidently broke the abi between these versions, and this will ensure the upgrade will still work
+#if !defined(_WIN32) && !defined(_WIN64)
     /*!
      * @brief Set and enable the callback methods. If this method is not called, the GetNext...() methods will have to be used.
      * @param cbParam Parameter to pass to callback methods.
@@ -67,6 +70,7 @@ namespace CEC
      * @return True when enabled, false otherwise.
      */
     virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks) = 0;
+#endif
 
     /*!
      * @brief Try to find all connected CEC adapters. Only implemented on Linux and Windows at the moment.
@@ -153,6 +157,9 @@ namespace CEC
      */
     virtual bool SetPhysicalAddress(uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS) = 0;
 
+// XXX XBMC Eden for Windows has been built against 1.2.0 and Ubuntu against 1.5.2
+// we accidently broke the abi between these versions, and this will ensure the upgrade will still work
+#if !defined(_WIN32) && !defined(_WIN64)
     /*!
      * @deprecated Use libcec_configuration instead.
      * @brief Enable physical address detection (if the connected adapter supports this).
@@ -167,6 +174,7 @@ namespace CEC
      * @return True when changed, false otherwise.
      */
     virtual bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort) = 0;
+#endif
 
     /*!
      * @brief Power on the connected CEC capable devices.
@@ -269,12 +277,16 @@ namespace CEC
      */
     virtual cec_power_status GetDevicePowerStatus(cec_logical_address iLogicalAddress) = 0;
 
+// XXX XBMC Eden for Windows has been built against 1.2.0 and Ubuntu against 1.5.2
+// we accidently broke the abi between these versions, and this will ensure the upgrade will still work
+#if !defined(_WIN32) && !defined(_WIN64)
     /*!
      * @brief Get the physical address of the device with the given logical address.
      * @param iLogicalAddress The device to get the vendor id for.
      * @return The physical address or 0 if it wasn't found.
      */
     virtual uint16_t GetDevicePhysicalAddress(cec_logical_address iLogicalAddress) = 0;
+#endif
 
     /*!
      * @brief Sends a POLL message to a device.
@@ -436,6 +448,40 @@ namespace CEC
      * @return True when the device was found, false otherwise
      */
     virtual bool GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs = 10000) = 0;
+
+// XXX XBMC Eden for Windows has been built against 1.2.0 and Ubuntu against 1.5.2
+// we accidently broke the abi between these versions, and this will ensure the upgrade will still work
+#if defined(_WIN32) || defined(_WIN64)
+    /*!
+     * @brief Set and enable the callback methods. If this method is not called, the GetNext...() methods will have to be used.
+     * @param cbParam Parameter to pass to callback methods.
+     * @param callbacks The callbacks to set.
+     * @return True when enabled, false otherwise.
+     */
+    virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks) = 0;
+
+        /*!
+     * @deprecated Use libcec_configuration instead.
+     * @brief Enable physical address detection (if the connected adapter supports this).
+     * @return True when physical address detection was enabled, false otherwise.
+     */
+    virtual bool EnablePhysicalAddressDetection(void) = 0;
+
+    /*!
+     * @brief Changes the active HDMI port.
+     * @param iBaseDevice The device to which this libcec is connected.
+     * @param iPort The new port number.
+     * @return True when changed, false otherwise.
+     */
+    virtual bool SetHDMIPort(cec_logical_address iBaseDevice, uint8_t iPort) = 0;
+
+    /*!
+     * @brief Get the physical address of the device with the given logical address.
+     * @param iLogicalAddress The device to get the vendor id for.
+     * @return The physical address or 0 if it wasn't found.
+     */
+    virtual uint16_t GetDevicePhysicalAddress(cec_logical_address iLogicalAddress) = 0;
+#endif
   };
 };
 
@@ -443,10 +489,19 @@ namespace CEC
  * @brief Load the CEC adapter library.
  * @param strDeviceName How to present this device to other devices.
  * @param deviceTypes The device types to use on the CEC bus.
- * @param iPhysicalAddress The physical address to assume on the bus. If set to 0, libCEC will try to autodetect the address, with the data provided via SetHDMIPort()
  * @return An instance of ICECAdapter or NULL on error.
  */
-extern "C" DECLSPEC void * CECInit(const char *strDeviceName, CEC::cec_device_type_list deviceTypes, uint16_t iPhysicalAddress = 0);
+extern "C" DECLSPEC void * CECInit(const char *strDeviceName, CEC::cec_device_type_list deviceTypes);
+
+/*!
+ * @deprecated
+ */
+extern "C" DECLSPEC void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress = CEC::CECDEVICE_PLAYBACKDEVICE1, uint16_t iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS);
+
+/*!
+ * @brief Unload the CEC adapter library.
+ */
+extern "C" DECLSPEC void CECDestroy(CEC::ICECAdapter *instance);
 
 /*!
  * @brief Load the CEC adapter library.
@@ -461,9 +516,4 @@ extern "C" DECLSPEC void * CECInitialise(CEC::libcec_configuration *configuratio
  */
 extern "C" DECLSPEC bool CECStartBootloader(void);
 
-/*!
- * @brief Unload the CEC adapter library.
- */
-extern "C" DECLSPEC void CECDestroy(CEC::ICECAdapter *instance);
-
 #endif /* CECEXPORTS_H_ */
index b5ae1eca5dce16f6f9e191355155eb8bc88cc9c4..47168a296a663d66bf347c4ae17734868490038a 100644 (file)
@@ -110,6 +110,9 @@ namespace CEC {
 #define CEC_SERIAL_DEFAULT_BAUDRATE     38400
 #define CEC_CLEAR_INPUT_DEFAULT_WAIT    1000
 
+#define CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS 5000
+#define CEC_FORWARD_STANDBY_MIN_INTERVAL 10000
+
 #define CEC_MIN_LIB_VERSION          1
 #define CEC_LIB_VERSION_MAJOR        1
 #define CEC_LIB_VERSION_MAJOR_STR    "1"
@@ -673,6 +676,15 @@ typedef enum cec_vendor_id
   CEC_VENDOR_PHILIPS   = 0x00903E,
   CEC_VENDOR_SONY      = 0x080046,
   CEC_VENDOR_TOSHIBA   = 0x000039,
+  CEC_VENDOR_AKAI      = 0x0020C7,
+  CEC_VENDOR_AOC       = 0x002467,
+  CEC_VENDOR_BENQ      = 0x8065E9,
+  CEC_VENDOR_DAEWOO    = 0x009053,
+  CEC_VENDOR_GRUNDIG   = 0x00D0D5,
+  CEC_VENDOR_MEDION    = 0x000CB8,
+  CEC_VENDOR_SHARP     = 0x08001F,
+  CEC_VENDOR_VIZIO     = 0x6B746D,
+   
   CEC_VENDOR_UNKNOWN   = 0
 } cec_vendor_id;
 
@@ -790,10 +802,11 @@ typedef struct cec_command
   int32_t             transmit_timeout; /**< the timeout to use in ms */
 
 #ifdef __cplusplus
-  cec_command(void)
-  {
-    Clear();
-  }
+  // @todo re-add in v2.0 (breaks ABI)
+  //cec_command(void)
+  //{
+  //  Clear();
+  //}
 
   cec_command &operator =(const struct cec_command &command)
   {
@@ -901,6 +914,12 @@ typedef struct cec_command
 
     return CEC_OPCODE_NONE;
   }
+
+  void PushArray(size_t len, uint8_t *data)
+  {
+    for (size_t iPtr = 0; iPtr < len; iPtr++)
+      PushBack(data[iPtr]);
+  }
 #endif
 } cec_command;
 
@@ -1116,6 +1135,7 @@ typedef int (CEC_CDECL* CBCecCommandType)(void *param, const cec_command &);
 typedef int (CEC_CDECL* CBCecConfigurationChangedType)(void *param, const libcec_configuration &);
 typedef int (CEC_CDECL* CBCecAlertType)(void *param, const libcec_alert, const libcec_parameter &);
 typedef int (CEC_CDECL* CBCecMenuStateChangedType)(void *param, const cec_menu_state);
+typedef void (CEC_CDECL* CBCecSourceActivatedType)(void *param, const cec_logical_address, const uint8_t);
 
 typedef struct ICECCallbacks
 {
@@ -1166,9 +1186,17 @@ typedef struct ICECCallbacks
    */
   CBCecMenuStateChangedType CBCecMenuStateChanged;
 
+  /*!
+   * @brief Called when a source that's handled by this client is activated.
+   * @param logicalAddress The address that was just activated.
+   * @param bActivated 1 when activated, 0 when deactivated.
+   */
+  CBCecSourceActivatedType CBCecSourceActivated;
+
 #ifdef __cplusplus
-   ICECCallbacks(void) { Clear(); }
-  ~ICECCallbacks(void) { Clear(); };
+  // @todo re-add in v2.0 (breaks ABI)
+  // ICECCallbacks(void) { Clear(); }
+  //~ICECCallbacks(void) { Clear(); };
 
   void Clear(void)
   {
@@ -1178,6 +1206,7 @@ typedef struct ICECCallbacks
     CBCecConfigurationChanged = NULL;
     CBCecAlert                = NULL;
     CBCecMenuStateChanged     = NULL;
+    CBCecSourceActivated      = NULL;
   }
 #endif
 } ICECCallbacks;
@@ -1193,7 +1222,8 @@ typedef enum cec_client_version
   CEC_CLIENT_VERSION_1_6_1   = 0x1601,
   CEC_CLIENT_VERSION_1_6_2   = 0x1602,
   CEC_CLIENT_VERSION_1_6_3   = 0x1603,
-  CEC_CLIENT_VERSION_1_7_0   = 0x1700
+  CEC_CLIENT_VERSION_1_7_0   = 0x1700,
+  CEC_CLIENT_VERSION_1_7_1   = 0x1701
 } cec_client_version;
 
 typedef enum cec_server_version
@@ -1207,7 +1237,8 @@ typedef enum cec_server_version
   CEC_SERVER_VERSION_1_6_1   = 0x1601,
   CEC_SERVER_VERSION_1_6_2   = 0x1602,
   CEC_SERVER_VERSION_1_6_3   = 0x1603,
-  CEC_SERVER_VERSION_1_7_0   = 0x1700
+  CEC_SERVER_VERSION_1_7_0   = 0x1700,
+  CEC_SERVER_VERSION_1_7_1   = 0x1701
 } cec_server_version;
 
 typedef struct libcec_configuration
@@ -1245,8 +1276,9 @@ typedef struct libcec_configuration
   uint8_t               bMonitorOnly;         /*!< won't allocate a CCECClient when starting the connection when set (same as monitor mode). added in 1.6.3 */
 
 #ifdef __cplusplus
-   libcec_configuration(void) { Clear(); }
-  ~libcec_configuration(void) { Clear(); }
+  // @todo re-add in v2.0 (breaks ABI)
+  // libcec_configuration(void) { Clear(); }
+  //~libcec_configuration(void) { Clear(); }
 
   bool operator==(const libcec_configuration &other) const
   {
@@ -1329,15 +1361,6 @@ typedef struct libcec_configuration
 #endif
 } libcec_configuration;
 
-#ifdef UNUSED
-#elif defined(__GNUC__)
-#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
-#elif defined(__LCLINT__)
-#define UNUSED(x) /*@unused@*/ x
-#else
-#define UNUSED(x) x
-#endif
-
 #ifdef __cplusplus
 };
 };
index 0f2c49293d1e4fea0b7bf50ecd29a3744832f992..38be809f226717df49c5ec5634aded41bba021fc 100644 (file)
@@ -48,7 +48,7 @@
                                Name="VCCLCompilerTool"
                                Optimization="0"
                                AdditionalIncludeDirectories="&quot;$(SolutionDir)..\include&quot;;&quot;$(SolutionDir)..\src\lib\platform\windows&quot;"
-                               PreprocessorDefinitions="_DEBUG"
+                               PreprocessorDefinitions="_DEBUG;_CRT_SECURE_NO_WARNINGS"
                                RuntimeLibrary="3"
                                UsePrecompiledHeader="0"
                                WarningLevel="3"
                                Name="VCCLCompilerTool"
                                Optimization="0"
                                AdditionalIncludeDirectories="&quot;$(SolutionDir)..\include&quot;;&quot;$(SolutionDir)..\src\lib\platform\windows&quot;"
-                               PreprocessorDefinitions="_DEBUG"
+                               PreprocessorDefinitions="_DEBUG;_CRT_SECURE_NO_WARNINGS"
                                RuntimeLibrary="3"
                                UsePrecompiledHeader="0"
                                WarningLevel="3"
                        <Tool
                                Name="VCCLCompilerTool"
                                AdditionalIncludeDirectories="&quot;$(SolutionDir)..\include&quot;;&quot;$(SolutionDir)..\src\lib\platform\windows&quot;"
-                               PreprocessorDefinitions="NDEBUG"
+                               PreprocessorDefinitions="NDEBUG;_CRT_SECURE_NO_WARNINGS"
                                RuntimeLibrary="2"
                                UsePrecompiledHeader="0"
                                WarningLevel="3"
                        <Tool
                                Name="VCCLCompilerTool"
                                AdditionalIncludeDirectories="&quot;$(SolutionDir)..\include&quot;;&quot;$(SolutionDir)..\src\lib\platform\windows&quot;"
-                               PreprocessorDefinitions="NDEBUG"
+                               PreprocessorDefinitions="NDEBUG;_CRT_SECURE_NO_WARNINGS"
                                RuntimeLibrary="2"
                                UsePrecompiledHeader="0"
                                WarningLevel="3"
index 1e6cff7860b4564c57ca5c3a1128c9e2fa38dc93..e47ea2df3279b884fe8c99eab847d927c60998ad 100644 (file)
Binary files a/project/cec-config.rc and b/project/cec-config.rc differ
index b7645d5ae3a47fa076183d2726832d92e101a154..547d08c9389c3aa6ffc77b8c1cdf3db06311bb4f 100644 (file)
Binary files a/project/libcec.rc and b/project/libcec.rc differ
index e6d2bb14c8ac71a6bb7e7ecb0433f54ab51a26e3..1025fccbcb9e2494a1695bc100757a470fb7a5fc 100644 (file)
Binary files a/project/testclient.rc and b/project/testclient.rc differ
index cc3fb03b7efb0137793db6091da953cdaec67c3f..4afbb537da2f4dc080c4b9c2d651786b8ea9aa52 100644 (file)
@@ -43,13 +43,13 @@ namespace CecSharpClient
       Config = new LibCECConfiguration();
       Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice;
       Config.DeviceName = "CEC Tester";
-      Config.ClientVersion = CecClientVersion.Version1_6_2;
+      Config.ClientVersion = CecClientVersion.Version1_7_1;
       Config.SetCallbacks(this);
       LogLevel = (int)CecLogLevel.All;
 
       Lib = new LibCecSharp(Config);
 
-      Console.WriteLine("CEC Parser created - libcec version " + Lib.ToString(Config.ServerVersion));
+      Console.WriteLine("CEC Parser created - libCEC version " + Lib.ToString(Config.ServerVersion));
     }
 
     public override int ReceiveCommand(CecCommand command)
index e633261e09d35421cf000b8bd848377c9d26c643..1e6b929fe2366b60c548966326da45e7bf4be31e 100644 (file)
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.0.0")]
-[assembly: AssemblyFileVersion("1.7.0.0")]
+[assembly: AssemblyVersion("1.7.1.0")]
+[assembly: AssemblyFileVersion("1.7.1.0")]
index 1d5f769befdbc9ab62a4de1c8ad15ad9a9cb5e09..4aa58ec94f72588f731e47209df91ecf1959012a 100644 (file)
@@ -13,7 +13,7 @@ using namespace System::Security::Permissions;
 [assembly:AssemblyTrademarkAttribute("")];
 [assembly:AssemblyCultureAttribute("")];
 
-[assembly:AssemblyVersionAttribute("1.7.0.0")];
+[assembly:AssemblyVersionAttribute("1.7.1.0")];
 
 [assembly:ComVisible(false)];
 [assembly:CLSCompliantAttribute(true)];
index 9be7ab5b87b64285b63e5bde5290a3e51f86e4ba..33f3200ec10c7f858598061685eb6cc1eb55eb9a 100644 (file)
  *     http://www.pulse-eight.net/
  */
 
-#include <windows.h>
+#include "../lib/platform/threads/mutex.h"
 #include <vcclr.h>
 #include <msclr/marshal.h>
 #include "../../include/cec.h"
+#include <vector>
 
 #using <System.dll>
 
@@ -253,14 +254,22 @@ namespace CecSharp
 
        public enum class CecVendorId
        {
-               Samsung   = 0x00F0,
-               LG        = 0xE091,
-               Panasonic = 0x8045,
-               Pioneer   = 0xE036,
-               Onkyo     = 0x09B0,
-               Yamaha    = 0xA0DE,
-               Philips   = 0x903E,
+               Samsung   = 0x0000F0,
+               LG        = 0x00E091,
+               Panasonic = 0x008045,
+               Pioneer   = 0x00E036,
+               Onkyo     = 0x0009B0,
+               Yamaha    = 0x00A0DE,
+               Philips   = 0x00903E,
                Sony      = 0x080046,
+               Toshiba   = 0x000039,
+               Akai      = 0x0020C7,
+               Benq      = 0x8065E9,
+               Daewoo    = 0x009053,
+               Grundig   = 0x00D0D5,
+               Medion    = 0x000CB8,
+               Sharp     = 0x08001F,
+               Vizio     = 0x6B746D,
                Unknown   = 0
        };
 
@@ -356,9 +365,10 @@ namespace CecSharp
                Version1_5_3  = 0x1503,
                Version1_6_0  = 0x1600,
                Version1_6_1  = 0x1601,
-    Version1_6_2  = 0x1602,
-    Version1_6_3  = 0x1603,
-    Version1_7_0  = 0x1700
+               Version1_6_2  = 0x1602,
+               Version1_6_3  = 0x1603,
+               Version1_7_0  = 0x1700,
+               Version1_7_1  = 0x1701
        };
 
        public enum class CecServerVersion
@@ -370,9 +380,10 @@ namespace CecSharp
                Version1_5_3  = 0x1503,
                Version1_6_0  = 0x1600,
                Version1_6_1  = 0x1601,
-    Version1_6_2  = 0x1602,
-    Version1_6_3  = 0x1603,
-    Version1_7_0  = 0x1700
+               Version1_6_2  = 0x1602,
+               Version1_6_3  = 0x1603,
+               Version1_7_0  = 0x1700,
+               Version1_7_1  = 0x1701
        };
 
        public ref class CecAdapter
@@ -696,65 +707,126 @@ namespace CecSharp
        typedef int (__stdcall *CONFIGCB) (const CEC::libcec_configuration &config);
        typedef int (__stdcall *ALERTCB)  (const CEC::libcec_alert, const CEC::libcec_parameter &data);
        typedef int (__stdcall *MENUCB)   (const CEC::cec_menu_state newVal);
+       typedef void (__stdcall *ACTICB)  (const CEC::cec_logical_address logicalAddress, const uint8_t bActivated);
 
-       static LOGCB              g_logCB;
-       static KEYCB              g_keyCB;
-       static COMMANDCB          g_commandCB;
-       static CONFIGCB           g_configCB;
-       static ALERTCB            g_alertCB;
-       static MENUCB             g_menuCB;
-       static CEC::ICECCallbacks g_cecCallbacks;
+       typedef struct
+       {
+               LOGCB     logCB;
+               KEYCB     keyCB;
+               COMMANDCB commandCB;
+               CONFIGCB  configCB;
+               ALERTCB   alertCB;
+               MENUCB    menuCB;
+               ACTICB    sourceActivatedCB;
+       } UnmanagedCecCallbacks;
+
+       static PLATFORM::CMutex                   g_callbackMutex;
+       static std::vector<UnmanagedCecCallbacks> g_unmanagedCallbacks;
+  static CEC::ICECCallbacks                 g_cecCallbacks;
 
        int CecLogMessageCB(void *cbParam, const CEC::cec_log_message &message)
        {
-               if (g_logCB)
-                       return g_logCB(message);
+               if (cbParam)
+               {
+                       size_t iPtr = (size_t)cbParam;
+                       PLATFORM::CLockObject lock(g_callbackMutex);
+                       if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+                               return g_unmanagedCallbacks[iPtr].logCB(message);
+               }
                return 0;
        }
 
        int CecKeyPressCB(void *cbParam, const CEC::cec_keypress &key)
        {
-               if (g_keyCB)
-                       return g_keyCB(key);
+               if (cbParam)
+               {
+                       size_t iPtr = (size_t)cbParam;
+                       PLATFORM::CLockObject lock(g_callbackMutex);
+                       if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+                               return g_unmanagedCallbacks[iPtr].keyCB(key);
+               }
                return 0;
        }
 
        int CecCommandCB(void *cbParam, const CEC::cec_command &command)
        {
-               if (g_commandCB)
-                       return g_commandCB(command);
+               if (cbParam)
+               {
+                       size_t iPtr = (size_t)cbParam;
+                       PLATFORM::CLockObject lock(g_callbackMutex);
+                       if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+                               return g_unmanagedCallbacks[iPtr].commandCB(command);
+               }
                return 0;
        }
 
   int CecConfigCB(void *cbParam, const CEC::libcec_configuration &config)
        {
-               if (g_configCB)
-                       return g_configCB(config);
+               if (cbParam)
+               {
+                       size_t iPtr = (size_t)cbParam;
+                       PLATFORM::CLockObject lock(g_callbackMutex);
+                       if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+                               return g_unmanagedCallbacks[iPtr].configCB(config);
+               }
                return 0;
        }
 
        int CecAlertCB(void *cbParam, const CEC::libcec_alert alert, const CEC::libcec_parameter &data)
        {
-               if (g_alertCB)
-                       return g_alertCB(alert, data);
+               if (cbParam)
+               {
+                       size_t iPtr = (size_t)cbParam;
+                       PLATFORM::CLockObject lock(g_callbackMutex);
+                       if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+                               return g_unmanagedCallbacks[iPtr].alertCB(alert, data);
+               }
                return 0;
        }
 
        int CecMenuCB(void *cbParam, const CEC::cec_menu_state newVal)
        {
-               if (g_menuCB)
-                       return g_menuCB(newVal);
+               if (cbParam)
+               {
+                       size_t iPtr = (size_t)cbParam;
+                       PLATFORM::CLockObject lock(g_callbackMutex);
+                       if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+                               return g_unmanagedCallbacks[iPtr].menuCB(newVal);
+               }
                return 0;
        }
 
+       void CecSourceActivatedCB(void *cbParam, const CEC::cec_logical_address logicalAddress, const uint8_t bActivated)
+       {
+               if (cbParam)
+               {
+                       size_t iPtr = (size_t)cbParam;
+                       PLATFORM::CLockObject lock(g_callbackMutex);
+                       if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+                               g_unmanagedCallbacks[iPtr].sourceActivatedCB(logicalAddress, bActivated);
+               }
+       }
+
        #pragma managed
        // delegates for the unmanaged callback methods
-       public delegate int CecLogMessageManagedDelegate(const CEC::cec_log_message &);
-       public delegate int CecKeyPressManagedDelegate(const CEC::cec_keypress &);
-       public delegate int CecCommandManagedDelegate(const CEC::cec_command &);
-       public delegate int CecConfigManagedDelegate(const CEC::libcec_configuration &);
-       public delegate int CecAlertManagedDelegate(const CEC::libcec_alert, const CEC::libcec_parameter &);
-       public delegate int CecMenuManagedDelegate(const CEC::cec_menu_state newVal);
+       public delegate int  CecLogMessageManagedDelegate(const CEC::cec_log_message &);
+       public delegate int  CecKeyPressManagedDelegate(const CEC::cec_keypress &);
+       public delegate int  CecCommandManagedDelegate(const CEC::cec_command &);
+       public delegate int  CecConfigManagedDelegate(const CEC::libcec_configuration &);
+       public delegate int  CecAlertManagedDelegate(const CEC::libcec_alert, const CEC::libcec_parameter &);
+       public delegate int  CecMenuManagedDelegate(const CEC::cec_menu_state newVal);
+       public delegate void CecSourceActivatedManagedDelegate(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated);
+
+       void AssignCallbacks()
+       {
+               g_cecCallbacks.CBCecLogMessage           = CecLogMessageCB;
+               g_cecCallbacks.CBCecKeyPress             = CecKeyPressCB;
+               g_cecCallbacks.CBCecCommand              = CecCommandCB;
+               g_cecCallbacks.CBCecConfigurationChanged = CecConfigCB;
+               g_cecCallbacks.CBCecAlert                = CecAlertCB;
+               g_cecCallbacks.CBCecMenuStateChanged     = CecMenuCB;
+    g_cecCallbacks.CBCecSourceActivated      = CecSourceActivatedCB;
+       }
 
        // callback method interface
        public ref class CecCallbackMethods
@@ -762,14 +834,22 @@ namespace CecSharp
        public:
     CecCallbackMethods(void)
     {
+                       m_iCallbackPtr = -1;
+                       AssignCallbacks();
       m_bHasCallbacks = false;
       m_bDelegatesCreated = false;
     }
 
-       ~CecCallbackMethods(void)
-   {
-     DestroyDelegates();
-   }
+         ~CecCallbackMethods(void)
+    {
+      DestroyDelegates();
+    }
+
+               size_t GetCallbackPtr(void)
+               {
+                       PLATFORM::CLockObject lock(g_callbackMutex);
+                       return m_iCallbackPtr;
+               }
 
        protected:
    !CecCallbackMethods(void)
@@ -826,6 +906,10 @@ namespace CecSharp
                        return 0;
                }
 
+               virtual void SourceActivated(CecLogicalAddress logicalAddress, bool bActivated)
+               {
+               }
+
        protected:
                // managed callback methods
                int CecLogMessageManaged(const CEC::cec_log_message &message)
@@ -895,6 +979,12 @@ namespace CecSharp
                        return iReturn;
                }
 
+               void CecSourceActivatedManaged(const CEC::cec_logical_address logicalAddress, const uint8_t bActivated)
+               {
+                       if (m_bHasCallbacks)
+                               m_callbacks->SourceActivated((CecLogicalAddress)logicalAddress, bActivated == 1);
+               }
+
                void DestroyDelegates()
                {
       m_bHasCallbacks = false;
@@ -906,6 +996,7 @@ namespace CecSharp
                                m_commandGCHandle.Free();
                                m_alertGCHandle.Free();
                                m_menuGCHandle.Free();
+                               m_sourceActivatedGCHandle.Free();
                        }
                }
 
@@ -918,43 +1009,55 @@ namespace CecSharp
         msclr::interop::marshal_context ^ context = gcnew msclr::interop::marshal_context();
 
         // create the delegate method for the log message callback
-        m_logMessageDelegate           = gcnew CecLogMessageManagedDelegate(this, &CecCallbackMethods::CecLogMessageManaged);
-        m_logMessageGCHandle           = System::Runtime::InteropServices::GCHandle::Alloc(m_logMessageDelegate);
-        g_logCB                        = static_cast<LOGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_logMessageDelegate).ToPointer());
-        g_cecCallbacks.CBCecLogMessage = CecLogMessageCB;
+        m_logMessageDelegate      = gcnew CecLogMessageManagedDelegate(this, &CecCallbackMethods::CecLogMessageManaged);
+        m_logMessageGCHandle      = System::Runtime::InteropServices::GCHandle::Alloc(m_logMessageDelegate);
+                               m_logMessageCallback      = static_cast<LOGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_logMessageDelegate).ToPointer());
 
         // create the delegate method for the keypress callback
-        m_keypressDelegate           = gcnew CecKeyPressManagedDelegate(this, &CecCallbackMethods::CecKeyPressManaged);
-        m_keypressGCHandle           = System::Runtime::InteropServices::GCHandle::Alloc(m_keypressDelegate);
-        g_keyCB                      = static_cast<KEYCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_keypressDelegate).ToPointer());
-        g_cecCallbacks.CBCecKeyPress = CecKeyPressCB;
+        m_keypressDelegate        = gcnew CecKeyPressManagedDelegate(this, &CecCallbackMethods::CecKeyPressManaged);
+        m_keypressGCHandle        = System::Runtime::InteropServices::GCHandle::Alloc(m_keypressDelegate);
+                               m_keypressCallback        = static_cast<KEYCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_keypressDelegate).ToPointer());
 
         // create the delegate method for the command callback
-        m_commandDelegate           = gcnew CecCommandManagedDelegate(this, &CecCallbackMethods::CecCommandManaged);
-        m_commandGCHandle           = System::Runtime::InteropServices::GCHandle::Alloc(m_commandDelegate);
-        g_commandCB                 = static_cast<COMMANDCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_commandDelegate).ToPointer());
-        g_cecCallbacks.CBCecCommand = CecCommandCB;
+        m_commandDelegate         = gcnew CecCommandManagedDelegate(this, &CecCallbackMethods::CecCommandManaged);
+        m_commandGCHandle         = System::Runtime::InteropServices::GCHandle::Alloc(m_commandDelegate);
+                               m_commandCallback         = static_cast<COMMANDCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_commandDelegate).ToPointer());
 
         // create the delegate method for the configuration change callback
-        m_configDelegate            = gcnew CecConfigManagedDelegate(this, &CecCallbackMethods::CecConfigManaged);
-        m_configGCHandle            = System::Runtime::InteropServices::GCHandle::Alloc(m_configDelegate);
-        g_configCB                  = static_cast<CONFIGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_configDelegate).ToPointer());
-        g_cecCallbacks.CBCecConfigurationChanged = CecConfigCB;
+        m_configDelegate          = gcnew CecConfigManagedDelegate(this, &CecCallbackMethods::CecConfigManaged);
+        m_configGCHandle          = System::Runtime::InteropServices::GCHandle::Alloc(m_configDelegate);
+                               m_configCallback          = static_cast<CONFIGCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_configDelegate).ToPointer());
 
         // create the delegate method for the alert callback
-        m_alertDelegate            = gcnew CecAlertManagedDelegate(this, &CecCallbackMethods::CecAlertManaged);
-        m_alertGCHandle            = System::Runtime::InteropServices::GCHandle::Alloc(m_alertDelegate);
-        g_alertCB                  = static_cast<ALERTCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_alertDelegate).ToPointer());
-        g_cecCallbacks.CBCecAlert  = CecAlertCB;
+        m_alertDelegate           = gcnew CecAlertManagedDelegate(this, &CecCallbackMethods::CecAlertManaged);
+        m_alertGCHandle           = System::Runtime::InteropServices::GCHandle::Alloc(m_alertDelegate);
+                               m_alertCallback           = static_cast<ALERTCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_alertDelegate).ToPointer());
 
         // create the delegate method for the menu callback
-        m_menuDelegate             = gcnew CecMenuManagedDelegate(this, &CecCallbackMethods::CecMenuManaged);
-        m_menuGCHandle             = System::Runtime::InteropServices::GCHandle::Alloc(m_menuDelegate);
-        g_menuCB                   = static_cast<MENUCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_menuDelegate).ToPointer());
-        g_cecCallbacks.CBCecMenuStateChanged = CecMenuCB;
+        m_menuDelegate            = gcnew CecMenuManagedDelegate(this, &CecCallbackMethods::CecMenuManaged);
+        m_menuGCHandle            = System::Runtime::InteropServices::GCHandle::Alloc(m_menuDelegate);
+                               m_menuCallback            = static_cast<MENUCB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_menuDelegate).ToPointer());
+
+                         // create the delegate method for the source activated callback
+        m_sourceActivatedDelegate = gcnew CecSourceActivatedManagedDelegate(this, &CecCallbackMethods::CecSourceActivatedManaged);
+        m_sourceActivatedGCHandle = System::Runtime::InteropServices::GCHandle::Alloc(m_sourceActivatedDelegate);
+                               m_sourceActivatedCallback = static_cast<ACTICB>(System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(m_sourceActivatedDelegate).ToPointer());
 
         delete context;
-        m_bDelegatesCreated = true;
+
+                               UnmanagedCecCallbacks unmanagedCallbacks;
+                               unmanagedCallbacks.logCB             = m_logMessageCallback;
+                               unmanagedCallbacks.keyCB             = m_keypressCallback;
+                               unmanagedCallbacks.commandCB         = m_commandCallback;
+                               unmanagedCallbacks.configCB          = m_configCallback;
+                               unmanagedCallbacks.alertCB           = m_alertCallback;
+                               unmanagedCallbacks.menuCB            = m_menuCallback;
+                               unmanagedCallbacks.sourceActivatedCB = m_sourceActivatedCallback;
+
+                               PLATFORM::CLockObject lock(g_callbackMutex);
+                               g_unmanagedCallbacks.push_back(unmanagedCallbacks);
+                               m_iCallbackPtr = g_unmanagedCallbacks.size() - 1;
+                               m_bDelegatesCreated = true;
       }
     }
 
@@ -976,14 +1079,19 @@ namespace CecSharp
 
                CecAlertManagedDelegate ^                         m_alertDelegate;
                static System::Runtime::InteropServices::GCHandle m_alertGCHandle;
-               CONFIGCB                                          m_alertCallback;
+               ALERTCB                                           m_alertCallback;
 
                CecMenuManagedDelegate ^                          m_menuDelegate;
                static System::Runtime::InteropServices::GCHandle m_menuGCHandle;
                MENUCB                                            m_menuCallback;
 
+               CecSourceActivatedManagedDelegate ^               m_sourceActivatedDelegate;
+               static System::Runtime::InteropServices::GCHandle m_sourceActivatedGCHandle;
+               ACTICB                                            m_sourceActivatedCallback;
+
                CecCallbackMethods ^ m_callbacks;
          bool                 m_bHasCallbacks;
     bool                 m_bDelegatesCreated;
+               size_t               m_iCallbackPtr;
        };
 }
index 7f0667a84066d92245f91ba1827c7aa263aabcdc..cd0f6d05d3ae239afc2e8286b9e1ae7694c2e2c8 100644 (file)
@@ -82,6 +82,7 @@ namespace CecSharp
                        ConvertConfiguration(context, config, libCecConfig);
 
                        m_libCec = (ICECAdapter *) CECInitialise(&libCecConfig);
+                       config->Update(libCecConfig);
 
                        delete context;
                        return m_libCec != NULL;
@@ -135,11 +136,9 @@ namespace CecSharp
                        }
 
                        if (netConfig->ServerVersion >= CecServerVersion::Version1_6_3)
-                       {
-                         config.bMonitorOnly              = netConfig->MonitorOnlyClient ? 1 : 0;
-                       }
+                         config.bMonitorOnly = netConfig->MonitorOnlyClient ? 1 : 0;
 
-                       config.callbacks            = &g_cecCallbacks;
+                       config.callbacks = &g_cecCallbacks;
                }
 
        public:
@@ -189,7 +188,7 @@ namespace CecSharp
                virtual bool EnableCallbacks(CecCallbackMethods ^ callbacks) override
                {
                        if (m_libCec && CecCallbackMethods::EnableCallbacks(callbacks))
-                               return m_libCec->EnableCallbacks(NULL, &g_cecCallbacks);
+                               return m_libCec->EnableCallbacks((void*)GetCallbackPtr(), &g_cecCallbacks);
 
                        return false;
                }
index 848ad60c7b978d02a71dbd9abae158a75ba1fec2..1bd2f071ba5da0e2eb52546cee3ebc25eb04ffda 100644 (file)
@@ -28,7 +28,7 @@ namespace CecConfigGui
       Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice;
       Config.DeviceName = "CEC Config";
       Config.GetSettingsFromROM = true;
-      Config.ClientVersion = CecClientVersion.Version1_5_1;
+      Config.ClientVersion = CecClientVersion.Version1_7_1;
       Callbacks = new CecCallbackWrapper(this);
       Config.SetCallbacks(Callbacks);
       LoadXMLConfiguration(ref Config);
index 1a83d3ec997991cf7af03c89238949881cc59cb3..56ca7ec14ec81a87a96a4c0c48528d058f0cb624 100644 (file)
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.0.0")]
-[assembly: AssemblyFileVersion("1.7.0.0")]
+[assembly: AssemblyVersion("1.7.1.0")]
+[assembly: AssemblyFileVersion("1.7.1.0")]
index a6c6c393d13af441e0b61369e86f1c9af59edb9d..da7b89b6e14c9701690b6fe8d094532f7570eb48 100644 (file)
@@ -2,4 +2,4 @@ bin_PROGRAMS = cec-config
 cec_config_SOURCES = cec-config.cpp
 
 cec_config_CPPFLAGS = -I@abs_top_srcdir@/include
-cec_config_LDFLAGS = @LIBS_DL@
\ No newline at end of file
+cec_config_LDFLAGS = @LIBS@
index 57931ee81dfb4dcbe59e54bdb8e23cfcc89a8768..7b203cb87c079b7663cb4c850009a9fcdfed2945 100644 (file)
@@ -315,6 +315,8 @@ bool PowerOnTV(uint64_t iTimeout = 60000)
 
 int main (int UNUSED(argc), char *UNUSED(argv[]))
 {
+  g_callbacks.Clear();
+  g_config.Clear();
   PrintToStdOut("=== USB-CEC Adapter Configuration ===\n");
   if (!OpenConnection())
     return 1;
index 7cf542bd1766ee445214d6cd718ee4c3b8a28a11..b0d7e188da38fd98a138214b6f5cb79c59e34f3c 100644 (file)
@@ -50,8 +50,10 @@ CCECClient::CCECClient(CCECProcessor *processor, const libcec_configuration &con
     m_bInitialised(false),
     m_bRegistered(false),
     m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
-    m_buttontime(0)
+    m_buttontime(0),
+    m_iPreventForwardingPowerOffCommand(0)
 {
+  m_configuration.Clear();
   // set the initial configuration
   SetConfiguration(configuration);
 }
@@ -123,7 +125,7 @@ bool CCECClient::OnRegister(void)
 
   // make the primary device the active source if the option is set
   if (m_configuration.bActivateSource == 1)
-    GetPrimaryDevice()->ActivateSource();
+    GetPrimaryDevice()->ActivateSource(500);
 
   return true;
 }
@@ -137,7 +139,7 @@ bool CCECClient::SetHDMIPort(const cec_logical_address iBaseDevice, const uint8_
       iPort > CEC_MAX_HDMI_PORTNUMBER)
     return bReturn;
 
-  LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
+  LIB_CEC->AddLog(CEC_LOG_NOTICE, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
 
   // update the configuration
   {
@@ -269,6 +271,7 @@ void CCECClient::SetSupportedDeviceTypes(void)
     if (!types.IsSet(type))
       types.Add(type);
   }
+  m_processor->GetTV()->MarkHandlerReady();
 
   // set the new type list
   m_configuration.deviceTypes = types;
@@ -881,14 +884,28 @@ bool CCECClient::SetConfiguration(const libcec_configuration &configuration)
 
 void CCECClient::AddCommand(const cec_command &command)
 {
-  CLockObject lock(m_mutex);
+  // don't forward the standby opcode more than once every 10 seconds
+  if (command.opcode == CEC_OPCODE_STANDBY)
+  {
+    CLockObject lock(m_mutex);
+    if (m_iPreventForwardingPowerOffCommand != 0 &&
+        m_iPreventForwardingPowerOffCommand > GetTimeMs())
+      return;
+    else
+      m_iPreventForwardingPowerOffCommand = GetTimeMs() + CEC_FORWARD_STANDBY_MIN_INTERVAL;
+  }
 
-  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 (command.destination == CECDEVICE_BROADCAST || GetLogicalAddresses().IsSet(command.destination))
+  {
+    CLockObject lock(m_mutex);
 
-  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");
+    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)
@@ -905,6 +922,30 @@ int CCECClient::MenuStateChanged(const cec_menu_state newState)
   return 0;
 }
 
+void CCECClient::SourceActivated(const cec_logical_address logicalAddress)
+{
+  CLockObject lock(m_mutex);
+
+  LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> source activated: %s (%x)", ToString(logicalAddress), logicalAddress);
+
+  if (m_configuration.callbacks &&
+      m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_7_1 &&
+      m_configuration.callbacks->CBCecSourceActivated)
+    m_configuration.callbacks->CBCecSourceActivated(m_configuration.callbackParam, logicalAddress, 1);
+}
+
+void CCECClient::SourceDeactivated(const cec_logical_address logicalAddress)
+{
+  CLockObject lock(m_mutex);
+
+  LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> source deactivated: %s (%x)", ToString(logicalAddress), logicalAddress);
+
+  if (m_configuration.callbacks &&
+      m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_7_1 &&
+      m_configuration.callbacks->CBCecSourceActivated)
+    m_configuration.callbacks->CBCecSourceActivated(m_configuration.callbackParam, logicalAddress, 0);
+}
+
 void CCECClient::Alert(const libcec_alert type, const libcec_parameter &param)
 {
   CLockObject lock(m_mutex);
@@ -1172,7 +1213,10 @@ cec_device_type_list CCECClient::GetDeviceTypes(void)
 bool CCECClient::SetDevicePhysicalAddress(const uint16_t iPhysicalAddress)
 {
   if (!CLibCEC::IsValidPhysicalAddress(iPhysicalAddress))
+  {
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - not setting invalid physical address %04x", __FUNCTION__, iPhysicalAddress);
     return false;
+  }
 
   // reconfigure all devices
   cec_logical_address reactivateSource(CECDEVICE_UNKNOWN);
index 87a4b7fbaf071d9067ea897dc1ca8f9ac1fb7233..26944a7068281229d444b36e77dedbf6c2d1a673 100644 (file)
@@ -182,6 +182,8 @@ namespace CEC
     virtual void                  AddKey(const cec_keypress &key);
     virtual void                  SetCurrentButton(const cec_user_control_code iButtonCode);
     virtual void                  CheckKeypressTimeout(void);
+    virtual void                  SourceActivated(const cec_logical_address logicalAddress);
+    virtual void                  SourceDeactivated(const cec_logical_address logicalAddress);
 
   protected:
     /*!
@@ -305,6 +307,7 @@ namespace CEC
     PLATFORM::CMutex                        m_logMutex;       /**< mutex that is held when sending a log message back to the client */
     cec_user_control_code                   m_iCurrentButton; /**< the control code of the button that's currently held down (if any) */
     int64_t                                 m_buttontime;     /**< the timestamp when the button was pressed (in seconds since epoch), or 0 if none was pressed. */
+    int64_t                                 m_iPreventForwardingPowerOffCommand; /**< prevent forwarding standby commands until this time */
     PLATFORM::SyncedBuffer<cec_log_message> m_logBuffer;      /**< @deprecated will be removed in v2.0. buffer for log messages */
     PLATFORM::SyncedBuffer<cec_keypress>    m_keyBuffer;      /**< @deprecated will be removed in v2.0. buffer for keypresses */
     PLATFORM::SyncedBuffer<cec_command>     m_commandBuffer;  /**< @deprecated will be removed in v2.0. buffer for commands */
index ca323fc4b67851fd3f26a58ff5b3998595b5bc56..28adee3282e4a22b6631a267403b5df512ed544f 100644 (file)
@@ -51,7 +51,7 @@ using namespace std;
 using namespace PLATFORM;
 
 #define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000
-#define ACTIVE_SOURCE_CHECK_TIMEOUT    15000
+#define ACTIVE_SOURCE_CHECK_INTERVAL   500
 
 #define ToString(x) CCECTypeUtils::ToString(x)
 
@@ -198,19 +198,6 @@ void CCECProcessor::ReplaceHandlers(void)
     it->second->ReplaceHandler(true);
 }
 
-void CCECProcessor::CheckPendingActiveSource(void)
-{
-  if (!CECInitialised())
-    return;
-
-  // check each device
-  for (CECDEVICEMAP::iterator it = m_busDevices->Begin(); it != m_busDevices->End(); it++)
-  {
-    if (it->second->GetHandler()->ActiveSourcePending())
-      it->second->ActivateSource();
-  }
-}
-
 bool CCECProcessor::OnCommandReceived(const cec_command &command)
 {
   return m_inBuffer.Push(command);
@@ -220,8 +207,8 @@ void *CCECProcessor::Process(void)
 {
   m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started");
 
-  cec_command command;
-  CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_TIMEOUT);
+  cec_command command; command.Clear();
+  CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_INTERVAL);
 
   // as long as we're not being stopped and the connection is open
   while (!IsStopped() && m_communication->IsOpen())
@@ -241,8 +228,9 @@ void *CCECProcessor::Process(void)
       // check whether we need to activate a source, if it failed before
       if (activeSourceCheck.TimeLeft() == 0)
       {
-        CheckPendingActiveSource();
-        activeSourceCheck.Init(ACTIVE_SOURCE_CHECK_TIMEOUT);
+        if (CECInitialised())
+          TransmitPendingActiveSourceCommands();
+        activeSourceCheck.Init(ACTIVE_SOURCE_CHECK_INTERVAL);
       }
     }
   }
@@ -413,6 +401,7 @@ bool CCECProcessor::Transmit(const cec_command &data)
     m_iLastTransmission = GetTimeMs();
     // set the number of tries
     iMaxTries = initiator->GetHandler()->GetTransmitRetries() + 1;
+    initiator->MarkHandlerReady();
   }
 
   // and try to send the command
@@ -565,7 +554,9 @@ bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator)
 bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress)
 {
   // stream path changes are sent by the TV
-  return GetTV()->GetHandler()->TransmitSetStreamPath(iPhysicalAddress);
+  bool bReturn = GetTV()->GetHandler()->TransmitSetStreamPath(iPhysicalAddress);
+  GetTV()->MarkHandlerReady();
+  return bReturn;
 }
 
 bool CCECProcessor::CanPersistConfiguration(void)
@@ -646,7 +637,9 @@ bool CCECProcessor::RegisterClient(CCECClient *client)
   }
 
   // ensure that we know the vendor id of the TV
-  GetTV()->GetVendorId(CECDEVICE_UNREGISTERED);
+  CCECBusDevice *tv = GetTV();
+  tv->GetVendorId(CECDEVICE_UNREGISTERED);
+  tv->ReplaceHandler(false);
 
   // unregister the client first if it's already been marked as registered
   if (client->IsRegistered())
@@ -675,6 +668,10 @@ bool CCECProcessor::RegisterClient(CCECClient *client)
   m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses);
   for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++)
   {
+               // set the physical address of the device at this LA
+    if (CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
+      (*it)->SetPhysicalAddress(configuration.iPhysicalAddress);
+
     // replace a previous client
     CLockObject lock(m_mutex);
     m_clients.erase((*it)->GetLogicalAddress());
@@ -684,7 +681,7 @@ bool CCECProcessor::RegisterClient(CCECClient *client)
   // get the settings from the rom
   if (configuration.bGetSettingsFromROM == 1)
   {
-    libcec_configuration config;
+    libcec_configuration config; config.Clear();
     m_communication->GetConfiguration(config);
 
     CLockObject lock(m_mutex);
@@ -729,6 +726,7 @@ bool CCECProcessor::RegisterClient(CCECClient *client)
     CCECCommandHandler *handler = GetTV()->GetHandler();
     if (handler)
       handler->InitHandler();
+    GetTV()->MarkHandlerReady();
   }
 
   return bReturn;
index 04d84f55ee2f5edab2997a5aec3d51a5df25d316..5f496d2631558506045e645ecf450e4ba37c5995 100644 (file)
@@ -134,7 +134,6 @@ namespace CEC
       void SetCECInitialised(bool bSetTo = true);
 
       void ReplaceHandlers(void);
-      void CheckPendingActiveSource(void);
       bool PhysicalAddressInUse(uint16_t iPhysicalAddress);
       bool SetAckMask(uint16_t iMask);
 
index 5e39f547d73b0db8b012a40cc39371213d9dd501..a62637bdfb2634263dd640edfaf1f62b42693d9a 100644 (file)
@@ -494,6 +494,22 @@ namespace CEC
         return "Sony";
       case CEC_VENDOR_TOSHIBA:
         return "Toshiba";
+      case CEC_VENDOR_AKAI:
+        return "Akai";
+      case CEC_VENDOR_AOC:
+        return "AOC";
+      case CEC_VENDOR_BENQ:
+        return "Benq";
+      case CEC_VENDOR_DAEWOO:
+        return "Daewoo";
+      case CEC_VENDOR_GRUNDIG:
+        return "Grundig";
+      case CEC_VENDOR_MEDION:
+        return "Medion";
+      case CEC_VENDOR_SHARP:
+        return "Sharp";
+      case CEC_VENDOR_VIZIO:
+        return "Vizio";
       default:
         return "Unknown";
       }
@@ -523,6 +539,8 @@ namespace CEC
         return "1.6.3";
       case CEC_CLIENT_VERSION_1_7_0:
         return "1.7.0";
+      case CEC_CLIENT_VERSION_1_7_1:
+        return "1.7.1";
       default:
         return "Unknown";
       }
@@ -552,9 +570,30 @@ namespace CEC
         return "1.6.3";
       case CEC_SERVER_VERSION_1_7_0:
         return "1.7.0";
+      case CEC_SERVER_VERSION_1_7_1:
+        return "1.7.1";
       default:
         return "Unknown";
       }
     }
+
+    static const char *ToString(const cec_abort_reason reason)
+    {
+      switch(reason)
+      {
+      case CEC_ABORT_REASON_UNRECOGNIZED_OPCODE:
+        return "unrecognised opcode";
+      case CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND:
+        return "not in correct mode to respond";
+      case CEC_ABORT_REASON_CANNOT_PROVIDE_SOURCE:
+        return "cannot provide source";
+      case CEC_ABORT_REASON_INVALID_OPERAND:
+        return "invalid operand";
+      case CEC_ABORT_REASON_REFUSED:
+        return "refused";
+      default:
+        return "unknown";
+      }
+    }
   };
 }
index 56ece65b08d706d7275b6f04fd696ccd1482511e..c0931c3e963d3fb724c5da88ba7d74e9b2cd1502 100644 (file)
@@ -114,6 +114,12 @@ void CLibCEC::Close(void)
 
 int8_t CLibCEC::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
 {
+  if (!CUSBCECAdapterDetection::CanAutodetect())
+  {
+    AddLog(CEC_LOG_WARNING, "libCEC has not been compiled with adapter detection code for this target, so the path to the COM port has to be provided to libCEC");
+    return 0;
+  }
+
   return CUSBCECAdapterDetection::FindAdapters(deviceList, iBufSize, strDevicePath);
 }
 
@@ -469,6 +475,13 @@ void CLibCEC::AddLog(const cec_log_level level, const char *strFormat, ...)
     (*it)->AddLog(message);
 }
 
+void CLibCEC::AddCommand(const cec_command &command)
+{
+  // send the command to all clients
+  for (vector<CCECClient *>::iterator it = m_clients.begin(); it != m_clients.end(); it++)
+    (*it)->AddCommand(command);
+}
+
 void CLibCEC::Alert(const libcec_alert type, const libcec_parameter &param)
 {
   // send the alert to all clients
@@ -543,14 +556,14 @@ void * CECInitialise(libcec_configuration *configuration)
   return static_cast< void* > (lib);
 }
 
-void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types, uint16_t iPhysicalAddress /* = 0 */)
+void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types)
 {
-  libcec_configuration configuration;
+  libcec_configuration configuration; configuration.Clear();
 
   // client version < 1.5.0
   snprintf(configuration.strDeviceName, 13, "%s", strDeviceName);
   configuration.deviceTypes      = types;
-  configuration.iPhysicalAddress = iPhysicalAddress;
+  configuration.iPhysicalAddress = CEC_INVALID_PHYSICAL_ADDRESS;
 
   if (configuration.deviceTypes.IsEmpty())
     configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
@@ -558,6 +571,18 @@ void * CECInit(const char *strDeviceName, CEC::cec_device_type_list types, uint1
   return CECInitialise(&configuration);
 }
 
+void * CECCreate(const char *strDeviceName, CEC::cec_logical_address iLogicalAddress /* = CEC::CECDEVICE_PLAYBACKDEVICE1 */, uint16_t iPhysicalAddress /* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
+{
+  libcec_configuration configuration; configuration.Clear();
+
+  // client version < 1.5.0
+  snprintf(configuration.strDeviceName, 13, "%s", strDeviceName);
+  configuration.iPhysicalAddress = iPhysicalAddress;
+  configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+
+  return CECInitialise(&configuration);
+}
+
 bool CECStartBootloader(void)
 {
   bool bReturn(false);
@@ -593,7 +618,6 @@ bool CLibCEC::GetDeviceInformation(const char *strPort, libcec_configuration *co
 
 // no longer being used
 void CLibCEC::AddKey(const cec_keypress &UNUSED(key)) {}
-void CLibCEC::AddCommand(const cec_command &UNUSED(command)) {}
 void CLibCEC::ConfigurationChanged(const libcec_configuration &UNUSED(config)) {}
 void CLibCEC::SetCurrentButton(cec_user_control_code UNUSED(iButtonCode)) {}
 CLibCEC *CLibCEC::GetInstance(void) { return NULL; }
index 0ef3e832d3d318218eda23c4beeccceefd40947e..6407e57a8fe479c28ba8151a11c6c29c4d7debbd 100644 (file)
@@ -134,7 +134,7 @@ namespace CEC
       void AddLog(const cec_log_level level, const char *strFormat, ...);
       static void AddKey(void) {}                                           //UNUSED
       static void AddKey(const cec_keypress &key);                          //UNUSED
-      static void AddCommand(const cec_command &command);                   //UNUSED
+      void AddCommand(const cec_command &command);
       static void ConfigurationChanged(const libcec_configuration &config); //UNUSED
       static void SetCurrentButton(cec_user_control_code iButtonCode);      //UNUSED
       void CheckKeypressTimeout(void);
index 30637f2920a091df0e365a4486d8a5fa62906b50..3d34f83c3b035610538198c688b012f81d8f338f 100644 (file)
@@ -35,5 +35,5 @@ libcec_la_SOURCES = CECProcessor.cpp \
                     platform/adl/adl-edid.cpp \
                     platform/nvidia/nv-edid.cpp
  
-libcec_la_LDFLAGS = @LIBS@ -version-info @VERSION@
+libcec_la_LDFLAGS = @LIBS_LIBCEC@ -version-info @VERSION@
 libcec_la_CPPFLAGS = -I@abs_top_srcdir@/include
index 45be4a6c739855de665581bf2802c085d1365be7..b3f0f7da7ba3209806b402c2e6e839d4c0b2648f 100644 (file)
@@ -512,7 +512,7 @@ bool CUSBCECAdapterCommunication::SetAckMask(uint16_t iMask)
     return true;
   }
 
-  LIB_CEC->AddLog(CEC_LOG_ERROR, "couldn't change the ackmask: the connection is closed");
+  LIB_CEC->AddLog(CEC_LOG_DEBUG, "couldn't change the ackmask: the connection is closed");
   return false;
 }
 
index 8775b4e55bbb2444c8b9a841e3e57f0e3748773f..78b2760a3b43f369759debd7ca136416ef25d280 100644 (file)
@@ -115,6 +115,15 @@ bool FindComPort(CStdString &strLocation)
 }
 #endif
 
+bool CUSBCECAdapterDetection::CanAutodetect(void)
+{
+#if defined(__APPLE__) || defined(HAVE_LIBUDEV) || defined(__WINDOWS__) || defined(__FreeBSD__)
+  return true;
+#else
+  return false;
+#endif
+}
+
 uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath /* = NULL */)
 {
   uint8_t iFound(0);
index 9be3a579346dda4ef177203070591358c9352a9f..9b6c624322c0b8fac152bf928e6221d36d504786 100644 (file)
@@ -38,6 +38,7 @@ namespace CEC
   class CUSBCECAdapterDetection
   {
   public:
-    static uint8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL); 
+    static uint8_t FindAdapters(cec_adapter *deviceList, uint8_t iBufSize, const char *strDevicePath = NULL);
+    static bool    CanAutodetect(void);
   };
 };
index 4646fe497cdeb7a56883ad291ed877ad8fb050d1..44c930be3cd7efcc84001506ac8c9943655222dd 100644 (file)
@@ -136,7 +136,11 @@ namespace CEC
     CCECAdapterMessageQueue(CUSBCECAdapterCommunication *com) :
       PLATFORM::CThread(),
       m_com(com),
-      m_iNextMessage(0) {}
+      m_iNextMessage(0)
+    {
+      m_currentCECFrame.Clear();
+    }
+
     virtual ~CCECAdapterMessageQueue(void);
 
     /*!
index 8f966a233194dd748e76a1a43c1b85263ca1a225..91dd83538c90ee213310c22c93ed648548ea1861 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "CECBusDevice.h"
 #include "../CECProcessor.h"
+#include "../CECClient.h"
 #include "../implementations/ANCommandHandler.h"
 #include "../implementations/CECCommandHandler.h"
 #include "../implementations/SLCommandHandler.h"
@@ -71,7 +72,8 @@ CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogi
   m_deviceStatus          (CEC_DEVICE_STATUS_UNKNOWN),
   m_iHandlerUseCount      (0),
   m_bAwaitingReceiveFailed(false),
-  m_bVendorIdRequested    (false)
+  m_bVendorIdRequested    (false),
+  m_waitForResponse       (new CWaitForResponse)
 {
   m_handler = new CCECCommandHandler(this);
 
@@ -86,6 +88,7 @@ CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogi
 CCECBusDevice::~CCECBusDevice(void)
 {
   DELETE_AND_NULL(m_handler);
+  DELETE_AND_NULL(m_waitForResponse);
 }
 
 bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
@@ -107,21 +110,27 @@ bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
       if (CCECCommandHandler::HasSpecificHandler(m_vendor))
       {
         LIB_CEC->AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
+
+        int32_t iTransmitTimeout     = m_handler->m_iTransmitTimeout;
+        int32_t iTransmitWait        = m_handler->m_iTransmitWait;
+        int8_t  iTransmitRetries     = m_handler->m_iTransmitRetries;
+        int64_t iActiveSourcePending = m_handler->m_iActiveSourcePending;
+
         DELETE_AND_NULL(m_handler);
 
         switch (m_vendor)
         {
         case CEC_VENDOR_SAMSUNG:
-          m_handler = new CANCommandHandler(this);
+          m_handler = new CANCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
           break;
         case CEC_VENDOR_LG:
-          m_handler = new CSLCommandHandler(this);
+          m_handler = new CSLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
           break;
         case CEC_VENDOR_PANASONIC:
-          m_handler = new CVLCommandHandler(this);
+          m_handler = new CVLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
           break;
         default:
-          m_handler = new CCECCommandHandler(this);
+          m_handler = new CCECCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending);
           break;
         }
 
@@ -148,6 +157,13 @@ bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
   return true;
 }
 
+CCECCommandHandler *CCECBusDevice::GetHandler(void)
+{
+  ReplaceHandler(false);
+  MarkBusy();
+  return m_handler;
+}
+
 bool CCECBusDevice::HandleCommand(const cec_command &command)
 {
   bool bHandled(false);
@@ -223,7 +239,7 @@ void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
 
   // signal threads that are waiting for a reponse
   MarkBusy();
-  m_handler->SignalOpcode(cec_command::GetResponseOpcode(opcode));
+  SignalOpcode(cec_command::GetResponseOpcode(opcode));
   MarkReady();
 }
 
@@ -793,6 +809,7 @@ void CCECBusDevice::ResetDeviceStatus(void)
   m_iLastActive = 0;
   m_bVendorIdRequested = false;
   m_unsupportedFeatures.clear();
+  m_waitForResponse->Clear();
 
   if (m_deviceStatus != CEC_DEVICE_STATUS_UNKNOWN)
     LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'unknown'", GetLogicalAddressName(), m_iLogicalAddress);
@@ -882,12 +899,21 @@ bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest)
   return bReturn;
 }
 
-bool CCECBusDevice::ActivateSource(void)
+bool CCECBusDevice::ActivateSource(uint64_t iDelay /* = 0 */)
 {
   MarkAsActiveSource();
-  LIB_CEC->AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
   MarkBusy();
-  bool bReturn = m_handler->ActivateSource();
+  bool bReturn(true);
+  if (iDelay == 0)
+  {
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending active source message for '%s'", ToString(m_iLogicalAddress));
+    bReturn = m_handler->ActivateSource();
+  }
+  else
+  {
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "scheduling active source message for '%s'", ToString(m_iLogicalAddress));
+    m_handler->ScheduleActivateSource(iDelay);
+  }
   MarkReady();
   return bReturn;
 }
@@ -909,38 +935,76 @@ bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
 
 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);
+  bool bWasActivated(false);
+
+  // set the power status to powered on
+  SetPowerStatus(CEC_POWER_STATUS_ON);
 
+  // mark this device as active source
+  {
+    CLockObject lock(m_mutex);
+    if (!m_bActiveSource)
+    {
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
+      bWasActivated = true;
+    }
+    else
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
+
+    m_bActiveSource = true;
+  }
+
+  // mark other devices as inactive sources
   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);
+  if (bWasActivated)
+  {
+    CCECClient *client = GetClient();
+    if (client)
+      client->SourceActivated(m_iLogicalAddress);
+  }
 }
 
 void CCECBusDevice::MarkAsInactiveSource(void)
 {
+  bool bWasDeactivated(false);
   {
     CLockObject lock(m_mutex);
     if (m_bActiveSource)
+    {
       LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
+      bWasDeactivated = true;
+    }
     m_bActiveSource = false;
   }
+
+  if (bWasDeactivated)
+  {
+    CCECClient *client = GetClient();
+    if (client)
+      client->SourceDeactivated(m_iLogicalAddress);
+  }
 }
 
 bool CCECBusDevice::TransmitActiveSource(void)
 {
   bool bSendActiveSource(false);
+  uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
 
   {
     CLockObject lock(m_mutex);
+    if (!HasValidPhysicalAddress())
+    {
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X) has an invalid physical address (%04x), not sending active source commands", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
+      return false;
+    }
+
+    iPhysicalAddress = m_iPhysicalAddress;
+
     if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
       LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
     else if (m_bActiveSource)
@@ -956,7 +1020,7 @@ bool CCECBusDevice::TransmitActiveSource(void)
   if (bSendActiveSource)
   {
     MarkBusy();
-    bActiveSourceSent = m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
+    bActiveSourceSent = m_handler->TransmitActiveSource(m_iLogicalAddress, iPhysicalAddress);
     MarkReady();
   }
 
@@ -999,7 +1063,7 @@ bool CCECBusDevice::TransmitInactiveSource(void)
 bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
 {
   MarkBusy();
-  bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
+  bool bReturn = m_handler->ActivateSource(true);
   MarkReady();
   return bReturn;
 }
@@ -1236,3 +1300,13 @@ CCECClient *CCECBusDevice::GetClient(void)
 {
   return m_processor->GetClient(m_iLogicalAddress);
 }
+
+void CCECBusDevice::SignalOpcode(cec_opcode opcode)
+{
+  m_waitForResponse->Received(opcode);
+}
+
+bool CCECBusDevice::WaitForOpcode(cec_opcode opcode)
+{
+  return m_waitForResponse->Wait(opcode);
+}
index 0e11d42725a5591f5670b60a5e02bf52501afa68..89fb690088dea9054599fba9c2837485b29fc100 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "../../../include/cectypes.h"
 #include <set>
+#include <map>
 #include "../platform/threads/mutex.h"
 #include "../platform/util/StdString.h"
 
@@ -47,6 +48,85 @@ namespace CEC
   class CCECTuner;
   class CCECTV;
 
+  class CResponse
+  {
+  public:
+    CResponse(cec_opcode opcode) :
+        m_opcode(opcode){}
+    ~CResponse(void)
+    {
+      Broadcast();
+    }
+
+    bool Wait(uint32_t iTimeout)
+    {
+      return m_event.Wait(iTimeout);
+    }
+
+    void Broadcast(void)
+    {
+      m_event.Broadcast();
+    }
+
+  private:
+    cec_opcode       m_opcode;
+    PLATFORM::CEvent m_event;
+  };
+
+  class CWaitForResponse
+  {
+  public:
+    CWaitForResponse(void) {}
+    ~CWaitForResponse(void)
+    {
+      Clear();
+    }
+
+    void Clear()
+    {
+      PLATFORM::CLockObject lock(m_mutex);
+      for (std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.begin(); it != m_waitingFor.end(); it++)
+        it->second->Broadcast();
+      m_waitingFor.clear();
+    }
+
+    bool Wait(cec_opcode opcode, uint32_t iTimeout = CEC_DEFAULT_TRANSMIT_WAIT)
+    {
+      CResponse *response = GetEvent(opcode);
+      return response ? response->Wait(iTimeout) : false;
+    }
+
+    void Received(cec_opcode opcode)
+    {
+      CResponse *response = GetEvent(opcode);
+      if (response)
+        response->Broadcast();
+    }
+
+  private:
+    CResponse *GetEvent(cec_opcode opcode)
+    {
+      CResponse *retVal(NULL);
+      {
+        PLATFORM::CLockObject lock(m_mutex);
+        std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.find(opcode);
+        if (it != m_waitingFor.end())
+        {
+          retVal = it->second;
+        }
+        else
+        {
+          retVal = new CResponse(opcode);
+          m_waitingFor[opcode] = retVal;
+        }
+        return retVal;
+      }
+    }
+
+    PLATFORM::CMutex                 m_mutex;
+    std::map<cec_opcode, CResponse*> m_waitingFor;
+  };
+
   class CCECBusDevice
   {
     friend class CCECProcessor;
@@ -56,7 +136,19 @@ namespace CEC
     virtual ~CCECBusDevice(void);
 
     virtual bool                  ReplaceHandler(bool bActivateSource = true);
-    virtual CCECCommandHandler *  GetHandler(void) const        { return m_handler; };
+
+    // TODO use something smarter than this
+    /*!
+     * @brief Get the command handler for this device. Call MarkHandlerReady() when done with it.
+     * @return The current handler.
+     */
+    virtual CCECCommandHandler *  GetHandler(void);
+
+    /*!
+     * @brief To be called after GetHandler(), when no longer using it.
+     */
+    virtual void                  MarkHandlerReady(void) { MarkReady(); }
+
     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; }
@@ -124,7 +216,7 @@ namespace CEC
     virtual void                  SetMenuState(const cec_menu_state state);
     virtual bool                  TransmitMenuState(const cec_logical_address destination);
 
-    virtual bool                  ActivateSource(void);
+    virtual bool                  ActivateSource(uint64_t iDelay = 0);
     virtual bool                  IsActiveSource(void) const    { return m_bActiveSource; }
     virtual bool                  RequestActiveSource(bool bWaitForResponse = true);
     virtual void                  MarkAsActiveSource(void);
@@ -141,6 +233,8 @@ namespace CEC
     virtual bool                  TryLogicalAddress(void);
 
     CCECClient *                  GetClient(void);
+    void                          SignalOpcode(cec_opcode opcode);
+    bool                          WaitForOpcode(cec_opcode opcode);
 
            CCECAudioSystem *      AsAudioSystem(void);
     static CCECAudioSystem *      AsAudioSystem(CCECBusDevice *device);
@@ -184,5 +278,6 @@ namespace CEC
     unsigned              m_iHandlerUseCount;
     bool                  m_bAwaitingReceiveFailed;
     bool                  m_bVendorIdRequested;
+    CWaitForResponse     *m_waitForResponse;
   };
 };
index 7c2d05906d7b4a33550edb0eb55cbfcdd129268f..8eccf88457b57750571d1ef5c6789105ae216da7 100644 (file)
@@ -41,68 +41,56 @@ using namespace CEC;
 #define LIB_CEC     m_busDevice->GetProcessor()->GetLib()
 #define ToString(p) LIB_CEC->ToString(p)
 
-CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice) :
-    CCECCommandHandler(busDevice)
+CANCommandHandler::CANCommandHandler(CCECBusDevice *busDevice,
+                                     int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+                                     int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+                                     int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+                                     int64_t iActiveSourcePending /* = 0 */) :
+    CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending)
 {
   m_vendorId = CEC_VENDOR_SAMSUNG;
   m_bOPTSendDeckStatusUpdateOnActiveSource = false;
 }
 
-bool CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
+int CANCommandHandler::HandleVendorRemoteButtonDown(const cec_command &command)
 {
-  if (m_processor->CECInitialised() && 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;
+  if (command.parameters.size == 0)
+    return CEC_ABORT_REASON_INVALID_OPERAND;
 
-    switch (command.parameters[0])
-    {
-    case CEC_USER_CONTROL_CODE_AN_RETURN:
-      key.keycode = client && client->GetClientVersion() >= CEC_CLIENT_VERSION_1_5_0 ?
-        CEC_USER_CONTROL_CODE_AN_RETURN :
-        CEC_USER_CONTROL_CODE_EXIT;
-      break;
-    case CEC_USER_CONTROL_CODE_AN_CHANNELS_LIST:
-      key.keycode = CEC_USER_CONTROL_CODE_AN_CHANNELS_LIST;
-      break;
-    default:
-      break;
-    }
+  if (!m_processor->CECInitialised())
+    return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 
-    if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN && client)
-      client->AddKey(key);
-  }
+  CCECClient *client = m_processor->GetClient(command.destination);
+  if (!client)
+    return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 
-  return true;
-}
+  cec_keypress key;
+  key.duration = CEC_BUTTON_TIMEOUT;
+  key.keycode = CEC_USER_CONTROL_CODE_UNKNOWN;
 
-bool CANCommandHandler::HandleCommand(const cec_command &command)
-{
-  bool bHandled(false);
-  if (m_processor->IsHandledByLibCEC(command.destination))
+  switch (command.parameters[0])
   {
-    switch(command.opcode)
-    {
-    case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
-      bHandled = true;
-      HandleVendorRemoteButtonDown(command);
-      break;
-    case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
-      bHandled = true;
-      HandleUserControlRelease(command);
-      break;
-    default:
-      break;
-    }
+  case CEC_USER_CONTROL_CODE_AN_RETURN:
+    key.keycode = client && client->GetClientVersion() >= CEC_CLIENT_VERSION_1_5_0 ?
+      CEC_USER_CONTROL_CODE_AN_RETURN :
+      CEC_USER_CONTROL_CODE_EXIT;
+    break;
+  case CEC_USER_CONTROL_CODE_AN_CHANNELS_LIST:
+    key.keycode = CEC_USER_CONTROL_CODE_AN_CHANNELS_LIST;
+    break;
+  default:
+    break;
   }
 
-  if (!bHandled)
-    bHandled = CCECCommandHandler::HandleCommand(command);
+  if (key.keycode != CEC_USER_CONTROL_CODE_UNKNOWN && client)
+    client->AddKey(key);
+
+  return COMMAND_HANDLED;
+}
 
-  return bHandled;
+int CANCommandHandler::HandleVendorRemoteButtonUp(const cec_command &command)
+{
+  return HandleUserControlRelease(command);
 }
 
 bool CANCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination)
index 567684fa7cf78e4bcd99edf95a1be9611f0783cb..3b08cbd04a8ae5839cc76f2d3ea7d8e6ed65554a 100644 (file)
@@ -38,13 +38,17 @@ namespace CEC
   class CANCommandHandler : public CCECCommandHandler
   {
   public:
-    CANCommandHandler(CCECBusDevice *busDevice);
+    CANCommandHandler(CCECBusDevice *busDevice,
+                      int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+                      int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+                      int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+                      int64_t iActiveSourcePending = 0);
     virtual ~CANCommandHandler(void) {};
 
-    bool HandleCommand(const cec_command &command);
+    int HandleVendorRemoteButtonDown(const cec_command &command);
+    int HandleVendorRemoteButtonUp(const cec_command &command);
 
   protected:
-    bool HandleVendorRemoteButtonDown(const cec_command &command);
     bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
   };
 };
index a240c9086739cc343e3e25354c5750d7acaedbfd..ffe78b839589f3ca6a3a2c16f1120c34219aadd9 100644 (file)
@@ -47,346 +47,343 @@ using namespace PLATFORM;
 #define LIB_CEC     m_busDevice->GetProcessor()->GetLib()
 #define ToString(p) CCECTypeUtils::ToString(p)
 
-CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) :
+CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice,
+                                       int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+                                       int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+                                       int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+                                       int64_t iActiveSourcePending /* = 0 */) :
     m_busDevice(busDevice),
     m_processor(m_busDevice->GetProcessor()),
-    m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT),
-    m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT),
-    m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES),
+    m_iTransmitTimeout(iTransmitTimeout),
+    m_iTransmitWait(iTransmitWait),
+    m_iTransmitRetries(iTransmitRetries),
     m_bHandlerInited(false),
     m_bOPTSendDeckStatusUpdateOnActiveSource(false),
     m_vendorId(CEC_VENDOR_UNKNOWN),
-    m_waitForResponse(new CWaitForResponse),
-    m_bActiveSourcePending(false)
+    m_iActiveSourcePending(iActiveSourcePending)
 {
 }
 
-CCECCommandHandler::~CCECCommandHandler(void)
-{
-  DELETE_AND_NULL(m_waitForResponse);
-}
-
 bool CCECCommandHandler::HandleCommand(const cec_command &command)
 {
   if (command.opcode_set == 0)
     return HandlePoll(command);
 
-  bool bHandled(true);
+  int iHandled(CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
 
-  CCECClient *client = m_busDevice->GetClient();
-  if (client)
-    client->AddCommand(command);
+  LIB_CEC->AddCommand(command);
 
   switch(command.opcode)
   {
   case CEC_OPCODE_REPORT_POWER_STATUS:
-    HandleReportPowerStatus(command);
+    iHandled = HandleReportPowerStatus(command);
     break;
   case CEC_OPCODE_CEC_VERSION:
-    HandleDeviceCecVersion(command);
+    iHandled = HandleDeviceCecVersion(command);
     break;
   case CEC_OPCODE_SET_MENU_LANGUAGE:
-    HandleSetMenuLanguage(command);
+    iHandled = HandleSetMenuLanguage(command);
     break;
   case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
-    if (m_processor->CECInitialised())
-      HandleGivePhysicalAddress(command);
+    iHandled = HandleGivePhysicalAddress(command);
     break;
   case CEC_OPCODE_GET_MENU_LANGUAGE:
-    if (m_processor->CECInitialised())
-      HandleGiveMenuLanguage(command);
+    iHandled = HandleGiveMenuLanguage(command);
     break;
   case CEC_OPCODE_GIVE_OSD_NAME:
-    if (m_processor->CECInitialised())
-      HandleGiveOSDName(command);
+    iHandled = HandleGiveOSDName(command);
     break;
   case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID:
-    if (m_processor->CECInitialised())
-      HandleGiveDeviceVendorId(command);
+    iHandled = HandleGiveDeviceVendorId(command);
     break;
   case CEC_OPCODE_DEVICE_VENDOR_ID:
-    HandleDeviceVendorId(command);
+    iHandled = HandleDeviceVendorId(command);
     break;
   case CEC_OPCODE_VENDOR_COMMAND_WITH_ID:
-    HandleDeviceVendorCommandWithId(command);
+    iHandled = HandleDeviceVendorCommandWithId(command);
     break;
   case CEC_OPCODE_GIVE_DECK_STATUS:
-    if (m_processor->CECInitialised())
-      HandleGiveDeckStatus(command);
+    iHandled = HandleGiveDeckStatus(command);
     break;
   case CEC_OPCODE_DECK_CONTROL:
-    HandleDeckControl(command);
+    iHandled = HandleDeckControl(command);
     break;
   case CEC_OPCODE_MENU_REQUEST:
-    if (m_processor->CECInitialised())
-      HandleMenuRequest(command);
+    iHandled = HandleMenuRequest(command);
     break;
   case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS:
-    if (m_processor->CECInitialised())
-      HandleGiveDevicePowerStatus(command);
+    iHandled = HandleGiveDevicePowerStatus(command);
     break;
   case CEC_OPCODE_GET_CEC_VERSION:
-    if (m_processor->CECInitialised())
-      HandleGetCecVersion(command);
+    iHandled = HandleGetCecVersion(command);
     break;
   case CEC_OPCODE_USER_CONTROL_PRESSED:
-    if (m_processor->CECInitialised())
-      HandleUserControlPressed(command);
+    iHandled = HandleUserControlPressed(command);
     break;
   case CEC_OPCODE_USER_CONTROL_RELEASE:
-    if (m_processor->CECInitialised())
-      HandleUserControlRelease(command);
+    iHandled = HandleUserControlRelease(command);
     break;
   case CEC_OPCODE_GIVE_AUDIO_STATUS:
-    if (m_processor->CECInitialised())
-      HandleGiveAudioStatus(command);
+    iHandled = HandleGiveAudioStatus(command);
     break;
   case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
-    if (m_processor->CECInitialised())
-      HandleGiveSystemAudioModeStatus(command);
+    iHandled = HandleGiveSystemAudioModeStatus(command);
     break;
   case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST:
-    if (m_processor->CECInitialised())
-      HandleSystemAudioModeRequest(command);
+    iHandled = HandleSystemAudioModeRequest(command);
     break;
   case CEC_OPCODE_REPORT_AUDIO_STATUS:
-    HandleReportAudioStatus(command);
+    iHandled = HandleReportAudioStatus(command);
     break;
   case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS:
-    HandleSystemAudioModeStatus(command);
+    iHandled = HandleSystemAudioModeStatus(command);
     break;
   case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
-    HandleSetSystemAudioMode(command);
+    iHandled = HandleSetSystemAudioMode(command);
     break;
   case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
-    if (m_processor->CECInitialised())
-      HandleRequestActiveSource(command);
+    iHandled = HandleRequestActiveSource(command);
     break;
   case CEC_OPCODE_SET_STREAM_PATH:
-    HandleSetStreamPath(command);
+    iHandled = HandleSetStreamPath(command);
     break;
   case CEC_OPCODE_ROUTING_CHANGE:
-    HandleRoutingChange(command);
+    iHandled = HandleRoutingChange(command);
     break;
   case CEC_OPCODE_ROUTING_INFORMATION:
-    HandleRoutingInformation(command);
+    iHandled = HandleRoutingInformation(command);
     break;
   case CEC_OPCODE_STANDBY:
-    if (m_processor->CECInitialised())
-      HandleStandby(command);
+    iHandled = HandleStandby(command);
     break;
   case CEC_OPCODE_ACTIVE_SOURCE:
-    HandleActiveSource(command);
+    iHandled = HandleActiveSource(command);
     break;
   case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
-    HandleReportPhysicalAddress(command);
+    iHandled = HandleReportPhysicalAddress(command);
     break;
   case CEC_OPCODE_SET_OSD_NAME:
-    HandleSetOSDName(command);
+    iHandled = HandleSetOSDName(command);
     break;
   case CEC_OPCODE_IMAGE_VIEW_ON:
-    HandleImageViewOn(command);
+    iHandled = HandleImageViewOn(command);
     break;
   case CEC_OPCODE_TEXT_VIEW_ON:
-    HandleTextViewOn(command);
+    iHandled = HandleTextViewOn(command);
     break;
   case CEC_OPCODE_FEATURE_ABORT:
-    HandleFeatureAbort(command);
+    iHandled = HandleFeatureAbort(command);
     break;
   case CEC_OPCODE_VENDOR_COMMAND:
-    HandleVendorCommand(command);
+    iHandled = HandleVendorCommand(command);
+    break;
+  case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN:
+    iHandled = HandleVendorRemoteButtonDown(command);
+    break;
+  case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP:
+    iHandled = HandleVendorRemoteButtonUp(command);
     break;
   case CEC_OPCODE_PLAY:
     // libCEC (currently) doesn't need to do anything with this, since player applications handle it
     // but it should not respond with a feature abort
+    iHandled = COMMAND_HANDLED;
     break;
   default:
-    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);
+  if (iHandled == COMMAND_HANDLED)
+    m_busDevice->SignalOpcode((command.opcode == CEC_OPCODE_FEATURE_ABORT && command.parameters.size > 0) ? (cec_opcode)command.parameters[0] : command.opcode);
   else
-    UnhandledCommand(command);
+    UnhandledCommand(command, (cec_abort_reason)iHandled);
 
-  return bHandled;
+  return iHandled == COMMAND_HANDLED;
 }
 
-bool CCECCommandHandler::HandleActiveSource(const cec_command &command)
+int 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]);
     CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iAddress);
     if (device)
+    {
       device->MarkAsActiveSource();
+      return COMMAND_HANDLED;
+    }
   }
 
-  return true;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleDeckControl(const cec_command &command)
+int CCECCommandHandler::HandleDeckControl(const cec_command &command)
 {
   CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
   if (device && command.parameters.size > 0)
   {
     device->SetDeckControlMode((cec_deck_control_mode) command.parameters[0]);
-    return true;
+    return COMMAND_HANDLED;
   }
 
-  return false;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleDeviceCecVersion(const cec_command &command)
+int CCECCommandHandler::HandleDeviceCecVersion(const cec_command &command)
 {
   if (command.parameters.size == 1)
   {
     CCECBusDevice *device = GetDevice(command.initiator);
     if (device)
       device->SetCecVersion((cec_version) command.parameters[0]);
+
+    return COMMAND_HANDLED;
   }
 
-  return true;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
+int CCECCommandHandler::HandleDeviceVendorCommandWithId(const cec_command & UNUSED(command))
 {
-  if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
-    m_processor->TransmitAbort(command.destination, command.initiator, command.opcode, CEC_ABORT_REASON_REFUSED);
-
-  return true;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleDeviceVendorId(const cec_command &command)
+int CCECCommandHandler::HandleDeviceVendorId(const cec_command &command)
 {
-  return SetVendorId(command);
+  SetVendorId(command);
+  return COMMAND_HANDLED;
 }
 
-bool CCECCommandHandler::HandleFeatureAbort(const cec_command &command)
+int 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->GetDevice(command.initiator)->SetUnsupportedFeature((cec_opcode)command.parameters[0]);
-  return true;
+  return COMMAND_HANDLED;
 }
 
-bool CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
+int CCECCommandHandler::HandleGetCecVersion(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
-    if (device)
-      return device->TransmitCECVersion(command.initiator);
+    if (device && device->TransmitCECVersion(command.initiator))
+      return COMMAND_HANDLED;
+    return CEC_ABORT_REASON_INVALID_OPERAND;
   }
 
-  return false;
+  return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
-bool CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
+int CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination));
-    if (device)
-      return device->TransmitAudioStatus(command.initiator);
+    if (device && device->TransmitAudioStatus(command.initiator))
+      return COMMAND_HANDLED;
+    return CEC_ABORT_REASON_INVALID_OPERAND;
   }
 
-  return false;
+  return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
-bool CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
+int CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
-    if (device)
-      return device->TransmitDeckStatus(command.initiator);
+    if (device && device->TransmitDeckStatus(command.initiator))
+      return COMMAND_HANDLED;
+    return CEC_ABORT_REASON_INVALID_OPERAND;
   }
 
-  return false;
+  return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
-bool CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
+int CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
-    if (device)
-      return device->TransmitPowerState(command.initiator);
+    if (device && device->TransmitPowerState(command.initiator))
+      return COMMAND_HANDLED;
+    return CEC_ABORT_REASON_INVALID_OPERAND;
   }
 
-  return false;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
+int CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
-    if (device)
-      return device->TransmitVendorID(command.initiator);
+    if (device && device->TransmitVendorID(command.initiator))
+      return COMMAND_HANDLED;
   }
 
-  return false;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
+int CCECCommandHandler::HandleGiveOSDName(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
-    if (device)
-      return device->TransmitOSDName(command.initiator);
+    if (device && device->TransmitOSDName(command.initiator))
+      return COMMAND_HANDLED;
   }
 
-  return false;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
+int CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
-    if (device)
-      return device->TransmitPhysicalAddress();
+    if (device && device->TransmitPhysicalAddress())
+      return COMMAND_HANDLED;
+    return CEC_ABORT_REASON_INVALID_OPERAND;
   }
 
-  return false;
+  return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
-bool CCECCommandHandler::HandleGiveMenuLanguage(const cec_command &command)
+int CCECCommandHandler::HandleGiveMenuLanguage(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECBusDevice *device = GetDevice(command.destination);
-    if (device)
-      return device->TransmitSetMenuLanguage(command.initiator);
+    if (device && device->TransmitSetMenuLanguage(command.initiator))
+      return COMMAND_HANDLED;
+    return CEC_ABORT_REASON_INVALID_OPERAND;
   }
 
-  return false;
+  return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
-bool CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
+int CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
     CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination));
-    if (device)
-      return device->TransmitSystemAudioModeStatus(command.initiator);
+    if (device && device->TransmitSystemAudioModeStatus(command.initiator))
+      return COMMAND_HANDLED;
+    return CEC_ABORT_REASON_INVALID_OPERAND;
   }
 
-  return false;
+  return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
-bool CCECCommandHandler::HandleImageViewOn(const cec_command &command)
+int CCECCommandHandler::HandleImageViewOn(const cec_command &command)
 {
   m_processor->GetDevice(command.initiator)->MarkAsActiveSource();
-  return true;
+  return COMMAND_HANDLED;
 }
 
-bool CCECCommandHandler::HandleMenuRequest(const cec_command &command)
+int CCECCommandHandler::HandleMenuRequest(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
@@ -407,11 +404,13 @@ bool CCECCommandHandler::HandleMenuRequest(const cec_command &command)
             device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
         }
       }
-      return device->TransmitMenuState(command.initiator);
+      if (device->TransmitMenuState(command.initiator))
+        return COMMAND_HANDLED;
     }
+    return CEC_ABORT_REASON_INVALID_OPERAND;
   }
 
-  return false;
+  return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
 bool CCECCommandHandler::HandlePoll(const cec_command &command)
@@ -420,7 +419,7 @@ bool CCECCommandHandler::HandlePoll(const cec_command &command)
   return true;
 }
 
-bool CCECCommandHandler::HandleReportAudioStatus(const cec_command &command)
+int CCECCommandHandler::HandleReportAudioStatus(const cec_command &command)
 {
   if (command.parameters.size == 1)
   {
@@ -428,34 +427,38 @@ bool CCECCommandHandler::HandleReportAudioStatus(const cec_command &command)
     if (device)
     {
       device->SetAudioStatus(command.parameters[0]);
-      return true;
+      return COMMAND_HANDLED;
     }
   }
-  return false;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleReportPhysicalAddress(const cec_command &command)
+int CCECCommandHandler::HandleReportPhysicalAddress(const cec_command &command)
 {
   if (command.parameters.size == 3)
   {
     uint16_t iNewAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
     SetPhysicalAddress(command.initiator, iNewAddress);
+    return COMMAND_HANDLED;
   }
-  return true;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleReportPowerStatus(const cec_command &command)
+int CCECCommandHandler::HandleReportPowerStatus(const cec_command &command)
 {
   if (command.parameters.size == 1)
   {
     CCECBusDevice *device = GetDevice(command.initiator);
     if (device)
+    {
       device->SetPowerStatus((cec_power_status) command.parameters[0]);
+      return COMMAND_HANDLED;
+    }
   }
-  return true;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
+int CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
 {
   if (m_processor->CECInitialised())
   {
@@ -465,13 +468,12 @@ bool CCECCommandHandler::HandleRequestActiveSource(const cec_command &command)
     vector<CCECBusDevice *> devices;
     for (size_t iDevicePtr = 0; iDevicePtr < GetMyDevices(devices); iDevicePtr++)
       devices[iDevicePtr]->TransmitActiveSource();
-
-    return true;
   }
-  return false;
+
+  return COMMAND_HANDLED;
 }
 
-bool CCECCommandHandler::HandleRoutingChange(const cec_command &command)
+int CCECCommandHandler::HandleRoutingChange(const cec_command &command)
 {
   if (command.parameters.size == 4)
   {
@@ -480,25 +482,32 @@ bool CCECCommandHandler::HandleRoutingChange(const cec_command &command)
 
     CCECBusDevice *device = GetDevice(command.initiator);
     if (device)
+    {
       device->SetStreamPath(iNewAddress, iOldAddress);
+      return COMMAND_HANDLED;
+    }
   }
-  return true;
+
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleRoutingInformation(const cec_command &command)
+int 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]);
     CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
     if (device)
+    {
       device->MarkAsActiveSource();
+      return COMMAND_HANDLED;
+    }
   }
 
-  return false;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleSetMenuLanguage(const cec_command &command)
+int CCECCommandHandler::HandleSetMenuLanguage(const cec_command &command)
 {
   if (command.parameters.size == 3)
   {
@@ -511,13 +520,14 @@ bool CCECCommandHandler::HandleSetMenuLanguage(const cec_command &command)
         language.language[iPtr] = command.parameters[iPtr];
       language.language[3] = 0;
       device->SetMenuLanguage(language);
-      return true;
+      return COMMAND_HANDLED;
     }
   }
-  return false;
+
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleSetOSDName(const cec_command &command)
+int CCECCommandHandler::HandleSetOSDName(const cec_command &command)
 {
   if (command.parameters.size > 0)
   {
@@ -532,28 +542,39 @@ bool CCECCommandHandler::HandleSetOSDName(const cec_command &command)
       CStdString strName(buf);
       device->SetOSDName(strName);
 
-      return true;
+      return COMMAND_HANDLED;
     }
   }
-  return false;
+
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
+int CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
 {
-  if (m_processor->CECInitialised() && command.parameters.size >= 2)
+  if (!m_processor->CECInitialised())
+    return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
+  if (command.parameters.size >= 2)
   {
     uint16_t iStreamAddress = ((uint16_t)command.parameters[0] << 8) | ((uint16_t)command.parameters[1]);
-    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i sets stream path to physical address %04x", command.initiator, iStreamAddress);
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%x) sets stream path to physical address %04x", ToString(command.initiator), command.initiator, iStreamAddress);
+
+    // a device will only change the stream path when it's powered on
+    m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON);
 
     /* one of the device handled by libCEC has been made active */
     CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress);
     if (device && device->IsHandledByLibCEC())
+    {
       device->ActivateSource();
+      return COMMAND_HANDLED;
+    }
   }
-  return false;
+
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
+int CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
 {
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
   {
@@ -568,28 +589,31 @@ bool CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command
         CCECBusDevice *newActiveDevice = GetDeviceByPhysicalAddress(iNewAddress);
         if (newActiveDevice)
           newActiveDevice->MarkAsActiveSource();
-        return device->TransmitSetSystemAudioMode(command.initiator);
+        if (device->TransmitSetSystemAudioMode(command.initiator))
+          return COMMAND_HANDLED;
       }
       else
       {
         device->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_OFF);
-        return device->TransmitSetSystemAudioMode(command.initiator);
+        if (device->TransmitSetSystemAudioMode(command.initiator))
+          return COMMAND_HANDLED;
       }
     }
   }
-  return false;
+
+  return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
-bool CCECCommandHandler::HandleStandby(const cec_command &command)
+int CCECCommandHandler::HandleStandby(const cec_command &command)
 {
   CCECBusDevice *device = GetDevice(command.initiator);
   if (device)
     device->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
 
-  return true;
+  return COMMAND_HANDLED;
 }
 
-bool CCECCommandHandler::HandleSystemAudioModeStatus(const cec_command &command)
+int CCECCommandHandler::HandleSystemAudioModeStatus(const cec_command &command)
 {
   if (command.parameters.size == 1)
   {
@@ -597,14 +621,14 @@ bool CCECCommandHandler::HandleSystemAudioModeStatus(const cec_command &command)
     if (device)
     {
       device->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
-      return true;
+      return COMMAND_HANDLED;
     }
   }
 
-  return false;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleSetSystemAudioMode(const cec_command &command)
+int CCECCommandHandler::HandleSetSystemAudioMode(const cec_command &command)
 {
   if (command.parameters.size == 1)
   {
@@ -612,87 +636,92 @@ bool CCECCommandHandler::HandleSetSystemAudioMode(const cec_command &command)
     if (device)
     {
       device->SetSystemAudioModeStatus((cec_system_audio_status)command.parameters[0]);
-      return true;
+      return COMMAND_HANDLED;
     }
   }
 
-  return false;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CCECCommandHandler::HandleTextViewOn(const cec_command &command)
+int CCECCommandHandler::HandleTextViewOn(const cec_command &command)
 {
   m_processor->GetDevice(command.initiator)->MarkAsActiveSource();
-  return true;
+  return COMMAND_HANDLED;
 }
 
-bool CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
+int CCECCommandHandler::HandleUserControlPressed(const cec_command &command)
 {
-  if (m_processor->CECInitialised() &&
-      m_processor->IsHandledByLibCEC(command.destination) &&
-      command.parameters.size > 0)
-  {
-    CCECBusDevice *device = GetDevice(command.destination);
-    if (!device)
-      return true;
+  if (!m_processor->CECInitialised() ||
+      !m_processor->IsHandledByLibCEC(command.destination))
+    return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 
-    CCECClient *client = device->GetClient();
-    if (client)
-      client->AddKey();
+  if (command.parameters.size == 0)
+    return CEC_ABORT_REASON_INVALID_OPERAND;
 
-    if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
-      client->SetCurrentButton((cec_user_control_code) command.parameters[0]);
+  CCECBusDevice *device = GetDevice(command.destination);
+  if (!device)
+    return CEC_ABORT_REASON_INVALID_OPERAND;
 
-    if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER ||
-        command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION)
-    {
-      bool bPowerOn(true);
-      if (!device)
-        return true;
+  CCECClient *client = device->GetClient();
+  if (client)
+    client->AddKey();
 
-      // CEC_USER_CONTROL_CODE_POWER operates as a toggle
-      // assume CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION does not
-      if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER)
-      {
-        cec_power_status status = device->GetCurrentPowerStatus();
-        bPowerOn = !(status == CEC_POWER_STATUS_ON || status == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
-      }
+  if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
+    client->SetCurrentButton((cec_user_control_code) command.parameters[0]);
 
-      if (bPowerOn)
-      {
-        device->ActivateSource();
-      }
-      else
-      {
-        device->MarkAsInactiveSource();
-        device->TransmitInactiveSource();
-        device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
-      }
+  if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER ||
+      command.parameters[0] == CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION)
+  {
+    bool bPowerOn(true);
+
+    // CEC_USER_CONTROL_CODE_POWER operates as a toggle
+    // assume CEC_USER_CONTROL_CODE_POWER_ON_FUNCTION does not
+    if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER)
+    {
+      cec_power_status status = device->GetCurrentPowerStatus();
+      bPowerOn = !(status == CEC_POWER_STATUS_ON || status == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
     }
 
-    return true;
+    if (bPowerOn)
+    {
+      device->ActivateSource();
+    }
+    else
+    {
+      device->MarkAsInactiveSource();
+      device->TransmitInactiveSource();
+      device->SetMenuState(CEC_MENU_STATE_DEACTIVATED);
+    }
   }
-  return false;
+
+  return COMMAND_HANDLED;
 }
 
-bool CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
+int CCECCommandHandler::HandleUserControlRelease(const cec_command &command)
 {
+  if (!m_processor->CECInitialised() ||
+      !m_processor->IsHandledByLibCEC(command.destination))
+    return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
   CCECClient *client = m_processor->GetClient(command.destination);
   if (client)
     client->AddKey();
-  return true;
+
+  return COMMAND_HANDLED;
 }
 
-bool CCECCommandHandler::HandleVendorCommand(const cec_command & UNUSED(command))
+int CCECCommandHandler::HandleVendorCommand(const cec_command & UNUSED(command))
 {
-  return true;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-void CCECCommandHandler::UnhandledCommand(const cec_command &command)
+void CCECCommandHandler::UnhandledCommand(const cec_command &command, const cec_abort_reason reason)
 {
-  LIB_CEC->AddLog(CEC_LOG_DEBUG, "unhandled command with opcode %02x from address %d", command.opcode, command.initiator);
-
-  if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
-    m_processor->TransmitAbort(m_busDevice->GetLogicalAddress(), command.initiator, command.opcode, CEC_ABORT_REASON_UNRECOGNIZED_OPCODE);
+  if (m_processor->IsHandledByLibCEC(command.destination))
+  {
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "sending abort with opcode %02x and reason '%s' to %s", command.opcode, ToString(reason), ToString(command.initiator));
+    m_processor->TransmitAbort(command.destination, command.initiator, command.opcode, reason);
+  }
 }
 
 size_t CCECCommandHandler::GetMyDevices(vector<CCECBusDevice *> &devices) const
@@ -1046,7 +1075,7 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* =
         LIB_CEC->AddLog(CEC_LOG_DEBUG, "command transmitted");
         if (bExpectResponse)
         {
-          bReturn = m_waitForResponse->Wait(expectedResponse);
+          bReturn = m_busDevice->WaitForOpcode(expectedResponse);
           LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? "expected response received (%X: %s)" : "expected response not received (%X: %s)", (int)expectedResponse, ToString(expectedResponse));
         }
       }
@@ -1056,50 +1085,71 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* =
   return bReturn;
 }
 
-bool CCECCommandHandler::ActivateSource(void)
+bool CCECCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = false */)
 {
   if (m_busDevice->IsActiveSource() &&
-    m_busDevice->IsHandledByLibCEC())
+      m_busDevice->IsHandledByLibCEC())
   {
     {
       CLockObject lock(m_mutex);
-      m_bActiveSourcePending = false;
+      // check if we need to send a delayed source switch
+      if (bTransmitDelayedCommandsOnly)
+      {
+        if (m_iActiveSourcePending == 0 || GetTimeMs() < m_iActiveSourcePending)
+          return false;
+
+        LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
+      }
+
+      // clear previous pending active source command
+      m_iActiveSourcePending = 0;
     }
 
+    // update the power state and menu state
     m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON);
-    m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED);
+    m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED); // TODO: LG
+
+    // power on the TV
+    bool bActiveSourceFailed = !m_busDevice->TransmitImageViewOn();
 
-    bool bActiveSourceFailed = !m_busDevice->TransmitImageViewOn() ||
-                               !m_busDevice->TransmitActiveSource() ||
-                               !m_busDevice->TransmitMenuState(CECDEVICE_TV);
+    // check if we're allowed to switch sources
+    bool bSourceSwitchAllowed = SourceSwitchAllowed();
+    if (!bSourceSwitchAllowed)
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "source switch is currently not allowed by command handler");
 
-    if (!bActiveSourceFailed)
+    // switch sources (if allowed)
+    if (!bActiveSourceFailed && bSourceSwitchAllowed)
     {
-      CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice();
-      if (playbackDevice && SendDeckStatusUpdateOnActiveSource())
-        bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV);
+      bActiveSourceFailed = !m_busDevice->TransmitActiveSource() ||
+                            !m_busDevice->TransmitMenuState(CECDEVICE_TV);
+
+      // update the deck status for playback devices
+      if (!bActiveSourceFailed)
+      {
+        CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice();
+        if (playbackDevice && SendDeckStatusUpdateOnActiveSource())
+          bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV);
+      }
     }
 
-    if (bActiveSourceFailed)
+    // retry later
+    if (bActiveSourceFailed || !bSourceSwitchAllowed)
     {
       LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to make '%s' the active source. will retry later", m_busDevice->GetLogicalAddressName());
       CLockObject lock(m_mutex);
-      m_bActiveSourcePending = true;
+      m_iActiveSourcePending = GetTimeMs() + (int64_t)CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS;
       return false;
     }
 
+    // mark the handler as initialised
+    CLockObject lock(m_mutex);
     m_bHandlerInited = true;
   }
   return true;
 }
 
-void CCECCommandHandler::SignalOpcode(cec_opcode opcode)
-{
-  m_waitForResponse->Received(opcode);
-}
-
-bool CCECCommandHandler::ActiveSourcePending(void)
+void CCECCommandHandler::ScheduleActivateSource(uint64_t iDelay)
 {
   CLockObject lock(m_mutex);
-  return m_bActiveSourcePending;
+  m_iActiveSourcePending = GetTimeMs() + iDelay;
 }
index 3a9bd6f1a3370bcc367bb611183cc2d6f9f691b2..bc421287664e61036d0530ea748553311f5d717d 100644 (file)
 
 #include "../../../include/cectypes.h"
 #include <vector>
-#include <map>
 #include "../platform/threads/mutex.h"
 #include "../platform/util/StdString.h"
 
 namespace CEC
 {
+  #define COMMAND_HANDLED 0xFF
+
   class CCECProcessor;
   class CCECBusDevice;
 
-  class CResponse
-  {
-  public:
-    CResponse(cec_opcode opcode) :
-        m_opcode(opcode){}
-    ~CResponse(void)
-    {
-      Broadcast();
-    }
-
-    bool Wait(uint32_t iTimeout)
-    {
-      return m_event.Wait(iTimeout);
-    }
-
-    void Broadcast(void)
-    {
-      m_event.Broadcast();
-    }
-
-  private:
-    cec_opcode       m_opcode;
-    PLATFORM::CEvent m_event;
-  };
-
-  class CWaitForResponse
-  {
-  public:
-    CWaitForResponse(void) {}
-    ~CWaitForResponse(void)
-    {
-      PLATFORM::CLockObject lock(m_mutex);
-      m_waitingFor.clear();
-    }
-
-    bool Wait(cec_opcode opcode, uint32_t iTimeout = CEC_DEFAULT_TRANSMIT_WAIT)
-    {
-      CResponse *response = GetEvent(opcode);
-      return response ? response->Wait(iTimeout) : false;
-    }
-
-    void Received(cec_opcode opcode)
-    {
-      CResponse *response = GetEvent(opcode);
-      if (response)
-        response->Broadcast();
-    }
-
-  private:
-    CResponse *GetEvent(cec_opcode opcode)
-    {
-      CResponse *retVal(NULL);
-      {
-        PLATFORM::CLockObject lock(m_mutex);
-        std::map<cec_opcode, CResponse*>::iterator it = m_waitingFor.find(opcode);
-        if (it != m_waitingFor.end())
-        {
-          retVal = it->second;
-        }
-        else
-        {
-          retVal = new CResponse(opcode);
-          m_waitingFor[opcode] = retVal;
-        }
-        return retVal;
-      }
-    }
-
-    PLATFORM::CMutex                 m_mutex;
-    std::map<cec_opcode, CResponse*> m_waitingFor;
-  };
-
   class CCECCommandHandler
   {
+    friend class CCECBusDevice;
+
   public:
-    CCECCommandHandler(CCECBusDevice *busDevice);
-    virtual ~CCECCommandHandler(void);
+    CCECCommandHandler(CCECBusDevice *busDevice,
+                       int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+                       int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+                       int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+                       int64_t iActiveSourcePending = 0);
+    virtual ~CCECCommandHandler(void) {};
 
     virtual bool HandleCommand(const cec_command &command);
     virtual cec_vendor_id GetVendorId(void) { return m_vendorId; };
@@ -126,7 +61,7 @@ namespace CEC
     static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC;}
 
     virtual bool InitHandler(void) { return true; }
-    virtual bool ActivateSource(void);
+    virtual bool ActivateSource(bool bTransmitDelayedCommandsOnly = false);
     virtual uint8_t GetTransmitRetries(void) const { return m_iTransmitRetries; }
 
     virtual bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
@@ -158,51 +93,51 @@ namespace CEC
     virtual bool TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait = true);
     virtual bool TransmitSetStreamPath(uint16_t iStreamPath);
     virtual bool SendDeckStatusUpdateOnActiveSource(void) const { return m_bOPTSendDeckStatusUpdateOnActiveSource; };
-    virtual bool TransmitPendingActiveSourceCommands(void) { return true; }
 
-    virtual void SignalOpcode(cec_opcode opcode);
+    virtual void ScheduleActivateSource(uint64_t iDelay);
 
-    virtual bool ActiveSourcePending(void);
     virtual bool SupportsDeviceType(const cec_device_type UNUSED(type)) const { return true; };
-    cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type; }
+    virtual cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type; }
 
   protected:
-    virtual bool HandleActiveSource(const cec_command &command);
-    virtual bool HandleDeckControl(const cec_command &command);
-    virtual bool HandleDeviceCecVersion(const cec_command &command);
-    virtual bool HandleDeviceVendorCommandWithId(const cec_command &command);
-    virtual bool HandleDeviceVendorId(const cec_command &command);
-    virtual bool HandleFeatureAbort(const cec_command &command);
-    virtual bool HandleGetCecVersion(const cec_command &command);
-    virtual bool HandleGiveAudioStatus(const cec_command &command);
-    virtual bool HandleGiveDeckStatus(const cec_command &command);
-    virtual bool HandleGiveDevicePowerStatus(const cec_command &command);
-    virtual bool HandleGiveDeviceVendorId(const cec_command &command);
-    virtual bool HandleGiveOSDName(const cec_command &command);
-    virtual bool HandleGivePhysicalAddress(const cec_command &command);
-    virtual bool HandleGiveMenuLanguage(const cec_command &command);
-    virtual bool HandleGiveSystemAudioModeStatus(const cec_command &command);
-    virtual bool HandleImageViewOn(const cec_command &command);
-    virtual bool HandleMenuRequest(const cec_command &command);
+    virtual int HandleActiveSource(const cec_command &command);
+    virtual int HandleDeckControl(const cec_command &command);
+    virtual int HandleDeviceCecVersion(const cec_command &command);
+    virtual int HandleDeviceVendorCommandWithId(const cec_command &command);
+    virtual int HandleDeviceVendorId(const cec_command &command);
+    virtual int HandleFeatureAbort(const cec_command &command);
+    virtual int HandleGetCecVersion(const cec_command &command);
+    virtual int HandleGiveAudioStatus(const cec_command &command);
+    virtual int HandleGiveDeckStatus(const cec_command &command);
+    virtual int HandleGiveDevicePowerStatus(const cec_command &command);
+    virtual int HandleGiveDeviceVendorId(const cec_command &command);
+    virtual int HandleGiveOSDName(const cec_command &command);
+    virtual int HandleGivePhysicalAddress(const cec_command &command);
+    virtual int HandleGiveMenuLanguage(const cec_command &command);
+    virtual int HandleGiveSystemAudioModeStatus(const cec_command &command);
+    virtual int HandleImageViewOn(const cec_command &command);
+    virtual int HandleMenuRequest(const cec_command &command);
     virtual bool HandlePoll(const cec_command &command);
-    virtual bool HandleReportAudioStatus(const cec_command &command);
-    virtual bool HandleReportPhysicalAddress(const cec_command &command);
-    virtual bool HandleReportPowerStatus(const cec_command &command);
-    virtual bool HandleRequestActiveSource(const cec_command &command);
-    virtual bool HandleRoutingChange(const cec_command &command);
-    virtual bool HandleRoutingInformation(const cec_command &command);
-    virtual bool HandleSetMenuLanguage(const cec_command &command);
-    virtual bool HandleSetOSDName(const cec_command &command);
-    virtual bool HandleSetStreamPath(const cec_command &command);
-    virtual bool HandleSystemAudioModeRequest(const cec_command &command);
-    virtual bool HandleStandby(const cec_command &command);
-    virtual bool HandleSystemAudioModeStatus(const cec_command &command);
-    virtual bool HandleSetSystemAudioMode(const cec_command &command);
-    virtual bool HandleTextViewOn(const cec_command &command);
-    virtual bool HandleUserControlPressed(const cec_command &command);
-    virtual bool HandleUserControlRelease(const cec_command &command);
-    virtual bool HandleVendorCommand(const cec_command &command);
-    virtual void UnhandledCommand(const cec_command &command);
+    virtual int HandleReportAudioStatus(const cec_command &command);
+    virtual int HandleReportPhysicalAddress(const cec_command &command);
+    virtual int HandleReportPowerStatus(const cec_command &command);
+    virtual int HandleRequestActiveSource(const cec_command &command);
+    virtual int HandleRoutingChange(const cec_command &command);
+    virtual int HandleRoutingInformation(const cec_command &command);
+    virtual int HandleSetMenuLanguage(const cec_command &command);
+    virtual int HandleSetOSDName(const cec_command &command);
+    virtual int HandleSetStreamPath(const cec_command &command);
+    virtual int HandleSystemAudioModeRequest(const cec_command &command);
+    virtual int HandleStandby(const cec_command &command);
+    virtual int HandleSystemAudioModeStatus(const cec_command &command);
+    virtual int HandleSetSystemAudioMode(const cec_command &command);
+    virtual int HandleTextViewOn(const cec_command &command);
+    virtual int HandleUserControlPressed(const cec_command &command);
+    virtual int HandleUserControlRelease(const cec_command &command);
+    virtual int HandleVendorCommand(const cec_command &command);
+    virtual int HandleVendorRemoteButtonDown(const cec_command & UNUSED(command)) { return CEC_ABORT_REASON_REFUSED; }
+    virtual int HandleVendorRemoteButtonUp(const cec_command & UNUSED(command)) { return CEC_ABORT_REASON_REFUSED; }
+    virtual void UnhandledCommand(const cec_command &command, const cec_abort_reason reason);
 
     virtual size_t GetMyDevices(std::vector<CCECBusDevice *> &devices) const;
     virtual CCECBusDevice *GetDevice(cec_logical_address iLogicalAddress) const;
@@ -213,6 +148,8 @@ namespace CEC
 
     virtual bool Transmit(cec_command &command, bool bSuppressWait = false);
 
+    virtual bool SourceSwitchAllowed(void) { return true; }
+
     CCECBusDevice *                       m_busDevice;
     CCECProcessor *                       m_processor;
     int32_t                               m_iTransmitTimeout;
@@ -221,8 +158,7 @@ namespace CEC
     bool                                  m_bHandlerInited;
     bool                                  m_bOPTSendDeckStatusUpdateOnActiveSource;
     cec_vendor_id                         m_vendorId;
-    CWaitForResponse                     *m_waitForResponse;
-    bool                                  m_bActiveSourcePending;
+    int64_t                               m_iActiveSourcePending;
     PLATFORM::CMutex                      m_mutex;
   };
 };
index b913c322be41e4ab17fa2af264c02f6db0fe25a0..5653137616d304b11bcb0949fdc69b05cf0c5966 100644 (file)
 using namespace CEC;
 using namespace PLATFORM;
 
-CRLCommandHandler::CRLCommandHandler(CCECBusDevice *busDevice) :
-    CCECCommandHandler(busDevice)
+CRLCommandHandler::CRLCommandHandler(CCECBusDevice *busDevice,
+                                     int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+                                     int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+                                     int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+                                     int64_t iActiveSourcePending /* = 0 */) :
+    CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending)
 {
   m_vendorId = CEC_VENDOR_TOSHIBA;
 }
index 9766827615de1cd4706e64b11d674633ca1e1545..ec9edd92b8553f3598113a86a10d5e1ac1295e44 100644 (file)
@@ -39,7 +39,11 @@ namespace CEC
   class CRLCommandHandler : public CCECCommandHandler
   {
   public:
-    CRLCommandHandler(CCECBusDevice *busDevice);
+    CRLCommandHandler(CCECBusDevice *busDevice,
+                      int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+                      int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+                      int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+                      int64_t iActiveSourcePending = 0);
     virtual ~CRLCommandHandler(void) {};
 
     bool InitHandler(void);
index 6066d3b9bb21dbf03591d8f7b0a3ef7057ae2bba..222fc957f2445ba66d3d72f9a27abcab739773df 100644 (file)
@@ -56,8 +56,12 @@ using namespace PLATFORM;
 #define LIB_CEC     m_busDevice->GetProcessor()->GetLib()
 #define ToString(p) LIB_CEC->ToString(p)
 
-CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice) :
-    CCECCommandHandler(busDevice),
+CSLCommandHandler::CSLCommandHandler(CCECBusDevice *busDevice,
+                                     int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+                                     int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+                                     int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+                                     int64_t iActiveSourcePending /* = 0 */) :
+    CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending),
     m_bSLEnabled(false),
     m_bActiveSourceSent(false)
 {
@@ -103,7 +107,7 @@ bool CSLCommandHandler::InitHandler(void)
   return true;
 }
 
-bool CSLCommandHandler::HandleActiveSource(const cec_command &command)
+int CSLCommandHandler::HandleActiveSource(const cec_command &command)
 {
   if (command.parameters.size == 2)
   {
@@ -122,13 +126,15 @@ bool CSLCommandHandler::HandleActiveSource(const cec_command &command)
       }
       primary->TransmitPowerState(CECDEVICE_TV);
     }
+
+    return COMMAND_HANDLED;
   }
 
-  return true;
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 
 }
 
-bool CSLCommandHandler::HandleDeviceVendorId(const cec_command &command)
+int CSLCommandHandler::HandleDeviceVendorId(const cec_command &command)
 {
   SetVendorId(command);
 
@@ -143,13 +149,15 @@ bool CSLCommandHandler::HandleDeviceVendorId(const cec_command &command)
 
       cec_command response;
       cec_command::Format(response, initiator, command.initiator, CEC_OPCODE_FEATURE_ABORT);
-      return Transmit(response);
+      Transmit(response);
+      return COMMAND_HANDLED;
     }
   }
-  return true;
+
+  return CCECCommandHandler::HandleDeviceVendorId(command);
 }
 
-bool CSLCommandHandler::HandleVendorCommand(const cec_command &command)
+int CSLCommandHandler::HandleVendorCommand(const cec_command &command)
 {
   if (!m_processor->IsHandledByLibCEC(command.destination))
     return true;
@@ -158,28 +166,28 @@ bool CSLCommandHandler::HandleVendorCommand(const cec_command &command)
       command.parameters[0] == SL_COMMAND_UNKNOWN_01)
   {
     HandleVendorCommand01(command);
-    return true;
+    return COMMAND_HANDLED;
   }
   else if (command.parameters.size == 2 &&
       command.parameters[0] == SL_COMMAND_POWER_ON)
   {
     HandleVendorCommandPowerOn(command);
-    return true;
+    return COMMAND_HANDLED;
   }
   else if (command.parameters.size == 2 &&
       command.parameters[0] == SL_COMMAND_CONNECT_REQUEST)
   {
     HandleVendorCommandSLConnect(command);
-    return true;
+    return COMMAND_HANDLED;
   }
   else if (command.parameters.size == 1 &&
       command.parameters[0] == SL_COMMAND_REQUEST_POWER_STATUS)
   {
     HandleVendorCommandPowerOnStatus(command);
-    return true;
+    return COMMAND_HANDLED;
   }
 
-  return false;
+  return CCECCommandHandler::HandleVendorCommand(command);
 }
 
 void CSLCommandHandler::HandleVendorCommand01(const cec_command &command)
@@ -252,44 +260,41 @@ void CSLCommandHandler::TransmitVendorCommandSetDeviceMode(const cec_logical_add
   Transmit(response);
 }
 
-bool CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
+int CSLCommandHandler::HandleGiveDeckStatus(const cec_command &command)
 {
-  if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination))
+  if (!m_processor->CECInitialised() ||
+      !m_processor->IsHandledByLibCEC(command.destination))
+    return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
+
+  CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination));
+  if (!device || command.parameters.size == 0)
+    return CEC_ABORT_REASON_INVALID_OPERAND;
+
+  device->SetDeckStatus(!device->IsActiveSource() ? CEC_DECK_INFO_OTHER_STATUS : CEC_DECK_INFO_OTHER_STATUS_LG);
+  if (command.parameters[0] == CEC_STATUS_REQUEST_ON)
   {
-    CCECBusDevice *device = GetDevice(command.destination);
-    if (device && (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE || device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
-    {
-      if (command.parameters.size > 0)
-      {
-        ((CCECPlaybackDevice *) device)->SetDeckStatus(!device->IsActiveSource() ? CEC_DECK_INFO_OTHER_STATUS : CEC_DECK_INFO_OTHER_STATUS_LG);
-        if (command.parameters[0] == CEC_STATUS_REQUEST_ON)
-        {
-          bool bReturn = ((CCECPlaybackDevice *) device)->TransmitDeckStatus(command.initiator);
-          if (!ActiveSourceSent())
-            ActivateSource();
-          return bReturn;
-        }
-        else if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE)
-        {
-          return ((CCECPlaybackDevice *) device)->TransmitDeckStatus(command.initiator);
-        }
-      }
-    }
-    return CCECCommandHandler::HandleGiveDeckStatus(command);
+    device->TransmitDeckStatus(command.initiator);
+    if (!ActiveSourceSent())
+      ActivateSource();
+    return COMMAND_HANDLED;
+  }
+  else if (command.parameters[0] == CEC_STATUS_REQUEST_ONCE)
+  {
+    device->TransmitDeckStatus(command.initiator);
+    return COMMAND_HANDLED;
   }
 
-  return false;
+  return CCECCommandHandler::HandleGiveDeckStatus(command);
 }
 
-bool CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
+int CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
 {
-  bool bReturn(false);
   if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination) && command.initiator == CECDEVICE_TV)
   {
     CCECBusDevice *device = GetDevice(command.destination);
     if (device && device->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON)
     {
-      bReturn = device->TransmitPowerState(command.initiator);
+      device->TransmitPowerState(command.initiator);
       device->SetPowerStatus(CEC_POWER_STATUS_ON);
     }
     else
@@ -297,7 +302,7 @@ bool CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
       if (!ActiveSourceSent())
       {
         device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
-        bReturn = device->TransmitPowerState(command.initiator);
+        device->TransmitPowerState(command.initiator);
         ActivateSource();
       }
       else if (m_resetPowerState.IsSet() && m_resetPowerState.TimeLeft() > 0)
@@ -309,22 +314,24 @@ bool CSLCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command)
           m_bActiveSourceSent = false;
         }
         device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
-        bReturn = device->TransmitPowerState(command.initiator);
+        device->TransmitPowerState(command.initiator);
         device->SetPowerStatus(CEC_POWER_STATUS_ON);
         m_resetPowerState.Init(5000);
       }
       else
       {
-        bReturn = device->TransmitPowerState(command.initiator);
+        device->TransmitPowerState(command.initiator);
         m_resetPowerState.Init(5000);
       }
     }
+
+    return COMMAND_HANDLED;
   }
 
-  return bReturn;
+  return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
-bool CSLCommandHandler::HandleRequestActiveSource(const cec_command &command)
+int CSLCommandHandler::HandleRequestActiveSource(const cec_command &command)
 {
   if (m_processor->CECInitialised())
   {
@@ -332,12 +339,12 @@ bool CSLCommandHandler::HandleRequestActiveSource(const cec_command &command)
       LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %i requests active source, ignored", (uint8_t) command.initiator);
     else
       ActivateSource();
-    return true;
+    return COMMAND_HANDLED;
   }
-  return false;
+  return CEC_ABORT_REASON_NOT_IN_CORRECT_MODE_TO_RESPOND;
 }
 
-bool CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
+int CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
 {
   if (command.parameters.size == 0 && m_processor->GetPrimaryDevice()->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON && !SLInitialised() &&
       command.initiator == CECDEVICE_TV)
@@ -349,7 +356,7 @@ bool CSLCommandHandler::HandleFeatureAbort(const cec_command &command)
   return CCECCommandHandler::HandleFeatureAbort(command);
 }
 
-bool CSLCommandHandler::HandleStandby(const cec_command &command)
+int CSLCommandHandler::HandleStandby(const cec_command &command)
 {
   if (command.initiator == CECDEVICE_TV)
   {
index 0eb6c8656e25170519279e9035c0bce66930da89..8c6902db41f42f824c26110e405fd6a008e69ea6 100644 (file)
@@ -39,15 +39,19 @@ namespace CEC
   class CSLCommandHandler : public CCECCommandHandler
   {
   public:
-    CSLCommandHandler(CCECBusDevice *busDevice);
+    CSLCommandHandler(CCECBusDevice *busDevice,
+                      int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+                      int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+                      int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+                      int64_t iActiveSourcePending = 0);
     virtual ~CSLCommandHandler(void) {};
 
     bool InitHandler(void);
 
   protected:
-    bool HandleActiveSource(const cec_command &command);
-    bool HandleDeviceVendorId(const cec_command &command);
-    bool HandleVendorCommand(const cec_command &command);
+    int HandleActiveSource(const cec_command &command);
+    int HandleDeviceVendorId(const cec_command &command);
+    int HandleVendorCommand(const cec_command &command);
 
     void HandleVendorCommand01(const cec_command &command);
     void TransmitVendorCommand0205(const cec_logical_address iSource, const cec_logical_address iDestination);
@@ -58,11 +62,11 @@ namespace CEC
     void HandleVendorCommandSLConnect(const cec_command &command);
     void TransmitVendorCommandSetDeviceMode(const cec_logical_address iSource, const cec_logical_address iDestination, const cec_device_type type);
 
-    bool HandleGiveDevicePowerStatus(const cec_command &command);
-    bool HandleGiveDeckStatus(const cec_command &command);
-    bool HandleRequestActiveSource(const cec_command &command);
-    bool HandleFeatureAbort(const cec_command &command);
-    bool HandleStandby(const cec_command &command);
+    int HandleGiveDevicePowerStatus(const cec_command &command);
+    int HandleGiveDeckStatus(const cec_command &command);
+    int HandleRequestActiveSource(const cec_command &command);
+    int HandleFeatureAbort(const cec_command &command);
+    int HandleStandby(const cec_command &command);
     bool TransmitMenuState(const cec_logical_address UNUSED(iInitiator), const cec_logical_address UNUSED(iDestination), cec_menu_state UNUSED(menuState)) { return true; }
     bool PowerOn(const cec_logical_address iInitiator, const cec_logical_address iDestination);
 
index 3d96004a7f401bdbf5874ac1a0cf69484b74b857..97d06a278e77ce8a1e2dd102006c8645b0d8e37f 100644 (file)
@@ -32,6 +32,8 @@
 
 #include "VLCommandHandler.h"
 #include "../devices/CECBusDevice.h"
+#include "../devices/CECPlaybackDevice.h"
+#include "../devices/CECTV.h"
 #include "../CECProcessor.h"
 #include "../LibCEC.h"
 #include "../CECClient.h"
@@ -39,6 +41,7 @@
 #define VL_POWER_CHANGE 0x20
 #define VL_POWERED_UP   0x00
 #define VL_POWERED_DOWN 0x01
+#define VL_UNKNOWN1     0x06
 
 using namespace CEC;
 using namespace PLATFORM;
@@ -46,10 +49,16 @@ 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),
-    m_bPowerUpEventReceived(false)
+// wait this amount of ms before trying to switch sources after receiving the message from the TV that it's powered on
+#define SOURCE_SWITCH_DELAY_MS 1000
+
+CVLCommandHandler::CVLCommandHandler(CCECBusDevice *busDevice,
+                                     int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
+                                     int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */,
+                                     int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */,
+                                     int64_t iActiveSourcePending /* = 0 */) :
+    CCECCommandHandler(busDevice, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending),
+    m_iPowerUpEventReceived(0)
 {
   m_vendorId = CEC_VENDOR_PANASONIC;
 }
@@ -71,92 +80,152 @@ bool CVLCommandHandler::InitHandler(void)
 
     if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
       return m_processor->GetPrimaryClient()->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
+
+    m_processor->GetTV()->RequestPowerStatus(primary->GetLogicalAddress(), false);
   }
 
   return CCECCommandHandler::InitHandler();
 }
 
-bool CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
+int CVLCommandHandler::HandleDeviceVendorCommandWithId(const cec_command &command)
 {
+  if (command.parameters[0] != 0x00 ||
+      command.parameters[1] != 0x80 ||
+      command.parameters[2] != 0x45)
+    return CEC_ABORT_REASON_INVALID_OPERAND;
+
   if (command.initiator == CECDEVICE_TV &&
+      command.parameters.At(3) == VL_UNKNOWN1)
+  {
+    // set the power up event time
+    {
+      CLockObject lock(m_mutex);
+      if (m_iPowerUpEventReceived == 0)
+        m_iPowerUpEventReceived = GetTimeMs();
+    }
+    // mark the TV as powered on
+    m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
+  }
+  else if (command.initiator == CECDEVICE_TV &&
       command.destination == CECDEVICE_BROADCAST &&
       command.parameters.At(3) == VL_POWER_CHANGE)
   {
     if (command.parameters.At(4) == VL_POWERED_UP)
     {
-      LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV powered up");
+      // set the power up event time
       {
         CLockObject lock(m_mutex);
-        m_bPowerUpEventReceived = true;
+        if (m_iPowerUpEventReceived == 0)
+          m_iPowerUpEventReceived = GetTimeMs();
       }
-      m_processor->TransmitPendingActiveSourceCommands();
+      // mark the TV as powered on
+      m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
     }
     else if (command.parameters.At(4) == VL_POWERED_DOWN)
-      LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV powered down");
-    else if (command.parameters.At(4) == VL_POWERED_DOWN)
-      LIB_CEC->AddLog(CEC_LOG_DEBUG, "unknown vendor command");
+    {
+      // reset the power up event time
+      {
+        CLockObject lock(m_mutex);
+        m_iPowerUpEventReceived = 0;
+      }
+      // mark the TV as powered off
+      m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_STANDBY);
+    }
+    else
+      LIB_CEC->AddLog(CEC_LOG_DEBUG, "skipping unknown vendor command");
 
-    return true;
+    return COMMAND_HANDLED;
   }
 
   return CCECCommandHandler::HandleDeviceVendorCommandWithId(command);
 }
 
-bool CVLCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress)
+bool CVLCommandHandler::PowerUpEventReceived(void)
 {
-  bool bPowerUpEventReceived(false);
-
-  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;
-  }
+  bool bPowerUpEventReceived(true);
 
-  if (!bPowerUpEventReceived)
+  if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV)
   {
-    CLockObject lock(m_mutex);
-    // wait until we received the event
-    m_bActiveSourcePending = true;
-    return true;
+    // get the status from the TV
+    CCECBusDevice *tv = m_processor->GetTV();
+    if (tv && tv->GetCurrentVendorId() == CEC_VENDOR_PANASONIC)
+    {
+      CVLCommandHandler *handler = static_cast<CVLCommandHandler *>(tv->GetHandler());
+      bPowerUpEventReceived = handler ? handler->PowerUpEventReceived() : false;
+      tv->MarkHandlerReady();
+    }
   }
   else
   {
-    // transmit standard active source message
-    return CCECCommandHandler::TransmitActiveSource(iInitiator, iPhysicalAddress) &&
-        TransmitMenuState(iInitiator, CECDEVICE_TV, CEC_MENU_STATE_ACTIVATED);
+    // get the current status
+    {
+      CLockObject lock(m_mutex);
+      bPowerUpEventReceived = m_iPowerUpEventReceived > 0 &&
+                              GetTimeMs() - m_iPowerUpEventReceived > SOURCE_SWITCH_DELAY_MS;
+    }
+
+    // if we didn't receive the event, check if the TV is already marked as powered on
+    if (!bPowerUpEventReceived && m_busDevice->GetCurrentPowerStatus() == CEC_POWER_STATUS_ON)
+    {
+      CLockObject lock(m_mutex);
+      m_iPowerUpEventReceived = GetTimeMs();
+      bPowerUpEventReceived = true;
+    }
   }
+
+  return bPowerUpEventReceived;
 }
 
-bool CVLCommandHandler::TransmitPendingActiveSourceCommands(void)
+int CVLCommandHandler::HandleStandby(const cec_command &command)
 {
-  bool bTransmitCommand(false);
+  // reset the power up event time
   {
     CLockObject lock(m_mutex);
-    bTransmitCommand = m_bActiveSourcePending;
-    m_bActiveSourcePending = false;
+    m_iPowerUpEventReceived = 0;
   }
 
-  if (bTransmitCommand)
+  return CCECCommandHandler::HandleStandby(command);
+}
+
+int CVLCommandHandler::HandleVendorCommand(const cec_command &command)
+{
+  // some vendor command voodoo that will enable more buttons on the remote
+  if (command.parameters.size == 3 &&
+      command.parameters[0] == 0x10 &&
+      command.parameters[1] == 0x01 &&
+      command.parameters[2] == 0x05)
   {
-    LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
-    return CCECCommandHandler::TransmitActiveSource(m_busDevice->GetLogicalAddress(), m_busDevice->GetCurrentPhysicalAddress()) &&
-        TransmitMenuState(m_busDevice->GetLogicalAddress(), CECDEVICE_TV, CEC_MENU_STATE_ACTIVATED);
+    cec_command response;
+    cec_command::Format(response, command.destination, command.initiator, CEC_OPCODE_VENDOR_COMMAND);
+    uint8_t iResponseData[] = {0x10, 0x02, 0xFF, 0xFF, 0x00, 0x05, 0x05, 0x45, 0x55, 0x5c, 0x58, 0x32};
+    response.PushArray(12, iResponseData);
+
+    Transmit(response, true);
+
+    return COMMAND_HANDLED;
   }
-  return true;
+
+  return CEC_ABORT_REASON_INVALID_OPERAND;
 }
 
-bool CVLCommandHandler::PowerUpEventReceived(void)
+bool CVLCommandHandler::SourceSwitchAllowed(void)
+{
+  return PowerUpEventReceived();
+}
+
+int CVLCommandHandler::HandleSystemAudioModeRequest(const cec_command &command)
 {
+  if (command.initiator == CECDEVICE_TV)
   {
-    CLockObject lock(m_mutex);
-    if (m_bPowerUpEventReceived)
-      return true;
+    // set the power up event time
+    {
+      CLockObject lock(m_mutex);
+      if (m_iPowerUpEventReceived == 0)
+        m_iPowerUpEventReceived = GetTimeMs();
+    }
+    // mark the TV as powered on
+    m_processor->GetTV()->SetPowerStatus(CEC_POWER_STATUS_ON);
   }
 
-  cec_power_status powerStatus = m_busDevice->GetCurrentPowerStatus();
-
-  CLockObject lock(m_mutex);
-  m_bPowerUpEventReceived = (powerStatus == CEC_POWER_STATUS_ON);
-  return m_bPowerUpEventReceived;
+  return CCECCommandHandler::HandleSystemAudioModeRequest(command);
 }
index f2bfc7ec7a0a7c9ead58845636d206a81fb9acfe..d1b25d2be0ee449822fb7c04b92bea76722fcd93 100644 (file)
@@ -38,22 +38,28 @@ namespace CEC
   class CVLCommandHandler : public CCECCommandHandler
   {
   public:
-    CVLCommandHandler(CCECBusDevice *busDevice);
+    CVLCommandHandler(CCECBusDevice *busDevice,
+                      int32_t iTransmitTimeout = CEC_DEFAULT_TRANSMIT_TIMEOUT,
+                      int32_t iTransmitWait = CEC_DEFAULT_TRANSMIT_WAIT,
+                      int8_t iTransmitRetries = CEC_DEFAULT_TRANSMIT_RETRIES,
+                      int64_t iActiveSourcePending = 0);
     virtual ~CVLCommandHandler(void) {};
 
     bool InitHandler(void);
 
-    bool HandleDeviceVendorCommandWithId(const cec_command &command);
-    bool TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress);
-    bool TransmitPendingActiveSourceCommands(void);
+    int HandleDeviceVendorCommandWithId(const cec_command &command);
+    int HandleStandby(const cec_command &command);
+    int HandleSystemAudioModeRequest(const cec_command &command);
 
+    int HandleVendorCommand(const cec_command &command);
     bool PowerUpEventReceived(void);
     bool SupportsDeviceType(const cec_device_type type) const { return type != CEC_DEVICE_TYPE_RECORDING_DEVICE; };
     cec_device_type GetReplacementDeviceType(const cec_device_type type) const { return type == CEC_DEVICE_TYPE_RECORDING_DEVICE ? CEC_DEVICE_TYPE_PLAYBACK_DEVICE : type; }
 
+    bool SourceSwitchAllowed(void);
+
   private:
     PLATFORM::CMutex m_mutex;
-    bool             m_bActiveSourcePending;
-    bool             m_bPowerUpEventReceived;
+    uint64_t         m_iPowerUpEventReceived;
   };
 };
index 4913d7b066244848fdabad850d58b0e8bd26dd38..60e02d6bf4b29466a111f5a6ad8b7decc4a488af 100644 (file)
  *     http://www.pulse-eight.net/
  */
 
+
+#ifdef UNUSED
+#elif defined(__GNUC__)
+#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
+#elif defined(__LCLINT__)
+#define UNUSED(x) /*@unused@*/ x
+#else
+#define UNUSED(x) x
+#endif
+
 #if (defined(_WIN32) || defined(_WIN64))
 #include "windows/os-types.h"
 #else
index ed60ba8724612fae369e1fd7e9e33ede7877e97e..6fc57d140bcdf183a0745fa7d52d3b54a23c00c0 100644 (file)
@@ -51,7 +51,7 @@ namespace PLATFORM
 
   private:
     inline PreventCopy(const PreventCopy &c) { *this = c; }
-    inline PreventCopy &operator=(const PreventCopy &c){ *this = c; return *this; }
+    inline PreventCopy &operator=(const PreventCopy & UNUSED(c)){ return *this; }
   };
 
   template <typename _Predicate>
index f9a127078016bc59b9857d55178bff4a8f12f919..267839250057403258dde433b2643eedd64dbf6c 100644 (file)
@@ -40,6 +40,7 @@
 using namespace PLATFORM;
 
 static GUID MONITOR_GUID =  { 0x4D36E96E, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
+#define PA_MAX_REGENTRIES_TO_CHECK 1024
 
 uint16_t GetPhysicalAddressFromDevice(IN HDEVINFO hDevHandle, IN PSP_DEVINFO_DATA deviceInfoData)
 {
@@ -51,16 +52,16 @@ uint16_t GetPhysicalAddressFromDevice(IN HDEVINFO hDevHandle, IN PSP_DEVINFO_DAT
     CHAR  regEntryName[128];
     DWORD regEntryNameLength(128);
     DWORD type;
-    LONG  retVal(0);
+    LONG  retVal(ERROR_SUCCESS);
 
-    for (LONG ptr = 0; iPA == 0 && retVal != ERROR_NO_MORE_ITEMS; ptr++)
+    for (LONG ptr = 0; iPA == 0 && retVal == ERROR_SUCCESS && ptr < PA_MAX_REGENTRIES_TO_CHECK; ptr++)
     {
       BYTE regEntryData[1024];
       DWORD regEntryDataSize = sizeof(regEntryData);
 
       retVal = RegEnumValue(hDevRegKey, ptr, &regEntryName[0], &regEntryNameLength, NULL, &type, regEntryData, &regEntryDataSize);
 
-      if (retVal == 0 && !strcmp(regEntryName,"EDID"))
+      if (retVal == ERROR_SUCCESS && !strcmp(regEntryName,"EDID"))
         iPA = CEDIDParser::GetPhysicalAddressFromEDID(regEntryData, regEntryDataSize);
     }
     RegCloseKey(hDevRegKey);
index 726cf621d352212e7b03306d8d975f1f263387bb..d613d6ddc40262778bf0e0ec8a7f395d36d9289a 100644 (file)
@@ -2,4 +2,4 @@ bin_PROGRAMS = cec-client
 cec_client_SOURCES = main.cpp
 
 cec_client_CPPFLAGS = -I@abs_top_srcdir@/include
-cec_client_LDFLAGS = @LIBS_DL@
\ No newline at end of file
+cec_client_LDFLAGS = @LIBS@
index 57f61974c725d9e7e54e461fbe5e83b146e03b57..fe3f893a863ef2df0cc92f8250409f144c6f993e 100644 (file)
@@ -45,11 +45,14 @@ using namespace CEC;
 using namespace std;
 using namespace PLATFORM;
 
+#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_1_7_1;
+
 #include <cecloader.h>
 
 ICECCallbacks        g_callbacks;
 libcec_configuration g_config;
-int                  g_cecLogLevel(CEC_LOG_ALL);
+int                  g_cecLogLevel(-1);
+int                  g_cecDefaultLogLevel(CEC_LOG_ALL);
 ofstream             g_logOutput;
 bool                 g_bShortLog(false);
 CStdString           g_strPort;
@@ -1007,6 +1010,8 @@ bool ProcessCommandLineArguments(int argc, char *argv[])
       else if (!strcmp(argv[iArgPtr], "--list-devices") ||
                !strcmp(argv[iArgPtr], "-l"))
       {
+        if (g_cecLogLevel == -1)
+          g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR;
         ICECAdapter *parser = LibCecInitialise(&g_config);
         if (parser)
         {
@@ -1030,6 +1035,9 @@ bool ProcessCommandLineArguments(int argc, char *argv[])
       else if (!strcmp(argv[iArgPtr], "--help") ||
                !strcmp(argv[iArgPtr], "-h"))
       {
+        if (g_cecLogLevel == -1)
+          g_cecLogLevel = CEC_LOG_WARNING + CEC_LOG_ERROR;
+
         ShowHelpCommandLine(argv[0]);
         return 0;
       }
@@ -1098,8 +1106,9 @@ bool ProcessCommandLineArguments(int argc, char *argv[])
 int main (int argc, char *argv[])
 {
   g_config.Clear();
+  g_callbacks.Clear();
   snprintf(g_config.strDeviceName, 13, "CECTester");
-  g_config.clientVersion       = CEC_CLIENT_VERSION_1_6_3;
+  g_config.clientVersion       = CEC_CONFIG_VERSION;
   g_config.bActivateSource     = 0;
   g_callbacks.CBCecLogMessage  = &CecLogMessage;
   g_callbacks.CBCecKeyPress    = &CecKeyPress;
@@ -1110,6 +1119,9 @@ int main (int argc, char *argv[])
   if (!ProcessCommandLineArguments(argc, argv))
     return 0;
 
+  if (g_cecLogLevel == -1)
+    g_cecLogLevel = g_cecDefaultLogLevel;
+
   if (g_config.deviceTypes.IsEmpty())
   {
     if (!g_bSingleCommand)