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/
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 CCECClient::CCECClient(CCECProcessor
*processor
, const libcec_configuration
&configuration
) :
51 m_processor(processor
),
52 m_bInitialised(false),
54 m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN
),
56 m_iPreventForwardingPowerOffCommand(0),
57 m_iLastKeypressTime(0)
59 m_lastKeypress
.keycode
= CEC_USER_CONTROL_CODE_UNKNOWN
;
60 m_lastKeypress
.duration
= 0;
61 m_configuration
.Clear();
62 // set the initial configuration
63 SetConfiguration(configuration
);
66 CCECClient::~CCECClient(void)
68 // unregister the client
69 if (m_processor
&& IsRegistered())
70 m_processor
->UnregisterClient(this);
73 bool CCECClient::IsInitialised(void)
75 CLockObject
lock(m_mutex
);
76 return m_bInitialised
&& m_processor
;
79 void CCECClient::SetInitialised(bool bSetTo
)
81 CLockObject
lock(m_mutex
);
82 m_bInitialised
= bSetTo
;
85 bool CCECClient::IsRegistered(void)
87 CLockObject
lock(m_mutex
);
88 return m_bRegistered
&& m_processor
;
91 void CCECClient::SetRegistered(bool bSetTo
)
93 CLockObject
lock(m_mutex
);
94 m_bRegistered
= bSetTo
;
97 bool CCECClient::OnRegister(void)
99 // return false if already initialised
103 // get all device we control
104 CECDEVICEVEC devices
;
105 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
107 // return false when no devices were found
110 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "cannot find the primary device (logical address %x)", GetPrimaryLogicalAdddress());
114 // mark as initialised
115 SetInitialised(true);
117 // configure all devices
118 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
120 // only set our OSD name for the primary device
121 if ((*it
)->GetLogicalAddress() == GetPrimaryLogicalAdddress())
122 (*it
)->SetOSDName(m_configuration
.strDeviceName
);
124 // set the default menu language for devices we control
125 (*it
)->SetMenuLanguage(m_configuration
.strDeviceLanguage
);
128 // set the physical address
129 SetPhysicalAddress(m_configuration
);
131 // make the primary device the active source if the option is set
132 if (m_configuration
.bActivateSource
== 1)
133 GetPrimaryDevice()->ActivateSource(500);
138 bool CCECClient::SetHDMIPort(const cec_logical_address iBaseDevice
, const uint8_t iPort
, bool bForce
/* = false */)
142 // limit the HDMI port range to 1-15
143 if (iPort
< CEC_MIN_HDMI_PORTNUMBER
||
144 iPort
> CEC_MAX_HDMI_PORTNUMBER
)
147 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "setting HDMI port to %d on device %s (%d)", iPort
, ToString(iBaseDevice
), (int)iBaseDevice
);
149 // update the configuration
151 CLockObject
lock(m_mutex
);
152 m_configuration
.baseDevice
= iBaseDevice
;
153 m_configuration
.iHDMIPort
= iPort
;
156 // don't continue if the connection isn't opened
157 if (!m_processor
->CECInitialised() && !bForce
)
160 // get the PA of the base device
161 uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS
);
162 CCECBusDevice
*baseDevice
= m_processor
->GetDevice(iBaseDevice
);
164 iPhysicalAddress
= baseDevice
->GetPhysicalAddress(GetPrimaryLogicalAdddress());
166 // add our port number
167 if (iPhysicalAddress
<= CEC_MAX_PHYSICAL_ADDRESS
)
169 if (iPhysicalAddress
== 0)
170 iPhysicalAddress
+= 0x1000 * iPort
;
171 else if (iPhysicalAddress
% 0x1000 == 0)
172 iPhysicalAddress
+= 0x100 * iPort
;
173 else if (iPhysicalAddress
% 0x100 == 0)
174 iPhysicalAddress
+= 0x10 * iPort
;
175 else if (iPhysicalAddress
% 0x10 == 0)
176 iPhysicalAddress
+= iPort
;
181 // set the default address when something went wrong
184 uint16_t iEepromAddress
= m_processor
->GetPhysicalAddressFromEeprom();
185 if (CLibCEC::IsValidPhysicalAddress(iEepromAddress
))
187 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "failed to set the physical address to %04X, setting it to the value that was persisted in the eeprom, %04X", iPhysicalAddress
, iEepromAddress
);
188 iPhysicalAddress
= iEepromAddress
;
193 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
);
194 iPhysicalAddress
= CEC_DEFAULT_PHYSICAL_ADDRESS
;
198 // and set the address
199 SetDevicePhysicalAddress(iPhysicalAddress
);
201 CallbackConfigurationChanged(m_configuration
);
206 void CCECClient::ResetPhysicalAddress(void)
208 SetPhysicalAddress(CEC_DEFAULT_PHYSICAL_ADDRESS
);
211 void CCECClient::SetPhysicalAddress(const libcec_configuration
&configuration
)
215 // override the physical address from configuration.iPhysicalAddress if it's set
216 if (!bPASet
&& CLibCEC::IsValidPhysicalAddress(configuration
.iPhysicalAddress
))
217 bPASet
= SetPhysicalAddress(configuration
.iPhysicalAddress
);
219 // try to autodetect the address
220 if (!bPASet
&& m_processor
->CECInitialised())
222 bPASet
= AutodetectPhysicalAddress();
223 m_configuration
.bAutodetectAddress
= bPASet
? 1 : 0;
226 // use the base device + hdmi port settings
228 bPASet
= SetHDMIPort(configuration
.baseDevice
, configuration
.iHDMIPort
);
230 // reset to defaults if something went wrong
233 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - resetting HDMI port and base device to defaults", __FUNCTION__
);
234 m_configuration
.baseDevice
= CECDEVICE_UNKNOWN
;
235 m_configuration
.iHDMIPort
= CEC_HDMI_PORTNUMBER_NONE
;
239 bool CCECClient::SetPhysicalAddress(const uint16_t iPhysicalAddress
)
241 // update the configuration
244 CLockObject
lock(m_mutex
);
245 if (m_configuration
.iPhysicalAddress
== iPhysicalAddress
)
248 m_configuration
.iPhysicalAddress
= iPhysicalAddress
;
252 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "physical address unchanged (%04X)", iPhysicalAddress
);
256 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "setting physical address to '%04X'", iPhysicalAddress
);
258 // set the physical address for each device
259 SetDevicePhysicalAddress(iPhysicalAddress
);
261 // and send back the updated configuration
262 CallbackConfigurationChanged(m_configuration
);
267 void CCECClient::SetSupportedDeviceTypes(void)
269 cec_device_type_list types
;
272 // get the command handler for the tv
273 CCECCommandHandler
*tvHandler
= m_processor
->GetTV()->GetHandler();
277 // check all device types
278 for (uint8_t iPtr
= 0; iPtr
< 5; iPtr
++)
280 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RESERVED
)
283 // get the supported device type. the handler will replace types it doesn't support by one it does support
284 cec_device_type type
= tvHandler
->GetReplacementDeviceType(m_configuration
.deviceTypes
.types
[iPtr
]);
285 if (!types
.IsSet(type
))
288 m_processor
->GetTV()->MarkHandlerReady();
290 // set the new type list
291 m_configuration
.deviceTypes
= types
;
293 // persist the new configuration
294 PersistConfiguration(m_configuration
);
297 bool CCECClient::AllocateLogicalAddresses(void)
299 // reset all previous LAs that were set
300 m_configuration
.logicalAddresses
.Clear();
302 // get the supported device types from the command handler of the TV
303 SetSupportedDeviceTypes();
305 // display an error if no device types are set
306 if (m_configuration
.deviceTypes
.IsEmpty())
308 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "no device types given");
312 // check each entry of the list
313 for (uint8_t iPtr
= 0; iPtr
< 5; iPtr
++)
315 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RESERVED
)
318 // find an LA for this type
319 cec_logical_address
address(CECDEVICE_UNKNOWN
);
320 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RECORDING_DEVICE
)
321 address
= AllocateLogicalAddressRecordingDevice();
322 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_TUNER
)
323 address
= AllocateLogicalAddressTuner();
324 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE
)
325 address
= AllocateLogicalAddressPlaybackDevice();
326 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_AUDIO_SYSTEM
)
327 address
= AllocateLogicalAddressAudioSystem();
329 // display an error if no LA could be allocated
330 if (address
== CECDEVICE_UNKNOWN
)
332 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s - failed to allocate device '%d', type '%s'", __FUNCTION__
, iPtr
, ToString(m_configuration
.deviceTypes
.types
[iPtr
]));
336 // display the registered LA
337 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - device '%d', type '%s', LA '%X'", __FUNCTION__
, iPtr
, ToString(m_configuration
.deviceTypes
.types
[iPtr
]), address
);
338 m_configuration
.logicalAddresses
.Set(address
);
341 // persist the new configuration
342 PersistConfiguration(m_configuration
);
347 cec_logical_address
CCECClient::AllocateLogicalAddressRecordingDevice(void)
349 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
351 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'recording device'");
352 if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1
, m_configuration
.cecVersion
))
353 retVal
= CECDEVICE_RECORDINGDEVICE1
;
354 else if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2
, m_configuration
.cecVersion
))
355 retVal
= CECDEVICE_RECORDINGDEVICE2
;
356 else if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3
, m_configuration
.cecVersion
))
357 retVal
= CECDEVICE_RECORDINGDEVICE3
;
362 cec_logical_address
CCECClient::AllocateLogicalAddressTuner(void)
364 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
366 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'tuner'");
367 if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER1
, m_configuration
.cecVersion
))
368 retVal
= CECDEVICE_TUNER1
;
369 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER2
, m_configuration
.cecVersion
))
370 retVal
= CECDEVICE_TUNER2
;
371 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER3
, m_configuration
.cecVersion
))
372 retVal
= CECDEVICE_TUNER3
;
373 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER4
, m_configuration
.cecVersion
))
374 retVal
= CECDEVICE_TUNER4
;
379 cec_logical_address
CCECClient::AllocateLogicalAddressPlaybackDevice(void)
381 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
383 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'playback device'");
384 if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1
, m_configuration
.cecVersion
))
385 retVal
= CECDEVICE_PLAYBACKDEVICE1
;
386 else if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2
, m_configuration
.cecVersion
))
387 retVal
= CECDEVICE_PLAYBACKDEVICE2
;
388 else if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3
, m_configuration
.cecVersion
))
389 retVal
= CECDEVICE_PLAYBACKDEVICE3
;
394 cec_logical_address
CCECClient::AllocateLogicalAddressAudioSystem(void)
396 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
398 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'audiosystem'");
399 if (m_processor
->TryLogicalAddress(CECDEVICE_AUDIOSYSTEM
, m_configuration
.cecVersion
))
400 retVal
= CECDEVICE_AUDIOSYSTEM
;
405 CCECBusDevice
*CCECClient::GetDeviceByType(const cec_device_type type
) const
407 // get all devices that match our logical addresses
408 CECDEVICEVEC devices
;
409 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
411 // filter the type we need
412 CCECDeviceMap::FilterType(type
, devices
);
414 return devices
.empty() ?
419 bool CCECClient::ChangeDeviceType(const cec_device_type from
, const cec_device_type to
)
424 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "changing device type '%s' into '%s'", ToString(from
), ToString(to
));
427 CLockObject
lock(m_mutex
);
429 // get the previous device that was allocated
430 CCECBusDevice
*previousDevice
= GetDeviceByType(from
);
434 // change the type in the device type list
435 bool bChanged(false);
436 for (uint8_t iPtr
= 0; iPtr
< 5; iPtr
++)
438 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RESERVED
)
441 if (m_configuration
.deviceTypes
.types
[iPtr
] == from
)
444 m_configuration
.deviceTypes
.types
[iPtr
] = to
;
446 else if (m_configuration
.deviceTypes
.types
[iPtr
] == to
&& bChanged
)
448 // ensure that dupes are removed
449 m_configuration
.deviceTypes
.types
[iPtr
] = CEC_DEVICE_TYPE_RESERVED
;
454 // re-register the client to set the new ackmask
455 if (!m_processor
->RegisterClient(this))
458 // persist the new configuration
459 PersistConfiguration(m_configuration
);
464 bool CCECClient::SetLogicalAddress(const cec_logical_address iLogicalAddress
)
468 if (GetPrimaryLogicalAdddress() != iLogicalAddress
)
470 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "setting primary logical address to %1x", iLogicalAddress
);
472 CLockObject
lock(m_mutex
);
473 m_configuration
.logicalAddresses
.primary
= iLogicalAddress
;
474 m_configuration
.logicalAddresses
.Set(iLogicalAddress
);
477 bReturn
= m_processor
->RegisterClient(this);
479 // persist the new configuration
481 PersistConfiguration(m_configuration
);
487 bool CCECClient::Transmit(const cec_command
&data
, bool bIsReply
)
489 return m_processor
? m_processor
->Transmit(data
, bIsReply
) : false;
492 bool CCECClient::SendPowerOnDevices(const cec_logical_address address
/* = CECDEVICE_TV */)
494 // if the broadcast address if set as destination, read the wakeDevices setting
495 if (address
== CECDEVICE_BROADCAST
)
497 CECDEVICEVEC devices
;
498 m_processor
->GetDevices()->GetWakeDevices(m_configuration
, devices
);
499 return m_processor
->PowerOnDevices(GetPrimaryLogicalAdddress(), devices
);
502 return m_processor
->PowerOnDevice(GetPrimaryLogicalAdddress(), address
);
505 bool CCECClient::SendStandbyDevices(const cec_logical_address address
/* = CECDEVICE_BROADCAST */)
507 // if the broadcast address if set as destination, read the standbyDevices setting
508 if (address
== CECDEVICE_BROADCAST
)
510 CECDEVICEVEC devices
;
511 m_processor
->GetDevices()->GetPowerOffDevices(m_configuration
, devices
);
512 return m_processor
->StandbyDevices(GetPrimaryLogicalAdddress(), devices
);
515 return m_processor
->StandbyDevice(GetPrimaryLogicalAdddress(), address
);
518 bool CCECClient::SendSetActiveSource(const cec_device_type type
/* = CEC_DEVICE_TYPE_RESERVED */)
520 // get the devices that are controlled by us
521 CECDEVICEVEC devices
;
522 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
524 // filter out the device that matches the given type
525 if (type
!= CEC_DEVICE_TYPE_RESERVED
)
526 CCECDeviceMap::FilterType(type
, devices
);
528 // no devices left, re-fetch the list of devices that are controlled by us
530 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
532 if (!devices
.empty())
534 // get the first device from the list
535 CCECBusDevice
*device
= *devices
.begin();
538 if (!m_processor
->CECInitialised())
539 device
->MarkAsActiveSource();
540 else if (device
->HasValidPhysicalAddress())
541 return device
->ActivateSource();
547 CCECPlaybackDevice
*CCECClient::GetPlaybackDevice(void)
549 CCECPlaybackDevice
*device(NULL
);
550 CECDEVICEVEC devices
;
552 // get the playback devices
553 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
554 CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE
, devices
);
556 // no matches, get the recording devices
559 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
560 CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_RECORDING_DEVICE
, devices
);
563 // get the first device that matches, and cast it to CCECPlaybackDevice
564 if (!devices
.empty())
565 device
= (*devices
.begin())->AsPlaybackDevice();
570 cec_logical_address
CCECClient::GetPrimaryLogicalAdddress(void)
572 CLockObject
lock(m_mutex
);
573 return m_configuration
.logicalAddresses
.primary
;
576 CCECBusDevice
*CCECClient::GetPrimaryDevice(void)
578 return m_processor
->GetDevice(GetPrimaryLogicalAdddress());
581 bool CCECClient::SendSetDeckControlMode(const cec_deck_control_mode mode
, bool bSendUpdate
/* = true */)
583 // find a playback device that we control
584 CCECPlaybackDevice
*device
= GetPlaybackDevice();
587 // and set the deck control mode if there is a match
588 device
->SetDeckControlMode(mode
);
590 return device
->TransmitDeckStatus(CECDEVICE_TV
, false);
598 bool CCECClient::SendSetDeckInfo(const cec_deck_info info
, bool bSendUpdate
/* = true */)
600 // find a playback device that we control
601 CCECPlaybackDevice
*device
= GetPlaybackDevice();
604 // and set the deck status if there is a match
605 device
->SetDeckStatus(info
);
607 return device
->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV
, false);
615 bool CCECClient::SendSetMenuState(const cec_menu_state state
, bool bSendUpdate
/* = true */)
617 CECDEVICEVEC devices
;
619 // set the menu state for all devices that are controlled by us
620 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
621 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
623 (*it
)->SetMenuState(state
);
625 (*it
)->TransmitMenuState(CECDEVICE_TV
, false);
631 bool CCECClient::SendSetInactiveView(void)
633 CECDEVICEVEC devices
;
635 // mark all devices that are controlled by us as inactive source
636 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
637 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
639 if ((*it
)->IsActiveSource())
641 (*it
)->MarkAsInactiveSource();
642 return (*it
)->TransmitInactiveSource();
649 bool CCECClient::SendSetOSDString(const cec_logical_address iLogicalAddress
, const cec_display_control duration
, const char *strMessage
)
651 CCECBusDevice
*primary
= GetPrimaryDevice();
653 return primary
->TransmitOSDString(iLogicalAddress
, duration
, strMessage
, false);
658 cec_version
CCECClient::GetDeviceCecVersion(const cec_logical_address iAddress
)
660 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
662 return device
->GetCecVersion(GetPrimaryLogicalAdddress());
663 return CEC_VERSION_UNKNOWN
;
666 bool CCECClient::GetDeviceMenuLanguage(const cec_logical_address iAddress
, cec_menu_language
&language
)
668 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
671 language
= device
->GetMenuLanguage(GetPrimaryLogicalAdddress());
672 return (strcmp(language
.language
, "???") != 0);
677 cec_osd_name
CCECClient::GetDeviceOSDName(const cec_logical_address iAddress
)
680 retVal
.device
= iAddress
;
683 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
686 CStdString strOSDName
= device
->GetOSDName(GetPrimaryLogicalAdddress());
687 snprintf(retVal
.name
, sizeof(retVal
.name
), "%s", strOSDName
.c_str());
688 retVal
.device
= iAddress
;
694 uint16_t CCECClient::GetDevicePhysicalAddress(const cec_logical_address iAddress
)
696 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
698 return device
->GetPhysicalAddress(GetPrimaryLogicalAdddress());
699 return CEC_INVALID_PHYSICAL_ADDRESS
;
702 cec_power_status
CCECClient::GetDevicePowerStatus(const cec_logical_address iAddress
)
704 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
706 return device
->GetPowerStatus(GetPrimaryLogicalAdddress());
707 return CEC_POWER_STATUS_UNKNOWN
;
710 uint64_t CCECClient::GetDeviceVendorId(const cec_logical_address iAddress
)
712 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
714 return device
->GetVendorId(GetPrimaryLogicalAdddress());
715 return CEC_VENDOR_UNKNOWN
;
718 uint8_t CCECClient::SendVolumeUp(bool bSendRelease
/* = true */)
720 CCECBusDevice
*device
= GetPrimaryDevice();
721 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
723 return device
&& audio
&& audio
->IsPresent() ?
724 audio
->VolumeUp(device
->GetLogicalAddress(), bSendRelease
) :
725 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
728 uint8_t CCECClient::SendVolumeDown(bool bSendRelease
/* = true */)
730 CCECBusDevice
*device
= GetPrimaryDevice();
731 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
733 return device
&& audio
&& audio
->IsPresent() ?
734 audio
->VolumeDown(device
->GetLogicalAddress(), bSendRelease
) :
735 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
738 uint8_t CCECClient::SendMuteAudio(void)
740 CCECBusDevice
*device
= GetPrimaryDevice();
741 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
743 return device
&& audio
&& audio
->IsPresent() ?
744 audio
->MuteAudio(device
->GetLogicalAddress()) :
745 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
748 uint8_t CCECClient::AudioToggleMute(void)
750 CCECBusDevice
*device
= GetPrimaryDevice();
751 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
753 return device
&& audio
&& audio
->IsPresent() ?
754 audio
->MuteAudio(device
->GetLogicalAddress()) :
755 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
758 uint8_t CCECClient::AudioMute(void)
760 CCECBusDevice
*device
= GetPrimaryDevice();
761 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
762 uint8_t iStatus
= device
&& audio
&& audio
->IsPresent() ? audio
->GetAudioStatus(device
->GetLogicalAddress()) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
763 if ((iStatus
& CEC_AUDIO_MUTE_STATUS_MASK
) != CEC_AUDIO_MUTE_STATUS_MASK
)
764 iStatus
= audio
->MuteAudio(device
->GetLogicalAddress());
769 uint8_t CCECClient::AudioUnmute(void)
771 CCECBusDevice
*device
= GetPrimaryDevice();
772 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
773 uint8_t iStatus
= device
&& audio
&& audio
->IsPresent() ? audio
->GetAudioStatus(device
->GetLogicalAddress()) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
774 if ((iStatus
& CEC_AUDIO_MUTE_STATUS_MASK
) == CEC_AUDIO_MUTE_STATUS_MASK
)
775 iStatus
= audio
->MuteAudio(device
->GetLogicalAddress());
780 uint8_t CCECClient::AudioStatus(void)
782 CCECBusDevice
*device
= GetPrimaryDevice();
783 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
784 return device
&& audio
&& audio
->IsPresent() ? audio
->GetAudioStatus(device
->GetLogicalAddress()) : (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
787 bool CCECClient::SendKeypress(const cec_logical_address iDestination
, const cec_user_control_code key
, bool bWait
/* = true */)
789 CCECBusDevice
*dest
= m_processor
->GetDevice(iDestination
);
792 dest
->TransmitKeypress(GetPrimaryLogicalAdddress(), key
, bWait
) :
796 bool CCECClient::SendKeyRelease(const cec_logical_address iDestination
, bool bWait
/* = true */)
798 CCECBusDevice
*dest
= m_processor
->GetDevice(iDestination
);
801 dest
->TransmitKeyRelease(GetPrimaryLogicalAdddress(), bWait
) :
805 bool CCECClient::GetCurrentConfiguration(libcec_configuration
&configuration
)
807 CLockObject
lock(m_mutex
);
809 // client version 1.5.0
810 snprintf(configuration
.strDeviceName
, 13, "%s", m_configuration
.strDeviceName
);
811 configuration
.deviceTypes
= m_configuration
.deviceTypes
;
812 configuration
.bAutodetectAddress
= m_configuration
.bAutodetectAddress
;
813 configuration
.iPhysicalAddress
= m_configuration
.iPhysicalAddress
;
814 configuration
.baseDevice
= m_configuration
.baseDevice
;
815 configuration
.iHDMIPort
= m_configuration
.iHDMIPort
;
816 configuration
.clientVersion
= m_configuration
.clientVersion
;
817 configuration
.serverVersion
= m_configuration
.serverVersion
;
818 configuration
.tvVendor
= m_configuration
.tvVendor
;
819 configuration
.bGetSettingsFromROM
= m_configuration
.bGetSettingsFromROM
;
820 configuration
.bUseTVMenuLanguage
= m_configuration
.bUseTVMenuLanguage
;
821 configuration
.bActivateSource
= m_configuration
.bActivateSource
;
822 configuration
.wakeDevices
= m_configuration
.wakeDevices
;
823 configuration
.powerOffDevices
= m_configuration
.powerOffDevices
;
824 configuration
.bPowerOffScreensaver
= m_configuration
.bPowerOffScreensaver
;
825 configuration
.bPowerOnScreensaver
= m_configuration
.bPowerOnScreensaver
;
826 configuration
.bPowerOffOnStandby
= m_configuration
.bPowerOffOnStandby
;
827 configuration
.bSendInactiveSource
= m_configuration
.bSendInactiveSource
;
828 configuration
.logicalAddresses
= m_configuration
.logicalAddresses
;
829 configuration
.iFirmwareVersion
= m_configuration
.iFirmwareVersion
;
830 configuration
.bPowerOffDevicesOnStandby
= m_configuration
.bPowerOffDevicesOnStandby
;
831 configuration
.bShutdownOnStandby
= m_configuration
.bShutdownOnStandby
;
832 memcpy(configuration
.strDeviceLanguage
, m_configuration
.strDeviceLanguage
, 3);
833 configuration
.iFirmwareBuildDate
= m_configuration
.iFirmwareBuildDate
;
834 configuration
.bMonitorOnly
= m_configuration
.bMonitorOnly
;
835 configuration
.cecVersion
= m_configuration
.cecVersion
;
836 configuration
.adapterType
= m_configuration
.adapterType
;
841 bool CCECClient::SetConfiguration(const libcec_configuration
&configuration
)
843 libcec_configuration defaultSettings
;
844 bool bIsRunning(m_processor
&& m_processor
->CECInitialised());
845 CCECBusDevice
*primary
= bIsRunning
? GetPrimaryDevice() : NULL
;
846 uint16_t iPA
= primary
? primary
->GetCurrentPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS
;
848 // update the callbacks
849 if (configuration
.callbacks
)
850 EnableCallbacks(configuration
.callbackParam
, configuration
.callbacks
);
852 // update the client version
853 SetClientVersion((cec_client_version
)configuration
.clientVersion
);
855 // update the OSD name
856 CStdString
strOSDName(configuration
.strDeviceName
);
857 SetOSDName(strOSDName
);
859 // update the TV vendor override
860 SetTVVendorOverride((cec_vendor_id
)configuration
.tvVendor
);
864 CLockObject
lock(m_mutex
);
865 m_configuration
.bUseTVMenuLanguage
= configuration
.bUseTVMenuLanguage
;
866 m_configuration
.bActivateSource
= configuration
.bActivateSource
;
867 m_configuration
.bGetSettingsFromROM
= configuration
.bGetSettingsFromROM
;
868 m_configuration
.wakeDevices
= configuration
.wakeDevices
;
869 m_configuration
.powerOffDevices
= configuration
.powerOffDevices
;
870 m_configuration
.bPowerOffScreensaver
= configuration
.bPowerOffScreensaver
;
871 m_configuration
.bPowerOffOnStandby
= configuration
.bPowerOffOnStandby
;
872 m_configuration
.bSendInactiveSource
= configuration
.bSendInactiveSource
;
873 m_configuration
.bPowerOffDevicesOnStandby
= configuration
.bPowerOffDevicesOnStandby
;
874 m_configuration
.bShutdownOnStandby
= configuration
.bShutdownOnStandby
;
875 memcpy(m_configuration
.strDeviceLanguage
, configuration
.strDeviceLanguage
, 3);
876 m_configuration
.bMonitorOnly
= configuration
.bMonitorOnly
;
877 m_configuration
.cecVersion
= configuration
.cecVersion
;
878 m_configuration
.adapterType
= configuration
.adapterType
;
879 m_configuration
.iDoubleTapTimeoutMs
= configuration
.iDoubleTapTimeoutMs
;
880 m_configuration
.deviceTypes
.Add(configuration
.deviceTypes
[0]);
882 if (m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_2_0_5
)
884 m_configuration
.comboKey
= configuration
.comboKey
;
885 m_configuration
.iComboKeyTimeoutMs
= configuration
.iComboKeyTimeoutMs
;
889 m_configuration
.comboKey
= defaultSettings
.comboKey
;
890 m_configuration
.iComboKeyTimeoutMs
= defaultSettings
.iComboKeyTimeoutMs
;
893 if (m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_2_1_0
)
894 m_configuration
.bPowerOnScreensaver
= configuration
.bPowerOnScreensaver
;
896 m_configuration
.bPowerOnScreensaver
= defaultSettings
.bPowerOnScreensaver
;
899 bool bNeedReinit(false);
902 if (SetDeviceTypes(configuration
.deviceTypes
))
904 // the device type changed. just copy the rest, and re-register
906 CLockObject
lock(m_mutex
);
907 m_configuration
.iPhysicalAddress
= configuration
.iPhysicalAddress
;
908 m_configuration
.baseDevice
= configuration
.baseDevice
;
909 m_configuration
.iHDMIPort
= configuration
.iHDMIPort
;
915 // set the physical address
916 SetPhysicalAddress(configuration
);
919 // persist the new configuration
920 PersistConfiguration(m_configuration
);
923 primary
= GetPrimaryDevice();
925 if (bNeedReinit
|| !primary
|| primary
->GetCurrentPhysicalAddress() != iPA
)
927 // PA or device type changed
928 m_processor
->RegisterClient(this);
930 else if (primary
&& configuration
.bActivateSource
== 1 && bIsRunning
&& !primary
->IsActiveSource())
932 // activate the source if we're not already the active source
933 primary
->ActivateSource();
939 void CCECClient::AddCommand(const cec_command
&command
)
941 // don't forward the standby opcode more than once every 10 seconds
942 if (command
.opcode
== CEC_OPCODE_STANDBY
)
944 CLockObject
lock(m_mutex
);
945 if (m_iPreventForwardingPowerOffCommand
!= 0 &&
946 m_iPreventForwardingPowerOffCommand
> GetTimeMs())
949 m_iPreventForwardingPowerOffCommand
= GetTimeMs() + CEC_FORWARD_STANDBY_MIN_INTERVAL
;
952 if (command
.destination
== CECDEVICE_BROADCAST
|| GetLogicalAddresses().IsSet(command
.destination
))
954 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
);
955 CallbackAddCommand(command
);
959 int CCECClient::MenuStateChanged(const cec_menu_state newState
)
961 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, ">> %s: %s", ToString(CEC_OPCODE_MENU_REQUEST
), ToString(newState
));
962 return CallbackMenuStateChanged(newState
);
965 void CCECClient::AddKey(bool bSendComboKey
/* = false */)
968 key
.keycode
= CEC_USER_CONTROL_CODE_UNKNOWN
;
971 CLockObject
lock(m_mutex
);
972 if (m_iCurrentButton
!= CEC_USER_CONTROL_CODE_UNKNOWN
)
974 key
.duration
= (unsigned int) (GetTimeMs() - m_buttontime
);
976 if (key
.duration
> m_configuration
.iComboKeyTimeoutMs
||
977 m_configuration
.iComboKeyTimeoutMs
== 0 ||
978 m_iCurrentButton
!= m_configuration
.comboKey
||
981 key
.keycode
= m_iCurrentButton
;
983 m_iCurrentButton
= CEC_USER_CONTROL_CODE_UNKNOWN
;
989 if (key
.keycode
!= CEC_USER_CONTROL_CODE_UNKNOWN
)
991 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "key released: %s (%1x)", ToString(key
.keycode
), key
.keycode
);
996 void CCECClient::AddKey(const cec_keypress
&key
)
998 if (key
.keycode
> CEC_USER_CONTROL_CODE_MAX
&&
999 key
.keycode
< CEC_USER_CONTROL_CODE_SELECT
)
1001 // send back the previous key if there is one
1006 cec_keypress
transmitKey(key
);
1007 cec_user_control_code
comboKey(m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_2_0_5
?
1008 m_configuration
.comboKey
: CEC_USER_CONTROL_CODE_STOP
);
1011 CLockObject
lock(m_mutex
);
1012 if (m_configuration
.iComboKeyTimeoutMs
> 0 && m_iCurrentButton
== comboKey
&& key
.duration
== 0)
1014 // stop + ok -> exit
1015 if (key
.keycode
== CEC_USER_CONTROL_CODE_SELECT
)
1016 transmitKey
.keycode
= CEC_USER_CONTROL_CODE_EXIT
;
1017 // stop + pause -> root menu
1018 else if (key
.keycode
== CEC_USER_CONTROL_CODE_PAUSE
)
1019 transmitKey
.keycode
= CEC_USER_CONTROL_CODE_ROOT_MENU
;
1020 // stop + play -> dot (which is handled as context menu in xbmc)
1021 else if (key
.keycode
== CEC_USER_CONTROL_CODE_PLAY
)
1022 transmitKey
.keycode
= CEC_USER_CONTROL_CODE_DOT
;
1023 // default, send back the previous key
1028 if (m_iCurrentButton
== key
.keycode
)
1030 m_buttontime
= GetTimeMs();
1035 if (key
.duration
== 0)
1037 m_iCurrentButton
= transmitKey
.keycode
;
1038 m_buttontime
= m_iCurrentButton
== CEC_USER_CONTROL_CODE_UNKNOWN
|| key
.duration
> 0 ? 0 : GetTimeMs();
1043 if (key
.keycode
!= comboKey
|| key
.duration
> 0)
1045 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "key pressed: %s (%1x)", ToString(transmitKey
.keycode
), transmitKey
.keycode
);
1046 CallbackAddKey(transmitKey
);
1050 void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode
)
1052 // push a keypress to the buffer with 0 duration and another with the duration set when released
1055 key
.keycode
= iButtonCode
;
1060 void CCECClient::CheckKeypressTimeout(void)
1065 CLockObject
lock(m_mutex
);
1066 uint64_t iNow
= GetTimeMs();
1067 cec_user_control_code
comboKey(m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_2_0_5
?
1068 m_configuration
.comboKey
: CEC_USER_CONTROL_CODE_STOP
);
1069 uint32_t iTimeoutMs(m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_2_0_5
?
1070 m_configuration
.iComboKeyTimeoutMs
: CEC_DEFAULT_COMBO_TIMEOUT_MS
);
1072 if (m_iCurrentButton
!= CEC_USER_CONTROL_CODE_UNKNOWN
&&
1073 ((m_iCurrentButton
== comboKey
&& iTimeoutMs
> 0 && iNow
- m_buttontime
> iTimeoutMs
) ||
1074 (m_iCurrentButton
!= comboKey
&& iNow
- m_buttontime
> CEC_BUTTON_TIMEOUT
)))
1076 key
.duration
= (unsigned int) (iNow
- m_buttontime
);
1077 key
.keycode
= m_iCurrentButton
;
1079 m_iCurrentButton
= CEC_USER_CONTROL_CODE_UNKNOWN
;
1088 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "key auto-released: %s (%1x)", ToString(key
.keycode
), key
.keycode
);
1089 CallbackAddKey(key
);
1092 bool CCECClient::EnableCallbacks(void *cbParam
, ICECCallbacks
*callbacks
)
1094 CLockObject
lock(m_cbMutex
);
1095 m_configuration
.callbackParam
= cbParam
;
1096 m_configuration
.callbacks
= callbacks
;
1100 bool CCECClient::PingAdapter(void)
1102 return m_processor
? m_processor
->PingAdapter() : false;
1105 std::string
CCECClient::GetConnectionInfo(void)
1108 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
);
1109 if (m_configuration
.iFirmwareBuildDate
!= CEC_FW_BUILD_UNKNOWN
)
1111 time_t buildTime
= (time_t)m_configuration
.iFirmwareBuildDate
;
1112 strLog
.AppendFormat(", firmware build date: %s", asctime(gmtime(&buildTime
)));
1113 strLog
= strLog
.substr(0, strLog
.length() > 0 ? (size_t)(strLog
.length() - 1) : 0); // strip \n added by asctime
1114 strLog
.append(" +0000");
1117 // log the addresses that are being used
1118 if (!m_configuration
.logicalAddresses
.IsEmpty())
1120 strLog
.append(", logical address(es) = ");
1121 CECDEVICEVEC devices
;
1122 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
1123 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
1124 strLog
.AppendFormat("%s (%X) ", (*it
)->GetLogicalAddressName(), (*it
)->GetLogicalAddress());
1127 if (!CLibCEC::IsValidPhysicalAddress(m_configuration
.iPhysicalAddress
))
1128 strLog
.AppendFormat(", base device: %s (%X), HDMI port number: %d", ToString(m_configuration
.baseDevice
), m_configuration
.baseDevice
, m_configuration
.iHDMIPort
);
1129 uint16_t iPhysicalAddress
= GetPrimaryDevice()->GetPhysicalAddress(GetLogicalAddresses().primary
, false);
1130 strLog
.AppendFormat(", physical address: %x.%x.%x.%x", (iPhysicalAddress
>> 12) & 0xF, (iPhysicalAddress
>> 8) & 0xF, (iPhysicalAddress
>> 4) & 0xF, iPhysicalAddress
& 0xF);
1132 strLog
.AppendFormat(", %s", LIB_CEC
->GetLibInfo());
1134 std::string
strReturn(strLog
.c_str());
1138 void CCECClient::SetTVVendorOverride(const cec_vendor_id id
)
1141 CLockObject
lock(m_mutex
);
1142 m_configuration
.tvVendor
= id
;
1145 if (id
!= CEC_VENDOR_UNKNOWN
)
1147 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - vendor id '%s'", __FUNCTION__
, ToString(id
));
1149 CCECBusDevice
*tv
= m_processor
? m_processor
->GetTV() : NULL
;
1151 tv
->SetVendorId((uint64_t)id
);
1154 // persist the new configuration
1155 PersistConfiguration(m_configuration
);
1158 cec_vendor_id
CCECClient::GetTVVendorOverride(void)
1160 CLockObject
lock(m_mutex
);
1161 return (cec_vendor_id
)m_configuration
.tvVendor
;
1164 void CCECClient::SetOSDName(const std::string
&strDeviceName
)
1167 CLockObject
lock(m_mutex
);
1168 snprintf(m_configuration
.strDeviceName
, 13, "%s", strDeviceName
.c_str());
1171 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using OSD name '%s'", __FUNCTION__
, strDeviceName
.c_str());
1173 CCECBusDevice
*primary
= GetPrimaryDevice();
1174 if (primary
&& !primary
->GetCurrentOSDName().Equals(strDeviceName
.c_str()))
1176 primary
->SetOSDName(strDeviceName
);
1177 if (m_processor
&& m_processor
->CECInitialised())
1178 primary
->TransmitOSDName(CECDEVICE_TV
, false);
1181 // persist the new configuration
1182 PersistConfiguration(m_configuration
);
1185 std::string
CCECClient::GetOSDName(void)
1187 CLockObject
lock(m_mutex
);
1188 std::string
strOSDName(m_configuration
.strDeviceName
);
1192 void CCECClient::SetWakeDevices(const cec_logical_addresses
&addresses
)
1195 CLockObject
lock(m_mutex
);
1196 m_configuration
.wakeDevices
= addresses
;
1198 // persist the new configuration
1199 PersistConfiguration(m_configuration
);
1202 cec_logical_addresses
CCECClient::GetWakeDevices(void)
1204 CLockObject
lock(m_mutex
);
1205 return m_configuration
.wakeDevices
;
1208 bool CCECClient::AutodetectPhysicalAddress(void)
1210 bool bPhysicalAutodetected(false);
1211 uint16_t iPhysicalAddress
= m_processor
? m_processor
->GetDetectedPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS
;
1213 if (CLibCEC::IsValidPhysicalAddress(iPhysicalAddress
))
1215 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - autodetected physical address '%04X'", __FUNCTION__
, iPhysicalAddress
);
1217 CLockObject
lock(m_mutex
);
1218 m_configuration
.iPhysicalAddress
= iPhysicalAddress
;
1219 m_configuration
.iHDMIPort
= CEC_HDMI_PORTNUMBER_NONE
;
1220 m_configuration
.baseDevice
= CECDEVICE_UNKNOWN
;
1221 bPhysicalAutodetected
= true;
1224 SetDevicePhysicalAddress(iPhysicalAddress
);
1226 return bPhysicalAutodetected
;
1229 void CCECClient::SetClientVersion(const cec_client_version version
)
1231 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using client version '%s'", __FUNCTION__
, ToString(version
));
1233 CLockObject
lock(m_mutex
);
1234 m_configuration
.clientVersion
= (uint32_t)version
;
1237 cec_client_version
CCECClient::GetClientVersion(void)
1239 CLockObject
lock(m_mutex
);
1240 return (cec_client_version
)m_configuration
.clientVersion
;
1243 bool CCECClient::SetDeviceTypes(const cec_device_type_list
&deviceTypes
)
1245 bool bNeedReinit(false);
1248 CLockObject
lock(m_mutex
);
1249 bNeedReinit
= m_processor
&& m_processor
->CECInitialised() &&
1250 (m_configuration
.deviceTypes
!= deviceTypes
);
1251 m_configuration
.deviceTypes
= deviceTypes
;
1254 // persist the new configuration
1255 PersistConfiguration(m_configuration
);
1258 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using primary device type '%s'", __FUNCTION__
, ToString(deviceTypes
[0]));
1263 cec_device_type_list
CCECClient::GetDeviceTypes(void)
1265 cec_device_type_list retVal
;
1266 CLockObject
lock(m_mutex
);
1267 retVal
= m_configuration
.deviceTypes
;
1271 bool CCECClient::SetDevicePhysicalAddress(const uint16_t iPhysicalAddress
)
1273 if (!CLibCEC::IsValidPhysicalAddress(iPhysicalAddress
))
1275 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - not setting invalid physical address %04x", __FUNCTION__
, iPhysicalAddress
);
1279 // reconfigure all devices
1280 cec_logical_address
reactivateSource(CECDEVICE_UNKNOWN
);
1281 CECDEVICEVEC devices
;
1282 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
1283 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
1285 // if this device was the active source, reactivate it afterwards
1286 if ((*it
)->IsActiveSource())
1287 reactivateSource
= (*it
)->GetLogicalAddress();
1289 // mark the device as inactive source
1290 if (IsInitialised())
1291 (*it
)->MarkAsInactiveSource();
1293 // set the new physical address
1294 (*it
)->SetPhysicalAddress(iPhysicalAddress
);
1297 if (IsInitialised())
1298 (*it
)->TransmitPhysicalAddress(false);
1301 // reactivate the previous active source
1302 if (reactivateSource
!= CECDEVICE_UNKNOWN
&&
1303 m_processor
->CECInitialised() &&
1306 CCECBusDevice
*device
= m_processor
->GetDevice(reactivateSource
);
1308 device
->ActivateSource();
1311 // persist the new configuration
1312 PersistConfiguration(m_configuration
);
1317 bool CCECClient::SwitchMonitoring(bool bEnable
)
1319 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "== %s monitoring mode ==", bEnable
? "enabling" : "disabling");
1323 m_processor
->SwitchMonitoring(bEnable
);
1324 m_configuration
.bMonitorOnly
= bEnable
;
1325 return bEnable
? true: m_processor
->RegisterClient(this);
1331 bool CCECClient::PollDevice(const cec_logical_address iAddress
)
1333 // try to find the primary device
1334 CCECBusDevice
*primary
= GetPrimaryDevice();
1335 // poll the destination, with the primary as source
1337 return primary
->TransmitPoll(iAddress
, true);
1339 return m_processor
? m_processor
->PollDevice(iAddress
) : false;
1342 cec_logical_addresses
CCECClient::GetActiveDevices(void)
1344 CECDEVICEVEC activeDevices
;
1346 m_processor
->GetDevices()->GetActive(activeDevices
);
1347 return CCECDeviceMap::ToLogicalAddresses(activeDevices
);
1350 bool CCECClient::IsActiveDevice(const cec_logical_address iAddress
)
1352 cec_logical_addresses activeDevices
= GetActiveDevices();
1353 return activeDevices
.IsSet(iAddress
);
1356 bool CCECClient::IsActiveDeviceType(const cec_device_type type
)
1358 CECDEVICEVEC activeDevices
;
1360 m_processor
->GetDevices()->GetActive(activeDevices
);
1361 CCECDeviceMap::FilterType(type
, activeDevices
);
1362 return !activeDevices
.empty();
1365 cec_logical_address
CCECClient::GetActiveSource(void)
1367 return m_processor
? m_processor
->GetActiveSource() : CECDEVICE_UNKNOWN
;
1370 bool CCECClient::IsActiveSource(const cec_logical_address iAddress
)
1372 return m_processor
? m_processor
->IsActiveSource(iAddress
) : false;
1375 bool CCECClient::SetStreamPath(const cec_logical_address iAddress
)
1377 uint16_t iPhysicalAddress
= GetDevicePhysicalAddress(iAddress
);
1378 if (iPhysicalAddress
!= CEC_INVALID_PHYSICAL_ADDRESS
)
1379 return SetStreamPath(iPhysicalAddress
);
1383 bool CCECClient::SetStreamPath(const uint16_t iPhysicalAddress
)
1385 bool bReturn(false);
1387 CCECBusDevice
*device
= GetDeviceByType(CEC_DEVICE_TYPE_TV
);
1390 device
->SetStreamPath(iPhysicalAddress
);
1391 bReturn
= device
->GetHandler()->TransmitSetStreamPath(iPhysicalAddress
, false);
1392 device
->MarkHandlerReady();
1396 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "only the TV is allowed to send CEC_OPCODE_SET_STREAM_PATH");
1402 cec_logical_addresses
CCECClient::GetLogicalAddresses(void)
1404 cec_logical_addresses addresses
;
1405 CLockObject
lock(m_mutex
);
1406 addresses
= m_configuration
.logicalAddresses
;
1410 bool CCECClient::CanPersistConfiguration(void)
1412 return m_processor
? m_processor
->CanPersistConfiguration() : false;
1415 bool CCECClient::PersistConfiguration(const libcec_configuration
&configuration
)
1417 return m_processor
&& IsRegistered() ?
1418 m_processor
->PersistConfiguration(configuration
) :
1422 void CCECClient::RescanActiveDevices(void)
1425 m_processor
->RescanActiveDevices();
1428 bool CCECClient::IsLibCECActiveSource(void)
1430 bool bReturn(false);
1433 cec_logical_address activeSource
= m_processor
->GetActiveSource();
1434 CCECBusDevice
*device
= m_processor
->GetDevice(activeSource
);
1436 bReturn
= device
->IsHandledByLibCEC() && !device
->GetHandler()->ActiveSourcePending();
1441 void CCECClient::SourceActivated(const cec_logical_address logicalAddress
)
1443 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, ">> source activated: %s (%x)", ToString(logicalAddress
), logicalAddress
);
1444 CallbackSourceActivated(true, logicalAddress
);
1447 void CCECClient::SourceDeactivated(const cec_logical_address logicalAddress
)
1449 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, ">> source deactivated: %s (%x)", ToString(logicalAddress
), logicalAddress
);
1450 CallbackSourceActivated(false, logicalAddress
);
1453 void CCECClient::CallbackAddCommand(const cec_command
&command
)
1455 CLockObject
lock(m_cbMutex
);
1456 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecCommand
)
1457 m_configuration
.callbacks
->CBCecCommand(m_configuration
.callbackParam
, command
);
1460 void CCECClient::CallbackAddKey(const cec_keypress
&key
)
1462 CLockObject
lock(m_cbMutex
);
1463 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecKeyPress
)
1465 // prevent double taps
1466 int64_t now
= GetTimeMs();
1467 if (m_lastKeypress
.keycode
!= key
.keycode
||
1469 now
- m_iLastKeypressTime
>= m_configuration
.iDoubleTapTimeoutMs
)
1472 if (key
.duration
== 0)
1473 m_iLastKeypressTime
= now
;
1474 m_lastKeypress
= key
;
1475 m_configuration
.callbacks
->CBCecKeyPress(m_configuration
.callbackParam
, key
);
1480 void CCECClient::CallbackAddLog(const cec_log_message
&message
)
1482 CLockObject
lock(m_cbMutex
);
1483 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecLogMessage
)
1484 m_configuration
.callbacks
->CBCecLogMessage(m_configuration
.callbackParam
, message
);
1487 void CCECClient::CallbackConfigurationChanged(const libcec_configuration
&config
)
1489 CLockObject
lock(m_cbMutex
);
1490 if (m_configuration
.callbacks
&&
1491 m_configuration
.callbacks
->CBCecConfigurationChanged
&&
1492 m_processor
->CECInitialised())
1493 m_configuration
.callbacks
->CBCecConfigurationChanged(m_configuration
.callbackParam
, config
);
1496 void CCECClient::CallbackSourceActivated(bool bActivated
, const cec_logical_address logicalAddress
)
1498 CLockObject
lock(m_cbMutex
);
1499 if (m_configuration
.callbacks
&&
1500 m_configuration
.callbacks
->CBCecSourceActivated
)
1501 m_configuration
.callbacks
->CBCecSourceActivated(m_configuration
.callbackParam
, logicalAddress
, bActivated
? 1 : 0);
1504 void CCECClient::CallbackAlert(const libcec_alert type
, const libcec_parameter
¶m
)
1506 CLockObject
lock(m_cbMutex
);
1507 if (m_configuration
.callbacks
&&
1508 m_configuration
.callbacks
->CBCecAlert
)
1509 m_configuration
.callbacks
->CBCecAlert(m_configuration
.callbackParam
, type
, param
);
1512 int CCECClient::CallbackMenuStateChanged(const cec_menu_state newState
)
1514 CLockObject
lock(m_cbMutex
);
1515 if (m_configuration
.callbacks
&&
1516 m_configuration
.callbacks
->CBCecMenuStateChanged
)
1517 return m_configuration
.callbacks
->CBCecMenuStateChanged(m_configuration
.callbackParam
, newState
);