libcec-sys 9.0.3

FFI bindings to libcec
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 &param) { 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;
  };
}