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 &param) { 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