Merge branch 'master' into release
authorLars Op den Kamp <lars@opdenkamp.eu>
Thu, 6 Dec 2012 20:18:49 +0000 (21:18 +0100)
committerLars Op den Kamp <lars@opdenkamp.eu>
Thu, 6 Dec 2012 20:18:49 +0000 (21:18 +0100)
27 files changed:
ChangeLog
debian/changelog
include/cec.h
include/cecc.h
include/cectypes.h
project/libCEC.nsi
project/libcec.rc
project/testclient.rc
src/CecSharpTester/CecSharpClient.cs
src/CecSharpTester/Properties/AssemblyInfo.cs
src/LibCecSharp/AssemblyInfo.cpp
src/LibCecSharp/CecSharpTypes.h
src/LibCecTray/Properties/AssemblyInfo.cs
src/LibCecTray/controller/CECController.cs
src/lib/CECClient.cpp
src/lib/CECClient.h
src/lib/CECProcessor.cpp
src/lib/CECTypeUtils.h
src/lib/LibCEC.cpp
src/lib/LibCEC.h
src/lib/LibCECC.cpp
src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.cpp
src/lib/devices/CECAudioSystem.cpp
src/lib/devices/CECAudioSystem.h
src/lib/devices/CECBusDevice.cpp
src/lib/implementations/CECCommandHandler.cpp
src/lib/implementations/CECCommandHandler.h

index a1ccd6822ecb0a95899391545f27424e682a819d..d284eda629476aaf92297789799965b9e2123057 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+libcec (2.0.5-1) unstable; urgency=low
+
+  * changed:
+    * also try polls at least twice when it failed
+    * added methods to get the audiostatus and toggle the mute status from the
+      amplifier (if connected)
+    * added comboKey and iComboKeyTimeoutMs to libcec_configuration
+    * force cec_user_control_code_unknown to 0xFF
+  * fixed:
+    * check unsupported features properly
+    * only send an active source message when the stream path changed and we
+      weren't the active source yet
+    * don't mark as inactive source on routing changes
+    * press & hold
+    * never mark user control opcodes as unsupported
+    * report our OSD name to the TV, since some TVs don't request it
+    * initial audiostatus value
+    * don't log a no longer relevant FIXME
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Thu, 6 Dec 2012 20:58:00 +0100
+
 libcec (2.0.4-1) unstable; urgency=low
 
   * changed:
index a1ccd6822ecb0a95899391545f27424e682a819d..d284eda629476aaf92297789799965b9e2123057 100644 (file)
@@ -1,3 +1,24 @@
+libcec (2.0.5-1) unstable; urgency=low
+
+  * changed:
+    * also try polls at least twice when it failed
+    * added methods to get the audiostatus and toggle the mute status from the
+      amplifier (if connected)
+    * added comboKey and iComboKeyTimeoutMs to libcec_configuration
+    * force cec_user_control_code_unknown to 0xFF
+  * fixed:
+    * check unsupported features properly
+    * only send an active source message when the stream path changed and we
+      weren't the active source yet
+    * don't mark as inactive source on routing changes
+    * press & hold
+    * never mark user control opcodes as unsupported
+    * report our OSD name to the TV, since some TVs don't request it
+    * initial audiostatus value
+    * don't log a no longer relevant FIXME
+
+ -- Pulse-Eight Packaging <packaging@pulse-eight.com>  Thu, 6 Dec 2012 20:58:00 +0100
+
 libcec (2.0.4-1) unstable; urgency=low
 
   * changed:
index c68bba81487dbccc85a9c32f749087e7a71f4622..02450331d43c0e365ab32eed44a6e5bbc62e1ca1 100644 (file)
@@ -251,6 +251,7 @@ namespace CEC
     virtual uint8_t VolumeDown(bool bSendRelease = true) = 0;
 
     /*!
+     * @deprecated Use AudioToggleMute() instead
      * @brief Sends a mute keypress to an audiosystem if it's present.
      * @param bSendRelease Send a key release after the keypress.
      * @return The new audio status.
@@ -421,6 +422,30 @@ namespace CEC
     virtual const char *ToString(const cec_server_version version) = 0;
     virtual const char *ToString(const cec_user_control_code key) = 0;
     virtual const char *ToString(const cec_adapter_type type) = 0;
+
+    /*!
+     * @brief Toggle the mute status of the AVR (if present)
+     * @return The new audio status.
+     */
+    virtual uint8_t AudioToggleMute(void) = 0;
+
+    /*!
+     * @brief Mute the AVR (if present)
+     * @return The new audio status.
+     */
+    virtual uint8_t AudioMute(void) = 0;
+
+    /*!
+     * @brief Mute the AVR (if connected)
+     * @return The new audio status.
+     */
+    virtual uint8_t AudioUnmute(void) = 0;
+
+    /*!
+     * @brief Get the current audio status (if an AVR is connected)
+     * @return The current audio status, or cec_audio_status if unknown.
+     */
+    virtual uint8_t AudioStatus(void) = 0;
   };
 };
 
