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 SetConfiguration(configuration
);
56 CCECClient::~CCECClient(void)
59 m_processor
->UnregisterClient(this);
62 bool CCECClient::IsInitialised(void)
64 CLockObject
lock(m_mutex
);
65 return m_bInitialised
&& m_processor
;
68 void CCECClient::SetInitialised(bool bSetTo
)
70 CLockObject
lock(m_mutex
);
71 m_bInitialised
= bSetTo
;
74 bool CCECClient::IsRegistered(void)
76 CLockObject
lock(m_mutex
);
77 return m_bRegistered
&& m_processor
;
80 void CCECClient::SetRegistered(bool bSetTo
)
82 CLockObject
lock(m_mutex
);
83 m_bRegistered
= bSetTo
;
86 bool CCECClient::Initialise(void)
91 //TODO do the same for the other devices
92 CCECBusDevice
*primary
= m_processor
->GetDevice(m_configuration
.logicalAddresses
.primary
);
95 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "cannot find the primary device (logical address %x)", m_configuration
.logicalAddresses
.primary
);
99 /* only set our OSD name for the primary device */
100 primary
->SetOSDName(m_configuration
.strDeviceName
);
102 /* set the default menu language for devices we control */
103 primary
->SetMenuLanguage(m_configuration
.strDeviceLanguage
);
105 if (CLibCEC::IsValidPhysicalAddress(m_configuration
.iPhysicalAddress
))
107 primary
->SetPhysicalAddress(m_configuration
.iPhysicalAddress
);
108 primary
->TransmitPhysicalAddress();
112 SetHDMIPort(m_configuration
.baseDevice
, m_configuration
.iHDMIPort
, true);
115 /* make the primary device the active source if the option is set */
116 if (m_configuration
.bActivateSource
== 1)
117 primary
->ActivateSource();
119 SetInitialised(true);
123 bool CCECClient::SetHDMIPort(cec_logical_address iBaseDevice
, uint8_t iPort
, bool bForce
/* = false */)
127 // limit the HDMI port range to 1-15
128 if (iPort
< CEC_MIN_HDMI_PORTNUMBER
||
129 iPort
> CEC_MAX_HDMI_PORTNUMBER
)
133 CLockObject
lock(m_mutex
);
134 m_configuration
.baseDevice
= iBaseDevice
;
135 m_configuration
.iHDMIPort
= iPort
;
138 if (!m_processor
->IsRunning() && !bForce
)
141 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "setting HDMI port to %d on device %s (%d)", iPort
, ToString(iBaseDevice
), (int)iBaseDevice
);
143 uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS
);
144 CCECBusDevice
*baseDevice
= m_processor
->GetDevice(iBaseDevice
);
146 iPhysicalAddress
= baseDevice
->GetPhysicalAddress(m_configuration
.logicalAddresses
.primary
);
148 if (iPhysicalAddress
<= CEC_MAX_PHYSICAL_ADDRESS
)
150 if (iPhysicalAddress
== 0)
151 iPhysicalAddress
+= 0x1000 * iPort
;
152 else if (iPhysicalAddress
% 0x1000 == 0)
153 iPhysicalAddress
+= 0x100 * iPort
;
154 else if (iPhysicalAddress
% 0x100 == 0)
155 iPhysicalAddress
+= 0x10 * iPort
;
156 else if (iPhysicalAddress
% 0x10 == 0)
157 iPhysicalAddress
+= iPort
;
164 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
);
165 iPhysicalAddress
= CEC_DEFAULT_PHYSICAL_ADDRESS
;
168 SetPhysicalAddress(iPhysicalAddress
);
173 bool CCECClient::SetPhysicalAddress(uint16_t iPhysicalAddress
)
175 bool bSendActiveView(false);
177 bool bSendUpdate
= m_processor
->CECInitialised();
179 CECDEVICEVEC sendUpdatesTo
;
181 CLockObject
lock(m_mutex
);
182 m_configuration
.iPhysicalAddress
= iPhysicalAddress
;
183 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "setting physical address to '%04X'", iPhysicalAddress
);
185 bool bWasActiveSource(false);
186 CECDEVICEVEC devices
;
188 m_processor
->GetDevices()->GetLibCECControlled(devices
);
190 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
192 bWasActiveSource
|= (*it
)->IsActiveSource();
193 (*it
)->MarkAsInactiveSource();
194 (*it
)->SetPhysicalAddress(iPhysicalAddress
);
196 sendUpdatesTo
.push_back(*it
);
199 bSendActiveView
= bWasActiveSource
&& bSendUpdate
;
203 for (CECDEVICEVEC::iterator it
= sendUpdatesTo
.begin(); it
!= sendUpdatesTo
.end(); it
++)
205 (*it
)->TransmitPhysicalAddress();
206 if (bSendActiveView
&& m_configuration
.logicalAddresses
.primary
== (*it
)->GetLogicalAddress())
208 (*it
)->MarkAsActiveSource();
209 if ((*it
)->HasValidPhysicalAddress())
210 (*it
)->ActivateSource();
216 m_processor
->PersistConfiguration(&m_configuration
);
217 ConfigurationChanged(m_configuration
);
223 bool CCECClient::FindLogicalAddresses(void)
225 m_configuration
.logicalAddresses
.Clear();
227 if (m_configuration
.deviceTypes
.IsEmpty())
229 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "no device types given");
233 for (uint8_t iPtr
= 0; iPtr
< 5; iPtr
++)
235 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RESERVED
)
238 cec_logical_address
address(CECDEVICE_UNKNOWN
);
239 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RECORDING_DEVICE
)
240 address
= FindLogicalAddressRecordingDevice();
241 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_TUNER
)
242 address
= FindLogicalAddressTuner();
243 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE
)
244 address
= FindLogicalAddressPlaybackDevice();
245 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_AUDIO_SYSTEM
)
246 address
= FindLogicalAddressAudioSystem();
248 if (address
== CECDEVICE_UNKNOWN
)
250 LIB_CEC
->AddLog(CEC_LOG_ERROR
, "%s - failed to allocate device '%d', type '%s'", __FUNCTION__
, iPtr
, ToString(m_configuration
.deviceTypes
.types
[iPtr
]));
254 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - device '%d', type '%s', LA '%X'", __FUNCTION__
, iPtr
, ToString(m_configuration
.deviceTypes
.types
[iPtr
]), address
);
255 m_configuration
.logicalAddresses
.Set(address
);
261 cec_logical_address
CCECClient::FindLogicalAddressRecordingDevice(void)
263 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
265 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'recording device'");
266 if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1
))
267 retVal
= CECDEVICE_RECORDINGDEVICE1
;
268 else if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2
))
269 retVal
= CECDEVICE_RECORDINGDEVICE2
;
270 else if (m_processor
->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3
))
271 retVal
= CECDEVICE_RECORDINGDEVICE3
;
276 cec_logical_address
CCECClient::FindLogicalAddressTuner(void)
278 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
280 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'tuner'");
281 if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER1
))
282 retVal
= CECDEVICE_TUNER1
;
283 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER2
))
284 retVal
= CECDEVICE_TUNER2
;
285 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER3
))
286 retVal
= CECDEVICE_TUNER3
;
287 else if (m_processor
->TryLogicalAddress(CECDEVICE_TUNER4
))
288 retVal
= CECDEVICE_TUNER4
;
293 cec_logical_address
CCECClient::FindLogicalAddressPlaybackDevice(void)
295 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
297 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'playback device'");
298 if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1
))
299 retVal
= CECDEVICE_PLAYBACKDEVICE1
;
300 else if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2
))
301 retVal
= CECDEVICE_PLAYBACKDEVICE2
;
302 else if (m_processor
->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3
))
303 retVal
= CECDEVICE_PLAYBACKDEVICE3
;
308 cec_logical_address
CCECClient::FindLogicalAddressAudioSystem(void)
310 cec_logical_address
retVal(CECDEVICE_UNKNOWN
);
312 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "detecting logical address for type 'audiosystem'");
313 if (m_processor
->TryLogicalAddress(CECDEVICE_AUDIOSYSTEM
))
314 retVal
= CECDEVICE_AUDIOSYSTEM
;
319 CCECBusDevice
*CCECClient::GetDeviceByType(const cec_device_type type
) const
321 // get all devices that match our logical addresses
322 CECDEVICEVEC devices
;
323 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
325 // filter the type we need
326 CCECDeviceMap::FilterType(type
, devices
);
328 return devices
.empty() ?
333 bool CCECClient::ChangeDeviceType(cec_device_type from
, cec_device_type to
)
335 bool bChanged(false);
337 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "changing device type '%s' into '%s'", ToString(from
), ToString(to
));
339 CLockObject
lock(m_mutex
);
341 CCECBusDevice
*previousDevice
= GetDeviceByType(from
);
345 m_processor
->UnregisterClient(this);
347 m_configuration
.logicalAddresses
.primary
= CECDEVICE_UNREGISTERED
;
349 for (uint8_t iPtr
= 0; iPtr
< 5; iPtr
++)
351 if (m_configuration
.deviceTypes
.types
[iPtr
] == CEC_DEVICE_TYPE_RESERVED
)
354 if (m_configuration
.deviceTypes
.types
[iPtr
] == from
)
357 m_configuration
.deviceTypes
.types
[iPtr
] = to
;
359 else if (m_configuration
.deviceTypes
.types
[iPtr
] == to
&& bChanged
)
361 m_configuration
.deviceTypes
.types
[iPtr
] = CEC_DEVICE_TYPE_RESERVED
;
367 // re-register the client to set the new ackmask
368 if (!m_processor
->RegisterClient(this))
371 // copy the data from the previous device
372 CCECBusDevice
*newDevice
= GetDeviceByType(to
);
373 if (previousDevice
&& newDevice
)
375 newDevice
->SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC
);
376 newDevice
->SetCecVersion(previousDevice
->GetCecVersion(m_configuration
.logicalAddresses
.primary
, false));
377 newDevice
->SetMenuLanguage(previousDevice
->GetMenuLanguage(m_configuration
.logicalAddresses
.primary
, false));
378 newDevice
->SetMenuState(previousDevice
->GetMenuState(m_configuration
.logicalAddresses
.primary
));
379 newDevice
->SetOSDName(previousDevice
->GetOSDName(m_configuration
.logicalAddresses
.primary
, false));
380 newDevice
->SetPhysicalAddress(previousDevice
->GetCurrentPhysicalAddress());
381 newDevice
->SetPowerStatus(previousDevice
->GetPowerStatus(m_configuration
.logicalAddresses
.primary
, false));
382 newDevice
->SetVendorId(previousDevice
->GetVendorId(m_configuration
.logicalAddresses
.primary
, false));
384 if ((from
== CEC_DEVICE_TYPE_PLAYBACK_DEVICE
|| from
== CEC_DEVICE_TYPE_RECORDING_DEVICE
) &&
385 (to
== CEC_DEVICE_TYPE_PLAYBACK_DEVICE
|| to
== CEC_DEVICE_TYPE_RECORDING_DEVICE
))
387 newDevice
->AsPlaybackDevice()->SetDeckControlMode(previousDevice
->AsPlaybackDevice()->GetDeckControlMode(m_configuration
.logicalAddresses
.primary
));
388 newDevice
->AsPlaybackDevice()->SetDeckStatus(previousDevice
->AsPlaybackDevice()->GetDeckStatus(m_configuration
.logicalAddresses
.primary
));
392 // and reset the previous device to the initial state
394 previousDevice
->ResetDeviceStatus();
400 bool CCECClient::SetLogicalAddress(cec_logical_address iLogicalAddress
)
402 CLockObject
lock(m_mutex
);
403 if (m_configuration
.logicalAddresses
.primary
!= iLogicalAddress
)
405 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, "<< setting primary logical address to %1x", iLogicalAddress
);
406 m_configuration
.logicalAddresses
.primary
= iLogicalAddress
;
407 m_configuration
.logicalAddresses
.Set(iLogicalAddress
);
408 return m_processor
->RegisterClient(this);
414 bool CCECClient::Transmit(const cec_command
&data
)
416 return m_processor
? m_processor
->Transmit(data
) : false;
419 bool CCECClient::SendPowerOnDevices(cec_logical_address address
/* = CECDEVICE_TV */)
421 if (address
== CECDEVICE_BROADCAST
&& m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_5_0
)
423 CECDEVICEVEC devices
;
424 m_processor
->GetDevices()->GetWakeDevices(m_configuration
, devices
);
425 return m_processor
->PowerOnDevices(m_configuration
.logicalAddresses
.primary
, devices
);
428 return m_processor
->PowerOnDevice(m_configuration
.logicalAddresses
.primary
, address
);
431 bool CCECClient::SendStandbyDevices(cec_logical_address address
/* = CECDEVICE_BROADCAST */)
433 if (address
== CECDEVICE_BROADCAST
&& m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_5_0
)
435 CECDEVICEVEC devices
;
436 m_processor
->GetDevices()->GetPowerOffDevices(m_configuration
, devices
);
437 return m_processor
->StandbyDevices(m_configuration
.logicalAddresses
.primary
, devices
);
440 return m_processor
->StandbyDevice(m_configuration
.logicalAddresses
.primary
, address
);
443 bool CCECClient::SendSetActiveSource(cec_device_type type
/* = CEC_DEVICE_TYPE_RESERVED */)
447 CCECBusDevice
*device(NULL
);
448 CECDEVICEVEC devices
;
449 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
451 if (type
!= CEC_DEVICE_TYPE_RESERVED
)
452 CCECDeviceMap::FilterType(type
, devices
);
456 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
458 if (!devices
.empty())
459 device
= *devices
.begin();
464 if (m_processor
->IsRunning() && device
->HasValidPhysicalAddress())
465 bReturn
= device
->ActivateSource();
471 CCECPlaybackDevice
*CCECClient::GetPlaybackDevice(void)
473 CCECPlaybackDevice
*device(NULL
);
474 CECDEVICEVEC devices
;
475 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
476 CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE
, devices
);
481 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
482 CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_RECORDING_DEVICE
, devices
);
485 if (!devices
.empty())
486 device
= (*devices
.begin())->AsPlaybackDevice();
491 CCECBusDevice
*CCECClient::GetPrimaryDevice(void)
493 return m_processor
->GetDevice(m_configuration
.logicalAddresses
.primary
);
496 bool CCECClient::SendSetDeckControlMode(cec_deck_control_mode mode
, bool bSendUpdate
/* = true */)
500 CCECBusDevice
*device
= GetPlaybackDevice();
503 device
->AsPlaybackDevice()->SetDeckControlMode(mode
);
505 bReturn
= device
->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV
);
513 bool CCECClient::SendSetDeckInfo(cec_deck_info info
, bool bSendUpdate
/* = true */)
517 CCECBusDevice
*device
= GetPlaybackDevice();
520 device
->AsPlaybackDevice()->SetDeckStatus(info
);
522 bReturn
= device
->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV
);
530 bool CCECClient::SendSetMenuState(cec_menu_state state
, bool bSendUpdate
/* = true */)
532 CECDEVICEVEC devices
;
533 m_processor
->GetDevices()->GetByLogicalAddresses(devices
, m_configuration
.logicalAddresses
);
535 for (CECDEVICEVEC::iterator it
= devices
.begin(); it
!= devices
.end(); it
++)
537 (*it
)->SetMenuState(state
);
539 (*it
)->TransmitMenuState(CECDEVICE_TV
);
545 bool CCECClient::SendSetInactiveView(void)
547 CCECBusDevice
*primary
= GetPrimaryDevice();
550 primary
->MarkAsInactiveSource();
551 return primary
->TransmitInactiveSource();
556 bool CCECClient::SendSetOSDString(cec_logical_address iLogicalAddress
, cec_display_control duration
, const char *strMessage
)
558 CCECBusDevice
*primary
= GetPrimaryDevice();
560 return primary
->TransmitOSDString(iLogicalAddress
, duration
, strMessage
);
565 cec_version
CCECClient::GetDeviceCecVersion(cec_logical_address iAddress
)
567 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
569 return device
->GetCecVersion(m_configuration
.logicalAddresses
.primary
);
570 return CEC_VERSION_UNKNOWN
;
573 bool CCECClient::GetDeviceMenuLanguage(cec_logical_address iAddress
, cec_menu_language
*language
)
575 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
578 *language
= device
->GetMenuLanguage(m_configuration
.logicalAddresses
.primary
);
579 return (strcmp(language
->language
, "???") != 0);
584 cec_osd_name
CCECClient::GetDeviceOSDName(cec_logical_address iAddress
)
587 retVal
.device
= iAddress
;
590 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
593 CStdString strOSDName
= device
->GetOSDName(m_configuration
.logicalAddresses
.primary
);
594 snprintf(retVal
.name
, sizeof(retVal
.name
), "%s", strOSDName
.c_str());
595 retVal
.device
= iAddress
;
601 uint16_t CCECClient::GetDevicePhysicalAddress(cec_logical_address iAddress
)
603 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
605 return device
->GetPhysicalAddress(m_configuration
.logicalAddresses
.primary
);
606 return CEC_INVALID_PHYSICAL_ADDRESS
;
609 cec_power_status
CCECClient::GetDevicePowerStatus(cec_logical_address iAddress
)
611 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
613 return device
->GetPowerStatus(m_configuration
.logicalAddresses
.primary
);
614 return CEC_POWER_STATUS_UNKNOWN
;
617 uint64_t CCECClient::GetDeviceVendorId(cec_logical_address iAddress
)
619 CCECBusDevice
*device
= m_processor
->GetDevice(iAddress
);
621 return device
->GetVendorId(m_configuration
.logicalAddresses
.primary
);
622 return CEC_VENDOR_UNKNOWN
;
625 uint8_t CCECClient::SendVolumeUp(bool bSendRelease
/* = true */)
627 CCECBusDevice
*device
= GetPrimaryDevice();
628 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
630 return device
&& audio
&& audio
->IsPresent() ?
631 audio
->VolumeUp(device
->GetLogicalAddress(), bSendRelease
) :
632 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
635 uint8_t CCECClient::SendVolumeDown(bool bSendRelease
/* = true */)
637 CCECBusDevice
*device
= GetPrimaryDevice();
638 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
640 return device
&& audio
&& audio
->IsPresent() ?
641 audio
->VolumeDown(device
->GetLogicalAddress(), bSendRelease
) :
642 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
645 uint8_t CCECClient::SendMuteAudio(void)
647 CCECBusDevice
*device
= GetPrimaryDevice();
648 CCECAudioSystem
*audio
= m_processor
->GetAudioSystem();
650 return device
&& audio
&& audio
->IsPresent() ?
651 audio
->MuteAudio(device
->GetLogicalAddress()) :
652 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN
;
655 bool CCECClient::SendKeypress(cec_logical_address iDestination
, cec_user_control_code key
, bool bWait
/* = true */)
657 CCECBusDevice
*device
= GetPrimaryDevice();
658 CCECBusDevice
*dest
= m_processor
->GetDevice(iDestination
);
660 return device
&& dest
?
661 device
->TransmitKeypress(m_configuration
.logicalAddresses
.primary
, key
, bWait
) :
665 bool CCECClient::SendKeyRelease(cec_logical_address iDestination
, bool bWait
/* = true */)
667 CCECBusDevice
*device
= GetPrimaryDevice();
668 CCECBusDevice
*dest
= m_processor
->GetDevice(iDestination
);
670 return device
&& dest
?
671 device
->TransmitKeyRelease(m_configuration
.logicalAddresses
.primary
, bWait
) :
675 bool CCECClient::GetCurrentConfiguration(libcec_configuration
*configuration
)
677 // client version 1.5.0
678 snprintf(configuration
->strDeviceName
, 13, "%s", m_configuration
.strDeviceName
);
679 configuration
->deviceTypes
= m_configuration
.deviceTypes
;
680 configuration
->bAutodetectAddress
= m_configuration
.bAutodetectAddress
;
681 configuration
->iPhysicalAddress
= m_configuration
.iPhysicalAddress
;
682 configuration
->baseDevice
= m_configuration
.baseDevice
;
683 configuration
->iHDMIPort
= m_configuration
.iHDMIPort
;
684 configuration
->clientVersion
= m_configuration
.clientVersion
;
685 configuration
->serverVersion
= m_configuration
.serverVersion
;
686 configuration
->tvVendor
= m_configuration
.tvVendor
;
688 configuration
->bGetSettingsFromROM
= m_configuration
.bGetSettingsFromROM
;
689 configuration
->bUseTVMenuLanguage
= m_configuration
.bUseTVMenuLanguage
;
690 configuration
->bActivateSource
= m_configuration
.bActivateSource
;
691 configuration
->wakeDevices
= m_configuration
.wakeDevices
;
692 configuration
->powerOffDevices
= m_configuration
.powerOffDevices
;
693 configuration
->bPowerOffScreensaver
= m_configuration
.bPowerOffScreensaver
;
694 configuration
->bPowerOffOnStandby
= m_configuration
.bPowerOffOnStandby
;
696 // client version 1.5.1
697 if (configuration
->clientVersion
>= CEC_CLIENT_VERSION_1_5_1
)
698 configuration
->bSendInactiveSource
= m_configuration
.bSendInactiveSource
;
700 // client version 1.5.3
701 if (configuration
->clientVersion
>= CEC_CLIENT_VERSION_1_5_3
)
702 configuration
->logicalAddresses
= m_configuration
.logicalAddresses
;
704 // client version 1.6.0
705 if (configuration
->clientVersion
>= CEC_CLIENT_VERSION_1_6_0
)
707 configuration
->iFirmwareVersion
= m_configuration
.iFirmwareVersion
;
708 configuration
->bPowerOffDevicesOnStandby
= m_configuration
.bPowerOffDevicesOnStandby
;
709 configuration
->bShutdownOnStandby
= m_configuration
.bShutdownOnStandby
;
712 // client version 1.6.2
713 if (configuration
->clientVersion
>= CEC_CLIENT_VERSION_1_6_2
)
715 memcpy(configuration
->strDeviceLanguage
, m_configuration
.strDeviceLanguage
, 3);
716 configuration
->iFirmwareBuildDate
= m_configuration
.iFirmwareBuildDate
;
721 bool CCECClient::SetConfiguration(const libcec_configuration
*configuration
)
724 bool bIsRunning(m_processor
&& m_processor
->IsRunning());
726 if (configuration
->callbacks
)
728 m_configuration
.callbacks
= configuration
->callbacks
;
729 m_configuration
.callbackParam
= configuration
->callbackParam
;
733 CCECBusDevice
*primary
= bIsRunning
? GetPrimaryDevice() : NULL
;
734 cec_device_type oldPrimaryType
= primary
? primary
->GetType() : CEC_DEVICE_TYPE_RECORDING_DEVICE
;
736 m_configuration
.clientVersion
= configuration
->clientVersion
;
737 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using client version '%s'", __FUNCTION__
, ToString((cec_client_version
)configuration
->clientVersion
));
739 // client version 1.5.0
742 bool bDeviceTypeChanged
= bIsRunning
&& m_configuration
.deviceTypes
!= configuration
->deviceTypes
;
743 m_configuration
.deviceTypes
= configuration
->deviceTypes
;
744 if (bDeviceTypeChanged
)
745 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using primary device type '%s'", __FUNCTION__
, ToString(configuration
->deviceTypes
[0]));
747 bool bPhysicalAddressChanged(false);
749 // autodetect address
750 bool bPhysicalAutodetected(false);
751 if (bIsRunning
&& configuration
->bAutodetectAddress
== 1)
753 uint16_t iPhysicalAddress
= m_processor
->GetDetectedPhysicalAddress();
754 if (CLibCEC::IsValidPhysicalAddress(iPhysicalAddress
))
757 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - autodetected physical address '%04X'", __FUNCTION__
, iPhysicalAddress
);
759 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using physical address '%04X'", __FUNCTION__
, iPhysicalAddress
);
760 bPhysicalAddressChanged
= (m_configuration
.iPhysicalAddress
!= iPhysicalAddress
);
761 m_configuration
.iPhysicalAddress
= iPhysicalAddress
;
762 m_configuration
.iHDMIPort
= CEC_HDMI_PORTNUMBER_NONE
;
763 m_configuration
.baseDevice
= CECDEVICE_UNKNOWN
;
764 bPhysicalAutodetected
= true;
769 if (!bPhysicalAutodetected
)
771 uint16_t iPhysicalAddress(CLibCEC::IsValidPhysicalAddress(configuration
->iPhysicalAddress
) ? configuration
->iPhysicalAddress
: CEC_PHYSICAL_ADDRESS_TV
);
772 bPhysicalAddressChanged
= bIsRunning
&& m_configuration
.iPhysicalAddress
!= iPhysicalAddress
;
773 if (bPhysicalAddressChanged
)
775 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - physical address '%04X'", __FUNCTION__
, iPhysicalAddress
);
776 m_configuration
.iPhysicalAddress
= iPhysicalAddress
;
780 bool bHdmiPortChanged(false);
781 if (!bPhysicalAutodetected
&& !CLibCEC::IsValidPhysicalAddress(configuration
->iPhysicalAddress
))
784 bHdmiPortChanged
= bIsRunning
&& m_configuration
.baseDevice
!= configuration
->baseDevice
;
785 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using base device '%x'", __FUNCTION__
, (int)configuration
->baseDevice
);
786 m_configuration
.baseDevice
= configuration
->baseDevice
;
789 bHdmiPortChanged
|= bIsRunning
&& m_configuration
.iHDMIPort
!= configuration
->iHDMIPort
;
790 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using HDMI port '%d'", __FUNCTION__
, configuration
->iHDMIPort
);
791 m_configuration
.iHDMIPort
= configuration
->iHDMIPort
;
795 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - resetting HDMI port and base device to defaults", __FUNCTION__
);
796 m_configuration
.baseDevice
= CECDEVICE_UNKNOWN
;
797 m_configuration
.iHDMIPort
= CEC_HDMI_PORTNUMBER_NONE
;
800 bReinit
= bPhysicalAddressChanged
|| bHdmiPortChanged
|| bDeviceTypeChanged
;
803 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - using OSD name '%s'", __FUNCTION__
, configuration
->strDeviceName
);
804 snprintf(m_configuration
.strDeviceName
, 13, "%s", configuration
->strDeviceName
);
805 if (primary
&& !primary
->GetOSDName(m_configuration
.logicalAddresses
.primary
, false).Equals(m_configuration
.strDeviceName
))
807 primary
->SetOSDName(m_configuration
.strDeviceName
);
808 if (!bReinit
&& bIsRunning
)
809 primary
->TransmitOSDName(CECDEVICE_TV
);
812 // tv vendor id override
813 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "%s - vendor id '%s'", __FUNCTION__
, ToString((cec_vendor_id
)configuration
->tvVendor
));
814 if (m_processor
&& m_configuration
.tvVendor
!= configuration
->tvVendor
)
816 m_configuration
.tvVendor
= configuration
->tvVendor
;
817 m_processor
->GetTV()->SetVendorId((uint64_t)m_configuration
.tvVendor
);
821 if (m_configuration
.wakeDevices
!= configuration
->wakeDevices
)
823 m_configuration
.wakeDevices
= configuration
->wakeDevices
;
824 if (!bReinit
&& bIsRunning
)
825 SendPowerOnDevices();
829 m_configuration
.bUseTVMenuLanguage
= configuration
->bUseTVMenuLanguage
;
830 m_configuration
.bActivateSource
= configuration
->bActivateSource
;
831 m_configuration
.bGetSettingsFromROM
= configuration
->bGetSettingsFromROM
;
832 m_configuration
.powerOffDevices
= configuration
->powerOffDevices
;
833 m_configuration
.bPowerOffScreensaver
= configuration
->bPowerOffScreensaver
;
834 m_configuration
.bPowerOffOnStandby
= configuration
->bPowerOffOnStandby
;
836 // client version 1.5.1
837 if (configuration
->clientVersion
>= CEC_CLIENT_VERSION_1_5_1
)
838 m_configuration
.bSendInactiveSource
= configuration
->bSendInactiveSource
;
840 // client version 1.6.0
841 if (configuration
->clientVersion
>= CEC_CLIENT_VERSION_1_6_0
)
843 m_configuration
.bPowerOffDevicesOnStandby
= configuration
->bPowerOffDevicesOnStandby
;
844 m_configuration
.bShutdownOnStandby
= configuration
->bShutdownOnStandby
;
847 // client version 1.6.2
848 if (configuration
->clientVersion
>= CEC_CLIENT_VERSION_1_6_2
)
850 memcpy(m_configuration
.strDeviceLanguage
, configuration
->strDeviceLanguage
, 3);
853 // ensure that there is at least 1 device type set
854 if (m_configuration
.deviceTypes
.IsEmpty())
855 m_configuration
.deviceTypes
.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE
);
858 m_processor
->GetTV()->ReplaceHandler(false);
861 if (bReinit
|| m_configuration
.logicalAddresses
.IsEmpty())
863 if (bDeviceTypeChanged
)
864 bReturn
= ChangeDeviceType(oldPrimaryType
, m_configuration
.deviceTypes
[0]);
865 else if (CLibCEC::IsValidPhysicalAddress(m_configuration
.iPhysicalAddress
))
866 bReturn
= SetPhysicalAddress(m_configuration
.iPhysicalAddress
);
867 else if (m_configuration
.baseDevice
!= CECDEVICE_UNKNOWN
&& m_configuration
.iHDMIPort
!= CEC_HDMI_PORTNUMBER_NONE
)
868 bReturn
= SetHDMIPort(m_configuration
.baseDevice
, m_configuration
.iHDMIPort
);
870 else if (m_configuration
.bActivateSource
== 1 && bIsRunning
&& !m_processor
->IsActiveSource(m_configuration
.logicalAddresses
.primary
))
872 // activate the source if we're not already the active source
873 m_processor
->SetActiveSource(m_configuration
.deviceTypes
.types
[0]);
876 // persist the configuration
878 m_processor
->PersistConfiguration(&m_configuration
);
883 void CCECClient::AddCommand(const cec_command
&command
)
885 CLockObject
lock(m_mutex
);
887 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
);
889 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecCommand
)
890 m_configuration
.callbacks
->CBCecCommand(m_configuration
.callbackParam
, command
);
891 else if (!m_commandBuffer
.Push(command
))
892 LIB_CEC
->AddLog(CEC_LOG_WARNING
, "command buffer is full");
895 int CCECClient::MenuStateChanged(const cec_menu_state newState
)
897 CLockObject
lock(m_mutex
);
899 LIB_CEC
->AddLog(CEC_LOG_NOTICE
, ">> %s: %s", ToString(CEC_OPCODE_MENU_REQUEST
), ToString(newState
));
901 if (m_configuration
.callbacks
&&
902 m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_6_2
&&
903 m_configuration
.callbacks
->CBCecMenuStateChanged
)
904 return m_configuration
.callbacks
->CBCecMenuStateChanged(m_configuration
.callbackParam
, newState
);
909 void CCECClient::Alert(const libcec_alert type
, const libcec_parameter
¶m
)
911 CLockObject
lock(m_mutex
);
913 if (m_configuration
.callbacks
&&
914 m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_6_0
&&
915 m_configuration
.callbacks
->CBCecAlert
)
916 m_configuration
.callbacks
->CBCecAlert(m_configuration
.callbackParam
, type
, param
);
919 void CCECClient::AddLog(const cec_log_message
&message
)
921 CLockObject
lock(m_logMutex
);
922 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecLogMessage
)
923 m_configuration
.callbacks
->CBCecLogMessage(m_configuration
.callbackParam
, message
);
925 m_logBuffer
.Push(message
);
928 void CCECClient::AddKey(void)
930 CLockObject
lock(m_mutex
);
932 if (m_iCurrentButton
!= CEC_USER_CONTROL_CODE_UNKNOWN
)
936 key
.duration
= (unsigned int) (GetTimeMs() - m_buttontime
);
937 key
.keycode
= m_iCurrentButton
;
938 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "key released: %1x", key
.keycode
);
940 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecKeyPress
)
941 m_configuration
.callbacks
->CBCecKeyPress(m_configuration
.callbackParam
, key
);
943 m_keyBuffer
.Push(key
);
944 m_iCurrentButton
= CEC_USER_CONTROL_CODE_UNKNOWN
;
950 void CCECClient::AddKey(const cec_keypress
&key
)
952 CLockObject
lock(m_mutex
);
954 LIB_CEC
->AddLog(CEC_LOG_DEBUG
, "key pressed: %1x", key
.keycode
);
956 if (m_configuration
.callbacks
&& m_configuration
.callbacks
->CBCecKeyPress
)
957 m_configuration
.callbacks
->CBCecKeyPress(m_configuration
.callbackParam
, key
);
959 m_keyBuffer
.Push(key
);
961 m_iCurrentButton
= key
.duration
> 0 ? CEC_USER_CONTROL_CODE_UNKNOWN
: key
.keycode
;
962 m_buttontime
= key
.duration
> 0 ? 0 : GetTimeMs();
965 void CCECClient::SetCurrentButton(cec_user_control_code iButtonCode
)
967 /* push keypress to the keybuffer with 0 duration.
968 push another press to the keybuffer with the duration set when the button is released */
971 key
.keycode
= iButtonCode
;
976 void CCECClient::CheckKeypressTimeout(void)
978 if (m_iCurrentButton
!= CEC_USER_CONTROL_CODE_UNKNOWN
&& GetTimeMs() - m_buttontime
> CEC_BUTTON_TIMEOUT
)
981 m_iCurrentButton
= CEC_USER_CONTROL_CODE_UNKNOWN
;
985 void CCECClient::ConfigurationChanged(const libcec_configuration
&config
)
987 CLockObject
lock(m_mutex
);
989 if (m_configuration
.callbacks
&&
990 m_configuration
.clientVersion
>= CEC_CLIENT_VERSION_1_5_0
&&
991 m_configuration
.callbacks
->CBCecConfigurationChanged
&&
992 m_processor
->CECInitialised())
993 m_configuration
.callbacks
->CBCecConfigurationChanged(m_configuration
.callbackParam
, config
);
996 bool CCECClient::EnableCallbacks(void *cbParam
, ICECCallbacks
*callbacks
)
998 CLockObject
lock(m_mutex
);
999 m_configuration
.callbackParam
= cbParam
;
1000 m_configuration
.callbacks
= callbacks
;
1004 bool CCECClient::GetNextLogMessage(cec_log_message
*message
)
1006 return (m_logBuffer
.Pop(*message
));
1009 bool CCECClient::GetNextKeypress(cec_keypress
*key
)
1011 return m_keyBuffer
.Pop(*key
);
1014 bool CCECClient::GetNextCommand(cec_command
*command
)
1016 return m_commandBuffer
.Pop(*command
);