2 * This file is part of the libCEC(R) library.
4 * libCEC(R) is Copyright (C) 2011-2013 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 AddLog(CEC_LOG_WARNING
, "deprecated function called: %s", __FUNCTION__
);
284 return m_client
? m_client
->SendMuteAudio() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
287 bool CLibCEC::SendKeypress(cec_logical_address iDestination
, cec_user_control_code key
, bool bWait
/* = true */)
289 return m_client
? m_client
->SendKeypress(iDestination
, key
, bWait
) : false;
292 bool CLibCEC::SendKeyRelease(cec_logical_address iDestination
, bool bWait
/* = true */)
294 return m_client
? m_client
->SendKeyRelease(iDestination
, bWait
) : false;
297 cec_osd_name
CLibCEC::GetDeviceOSDName(cec_logical_address iAddress
)
300 retVal
.device
= CECDEVICE_UNKNOWN
;
301 memset(retVal
.name
, 0, 14);
304 retVal
= m_client
->GetDeviceOSDName(iAddress
);
308 cec_logical_address
CLibCEC::GetActiveSource(void)
310 return m_client
? m_client
->GetActiveSource() : CECDEVICE_UNKNOWN
;
313 bool CLibCEC::IsActiveSource(cec_logical_address iAddress
)
315 return m_client
? m_client
->IsActiveSource(iAddress
) : false;
317 bool CLibCEC::SetStreamPath(cec_logical_address iAddress
)
319 return m_client
? m_client
->SetStreamPath(iAddress
) : false;
322 bool CLibCEC::SetStreamPath(uint16_t iPhysicalAddress
)
324 return m_client
? m_client
->SetStreamPath(iPhysicalAddress
) : false;
327 cec_logical_addresses
CLibCEC::GetLogicalAddresses(void)
329 cec_logical_addresses addresses
;
332 addresses
= m_client
->GetLogicalAddresses();
336 cec_device_type
CLibCEC::GetType(cec_logical_address address
)
338 return CCECTypeUtils::GetType(address
);
341 uint16_t CLibCEC::GetMaskForType(cec_logical_address address
)
343 return CCECTypeUtils::GetMaskForType(address
);
346 uint16_t CLibCEC::GetMaskForType(cec_device_type type
)
348 return CCECTypeUtils::GetMaskForType(type
);
351 bool CLibCEC::IsValidPhysicalAddress(uint16_t iPhysicalAddress
)
353 return iPhysicalAddress
>= CEC_MIN_PHYSICAL_ADDRESS
&&
354 iPhysicalAddress
<= CEC_MAX_PHYSICAL_ADDRESS
;
357 void CLibCEC::CheckKeypressTimeout(void)
360 for (vector
<CCECClient
*>::iterator it
= m_clients
.begin(); it
!= m_clients
.end(); it
++)
361 (*it
)->CheckKeypressTimeout();
364 void CLibCEC::AddLog(const cec_log_level level
, const char *strFormat
, ...)
368 // format the message
370 va_start(argList
, strFormat
);
371 strLog
.FormatV(strFormat
, argList
);
374 cec_log_message message
;
375 message
.level
= level
;
376 message
.time
= GetTimeMs() - m_iStartTime
;
377 snprintf(message
.message
, sizeof(message
.message
), "%s", strLog
.c_str());
379 // send the message to all clients
380 for (vector
<CCECClient
*>::iterator it
= m_clients
.begin(); it
!= m_clients
.end(); it
++)
381 (*it
)->AddLog(message
);
384 void CLibCEC::AddCommand(const cec_command
&command
)
386 // send the command to all clients
387 for (vector
<CCECClient
*>::iterator it
= m_clients
.begin(); it
!= m_clients
.end(); it
++)
388 (*it
)->AddCommand(command
);
391 void CLibCEC::Alert(const libcec_alert type
, const libcec_parameter
¶m
)
393 // send the alert to all clients
394 for (vector
<CCECClient
*>::iterator it
= m_clients
.begin(); it
!= m_clients
.end(); it
++)
395 (*it
)->Alert(type
, param
);
398 CCECClient
*CLibCEC::RegisterClient(libcec_configuration
&configuration
)
403 // create a new client instance
404 CCECClient
*newClient
= new CCECClient(m_cec
, configuration
);
407 m_clients
.push_back(newClient
);
409 // if the default client isn't set, set it
411 m_client
= newClient
;
413 // register the new client
414 if (m_cec
->CECInitialised())
415 m_cec
->RegisterClient(newClient
);
420 void CLibCEC::UnregisterClients(void)
422 if (m_cec
&& m_cec
->IsRunning())
423 m_cec
->UnregisterClients();
427 DELETE_AND_NULL(m_client
);
430 void * CECInitialise(libcec_configuration
*configuration
)
435 // create a new libCEC instance
436 CLibCEC
*lib
= new CLibCEC
;
438 // register a new client
439 CCECClient
*client(NULL
);
440 if (lib
&& configuration
)
441 client
= lib
->RegisterClient(*configuration
);
443 // update the current configuration
445 client
->GetCurrentConfiguration(*configuration
);
447 // ensure that the correct server version is set
448 configuration
->serverVersion
= LIBCEC_VERSION_CURRENT
;
450 return static_cast< void* > (lib
);
453 void * CECInit(const char *strDeviceName
, CEC::cec_device_type_list types
)
455 libcec_configuration configuration
; configuration
.Clear();
457 // client version < 1.5.0
458 snprintf(configuration
.strDeviceName
, 13, "%s", strDeviceName
);
459 configuration
.deviceTypes
= types
;
460 configuration
.iPhysicalAddress
= CEC_INVALID_PHYSICAL_ADDRESS
;
462 if (configuration
.deviceTypes
.IsEmpty())
463 configuration
.deviceTypes
.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE
);
465 return CECInitialise(&configuration
);
468 bool CECStartBootloader(void)
471 cec_adapter deviceList
[1];
472 if (CAdapterFactory(NULL
).FindAdapters(deviceList
, 1, 0) > 0)
474 CAdapterFactory
factory(NULL
);
475 IAdapterCommunication
*comm
= factory
.GetInstance(deviceList
[0].comm
);
478 CTimeout
timeout(CEC_DEFAULT_CONNECT_TIMEOUT
);
479 while (timeout
.TimeLeft() > 0 &&
480 (bReturn
= comm
->Open(timeout
.TimeLeft() / CEC_CONNECT_TRIES
, true)) == false)
486 bReturn
= comm
->StartBootloader();
495 void CECDestroy(CEC::ICECAdapter
*instance
)
497 DELETE_AND_NULL(instance
);
500 bool CLibCEC::GetDeviceInformation(const char *strPort
, libcec_configuration
*config
, uint32_t iTimeoutMs
/* = CEC_DEFAULT_CONNECT_TIMEOUT */)
502 if (m_cec
->IsRunning())
505 return m_cec
->GetDeviceInformation(strPort
, config
, iTimeoutMs
);
508 const char *CLibCEC::GetLibInfo(void)
512 #define FEATURES "'P8 USB' 'P8 USB detect'"
514 #define HOST_TYPE "Windows (x64)"
516 #define HOST_TYPE "Windows (x86)"
519 #define HOST_TYPE "unknown"
520 #define FEATURES "unknown"
523 return "host: " HOST_TYPE
", features: " FEATURES
", compiled: " __DATE__
;
529 void CLibCEC::InitVideoStandalone(void)
531 CAdapterFactory::InitVideoStandalone();
533 uint16_t CLibCEC::GetAdapterVendorId(void) const
535 return m_cec
&& m_cec
->IsRunning() ? m_cec
->GetAdapterVendorId() : 0;
538 uint16_t CLibCEC::GetAdapterProductId(void) const
540 return m_cec
&& m_cec
->IsRunning() ? m_cec
->GetAdapterProductId() : 0;
543 uint8_t CLibCEC::AudioToggleMute(void)
545 return m_client
? m_client
->AudioToggleMute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
548 uint8_t CLibCEC::AudioMute(void)
550 return m_client
? m_client
->AudioMute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
553 uint8_t CLibCEC::AudioUnmute(void)
555 return m_client
? m_client
->AudioUnmute() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
558 uint8_t CLibCEC::AudioStatus(void)
560 return m_client
? m_client
->AudioStatus() : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
563 int8_t CLibCEC::DetectAdapters(cec_adapter_descriptor
*deviceList
, uint8_t iBufSize
, const char *strDevicePath
/* = NULL */, bool bQuickScan
/* = false */)
565 int8_t iAdaptersFound
= CAdapterFactory(this).DetectAdapters(deviceList
, iBufSize
, strDevicePath
);
568 for (int8_t iPtr
= 0; iPtr
< iAdaptersFound
; iPtr
++)
570 libcec_configuration config
;
571 GetDeviceInformation(deviceList
[iPtr
].strComName
, &config
);
572 deviceList
[iPtr
].iFirmwareVersion
= config
.iFirmwareVersion
;
573 deviceList
[iPtr
].iPhysicalAddress
= config
.iPhysicalAddress
;
574 deviceList
[iPtr
].iFirmwareBuildDate
= config
.iFirmwareBuildDate
;
575 deviceList
[iPtr
].adapterType
= config
.adapterType
;
578 return iAdaptersFound
;