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/
34 #include "CECClient.h"
36 #include "CECProcessor.h"
38 #include "CECTypeUtils.h"
39 #include "devices/CECPlaybackDevice.h"
40 #include "devices/CECAudioSystem.h"
41 #include "devices/CECTV.h"
42 #include "implementations/CECCommandHandler.h"
45 using namespace PLATFORM
;
47 #define LIB_CEC m_processor->GetLib()
48 #define ToString(x) CCECTypeUtils::ToString(x)
50 #define COMBO_KEY CEC_USER_CONTROL_CODE_STOP
51 #define COMBO_TIMEOUT_MS 1000
53 CCECClient::CCECClient(CCECProcessor
*processor
, const libcec_configuration
&configuration
) :
54 m_processor(processor
),
55 m_bInitialised(false),
57 m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN
),
59 m_iPreventForwardingPowerOffCommand(0),
60 m_iLastKeypressTime(0)
62 m_lastKeypress
.keycode
= CEC_USER_CONTROL_CODE_UNKNOWN
;
63 m_lastKeypress
.duration
= 0;
64 m_configuration
.Clear();
65 // set the initial configuration
66 SetConfiguration(configuration
);
69 CCECClient::~CCECClient(void)
71 // unregister the client
72 if (m_processor
&& IsRegistered())
73 m_processor
->UnregisterClient(this);
76 bool CCECClient::IsInitialised(void)
78 CLockObject
lock(m_mutex
);
79 return m_bInitialised
&& m_processor
;
82 void CCECClient::SetInitialised(bool bSetTo
)
84 CLockObject
lock(m_mutex
);
85 m_bInitialised
= bSetTo
;
88 bool CCECClient::IsRegistered(void)
90 CLockObject
lock(m_mutex
);
91 return m_bRegistered
&& m_processor
;
94 void CCECClient::SetRegistered(bool bSetTo
)
96 CLockObject
lock(m_mutex
);
97 m_bRegistered
= bSetTo
;
100 bool CCECClient::OnRegister(void)
102 // return false if already initialised
106 // get all device we control
107 CECDEVICEVEC devices
;
108 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
110 // return false when no devices were found
113 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "cannot find the primary device (logical address %x)", GetPrimaryLogicalAdddress());
117 // mark as initialised
118 SetInitialised(true);
120 // configure all devices
121 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
123 // only set our OSD name for the primary device
124 if ((*it
)->GetLogicalAddress() == GetPrimaryLogicalAdddress())
125 (*it
)->SetOSDName(m_configuration
.strDeviceName
);
127 // set the default menu language for devices we control
128 (*it
)->SetMenuLanguage(m_configuration
.strDeviceLanguage
);
131 // set the physical address
132 SetPhysicalAddress(m_configuration
);
134 // make the primary device the active source if the option is set
135 if (m_configuration
.bActivateSource
== 1)
136 GetPrimaryDevice()->ActivateSource(500);
141 bool CCECClient::SetHDMIPort(const cec_logical_address iBaseDevice
, const uint8_t iPort
, bool bForce
/* = false */)
145 // limit the HDMI port range to 1-15
146 if (iPort
< CEC_MIN_HDMI_PORTNUMBER
||
147 iPort
> CEC_MAX_HDMI_PORTNUMBER
)
150 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "setting HDMI port to %d on device %s (%d)", iPort
, ToString(iBaseDevice
), (int)iBaseDevice
);
152 // update the configuration
154 CLockObject
lock(m_mutex
);
155 m_configuration
.baseDevice
= iBaseDevice
;
156 m_configuration
.iHDMIPort
= iPort
;
159 // don't continue if the connection isn't opened
160 if (!m_processor
->CECInitialised() && !bForce
)
163 // get the PA of the base device
164 uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS
);
165 CCECBusDevice
*baseDevice
= m_processor
->GetDevice(iBaseDevice
);
167 iPhysicalAddress
= baseDevice
->GetPhysicalAddress(GetPrimaryLogicalAdddress());
169 // add our port number
170 if (iPhysicalAddress
<= CEC_MAX_PHYSICAL_ADDRESS
)
172 if (iPhysicalAddress
== 0)
173 iPhysicalAddress
+= 0x1000 * iPort
;
174 else if (iPhysicalAddress
% 0x1000 == 0)
175 iPhysicalAddress
+= 0x100 * iPort
;
176 else if (iPhysicalAddress
% 0x100 == 0)
177 iPhysicalAddress
+= 0x10 * iPort
;
178 else if (iPhysicalAddress
% 0x10 == 0)
179 iPhysicalAddress
+= iPort
;
184 // set the default address when something went wrong
187 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
);
188 iPhysicalAddress
= CEC_DEFAULT_PHYSICAL_ADDRESS
;
191 // and set the address
192 SetDevicePhysicalAddress(iPhysicalAddress
);
194 CallbackConfigurationChanged(m_configuration
);
199 void CCECClient::ResetPhysicalAddress(void)
201 SetPhysicalAddress(m_configuration
);
204 void CCECClient::SetPhysicalAddress(const libcec_configuration
&configuration
)
208 // override the physical address from configuration.iPhysicalAddress if it's set
209 if (!bPASet
&& CLibCEC::IsValidPhysicalAddress(configuration
.iPhysicalAddress
))
210 bPASet
= SetPhysicalAddress(configuration
.iPhysicalAddress
);
212 // try to autodetect the address
213 if (!bPASet
&& m_processor
->CECInitialised())
215 bPASet
= AutodetectPhysicalAddress();
216 m_configuration
.bAutodetectAddress
= bPASet
? 1 : 0;
219 // use the base device + hdmi port settings
221 bPASet
= SetHDMIPort(configuration
.baseDevice
, configuration
.iHDMIPort
);
223 // reset to defaults if something went wrong
226 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - resetting HDMI port and base device to defaults", __FUNCTION__
);
227 m_configuration
.baseDevice
= CECDEVICE_UNKNOWN
;
228 m_configuration
.iHDMIPort
= CEC_HDMI_PORTNUMBER_NONE
;
232 bool CCECClient::SetPhysicalAddress(const uint16_t iPhysicalAddress
)
234 // update the configuration
237 CLockObject
lock(m_mutex
);
238 if (m_configuration
.iPhysicalAddress
== iPhysicalAddress
)
241 m_configuration
.iPhysicalAddress
= iPhysicalAddress
;
245 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "physical address unchanged (%04X)", iPhysicalAddress
);
249 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "setting physical address to '%04X'", iPhysicalAddress
);
251 // set the physical address for each device
252 SetDevicePhysicalAddress(iPhysicalAddress
);
254 // and send back the updated configuration
255 CallbackConfigurationChanged(m_configuration
);
260 void CCECClient::SetSupportedDeviceTypes(void)
262 cec_device_type_list types
;
265 // get the command handler for the tv
266 CCECCommandHandler
*tvHandler
= m_processor
->GetTV()->GetHandler();
270 // check all device types
271 for (uint8_t iPtr
= 0; iPtr
< 5; iPtr
++)
273 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RESERVED
)
276 // get the supported device type. the handler will replace types it doesn't support by one it does support
277 cec_device_type type
= tvHandler
->GetReplacementDeviceType(m_configuration
.deviceTypes
.types
[iPtr
]);
278 if (!types
.IsSet(type
))
281 m_processor
->GetTV()->MarkHandlerReady();
283 // set the new type list
284 m_configuration
.deviceTypes
= types
;
286 // persist the new configuration
287 PersistConfiguration(m_configuration
);
290 bool CCECClient::AllocateLogicalAddresses(void)
292 // reset all previous LAs that were set
293 m_configuration
.logicalAddresses
.Clear();
295 // get the supported device types from the command handler of the TV
296 SetSupportedDeviceTypes();
298 // display an error if no device types are set
299 if (m_configuration
.deviceTypes
.IsEmpty())
301 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "no device types given");
305 // check each entry of the list
306 for (uint8_t iPtr
= 0; iPtr
< 5; iPtr
++)
308 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RESERVED
)
311 // find an LA for this type
312 cec_logical_address
address(CECDEVICE_UNKNOWN
);
313 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RECORDING_DEVICE
)
314 address
= AllocateLogicalAddressRecordingDevice();
315 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_TUNER
)
316 address
= AllocateLogicalAddressTuner();
317 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE
)
318 address
= AllocateLogicalAddressPlaybackDevice();
319 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_AUDIO_SYSTEM
)
320 address
= AllocateLogicalAddressAudioSystem();
322 // display an error if no LA could be allocated
323 if (address
== CECDEVICE_UNKNOWN
)
325 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s - failed to allocate device '%d', type '%s'", __FUNCTION__
, iPtr
, ToString(m_configuration
.deviceTypes
.types
[iPtr
]));
329 // display the registered LA
330 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - device '%d', type '%s', LA '%X'", __FUNCTION__
, iPtr
, ToString(m_configuration
.deviceTypes
.types
[iPtr
]), address
);
331 m_configuration
.logicalAddresses
.Set(address
);
334 // persist the new configuration
335 PersistConfiguration(m_configuration
);
340 cec_logical_address
CCECClient::AllocateLogicalAddressRecordingDevice(void)
342 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
344 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'recording device'");
345 if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1
, m_configuration
.cecVersion
))
346 retVal
= CECDEVICE_RECORDINGDEVICE1
;
347 else if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2
, m_configuration
.cecVersion
))
348 retVal
= CECDEVICE_RECORDINGDEVICE2
;
349 else if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3
, m_configuration
.cecVersion
))
350 retVal
= CECDEVICE_RECORDINGDEVICE3
;
355 cec_logical_address
CCECClient::AllocateLogicalAddressTuner(void)
357 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
359 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'tuner'");
360 if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER1
, m_configuration
.cecVersion
))
361 retVal
= CECDEVICE_TUNER1
;
362 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER2
, m_configuration
.cecVersion
))
363 retVal
= CECDEVICE_TUNER2
;
364 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER3
, m_configuration
.cecVersion
))
365 retVal
= CECDEVICE_TUNER3
;
366 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER4
, m_configuration
.cecVersion
))
367 retVal
= CECDEVICE_TUNER4
;
372 cec_logical_address
CCECClient::AllocateLogicalAddressPlaybackDevice(void)
374 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
376 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'playback device'");
377 if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1
, m_configuration
.cecVersion
))
378 retVal
= CECDEVICE_PLAYBACKDEVICE1
;
379 else if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2
, m_configuration
.cecVersion
))
380 retVal
= CECDEVICE_PLAYBACKDEVICE2
;
381 else if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3
, m_configuration
.cecVersion
))
382 retVal
= CECDEVICE_PLAYBACKDEVICE3
;
387 cec_logical_address
CCECClient::AllocateLogicalAddressAudioSystem(void)
389 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
391 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'audiosystem'");
392 if (m_processor
->TryLogicalAddress(CECDEVICE_AUDIOSYSTEM
, m_configuration
.cecVersion
))
393 retVal
= CECDEVICE_AUDIOSYSTEM
;
398 CCECBusDevice
*CCECClient::GetDeviceByType(const cec_device_type type
) const
400 // get all devices that match our logical addresses
401 CECDEVICEVEC devices
;
402 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
404 // filter the type we need
405 CCECDeviceMap::FilterType(type
, devices
);
407 return devices
.empty() ?
412 bool CCECClient::ChangeDeviceType(const cec_device_type from
, const cec_device_type to
)
417 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "changing device type '%s' into '%s'", ToString(from
), ToString(to
));
420 CLockObject
lock(m_mutex
);
422 // get the previous device that was allocated
423 CCECBusDevice
*previousDevice
= GetDeviceByType(from
);
427 // change the type in the device type list
428 bool bChanged(false);
429 for (uint8_t iPtr
= 0; iPtr
< 5; iPtr
++)
431 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RESERVED
)
434 if (m_configuration
.deviceTypes
.types
[iPtr
] == from
)
437 m_configuration
.deviceTypes
.types
[iPtr
] = to
;
439 else if (m_configuration
.deviceTypes
.types
[iPtr
] == to
&& bChanged
)
441 // ensure that dupes are removed
442 m_configuration
.deviceTypes
.types
[iPtr
] = CEC_DEVICE_TYPE_RESERVED
;
447 // re-register the client to set the new ackmask
448 if (!m_processor
->RegisterClient(this))
451 // persist the new configuration
452 PersistConfiguration(m_configuration
);
457 bool CCECClient::SetLogicalAddress(const cec_logical_address iLogicalAddress
)
461 if (GetPrimaryLogicalAdddress() != iLogicalAddress
)
463 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "setting primary logical address to %1x", iLogicalAddress
);
465 CLockObject
lock(m_mutex
);
466 m_configuration
.logicalAddresses
.primary
= iLogicalAddress
;
467 m_configuration
.logicalAddresses
.Set(iLogicalAddress
);
470 bReturn
= m_processor
->RegisterClient(this);
472 // persist the new configuration
474 PersistConfiguration(m_configuration
);
480 bool CCECClient::Transmit(const cec_command
&data
, bool bIsReply
)
482 return m_processor
? m_processor
->Transmit(data
, bIsReply
) : false;
485 bool CCECClient::SendPowerOnDevices(const cec_logical_address address
/* = CECDEVICE_TV */)
487 // if the broadcast address if set as destination, read the wakeDevices setting
488 if (address
== CECDEVICE_BROADCAST
)
490 CECDEVICEVEC devices
;
491 m_processor
->GetDevices()->GetWakeDevices(m_configuration
, devices
);
492 return m_processor
->PowerOnDevices(GetPrimaryLogicalAdddress(), devices
);
495 return m_processor
->PowerOnDevice(GetPrimaryLogicalAdddress(), address
);
498 bool CCECClient::SendStandbyDevices(const cec_logical_address address
/* = CECDEVICE_BROADCAST */)
500 // if the broadcast address if set as destination, read the standbyDevices setting
501 if (address
== CECDEVICE_BROADCAST
)
503 CECDEVICEVEC devices
;
504 m_processor
->GetDevices()->GetPowerOffDevices(m_configuration
, devices
);
505 return m_processor
->StandbyDevices(GetPrimaryLogicalAdddress(), devices
);
508 return m_processor
->StandbyDevice(GetPrimaryLogicalAdddress(), address
);
511 bool CCECClient::SendSetActiveSource(const cec_device_type type
/* = CEC_DEVICE_TYPE_RESERVED */)
513 // get the devices that are controlled by us
514 CECDEVICEVEC devices
;
515 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
517 // filter out the device that matches the given type
518 if (type
!= CEC_DEVICE_TYPE_RESERVED
)
519 CCECDeviceMap::FilterType(type
, devices
);
521 // no devices left, re-fetch the list of devices that are controlled by us
523 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
525 if (!devices
.empty())
527 // get the first device from the list
528 CCECBusDevice
*device
= *devices
.begin();
531 if (!m_processor
->CECInitialised())
532 device
->MarkAsActiveSource();
533 else if (device
->HasValidPhysicalAddress())
534 return device
->ActivateSource();
540 CCECPlaybackDevice
*CCECClient::GetPlaybackDevice(void)
542 CCECPlaybackDevice
*device(NULL
);
543 CECDEVICEVEC devices
;
545 // get the playback devices
546 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
547 CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE
, devices
);
549 // no matches, get the recording devices
552 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
553 CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_RECORDING_DEVICE
, devices
);
556 // get the first device that matches, and cast it to CCECPlaybackDevice
557 if (!devices
.empty())
558 device
= (*devices
.begin())->AsPlaybackDevice();
563 cec_logical_address
CCECClient::GetPrimaryLogicalAdddress(void)
565 CLockObject
lock(m_mutex
);
566 return m_configuration
.logicalAddresses
.primary
;
569 CCECBusDevice
*CCECClient::GetPrimaryDevice(void)
571 return m_processor
->GetDevice(GetPrimaryLogicalAdddress());
574 bool CCECClient::SendSetDeckControlMode(const cec_deck_control_mode mode
, bool bSendUpdate
/* = true */)
576 // find a playback device that we control
577 CCECPlaybackDevice
*device
= GetPlaybackDevice();
580 // and set the deck control mode if there is a match
581 device
->SetDeckControlMode(mode
);
583 return device
->TransmitDeckStatus(CECDEVICE_TV
, false);
591 bool CCECClient::SendSetDeckInfo(const cec_deck_info info
, bool bSendUpdate
/* = true */)
593 // find a playback device that we control
594 CCECPlaybackDevice
*device
= GetPlaybackDevice();
597 // and set the deck status if there is a match
598 device
->SetDeckStatus(info
);
600 return device
->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV
, false);
608 bool CCECClient::SendSetMenuState(const cec_menu_state state
, bool bSendUpdate
/* = true */)
610 CECDEVICEVEC devices
;
612 // set the menu state for all devices that are controlled by us
613 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
614 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
616 (*it
)->SetMenuState(state
);
618 (*it
)->TransmitMenuState(CECDEVICE_TV
, false);
624 bool CCECClient::SendSetInactiveView(void)
626 CECDEVICEVEC devices
;
628 // mark all devices that are controlled by us as inactive source
629 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
630 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
632 if ((*it
)->IsActiveSource())
634 (*it
)->MarkAsInactiveSource();
635 return (*it
)->TransmitInactiveSource();
642 bool CCECClient::SendSetOSDString(const cec_logical_address iLogicalAddress
, const cec_display_control duration
, const char *strMessage
)
644 CCECBusDevice
*primary
= GetPrimaryDevice();
646 return primary
->TransmitOSDString(iLogicalAddress
, duration
, strMessage
, false);
651 cec_version
CCECClient::GetDeviceCecVersion(const cec_logical_address iAddress
)
653 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
655 return device
->GetCecVersion(GetPrimaryLogicalAdddress());
656 return CEC_VERSION_UNKNOWN
;
659 bool CCECClient::GetDeviceMenuLanguage(const cec_logical_address iAddress
, cec_menu_language
&language
)
661 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
664 language
= device
->GetMenuLanguage(GetPrimaryLogicalAdddress());
665 return (strcmp(language
.language
, "???") != 0);
670 cec_osd_name
CCECClient::GetDeviceOSDName(const cec_logical_address iAddress
)
673 retVal
.device
= iAddress
;
676 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
679 CStdString strOSDName
= device
->GetOSDName(GetPrimaryLogicalAdddress());
680 snprintf(retVal
.name
, sizeof(retVal
.name
), "%s", strOSDName
.c_str());
681 retVal
.device
= iAddress
;
687 uint16_t CCECClient::GetDevicePhysicalAddress(const cec_logical_address iAddress
)
689 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
691 return device
->GetPhysicalAddress(GetPrimaryLogicalAdddress());
692 return CEC_INVALID_PHYSICAL_ADDRESS
;
695 cec_power_status
CCECClient::GetDevicePowerStatus(const cec_logical_address iAddress
)
697 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
699 return device
->GetPowerStatus(GetPrimaryLogicalAdddress());
700 return CEC_POWER_STATUS_UNKNOWN
;
703 uint64_t CCECClient::GetDeviceVendorId(const cec_logical_address iAddress
)
705 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
707 return device
->GetVendorId(GetPrimaryLogicalAdddress());
708 return CEC_VENDOR_UNKNOWN
;
711 uint8_t CCECClient::SendVolumeUp(bool bSendRelease
/* = true */)
713 CCECBusDevice
*device
= GetPrimaryDevice();
714 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
716 return device
&& audio
&& audio
->IsPresent() ?
717 audio
->VolumeUp(device
->GetLogicalAddress(), bSendRelease
) :
718 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
721 uint8_t CCECClient::SendVolumeDown(bool bSendRelease
/* = true */)
723 CCECBusDevice
*device
= GetPrimaryDevice();
724 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
726 return device
&& audio
&& audio
->IsPresent() ?
727 audio
->VolumeDown(device
->GetLogicalAddress(), bSendRelease
) :
728 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
731 uint8_t CCECClient::SendMuteAudio(void)
733 CCECBusDevice
*device
= GetPrimaryDevice();
734 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
736 return device
&& audio
&& audio
->IsPresent() ?
737 audio
->MuteAudio(device
->GetLogicalAddress()) :
738 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
741 bool CCECClient::SendKeypress(const cec_logical_address iDestination
, const cec_user_control_code key
, bool bWait
/* = true */)
743 CCECBusDevice
*dest
= m_processor
->GetDevice(iDestination
);
746 dest
->TransmitKeypress(GetPrimaryLogicalAdddress(), key
, bWait
) :
750 bool CCECClient::SendKeyRelease(const cec_logical_address iDestination
, bool bWait
/* = true */)
752 CCECBusDevice
*dest
= m_processor
->GetDevice(iDestination
);
755 dest
->TransmitKeyRelease(GetPrimaryLogicalAdddress(), bWait
) :
759 bool CCECClient::GetCurrentConfiguration(libcec_configuration
&configuration
)
761 CLockObject
lock(m_mutex
);
763 // client version 1.5.0
764 snprintf(configuration
.strDeviceName
, 13, "%s", m_configuration
.strDeviceName
);
765 configuration
.deviceTypes
= m_configuration
.deviceTypes
;
766 configuration
.bAutodetectAddress
= m_configuration
.bAutodetectAddress
;
767 configuration
.iPhysicalAddress
= m_configuration
.iPhysicalAddress
;
768 configuration
.baseDevice
= m_configuration
.baseDevice
;
769 configuration
.iHDMIPort
= m_configuration
.iHDMIPort
;
770 configuration
.clientVersion
= m_configuration
.clientVersion
;
771 configuration
.serverVersion
= m_configuration
.serverVersion
;
772 configuration
.tvVendor
= m_configuration
.tvVendor
;
773 configuration
.bGetSettingsFromROM
= m_configuration
.bGetSettingsFromROM
;
774 configuration
.bUseTVMenuLanguage
= m_configuration
.bUseTVMenuLanguage
;
775 configuration
.bActivateSource
= m_configuration
.bActivateSource
;
776 configuration
.wakeDevices
= m_configuration
.wakeDevices
;
777 configuration
.powerOffDevices
= m_configuration
.powerOffDevices
;
778 configuration
.bPowerOffScreensaver
= m_configuration
.bPowerOffScreensaver
;
779 configuration
.bPowerOffOnStandby
= m_configuration
.bPowerOffOnStandby
;
780 configuration
.bSendInactiveSource
= m_configuration
.bSendInactiveSource
;
781 configuration
.logicalAddresses
= m_configuration
.logicalAddresses
;
782 configuration
.iFirmwareVersion
= m_configuration
.iFirmwareVersion
;
783 configuration
.bPowerOffDevicesOnStandby
= m_configuration
.bPowerOffDevicesOnStandby
;
784 configuration
.bShutdownOnStandby
= m_configuration
.bShutdownOnStandby
;
785 memcpy(configuration
.strDeviceLanguage
, m_configuration
.strDeviceLanguage
, 3);
786 configuration
.iFirmwareBuildDate
= m_configuration
.iFirmwareBuildDate
;
787 configuration
.bMonitorOnly
= m_configuration
.bMonitorOnly
;
788 configuration
.cecVersion
= m_configuration
.cecVersion
;
789 configuration
.adapterType
= m_configuration
.adapterType
;
794 bool CCECClient::SetConfiguration(const libcec_configuration
&configuration
)
796 bool bIsRunning(m_processor
&& m_processor
->CECInitialised());
797 CCECBusDevice
*primary
= bIsRunning
? GetPrimaryDevice() : NULL
;
798 uint16_t iPA
= primary
? primary
->GetCurrentPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS
;
800 // update the callbacks
801 if (configuration
.callbacks
)
802 EnableCallbacks(configuration
.callbackParam
, configuration
.callbacks
);
804 // update the client version
805 SetClientVersion((cec_client_version
)configuration
.clientVersion
);
807 // update the OSD name
808 CStdString
strOSDName(configuration
.strDeviceName
);
809 SetOSDName(strOSDName
);
811 // update the TV vendor override
812 SetTVVendorOverride((cec_vendor_id
)configuration
.tvVendor
);
816 CLockObject
lock(m_mutex
);
817 m_configuration
.bUseTVMenuLanguage
= configuration
.bUseTVMenuLanguage
;
818 m_configuration
.bActivateSource
= configuration
.bActivateSource
;
819 m_configuration
.bGetSettingsFromROM
= configuration
.bGetSettingsFromROM
;
820 m_configuration
.wakeDevices
= configuration
.wakeDevices
;
821 m_configuration
.powerOffDevices
= configuration
.powerOffDevices
;
822 m_configuration
.bPowerOffScreensaver
= configuration
.bPowerOffScreensaver
;
823 m_configuration
.bPowerOffOnStandby
= configuration
.bPowerOffOnStandby
;
824 m_configuration
.bSendInactiveSource
= configuration
.bSendInactiveSource
;
825 m_configuration
.bPowerOffDevicesOnStandby
= configuration
.bPowerOffDevicesOnStandby
;
826 m_configuration
.bShutdownOnStandby
= configuration
.bShutdownOnStandby
;
827 memcpy(m_configuration
.strDeviceLanguage
, configuration
.strDeviceLanguage
, 3);
828 m_configuration
.bMonitorOnly
= configuration
.bMonitorOnly
;
829 m_configuration
.cecVersion
= configuration
.cecVersion
;
830 m_configuration
.adapterType
= configuration
.adapterType
;
831 m_configuration
.deviceTypes
.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE
);
834 bool bNeedReinit(false);
837 if (SetDeviceTypes(configuration
.deviceTypes
))
839 // the device type changed. just copy the rest, and re-register
841 CLockObject
lock(m_mutex
);
842 m_configuration
.iPhysicalAddress
= configuration
.iPhysicalAddress
;
843 m_configuration
.baseDevice
= configuration
.baseDevice
;
844 m_configuration
.iHDMIPort
= configuration
.iHDMIPort
;
850 // set the physical address
851 SetPhysicalAddress(configuration
);
854 // persist the new configuration
855 PersistConfiguration(m_configuration
);
858 primary
= GetPrimaryDevice();
860 if (bNeedReinit
|| !primary
|| primary
->GetCurrentPhysicalAddress() != iPA
)
862 // PA or device type changed
863 m_processor
->RegisterClient(this);
865 else if (primary
&& configuration
.bActivateSource
== 1 && bIsRunning
&& !primary
->IsActiveSource())
867 // activate the source if we're not already the active source
868 primary
->ActivateSource();
874 void CCECClient::AddCommand(const cec_command
&command
)
876 // don't forward the standby opcode more than once every 10 seconds
877 if (command
.opcode
== CEC_OPCODE_STANDBY
)
879 CLockObject
lock(m_mutex
);
880 if (m_iPreventForwardingPowerOffCommand
!= 0 &&
881 m_iPreventForwardingPowerOffCommand
> GetTimeMs())
884 m_iPreventForwardingPowerOffCommand
= GetTimeMs() + CEC_FORWARD_STANDBY_MIN_INTERVAL
;
887 if (command
.destination
== CECDEVICE_BROADCAST
|| GetLogicalAddresses().IsSet(command
.destination
))
889 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, ">> %s (%X) -> %s (%X): %s (%2X)", ToString(command
.initiator
), command
.initiator
, ToString(command
.destination
), command
.destination
, ToString(command
.opcode
), command
.opcode
);
890 CallbackAddCommand(command
);
894 int CCECClient::MenuStateChanged(const cec_menu_state newState
)
896 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, ">> %s: %s", ToString(CEC_OPCODE_MENU_REQUEST
), ToString(newState
));
897 return CallbackMenuStateChanged(newState
);
900 void CCECClient::AddKey(bool bSendComboKey
/* = false */)
903 key
.keycode
= CEC_USER_CONTROL_CODE_UNKNOWN
;
906 CLockObject
lock(m_mutex
);
907 if (m_iCurrentButton
!= CEC_USER_CONTROL_CODE_UNKNOWN
)
909 key
.duration
= (unsigned int) (GetTimeMs() - m_buttontime
);
911 if (key
.duration
> COMBO_TIMEOUT_MS
|| m_iCurrentButton
!= COMBO_KEY
|| bSendComboKey
)
913 key
.keycode
= m_iCurrentButton
;
915 m_iCurrentButton
= CEC_USER_CONTROL_CODE_UNKNOWN
;
921 if (key
.keycode
!= CEC_USER_CONTROL_CODE_UNKNOWN
)
923 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "key released: %s (%1x)", ToString(key
.keycode
), key
.keycode
);
928 void CCECClient::AddKey(const cec_keypress
&key
)
930 // send back the previous key if there is one
933 cec_keypress
transmitKey(key
);
936 CLockObject
lock(m_mutex
);
937 if (key
.duration
> 0 || key
.keycode
> CEC_USER_CONTROL_CODE_MAX
)
939 transmitKey
.keycode
= CEC_USER_CONTROL_CODE_UNKNOWN
;
941 else if (m_iCurrentButton
== COMBO_KEY
)
944 if (key
.keycode
== CEC_USER_CONTROL_CODE_SELECT
)
945 transmitKey
.keycode
= CEC_USER_CONTROL_CODE_EXIT
;
946 // stop + pause -> root menu
947 else if (key
.keycode
== CEC_USER_CONTROL_CODE_ROOT_MENU
)
948 transmitKey
.keycode
= CEC_USER_CONTROL_CODE_ROOT_MENU
;
949 // stop + play -> dot (which is handled as context menu in xbmc)
950 else if (key
.keycode
== CEC_USER_CONTROL_CODE_PLAY
)
951 transmitKey
.keycode
= CEC_USER_CONTROL_CODE_DOT
;
952 // default, send back the previous key
957 m_iCurrentButton
= transmitKey
.keycode
;
958 m_buttontime
= m_iCurrentButton
== CEC_USER_CONTROL_CODE_UNKNOWN
|| key
.duration
> 0 ? 0 : GetTimeMs();
961 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "key pressed: %s (%1x)", ToString(transmitKey
.keycode
), transmitKey
.keycode
);
962 CallbackAddKey(transmitKey
);
965 void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode
)
967 // push a keypress to the buffer with 0 duration and another with the duration set when released
970 key
.keycode
= iButtonCode
;
975 void CCECClient::CheckKeypressTimeout(void)
980 CLockObject
lock(m_mutex
);
981 uint64_t iNow
= GetTimeMs();
983 if (m_iCurrentButton
!= CEC_USER_CONTROL_CODE_UNKNOWN
&&
984 ((m_iCurrentButton
== COMBO_KEY
&& iNow
- m_buttontime
> COMBO_TIMEOUT_MS
) ||
985 (m_iCurrentButton
!= COMBO_KEY
&& iNow
- m_buttontime
> CEC_BUTTON_TIMEOUT
)))
987 key
.duration
= (unsigned int) (iNow
- m_buttontime
);
988 key
.keycode
= m_iCurrentButton
;
990 m_iCurrentButton
= CEC_USER_CONTROL_CODE_UNKNOWN
;
999 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "key auto-released: %s (%1x)", ToString(key
.keycode
), key
.keycode
);
1000 CallbackAddKey(key
);
1003 bool CCECClient::EnableCallbacks(void *cbParam
, ICECCallbacks
*callbacks
)
1005 CLockObject
lock(m_cbMutex
);
1006 m_configuration
.callbackParam
= cbParam
;
1007 m_configuration
.callbacks
= callbacks
;
1011 bool CCECClient::PingAdapter(void)
1013 return m_processor
? m_processor
->PingAdapter() : false;
1016 std::string
CCECClient::GetConnectionInfo(void)
1019 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
);
1020 if (m_configuration
.iFirmwareBuildDate
!= CEC_FW_BUILD_UNKNOWN
)
1022 time_t buildTime
= (time_t)m_configuration
.iFirmwareBuildDate
;
1023 strLog
.AppendFormat(", firmware build date: %s", asctime(gmtime(&buildTime
)));
1024 strLog
= strLog
.substr(0, strLog
.length() > 0 ? (size_t)(strLog
.length() - 1) : 0); // strip \n added by asctime
1025 strLog
.append(" +0000");
1028 // log the addresses that are being used
1029 if (!m_configuration
.logicalAddresses
.IsEmpty())
1031 strLog
.append(", logical address(es) = ");
1032 CECDEVICEVEC devices
;
1033 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
1034 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
1035 strLog
.AppendFormat("%s (%X) ", (*it
)->GetLogicalAddressName(), (*it
)->GetLogicalAddress());
1038 if (!CLibCEC::IsValidPhysicalAddress(m_configuration
.iPhysicalAddress
))
1039 strLog
.AppendFormat(", base device: %s (%X), HDMI port number: %d", ToString(m_configuration
.baseDevice
), m_configuration
.baseDevice
, m_configuration
.iHDMIPort
);
1040 uint16_t iPhysicalAddress
= GetPrimaryDevice()->GetPhysicalAddress(GetLogicalAddresses().primary
, false);
1041 strLog
.AppendFormat(", physical address: %x.%x.%x.%x", (iPhysicalAddress
>> 12) & 0xF, (iPhysicalAddress
>> 8) & 0xF, (iPhysicalAddress
>> 4) & 0xF, iPhysicalAddress
& 0xF);
1043 strLog
.AppendFormat(", %s", LIB_CEC
->GetLibInfo());
1045 std::string
strReturn(strLog
.c_str());
1049 void CCECClient::SetTVVendorOverride(const cec_vendor_id id
)
1052 CLockObject
lock(m_mutex
);
1053 m_configuration
.tvVendor
= id
;
1056 if (id
!= CEC_VENDOR_UNKNOWN
)
1058 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - vendor id '%s'", __FUNCTION__
, ToString(id
));
1060 CCECBusDevice
*tv
= m_processor
? m_processor
->GetTV() : NULL
;
1062 tv
->SetVendorId((uint64_t)id
);
1065 // persist the new configuration
1066 PersistConfiguration(m_configuration
);
1069 cec_vendor_id
CCECClient::GetTVVendorOverride(void)
1071 CLockObject
lock(m_mutex
);
1072 return (cec_vendor_id
)m_configuration
.tvVendor
;
1075 void CCECClient::SetOSDName(const std::string
&strDeviceName
)
1078 CLockObject
lock(m_mutex
);
1079 snprintf(m_configuration
.strDeviceName
, 13, "%s", strDeviceName
.c_str());
1082 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using OSD name '%s'", __FUNCTION__
, strDeviceName
.c_str());
1084 CCECBusDevice
*primary
= GetPrimaryDevice();
1085 if (primary
&& !primary
->GetCurrentOSDName().Equals(strDeviceName
.c_str()))
1087 primary
->SetOSDName(strDeviceName
);
1088 if (m_processor
&& m_processor
->CECInitialised())
1089 primary
->TransmitOSDName(CECDEVICE_TV
, false);
1092 // persist the new configuration
1093 PersistConfiguration(m_configuration
);
1096 std::string
CCECClient::GetOSDName(void)
1098 CLockObject
lock(m_mutex
);
1099 std::string
strOSDName(m_configuration
.strDeviceName
);
1103 void CCECClient::SetWakeDevices(const cec_logical_addresses
&addresses
)
1106 CLockObject
lock(m_mutex
);
1107 m_configuration
.wakeDevices
= addresses
;
1109 // persist the new configuration
1110 PersistConfiguration(m_configuration
);
1113 cec_logical_addresses
CCECClient::GetWakeDevices(void)
1115 CLockObject
lock(m_mutex
);
1116 return m_configuration
.wakeDevices
;
1119 bool CCECClient::AutodetectPhysicalAddress(void)
1121 bool bPhysicalAutodetected(false);
1122 uint16_t iPhysicalAddress
= m_processor
? m_processor
->GetDetectedPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS
;
1124 if (CLibCEC::IsValidPhysicalAddress(iPhysicalAddress
))
1126 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - autodetected physical address '%04X'", __FUNCTION__
, iPhysicalAddress
);
1128 CLockObject
lock(m_mutex
);
1129 m_configuration
.iPhysicalAddress
= iPhysicalAddress
;
1130 m_configuration
.iHDMIPort
= CEC_HDMI_PORTNUMBER_NONE
;
1131 m_configuration
.baseDevice
= CECDEVICE_UNKNOWN
;
1132 bPhysicalAutodetected
= true;
1135 SetDevicePhysicalAddress(iPhysicalAddress
);
1137 return bPhysicalAutodetected
;
1140 void CCECClient::SetClientVersion(const cec_client_version version
)
1142 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using client version '%s'", __FUNCTION__
, ToString(version
));
1144 CLockObject
lock(m_mutex
);
1145 m_configuration
.clientVersion
= (uint32_t)version
;
1148 cec_client_version
CCECClient::GetClientVersion(void)
1150 CLockObject
lock(m_mutex
);
1151 return (cec_client_version
)m_configuration
.clientVersion
;
1154 bool CCECClient::SetDeviceTypes(const cec_device_type_list
&deviceTypes
)
1156 bool bNeedReinit(false);
1159 CLockObject
lock(m_mutex
);
1160 bNeedReinit
= m_processor
&& m_processor
->CECInitialised() &&
1161 (m_configuration
.deviceTypes
!= deviceTypes
);
1162 m_configuration
.deviceTypes
= deviceTypes
;
1165 // persist the new configuration
1166 PersistConfiguration(m_configuration
);
1169 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using primary device type '%s'", __FUNCTION__
, ToString(deviceTypes
[0]));
1174 cec_device_type_list
CCECClient::GetDeviceTypes(void)
1176 cec_device_type_list retVal
;
1177 CLockObject
lock(m_mutex
);
1178 retVal
= m_configuration
.deviceTypes
;
1182 bool CCECClient::SetDevicePhysicalAddress(const uint16_t iPhysicalAddress
)
1184 if (!CLibCEC::IsValidPhysicalAddress(iPhysicalAddress
))
1186 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - not setting invalid physical address %04x", __FUNCTION__
, iPhysicalAddress
);
1190 // reconfigure all devices
1191 cec_logical_address
reactivateSource(CECDEVICE_UNKNOWN
);
1192 CECDEVICEVEC devices
;
1193 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
1194 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
1196 // if this device was the active source, reactivate it afterwards
1197 if ((*it
)->IsActiveSource())
1198 reactivateSource
= (*it
)->GetLogicalAddress();
1200 // mark the device as inactive source
1201 if (IsInitialised())
1202 (*it
)->MarkAsInactiveSource();
1204 // set the new physical address
1205 (*it
)->SetPhysicalAddress(iPhysicalAddress
);
1208 if (IsInitialised())
1209 (*it
)->TransmitPhysicalAddress(false);
1212 // reactivate the previous active source
1213 if (reactivateSource
!= CECDEVICE_UNKNOWN
&&
1214 m_processor
->CECInitialised() &&
1217 CCECBusDevice
*device
= m_processor
->GetDevice(reactivateSource
);
1219 device
->ActivateSource();
1222 // persist the new configuration
1223 PersistConfiguration(m_configuration
);
1228 bool CCECClient::SwitchMonitoring(bool bEnable
)
1230 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "== %s monitoring mode ==", bEnable
? "enabling" : "disabling");
1234 m_processor
->SwitchMonitoring(bEnable
);
1235 m_configuration
.bMonitorOnly
= bEnable
;
1236 return bEnable
? true: m_processor
->RegisterClient(this);
1242 bool CCECClient::PollDevice(const cec_logical_address iAddress
)
1244 // try to find the primary device
1245 CCECBusDevice
*primary
= GetPrimaryDevice();
1246 // poll the destination, with the primary as source
1248 return primary
->TransmitPoll(iAddress
, false);
1250 return m_processor
? m_processor
->PollDevice(iAddress
) : false;
1253 cec_logical_addresses
CCECClient::GetActiveDevices(void)
1255 CECDEVICEVEC activeDevices
;
1257 m_processor
->GetDevices()->GetActive(activeDevices
);
1258 return CCECDeviceMap::ToLogicalAddresses(activeDevices
);
1261 bool CCECClient::IsActiveDevice(const cec_logical_address iAddress
)
1263 cec_logical_addresses activeDevices
= GetActiveDevices();
1264 return activeDevices
.IsSet(iAddress
);
1267 bool CCECClient::IsActiveDeviceType(const cec_device_type type
)
1269 CECDEVICEVEC activeDevices
;
1271 m_processor
->GetDevices()->GetActive(activeDevices
);
1272 CCECDeviceMap::FilterType(type
, activeDevices
);
1273 return !activeDevices
.empty();
1276 cec_logical_address
CCECClient::GetActiveSource(void)
1278 return m_processor
? m_processor
->GetActiveSource() : CECDEVICE_UNKNOWN
;
1281 bool CCECClient::IsActiveSource(const cec_logical_address iAddress
)
1283 return m_processor
? m_processor
->IsActiveSource(iAddress
) : false;
1286 bool CCECClient::SetStreamPath(const cec_logical_address iAddress
)
1288 uint16_t iPhysicalAddress
= GetDevicePhysicalAddress(iAddress
);
1289 if (iPhysicalAddress
!= CEC_INVALID_PHYSICAL_ADDRESS
)
1290 return SetStreamPath(iPhysicalAddress
);
1294 bool CCECClient::SetStreamPath(const uint16_t iPhysicalAddress
)
1296 bool bReturn(false);
1298 CCECBusDevice
*device
= GetDeviceByType(CEC_DEVICE_TYPE_TV
);
1301 device
->SetStreamPath(iPhysicalAddress
);
1302 bReturn
= device
->GetHandler()->TransmitSetStreamPath(iPhysicalAddress
, false);
1303 device
->MarkHandlerReady();
1307 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "only the TV is allowed to send CEC_OPCODE_SET_STREAM_PATH");
1313 cec_logical_addresses
CCECClient::GetLogicalAddresses(void)
1315 cec_logical_addresses addresses
;
1316 CLockObject
lock(m_mutex
);
1317 addresses
= m_configuration
.logicalAddresses
;
1321 bool CCECClient::CanPersistConfiguration(void)
1323 return m_processor
? m_processor
->CanPersistConfiguration() : false;
1326 bool CCECClient::PersistConfiguration(const libcec_configuration
&configuration
)
1328 return m_processor
&& IsRegistered() ?
1329 m_processor
->PersistConfiguration(configuration
) :
1333 void CCECClient::RescanActiveDevices(void)
1336 m_processor
->RescanActiveDevices();
1339 bool CCECClient::IsLibCECActiveSource(void)
1341 bool bReturn(false);
1344 cec_logical_address activeSource
= m_processor
->GetActiveSource();
1345 CCECBusDevice
*device
= m_processor
->GetDevice(activeSource
);
1347 bReturn
= device
->IsHandledByLibCEC();
1352 void CCECClient::SourceActivated(const cec_logical_address logicalAddress
)
1354 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, ">> source activated: %s (%x)", ToString(logicalAddress
), logicalAddress
);
1355 CallbackSourceActivated(true, logicalAddress
);
1358 void CCECClient::SourceDeactivated(const cec_logical_address logicalAddress
)
1360 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, ">> source deactivated: %s (%x)", ToString(logicalAddress
), logicalAddress
);
1361 CallbackSourceActivated(false, logicalAddress
);
1364 void CCECClient::CallbackAddCommand(const cec_command
&command
)
1366 CLockObject
lock(m_cbMutex
);
1367 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecCommand
)
1368 m_configuration
.callbacks
->CBCecCommand(m_configuration
.callbackParam
, command
);
1371 void CCECClient::CallbackAddKey(const cec_keypress
&key
)
1373 CLockObject
lock(m_cbMutex
);
1374 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecKeyPress
)
1376 // prevent double taps
1377 int64_t now
= GetTimeMs();
1378 if (m_lastKeypress
.keycode
!= key
.keycode
||
1380 now
- m_iLastKeypressTime
>= CEC_DOUBLE_TAP_TIMEOUT_MS
)
1383 if (key
.duration
== 0)
1384 m_iLastKeypressTime
= now
;
1385 m_lastKeypress
= key
;
1386 m_configuration
.callbacks
->CBCecKeyPress(m_configuration
.callbackParam
, key
);
1391 void CCECClient::CallbackAddLog(const cec_log_message
&message
)
1393 CLockObject
lock(m_cbMutex
);
1394 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecLogMessage
)
1395 m_configuration
.callbacks
->CBCecLogMessage(m_configuration
.callbackParam
, message
);
1398 void CCECClient::CallbackConfigurationChanged(const libcec_configuration
&config
)
1400 CLockObject
lock(m_cbMutex
);
1401 if (m_configuration
.callbacks
&&
1402 m_configuration
.callbacks
->CBCecConfigurationChanged
&&
1403 m_processor
->CECInitialised())
1404 m_configuration
.callbacks
->CBCecConfigurationChanged(m_configuration
.callbackParam
, config
);
1407 void CCECClient::CallbackSourceActivated(bool bActivated
, const cec_logical_address logicalAddress
)
1409 CLockObject
lock(m_cbMutex
);
1410 if (m_configuration
.callbacks
&&
1411 m_configuration
.callbacks
->CBCecSourceActivated
)
1412 m_configuration
.callbacks
->CBCecSourceActivated(m_configuration
.callbackParam
, logicalAddress
, bActivated
? 1 : 0);
1415 void CCECClient::CallbackAlert(const libcec_alert type
, const libcec_parameter
¶m
)
1417 CLockObject
lock(m_cbMutex
);
1418 if (m_configuration
.callbacks
&&
1419 m_configuration
.callbacks
->CBCecAlert
)
1420 m_configuration
.callbacks
->CBCecAlert(m_configuration
.callbackParam
, type
, param
);
1423 int CCECClient::CallbackMenuStateChanged(const cec_menu_state newState
)
1425 CLockObject
lock(m_cbMutex
);
1426 if (m_configuration
.callbacks
&&
1427 m_configuration
.callbacks
->CBCecMenuStateChanged
)
1428 return m_configuration
.callbacks
->CBCecMenuStateChanged(m_configuration
.callbackParam
, newState
);