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