2 * This file is part of the libCEC(R) library.
4 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
5 * libCEC(R) is an original work, containing original code.
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
9 * This program is dual-licensed; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
27 * For more information contact:
28 * Pulse-Eight Licensing <license@pulse-eight.com>
29 * http://www.pulse-eight.com/
30 * http://www.pulse-eight.net/
36 #include "adapter/AdapterFactory.h"
37 #include "adapter/AdapterCommunication.h"
38 #include "CECProcessor.h"
39 #include "devices/CECAudioSystem.h"
40 #include "devices/CECBusDevice.h"
41 #include "devices/CECPlaybackDevice.h"
42 #include "devices/CECTV.h"
43 #include "platform/util/timeutils.h"
44 #include "platform/util/StdString.h"
45 #include "platform/util/util.h"
47 #include "CECClient.h"
51 using namespace PLATFORM
;
53 CLibCEC::CLibCEC(void) :
54 m_iStartTime(GetTimeMs()),
57 m_cec
= new CCECProcessor(this);
60 CLibCEC::~CLibCEC(void)
62 // unregister all clients client
65 // delete the adapter connection
66 DELETE_AND_NULL(m_cec
);
69 bool CLibCEC::Open(const char *strPort
, uint32_t iTimeoutMs
/* = CEC_DEFAULT_CONNECT_TIMEOUT */)
71 if (!m_cec
|| !strPort
)
74 // open a new connection
75 if (!m_cec
->Start(strPort
, CEC_SERIAL_DEFAULT_BAUDRATE
, iTimeoutMs
))
77 AddLog(CEC_LOG_ERROR
, "could not start CEC communications");
81 // register all clients
82 for (vector
<CCECClient
*>::iterator it
= m_clients
.begin(); it
!= m_clients
.end(); it
++)
84 if (!m_cec
->RegisterClient(*it
))
86 AddLog(CEC_LOG_ERROR
, "failed to register a CEC client");
94 void CLibCEC::Close(void)
99 // unregister all clients
100 m_cec
->UnregisterClients();
102 // close the connection
106 int8_t CLibCEC::FindAdapters(cec_adapter
*deviceList
, uint8_t iBufSize
, const char *strDevicePath
/* = NULL */)
108 return CAdapterFactory(this).FindAdapters(deviceList
, iBufSize
, strDevicePath
);
111 bool CLibCEC::StartBootloader(void)
113 return m_cec
? m_cec
->StartBootloader() : false;
116 bool CLibCEC::PingAdapter(void)
118 return m_client
? m_client
->PingAdapter() : false;
121 bool CLibCEC::EnableCallbacks(void *cbParam
, ICECCallbacks
*callbacks
)
123 return m_client
? m_client
->EnableCallbacks(cbParam
, callbacks
) : false;
126 bool CLibCEC::GetCurrentConfiguration(libcec_configuration
*configuration
)
128 return m_client
? m_client
->GetCurrentConfiguration(*configuration
) : false;
131 bool CLibCEC::SetConfiguration(const libcec_configuration
*configuration
)
133 return m_client
? m_client
->SetConfiguration(*configuration
) : false;
136 bool CLibCEC::CanPersistConfiguration(void)
138 return m_client
? m_client
->CanPersistConfiguration() : false;
141 bool CLibCEC::PersistConfiguration(libcec_configuration
*configuration
)
143 return m_client
? m_client
->PersistConfiguration(*configuration
) : false;
146 void CLibCEC::RescanActiveDevices(void)
149 m_client
->RescanActiveDevices();
152 bool CLibCEC::IsLibCECActiveSource(void)
154 return m_client
? m_client
->IsLibCECActiveSource() : false;
157 bool CLibCEC::Transmit(const cec_command
&data
)
159 return m_client
? m_client
->Transmit(data
, false) : false;
162 bool CLibCEC::SetLogicalAddress(cec_logical_address iLogicalAddress
)
164 return m_client
? m_client
->SetLogicalAddress(iLogicalAddress
) : false;
167 bool CLibCEC::SetPhysicalAddress(uint16_t iPhysicalAddress
/* = CEC_DEFAULT_PHYSICAL_ADDRESS */)
169 return m_client
? m_client
->SetPhysicalAddress(iPhysicalAddress
) : false;
172 bool CLibCEC::SetHDMIPort(cec_logical_address iBaseDevice
, uint8_t iPort
/* = CEC_DEFAULT_HDMI_PORT */)
174 return m_client
? m_client
->SetHDMIPort(iBaseDevice
, iPort
) : false;
177 bool CLibCEC::PowerOnDevices(cec_logical_address address
/* = CECDEVICE_TV */)
179 return m_client
? m_client
->SendPowerOnDevices(address
) : false;
182 bool CLibCEC::StandbyDevices(cec_logical_address address
/* = CECDEVICE_BROADCAST */)
184 return m_client
? m_client
->SendStandbyDevices(address
) : false;
187 bool CLibCEC::SetActiveSource(cec_device_type type
/* = CEC_DEVICE_TYPE_RESERVED */)
189 return m_client
? m_client
->SendSetActiveSource(type
) : false;
192 bool CLibCEC::SetDeckControlMode(cec_deck_control_mode mode
, bool bSendUpdate
/* = true */)
194 return m_client
? m_client
->SendSetDeckControlMode(mode
, bSendUpdate
) : false;
197 bool CLibCEC::SetDeckInfo(cec_deck_info info
, bool bSendUpdate
/* = true */)
199 return m_client
? m_client
->SendSetDeckInfo(info
, bSendUpdate
) : false;
202 bool CLibCEC::SetInactiveView(void)
204 return m_client
? m_client
->SendSetInactiveView() : false;
207 bool CLibCEC::SetMenuState(cec_menu_state state
, bool bSendUpdate
/* = true */)
209 return m_client
? m_client
->SendSetMenuState(state
, bSendUpdate
) : false;
212 bool CLibCEC::SetOSDString(cec_logical_address iLogicalAddress
, cec_display_control duration
, const char *strMessage
)
214 return m_client
? m_client
->SendSetOSDString(iLogicalAddress
, duration
, strMessage
) : false;
217 bool CLibCEC::SwitchMonitoring(bool bEnable
)
219 return m_client
? m_client
->SwitchMonitoring(bEnable
) : false;
222 cec_version
CLibCEC::GetDeviceCecVersion(cec_logical_address iAddress
)
224 return m_client
? m_client
->GetDeviceCecVersion(iAddress
) : CEC_VERSION_UNKNOWN
;
227 bool CLibCEC::GetDeviceMenuLanguage(cec_logical_address iAddress
, cec_menu_language
*language
)
229 return m_client
? m_client
->GetDeviceMenuLanguage(iAddress
, *language
) : false;
232 uint64_t CLibCEC::GetDeviceVendorId(cec_logical_address iAddress
)
234 return m_client
? m_client
->GetDeviceVendorId(iAddress
) : (uint64_t)CEC_VENDOR_UNKNOWN
;
237 uint16_t CLibCEC::GetDevicePhysicalAddress(cec_logical_address iAddress
)
239 return m_client
? m_client
->GetDevicePhysicalAddress(iAddress
) : CEC_INVALID_PHYSICAL_ADDRESS
;
242 cec_power_status
CLibCEC::GetDevicePowerStatus(cec_logical_address iAddress
)
244 return m_client
? m_client
->GetDevicePowerStatus(iAddress
) : CEC_POWER_STATUS_UNKNOWN
;
247 bool CLibCEC::PollDevice(cec_logical_address iAddress
)
249 return m_client
? m_client
->PollDevice(iAddress
) : false;
252 cec_logical_addresses
CLibCEC::GetActiveDevices(void)
254 cec_logical_addresses addresses
;
257 addresses
= m_client
->GetActiveDevices();
261 bool CLibCEC::IsActiveDevice(cec_logical_address iAddress
)
263 return m_client
? m_client
->IsActiveDevice(iAddress
) : false;
266 bool CLibCEC::IsActiveDeviceType(cec_device_type type
)
268 return m_client
? m_client
->IsActiveDeviceType(type
) : false;
271 uint8_t CLibCEC::VolumeUp(bool bSendRelease
/* = true */)
273 return m_client
? m_client
->SendVolumeUp(bSendRelease
) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
276 uint8_t CLibCEC::VolumeDown(bool bSendRelease
/* = true */)
278 return m_client
? m_client
->SendVolumeDown(bSendRelease
) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
281 uint8_t CLibCEC::MuteAudio(bool UNUSED(bSendRelease
) /* = true */)
283 return m_client
? m_client
->SendMuteAudio() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
286 bool CLibCEC::SendKeypress(cec_logical_address iDestination
, cec_user_control_code key
, bool bWait
/* = true */)
288 return m_client
? m_client
->SendKeypress(iDestination
, key
, bWait
) : false;
291 bool CLibCEC::SendKeyRelease(cec_logical_address iDestination
, bool bWait
/* = true */)
293 return m_client
? m_client
->SendKeyRelease(iDestination
, bWait
) : false;
296 cec_osd_name
CLibCEC::GetDeviceOSDName(cec_logical_address iAddress
)
299 retVal
.device
= CECDEVICE_UNKNOWN
;
300 memset(retVal
.name
, 0, 14);
303 retVal
= m_client
->GetDeviceOSDName(iAddress
);
307 cec_logical_address
CLibCEC::GetActiveSource(void)
309 return m_client
? m_client
->GetActiveSource() : CECDEVICE_UNKNOWN
;
312 bool CLibCEC::IsActiveSource(cec_logical_address iAddress
)
314 return m_client
? m_client
->IsActiveSource(iAddress
) : false;
316 bool CLibCEC::SetStreamPath(cec_logical_address iAddress
)
318 return m_client
? m_client
->SetStreamPath(iAddress
) : false;
321 bool CLibCEC::SetStreamPath(uint16_t iPhysicalAddress
)
323 return m_client
? m_client
->SetStreamPath(iPhysicalAddress
) : false;
326 cec_logical_addresses
CLibCEC::GetLogicalAddresses(void)
328 cec_logical_addresses addresses
;
331 m_client
->GetLogicalAddresses();
335 cec_device_type
CLibCEC::GetType(cec_logical_address address
)
337 return CCECTypeUtils::GetType(address
);
340 uint16_t CLibCEC::GetMaskForType(cec_logical_address address
)
342 return CCECTypeUtils::GetMaskForType(address
);
345 uint16_t CLibCEC::GetMaskForType(cec_device_type type
)
347 return CCECTypeUtils::GetMaskForType(type
);
350 bool CLibCEC::IsValidPhysicalAddress(uint16_t iPhysicalAddress
)
352 return iPhysicalAddress
>= CEC_MIN_PHYSICAL_ADDRESS
&&
353 iPhysicalAddress
<= CEC_MAX_PHYSICAL_ADDRESS
;
356 void CLibCEC::CheckKeypressTimeout(void)
359 for (vector
<CCECClient
*>::iterator it
= m_clients
.begin(); it
!= m_clients
.end(); it
++)
360 (*it
)->CheckKeypressTimeout();
363 void CLibCEC::AddLog(const cec_log_level level
, const char *strFormat
, ...)
367 // format the message
369 va_start(argList
, strFormat
);
370 strLog
.FormatV(strFormat
, argList
);
373 cec_log_message message
;
374 message
.level
= level
;
375 message
.time
= GetTimeMs() - m_iStartTime
;
376 snprintf(message
.message
, sizeof(message
.message
), "%s", strLog
.c_str());
378 // send the message to all clients
379 for (vector
<CCECClient
*>::iterator it
= m_clients
.begin(); it
!= m_clients
.end(); it
++)
380 (*it
)->AddLog(message
);
383 void CLibCEC::AddCommand(const cec_command
&command
)
385 // send the command to all clients
386 for (vector
<CCECClient
*>::iterator it
= m_clients
.begin(); it
!= m_clients
.end(); it
++)
387 (*it
)->AddCommand(command
);
390 void CLibCEC::Alert(const libcec_alert type
, const libcec_parameter
¶m
)
392 // send the alert to all clients
393 for (vector
<CCECClient
*>::iterator it
= m_clients
.begin(); it
!= m_clients
.end(); it
++)
394 (*it
)->Alert(type
, param
);
397 CCECClient
*CLibCEC::RegisterClient(libcec_configuration
&configuration
)
402 // create a new client instance
403 CCECClient
*newClient
= new CCECClient(m_cec
, configuration
);
406 m_clients
.push_back(newClient
);
408 // if the default client isn't set, set it
410 m_client
= newClient
;
412 // register the new client
413 if (m_cec
->CECInitialised())
414 m_cec
->RegisterClient(newClient
);
419 void CLibCEC::UnregisterClients(void)
421 if (m_cec
&& m_cec
->IsRunning())
422 m_cec
->UnregisterClients();
426 DELETE_AND_NULL(m_client
);
429 void * CECInitialise(libcec_configuration
*configuration
)
434 // create a new libCEC instance
435 CLibCEC
*lib
= new CLibCEC
;
437 // register a new client
438 CCECClient
*client(NULL
);
439 if (lib
&& configuration
)
440 client
= lib
->RegisterClient(*configuration
);
442 // update the current configuration
444 client
->GetCurrentConfiguration(*configuration
);
446 // ensure that the correct server version is set
447 configuration
->serverVersion
= LIBCEC_VERSION_CURRENT
;
449 return static_cast< void* > (lib
);
452 void * CECInit(const char *strDeviceName
, CEC::cec_device_type_list types
)
454 libcec_configuration configuration
; configuration
.Clear();
456 // client version < 1.5.0
457 snprintf(configuration
.strDeviceName
, 13, "%s", strDeviceName
);
458 configuration
.deviceTypes
= types
;
459 configuration
.iPhysicalAddress
= CEC_INVALID_PHYSICAL_ADDRESS
;
461 if (configuration
.deviceTypes
.IsEmpty())
462 configuration
.deviceTypes
.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE
);
464 return CECInitialise(&configuration
);
467 bool CECStartBootloader(void)
470 cec_adapter deviceList
[1];
471 if (CAdapterFactory(NULL
).FindAdapters(deviceList
, 1, 0) > 0)
473 CAdapterFactory
factory(NULL
);
474 IAdapterCommunication
*comm
= factory
.GetInstance(deviceList
[0].comm
);
477 CTimeout
timeout(CEC_DEFAULT_CONNECT_TIMEOUT
);
478 while (timeout
.TimeLeft() > 0 &&
479 (bReturn
= comm
->Open(timeout
.TimeLeft() / CEC_CONNECT_TRIES
, true)) == false)
485 bReturn
= comm
->StartBootloader();
494 void CECDestroy(CEC::ICECAdapter
*instance
)
496 DELETE_AND_NULL(instance
);
499 bool CLibCEC::GetDeviceInformation(const char *strPort
, libcec_configuration
*config
, uint32_t iTimeoutMs
/* = CEC_DEFAULT_CONNECT_TIMEOUT */)
501 if (m_cec
->IsRunning())
504 return m_cec
->GetDeviceInformation(strPort
, config
, iTimeoutMs
);
507 const char *CLibCEC::GetLibInfo(void)
511 #define FEATURES "'P8 USB' 'P8 USB detect'"
513 #define HOST_TYPE "Windows (x64)"
515 #define HOST_TYPE "Windows (x86)"
518 #define HOST_TYPE "unknown"
519 #define FEATURES "unknown"
522 return "host: " HOST_TYPE
", features: " FEATURES
", compiled: " __DATE__
;
528 void CLibCEC::InitVideoStandalone(void)
530 CAdapterFactory::InitVideoStandalone();
532 uint16_t CLibCEC::GetAdapterVendorId(void) const
534 return m_cec
&& m_cec
->IsRunning() ? m_cec
->GetAdapterVendorId() : 0;
537 uint16_t CLibCEC::GetAdapterProductId(void) const
539 return m_cec
&& m_cec
->IsRunning() ? m_cec
->GetAdapterProductId() : 0;