index a4892c48b045ab13d276e1e32ee69738503c0b06..2e1f9a80d8ab6f5260aa7eaf47450a9be51f238f 100644 (file)
@@ -276,6 +276,14 @@ extern DECLSPEC uint16_t cec_get_adapter_vendor_id(void);
 
 extern DECLSPEC uint16_t cec_get_adapter_product_id(void);
 
+extern DECLSPEC uint8_t cec_audio_toggle_mute(void);
+
+extern DECLSPEC uint8_t cec_audio_mute(void);
+
+extern DECLSPEC uint8_t cec_audio_unmute(void);
+
+extern DECLSPEC uint8_t cec_audio_status(void);
+
 #ifdef __cplusplus
 };
 #endif
index dfcebfe282e10701b2a526db0fcec576cab15ea4..e85bcfa44bccf45e3c182531a455f9b94c4ba374 100644 (file)
@@ -264,6 +264,11 @@ namespace CEC {
  */
 #define CEC_FORWARD_STANDBY_MIN_INTERVAL 10000
 
+/*!
+ * default timeout in milliseconds for combo keys
+ */
+#define CEC_DEFAULT_COMBO_TIMEOUT_MS 1000
+
 /*!
  * the virtual device path to use for the Raspberry Pi's CEC wire
  */
@@ -309,6 +314,8 @@ namespace CEC {
 #define MSGESC                       0xFD
 #define ESCOFFSET                    3
 
+// defines to make compile time checks for certain features easy
+#define CEC_FEATURE_CONFIGURABLE_COMBO_KEY 1
 
 typedef enum cec_abort_reason
 {
@@ -691,7 +698,7 @@ typedef enum cec_user_control_code
   CEC_USER_CONTROL_CODE_AN_RETURN                   = 0x91,
   CEC_USER_CONTROL_CODE_AN_CHANNELS_LIST            = 0x96,
   CEC_USER_CONTROL_CODE_MAX                         = 0x96,
-  CEC_USER_CONTROL_CODE_UNKNOWN
+  CEC_USER_CONTROL_CODE_UNKNOWN                     = 0xFF
 } cec_user_control_code;
 
 typedef enum cec_logical_address
@@ -1379,7 +1386,8 @@ typedef enum cec_client_version
   CEC_CLIENT_VERSION_2_0_2   = 0x2002,
   CEC_CLIENT_VERSION_2_0_3   = 0x2003,
   CEC_CLIENT_VERSION_2_0_4   = 0x2004,
-  CEC_CLIENT_VERSION_CURRENT = 0x2004
+  CEC_CLIENT_VERSION_2_0_5   = 0x2005,
+  CEC_CLIENT_VERSION_CURRENT = 0x2005
 } cec_client_version;
 
 typedef enum cec_server_version
@@ -1406,7 +1414,8 @@ typedef enum cec_server_version
   CEC_SERVER_VERSION_2_0_2   = 0x2002,
   CEC_SERVER_VERSION_2_0_3   = 0x2003,
   CEC_SERVER_VERSION_2_0_4   = 0x2004,
-  CEC_SERVER_VERSION_CURRENT = 0x2004
+  CEC_SERVER_VERSION_2_0_5   = 0x2005,
+  CEC_SERVER_VERSION_CURRENT = 0x2005
 } cec_server_version;
 
 struct libcec_configuration
@@ -1445,6 +1454,8 @@ struct libcec_configuration
   cec_version           cecVersion;           /*!< CEC spec version to use by libCEC. defaults to v1.4. added in 1.8.0 */
   cec_adapter_type      adapterType;          /*!< type of the CEC adapter that we're connected to. added in 1.8.2 */
   uint8_t               iDoubleTapTimeoutMs;  /*!< prevent double taps withing this timeout. defaults to 200ms. added in 2.0.0 */
+  cec_user_control_code comboKey;             /*!< key code that initiates combo keys. defaults to CEC_USER_CONTROL_CODE_F1_BLUE. CEC_USER_CONTROL_CODE_UNKNOWN to disable. added in 2.0.5 */
+  uint32_t              iComboKeyTimeoutMs;   /*!< timeout until the combo key is sent as normal keypress */
 
 #ifdef __cplusplus
    libcec_configuration(void) { Clear(); }
