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/
33 #include "CECClient.h"
34 #include "CECProcessor.h"
36 #include "devices/CECPlaybackDevice.h"
37 #include "devices/CECAudioSystem.h"
38 #include "devices/CECTV.h"
41 using namespace PLATFORM
;
43 #define LIB_CEC m_processor->GetLib()
44 #define ToString(x) LIB_CEC->ToString(x)
46 CCECClient::CCECClient(CCECProcessor
*processor
, const libcec_configuration
&configuration
) :
47 m_processor(processor
),
48 m_bInitialised(false),
50 m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN
),
53 // set the initial configuration
54 SetConfiguration(configuration
);
57 CCECClient::~CCECClient(void)
59 // unregister the client
60 if (m_processor
&& IsRegistered())
61 m_processor
->UnregisterClient(this);
64 bool CCECClient::IsInitialised(void)
66 CLockObject
lock(m_mutex
);
67 return m_bInitialised
&& m_processor
;
70 void CCECClient::SetInitialised(bool bSetTo
)
72 CLockObject
lock(m_mutex
);
73 m_bInitialised
= bSetTo
;
76 bool CCECClient::IsRegistered(void)
78 CLockObject
lock(m_mutex
);
79 return m_bRegistered
&& m_processor
;
82 void CCECClient::SetRegistered(bool bSetTo
)
84 CLockObject
lock(m_mutex
);
85 m_bRegistered
= bSetTo
;
88 bool CCECClient::OnRegister(void)
90 // return false if already initialised
94 // get all device we control
96 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
98 // return false when no devices were found
101 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "cannot find the primary device (logical address %x)", GetPrimaryLogicalAdddress());
105 // mark as initialised
106 SetInitialised(true);
108 // configure all devices
109 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
111 // only set our OSD name for the primary device
112 if ((*it
)->GetLogicalAddress() == GetPrimaryLogicalAdddress())
113 (*it
)->SetOSDName(m_configuration
.strDeviceName
);
115 // set the default menu language for devices we control
116 (*it
)->SetMenuLanguage(m_configuration
.strDeviceLanguage
);
119 // set the physical address
120 SetPhysicalAddress(m_configuration
);
122 // ensure that we know the vendor id of the TV, so we are using the correct handler
123 m_processor
->GetTV()->GetVendorId(GetPrimaryLogicalAdddress());
125 // make the primary device the active source if the option is set
126 if (m_configuration
.bActivateSource
== 1)
127 GetPrimaryDevice()->ActivateSource();
132 bool CCECClient::SetHDMIPort(const cec_logical_address iBaseDevice
, const uint8_t iPort
, bool bForce
/* = false */)
136 // limit the HDMI port range to 1-15
137 if (iPort
< CEC_MIN_HDMI_PORTNUMBER
||
138 iPort
> CEC_MAX_HDMI_PORTNUMBER
)
141 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "setting HDMI port to %d on device %s (%d)", iPort
, ToString(iBaseDevice
), (int)iBaseDevice
);
143 // update the configuration
145 CLockObject
lock(m_mutex
);
146 m_configuration
.baseDevice
= iBaseDevice
;
147 m_configuration
.iHDMIPort
= iPort
;
150 // don't continue if the connection isn't opened
151 if (!m_processor
->CECInitialised() && !bForce
)
154 // get the PA of the base device
155 uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS
);
156 CCECBusDevice
*baseDevice
= m_processor
->GetDevice(iBaseDevice
);
158 iPhysicalAddress
= baseDevice
->GetPhysicalAddress(GetPrimaryLogicalAdddress());
160 // add our port number
161 if (iPhysicalAddress
<= CEC_MAX_PHYSICAL_ADDRESS
)
163 if (iPhysicalAddress
== 0)
164 iPhysicalAddress
+= 0x1000 * iPort
;
165 else if (iPhysicalAddress
% 0x1000 == 0)
166 iPhysicalAddress
+= 0x100 * iPort
;
167 else if (iPhysicalAddress
% 0x100 == 0)
168 iPhysicalAddress
+= 0x10 * iPort
;
169 else if (iPhysicalAddress
% 0x10 == 0)
170 iPhysicalAddress
+= iPort
;
175 // set the default address when something went wrong
178 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "failed to set the physical address to %04X, setting it to the default value %04X", iPhysicalAddress
, CEC_DEFAULT_PHYSICAL_ADDRESS
);
179 iPhysicalAddress
= CEC_DEFAULT_PHYSICAL_ADDRESS
;
182 // and set the address
183 SetDevicePhysicalAddress(iPhysicalAddress
);
185 ConfigurationChanged(m_configuration
);
190 void CCECClient::ResetPhysicalAddress(void)
192 SetPhysicalAddress(m_configuration
);
195 void CCECClient::SetPhysicalAddress(const libcec_configuration
&configuration
)
197 // try to autodetect the address
199 if (m_processor
->CECInitialised() && configuration
.bAutodetectAddress
== 1)
200 bPASet
= AutodetectPhysicalAddress();
202 // try to use physical address setting
203 if (!bPASet
&& CLibCEC::IsValidPhysicalAddress(configuration
.iPhysicalAddress
))
204 bPASet
= SetPhysicalAddress(configuration
.iPhysicalAddress
);
206 // use the base device + hdmi port settings
208 bPASet
= SetHDMIPort(configuration
.baseDevice
, configuration
.iHDMIPort
);
210 // reset to defaults if something went wrong
213 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - resetting HDMI port and base device to defaults", __FUNCTION__
);
214 m_configuration
.baseDevice
= CECDEVICE_UNKNOWN
;
215 m_configuration
.iHDMIPort
= CEC_HDMI_PORTNUMBER_NONE
;
219 bool CCECClient::SetPhysicalAddress(const uint16_t iPhysicalAddress
)
221 // update the configuration
223 CLockObject
lock(m_mutex
);
224 if (m_configuration
.iPhysicalAddress
== iPhysicalAddress
)
226 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "physical address unchanged (%04X)", iPhysicalAddress
);
231 m_configuration
.iPhysicalAddress
= iPhysicalAddress
;
232 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "setting physical address to '%04X'", iPhysicalAddress
);
236 // persist the new configuration
237 m_processor
->PersistConfiguration(m_configuration
);
239 // set the physical address for each device
240 SetDevicePhysicalAddress(iPhysicalAddress
);
242 // and send back the updated configuration
243 ConfigurationChanged(m_configuration
);
248 bool CCECClient::AllocateLogicalAddresses(void)
250 // reset all previous LAs that were set
251 m_configuration
.logicalAddresses
.Clear();
253 // display an error if no device types are set
254 if (m_configuration
.deviceTypes
.IsEmpty())
256 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "no device types given");
260 // check each entry of the list
261 for (uint8_t iPtr
= 0; iPtr
< 5; iPtr
++)
263 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RESERVED
)
266 // find an LA for this type
267 cec_logical_address
address(CECDEVICE_UNKNOWN
);
268 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RECORDING_DEVICE
)
269 address
= AllocateLogicalAddressRecordingDevice();
270 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_TUNER
)
271 address
= AllocateLogicalAddressTuner();
272 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE
)
273 address
= AllocateLogicalAddressPlaybackDevice();
274 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_AUDIO_SYSTEM
)
275 address
= AllocateLogicalAddressAudioSystem();
277 // display an error if no LA could be allocated
278 if (address
== CECDEVICE_UNKNOWN
)
280 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s - failed to allocate device '%d', type '%s'", __FUNCTION__
, iPtr
, ToString(m_configuration
.deviceTypes
.types
[iPtr
]));
284 // display the registered LA
285 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - device '%d', type '%s', LA '%X'", __FUNCTION__
, iPtr
, ToString(m_configuration
.deviceTypes
.types
[iPtr
]), address
);
286 m_configuration
.logicalAddresses
.Set(address
);
292 cec_logical_address
CCECClient::AllocateLogicalAddressRecordingDevice(void)
294 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
296 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'recording device'");
297 if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1
))
298 retVal
= CECDEVICE_RECORDINGDEVICE1
;
299 else if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2
))
300 retVal
= CECDEVICE_RECORDINGDEVICE2
;
301 else if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3
))
302 retVal
= CECDEVICE_RECORDINGDEVICE3
;
307 cec_logical_address
CCECClient::AllocateLogicalAddressTuner(void)
309 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
311 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'tuner'");
312 if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER1
))
313 retVal
= CECDEVICE_TUNER1
;
314 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER2
))
315 retVal
= CECDEVICE_TUNER2
;
316 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER3
))
317 retVal
= CECDEVICE_TUNER3
;
318 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER4
))
319 retVal
= CECDEVICE_TUNER4
;
324 cec_logical_address
CCECClient::AllocateLogicalAddressPlaybackDevice(void)
326 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
328 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'playback device'");
329 if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1
))
330 retVal
= CECDEVICE_PLAYBACKDEVICE1
;
331 else if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2
))
332 retVal
= CECDEVICE_PLAYBACKDEVICE2
;
333 else if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3
))
334 retVal
= CECDEVICE_PLAYBACKDEVICE3
;
339 cec_logical_address
CCECClient::AllocateLogicalAddressAudioSystem(void)
341 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
343 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'audiosystem'");
344 if (m_processor
->TryLogicalAddress(CECDEVICE_AUDIOSYSTEM
))
345 retVal
= CECDEVICE_AUDIOSYSTEM
;
350 CCECBusDevice
*CCECClient::GetDeviceByType(const cec_device_type type
) const
352 // get all devices that match our logical addresses
353 CECDEVICEVEC devices
;
354 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
356 // filter the type we need
357 CCECDeviceMap::FilterType(type
, devices
);
359 return devices
.empty() ?
364 bool CCECClient::ChangeDeviceType(const cec_device_type from
, const cec_device_type to
)
366 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "changing device type '%s' into '%s'", ToString(from
), ToString(to
));
368 CLockObject
lock(m_mutex
);
370 // get the previous device that was allocated
371 CCECBusDevice
*previousDevice
= GetDeviceByType(from
);
375 // change the type in the device type list
376 bool bChanged(false);
377 for (uint8_t iPtr
= 0; iPtr
< 5; iPtr
++)
379 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RESERVED
)
382 if (m_configuration
.deviceTypes
.types
[iPtr
] == from
)
385 m_configuration
.deviceTypes
.types
[iPtr
] = to
;
387 else if (m_configuration
.deviceTypes
.types
[iPtr
] == to
&& bChanged
)
389 // ensure that dupes are removed
390 m_configuration
.deviceTypes
.types
[iPtr
] = CEC_DEVICE_TYPE_RESERVED
;
394 // re-register the client to set the new ackmask
395 if (!m_processor
->RegisterClient(this))
401 bool CCECClient::SetLogicalAddress(const cec_logical_address iLogicalAddress
)
403 CLockObject
lock(m_mutex
);
404 if (GetPrimaryLogicalAdddress() != iLogicalAddress
)
407 CLockObject
lock(m_mutex
);
408 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "<< setting primary logical address to %1x", iLogicalAddress
);
409 m_configuration
.logicalAddresses
.primary
= iLogicalAddress
;
410 m_configuration
.logicalAddresses
.Set(iLogicalAddress
);
412 return m_processor
->RegisterClient(this);
418 bool CCECClient::Transmit(const cec_command
&data
)
420 return m_processor
? m_processor
->Transmit(data
) : false;
423 bool CCECClient::SendPowerOnDevices(const cec_logical_address address
/* = CECDEVICE_TV */)
425 // if the broadcast address if set as destination and the client version >=1.5.0, read the wakeDevices setting
426 if (address
== CECDEVICE_BROADCAST
&& m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_5_0
)
428 CECDEVICEVEC devices
;
429 m_processor
->GetDevices()->GetWakeDevices(m_configuration
, devices
);
430 return m_processor
->PowerOnDevices(GetPrimaryLogicalAdddress(), devices
);
433 return m_processor
->PowerOnDevice(GetPrimaryLogicalAdddress(), address
);
436 bool CCECClient::SendStandbyDevices(const cec_logical_address address
/* = CECDEVICE_BROADCAST */)
438 // if the broadcast address if set as destination and the client version >=1.5.0, read the standbyDevices setting
439 if (address
== CECDEVICE_BROADCAST
&& m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_5_0
)
441 CECDEVICEVEC devices
;
442 m_processor
->GetDevices()->GetPowerOffDevices(m_configuration
, devices
);
443 return m_processor
->StandbyDevices(GetPrimaryLogicalAdddress(), devices
);
446 return m_processor
->StandbyDevice(GetPrimaryLogicalAdddress(), address
);
449 bool CCECClient::SendSetActiveSource(const cec_device_type type
/* = CEC_DEVICE_TYPE_RESERVED */)
451 // get the devices that are controlled by us
452 CECDEVICEVEC devices
;
453 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
455 // filter out the device that matches the given type
456 if (type
!= CEC_DEVICE_TYPE_RESERVED
)
457 CCECDeviceMap::FilterType(type
, devices
);
459 // no devices left, re-fetch the list of devices that are controlled by us
461 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
463 if (!devices
.empty())
465 // get the first device from the list
466 CCECBusDevice
*device
= *devices
.begin();
469 if (!m_processor
->CECInitialised())
470 device
->MarkAsActiveSource();
471 else if (device
->HasValidPhysicalAddress())
472 return device
->ActivateSource();
478 CCECPlaybackDevice
*CCECClient::GetPlaybackDevice(void)
480 CCECPlaybackDevice
*device(NULL
);
481 CECDEVICEVEC devices
;
483 // get the playback devices
484 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
485 CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE
, devices
);
487 // no matches, get the recording devices
490 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
491 CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_RECORDING_DEVICE
, devices
);
494 // get the first device that matches, and cast it to CCECPlaybackDevice
495 if (!devices
.empty())
496 device
= (*devices
.begin())->AsPlaybackDevice();
501 cec_logical_address
CCECClient::GetPrimaryLogicalAdddress(void)
503 CLockObject
lock(m_mutex
);
504 return m_configuration
.logicalAddresses
.primary
;
507 CCECBusDevice
*CCECClient::GetPrimaryDevice(void)
509 return m_processor
->GetDevice(GetPrimaryLogicalAdddress());
512 bool CCECClient::SendSetDeckControlMode(const cec_deck_control_mode mode
, bool bSendUpdate
/* = true */)
514 // find a playback device that we control
515 CCECPlaybackDevice
*device
= GetPlaybackDevice();
518 // and set the deck control mode if there is a match
519 device
->SetDeckControlMode(mode
);
521 return device
->TransmitDeckStatus(CECDEVICE_TV
);
529 bool CCECClient::SendSetDeckInfo(const cec_deck_info info
, bool bSendUpdate
/* = true */)
531 // find a playback device that we control
532 CCECPlaybackDevice
*device
= GetPlaybackDevice();
535 // and set the deck status if there is a match
536 device
->SetDeckStatus(info
);
538 return device
->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV
);
546 bool CCECClient::SendSetMenuState(const cec_menu_state state
, bool bSendUpdate
/* = true */)
548 CECDEVICEVEC devices
;
550 // set the menu state for all devices that are controlled by us
551 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
552 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
554 (*it
)->SetMenuState(state
);
556 (*it
)->TransmitMenuState(CECDEVICE_TV
);
562 bool CCECClient::SendSetInactiveView(void)
564 CECDEVICEVEC devices
;
566 // mark all devices that are controlled by us as inactive source
567 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
568 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
570 if ((*it
)->IsActiveSource())
572 (*it
)->MarkAsInactiveSource();
573 return (*it
)->TransmitInactiveSource();
580 bool CCECClient::SendSetOSDString(const cec_logical_address iLogicalAddress
, const cec_display_control duration
, const char *strMessage
)
582 CCECBusDevice
*primary
= GetPrimaryDevice();
584 return primary
->TransmitOSDString(iLogicalAddress
, duration
, strMessage
);
589 cec_version
CCECClient::GetDeviceCecVersion(const cec_logical_address iAddress
)
591 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
593 return device
->GetCecVersion(GetPrimaryLogicalAdddress());
594 return CEC_VERSION_UNKNOWN
;
597 bool CCECClient::GetDeviceMenuLanguage(const cec_logical_address iAddress
, cec_menu_language
&language
)
599 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
602 language
= device
->GetMenuLanguage(GetPrimaryLogicalAdddress());
603 return (strcmp(language
.language
, "???") != 0);
608 cec_osd_name
CCECClient::GetDeviceOSDName(const cec_logical_address iAddress
)
611 retVal
.device
= iAddress
;
614 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
617 CStdString strOSDName
= device
->GetOSDName(GetPrimaryLogicalAdddress());
618 snprintf(retVal
.name
, sizeof(retVal
.name
), "%s", strOSDName
.c_str());
619 retVal
.device
= iAddress
;
625 uint16_t CCECClient::GetDevicePhysicalAddress(const cec_logical_address iAddress
)
627 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
629 return device
->GetPhysicalAddress(GetPrimaryLogicalAdddress());
630 return CEC_INVALID_PHYSICAL_ADDRESS
;
633 cec_power_status
CCECClient::GetDevicePowerStatus(const cec_logical_address iAddress
)
635 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
637 return device
->GetPowerStatus(GetPrimaryLogicalAdddress());
638 return CEC_POWER_STATUS_UNKNOWN
;
641 uint64_t CCECClient::GetDeviceVendorId(const cec_logical_address iAddress
)
643 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
645 return device
->GetVendorId(GetPrimaryLogicalAdddress());
646 return CEC_VENDOR_UNKNOWN
;
649 uint8_t CCECClient::SendVolumeUp(bool bSendRelease
/* = true */)
651 CCECBusDevice
*device
= GetPrimaryDevice();
652 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
654 return device
&& audio
&& audio
->IsPresent() ?
655 audio
->VolumeUp(device
->GetLogicalAddress(), bSendRelease
) :
656 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
659 uint8_t CCECClient::SendVolumeDown(bool bSendRelease
/* = true */)
661 CCECBusDevice
*device
= GetPrimaryDevice();
662 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
664 return device
&& audio
&& audio
->IsPresent() ?
665 audio
->VolumeDown(device
->GetLogicalAddress(), bSendRelease
) :
666 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
669 uint8_t CCECClient::SendMuteAudio(void)
671 CCECBusDevice
*device
= GetPrimaryDevice();
672 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
674 return device
&& audio
&& audio
->IsPresent() ?
675 audio
->MuteAudio(device
->GetLogicalAddress()) :
676 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
679 bool CCECClient::SendKeypress(const cec_logical_address iDestination
, const cec_user_control_code key
, bool bWait
/* = true */)
681 CCECBusDevice
*device
= GetPrimaryDevice();
682 CCECBusDevice
*dest
= m_processor
->GetDevice(iDestination
);
684 return device
&& dest
?
685 device
->TransmitKeypress(GetPrimaryLogicalAdddress(), key
, bWait
) :
689 bool CCECClient::SendKeyRelease(const cec_logical_address iDestination
, bool bWait
/* = true */)
691 CCECBusDevice
*device
= GetPrimaryDevice();
692 CCECBusDevice
*dest
= m_processor
->GetDevice(iDestination
);
694 return device
&& dest
?
695 device
->TransmitKeyRelease(GetPrimaryLogicalAdddress(), bWait
) :
699 bool CCECClient::GetCurrentConfiguration(libcec_configuration
&configuration
)
701 CLockObject
lock(m_mutex
);
703 // client version 1.5.0
704 snprintf(configuration
.strDeviceName
, 13, "%s", m_configuration
.strDeviceName
);
705 configuration
.deviceTypes
= m_configuration
.deviceTypes
;
706 configuration
.bAutodetectAddress
= m_configuration
.bAutodetectAddress
;
707 configuration
.iPhysicalAddress
= m_configuration
.iPhysicalAddress
;
708 configuration
.baseDevice
= m_configuration
.baseDevice
;
709 configuration
.iHDMIPort
= m_configuration
.iHDMIPort
;
710 configuration
.clientVersion
= m_configuration
.clientVersion
;
711 configuration
.serverVersion
= m_configuration
.serverVersion
;
712 configuration
.tvVendor
= m_configuration
.tvVendor
;
714 configuration
.bGetSettingsFromROM
= m_configuration
.bGetSettingsFromROM
;
715 configuration
.bUseTVMenuLanguage
= m_configuration
.bUseTVMenuLanguage
;
716 configuration
.bActivateSource
= m_configuration
.bActivateSource
;
717 configuration
.wakeDevices
= m_configuration
.wakeDevices
;
718 configuration
.powerOffDevices
= m_configuration
.powerOffDevices
;
719 configuration
.bPowerOffScreensaver
= m_configuration
.bPowerOffScreensaver
;
720 configuration
.bPowerOffOnStandby
= m_configuration
.bPowerOffOnStandby
;
722 // client version 1.5.1
723 if (configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_5_1
)
724 configuration
.bSendInactiveSource
= m_configuration
.bSendInactiveSource
;
726 // client version 1.5.3
727 if (configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_5_3
)
728 configuration
.logicalAddresses
= m_configuration
.logicalAddresses
;
730 // client version 1.6.0
731 if (configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_6_0
)
733 configuration
.iFirmwareVersion
= m_configuration
.iFirmwareVersion
;
734 configuration
.bPowerOffDevicesOnStandby
= m_configuration
.bPowerOffDevicesOnStandby
;
735 configuration
.bShutdownOnStandby
= m_configuration
.bShutdownOnStandby
;
738 // client version 1.6.2
739 if (configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_6_2
)
741 memcpy(configuration
.strDeviceLanguage
, m_configuration
.strDeviceLanguage
, 3);
742 configuration
.iFirmwareBuildDate
= m_configuration
.iFirmwareBuildDate
;
745 // client version 1.6.3
746 if (configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_6_3
)
748 configuration
.bMonitorOnly
= m_configuration
.bMonitorOnly
;
754 bool CCECClient::SetConfiguration(const libcec_configuration
&configuration
)
756 bool bIsRunning(m_processor
&& m_processor
->CECInitialised());
757 CCECBusDevice
*primary
= bIsRunning
? GetPrimaryDevice() : NULL
;
758 uint16_t iPA
= primary
? primary
->GetCurrentPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS
;
760 // update the callbacks
761 if (configuration
.callbacks
)
762 EnableCallbacks(configuration
.callbackParam
, configuration
.callbacks
);
764 // update the client version
765 SetClientVersion((cec_client_version
)configuration
.clientVersion
);
767 // update the OSD name
768 CStdString
strOSDName(configuration
.strDeviceName
);
769 SetOSDName(strOSDName
);
771 // update the TV vendor override
772 SetTVVendorOverride((cec_vendor_id
)configuration
.tvVendor
);
776 CLockObject
lock(m_mutex
);
777 m_configuration
.bUseTVMenuLanguage
= configuration
.bUseTVMenuLanguage
;
778 m_configuration
.bActivateSource
= configuration
.bActivateSource
;
779 m_configuration
.bGetSettingsFromROM
= configuration
.bGetSettingsFromROM
;
780 m_configuration
.wakeDevices
= configuration
.wakeDevices
;
781 m_configuration
.powerOffDevices
= configuration
.powerOffDevices
;
782 m_configuration
.bPowerOffScreensaver
= configuration
.bPowerOffScreensaver
;
783 m_configuration
.bPowerOffOnStandby
= configuration
.bPowerOffOnStandby
;
785 // client version 1.5.1
786 if (configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_5_1
)
787 m_configuration
.bSendInactiveSource
= configuration
.bSendInactiveSource
;
789 // client version 1.6.0
790 if (configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_6_0
)
792 m_configuration
.bPowerOffDevicesOnStandby
= configuration
.bPowerOffDevicesOnStandby
;
793 m_configuration
.bShutdownOnStandby
= configuration
.bShutdownOnStandby
;
796 // client version 1.6.2
797 if (configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_6_2
)
799 memcpy(m_configuration
.strDeviceLanguage
, configuration
.strDeviceLanguage
, 3);
802 // client version 1.6.3
803 if (configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_6_3
)
805 m_configuration
.bMonitorOnly
= configuration
.bMonitorOnly
;
808 // ensure that there is at least 1 device type set
809 if (m_configuration
.deviceTypes
.IsEmpty())
810 m_configuration
.deviceTypes
.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE
);
813 bool bNeedReinit(false);
816 if (SetDeviceTypes(configuration
.deviceTypes
))
818 // the device type changed. just copy the rest, and re-register
820 CLockObject
lock(m_mutex
);
821 m_configuration
.iPhysicalAddress
= configuration
.iPhysicalAddress
;
822 m_configuration
.baseDevice
= configuration
.baseDevice
;
823 m_configuration
.iHDMIPort
= configuration
.iHDMIPort
;
829 // set the physical address
830 SetPhysicalAddress(configuration
);
833 m_processor
->PersistConfiguration(m_configuration
);
836 primary
= GetPrimaryDevice();
838 if (bNeedReinit
|| !primary
|| primary
->GetCurrentPhysicalAddress() != iPA
)
840 // PA or device type changed
841 m_processor
->RegisterClient(this);
843 else if (primary
&& configuration
.bActivateSource
== 1 && bIsRunning
&& !primary
->IsActiveSource())
845 // activate the source if we're not already the active source
846 primary
->ActivateSource();
852 void CCECClient::AddCommand(const cec_command
&command
)
854 CLockObject
lock(m_mutex
);
856 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, ">> %s (%X) -> %s (%X): %s (%2X)", ToString(command
.initiator
), command
.initiator
, ToString(command
.destination
), command
.destination
, ToString(command
.opcode
), command
.opcode
);
858 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecCommand
)
859 m_configuration
.callbacks
->CBCecCommand(m_configuration
.callbackParam
, command
);
860 else if (!m_commandBuffer
.Push(command
))
861 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "command buffer is full");
864 int CCECClient::MenuStateChanged(const cec_menu_state newState
)
866 CLockObject
lock(m_mutex
);
868 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, ">> %s: %s", ToString(CEC_OPCODE_MENU_REQUEST
), ToString(newState
));
870 if (m_configuration
.callbacks
&&
871 m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_6_2
&&
872 m_configuration
.callbacks
->CBCecMenuStateChanged
)
873 return m_configuration
.callbacks
->CBCecMenuStateChanged(m_configuration
.callbackParam
, newState
);
878 void CCECClient::Alert(const libcec_alert type
, const libcec_parameter
¶m
)
880 CLockObject
lock(m_mutex
);
882 if (m_configuration
.callbacks
&&
883 m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_6_0
&&
884 m_configuration
.callbacks
->CBCecAlert
)
885 m_configuration
.callbacks
->CBCecAlert(m_configuration
.callbackParam
, type
, param
);
888 void CCECClient::AddLog(const cec_log_message
&message
)
890 CLockObject
lock(m_logMutex
);
891 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecLogMessage
)
892 m_configuration
.callbacks
->CBCecLogMessage(m_configuration
.callbackParam
, message
);
894 m_logBuffer
.Push(message
);
897 void CCECClient::AddKey(void)
899 CLockObject
lock(m_mutex
);
901 if (m_iCurrentButton
!= CEC_USER_CONTROL_CODE_UNKNOWN
)
905 key
.duration
= (unsigned int) (GetTimeMs() - m_buttontime
);
906 key
.keycode
= m_iCurrentButton
;
907 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "key released: %1x", key
.keycode
);
909 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecKeyPress
)
910 m_configuration
.callbacks
->CBCecKeyPress(m_configuration
.callbackParam
, key
);
912 m_keyBuffer
.Push(key
);
913 m_iCurrentButton
= CEC_USER_CONTROL_CODE_UNKNOWN
;
919 void CCECClient::AddKey(const cec_keypress
&key
)
921 CLockObject
lock(m_mutex
);
923 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "key pressed: %1x", key
.keycode
);
925 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecKeyPress
)
926 m_configuration
.callbacks
->CBCecKeyPress(m_configuration
.callbackParam
, key
);
928 m_keyBuffer
.Push(key
);
930 m_iCurrentButton
= key
.duration
> 0 ? CEC_USER_CONTROL_CODE_UNKNOWN
: key
.keycode
;
931 m_buttontime
= key
.duration
> 0 ? 0 : GetTimeMs();
934 void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode
)
936 // push a keypress to the buffer with 0 duration and another with the duration set when released
939 key
.keycode
= iButtonCode
;
944 void CCECClient::CheckKeypressTimeout(void)
946 if (m_iCurrentButton
!= CEC_USER_CONTROL_CODE_UNKNOWN
&& GetTimeMs() - m_buttontime
> CEC_BUTTON_TIMEOUT
)
949 m_iCurrentButton
= CEC_USER_CONTROL_CODE_UNKNOWN
;
953 void CCECClient::ConfigurationChanged(const libcec_configuration
&config
)
955 CLockObject
lock(m_mutex
);
957 if (m_configuration
.callbacks
&&
958 m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_5_0
&&
959 m_configuration
.callbacks
->CBCecConfigurationChanged
&&
960 m_processor
->CECInitialised())
961 m_configuration
.callbacks
->CBCecConfigurationChanged(m_configuration
.callbackParam
, config
);
964 bool CCECClient::EnableCallbacks(void *cbParam
, ICECCallbacks
*callbacks
)
966 CLockObject
lock(m_mutex
);
967 m_configuration
.callbackParam
= cbParam
;
968 m_configuration
.callbacks
= callbacks
;
972 bool CCECClient::PingAdapter(void)
974 return m_processor
? m_processor
->PingAdapter() : false;
977 bool CCECClient::GetNextLogMessage(cec_log_message
*message
)
979 return (m_logBuffer
.Pop(*message
));
982 bool CCECClient::GetNextKeypress(cec_keypress
*key
)
984 return m_keyBuffer
.Pop(*key
);
987 bool CCECClient::GetNextCommand(cec_command
*command
)
989 return m_commandBuffer
.Pop(*command
);
992 CStdString
CCECClient::GetConnectionInfo(void)
995 strLog
.Format("libCEC version = %s, client version = %s, firmware version = %d", ToString((cec_server_version
)m_configuration
.serverVersion
), ToString((cec_client_version
)m_configuration
.clientVersion
), m_configuration
.iFirmwareVersion
);
996 if (m_configuration
.iFirmwareBuildDate
!= CEC_FW_BUILD_UNKNOWN
)
998 time_t buildTime
= (time_t)m_configuration
.iFirmwareBuildDate
;
999 strLog
.AppendFormat(", firmware build date: %s", asctime(gmtime(&buildTime
)));
1000 strLog
= strLog
.Left((int)strLog
.length() - 1); // strip \n added by asctime
1001 strLog
.append(" +0000");
1004 // log the addresses that are being used
1005 if (!m_configuration
.logicalAddresses
.IsEmpty())
1007 strLog
.append(", logical address(es) = ");
1008 CECDEVICEVEC devices
;
1009 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
1010 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
1011 strLog
.AppendFormat("%s (%X) ", (*it
)->GetLogicalAddressName(), (*it
)->GetLogicalAddress());
1014 if (!CLibCEC::IsValidPhysicalAddress(m_configuration
.iPhysicalAddress
))
1015 strLog
.AppendFormat(", base device: %s (%X), HDMI port number: %d", ToString(m_configuration
.baseDevice
), m_configuration
.baseDevice
, m_configuration
.iHDMIPort
);
1017 strLog
.AppendFormat(", physical address: %04x", m_configuration
.iPhysicalAddress
);
1022 void CCECClient::SetTVVendorOverride(const cec_vendor_id id
)
1025 CLockObject
lock(m_mutex
);
1026 m_configuration
.tvVendor
= id
;
1029 if (id
!= CEC_VENDOR_UNKNOWN
)
1031 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - vendor id '%s'", __FUNCTION__
, ToString(id
));
1033 CCECBusDevice
*tv
= m_processor
? m_processor
->GetTV() : NULL
;
1035 tv
->SetVendorId((uint64_t)id
);
1039 cec_vendor_id
CCECClient::GetTVVendorOverride(void)
1041 CLockObject
lock(m_mutex
);
1042 return (cec_vendor_id
)m_configuration
.tvVendor
;
1045 void CCECClient::SetOSDName(const CStdString
&strDeviceName
)
1048 CLockObject
lock(m_mutex
);
1049 snprintf(m_configuration
.strDeviceName
, 13, "%s", strDeviceName
.c_str());
1052 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using OSD name '%s'", __FUNCTION__
, strDeviceName
.c_str());
1054 CCECBusDevice
*primary
= GetPrimaryDevice();
1055 if (primary
&& !primary
->GetCurrentOSDName().Equals(strDeviceName
))
1057 primary
->SetOSDName(strDeviceName
);
1058 if (m_processor
&& m_processor
->CECInitialised())
1059 primary
->TransmitOSDName(CECDEVICE_TV
);
1063 CStdString
CCECClient::GetOSDName(void)
1065 CLockObject
lock(m_mutex
);
1066 CStdString
strOSDName(m_configuration
.strDeviceName
);
1070 void CCECClient::SetWakeDevices(const cec_logical_addresses
&addresses
)
1072 CLockObject
lock(m_mutex
);
1073 m_configuration
.wakeDevices
= addresses
;
1076 cec_logical_addresses
CCECClient::GetWakeDevices(void)
1078 CLockObject
lock(m_mutex
);
1079 return m_configuration
.wakeDevices
;
1082 bool CCECClient::AutodetectPhysicalAddress(void)
1084 bool bPhysicalAutodetected(false);
1085 uint16_t iPhysicalAddress
= m_processor
? m_processor
->GetDetectedPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS
;
1087 if (CLibCEC::IsValidPhysicalAddress(iPhysicalAddress
))
1089 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - autodetected physical address '%04X'", __FUNCTION__
, iPhysicalAddress
);
1091 CLockObject
lock(m_mutex
);
1092 m_configuration
.iPhysicalAddress
= iPhysicalAddress
;
1093 m_configuration
.iHDMIPort
= CEC_HDMI_PORTNUMBER_NONE
;
1094 m_configuration
.baseDevice
= CECDEVICE_UNKNOWN
;
1095 bPhysicalAutodetected
= true;
1098 SetDevicePhysicalAddress(iPhysicalAddress
);
1100 return bPhysicalAutodetected
;
1103 void CCECClient::SetClientVersion(const cec_client_version version
)
1105 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using client version '%s'", __FUNCTION__
, ToString(version
));
1107 CLockObject
lock(m_mutex
);
1108 m_configuration
.clientVersion
= (uint32_t)version
;
1111 cec_client_version
CCECClient::GetClientVersion(void)
1113 CLockObject
lock(m_mutex
);
1114 return (cec_client_version
)m_configuration
.clientVersion
;
1117 bool CCECClient::SetDeviceTypes(const cec_device_type_list
&deviceTypes
)
1119 bool bNeedReinit(false);
1122 CLockObject
lock(m_mutex
);
1123 bNeedReinit
= m_processor
&& m_processor
->CECInitialised() &&
1124 (m_configuration
.deviceTypes
!= deviceTypes
);
1125 m_configuration
.deviceTypes
= deviceTypes
;
1129 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using primary device type '%s'", __FUNCTION__
, ToString(deviceTypes
[0]));
1134 cec_device_type_list
CCECClient::GetDeviceTypes(void)
1136 cec_device_type_list retVal
;
1137 CLockObject
lock(m_mutex
);
1138 retVal
= m_configuration
.deviceTypes
;
1142 bool CCECClient::SetDevicePhysicalAddress(const uint16_t iPhysicalAddress
)
1144 if (!CLibCEC::IsValidPhysicalAddress(iPhysicalAddress
))
1147 // reconfigure all devices
1148 cec_logical_address
reactivateSource(CECDEVICE_UNKNOWN
);
1149 CECDEVICEVEC devices
;
1150 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
1151 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
1153 // if this device was the active source, reactivate it afterwards
1154 if ((*it
)->IsActiveSource())
1155 reactivateSource
= (*it
)->GetLogicalAddress();
1157 // mark the device as inactive source
1158 if (IsInitialised())
1159 (*it
)->MarkAsInactiveSource();
1161 // set the new physical address
1162 (*it
)->SetPhysicalAddress(iPhysicalAddress
);
1165 if (IsInitialised())
1166 (*it
)->TransmitPhysicalAddress();
1169 // reactivate the previous active source
1170 if (reactivateSource
!= CECDEVICE_UNKNOWN
&&
1171 m_processor
->CECInitialised() &&
1174 CCECBusDevice
*device
= m_processor
->GetDevice(reactivateSource
);
1176 device
->ActivateSource();
1182 bool CCECClient::SwitchMonitoring(bool bEnable
)
1184 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "== %s monitoring mode ==", bEnable
? "enabling" : "disabling");
1189 return m_processor
->UnregisterClient(this);
1192 m_configuration
.bMonitorOnly
= false;
1193 return m_processor
->RegisterClient(this);
1200 bool CCECClient::PollDevice(const cec_logical_address iAddress
)
1202 // try to find the primary device
1203 CCECBusDevice
*primary
= GetPrimaryDevice();
1204 // poll the destination, with the primary as source
1206 return primary
->TransmitPoll(iAddress
);
1208 return m_processor
? m_processor
->PollDevice(iAddress
) : false;
1211 cec_logical_addresses
CCECClient::GetActiveDevices(void)
1213 CECDEVICEVEC activeDevices
;
1215 m_processor
->GetDevices()->GetActive(activeDevices
);
1216 return CCECDeviceMap::ToLogicalAddresses(activeDevices
);
1219 bool CCECClient::IsActiveDevice(const cec_logical_address iAddress
)
1221 cec_logical_addresses activeDevices
= GetActiveDevices();
1222 return activeDevices
.IsSet(iAddress
);
1225 bool CCECClient::IsActiveDeviceType(const cec_device_type type
)
1227 CECDEVICEVEC activeDevices
;
1229 m_processor
->GetDevices()->GetActive(activeDevices
);
1230 CCECDeviceMap::FilterType(type
, activeDevices
);
1231 return !activeDevices
.empty();
1234 cec_logical_address
CCECClient::GetActiveSource(void)
1236 return m_processor
? m_processor
->GetActiveSource() : CECDEVICE_UNKNOWN
;
1239 bool CCECClient::IsActiveSource(const cec_logical_address iAddress
)
1241 return m_processor
? m_processor
->IsActiveSource(iAddress
) : false;
1244 bool CCECClient::SetStreamPath(const cec_logical_address iAddress
)
1246 uint16_t iPhysicalAddress
= GetDevicePhysicalAddress(iAddress
);
1247 if (iPhysicalAddress
!= CEC_INVALID_PHYSICAL_ADDRESS
)
1248 return SetStreamPath(iPhysicalAddress
);
1252 bool CCECClient::SetStreamPath(const uint16_t iPhysicalAddress
)
1254 return m_processor
? m_processor
->SetStreamPath(iPhysicalAddress
) : false;
1257 cec_logical_addresses
CCECClient::GetLogicalAddresses(void)
1259 cec_logical_addresses addresses
;
1260 CLockObject
lock(m_mutex
);
1261 addresses
= m_configuration
.logicalAddresses
;
1265 bool CCECClient::CanPersistConfiguration(void)
1267 return m_processor
? m_processor
->CanPersistConfiguration() : false;
1270 bool CCECClient::PersistConfiguration(const libcec_configuration
&configuration
)
1272 return m_processor
? m_processor
->PersistConfiguration(configuration
) : false;
1275 void CCECClient::RescanActiveDevices(void)
1278 m_processor
->RescanActiveDevices();
1281 bool CCECClient::IsLibCECActiveSource(void)
1283 bool bReturn(false);
1286 cec_logical_address activeSource
= m_processor
->GetActiveSource();
1287 CCECBusDevice
*device
= m_processor
->GetDevice(activeSource
);
1289 bReturn
= device
->IsHandledByLibCEC();