1 #pragma once 2 /* 3 * This file is part of the libCEC(R) library. 4 * 5 * libCEC(R) is Copyright (C) 2011-2015 Pulse-Eight Limited. All rights reserved. 6 * libCEC(R) is an original work, containing original code. 7 * 8 * libCEC(R) is a trademark of Pulse-Eight Limited. 9 * 10 * This program is dual-licensed; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 23 * 02110-1301 USA 24 * 25 * 26 * Alternatively, you can license this library under a commercial license, 27 * please contact Pulse-Eight Licensing for more information. 28 * 29 * For more information contact: 30 * Pulse-Eight Licensing <license@pulse-eight.com> 31 * http://www.pulse-eight.com/ 32 * http://www.pulse-eight.net/ 33 */ 34 35 #include "env.h" 36 #include "LibCEC.h" 37 #include "p8-platform/threads/threads.h" 38 #include "p8-platform/util/buffer.h" 39 #include "p8-platform/threads/mutex.h" 40 #include <string> 41 #include <memory> 42 43 namespace CEC 44 { 45 class CCECProcessor; 46 class CCECBusDevice; 47 class CCECPlaybackDevice; 48 class CCECClient; 49 50 typedef std::shared_ptr<CCECClient> CECClientPtr; 51 52 class CCallbackWrap 53 { 54 public: CCallbackWrap(const cec_command & command)55 CCallbackWrap(const cec_command& command) : 56 m_type(CEC_CB_COMMAND), 57 m_command(command), 58 m_alertType(CEC_ALERT_SERVICE_DEVICE), 59 m_menuState(CEC_MENU_STATE_ACTIVATED), 60 m_bActivated(false), 61 m_logicalAddress(CECDEVICE_UNKNOWN), 62 m_keepResult(false), 63 m_result(0), 64 m_bSucceeded(false) {} 65 CCallbackWrap(const cec_keypress & key)66 CCallbackWrap(const cec_keypress& key) : 67 m_type(CEC_CB_KEY_PRESS), 68 m_key(key), 69 m_alertType(CEC_ALERT_SERVICE_DEVICE), 70 m_menuState(CEC_MENU_STATE_ACTIVATED), 71 m_bActivated(false), 72 m_logicalAddress(CECDEVICE_UNKNOWN), 73 m_keepResult(false), 74 m_result(0), 75 m_bSucceeded(false) {} 76 CCallbackWrap(const cec_log_message_cpp & message)77 CCallbackWrap(const cec_log_message_cpp& message) : 78 m_type(CEC_CB_LOG_MESSAGE), 79 m_message(message), 80 m_alertType(CEC_ALERT_SERVICE_DEVICE), 81 m_menuState(CEC_MENU_STATE_ACTIVATED), 82 m_bActivated(false), 83 m_logicalAddress(CECDEVICE_UNKNOWN), 84 m_keepResult(false), 85 m_result(0), 86 m_bSucceeded(false) {} 87 CCallbackWrap(const libcec_alert type,const libcec_parameter & param)88 CCallbackWrap(const libcec_alert type, const libcec_parameter& param) : 89 m_type(CEC_CB_ALERT), 90 m_alertType(type), 91 m_alertParam(param), 92 m_menuState(CEC_MENU_STATE_ACTIVATED), 93 m_bActivated(false), 94 m_logicalAddress(CECDEVICE_UNKNOWN), 95 m_keepResult(false), 96 m_result(0), 97 m_bSucceeded(false) {} 98 CCallbackWrap(const libcec_configuration & config)99 CCallbackWrap(const libcec_configuration& config) : 100 m_type(CEC_CB_CONFIGURATION), 101 m_alertType(CEC_ALERT_SERVICE_DEVICE), 102 m_config(config), 103 m_menuState(CEC_MENU_STATE_ACTIVATED), 104 m_bActivated(false), 105 m_logicalAddress(CECDEVICE_UNKNOWN), 106 m_keepResult(false), 107 m_result(0), 108 m_bSucceeded(false) {} 109 110 CCallbackWrap(const cec_menu_state newState, const bool keepResult = false) : m_type(CEC_CB_MENU_STATE)111 m_type(CEC_CB_MENU_STATE), 112 m_alertType(CEC_ALERT_SERVICE_DEVICE), 113 m_menuState(newState), 114 m_bActivated(false), 115 m_logicalAddress(CECDEVICE_UNKNOWN), 116 m_keepResult(keepResult), 117 m_result(0), 118 m_bSucceeded(false) {} 119 CCallbackWrap(bool bActivated,const cec_logical_address logicalAddress)120 CCallbackWrap(bool bActivated, const cec_logical_address logicalAddress) : 121 m_type(CEC_CB_SOURCE_ACTIVATED), 122 m_alertType(CEC_ALERT_SERVICE_DEVICE), 123 m_menuState(CEC_MENU_STATE_ACTIVATED), 124 m_bActivated(bActivated), 125 m_logicalAddress(logicalAddress), 126 m_keepResult(false), 127 m_result(0), 128 m_bSucceeded(false) {} 129 Result(uint32_t iTimeout)130 int Result(uint32_t iTimeout) 131 { 132 P8PLATFORM::CLockObject lock(m_mutex); 133 134 bool bReturn = m_bSucceeded ? true : m_condition.Wait(m_mutex, m_bSucceeded, iTimeout); 135 if (bReturn) 136 return m_result; 137 return 0; 138 } 139 Report(int result)140 void Report(int result) 141 { 142 P8PLATFORM::CLockObject lock(m_mutex); 143 144 m_result = result; 145 m_bSucceeded = true; 146 m_condition.Signal(); 147 } 148 149 enum callbackWrapType { 150 CEC_CB_LOG_MESSAGE, 151 CEC_CB_KEY_PRESS, 152 CEC_CB_COMMAND, 153 CEC_CB_ALERT, 154 CEC_CB_CONFIGURATION, 155 CEC_CB_MENU_STATE, 156 CEC_CB_SOURCE_ACTIVATED, 157 } m_type; 158 159 cec_command m_command; 160 cec_keypress m_key; 161 cec_log_message_cpp m_message; 162 libcec_alert m_alertType; 163 libcec_parameter m_alertParam; 164 libcec_configuration m_config; 165 cec_menu_state m_menuState; 166 bool m_bActivated; 167 cec_logical_address m_logicalAddress; 168 bool m_keepResult; 169 int m_result; 170 P8PLATFORM::CCondition<bool> m_condition; 171 P8PLATFORM::CMutex m_mutex; 172 bool m_bSucceeded; 173 }; 174 175 class CCECClient : private P8PLATFORM::CThread 176 { 177 friend class CCECProcessor; 178 179 public: 180 CCECClient(CCECProcessor *processor, const libcec_configuration &configuration); 181 virtual ~CCECClient(void); 182 183 /*! 184 * @return True when initialised and registered, false otherwise. 185 */ 186 virtual bool IsInitialised(void); 187 188 /*! 189 * @return True when registered in the processor, false otherwise. 190 */ 191 virtual bool IsRegistered(void); 192 193 /*! 194 * @return The primary logical address that this client is controlling. 195 */ 196 virtual cec_logical_address GetPrimaryLogicalAddress(void); 197 198 /*! 199 * @return The primary device that this client is controlling, or NULL if none. 200 */ 201 virtual CCECBusDevice *GetPrimaryDevice(void); 202 203 /*! 204 * @return Get the playback device or recording device that this client is controlling, or NULL if none. 205 */ 206 virtual CCECPlaybackDevice *GetPlaybackDevice(void); 207 208 /*! 209 * @brief Change one of the device types that this client is controlling into another. 210 * @param from The type to change. 211 * @param to The new value. 212 * @return True when changed, false otherwise. 213 */ 214 virtual bool ChangeDeviceType(const cec_device_type from, const cec_device_type to); 215 216 /*! 217 * @brief Get a device that this client is controlling, given it's type. 218 * @param type The type of the device to get. 219 * @return The requested device, or NULL if not found. 220 */ 221 virtual CCECBusDevice *GetDeviceByType(const cec_device_type type) const; 222 223 /*! 224 * @brief Reset the physical address from the configuration. 225 */ 226 virtual void ResetPhysicalAddress(void); 227 228 /*! 229 * @return A string that describes this client. 230 */ 231 virtual std::string GetConnectionInfo(void); 232 233 /*! 234 * @return The current value of the TV vendor override setting. 235 */ 236 virtual cec_vendor_id GetTVVendorOverride(void); 237 238 /*! 239 * @return The current value of the OSD name setting. 240 */ 241 virtual std::string GetOSDName(void); 242 243 /*! 244 * @return Get the current value of the wake device setting. 245 */ 246 virtual cec_logical_addresses GetWakeDevices(void); 247 248 /*! 249 * @return The version of this client. 250 */ 251 virtual uint32_t GetClientVersion(void); 252 253 /*! 254 * @return The device types that this client is controlling. 255 */ 256 virtual cec_device_type_list GetDeviceTypes(void); 257 258 // client-specific part of ICECAdapter 259 virtual bool EnableCallbacks(void *cbParam, ICECCallbacks *callbacks); 260 virtual bool PingAdapter(void); 261 virtual bool Transmit(const cec_command &data, bool bIsReply); 262 virtual bool SetLogicalAddress(const cec_logical_address iLogicalAddress); 263 virtual bool SetPhysicalAddress(const uint16_t iPhysicalAddress); 264 virtual bool SetHDMIPort(const cec_logical_address iBaseDevice, const uint8_t iPort, bool bForce = false); 265 virtual bool SendPowerOnDevices(const cec_logical_address address = CECDEVICE_TV); 266 virtual bool SendStandbyDevices(const cec_logical_address address = CECDEVICE_BROADCAST); 267 virtual bool SendSetActiveSource(const cec_device_type type = CEC_DEVICE_TYPE_RESERVED); 268 virtual bool SendSetDeckControlMode(const cec_deck_control_mode mode, bool bSendUpdate = true); 269 virtual bool SendSetDeckInfo(const cec_deck_info info, bool bSendUpdate = true); 270 virtual bool SendSetInactiveView(void); 271 virtual bool SendSetMenuState(const cec_menu_state state, bool bSendUpdate = true); 272 virtual bool SendSetOSDString(const cec_logical_address iLogicalAddress, const cec_display_control duration, const char *strMessage); 273 virtual bool SwitchMonitoring(bool bEnable); 274 virtual cec_version GetDeviceCecVersion(const cec_logical_address iAddress); 275 virtual std::string GetDeviceMenuLanguage(const cec_logical_address iAddress); 276 virtual uint32_t GetDeviceVendorId(const cec_logical_address iAddress); 277 virtual cec_power_status GetDevicePowerStatus(const cec_logical_address iAddress); 278 virtual uint16_t GetDevicePhysicalAddress(const cec_logical_address iAddress); 279 virtual bool PollDevice(const cec_logical_address iAddress); 280 virtual cec_logical_addresses GetActiveDevices(void); 281 virtual bool IsActiveDevice(const cec_logical_address iAddress); 282 virtual bool IsActiveDeviceType(const cec_device_type type); 283 virtual uint8_t SendVolumeUp(bool bSendRelease = true); 284 virtual uint8_t SendVolumeDown(bool bSendRelease = true); 285 virtual uint8_t SendMuteAudio(void); 286 virtual uint8_t AudioToggleMute(void); 287 virtual uint8_t AudioMute(void); 288 virtual uint8_t AudioUnmute(void); 289 virtual uint8_t AudioStatus(void); 290 virtual bool SendKeypress(const cec_logical_address iDestination, const cec_user_control_code key, bool bWait = true); 291 virtual bool SendKeyRelease(const cec_logical_address iDestination, bool bWait = true); 292 virtual std::string GetDeviceOSDName(const cec_logical_address iAddress); 293 virtual cec_logical_address GetActiveSource(void); 294 virtual bool IsActiveSource(const cec_logical_address iAddress); 295 virtual bool SetStreamPath(const cec_logical_address iAddress); 296 virtual bool SetStreamPath(const uint16_t iPhysicalAddress); 297 virtual cec_logical_addresses GetLogicalAddresses(void); 298 virtual void RescanActiveDevices(void); 299 virtual bool IsLibCECActiveSource(void); 300 bool AudioEnable(bool enable); 301 bool GetStats(struct cec_adapter_stats* stats); 302 303 // configuration 304 virtual bool GetCurrentConfiguration(libcec_configuration &configuration); 305 virtual bool SetConfiguration(const libcec_configuration &configuration); 306 virtual bool CanSaveConfiguration(void); 307 virtual bool SaveConfiguration(const libcec_configuration &configuration); 308 virtual bool SetPhysicalAddress(const libcec_configuration &configuration); 309 310 void QueueAddCommand(const cec_command& command); 311 void QueueAddKey(const cec_keypress& key); 312 void QueueAddLog(const cec_log_message_cpp& message); 313 void QueueAlert(const libcec_alert type, const libcec_parameter& param); 314 void QueueConfigurationChanged(const libcec_configuration& config); 315 int QueueMenuStateChanged(const cec_menu_state newState); //TODO 316 void QueueSourceActivated(bool bActivated, const cec_logical_address logicalAddress); 317 318 // callbacks Alert(const libcec_alert type,const libcec_parameter & param)319 virtual void Alert(const libcec_alert type, const libcec_parameter ¶m) { QueueAlert(type, param); } AddLog(const cec_log_message_cpp & message)320 virtual void AddLog(const cec_log_message_cpp &message) { QueueAddLog(message); } 321 virtual void AddKey(bool bSendComboKey = false, bool bButtonRelease = false); 322 virtual void AddKey(const cec_keypress &key); 323 virtual void SetCurrentButton(const cec_user_control_code iButtonCode); 324 virtual uint16_t CheckKeypressTimeout(void); 325 virtual void SourceActivated(const cec_logical_address logicalAddress); 326 virtual void SourceDeactivated(const cec_logical_address logicalAddress); 327 328 protected: 329 void* Process(void); 330 331 /*! 332 * @brief Register this client in the processor 333 * @return True when registered, false otherwise. 334 */ 335 virtual bool OnRegister(void); 336 337 /*! 338 * @brief Called by the processor when this client is unregistered 339 */ OnUnregister(void)340 virtual void OnUnregister(void) { SetRegistered(false); SetInitialised(false); } 341 342 /*! 343 * @brief Set the registered state of this client. 344 * @param bSetTo The new value. 345 */ 346 virtual void SetRegistered(bool bSetTo); 347 348 /*! 349 * @brief Set the initialised state of this client. 350 * @param bSetTo The new value 351 */ 352 virtual void SetInitialised(bool bSetTo); 353 354 /*! 355 * @brief Change the TV vendor id override setting. 356 * @param id The new value. 357 */ 358 virtual void SetTVVendorOverride(const cec_vendor_id id); 359 360 /*! 361 * @brief Change the OSD name of the primary device that this client is controlling. 362 * @param strDeviceName The new value. 363 */ 364 virtual void SetOSDName(const std::string &strDeviceName); 365 366 /*! 367 * @brief Change the value of the devices to wake. 368 * @param addresses The new value. 369 */ 370 virtual void SetWakeDevices(const cec_logical_addresses &addresses); 371 372 /*! 373 * @brief Change the value of the client version setting. 374 * @param version The new version setting. 375 */ 376 virtual void SetClientVersion(uint32_t version); 377 378 /*! 379 * @brief Change the device types that this client is controlling. 380 * @param deviceTypes The new types. 381 * @return True when the client needs to be re-registered to pick up the new setting, false otherwise. 382 */ 383 virtual bool SetDeviceTypes(const cec_device_type_list &deviceTypes); 384 385 /*! 386 * @return A pointer to the current configuration of this client. 387 */ GetConfiguration(void)388 virtual libcec_configuration *GetConfiguration(void) { return &m_configuration; } 389 390 /*! 391 * @brief Called by the processor when registering this client to allocate the logical addresses. 392 * @return True when the addresses for all types were allocated, false otherwise. 393 */ 394 virtual bool AllocateLogicalAddresses(void); 395 396 /*! 397 * @brief Try to allocate a logical address for a recording device controlled by this client. 398 * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated. 399 */ 400 virtual cec_logical_address AllocateLogicalAddressRecordingDevice(void); 401 402 /*! 403 * @brief Try to allocate a logical address for a tuner controlled by this client. 404 * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated. 405 */ 406 virtual cec_logical_address AllocateLogicalAddressTuner(void); 407 408 /*! 409 * @brief Try to allocate a logical address for a playback device controlled by this client. 410 * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated. 411 */ 412 virtual cec_logical_address AllocateLogicalAddressPlaybackDevice(void); 413 414 /*! 415 * @brief Try to allocate a logical address for an audiosystem controlled by this client. 416 * @return The logical address that was allocated, or CECDEVICE_UNKNOWN if none could be allocated. 417 */ 418 virtual cec_logical_address AllocateLogicalAddressAudioSystem(void); 419 420 /*! 421 * @brief Change the physical address of the devices controlled by this client. 422 * @param iPhysicalAddress The new physical address. 423 * @return True when changed, false otherwise. 424 */ 425 virtual bool SetDevicePhysicalAddress(const uint16_t iPhysicalAddress); 426 427 /*! 428 * @brief Try to autodetect the physical address. 429 * @return True when autodetected (and set in m_configuration), false otherwise. 430 */ 431 virtual bool AutodetectPhysicalAddress(void); 432 433 /*! 434 * @brief Replaces all device types in m_configuration by types that are supported by the command handler of the TV 435 */ 436 virtual void SetSupportedDeviceTypes(void); 437 438 void AddCommand(const cec_command &command); 439 void CallbackAddCommand(const cec_command& command); 440 void CallbackAddKey(const cec_keypress& key); 441 void CallbackAddLog(const cec_log_message_cpp& message); 442 void CallbackAlert(const libcec_alert type, const libcec_parameter& param); 443 void CallbackConfigurationChanged(const libcec_configuration& config); 444 int CallbackMenuStateChanged(const cec_menu_state newState); 445 void CallbackSourceActivated(bool bActivated, const cec_logical_address logicalAddress); 446 447 uint32_t DoubleTapTimeoutMS(void); 448 449 CCECProcessor * m_processor; /**< a pointer to the processor */ 450 libcec_configuration m_configuration; /**< the configuration of this client */ 451 bool m_bInitialised; /**< true when initialised, false otherwise */ 452 bool m_bRegistered; /**< true when registered in the processor, false otherwise */ 453 P8PLATFORM::CMutex m_mutex; /**< mutex for changes to this instance */ 454 P8PLATFORM::CMutex m_cbMutex; /**< mutex that is held when doing anything with callbacks */ 455 cec_user_control_code m_iCurrentButton; /**< the control code of the button that's currently held down (if any) */ 456 int64_t m_initialButtontime; /**< the timestamp when the button was initially pressed (in seconds since epoch), or 0 if none was pressed. */ 457 int64_t m_updateButtontime; /**< the timestamp when the button was updated (in seconds since epoch), or 0 if none was pressed. */ 458 int64_t m_repeatButtontime; /**< the timestamp when the button will next repeat (in seconds since epoch), or 0 if repeat is disabled. */ 459 int64_t m_releaseButtontime; /**< the timestamp when the button will be released (in seconds since epoch), or 0 if none was pressed. */ 460 int32_t m_pressedButtoncount; /**< the number of times a button released message has been seen for this press. */ 461 int32_t m_releasedButtoncount; /**< the number of times a button pressed message has been seen for this press. */ 462 int64_t m_iPreventForwardingPowerOffCommand; /**< prevent forwarding standby commands until this time */ 463 P8PLATFORM::SyncedBuffer<CCallbackWrap*> m_callbackCalls; 464 }; 465 } 466