@@ -1478,7 +1489,9 @@ struct libcec_configuration
                   bMonitorOnly              == other.bMonitorOnly &&
                   cecVersion                == other.cecVersion &&
                   adapterType               == other.adapterType &&
-                  iDoubleTapTimeoutMs       == other.iDoubleTapTimeoutMs);
+                  iDoubleTapTimeoutMs       == other.iDoubleTapTimeoutMs &&
+                  (other.clientVersion <= CEC_CLIENT_VERSION_2_0_4 || comboKey           == other.comboKey) &&
+                  (other.clientVersion <= CEC_CLIENT_VERSION_2_0_4 || iComboKeyTimeoutMs == other.iComboKeyTimeoutMs));
   }
 
   bool operator!=(const libcec_configuration &other) const
@@ -1495,8 +1508,8 @@ struct libcec_configuration
     baseDevice = (cec_logical_address)CEC_DEFAULT_BASE_DEVICE;
     iHDMIPort =                       CEC_DEFAULT_HDMI_PORT;
     tvVendor =              (uint64_t)CEC_VENDOR_UNKNOWN;
-    clientVersion =         (uint32_t)CEC_CLIENT_VERSION_2_0_0;
-    serverVersion =         (uint32_t)CEC_SERVER_VERSION_2_0_0;
+    clientVersion =         (uint32_t)CEC_CLIENT_VERSION_CURRENT;
+    serverVersion =         (uint32_t)CEC_SERVER_VERSION_CURRENT;
     bAutodetectAddress =              0;
     bGetSettingsFromROM =             CEC_DEFAULT_SETTING_GET_SETTINGS_FROM_ROM;
     bUseTVMenuLanguage =              CEC_DEFAULT_SETTING_USE_TV_MENU_LANGUAGE;
@@ -1513,6 +1526,8 @@ struct libcec_configuration
     cecVersion =         (cec_version)CEC_DEFAULT_SETTING_CEC_VERSION;
     adapterType =                     ADAPTERTYPE_UNKNOWN;
     iDoubleTapTimeoutMs =             CEC_DOUBLE_TAP_TIMEOUT_MS;
+    comboKey =                        CEC_USER_CONTROL_CODE_STOP;
+    iComboKeyTimeoutMs =              CEC_DEFAULT_COMBO_TIMEOUT_MS;
 
     memset(strDeviceName, 0, 13);
     deviceTypes.Clear();
index 8f665f22800e1326a5884e19d1d2c7e5e26f6f98..635df7abe61bebe1b99dbaaa029e4fe0c46a2a68 100644 (file)
@@ -7,7 +7,7 @@
 !include "LogicLib.nsh"
 !include "x64.nsh"
 
-Name "Pulse-Eight libCEC version 2.0.4"
+Name "Pulse-Eight libCEC version 2.0.5"
 OutFile "..\build\libCEC-installer.exe"
 
 XPStyle on
index 2f70b2f9d34b0964aa267568416a13ab6a0375d2..0b1ebe19a9cb8f8d55ac6d1551cfe2dba85901d4 100644 (file)
Binary files a/project/libcec.rc and b/project/libcec.rc differ
index b2ba0e28a7ce9f39c7d7c480b79682691dcd99ff..1f44a184e00ce593bf9a2e618f5c4f8332867887 100644 (file)
Binary files a/project/testclient.rc and b/project/testclient.rc differ
index d1c6c3ee1b6972caa67a6b44aa2476e0169fbb0c..0e8f4602858ffbae6864cb020d95ed2787a4d99e 100644 (file)
@@ -43,7 +43,7 @@ namespace CecSharpClient
       Config = new LibCECConfiguration();
       Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice;
       Config.DeviceName = "CEC Tester";
-      Config.ClientVersion = CecClientVersion.Version2_0_4;
+      Config.ClientVersion = CecClientVersion.Version2_0_5;
       Config.SetCallbacks(this);
       LogLevel = (int)CecLogLevel.All;
 
index 12704014ca49f0c2f4b3cf5c75e511ad20cfcd06..d49913bdcba799b3c23e59199236d55654807ca9 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("2.0.4.0")]
-[assembly: AssemblyFileVersion("2.0.4.0")]
+[assembly: AssemblyVersion("2.0.5.0")]
+[assembly: AssemblyFileVersion("2.0.5.0")]
index d5d229f3c51f15e782f3abd32239ecfc007594d3..8e4ecb845e825a9a55f669f5c7f528478bfbcac6 100644 (file)
@@ -13,7 +13,7 @@ using namespace System::Security::Permissions;
 [assembly:AssemblyTrademarkAttribute("")];
 [assembly:AssemblyCultureAttribute("")];
 
