From: Lars Op den Kamp Date: Thu, 15 Nov 2012 14:51:25 +0000 (+0100) Subject: Merge branch 'master' into release X-Git-Tag: upstream/2.2.0~1^2~12 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=cf34f9fd4c28854152a995bdc9243b8a7bb893a1;hp=75362c3c044a252f4d596ed8b28cad8069c2e781;p=deb_libcec.git Merge branch 'master' into release --- diff --git a/ChangeLog b/ChangeLog index 9b0d274..a1ccd68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,49 @@ +libcec (2.0.4-1) unstable; urgency=low + + * changed: + * dropped obsolete cec-config + * added CEC_CLIENT_VERSION_CURRENT and CEC_SERVER_VERSION_CURRENT. closes + #88 + * support colon separated data for the 'tx' command in cec-client + * mark the adapter as (in)active source for firmware v3+ + * added 'is' command to cec-client, to mark libCEC as inactive source + * fixed: + * only change the handler of the primary device if the tv has a quirks mode + not for other devices + * send an active source message when the route was set to the physical + address that is handled by libCEC + * default double tap timeout wasn't set for panasonic + * philips TVs sometimes keep sending key presses without key releases + * philips TVs ignore 'image view on' right after they were sent into + standby. check the power status of the tv every 5 seconds, until it + reports to have powered on + * mark a device as powered on when receiving a stream path or routing + change + * update the active source status correctly on stream path changes + * ensure that we only send 'image view on' when needed + * mark the TV as 'in transition standby -> on' after sending + 'image view on', so we don't spam the TV with 'image view on' command + while waiting for it to finish powering up. bugzid: 1603. bugzid: 1609. + bugzid: 1592 + * request the active source before requesting device information in + cec-client, or it'll display incorrect information when called the first + time + * update the value of CCECProcessor::m_bMonitor when registering a client. + SetControlled() wasn't called on exit, so it took 30 seconds until it was + auto-enabled + * silence 'unused' warning properly. closes #86 + * only change the type of the client to 'playback device' instead of + 'recorder' for panasonic if the TV is a panasonic. issue #84 + * always poll the TV if it's marked as not present. issue #83. issue #84 + * only set m_iCurrentButton when the duration isn't known yet. fixes + duplicate key press for vendor remote codes. closes #81 + * delete the right registry key + * send active source message when we received a routing change with a + device that is handled by libCEC as address. issue #89 + * return value wasn't updated in GetLogicalAddresses() + + -- Pulse-Eight Packaging Thu, 15 Nov 2012 02:26:00 +0100 + libcec (2.0.3-1) unstable; urgency=low * changed: diff --git a/Makefile.am b/Makefile.am index 6c69f51..0fd66f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = src/lib src/testclient src/cec-config +SUBDIRS = src/lib src/testclient docs: echo "Updating documentation (if doxygen is present)" diff --git a/configure.ac b/configure.ac index 45d969b..acfe18b 100644 --- a/configure.ac +++ b/configure.ac @@ -332,7 +332,7 @@ if test "x$HAVE_UNAME" = "xyes"; then LIB_INFO="$LIB_INFO on `uname -s` `uname -r` (`uname -m`)" fi -## redefine the LIBS, so cec-client and cec-config aren't linked against things they don't need +## redefine the LIBS, so cec-client isn't linked against things they don't need LIBS_LIBCEC="$LIBS" LIBS="$libs_client" @@ -357,7 +357,7 @@ AC_SUBST([USE_P8_USB]) AC_SUBST([USE_P8_USB_DETECT]) AC_SUBST([USE_RPI_API]) AC_CONFIG_FILES([src/lib/libcec.pc]) -AC_OUTPUT([Makefile src/lib/Makefile src/testclient/Makefile src/cec-config/Makefile]) +AC_OUTPUT([Makefile src/lib/Makefile src/testclient/Makefile]) cat < on' after sending + 'image view on', so we don't spam the TV with 'image view on' command + while waiting for it to finish powering up. bugzid: 1603. bugzid: 1609. + bugzid: 1592 + * request the active source before requesting device information in + cec-client, or it'll display incorrect information when called the first + time + * update the value of CCECProcessor::m_bMonitor when registering a client. + SetControlled() wasn't called on exit, so it took 30 seconds until it was + auto-enabled + * silence 'unused' warning properly. closes #86 + * only change the type of the client to 'playback device' instead of + 'recorder' for panasonic if the TV is a panasonic. issue #84 + * always poll the TV if it's marked as not present. issue #83. issue #84 + * only set m_iCurrentButton when the duration isn't known yet. fixes + duplicate key press for vendor remote codes. closes #81 + * delete the right registry key + * send active source message when we received a routing change with a + device that is handled by libCEC as address. issue #89 + * return value wasn't updated in GetLogicalAddresses() + + -- Pulse-Eight Packaging Thu, 15 Nov 2012 02:26:00 +0100 + libcec (2.0.3-1) unstable; urgency=low * changed: diff --git a/include/cec.h b/include/cec.h index 7d14a47..c68bba8 100644 --- a/include/cec.h +++ b/include/cec.h @@ -36,7 +36,7 @@ #include "cectypes.h" -#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_2_0_3 +#define LIBCEC_VERSION_CURRENT CEC_SERVER_VERSION_CURRENT namespace CEC { diff --git a/include/cectypes.h b/include/cectypes.h index 48d1ab8..dfcebfe 100644 --- a/include/cectypes.h +++ b/include/cectypes.h @@ -1256,7 +1256,8 @@ typedef enum libcec_alert CEC_ALERT_SERVICE_DEVICE, CEC_ALERT_CONNECTION_LOST, CEC_ALERT_PERMISSION_ERROR, - CEC_ALERT_PORT_BUSY + CEC_ALERT_PORT_BUSY, + CEC_ALERT_PHYSICAL_ADDRESS_ERROR } libcec_alert; typedef enum libcec_parameter_type @@ -1377,6 +1378,8 @@ typedef enum cec_client_version CEC_CLIENT_VERSION_2_0_1 = 0x2001, 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; typedef enum cec_server_version @@ -1402,6 +1405,8 @@ typedef enum cec_server_version CEC_SERVER_VERSION_2_0_1 = 0x2001, 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; struct libcec_configuration diff --git a/project/cec-config.rc b/project/cec-config.rc deleted file mode 100644 index def8b1f..0000000 Binary files a/project/cec-config.rc and /dev/null differ diff --git a/project/cec-config.vcxproj b/project/cec-config.vcxproj deleted file mode 100644 index 5fef417..0000000 --- a/project/cec-config.vcxproj +++ /dev/null @@ -1,184 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {00EE7081-9EEE-485C-B7CE-699A7BCA40C1} - Win32Proj - cec-config - cec-config - - - - Application - true - MultiByte - - - Application - true - MultiByte - - - Application - false - MultiByte - - - Application - false - MultiByte - - - - - - - - - - - - - - - - - - - $(SolutionDir)..\build\ - cec-config - - - $(SolutionDir)..\build\ - cec-config.x64 - - - $(SolutionDir)..\build\ - cec-config - - - $(SolutionDir)..\build\ - cec-config.x64 - - - - - - Level4 - Disabled - _USE_32BIT_TIME_T;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions) - true - - - $(SolutiontDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) - - - Console - true - - - - - - - - - Level4 - Disabled - _WIN64;_DEBUG;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions) - true - - - $(SolutiontDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) - - - Console - true - - - - - - - - - Level4 - - - Full - false - true - _USE_32BIT_TIME_T;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions) - true - - - $(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) - Speed - - - Console - false - true - true - - - - - - - Level4 - - - Full - true - _WIN64;_CRT_SECURE_NO_WARNINGS;_WINSOCKAPI_;__STDC_CONSTANT_MACROS;%(PreprocessorDefinitions) - true - - - $(SolutionDir)..\include;$(SolutionDir)..\src;%(AdditionalIncludeDirectories) - Speed - - - Console - false - true - true - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/project/cec-config.vcxproj.filters b/project/cec-config.vcxproj.filters deleted file mode 100644 index 2ee5127..0000000 --- a/project/cec-config.vcxproj.filters +++ /dev/null @@ -1,31 +0,0 @@ - - - - - {cc0a01c1-e1e7-4af8-9656-fa9463140613} - - - {f08c0a80-22d9-4bdd-90de-b9cf5fa88f99} - - - - - exports - - - exports - - - platform - - - - - - platform - - - - - - \ No newline at end of file diff --git a/project/libCEC.nsi b/project/libCEC.nsi index 5860b2e..8f665f2 100644 --- a/project/libCEC.nsi +++ b/project/libCEC.nsi @@ -7,7 +7,7 @@ !include "LogicLib.nsh" !include "x64.nsh" -Name "Pulse-Eight libCEC version 2.0.2" +Name "Pulse-Eight libCEC version 2.0.4" OutFile "..\build\libCEC-installer.exe" XPStyle on @@ -18,8 +18,8 @@ Var StartMenuFolder Var VSRedistSetupError Var VSRedistInstalled -!define MUI_FINISHPAGE_LINK "Visit http://www.pulse-eight.com/ for more information." -!define MUI_FINISHPAGE_LINK_LOCATION "http://www.pulse-eight.com/" +!define MUI_FINISHPAGE_LINK "Visit http://libcec.pulse-eight.com/ for more information." +!define MUI_FINISHPAGE_LINK_LOCATION "http://libcec.pulse-eight.com/" !define MUI_ABORTWARNING !insertmacro MUI_PAGE_WELCOME @@ -42,11 +42,11 @@ Var VSRedistInstalled !insertmacro MUI_LANGUAGE "English" -InstType "USB-CEC driver & libCEC" -InstType "USB-CEC driver only" +InstType "USB-CEC Driver & libCEC" +InstType "USB-CEC Driver Only" InstType "Full installation" -Section "USB-CEC driver" SecDriver +Section "USB-CEC Driver" SecDriver SetShellVarContext current SectionIn RO SectionIn 1 2 3 @@ -55,7 +55,7 @@ Section "USB-CEC driver" SecDriver ReadRegStr $1 HKCU "Software\libCEC" "" ${If} $1 != "" MessageBox MB_OK \ - "A previous libCEC and USB-CEC driver was found. This update requires the old version to be uninstalled. Press OK to uninstall the old version." + "A previous libCEC and USB-CEC Driver was found. This update requires the old version to be uninstalled. Press OK to uninstall the old version." ExecWait '"$1\Uninstall.exe" /S _?=$1' Delete "$1\Uninstall.exe" RMDir "$1" @@ -145,7 +145,7 @@ Section "libCEC" SecLibCec File /r /x *.so "..\include\cec*.*" SectionEnd -Section "CEC debug client" SecCecClient +Section "CEC Debug Client" SecCecClient SetShellVarContext current SectionIn 3 @@ -335,7 +335,7 @@ Section "Uninstall" Delete "$SMPROGRAMS\$StartMenuFolder\Visit Pulse-Eight.url" RMDir "$SMPROGRAMS\$StartMenuFolder" - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter sofware" + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter software" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Pulse-Eight USB-CEC Adapter driver" DeleteRegKey /ifempty HKLM "Software\Pulse-Eight\USB-CEC Adapter software" DeleteRegKey /ifempty HKLM "Software\Pulse-Eight" diff --git a/project/libcec.rc b/project/libcec.rc index c92cadc..2f70b2f 100644 Binary files a/project/libcec.rc and b/project/libcec.rc differ diff --git a/project/libcec.vcxproj b/project/libcec.vcxproj index fca9635..271d0df 100644 --- a/project/libcec.vcxproj +++ b/project/libcec.vcxproj @@ -43,6 +43,7 @@ + @@ -87,6 +88,7 @@ + diff --git a/project/libcec.vcxproj.filters b/project/libcec.vcxproj.filters index e867399..f966a2b 100644 --- a/project/libcec.vcxproj.filters +++ b/project/libcec.vcxproj.filters @@ -128,6 +128,9 @@ implementations + + implementations + @@ -221,6 +224,9 @@ implementations + + implementations + devices diff --git a/project/testclient.rc b/project/testclient.rc index 0da16c6..b2ba0e2 100644 Binary files a/project/testclient.rc and b/project/testclient.rc differ diff --git a/src/CecSharpTester/CecSharpClient.cs b/src/CecSharpTester/CecSharpClient.cs index 63a2e23..d1c6c3e 100644 --- a/src/CecSharpTester/CecSharpClient.cs +++ b/src/CecSharpTester/CecSharpClient.cs @@ -43,7 +43,7 @@ namespace CecSharpClient Config = new LibCECConfiguration(); Config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice; Config.DeviceName = "CEC Tester"; - Config.ClientVersion = CecClientVersion.Version2_0_3; + Config.ClientVersion = CecClientVersion.Version2_0_4; Config.SetCallbacks(this); LogLevel = (int)CecLogLevel.All; diff --git a/src/CecSharpTester/Properties/AssemblyInfo.cs b/src/CecSharpTester/Properties/AssemblyInfo.cs index ad7143f..1270401 100644 --- a/src/CecSharpTester/Properties/AssemblyInfo.cs +++ b/src/CecSharpTester/Properties/AssemblyInfo.cs @@ -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.3.0")] -[assembly: AssemblyFileVersion("2.0.3.0")] +[assembly: AssemblyVersion("2.0.4.0")] +[assembly: AssemblyFileVersion("2.0.4.0")] diff --git a/src/LibCecSharp/AssemblyInfo.cpp b/src/LibCecSharp/AssemblyInfo.cpp index fa6b40b..d5d229f 100644 --- a/src/LibCecSharp/AssemblyInfo.cpp +++ b/src/LibCecSharp/AssemblyInfo.cpp @@ -13,7 +13,7 @@ using namespace System::Security::Permissions; [assembly:AssemblyTrademarkAttribute("")]; [assembly:AssemblyCultureAttribute("")]; -[assembly:AssemblyVersionAttribute("2.0.3.0")]; +[assembly:AssemblyVersionAttribute("2.0.4.0")]; [assembly:ComVisible(false)]; [assembly:CLSCompliantAttribute(true)]; diff --git a/src/LibCecSharp/CecSharpTypes.h b/src/LibCecSharp/CecSharpTypes.h index bf42996..a6fc2d4 100644 --- a/src/LibCecSharp/CecSharpTypes.h +++ b/src/LibCecSharp/CecSharpTypes.h @@ -1175,7 +1175,11 @@ namespace CecSharp /// /// v2.0.3 /// - Version2_0_3 = 0x2003 + Version2_0_3 = 0x2003, + /// + /// v2.0.4 + /// + Version2_0_4 = 0x2004 }; /// @@ -1266,7 +1270,11 @@ namespace CecSharp /// /// v2.0.3 /// - Version2_0_3 = 0x2003 + Version2_0_3 = 0x2003, + /// + /// v2.0.4 + /// + Version2_0_4 = 0x2004 }; /// diff --git a/src/LibCecTray/Properties/AssemblyInfo.cs b/src/LibCecTray/Properties/AssemblyInfo.cs index 8bc2245..bccd9c7 100644 --- a/src/LibCecTray/Properties/AssemblyInfo.cs +++ b/src/LibCecTray/Properties/AssemblyInfo.cs @@ -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.3.0")] -[assembly: AssemblyFileVersion("2.0.3.0")] +[assembly: AssemblyVersion("2.0.4.0")] +[assembly: AssemblyFileVersion("2.0.4.0")] diff --git a/src/LibCecTray/controller/CECController.cs b/src/LibCecTray/controller/CECController.cs index f4dc434..b54ecdd 100644 --- a/src/LibCecTray/controller/CECController.cs +++ b/src/LibCecTray/controller/CECController.cs @@ -438,7 +438,7 @@ namespace LibCECTray.controller { if (_config == null) { - _config = new LibCECConfiguration { DeviceName = "CEC Tray", ClientVersion = CecClientVersion.Version2_0_3 }; + _config = new LibCECConfiguration { DeviceName = "CEC Tray", ClientVersion = CecClientVersion.Version2_0_4 }; _config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice; _config.SetCallbacks(this); diff --git a/src/cec-config/Makefile.am b/src/cec-config/Makefile.am deleted file mode 100644 index da7b89b..0000000 --- a/src/cec-config/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -bin_PROGRAMS = cec-config -cec_config_SOURCES = cec-config.cpp - -cec_config_CPPFLAGS = -I@abs_top_srcdir@/include -cec_config_LDFLAGS = @LIBS@ diff --git a/src/cec-config/cec-config.cpp b/src/cec-config/cec-config.cpp deleted file mode 100644 index a7cae9c..0000000 --- a/src/cec-config/cec-config.cpp +++ /dev/null @@ -1,487 +0,0 @@ -/* - * This file is part of the libCEC(R) library. - * - * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. - * libCEC(R) is an original work, containing original code. - * - * libCEC(R) is a trademark of Pulse-Eight Limited. - * - * This program is dual-licensed; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * - * Alternatively, you can license this library under a commercial license, - * please contact Pulse-Eight Licensing for more information. - * - * For more information contact: - * Pulse-Eight Licensing - * http://www.pulse-eight.com/ - * http://www.pulse-eight.net/ - */ - -#include "../env.h" -#include "../include/cec.h" - -#include -#include -#include -#include -#include -#include -#include -#include "../lib/platform/threads/mutex.h" -#include "../lib/platform/util/timeutils.h" -#include "../lib/implementations/CECCommandHandler.h" -#include "../lib/platform/util/StdString.h" - -using namespace CEC; -using namespace std; -using namespace PLATFORM; - -#include - -CMutex g_outputMutex; - -CEvent g_responseEvent; -cec_opcode g_lastCommand = CEC_OPCODE_NONE; - -CEvent g_keyEvent; -cec_user_control_code g_lastKey = CEC_USER_CONTROL_CODE_UNKNOWN; - -ICECCallbacks g_callbacks; -libcec_configuration g_config; -ICECAdapter * g_parser; - -inline void PrintToStdOut(const char *strFormat, ...) -{ - CStdString strLog; - - va_list argList; - va_start(argList, strFormat); - strLog.FormatV(strFormat, argList); - va_end(argList); - - CLockObject lock(g_outputMutex); - cout << strLog << endl; -} - -//get the first word (separated by whitespace) from string data and place that in word -//then remove that word from string data -bool GetWord(string& data, string& word) -{ - stringstream datastream(data); - string end; - - datastream >> word; - if (datastream.fail()) - { - data.clear(); - return false; - } - - size_t pos = data.find(word) + word.length(); - - if (pos >= data.length()) - { - data.clear(); - return true; - } - - data = data.substr(pos); - - datastream.clear(); - datastream.str(data); - - datastream >> end; - if (datastream.fail()) - data.clear(); - - return true; -} - -int CecLogMessage(void *UNUSED(cbParam), const cec_log_message message) -{ - switch (message.level) - { - case CEC_LOG_ERROR: - PrintToStdOut("ERROR:\t%s", message.message); - break; - case CEC_LOG_WARNING: - PrintToStdOut("ERROR:\t%s", message.message); - break; - default: - break; - } - - return 0; -} - -int CecKeyPress(void *UNUSED(cbParam), const cec_keypress key) -{ - g_lastKey = key.keycode; - g_keyEvent.Signal(); - return 0; -} - -int CecCommand(void *UNUSED(cbParam), const cec_command command) -{ - g_lastCommand = command.opcode; - g_responseEvent.Signal(); - return 0; -} - -bool ProcessConsoleCommand(string &input) -{ - if (!input.empty()) - { - string command; - if (GetWord(input, command)) - { - if (command == "q" || command == "quit") - return false; - } - } - return true; -} - -bool OpenConnection(cec_device_type type = CEC_DEVICE_TYPE_RECORDING_DEVICE) -{ - g_config.Clear(); - snprintf(g_config.strDeviceName, 13, "CEC-config"); - g_config.callbackParam = NULL; - g_config.clientVersion = (uint32_t)CEC_CLIENT_VERSION_2_0_2; - g_callbacks.CBCecLogMessage = &CecLogMessage; - g_callbacks.CBCecKeyPress = &CecKeyPress; - g_callbacks.CBCecCommand = &CecCommand; - g_config.callbacks = &g_callbacks; - - g_config.deviceTypes.Add(type); - - g_parser = LibCecInitialise(&g_config); - if (!g_parser) - return false; - - // init video on targets that need this - g_parser->InitVideoStandalone(); - - CStdString strPort; - cec_adapter devices[10]; - uint8_t iDevicesFound = g_parser->FindAdapters(devices, 10, NULL); - if (iDevicesFound <= 0) - { - PrintToStdOut("autodetect FAILED"); - UnloadLibCec(g_parser); - return false; - } - else - { - strPort = devices[0].comm; - } - - PrintToStdOut("opening a connection to the CEC adapter..."); - if (!g_parser->Open(strPort.c_str())) - { - PrintToStdOut("unable to open the device on port %s", strPort.c_str()); - UnloadLibCec(g_parser); - return false; - } - - g_parser->GetCurrentConfiguration(&g_config); - PrintToStdOut("CEC Parser created - libCEC version %s", g_parser->ToString((cec_server_version)g_config.serverVersion)); - - return true; -} - -int8_t FindPhysicalAddressPortNumber(void) -{ - PrintToStdOut("Enter the HDMI port number to which you connected your CEC adapter, followed by . Valid ports are in the range 1-15. Anything else will cancel this wizard."); - string input; - getline(cin, input); - cin.clear(); - if (input.empty()) - return -1; - - int hdmiport = atoi(input.c_str()); - return (hdmiport < 1 || hdmiport > 15) ? -1 : (int8_t)hdmiport; -} - -cec_logical_address FindPhysicalAddressBaseDevice(void) -{ - PrintToStdOut("Press 1 if your CEC adapter is connected to your TV or\nPress 2 if it's connected to an AVR, followed by . Anything else will cancel this wizard."); - - string input; - getline(cin, input); - cin.clear(); - if (input.empty() || (input != "1" && input != "2")) - { - PrintToStdOut("Exiting..."); - return CECDEVICE_UNKNOWN; - } - return (input == "2") ? - CECDEVICE_AUDIOSYSTEM : - CECDEVICE_TV; -} - -uint16_t FindPhysicalAddress(void) -{ - PrintToStdOut("=== Physical Address Configuration ===\n"); - uint16_t iAddress(CEC_INVALID_PHYSICAL_ADDRESS); - - PrintToStdOut("Do you want to let libCEC try to autodetect the address (y/n)?"); - string input; - getline(cin, input); - cin.clear(); - if (input == "y" || input == "Y") - { - cec_logical_address baseDevice = FindPhysicalAddressBaseDevice(); - if (baseDevice == CECDEVICE_UNKNOWN) - return iAddress; - - int8_t iPortNumber = FindPhysicalAddressPortNumber(); - if (iPortNumber == -1) - return iAddress; - - PrintToStdOut("Trying to detect the physical address..."); - if (!g_parser->SetHDMIPort(baseDevice, iPortNumber)) - PrintToStdOut("Failed. Please enter the address manually, or restart this wizard and use different settings."); - else - { - g_parser->GetCurrentConfiguration(&g_config); - iAddress = g_parser->GetDevicePhysicalAddress(g_config.logicalAddresses.primary); - if (iAddress == 0 || iAddress == CEC_INVALID_PHYSICAL_ADDRESS) - PrintToStdOut("Failed. Please enter the address manually, or restart this wizard and use different settings."); - } - } - - if (iAddress == 0 || iAddress == CEC_INVALID_PHYSICAL_ADDRESS) - { - PrintToStdOut("Please enter the physical address (0001 - FFFE), followed by ."); - getline(cin, input); - cin.clear(); - - int iAddressTmp; - if (sscanf(input.c_str(), "%x", &iAddressTmp) == 1) - { - if (iAddressTmp <= CEC_PHYSICAL_ADDRESS_TV || iAddressTmp > CEC_MAX_PHYSICAL_ADDRESS) - iAddressTmp = CEC_INVALID_PHYSICAL_ADDRESS; - iAddress = (uint16_t)iAddressTmp; - } - } - - if (iAddress != 0) - { - g_parser->SetPhysicalAddress(iAddress); - g_parser->SetActiveSource(g_config.deviceTypes[0]); - } - - return iAddress; -} - -bool PowerOnTV(uint64_t iTimeout = 60000) -{ - cec_power_status currentTvPower(CEC_POWER_STATUS_UNKNOWN); - uint64_t iNow = GetTimeMs(); - uint64_t iTarget = iNow + iTimeout; - - currentTvPower = g_parser->GetDevicePowerStatus(CECDEVICE_TV); - if (currentTvPower != CEC_POWER_STATUS_ON) - { - PrintToStdOut("Sending 'power on' command to the TV\n=== Please wait ==="); - g_parser->PowerOnDevices(CECDEVICE_TV); - while (iTarget > iNow) - { - g_responseEvent.Wait((uint32_t)(iTarget - iNow)); - if (g_lastCommand == CEC_OPCODE_REQUEST_ACTIVE_SOURCE) - break; - iNow = GetTimeMs(); - } - } - - currentTvPower = g_parser->GetDevicePowerStatus(CECDEVICE_TV); - - if (currentTvPower != CEC_POWER_STATUS_ON) - PrintToStdOut("Failed to power on the TV, or the TV does not respond properly"); - - return currentTvPower == CEC_POWER_STATUS_ON; -} - -void sighandler(int iSignal) -{ - PrintToStdOut("signal caught: %d - exiting", iSignal); - - g_parser->Close(); - UnloadLibCec(g_parser); - - exit(1); -} - -int main (int UNUSED(argc), char *UNUSED(argv[])) -{ - if (signal(SIGINT, sighandler) == SIG_ERR) - { - PrintToStdOut("can't register sighandler"); - return -1; - } - - g_callbacks.Clear(); - g_config.Clear(); - PrintToStdOut("=== USB-CEC Adapter Configuration ===\n"); - if (!OpenConnection()) - return 1; - - if (!PowerOnTV()) - return 1; - - bool bAddressOk(false); - while (!bAddressOk) - { - uint16_t iAddress = FindPhysicalAddress(); - - PrintToStdOut("Physical address: %4X", iAddress); - PrintToStdOut("Is this correct (y/n)?"); - string input; - getline(cin, input); - cin.clear(); - bAddressOk = (input == "y" || input == "Y"); - } - - g_parser->GetCurrentConfiguration(&g_config); - - { - cec_menu_language lang; - if (g_parser->GetDeviceMenuLanguage(CECDEVICE_TV, &lang)) - { - PrintToStdOut("TV menu language: %s", lang.language); - PrintToStdOut("Do you want the application to use the menu language of the TV (y/n)?"); - string input; - getline(cin, input); - cin.clear(); - g_config.bUseTVMenuLanguage = (input == "y" || input == "Y") ? 1 : 0; - } - else - { - PrintToStdOut("The TV did not respond properly to the menu language request."); - } - } - - { - PrintToStdOut("Do you want to make the CEC adapter the active source when starting the application (y/n)?"); - string input; - getline(cin, input); - cin.clear(); - g_config.bActivateSource = (input == "y" || input == "Y") ? 1 : 0; - } - - { - PrintToStdOut("Do you want to power on the TV when starting the application (y/n)?"); - string input; - getline(cin, input); - cin.clear(); - if (input == "y" || input == "Y") - g_config.wakeDevices.Set(CECDEVICE_TV); - } - - { - PrintToStdOut("Do you want to power off CEC devices when closing the application (y/n)?"); - string input; - getline(cin, input); - cin.clear(); - if (input == "y" || input == "Y") - g_config.powerOffDevices.Set(CECDEVICE_TV); - } - - { - PrintToStdOut("Do you want to power off CEC devices when the screensaver is activated (y/n)?"); - string input; - getline(cin, input); - cin.clear(); - g_config.bPowerOffScreensaver = (input == "y" || input == "Y") ? 1 : 0; - } - - { - PrintToStdOut("Do you want to put the PC in standby when the TV is put in standby mode (y/n)?"); - string input; - getline(cin, input); - cin.clear(); - g_config.bPowerOffOnStandby = (input == "y" || input == "Y") ? 1 : 0; - } - - { - PrintToStdOut("Do you want to send an inactive source message when stopping the application (y/n)?"); - string input; - getline(cin, input); - cin.clear(); - g_config.bSendInactiveSource = (input == "y" || input == "Y") ? 1 : 0; - } - - PrintToStdOut("\n\n=== USB-CEC Adapter Configuration Summary ==="); - PrintToStdOut("HDMI port number: %d", g_config.iHDMIPort); - PrintToStdOut("Connected to HDMI device: %X", (uint8_t)g_config.baseDevice); - PrintToStdOut("Physical address: %4X", g_config.iPhysicalAddress); - PrintToStdOut("Use the TV's language setting: %s", g_config.bUseTVMenuLanguage ? "yes" : "no"); - PrintToStdOut("Make the adapter the active source when starting XBMC: %s", g_config.bActivateSource ? "yes" : "no"); - PrintToStdOut("Power on the TV when starting XBMC: %s", g_config.wakeDevices.IsSet(CECDEVICE_BROADCAST) ? "yes" : "no"); - PrintToStdOut("Power off devices when stopping XBMC: %s", g_config.powerOffDevices.IsSet(CECDEVICE_BROADCAST) ? "yes" : "no"); - PrintToStdOut("Put devices in standby mode when activating screensaver: %s", g_config.bPowerOffScreensaver ? "yes" : "no"); - PrintToStdOut("Put this PC in standby mode when the TV is switched off: %s", g_config.bPowerOffOnStandby ? "yes" : "no"); - PrintToStdOut("Send an inactive source message when stopping XBMC: %s\n\n", g_config.bSendInactiveSource ? "yes" : "no"); - - PrintToStdOut("Storing settings ..."); - if (g_parser->PersistConfiguration(&g_config)) - PrintToStdOut("Settings stored."); - else - PrintToStdOut("The settings could not be stored"); - - ofstream configOutput; - configOutput.open("usb_2548_1001.xml"); - if (configOutput.is_open()) - { - CStdString strWakeDevices; - for (uint8_t iPtr = 0; iPtr < 16; iPtr++) - if (g_config.wakeDevices[iPtr]) - strWakeDevices.AppendFormat(" %d", iPtr); - CStdString strStandbyDevices; - for (uint8_t iPtr = 0; iPtr < 16; iPtr++) - if (g_config.powerOffDevices[iPtr]) - strStandbyDevices.AppendFormat(" %d", iPtr); - - configOutput << - "\n" << - "\t\n" << - "\t\n" << - "\t\n" << - "\t\n" << - "\t\n" << - "\t\n" << - "\t\n" << - "\t\n" << - "\t\n" << - "\t\n" << - "\t\n" << - "\t\n" << - ""; - configOutput.close(); - - PrintToStdOut("The configuration has been stored in 'usb_2548_1001.xml'. Copy this file to ~/.userdata/peripheral_data to use it in XBMC"); - } - - g_parser->StandbyDevices(); - g_parser->Close(); - UnloadLibCec(g_parser); - - PrintToStdOut("Press enter to close this wizard."); - string input; - getline(cin, input); - return 0; -} diff --git a/src/lib/CECClient.cpp b/src/lib/CECClient.cpp index 004d741..9d814cd 100644 --- a/src/lib/CECClient.cpp +++ b/src/lib/CECClient.cpp @@ -208,7 +208,7 @@ bool CCECClient::SetHDMIPort(const cec_logical_address iBaseDevice, const uint8_ void CCECClient::ResetPhysicalAddress(void) { - SetPhysicalAddress(m_configuration); + SetPhysicalAddress(CEC_DEFAULT_PHYSICAL_ADDRESS); } void CCECClient::SetPhysicalAddress(const libcec_configuration &configuration) @@ -964,8 +964,11 @@ void CCECClient::AddKey(const cec_keypress &key) AddKey(true); } - m_iCurrentButton = transmitKey.keycode; - m_buttontime = m_iCurrentButton == CEC_USER_CONTROL_CODE_UNKNOWN || key.duration > 0 ? 0 : GetTimeMs(); + 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) diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index 73c921d..e432033 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -260,6 +260,12 @@ bool CCECProcessor::ActivateSource(uint16_t iStreamPath) return bReturn; } +void CCECProcessor::SetActiveSource(bool bSetTo, bool bClientUnregistered) +{ + if (m_communication) + m_communication->SetActiveSource(bSetTo, bClientUnregistered); +} + void CCECProcessor::SetStandardLineTimeout(uint8_t iTimeout) { CLockObject lock(m_mutex); @@ -737,6 +743,7 @@ bool CCECProcessor::RegisterClient(CCECClient *client) // ensure that controlled mode is enabled m_communication->SetControlledMode(true); + m_bMonitor = false; // source logical address for requests cec_logical_address sourceAddress(CECDEVICE_UNREGISTERED); @@ -863,7 +870,7 @@ bool CCECProcessor::UnregisterClient(CCECClient *client) m_clients.erase(entry); // reset the device status - (*it)->ResetDeviceStatus(); + (*it)->ResetDeviceStatus(true); } } diff --git a/src/lib/CECProcessor.h b/src/lib/CECProcessor.h index 5593a2c..69586a7 100644 --- a/src/lib/CECProcessor.h +++ b/src/lib/CECProcessor.h @@ -110,6 +110,7 @@ namespace CEC bool SetDeckInfo(cec_deck_info info, bool bSendUpdate = true); bool ActivateSource(uint16_t iStreamPath); + void SetActiveSource(bool bSetTo, bool bClientUnregistered); bool PollDevice(cec_logical_address iAddress); void SetStandardLineTimeout(uint8_t iTimeout); uint8_t GetStandardLineTimeout(void); diff --git a/src/lib/CECTypeUtils.h b/src/lib/CECTypeUtils.h index ee3ddb3..7699b89 100644 --- a/src/lib/CECTypeUtils.h +++ b/src/lib/CECTypeUtils.h @@ -563,6 +563,8 @@ namespace CEC return "2.0.2"; case CEC_CLIENT_VERSION_2_0_3: return "2.0.3"; + case CEC_CLIENT_VERSION_2_0_4: + return "2.0.4"; default: return "Unknown"; } @@ -614,6 +616,8 @@ namespace CEC return "2.0.2"; case CEC_SERVER_VERSION_2_0_3: return "2.0.3"; + case CEC_SERVER_VERSION_2_0_4: + return "2.0.4"; default: return "Unknown"; } diff --git a/src/lib/LibCEC.cpp b/src/lib/LibCEC.cpp index 904204a..2cb5b2f 100644 --- a/src/lib/LibCEC.cpp +++ b/src/lib/LibCEC.cpp @@ -328,7 +328,7 @@ cec_logical_addresses CLibCEC::GetLogicalAddresses(void) cec_logical_addresses addresses; addresses.Clear(); if (m_client) - m_client->GetLogicalAddresses(); + addresses = m_client->GetLogicalAddresses(); return addresses; } diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index ab00f1b..35166f2 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -25,7 +25,8 @@ libcec_la_SOURCES = CECProcessor.cpp \ implementations/CECCommandHandler.cpp \ implementations/SLCommandHandler.cpp \ implementations/VLCommandHandler.cpp \ - implementations/RLCommandHandler.cpp + implementations/RLCommandHandler.cpp \ + implementations/PHCommandHandler.cpp ## server sockets, currently unused ##libcec_la_SOURCES += platform/posix/serversocket.cpp diff --git a/src/lib/adapter/AdapterCommunication.h b/src/lib/adapter/AdapterCommunication.h index 7dd56b7..b1762b7 100644 --- a/src/lib/adapter/AdapterCommunication.h +++ b/src/lib/adapter/AdapterCommunication.h @@ -221,6 +221,13 @@ namespace CEC */ virtual uint16_t GetAdapterProductId(void) const = 0; + /*! + * @brief Marks the adapter as active or inactive source + * @param bSetTo True to mark as active source, false to mark as inactive source + * @param bClientUnregistered True when the client was unregistered, false when the device was explicitly marked as (in)active source + */ + virtual void SetActiveSource(bool bSetTo, bool bClientUnregistered) = 0; + IAdapterCommunicationCallback *m_callback; }; }; diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp index 9448068..b037e1c 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.cpp @@ -592,6 +592,19 @@ bool CUSBCECAdapterCommands::SetAckMask(uint16_t iMask) return bReturn; } +void CUSBCECAdapterCommands::SetActiveSource(bool bSetTo, bool bClientUnregistered) +{ + if (bClientUnregistered) return; + if (m_persistedConfiguration.iFirmwareVersion >= 3) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking the adapter as %s source", bSetTo ? "active" : "inactive"); + CCECAdapterMessage params; + params.PushEscaped(bSetTo ? 1 : 0); + CCECAdapterMessage *message = m_comm->SendCommand(MSGCODE_SET_ACTIVE_SOURCE, params); + delete message; + } +} + bool CUSBCECAdapterCommands::StartBootloader(void) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "starting the bootloader"); diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h index fa7f543..e0bfb1f 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommands.h @@ -131,6 +131,8 @@ namespace CEC */ bool WriteEEPROM(void); + void SetActiveSource(bool bSetTo, bool bClientUnregistered); + private: /*! * @brief Reads all settings from the eeprom. diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp index 9c6743f..0024d11 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.cpp @@ -54,10 +54,10 @@ using namespace PLATFORM; #define CEC_ADAPTER_EEPROM_WRITE_INTERVAL 30000 #define CEC_ADAPTER_EEPROM_WRITE_RETRY 5000 -// firmware version 2 -#define CEC_LATEST_ADAPTER_FW_VERSION 2 -// firmware date Thu Aug 2 08:31:24 UTC 2012 -#define CEC_LATEST_ADAPTER_FW_DATE 0x501a4b0c +// firmware version 3 +#define CEC_LATEST_ADAPTER_FW_VERSION 3 +// firmware date Thu Nov 15 11:09:45 2012 +#define CEC_LATEST_ADAPTER_FW_DATE 0x50a4cd79 #define CEC_FW_DATE_EXTENDED_RESPONSE 0x501a4b0c #define CEC_FW_DATE_DESCRIPTOR2 0x5045dbf5 @@ -628,6 +628,12 @@ uint16_t CUSBCECAdapterCommunication::GetAdapterProductId(void) const return iBuildDate >= CEC_FW_DATE_DESCRIPTOR2 ? CEC_PID2 : CEC_PID; } +void CUSBCECAdapterCommunication::SetActiveSource(bool bSetTo, bool bClientUnregistered) +{ + if (m_commands) + m_commands->SetActiveSource(bSetTo, bClientUnregistered); +} + bool CUSBCECAdapterCommunication::IsRunningLatestFirmware(void) { return GetFirmwareBuildDate() >= CEC_LATEST_ADAPTER_FW_DATE && diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h index 04199e2..0c473ea 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterCommunication.h @@ -90,6 +90,7 @@ namespace CEC cec_adapter_type GetAdapterType(void); uint16_t GetAdapterVendorId(void) const; uint16_t GetAdapterProductId(void) const; + void SetActiveSource(bool bSetTo, bool bClientUnregistered); ///} bool ProvidesExtendedResponse(void); diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp index da101e7..433a3d3 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterDetection.cpp @@ -438,8 +438,8 @@ uint8_t CUSBCECAdapterDetection::FindAdapters(cec_adapter *deviceList, uint8_t i } #else //silence "unused" warnings - void *tmp = (void*)deviceList; - tmp = (void *)strDevicePath; + ((void)deviceList); + ((void) strDevicePath); #endif iBufSize = 0; if(!iBufSize){} /* silence "unused" warning on linux/osx */ diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h index 89005e8..ec45bb9 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessage.h @@ -78,6 +78,8 @@ namespace CEC MSGCODE_SET_OSD_NAME, MSGCODE_WRITE_EEPROM, MSGCODE_GET_ADAPTER_TYPE, + MSGCODE_SET_ACTIVE_SOURCE, + MSGCODE_FRAME_EOM = 0x80, MSGCODE_FRAME_ACK = 0x40, } cec_adapter_messagecode; diff --git a/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.cpp b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.cpp index 9fca017..4e4c2cb 100644 --- a/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.cpp +++ b/src/lib/adapter/Pulse-Eight/USBCECAdapterMessageQueue.cpp @@ -164,7 +164,8 @@ bool CCECAdapterMessageQueueEntry::IsResponse(const CCECAdapterMessage &msg) thisMsgCode == MSGCODE_SET_HDMI_VERSION || thisMsgCode == MSGCODE_SET_OSD_NAME || thisMsgCode == MSGCODE_WRITE_EEPROM || - thisMsgCode == MSGCODE_TRANSMIT_IDLETIME) + thisMsgCode == MSGCODE_TRANSMIT_IDLETIME || + thisMsgCode == MSGCODE_SET_ACTIVE_SOURCE) return thisMsgCode == msgResponse; if (!m_message->IsTranmission()) diff --git a/src/lib/adapter/RPi/RPiCECAdapterCommunication.h b/src/lib/adapter/RPi/RPiCECAdapterCommunication.h index 3cbbdde..92b7157 100644 --- a/src/lib/adapter/RPi/RPiCECAdapterCommunication.h +++ b/src/lib/adapter/RPi/RPiCECAdapterCommunication.h @@ -85,6 +85,7 @@ namespace CEC cec_adapter_type GetAdapterType(void) { return ADAPTERTYPE_RPI; }; uint16_t GetAdapterVendorId(void) const { return RPI_ADAPTER_VID; } uint16_t GetAdapterProductId(void) const { return RPI_ADAPTER_PID; } + void SetActiveSource(bool UNUSED(bSetTo), bool UNUSED(bClientUnregistered)) {} ///} bool IsInitialised(void); diff --git a/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.h b/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.h index 9476383..2adc1f8 100644 --- a/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.h +++ b/src/lib/adapter/TDA995x/TDA995xCECAdapterCommunication.h @@ -89,6 +89,7 @@ namespace CEC uint16_t GetAdapterVendorId(void) const { return TDA995X_ADAPTER_VID; } uint16_t GetAdapterProductId(void) const { return TDA995X_ADAPTER_PID; } void HandleLogicalAddressLost(cec_logical_address oldAddress); + void SetActiveSource(bool UNUSED(bSetTo), bool UNUSED(bClientUnregistered)) {} ///} /** @name PLATFORM::CThread implementation */ diff --git a/src/lib/devices/CECBusDevice.cpp b/src/lib/devices/CECBusDevice.cpp index 5fe6d4d..7733cfb 100644 --- a/src/lib/devices/CECBusDevice.cpp +++ b/src/lib/devices/CECBusDevice.cpp @@ -39,6 +39,7 @@ #include "lib/implementations/CECCommandHandler.h" #include "lib/implementations/SLCommandHandler.h" #include "lib/implementations/VLCommandHandler.h" +#include "lib/implementations/PHCommandHandler.h" #include "lib/LibCEC.h" #include "lib/CECTypeUtils.h" #include "lib/platform/util/timeutils.h" @@ -75,7 +76,8 @@ CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogi m_iHandlerUseCount (0), m_bAwaitingReceiveFailed(false), m_bVendorIdRequested (false), - m_waitForResponse (new CWaitForResponse) + m_waitForResponse (new CWaitForResponse), + m_bImageViewOnSent (false) { m_handler = new CCECCommandHandler(this); @@ -131,6 +133,9 @@ bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */) case CEC_VENDOR_PANASONIC: m_handler = new CVLCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending); break; + case CEC_VENDOR_PHILIPS: + m_handler = new CPHCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending); + break; default: m_handler = new CCECCommandHandler(this, iTransmitTimeout, iTransmitWait, iTransmitRetries, iActiveSourcePending); break; @@ -181,7 +186,7 @@ bool CCECBusDevice::HandleCommand(const cec_command &command) bHandled = m_handler->HandleCommand(command); /* change status to present */ - if (bHandled && GetLogicalAddress() != CECDEVICE_BROADCAST) + if (bHandled && GetLogicalAddress() != CECDEVICE_BROADCAST && command.opcode_set == 1) { CLockObject lock(m_mutex); if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC) @@ -386,12 +391,13 @@ bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destinatio language = m_menuLanguage; } - char lang[3]; + char lang[4]; { CLockObject lock(m_mutex); lang[0] = language.language[0]; lang[1] = language.language[1]; lang[2] = language.language[2]; + lang[3] = (char)0; } MarkBusy(); @@ -610,6 +616,25 @@ void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus) } } +void CCECBusDevice::OnImageViewOnSent(bool bSentByLibCEC) +{ + CLockObject lock(m_mutex); + m_bImageViewOnSent = bSentByLibCEC; + + if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON) + { + m_iLastPowerStateUpdate = GetTimeMs(); + LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)); + m_powerStatus = CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON; + } +} + +bool CCECBusDevice::ImageViewOnSent(void) +{ + CLockObject lock(m_mutex); + return m_bImageViewOnSent; +} + bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */) { bool bReturn(false); @@ -619,6 +644,8 @@ bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool { MarkBusy(); bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bWaitForResponse); + if (!bReturn) + SetPowerStatus(CEC_POWER_STATUS_UNKNOWN); MarkReady(); } return bReturn; @@ -722,7 +749,7 @@ bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool else { LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString((cec_vendor_id)iVendorId), iVendorId); - bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId, bIsReply); + bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, destination, iVendorId, bIsReply); } MarkReady(); return bReturn; @@ -740,8 +767,13 @@ cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bo CLockObject lock(m_mutex); status = m_deviceStatus; bNeedsPoll = !bSuppressPoll && - (bForcePoll || m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN) && - m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC; + m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC && + // poll forced + (bForcePoll || + // don't know the status + m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN || + // always poll the TV if it's marked as not present + (m_deviceStatus == CEC_DEVICE_STATUS_NOT_PRESENT && m_iLogicalAddress == CECDEVICE_TV)); } if (bNeedsPoll) @@ -788,7 +820,7 @@ void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus, cec_v if (m_deviceStatus != newStatus) { LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'not present'", GetLogicalAddressName(), m_iLogicalAddress); - ResetDeviceStatus(); + ResetDeviceStatus(true); m_deviceStatus = newStatus; } break; @@ -799,7 +831,7 @@ void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus, cec_v } } -void CCECBusDevice::ResetDeviceStatus(void) +void CCECBusDevice::ResetDeviceStatus(bool bClientUnregistered /* = false */) { CLockObject lock(m_mutex); SetPowerStatus (CEC_POWER_STATUS_UNKNOWN); @@ -808,7 +840,7 @@ void CCECBusDevice::ResetDeviceStatus(void) SetCecVersion (CEC_VERSION_UNKNOWN); SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS); SetOSDName (ToString(m_iLogicalAddress)); - MarkAsInactiveSource(); + MarkAsInactiveSource(bClientUnregistered); m_iLastActive = 0; m_bVendorIdRequested = false; @@ -952,6 +984,10 @@ void CCECBusDevice::MarkAsActiveSource(void) m_bActiveSource = true; } + CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV); + if (tv) + tv->OnImageViewOnSent(false); + // mark other devices as inactive sources CECDEVICEVEC devices; m_processor->GetDevices()->Get(devices); @@ -961,13 +997,15 @@ void CCECBusDevice::MarkAsActiveSource(void) if (bWasActivated) { + if (IsHandledByLibCEC()) + m_processor->SetActiveSource(true, false); CCECClient *client = GetClient(); if (client) client->SourceActivated(m_iLogicalAddress); } } -void CCECBusDevice::MarkAsInactiveSource(void) +void CCECBusDevice::MarkAsInactiveSource(bool bClientUnregistered /* = false */) { bool bWasDeactivated(false); { @@ -982,6 +1020,8 @@ void CCECBusDevice::MarkAsInactiveSource(void) if (bWasDeactivated) { + if (IsHandledByLibCEC()) + m_processor->SetActiveSource(false, bClientUnregistered); CCECClient *client = GetClient(); if (client) client->SourceDeactivated(m_iLogicalAddress); @@ -1036,10 +1076,27 @@ bool CCECBusDevice::TransmitImageViewOn(void) } } + CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV); + if (!tv) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - couldn't get TV instance", __FUNCTION__); + return false; + } + + if (tv->ImageViewOnSent()) + { + LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - 'image view on' already sent", __FUNCTION__); + return true; + } + bool bImageViewOnSent(false); MarkBusy(); bImageViewOnSent = m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV); MarkReady(); + + if (bImageViewOnSent) + tv->OnImageViewOnSent(true); + return bImageViewOnSent; } @@ -1068,26 +1125,36 @@ bool CCECBusDevice::TransmitPendingActiveSourceCommands(void) void CCECBusDevice::SetActiveRoute(uint16_t iRoute) { + SetPowerStatus(CEC_POWER_STATUS_ON); + CCECDeviceMap* map = m_processor->GetDevices(); if (!map) return; - CCECBusDevice* previouslyActive = map->GetActiveSource(); - if (!previouslyActive) + 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 (!CCECTypeUtils::PhysicalAddressIsIncluded(iRoute, (*it)->GetCurrentPhysicalAddress())) + if ((*it)->GetCurrentPhysicalAddress() == iRoute && (*it)->IsHandledByLibCEC()) + (*it)->ActivateSource(); + else if (!CCECTypeUtils::PhysicalAddressIsIncluded(iRoute, (*it)->GetCurrentPhysicalAddress())) (*it)->MarkAsInactiveSource(); } } void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) { + if (iNewAddress != CEC_INVALID_PHYSICAL_ADDRESS) + SetPowerStatus(CEC_POWER_STATUS_ON); + CLockObject lock(m_mutex); if (iNewAddress != m_iStreamPath) { diff --git a/src/lib/devices/CECBusDevice.h b/src/lib/devices/CECBusDevice.h index 6cba39f..d04b559 100644 --- a/src/lib/devices/CECBusDevice.h +++ b/src/lib/devices/CECBusDevice.h @@ -192,6 +192,8 @@ namespace CEC virtual cec_power_status GetCurrentPowerStatus(void); virtual cec_power_status GetPowerStatus(const cec_logical_address initiator, bool bUpdate = false); virtual void SetPowerStatus(const cec_power_status powerStatus); + virtual void OnImageViewOnSent(bool bSentByLibCEC); + virtual bool ImageViewOnSent(void); virtual bool RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse = true); virtual bool TransmitPowerState(const cec_logical_address destination, bool bIsReply); @@ -205,7 +207,7 @@ namespace CEC virtual cec_bus_device_status GetCurrentStatus(void) { return GetStatus(false, true); } virtual cec_bus_device_status GetStatus(bool bForcePoll = false, bool bSuppressPoll = false); virtual void SetDeviceStatus(const cec_bus_device_status newStatus, cec_version libCECSpecVersion = CEC_VERSION_1_4); - virtual void ResetDeviceStatus(void); + virtual void ResetDeviceStatus(bool bClientUnregistered = false); virtual bool TransmitPoll(const cec_logical_address destination, bool bUpdateDeviceStatus); virtual void HandlePoll(const cec_logical_address destination); virtual void HandlePollFrom(const cec_logical_address initiator); @@ -219,7 +221,7 @@ namespace CEC virtual bool IsActiveSource(void) const { return m_bActiveSource; } virtual bool RequestActiveSource(bool bWaitForResponse = true); virtual void MarkAsActiveSource(void); - virtual void MarkAsInactiveSource(void); + virtual void MarkAsInactiveSource(bool bClientUnregistered = false); virtual bool TransmitActiveSource(bool bIsReply); virtual bool TransmitImageViewOn(void); virtual bool TransmitInactiveSource(void); @@ -279,5 +281,6 @@ namespace CEC bool m_bAwaitingReceiveFailed; bool m_bVendorIdRequested; CWaitForResponse *m_waitForResponse; + bool m_bImageViewOnSent; }; }; diff --git a/src/lib/devices/CECDeviceMap.cpp b/src/lib/devices/CECDeviceMap.cpp index 23e7a6f..b7f3ab2 100644 --- a/src/lib/devices/CECDeviceMap.cpp +++ b/src/lib/devices/CECDeviceMap.cpp @@ -283,3 +283,9 @@ void CCECDeviceMap::GetChildrenOf(CECDEVICEVEC& devices, CCECBusDevice* device) devices.push_back(it->second); } } + +void CCECDeviceMap::SignalAll(cec_opcode opcode) +{ + for (CECDEVICEMAP::iterator it = m_busDevices.begin(); it != m_busDevices.end(); it++) + it->second->SignalOpcode(opcode); +} diff --git a/src/lib/devices/CECDeviceMap.h b/src/lib/devices/CECDeviceMap.h index c27a2dd..6037fa3 100644 --- a/src/lib/devices/CECDeviceMap.h +++ b/src/lib/devices/CECDeviceMap.h @@ -63,6 +63,7 @@ namespace CEC void GetActive(CECDEVICEVEC &devices) const; void GetByType(const cec_device_type type, CECDEVICEVEC &devices) const; void GetChildrenOf(CECDEVICEVEC& devices, CCECBusDevice* device) const; + void SignalAll(cec_opcode opcode); void GetPowerOffDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const; void GetWakeDevices(const libcec_configuration &configuration, CECDEVICEVEC &devices) const; diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index 3b0187a..e4a7995 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -209,12 +209,15 @@ 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); + CCECBusDevice *device = m_processor->GetDevice(command.initiator); if (device) { + device->SetPhysicalAddress(iAddress); device->MarkAsActiveSource(); - return COMMAND_HANDLED; } + + m_processor->GetDevices()->SignalAll(command.opcode); + return COMMAND_HANDLED; } return CEC_ABORT_REASON_INVALID_OPERAND; @@ -384,12 +387,14 @@ int CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &comma int CCECCommandHandler::HandleImageViewOn(const cec_command &command) { CCECBusDevice *device = GetDevice(command.destination); - if (device && (device->GetCurrentStatus() == CEC_DEVICE_STATUS_PRESENT || - device->GetCurrentStatus() == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)) + if (device && device->GetCurrentStatus() == CEC_DEVICE_STATUS_PRESENT) { if (device->GetCurrentPowerStatus() == CEC_POWER_STATUS_STANDBY || device->GetCurrentPowerStatus() == CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY) device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); + CCECBusDevice* tv = GetDevice(CECDEVICE_TV); + if (tv) + tv->OnImageViewOnSent(false); } return COMMAND_HANDLED; } @@ -570,11 +575,21 @@ int CCECCommandHandler::HandleSetStreamPath(const cec_command &command) /* one of the device handled by libCEC has been made active */ CCECBusDevice *device = GetDeviceByPhysicalAddress(iStreamAddress); - if (device && device->IsHandledByLibCEC()) + if (device) { - device->ActivateSource(); + if (device->IsHandledByLibCEC()) + device->ActivateSource(); + else + device->MarkAsActiveSource(); return COMMAND_HANDLED; } + else + { + cec_logical_address previousSource = m_processor->GetActiveSource(false); + CCECBusDevice* device = m_processor->GetDevice(previousSource); + if (device && device->GetCurrentPhysicalAddress() != iStreamAddress) + device->MarkAsInactiveSource(); + } } return CEC_ABORT_REASON_INVALID_OPERAND; @@ -702,7 +717,7 @@ int CCECCommandHandler::HandleUserControlPressed(const cec_command &command) { // we're not marked as active source, but the tv sends keypresses to us, so assume it forgot to activate us if (!device->IsActiveSource() && command.initiator == CECDEVICE_TV) - device->ActivateSource(); + device->MarkAsActiveSource(); } return COMMAND_HANDLED; @@ -801,13 +816,17 @@ void CCECCommandHandler::SetPhysicalAddress(cec_logical_address iAddress, uint16 if (device) device->SetPhysicalAddress(iNewAddress); else - { LIB_CEC->AddLog(CEC_LOG_DEBUG, "device with logical address %X not found", iAddress); - } /* another device reported the same physical address as ours */ if (client) + { + libcec_parameter param; + param.paramType = CEC_PARAMETER_TYPE_STRING; + param.paramData = (void*)"Physical address in use by another device. Please verify your settings"; + client->Alert(CEC_ALERT_PHYSICAL_ADDRESS_ERROR, param); client->ResetPhysicalAddress(); + } } else { @@ -987,7 +1006,7 @@ bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInit return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[3], bool bIsReply) +bool CCECCommandHandler::TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[4], bool bIsReply) { cec_command command; command.Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_SET_MENU_LANGUAGE); @@ -1015,7 +1034,7 @@ bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId, bool bIsReply) +bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address UNUSED(iDestination), uint64_t iVendorId, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_DEVICE_VENDOR_ID); @@ -1180,10 +1199,7 @@ bool CCECCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = f bool bTvPresent = (tv && tv->GetStatus() == CEC_DEVICE_STATUS_PRESENT); bool bActiveSourceFailed(false); if (bTvPresent) - { - if (tv->GetCurrentPowerStatus() != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON) - bActiveSourceFailed = !m_busDevice->TransmitImageViewOn(); - } + bActiveSourceFailed = !m_busDevice->TransmitImageViewOn(); else LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV not present, not sending 'image view on'"); diff --git a/src/lib/implementations/CECCommandHandler.h b/src/lib/implementations/CECCommandHandler.h index b09f9b3..c8430ec 100644 --- a/src/lib/implementations/CECCommandHandler.h +++ b/src/lib/implementations/CECCommandHandler.h @@ -57,7 +57,7 @@ namespace CEC virtual bool HandleCommand(const cec_command &command); virtual cec_vendor_id GetVendorId(void) { return m_vendorId; }; virtual void SetVendorId(cec_vendor_id vendorId) { m_vendorId = vendorId; } - static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC;} + static bool HasSpecificHandler(cec_vendor_id vendorId) { return vendorId == CEC_VENDOR_LG || vendorId == CEC_VENDOR_SAMSUNG || vendorId == CEC_VENDOR_PANASONIC || vendorId == CEC_VENDOR_PHILIPS;} virtual bool InitHandler(void) { return true; } virtual bool ActivateSource(bool bTransmitDelayedCommandsOnly = false); @@ -80,10 +80,10 @@ namespace CEC virtual bool TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, std::string strDeviceName, bool bIsReply); virtual bool TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage, bool bIsReply); virtual bool TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type, bool bIsReply); - virtual bool TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[3], bool bIsReply); + virtual bool TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[4], bool bIsReply); virtual bool TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bIsReply); virtual bool TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state, bool bIsReply); - virtual bool TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId, bool bIsReply); + virtual bool TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint64_t iVendorId, bool bIsReply); virtual bool TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state, bool bIsReply); virtual bool TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply); virtual bool TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply); diff --git a/src/lib/implementations/PHCommandHandler.cpp b/src/lib/implementations/PHCommandHandler.cpp new file mode 100644 index 0000000..b46f69e --- /dev/null +++ b/src/lib/implementations/PHCommandHandler.cpp @@ -0,0 +1,159 @@ +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "env.h" +#include "PHCommandHandler.h" + +#include "lib/devices/CECBusDevice.h" +#include "lib/CECProcessor.h" +#include "lib/LibCEC.h" +#include "lib/CECClient.h" + +using namespace CEC; +using namespace PLATFORM; + +#define LIB_CEC m_busDevice->GetProcessor()->GetLib() +#define ToString(p) LIB_CEC->ToString(p) + +#define TV_ON_CHECK_TIME_MS 5000 + +CImageViewOnCheck::~CImageViewOnCheck(void) +{ + StopThread(-1); + m_event.Broadcast(); + StopThread(); +} + +void* CImageViewOnCheck::Process(void) +{ + CCECBusDevice* tv = m_handler->m_processor->GetDevice(CECDEVICE_TV); + cec_power_status status(CEC_POWER_STATUS_UNKNOWN); + while (status != CEC_POWER_STATUS_ON) + { + m_event.Wait(TV_ON_CHECK_TIME_MS); + if (!IsRunning()) + return NULL; + + status = tv->GetPowerStatus(m_handler->m_busDevice->GetLogicalAddress()); + + if (status != CEC_POWER_STATUS_ON && + status != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON) + { + CLockObject lock(m_handler->m_mutex); + tv->OnImageViewOnSent(false); + m_handler->m_iActiveSourcePending = GetTimeMs(); + } + } + return NULL; +} + +CPHCommandHandler::CPHCommandHandler(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_iLastKeyCode(CEC_USER_CONTROL_CODE_UNKNOWN) +{ + m_imageViewOnCheck = new CImageViewOnCheck(this); + m_vendorId = CEC_VENDOR_PHILIPS; +} + +CPHCommandHandler::~CPHCommandHandler(void) +{ + delete m_imageViewOnCheck; +} + +bool CPHCommandHandler::InitHandler(void) +{ + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); + if (primary && primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED) + { + //XXX hack to use this handler for the primary device + if (m_busDevice->GetLogicalAddress() == CECDEVICE_TV && + primary && m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) + { + primary->SetVendorId(CEC_VENDOR_PHILIPS); + primary->ReplaceHandler(false); + } + } + + return CCECCommandHandler::InitHandler(); +} + +bool CPHCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = false */) +{ + + CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV); + if (m_busDevice->IsActiveSource() && + m_busDevice->IsHandledByLibCEC() && + tv && tv->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON && + !bTransmitDelayedCommandsOnly) + { + // tv sometimes ignores image view on. check the power status of the tv in 5 seconds, and retry when it failed to power up + if (m_imageViewOnCheck && !m_imageViewOnCheck->IsRunning()) + m_imageViewOnCheck->CreateThread(false); + } + + return CCECCommandHandler::ActivateSource(bTransmitDelayedCommandsOnly); +} + +int CPHCommandHandler::HandleUserControlPressed(const cec_command& command) +{ + // TV sometimes keeps sending key presses without releases + if (m_iLastKeyCode == command.parameters[0]) + return COMMAND_HANDLED; + + m_iLastKeyCode = command.parameters[0]; + + return CCECCommandHandler::HandleUserControlPressed(command); +} + +int CPHCommandHandler::HandleUserControlRelease(const cec_command& command) +{ + m_iLastKeyCode = CEC_USER_CONTROL_CODE_UNKNOWN; + + return CCECCommandHandler::HandleUserControlRelease(command); +} + +int CPHCommandHandler::HandleDeviceVendorId(const cec_command& command) +{ + m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON); + return CCECCommandHandler::HandleDeviceVendorId(command); +} + +bool CPHCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint64_t UNUSED(iVendorId), bool UNUSED(bIsReply)) +{ + LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) -> %s (%X): vendor id feature abort", ToString(iInitiator), iInitiator, ToString(iDestination), iDestination); + m_processor->TransmitAbort(iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); + return true; +} diff --git a/src/lib/implementations/PHCommandHandler.h b/src/lib/implementations/PHCommandHandler.h new file mode 100644 index 0000000..d1788c0 --- /dev/null +++ b/src/lib/implementations/PHCommandHandler.h @@ -0,0 +1,77 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "CECCommandHandler.h" +#include "lib/platform/threads/threads.h" + +namespace CEC +{ + class CPHCommandHandler; + + class CImageViewOnCheck : public PLATFORM::CThread + { + public: + CImageViewOnCheck(CPHCommandHandler* handler): + m_handler(handler) {} + virtual ~CImageViewOnCheck(void); + + void* Process(void); + + private: + CPHCommandHandler* m_handler; + PLATFORM::CEvent m_event; + }; + + class CPHCommandHandler : public CCECCommandHandler + { + friend class CImageViewOnCheck; + public: + CPHCommandHandler(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 ~CPHCommandHandler(void); + + bool InitHandler(void); + + protected: + virtual bool ActivateSource(bool bTransmitDelayedCommandsOnly = false); + virtual int HandleUserControlPressed(const cec_command& command); + virtual int HandleUserControlRelease(const cec_command& command); + virtual bool TransmitVendorID(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint64_t iVendorId, bool bIsReply); + virtual int HandleDeviceVendorId(const cec_command& command); + uint8_t m_iLastKeyCode; + CImageViewOnCheck* m_imageViewOnCheck; + }; +}; diff --git a/src/lib/implementations/RLCommandHandler.cpp b/src/lib/implementations/RLCommandHandler.cpp index f1f936a..6956a21 100644 --- a/src/lib/implementations/RLCommandHandler.cpp +++ b/src/lib/implementations/RLCommandHandler.cpp @@ -57,6 +57,9 @@ bool CRLCommandHandler::InitHandler(void) return true; m_bHandlerInited = true; + if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV) + return true; + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); if (primary && primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED) { diff --git a/src/lib/implementations/SLCommandHandler.cpp b/src/lib/implementations/SLCommandHandler.cpp index 7c9579d..e686fdd 100644 --- a/src/lib/implementations/SLCommandHandler.cpp +++ b/src/lib/implementations/SLCommandHandler.cpp @@ -86,6 +86,9 @@ bool CSLCommandHandler::InitHandler(void) return true; m_bHandlerInited = true; + if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV) + return true; + CCECBusDevice *primary = m_processor->GetPrimaryDevice(); if (primary && primary->GetLogicalAddress() != CECDEVICE_UNREGISTERED) { @@ -400,7 +403,7 @@ bool CSLCommandHandler::PowerOn(const cec_logical_address iInitiator, const cec_ cec_command command; if (!m_bSLEnabled) - TransmitVendorID(CECDEVICE_TV, CEC_VENDOR_LG, false); + TransmitVendorID(CECDEVICE_TV, iDestination, CEC_VENDOR_LG, false); cec_command::Format(command, CECDEVICE_TV, iDestination, CEC_OPCODE_VENDOR_COMMAND); command.PushBack(SL_COMMAND_POWER_ON); diff --git a/src/lib/implementations/VLCommandHandler.cpp b/src/lib/implementations/VLCommandHandler.cpp index b7cdb7a..21dc42e 100644 --- a/src/lib/implementations/VLCommandHandler.cpp +++ b/src/lib/implementations/VLCommandHandler.cpp @@ -76,13 +76,21 @@ bool CVLCommandHandler::InitHandler(void) { if (primary && m_busDevice->GetLogicalAddress() != primary->GetLogicalAddress()) { + libcec_configuration config; + m_processor->GetPrimaryClient()->GetCurrentConfiguration(config); + if (config.iDoubleTapTimeoutMs == 0) + { + config.iDoubleTapTimeoutMs = CEC_DOUBLE_TAP_TIMEOUT_MS; + m_processor->GetPrimaryClient()->SetConfiguration(config); + } + primary->SetVendorId(CEC_VENDOR_PANASONIC); primary->ReplaceHandler(false); } - } - if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) - return m_processor->GetPrimaryClient()->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE); + if (primary->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE) + return m_processor->GetPrimaryClient()->ChangeDeviceType(CEC_DEVICE_TYPE_RECORDING_DEVICE, CEC_DEVICE_TYPE_PLAYBACK_DEVICE); + } } return CCECCommandHandler::InitHandler(); diff --git a/src/testclient/main.cpp b/src/testclient/main.cpp index d73d4cb..c608292 100644 --- a/src/testclient/main.cpp +++ b/src/testclient/main.cpp @@ -48,7 +48,7 @@ using namespace CEC; using namespace std; using namespace PLATFORM; -#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_2_0_3; +#define CEC_CONFIG_VERSION CEC_CLIENT_VERSION_CURRENT; #include "../../include/cecloader.h" @@ -285,6 +285,7 @@ void ShowHelpConsole(void) "[p] {device} {port} change the HDMI port number of the CEC adapter." << endl << "[pa] {physical address} change the physical address of the CEC adapter." << endl << "[as] make the CEC adapter the active source." << endl << + "[is] mark the CEC adapter as inactive source." << endl << "[osd] {addr} {string} set OSD message on the specified device." << endl << "[ver] {addr} get the CEC version of the specified device." << endl << "[ven] {addr} get the vendor ID of the specified device." << endl << @@ -381,6 +382,10 @@ bool ProcessCommandTX(ICECAdapter *parser, const string &command, string &argume cec_command bytes; bytes.Clear(); + CStdString strArguments(arguments); + strArguments.Replace(':', ' '); + arguments = strArguments; + while (GetWord(arguments, strvalue) && HexStrToInt(strvalue, ivalue)) bytes.PushBack(ivalue); @@ -555,6 +560,13 @@ bool ProcessCommandAS(ICECAdapter *parser, const string &command, string & UNUSE return false; } +bool ProcessCommandIS(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) +{ + if (command == "is") + return parser->SetInactiveView(); + + return false; +} bool ProcessCommandPING(ICECAdapter *parser, const string &command, string & UNUSED(arguments)) { @@ -858,13 +870,14 @@ bool ProcessCommandSCAN(ICECAdapter *parser, const string &command, string & UNU strLog.append("CEC bus information\n===================\n"); cec_logical_addresses addresses = parser->GetActiveDevices(); + cec_logical_address activeSource = parser->GetActiveSource(); for (uint8_t iPtr = 0; iPtr < 16; iPtr++) { if (addresses[iPtr]) { uint64_t iVendorId = parser->GetDeviceVendorId((cec_logical_address)iPtr); - bool bActive = parser->IsActiveSource((cec_logical_address)iPtr); uint16_t iPhysicalAddress = parser->GetDevicePhysicalAddress((cec_logical_address)iPtr); + bool bActive = parser->IsActiveSource((cec_logical_address)iPtr); cec_version iCecVersion = parser->GetDeviceCecVersion((cec_logical_address)iPtr); cec_power_status power = parser->GetDevicePowerStatus((cec_logical_address)iPtr); cec_osd_name osdName = parser->GetDeviceOSDName((cec_logical_address)iPtr); @@ -887,7 +900,7 @@ bool ProcessCommandSCAN(ICECAdapter *parser, const string &command, string & UNU } } - cec_logical_address activeSource = parser->GetActiveSource(); + activeSource = parser->GetActiveSource(); strLog.AppendFormat("currently active source: %s (%d)", parser->ToString(activeSource), (int)activeSource); PrintToStdOut(strLog); @@ -915,6 +928,7 @@ bool ProcessConsoleCommand(ICECAdapter *parser, string &input) ProcessCommandP(parser, command, input) || ProcessCommandPA(parser, command, input) || ProcessCommandAS(parser, command, input) || + ProcessCommandIS(parser, command, input) || ProcessCommandOSD(parser, command, input) || ProcessCommandPING(parser, command, input) || ProcessCommandVOLUP(parser, command, input) ||