-[assembly:AssemblyVersionAttribute("2.0.4.0")];
+[assembly:AssemblyVersionAttribute("2.0.5.0")];
 
 [assembly:ComVisible(false)];
 [assembly:CLSCompliantAttribute(true)];
index a6fc2d4a25602ed4a5c5911362c607bc71ca88c1..a75a76217a511f852ef68f856ca4e8a707df5b8b 100644 (file)
@@ -1179,7 +1179,11 @@ namespace CecSharp
     /// <summary>
     /// v2.0.4
     /// </summary>
-    Version2_0_4   = 0x2004
+    Version2_0_4   = 0x2004,
+    /// <summary>
+    /// v2.0.5
+    /// </summary>
+    Version2_0_5   = 0x2005
   };
 
   /// <summary>
@@ -1274,7 +1278,11 @@ namespace CecSharp
     /// <summary>
     /// v2.0.4
     /// </summary>
-    Version2_0_4   = 0x2004
+    Version2_0_4   = 0x2004,
+    /// <summary>
+    /// v2.0.5
+    /// </summary>
+    Version2_0_5   = 0x2005
   };
 
   /// <summary>
index bccd9c72cc55693ea7d1b8b9ff3d86a53b2dfc58..3f09c27e43e3d700219d28be5e52845a5ca95a52 100644 (file)
@@ -31,5 +31,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("2.0.4.0")]
-[assembly: AssemblyFileVersion("2.0.4.0")]
+[assembly: AssemblyVersion("2.0.5.0")]
+[assembly: AssemblyFileVersion("2.0.5.0")]
index b54ecdd9197a53d7b819acc64b7e5f460ba61e3c..751330fd77497a234df98c09148cee7205c20063 100644 (file)
@@ -438,7 +438,7 @@ namespace LibCECTray.controller
       {
         if (_config == null)
         {
-          _config = new LibCECConfiguration { DeviceName = "CEC Tray", ClientVersion = CecClientVersion.Version2_0_4 };
+          _config = new LibCECConfiguration { DeviceName = "CEC Tray", ClientVersion = CecClientVersion.Version2_0_5 };
           _config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice;
           _config.SetCallbacks(this);
 
index 9d814cd35868409222f1f0457b0441a941388434..d0699130cd303a6bc247351edd318653ce7cdd5a 100644 (file)
@@ -47,9 +47,6 @@ using namespace PLATFORM;
 #define LIB_CEC     m_processor->GetLib()
 #define ToString(x) CCECTypeUtils::ToString(x)
 
-#define COMBO_KEY        CEC_USER_CONTROL_CODE_STOP
-#define COMBO_TIMEOUT_MS 1000
-
 CCECClient::CCECClient(CCECProcessor *processor, const libcec_configuration &configuration) :
     m_processor(processor),
     m_bInitialised(false),
@@ -748,6 +745,45 @@ uint8_t CCECClient::SendMuteAudio(void)
       (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
 }
 
+uint8_t CCECClient::AudioToggleMute(void)
+{
+  CCECBusDevice *device = GetPrimaryDevice();
+  CCECAudioSystem *audio = m_processor->GetAudioSystem();
+
+  return device && audio && audio->IsPresent() ?
+      audio->MuteAudio(device->GetLogicalAddress()) :
+      (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CCECClient::AudioMute(void)
+{
+  CCECBusDevice *device = GetPrimaryDevice();
+  CCECAudioSystem *audio = m_processor->GetAudioSystem();
+  uint8_t iStatus = device && audio && audio->IsPresent() ? audio->GetAudioStatus(device->GetLogicalAddress()) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+  if ((iStatus & CEC_AUDIO_MUTE_STATUS_MASK) != CEC_AUDIO_MUTE_STATUS_MASK)
+    iStatus = audio->MuteAudio(device->GetLogicalAddress());
+
+  return iStatus;
+}
+
+uint8_t CCECClient::AudioUnmute(void)
+{
+  CCECBusDevice *device = GetPrimaryDevice();
+  CCECAudioSystem *audio = m_processor->GetAudioSystem();
+  uint8_t iStatus = device && audio && audio->IsPresent() ? audio->GetAudioStatus(device->GetLogicalAddress()) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+  if ((iStatus & CEC_AUDIO_MUTE_STATUS_MASK) == CEC_AUDIO_MUTE_STATUS_MASK)
+    iStatus = audio->MuteAudio(device->GetLogicalAddress());
+
+  return iStatus;
+}
+
+uint8_t CCECClient::AudioStatus(void)
+{
+  CCECBusDevice *device = GetPrimaryDevice();
+  CCECAudioSystem *audio = m_processor->GetAudioSystem();
+  return device && audio && audio->IsPresent() ? audio->GetAudioStatus(device->GetLogicalAddress()) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
 bool CCECClient::SendKeypress(const cec_logical_address iDestination, const cec_user_control_code key, bool bWait /* = true */)
 {
   CCECBusDevice *dest = m_processor->GetDevice(iDestination);
@@ -803,6 +839,7 @@ bool CCECClient::GetCurrentConfiguration(libcec_configuration &configuration)
 
 bool CCECClient::SetConfiguration(const libcec_configuration &configuration)
 {
+  libcec_configuration defaultSettings;
   bool bIsRunning(m_processor && m_processor->CECInitialised());
   CCECBusDevice *primary = bIsRunning ? GetPrimaryDevice() : NULL;
   uint16_t iPA = primary ? primary->GetCurrentPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
@@ -838,7 +875,19 @@ bool CCECClient::SetConfiguration(const libcec_configuration &configuration)
     m_configuration.bMonitorOnly               = configuration.bMonitorOnly;
     m_configuration.cecVersion                 = configuration.cecVersion;
     m_configuration.adapterType                = configuration.adapterType;
-    m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
+    m_configuration.iDoubleTapTimeoutMs        = configuration.iDoubleTapTimeoutMs;
+    m_configuration.deviceTypes.Add(configuration.deviceTypes[0]);
+
+    if (m_configuration.clientVersion >= CEC_CLIENT_VERSION_2_0_5)
+    {
+      m_configuration.comboKey           = configuration.comboKey;
+      m_configuration.iComboKeyTimeoutMs = configuration.iComboKeyTimeoutMs;
+    }
+    else
+    {
+      m_configuration.comboKey           = defaultSettings.comboKey;
+      m_configuration.iComboKeyTimeoutMs = defaultSettings.iComboKeyTimeoutMs;
+    }
   }
 
   bool bNeedReinit(false);
@@ -918,7 +967,10 @@ void CCECClient::AddKey(bool bSendComboKey /* = false */)
     {
       key.duration = (unsigned int) (GetTimeMs() - m_buttontime);
 
-      if (key.duration > COMBO_TIMEOUT_MS || m_iCurrentButton != COMBO_KEY || bSendComboKey)
+      cec_user_control_code comboKey(m_configuration.comboKey);
+      uint32_t iTimeoutMs(m_configuration.iComboKeyTimeoutMs);
+
+      if (key.duration > iTimeoutMs || m_iCurrentButton != comboKey || bSendComboKey)
       {
         key.keycode = m_iCurrentButton;
 
@@ -937,18 +989,21 @@ void CCECClient::AddKey(bool bSendComboKey /* = false */)
 
 void CCECClient::AddKey(const cec_keypress &key)
 {
-  // send back the previous key if there is one
-  AddKey();
-
   if (key.keycode > CEC_USER_CONTROL_CODE_MAX &&
       key.keycode < CEC_USER_CONTROL_CODE_SELECT)
+  {
+    // send back the previous key if there is one
+    AddKey();
     return;
+  }
 
   cec_keypress transmitKey(key);
+  cec_user_control_code comboKey(m_configuration.clientVersion >= CEC_CLIENT_VERSION_2_0_5 ?
+      m_configuration.comboKey : CEC_USER_CONTROL_CODE_STOP);
 
   {
     CLockObject lock(m_mutex);
-    if (m_iCurrentButton == COMBO_KEY && key.duration == 0)
+    if (m_iCurrentButton == comboKey && key.duration == 0)
     {
       // stop + ok -> exit
       if (key.keycode == CEC_USER_CONTROL_CODE_SELECT)
@@ -964,14 +1019,22 @@ void CCECClient::AddKey(const cec_keypress &key)
         AddKey(true);
     }
 
-    if (key.duration == 0)
+    if (m_iCurrentButton == key.keycode)
+    {
+      m_buttontime = GetTimeMs();
+    }
+    else
     {
-      m_iCurrentButton = transmitKey.keycode;
-      m_buttontime = m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN || key.duration > 0 ? 0 : GetTimeMs();
+      AddKey();
+      if (key.duration == 0)
+      {
+        m_iCurrentButton = transmitKey.keycode;
+        m_buttontime = m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN || key.duration > 0 ? 0 : GetTimeMs();
+      }
     }
   }
 
-  if (key.keycode != COMBO_KEY || key.duration > 0)
+  if (key.keycode != comboKey || key.duration > 0)
   {
     LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %s (%1x)", ToString(transmitKey.keycode), transmitKey.keycode);
     CallbackAddKey(transmitKey);
@@ -995,10 +1058,14 @@ void CCECClient::CheckKeypressTimeout(void)
   {
     CLockObject lock(m_mutex);
     uint64_t iNow = GetTimeMs();
+    cec_user_control_code comboKey(m_configuration.clientVersion >= CEC_CLIENT_VERSION_2_0_5 ?
+        m_configuration.comboKey : CEC_USER_CONTROL_CODE_STOP);
+    uint32_t iTimeoutMs(m_configuration.clientVersion >= CEC_CLIENT_VERSION_2_0_5 ?
+        m_configuration.iComboKeyTimeoutMs : CEC_DEFAULT_COMBO_TIMEOUT_MS);
 
     if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN &&
-          ((m_iCurrentButton == COMBO_KEY && iNow - m_buttontime > COMBO_TIMEOUT_MS) ||
-          (m_iCurrentButton != COMBO_KEY && iNow - m_buttontime > CEC_BUTTON_TIMEOUT)))
+          ((m_iCurrentButton == comboKey && iNow - m_buttontime > iTimeoutMs) ||
+          (m_iCurrentButton != comboKey && iNow - m_buttontime > CEC_BUTTON_TIMEOUT)))
     {
       key.duration = (unsigned int) (iNow - m_buttontime);
       key.keycode = m_iCurrentButton;
index 11a6504d826aaa14b3f59e7cec1100f55bc2e249..adeaf739b22c5474ce6e9ddae15085063bbb46d2 100644 (file)
@@ -152,6 +152,10 @@ namespace CEC
     virtual uint8_t               SendVolumeUp(bool bSendRelease = true);
     virtual uint8_t               SendVolumeDown(bool bSendRelease = true);
     virtual uint8_t               SendMuteAudio(void);
+    virtual uint8_t               AudioToggleMute(void);
+    virtual uint8_t               AudioMute(void);
+    virtual uint8_t               AudioUnmute(void);
+    virtual uint8_t               AudioStatus(void);
     virtual bool                  SendKeypress(const cec_logical_address iDestination, const cec_user_control_code key, bool bWait = true);
     virtual bool                  SendKeyRelease(const cec_logical_address iDestination, bool bWait = true);
     virtual cec_osd_name          GetDeviceOSDName(const cec_logical_address iAddress);
index e432033961ab0a487cbeb4d4768d44455ac48824..707b8eb2d6e767a13c527d62b4d23ac21fa803ea 100644 (file)
@@ -839,6 +839,9 @@ bool CCECProcessor::RegisterClient(CCECClient *client)
     GetTV()->MarkHandlerReady();
   }
 
+  // report our OSD name to the TV, since some TVs don't request it
+  client->GetPrimaryDevice()->TransmitOSDName(CECDEVICE_TV, false);
+
   // request the power status of the TV
   tv->RequestPowerStatus(sourceAddress, true);
 
index 7699b8994b4148c86e0c2f36933857f8100e2aca..b3e209bb97c3516d69f1236a476bbf1e85e91349 100644 (file)
@@ -565,6 +565,8 @@ namespace CEC
         return "2.0.3";
       case CEC_CLIENT_VERSION_2_0_4:
         return "2.0.4";
+      case CEC_CLIENT_VERSION_2_0_5:
+        return "2.0.5";
       default:
         return "Unknown";
       }
@@ -618,6 +620,8 @@ namespace CEC
         return "2.0.3";
       case CEC_SERVER_VERSION_2_0_4:
         return "2.0.4";
+      case CEC_SERVER_VERSION_2_0_5:
+        return "2.0.5";
       default:
         return "Unknown";
       }
index 2cb5b2f6ab55c000645a5114f4d3a6a56184c183..a27ad9dbc45530e02a38ed3a3b408b64db6f9955 100644 (file)
@@ -280,6 +280,7 @@ uint8_t CLibCEC::VolumeDown(bool bSendRelease /* = true */)
 
 uint8_t CLibCEC::MuteAudio(bool UNUSED(bSendRelease) /* = true */)
 {
+  AddLog(CEC_LOG_WARNING, "deprecated function called: %s", __FUNCTION__);
   return m_client ? m_client->SendMuteAudio() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
 }
 
@@ -538,3 +539,23 @@ uint16_t CLibCEC::GetAdapterProductId(void) const
 {
   return m_cec && m_cec->IsRunning() ? m_cec->GetAdapterProductId() : 0;
 }
+
+uint8_t CLibCEC::AudioToggleMute(void)
+{
+  return m_client ? m_client->AudioToggleMute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CLibCEC::AudioMute(void)
+{
+  return m_client ? m_client->AudioMute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CLibCEC::AudioUnmute(void)
+{
+  return m_client ? m_client->AudioUnmute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t CLibCEC::AudioStatus(void)
+{
+  return m_client ? m_client->AudioStatus() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
index 56a112bf52e9e42ee49c45eaf05838eb6719a1ab..f65b8186b9e843d2917fa95e98be62b891a1b2a5 100644 (file)
@@ -132,6 +132,11 @@ namespace CEC
       uint16_t GetAdapterVendorId(void) const;
       uint16_t GetAdapterProductId(void) const;
 
+      uint8_t AudioToggleMute(void);
+      uint8_t AudioMute(void);
+      uint8_t AudioUnmute(void);
+      uint8_t AudioStatus(void);
+
       CCECProcessor *           m_cec;
 
     protected:
index 153668db2f6f3c1349d35fd28b0b9a7ca2431264..b53dc05f29541ef7bd3aa23553a23d0cd5efe264 100644 (file)
@@ -388,4 +388,24 @@ uint16_t cec_get_adapter_product_id(void)
   return cec_parser ? cec_parser->GetAdapterProductId() : 0;
 }
 
+uint8_t cec_audio_toggle_mute(void)
+{
+  return cec_parser ? cec_parser->AudioToggleMute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t cec_audio_mute(void)
+{
+  return cec_parser ? cec_parser->AudioMute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t cec_audio_unmute(void)
+{
+  return cec_parser ? cec_parser->AudioUnmute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
+uint8_t cec_audio_status(void)
+{
+  return cec_parser ? cec_parser->AudioStatus() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
+}
+
 //@}
index 4e4c2cb82a678e1b0f63e94d1b2b82bfe7b5b49b..a9913ab560af37674f81106e30ca1f6288ba05a2 100644 (file)
@@ -169,10 +169,7 @@ bool CCECAdapterMessageQueueEntry::IsResponse(const CCECAdapterMessage &msg)
     return thisMsgCode == msgResponse;
 
   if (!m_message->IsTranmission())
-  {
-    m_queue->m_com->m_callback->GetLib()->AddLog(CEC_LOG_WARNING, "FIXME! not a transmission: %s", msg.ToString().c_str());
     return false;
-  }
 
   return ((msgCode == MSGCODE_COMMAND_ACCEPTED || msgCode == MSGCODE_COMMAND_REJECTED) &&
       (msgResponse == MSGCODE_TRANSMIT_ACK_POLARITY || msgResponse == MSGCODE_TRANSMIT || msgResponse == MSGCODE_TRANSMIT_EOM)) ||
index add3e6f3f6286137370a5d53fa3982012c8ce8d9..1dc2bdcbd7ca48ee29ed9e32d93bbdf1485fe8f7 100644 (file)
@@ -47,7 +47,7 @@ using namespace PLATFORM;
 CCECAudioSystem::CCECAudioSystem(CCECProcessor *processor, cec_logical_address address, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
     CCECBusDevice(processor, address, iPhysicalAddress),
     m_systemAudioStatus(CEC_SYSTEM_AUDIO_STATUS_ON),
-    m_audioStatus(CEC_AUDIO_MUTE_STATUS_MASK)
+    m_audioStatus(CEC_AUDIO_VOLUME_STATUS_UNKNOWN)
 {
   m_type = CEC_DEVICE_TYPE_AUDIO_SYSTEM;
 }
@@ -139,6 +139,40 @@ uint8_t CCECAudioSystem::MuteAudio(const cec_logical_address source)
   TransmitKeypress(source, CEC_USER_CONTROL_CODE_MUTE);
   TransmitKeyRelease(source);
 
+  return GetAudioStatus(source, true);
+}
+
+bool CCECAudioSystem::RequestAudioStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
+{
+  bool bReturn(false);
+
+  if (!IsHandledByLibCEC() &&
+      !IsUnsupportedFeature(CEC_OPCODE_GIVE_AUDIO_STATUS))
+  {
+    MarkBusy();
+    LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting audio status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
+    bReturn = m_handler->TransmitRequestAudioStatus(initiator, m_iLogicalAddress, bWaitForResponse);
+    MarkReady();
+  }
+  return bReturn;
+}
+
+uint8_t CCECAudioSystem::GetAudioStatus(const cec_logical_address initiator, bool bUpdate /* = false */)
+{
+  bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+  bool bRequestUpdate(false);
+  {
+    CLockObject lock(m_mutex);
+    bRequestUpdate = bIsPresent &&
+        (bUpdate || m_audioStatus == CEC_AUDIO_VOLUME_STATUS_UNKNOWN);
+  }
+
+  if (bRequestUpdate)
+  {
+    CheckVendorIdRequested(initiator);
+    RequestAudioStatus(initiator);
+  }
+
   CLockObject lock(m_mutex);
   return m_audioStatus;
 }
index 795031101223e1ff250b49fe3cb7659cc3e854d8..8ab055e0bc7a520ca207ca20afdaf1ab7727c022 100644 (file)
@@ -50,10 +50,13 @@ namespace CEC
     uint8_t VolumeUp(const cec_logical_address source, bool bSendRelease = true);
     uint8_t VolumeDown(const cec_logical_address source, bool bSendRelease = true);
     uint8_t MuteAudio(const cec_logical_address source);
+    uint8_t GetAudioStatus(const cec_logical_address initiator, bool bUpdate = false);
 
     bool TransmitActiveSource(void) { return false; }
 
   protected:
+    bool RequestAudioStatus(const cec_logical_address initiator, bool bWaitForResponse = true);
+
     cec_system_audio_status m_systemAudioStatus;
     uint8_t                 m_audioStatus;
   };
index 7733cfbe91130923736b35e4a3bc31f1c6e8c727..fa063f4e52d47209bf3b223228c939b683602652 100644 (file)
@@ -227,7 +227,9 @@ void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
       opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP ||
       opcode == CEC_OPCODE_ABORT ||
       opcode == CEC_OPCODE_FEATURE_ABORT ||
-      opcode == CEC_OPCODE_NONE)
+      opcode == CEC_OPCODE_NONE ||
+      opcode == CEC_OPCODE_USER_CONTROL_PRESSED ||
+      opcode == CEC_OPCODE_USER_CONTROL_RELEASE)
     return;
 
   {
@@ -1133,21 +1135,7 @@ void CCECBusDevice::SetActiveRoute(uint16_t iRoute)
 
   CCECBusDevice* newRoute = m_processor->GetDeviceByPhysicalAddress(iRoute, true);
   if (newRoute && newRoute->IsHandledByLibCEC())
-  {
     newRoute->ActivateSource();
-    return;
-  }
-
-  CECDEVICEVEC devices;
-  m_processor->GetDevices()->GetChildrenOf(devices, this);
-
-  for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
-  {
-    if ((*it)->GetCurrentPhysicalAddress() == iRoute && (*it)->IsHandledByLibCEC())
-      (*it)->ActivateSource();
-    else if (!CCECTypeUtils::PhysicalAddressIsIncluded(iRoute, (*it)->GetCurrentPhysicalAddress()))
-      (*it)->MarkAsInactiveSource();
-  }
 }
 
 void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
index e4a7995173a1868cf5728c91bb3382d09733c852..174275ca2e48850fc4c9b63511ef1345949a04ac 100644 (file)
@@ -577,7 +577,7 @@ int CCECCommandHandler::HandleSetStreamPath(const cec_command &command)
     CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress);
     if (device)
     {
-      if (device->IsHandledByLibCEC())
+      if (device->IsHandledByLibCEC() && !device->IsActiveSource())
         device->ActivateSource();
       else
         device->MarkAsActiveSource();
@@ -898,6 +898,14 @@ bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iIniti
   return Transmit(command, !bWaitForResponse, false);
 }
 
+bool CCECCommandHandler::TransmitRequestAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */)
+{
+  cec_command command;
+  cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_AUDIO_STATUS);
+
+  return Transmit(command, !bWaitForResponse, false);
+}
+
 bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */)
 {
   cec_command command;
@@ -1142,11 +1150,15 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait, bool
       LIB_CEC->AddLog(CEC_LOG_DEBUG, "not sending command '%s': destination device '%s' marked as handled by libCEC", ToString(command.opcode),ToString(command.destination));
       return bReturn;
     }
+    else if (destinationDevice->IsUnsupportedFeature(command.opcode))
+    {
+      return true;
+    }
   }
 
   {
-    uint8_t iTries(0), iMaxTries(!command.opcode_set ? 1 : m_iTransmitRetries + 1);
-    while (!bReturn && ++iTries <= iMaxTries && !m_busDevice->IsUnsupportedFeature(command.opcode))
+    uint8_t iTries(0), iMaxTries(m_iTransmitRetries + 1);
+    while (!bReturn && ++iTries <= iMaxTries)
     {
       if ((bReturn = m_processor->Transmit(command, bIsReply)) == true)
       {
index c8430ec1e5f45b5e119f015a3a543bafe153d983..4a8dacbe7f59e25ecc400ca6763b5eb559525bfc 100644 (file)
@@ -70,6 +70,7 @@ namespace CEC
     virtual bool TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
     virtual bool TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
     virtual bool TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
+    virtual bool TransmitRequestAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
     virtual bool TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
     virtual bool TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);
     virtual bool TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse = true);