cec: check if the processor thread is marked as initialised, not if the thread is...
[deb_libcec.git] / src / lib / CECClient.cpp
1 /*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
5 * libCEC(R) is an original work, containing original code.
6 *
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
8 *
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.
13 *
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.
18 *
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.
22 *
23 *
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
26 *
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/
31 */
32
33 #include "CECClient.h"
34 #include "CECProcessor.h"
35 #include "LibCEC.h"
36 #include "devices/CECPlaybackDevice.h"
37 #include "devices/CECAudioSystem.h"
38 #include "devices/CECTV.h"
39
40 using namespace CEC;
41 using namespace PLATFORM;
42
43 #define LIB_CEC m_processor->GetLib()
44 #define ToString(x) LIB_CEC->ToString(x)
45
46 CCECClient::CCECClient(CCECProcessor *processor, const libcec_configuration &configuration) :
47 m_processor(processor),
48 m_bInitialised(false),
49 m_bRegistered(false),
50 m_iCurrentButton(CEC_USER_CONTROL_CODE_UNKNOWN),
51 m_buttontime(0)
52 {
53 // set the initial configuration
54 SetConfiguration(configuration);
55 }
56
57 CCECClient::~CCECClient(void)
58 {
59 // unregister the client
60 if (m_processor && IsRegistered())
61 m_processor->UnregisterClient(this);
62 }
63
64 bool CCECClient::IsInitialised(void)
65 {
66 CLockObject lock(m_mutex);
67 return m_bInitialised && m_processor;
68 }
69
70 void CCECClient::SetInitialised(bool bSetTo)
71 {
72 CLockObject lock(m_mutex);
73 m_bInitialised = bSetTo;
74 }
75
76 bool CCECClient::IsRegistered(void)
77 {
78 CLockObject lock(m_mutex);
79 return m_bRegistered && m_processor;
80 }
81
82 void CCECClient::SetRegistered(bool bSetTo)
83 {
84 CLockObject lock(m_mutex);
85 m_bRegistered = bSetTo;
86 }
87
88 bool CCECClient::OnRegister(void)
89 {
90 // return false if already initialised
91 if (IsInitialised())
92 return true;
93
94 // get all device we control
95 CECDEVICEVEC devices;
96 m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
97
98 // return false when no devices were found
99 if (devices.empty())
100 {
101 LIB_CEC->AddLog(CEC_LOG_WARNING, "cannot find the primary device (logical address %x)", GetPrimaryLogicalAdddress());
102 return false;
103 }
104
105 // mark as initialised
106 SetInitialised(true);
107
108 // configure all devices
109 for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
110 {
111 // only set our OSD name for the primary device
112 if ((*it)->GetLogicalAddress() == GetPrimaryLogicalAdddress())
113 (*it)->SetOSDName(m_configuration.strDeviceName);
114
115 // set the default menu language for devices we control
116 (*it)->SetMenuLanguage(m_configuration.strDeviceLanguage);
117 }
118
119 // set the physical address
120 SetPhysicalAddress(m_configuration);
121
122 // ensure that we know the vendor id of the TV, so we are using the correct handler
123 m_processor->GetTV()->GetVendorId(GetPrimaryLogicalAdddress());
124
125 // make the primary device the active source if the option is set
126 if (m_configuration.bActivateSource == 1)
127 GetPrimaryDevice()->ActivateSource();
128
129 return true;
130 }
131
132 bool CCECClient::SetHDMIPort(const cec_logical_address iBaseDevice, const uint8_t iPort, bool bForce /* = false */)
133 {
134 bool bReturn(false);
135
136 // limit the HDMI port range to 1-15
137 if (iPort < CEC_MIN_HDMI_PORTNUMBER ||
138 iPort > CEC_MAX_HDMI_PORTNUMBER)
139 return bReturn;
140
141 LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting HDMI port to %d on device %s (%d)", iPort, ToString(iBaseDevice), (int)iBaseDevice);
142
143 // update the configuration
144 {
145 CLockObject lock(m_mutex);
146 m_configuration.baseDevice = iBaseDevice;
147 m_configuration.iHDMIPort = iPort;
148 }
149
150 // don't continue if the connection isn't opened
151 if (!m_processor->CECInitialised() && !bForce)
152 return true;
153
154 // get the PA of the base device
155 uint16_t iPhysicalAddress(CEC_INVALID_PHYSICAL_ADDRESS);
156 CCECBusDevice *baseDevice = m_processor->GetDevice(iBaseDevice);
157 if (baseDevice)
158 iPhysicalAddress = baseDevice->GetPhysicalAddress(GetPrimaryLogicalAdddress());
159
160 // add our port number
161 if (iPhysicalAddress <= CEC_MAX_PHYSICAL_ADDRESS)
162 {
163 if (iPhysicalAddress == 0)
164 iPhysicalAddress += 0x1000 * iPort;
165 else if (iPhysicalAddress % 0x1000 == 0)
166 iPhysicalAddress += 0x100 * iPort;
167 else if (iPhysicalAddress % 0x100 == 0)
168 iPhysicalAddress += 0x10 * iPort;
169 else if (iPhysicalAddress % 0x10 == 0)
170 iPhysicalAddress += iPort;
171
172 bReturn = true;
173 }
174
175 // set the default address when something went wrong
176 if (!bReturn)
177 {
178 LIB_CEC->AddLog(CEC_LOG_WARNING, "failed to set the physical address to %04X, setting it to the default value %04X", iPhysicalAddress, CEC_DEFAULT_PHYSICAL_ADDRESS);
179 iPhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS;
180 }
181
182 // and set the address
183 SetDevicePhysicalAddress(iPhysicalAddress);
184
185 ConfigurationChanged(m_configuration);
186
187 return bReturn;
188 }
189
190 void CCECClient::ResetPhysicalAddress(void)
191 {
192 SetPhysicalAddress(m_configuration);
193 }
194
195 void CCECClient::SetPhysicalAddress(const libcec_configuration &configuration)
196 {
197 // try to autodetect the address
198 bool bPASet(false);
199 if (m_processor->CECInitialised() && configuration.bAutodetectAddress == 1)
200 bPASet = AutodetectPhysicalAddress();
201
202 // try to use physical address setting
203 if (!bPASet && CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress))
204 bPASet = SetPhysicalAddress(configuration.iPhysicalAddress);
205
206 // use the base device + hdmi port settings
207 if (!bPASet)
208 bPASet = SetHDMIPort(configuration.baseDevice, configuration.iHDMIPort);
209
210 // reset to defaults if something went wrong
211 if (!bPASet)
212 {
213 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - resetting HDMI port and base device to defaults", __FUNCTION__);
214 m_configuration.baseDevice = CECDEVICE_UNKNOWN;
215 m_configuration.iHDMIPort = CEC_HDMI_PORTNUMBER_NONE;
216 }
217 }
218
219 bool CCECClient::SetPhysicalAddress(const uint16_t iPhysicalAddress)
220 {
221 // update the configuration
222 {
223 CLockObject lock(m_mutex);
224 if (m_configuration.iPhysicalAddress == iPhysicalAddress)
225 {
226 LIB_CEC->AddLog(CEC_LOG_DEBUG, "physical address unchanged (%04X)", iPhysicalAddress);
227 return true;
228 }
229 else
230 {
231 m_configuration.iPhysicalAddress = iPhysicalAddress;
232 LIB_CEC->AddLog(CEC_LOG_DEBUG, "setting physical address to '%04X'", iPhysicalAddress);
233 }
234 }
235
236 // persist the new configuration
237 if (m_processor->CECInitialised())
238 m_processor->PersistConfiguration(m_configuration);
239
240 // set the physical address for each device
241 SetDevicePhysicalAddress(iPhysicalAddress);
242
243 // and send back the updated configuration
244 ConfigurationChanged(m_configuration);
245
246 return true;
247 }
248
249 bool CCECClient::AllocateLogicalAddresses(void)
250 {
251 // reset all previous LAs that were set
252 m_configuration.logicalAddresses.Clear();
253
254 // display an error if no device types are set
255 if (m_configuration.deviceTypes.IsEmpty())
256 {
257 LIB_CEC->AddLog(CEC_LOG_ERROR, "no device types given");
258 return false;
259 }
260
261 // check each entry of the list
262 for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
263 {
264 if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
265 continue;
266
267 // find an LA for this type
268 cec_logical_address address(CECDEVICE_UNKNOWN);
269 if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RECORDING_DEVICE)
270 address = AllocateLogicalAddressRecordingDevice();
271 if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_TUNER)
272 address = AllocateLogicalAddressTuner();
273 if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_PLAYBACK_DEVICE)
274 address = AllocateLogicalAddressPlaybackDevice();
275 if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
276 address = AllocateLogicalAddressAudioSystem();
277
278 // display an error if no LA could be allocated
279 if (address == CECDEVICE_UNKNOWN)
280 {
281 LIB_CEC->AddLog(CEC_LOG_ERROR, "%s - failed to allocate device '%d', type '%s'", __FUNCTION__, iPtr, ToString(m_configuration.deviceTypes.types[iPtr]));
282 return false;
283 }
284
285 // display the registered LA
286 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - device '%d', type '%s', LA '%X'", __FUNCTION__, iPtr, ToString(m_configuration.deviceTypes.types[iPtr]), address);
287 m_configuration.logicalAddresses.Set(address);
288 }
289
290 return true;
291 }
292
293 cec_logical_address CCECClient::AllocateLogicalAddressRecordingDevice(void)
294 {
295 cec_logical_address retVal(CECDEVICE_UNKNOWN);
296
297 LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'recording device'");
298 if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE1))
299 retVal = CECDEVICE_RECORDINGDEVICE1;
300 else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE2))
301 retVal = CECDEVICE_RECORDINGDEVICE2;
302 else if (m_processor->TryLogicalAddress(CECDEVICE_RECORDINGDEVICE3))
303 retVal = CECDEVICE_RECORDINGDEVICE3;
304
305 return retVal;
306 }
307
308 cec_logical_address CCECClient::AllocateLogicalAddressTuner(void)
309 {
310 cec_logical_address retVal(CECDEVICE_UNKNOWN);
311
312 LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'tuner'");
313 if (m_processor->TryLogicalAddress(CECDEVICE_TUNER1))
314 retVal = CECDEVICE_TUNER1;
315 else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER2))
316 retVal = CECDEVICE_TUNER2;
317 else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER3))
318 retVal = CECDEVICE_TUNER3;
319 else if (m_processor->TryLogicalAddress(CECDEVICE_TUNER4))
320 retVal = CECDEVICE_TUNER4;
321
322 return retVal;
323 }
324
325 cec_logical_address CCECClient::AllocateLogicalAddressPlaybackDevice(void)
326 {
327 cec_logical_address retVal(CECDEVICE_UNKNOWN);
328
329 LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'playback device'");
330 if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE1))
331 retVal = CECDEVICE_PLAYBACKDEVICE1;
332 else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE2))
333 retVal = CECDEVICE_PLAYBACKDEVICE2;
334 else if (m_processor->TryLogicalAddress(CECDEVICE_PLAYBACKDEVICE3))
335 retVal = CECDEVICE_PLAYBACKDEVICE3;
336
337 return retVal;
338 }
339
340 cec_logical_address CCECClient::AllocateLogicalAddressAudioSystem(void)
341 {
342 cec_logical_address retVal(CECDEVICE_UNKNOWN);
343
344 LIB_CEC->AddLog(CEC_LOG_DEBUG, "detecting logical address for type 'audiosystem'");
345 if (m_processor->TryLogicalAddress(CECDEVICE_AUDIOSYSTEM))
346 retVal = CECDEVICE_AUDIOSYSTEM;
347
348 return retVal;
349 }
350
351 CCECBusDevice *CCECClient::GetDeviceByType(const cec_device_type type) const
352 {
353 // get all devices that match our logical addresses
354 CECDEVICEVEC devices;
355 m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
356
357 // filter the type we need
358 CCECDeviceMap::FilterType(type, devices);
359
360 return devices.empty() ?
361 NULL :
362 *devices.begin();
363 }
364
365 bool CCECClient::ChangeDeviceType(const cec_device_type from, const cec_device_type to)
366 {
367 LIB_CEC->AddLog(CEC_LOG_NOTICE, "changing device type '%s' into '%s'", ToString(from), ToString(to));
368
369 CLockObject lock(m_mutex);
370
371 // get the previous device that was allocated
372 CCECBusDevice *previousDevice = GetDeviceByType(from);
373 if (!previousDevice)
374 return false;
375
376 // change the type in the device type list
377 bool bChanged(false);
378 for (uint8_t iPtr = 0; iPtr < 5; iPtr++)
379 {
380 if (m_configuration.deviceTypes.types[iPtr] == CEC_DEVICE_TYPE_RESERVED)
381 continue;
382
383 if (m_configuration.deviceTypes.types[iPtr] == from)
384 {
385 bChanged = true;
386 m_configuration.deviceTypes.types[iPtr] = to;
387 }
388 else if (m_configuration.deviceTypes.types[iPtr] == to && bChanged)
389 {
390 // ensure that dupes are removed
391 m_configuration.deviceTypes.types[iPtr] = CEC_DEVICE_TYPE_RESERVED;
392 }
393 }
394
395 // re-register the client to set the new ackmask
396 if (!m_processor->RegisterClient(this))
397 return false;
398
399 return true;
400 }
401
402 bool CCECClient::SetLogicalAddress(const cec_logical_address iLogicalAddress)
403 {
404 CLockObject lock(m_mutex);
405 if (GetPrimaryLogicalAdddress() != iLogicalAddress)
406 {
407 {
408 CLockObject lock(m_mutex);
409 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< setting primary logical address to %1x", iLogicalAddress);
410 m_configuration.logicalAddresses.primary = iLogicalAddress;
411 m_configuration.logicalAddresses.Set(iLogicalAddress);
412 }
413 return m_processor->RegisterClient(this);
414 }
415
416 return true;
417 }
418
419 bool CCECClient::Transmit(const cec_command &data)
420 {
421 return m_processor ? m_processor->Transmit(data) : false;
422 }
423
424 bool CCECClient::SendPowerOnDevices(const cec_logical_address address /* = CECDEVICE_TV */)
425 {
426 // if the broadcast address if set as destination and the client version >=1.5.0, read the wakeDevices setting
427 if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
428 {
429 CECDEVICEVEC devices;
430 m_processor->GetDevices()->GetWakeDevices(m_configuration, devices);
431 return m_processor->PowerOnDevices(GetPrimaryLogicalAdddress(), devices);
432 }
433
434 return m_processor->PowerOnDevice(GetPrimaryLogicalAdddress(), address);
435 }
436
437 bool CCECClient::SendStandbyDevices(const cec_logical_address address /* = CECDEVICE_BROADCAST */)
438 {
439 // if the broadcast address if set as destination and the client version >=1.5.0, read the standbyDevices setting
440 if (address == CECDEVICE_BROADCAST && m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0)
441 {
442 CECDEVICEVEC devices;
443 m_processor->GetDevices()->GetPowerOffDevices(m_configuration, devices);
444 return m_processor->StandbyDevices(GetPrimaryLogicalAdddress(), devices);
445 }
446
447 return m_processor->StandbyDevice(GetPrimaryLogicalAdddress(), address);
448 }
449
450 bool CCECClient::SendSetActiveSource(const cec_device_type type /* = CEC_DEVICE_TYPE_RESERVED */)
451 {
452 // get the devices that are controlled by us
453 CECDEVICEVEC devices;
454 m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
455
456 // filter out the device that matches the given type
457 if (type != CEC_DEVICE_TYPE_RESERVED)
458 CCECDeviceMap::FilterType(type, devices);
459
460 // no devices left, re-fetch the list of devices that are controlled by us
461 if (devices.empty())
462 m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
463
464 if (!devices.empty())
465 {
466 // get the first device from the list
467 CCECBusDevice *device = *devices.begin();
468
469 // and activate it
470 if (!m_processor->CECInitialised())
471 device->MarkAsActiveSource();
472 else if (device->HasValidPhysicalAddress())
473 return device->ActivateSource();
474 }
475
476 return false;
477 }
478
479 CCECPlaybackDevice *CCECClient::GetPlaybackDevice(void)
480 {
481 CCECPlaybackDevice *device(NULL);
482 CECDEVICEVEC devices;
483
484 // get the playback devices
485 m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
486 CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_PLAYBACK_DEVICE, devices);
487
488 // no matches, get the recording devices
489 if (devices.empty())
490 {
491 m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
492 CCECDeviceMap::FilterType(CEC_DEVICE_TYPE_RECORDING_DEVICE, devices);
493 }
494
495 // get the first device that matches, and cast it to CCECPlaybackDevice
496 if (!devices.empty())
497 device = (*devices.begin())->AsPlaybackDevice();
498
499 return device;
500 }
501
502 cec_logical_address CCECClient::GetPrimaryLogicalAdddress(void)
503 {
504 CLockObject lock(m_mutex);
505 return m_configuration.logicalAddresses.primary;
506 }
507
508 CCECBusDevice *CCECClient::GetPrimaryDevice(void)
509 {
510 return m_processor->GetDevice(GetPrimaryLogicalAdddress());
511 }
512
513 bool CCECClient::SendSetDeckControlMode(const cec_deck_control_mode mode, bool bSendUpdate /* = true */)
514 {
515 // find a playback device that we control
516 CCECPlaybackDevice *device = GetPlaybackDevice();
517 if (device)
518 {
519 // and set the deck control mode if there is a match
520 device->SetDeckControlMode(mode);
521 if (bSendUpdate)
522 return device->TransmitDeckStatus(CECDEVICE_TV);
523 return true;
524 }
525
526 // no match
527 return false;
528 }
529
530 bool CCECClient::SendSetDeckInfo(const cec_deck_info info, bool bSendUpdate /* = true */)
531 {
532 // find a playback device that we control
533 CCECPlaybackDevice *device = GetPlaybackDevice();
534 if (device)
535 {
536 // and set the deck status if there is a match
537 device->SetDeckStatus(info);
538 if (bSendUpdate)
539 return device->AsPlaybackDevice()->TransmitDeckStatus(CECDEVICE_TV);
540 return true;
541 }
542
543 // no match
544 return false;
545 }
546
547 bool CCECClient::SendSetMenuState(const cec_menu_state state, bool bSendUpdate /* = true */)
548 {
549 CECDEVICEVEC devices;
550
551 // set the menu state for all devices that are controlled by us
552 m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
553 for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
554 {
555 (*it)->SetMenuState(state);
556 if (bSendUpdate)
557 (*it)->TransmitMenuState(CECDEVICE_TV);
558 }
559
560 return true;
561 }
562
563 bool CCECClient::SendSetInactiveView(void)
564 {
565 CECDEVICEVEC devices;
566
567 // mark all devices that are controlled by us as inactive source
568 m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
569 for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
570 {
571 if ((*it)->IsActiveSource())
572 {
573 (*it)->MarkAsInactiveSource();
574 return (*it)->TransmitInactiveSource();
575 }
576 }
577
578 return true;
579 }
580
581 bool CCECClient::SendSetOSDString(const cec_logical_address iLogicalAddress, const cec_display_control duration, const char *strMessage)
582 {
583 CCECBusDevice *primary = GetPrimaryDevice();
584 if (primary)
585 return primary->TransmitOSDString(iLogicalAddress, duration, strMessage);
586
587 return false;
588 }
589
590 cec_version CCECClient::GetDeviceCecVersion(const cec_logical_address iAddress)
591 {
592 CCECBusDevice *device = m_processor->GetDevice(iAddress);
593 if (device)
594 return device->GetCecVersion(GetPrimaryLogicalAdddress());
595 return CEC_VERSION_UNKNOWN;
596 }
597
598 bool CCECClient::GetDeviceMenuLanguage(const cec_logical_address iAddress, cec_menu_language &language)
599 {
600 CCECBusDevice *device = m_processor->GetDevice(iAddress);
601 if (device)
602 {
603 language = device->GetMenuLanguage(GetPrimaryLogicalAdddress());
604 return (strcmp(language.language, "???") != 0);
605 }
606 return false;
607 }
608
609 cec_osd_name CCECClient::GetDeviceOSDName(const cec_logical_address iAddress)
610 {
611 cec_osd_name retVal;
612 retVal.device = iAddress;
613 retVal.name[0] = 0;
614
615 CCECBusDevice *device = m_processor->GetDevice(iAddress);
616 if (device)
617 {
618 CStdString strOSDName = device->GetOSDName(GetPrimaryLogicalAdddress());
619 snprintf(retVal.name, sizeof(retVal.name), "%s", strOSDName.c_str());
620 retVal.device = iAddress;
621 }
622
623 return retVal;
624 }
625
626 uint16_t CCECClient::GetDevicePhysicalAddress(const cec_logical_address iAddress)
627 {
628 CCECBusDevice *device = m_processor->GetDevice(iAddress);
629 if (device)
630 return device->GetPhysicalAddress(GetPrimaryLogicalAdddress());
631 return CEC_INVALID_PHYSICAL_ADDRESS;
632 }
633
634 cec_power_status CCECClient::GetDevicePowerStatus(const cec_logical_address iAddress)
635 {
636 CCECBusDevice *device = m_processor->GetDevice(iAddress);
637 if (device)
638 return device->GetPowerStatus(GetPrimaryLogicalAdddress());
639 return CEC_POWER_STATUS_UNKNOWN;
640 }
641
642 uint64_t CCECClient::GetDeviceVendorId(const cec_logical_address iAddress)
643 {
644 CCECBusDevice *device = m_processor->GetDevice(iAddress);
645 if (device)
646 return device->GetVendorId(GetPrimaryLogicalAdddress());
647 return CEC_VENDOR_UNKNOWN;
648 }
649
650 uint8_t CCECClient::SendVolumeUp(bool bSendRelease /* = true */)
651 {
652 CCECBusDevice *device = GetPrimaryDevice();
653 CCECAudioSystem *audio = m_processor->GetAudioSystem();
654
655 return device && audio && audio->IsPresent() ?
656 audio->VolumeUp(device->GetLogicalAddress(), bSendRelease) :
657 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
658 }
659
660 uint8_t CCECClient::SendVolumeDown(bool bSendRelease /* = true */)
661 {
662 CCECBusDevice *device = GetPrimaryDevice();
663 CCECAudioSystem *audio = m_processor->GetAudioSystem();
664
665 return device && audio && audio->IsPresent() ?
666 audio->VolumeDown(device->GetLogicalAddress(), bSendRelease) :
667 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
668 }
669
670 uint8_t CCECClient::SendMuteAudio(void)
671 {
672 CCECBusDevice *device = GetPrimaryDevice();
673 CCECAudioSystem *audio = m_processor->GetAudioSystem();
674
675 return device && audio && audio->IsPresent() ?
676 audio->MuteAudio(device->GetLogicalAddress()) :
677 (uint8_t)CEC_AUDIO_VOLUME_STATUS_UNKNOWN;
678 }
679
680 bool CCECClient::SendKeypress(const cec_logical_address iDestination, const cec_user_control_code key, bool bWait /* = true */)
681 {
682 CCECBusDevice *device = GetPrimaryDevice();
683 CCECBusDevice *dest = m_processor->GetDevice(iDestination);
684
685 return device && dest ?
686 device->TransmitKeypress(GetPrimaryLogicalAdddress(), key, bWait) :
687 false;
688 }
689
690 bool CCECClient::SendKeyRelease(const cec_logical_address iDestination, bool bWait /* = true */)
691 {
692 CCECBusDevice *device = GetPrimaryDevice();
693 CCECBusDevice *dest = m_processor->GetDevice(iDestination);
694
695 return device && dest ?
696 device->TransmitKeyRelease(GetPrimaryLogicalAdddress(), bWait) :
697 false;
698 }
699
700 bool CCECClient::GetCurrentConfiguration(libcec_configuration &configuration)
701 {
702 CLockObject lock(m_mutex);
703
704 // client version 1.5.0
705 snprintf(configuration.strDeviceName, 13, "%s", m_configuration.strDeviceName);
706 configuration.deviceTypes = m_configuration.deviceTypes;
707 configuration.bAutodetectAddress = m_configuration.bAutodetectAddress;
708 configuration.iPhysicalAddress = m_configuration.iPhysicalAddress;
709 configuration.baseDevice = m_configuration.baseDevice;
710 configuration.iHDMIPort = m_configuration.iHDMIPort;
711 configuration.clientVersion = m_configuration.clientVersion;
712 configuration.serverVersion = m_configuration.serverVersion;
713 configuration.tvVendor = m_configuration.tvVendor;
714
715 configuration.bGetSettingsFromROM = m_configuration.bGetSettingsFromROM;
716 configuration.bUseTVMenuLanguage = m_configuration.bUseTVMenuLanguage;
717 configuration.bActivateSource = m_configuration.bActivateSource;
718 configuration.wakeDevices = m_configuration.wakeDevices;
719 configuration.powerOffDevices = m_configuration.powerOffDevices;
720 configuration.bPowerOffScreensaver = m_configuration.bPowerOffScreensaver;
721 configuration.bPowerOffOnStandby = m_configuration.bPowerOffOnStandby;
722
723 // client version 1.5.1
724 if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_1)
725 configuration.bSendInactiveSource = m_configuration.bSendInactiveSource;
726
727 // client version 1.5.3
728 if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_3)
729 configuration.logicalAddresses = m_configuration.logicalAddresses;
730
731 // client version 1.6.0
732 if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_0)
733 {
734 configuration.iFirmwareVersion = m_configuration.iFirmwareVersion;
735 configuration.bPowerOffDevicesOnStandby = m_configuration.bPowerOffDevicesOnStandby;
736 configuration.bShutdownOnStandby = m_configuration.bShutdownOnStandby;
737 }
738
739 // client version 1.6.2
740 if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_2)
741 {
742 memcpy(configuration.strDeviceLanguage, m_configuration.strDeviceLanguage, 3);
743 configuration.iFirmwareBuildDate = m_configuration.iFirmwareBuildDate;
744 }
745 return true;
746 }
747
748 bool CCECClient::SetConfiguration(const libcec_configuration &configuration)
749 {
750 bool bIsRunning(m_processor && m_processor->CECInitialised());
751 CCECBusDevice *primary = bIsRunning ? GetPrimaryDevice() : NULL;
752 uint16_t iPA = primary ? primary->GetCurrentPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
753
754 // update the callbacks
755 if (configuration.callbacks)
756 EnableCallbacks(configuration.callbackParam, configuration.callbacks);
757
758 // update the client version
759 SetClientVersion((cec_client_version)configuration.clientVersion);
760
761 // update the OSD name
762 CStdString strOSDName(configuration.strDeviceName);
763 SetOSDName(strOSDName);
764
765 // update the TV vendor override
766 SetTVVendorOverride((cec_vendor_id)configuration.tvVendor);
767
768 // just copy these
769 {
770 CLockObject lock(m_mutex);
771 m_configuration.bUseTVMenuLanguage = configuration.bUseTVMenuLanguage;
772 m_configuration.bActivateSource = configuration.bActivateSource;
773 m_configuration.bGetSettingsFromROM = configuration.bGetSettingsFromROM;
774 m_configuration.wakeDevices = configuration.wakeDevices;
775 m_configuration.powerOffDevices = configuration.powerOffDevices;
776 m_configuration.bPowerOffScreensaver = configuration.bPowerOffScreensaver;
777 m_configuration.bPowerOffOnStandby = configuration.bPowerOffOnStandby;
778
779 // client version 1.5.1
780 if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_1)
781 m_configuration.bSendInactiveSource = configuration.bSendInactiveSource;
782
783 // client version 1.6.0
784 if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_0)
785 {
786 m_configuration.bPowerOffDevicesOnStandby = configuration.bPowerOffDevicesOnStandby;
787 m_configuration.bShutdownOnStandby = configuration.bShutdownOnStandby;
788 }
789
790 // client version 1.6.2
791 if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_2)
792 {
793 memcpy(m_configuration.strDeviceLanguage, configuration.strDeviceLanguage, 3);
794 }
795
796 // ensure that there is at least 1 device type set
797 if (m_configuration.deviceTypes.IsEmpty())
798 m_configuration.deviceTypes.Add(CEC_DEVICE_TYPE_RECORDING_DEVICE);
799 }
800
801 bool bNeedReinit(false);
802
803 // device types
804 if (SetDeviceTypes(configuration.deviceTypes))
805 {
806 // the device type changed. just copy the rest, and re-register
807 {
808 CLockObject lock(m_mutex);
809 m_configuration.iPhysicalAddress = configuration.iPhysicalAddress;
810 m_configuration.baseDevice = configuration.baseDevice;
811 m_configuration.iHDMIPort = configuration.iHDMIPort;
812 bNeedReinit = true;
813 }
814 }
815 else
816 {
817 // set the physical address
818 SetPhysicalAddress(configuration);
819 }
820
821 if (bIsRunning)
822 m_processor->PersistConfiguration(m_configuration);
823
824 if (!primary)
825 primary = GetPrimaryDevice();
826
827 if (bNeedReinit || !primary || primary->GetCurrentPhysicalAddress() != iPA)
828 {
829 // PA or device type changed
830 m_processor->RegisterClient(this);
831 }
832 else if (primary && configuration.bActivateSource == 1 && bIsRunning && !primary->IsActiveSource())
833 {
834 // activate the source if we're not already the active source
835 primary->ActivateSource();
836 }
837
838 return true;
839 }
840
841 void CCECClient::AddCommand(const cec_command &command)
842 {
843 CLockObject lock(m_mutex);
844
845 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);
846
847 if (m_configuration.callbacks && m_configuration.callbacks->CBCecCommand)
848 m_configuration.callbacks->CBCecCommand(m_configuration.callbackParam, command);
849 else if (!m_commandBuffer.Push(command))
850 LIB_CEC->AddLog(CEC_LOG_WARNING, "command buffer is full");
851 }
852
853 int CCECClient::MenuStateChanged(const cec_menu_state newState)
854 {
855 CLockObject lock(m_mutex);
856
857 LIB_CEC->AddLog(CEC_LOG_NOTICE, ">> %s: %s", ToString(CEC_OPCODE_MENU_REQUEST), ToString(newState));
858
859 if (m_configuration.callbacks &&
860 m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_2 &&
861 m_configuration.callbacks->CBCecMenuStateChanged)
862 return m_configuration.callbacks->CBCecMenuStateChanged(m_configuration.callbackParam, newState);
863
864 return 0;
865 }
866
867 void CCECClient::Alert(const libcec_alert type, const libcec_parameter &param)
868 {
869 CLockObject lock(m_mutex);
870
871 if (m_configuration.callbacks &&
872 m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_0 &&
873 m_configuration.callbacks->CBCecAlert)
874 m_configuration.callbacks->CBCecAlert(m_configuration.callbackParam, type, param);
875 }
876
877 void CCECClient::AddLog(const cec_log_message &message)
878 {
879 CLockObject lock(m_logMutex);
880 if (m_configuration.callbacks && m_configuration.callbacks->CBCecLogMessage)
881 m_configuration.callbacks->CBCecLogMessage(m_configuration.callbackParam, message);
882 else
883 m_logBuffer.Push(message);
884 }
885
886 void CCECClient::AddKey(void)
887 {
888 CLockObject lock(m_mutex);
889
890 if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN)
891 {
892 cec_keypress key;
893
894 key.duration = (unsigned int) (GetTimeMs() - m_buttontime);
895 key.keycode = m_iCurrentButton;
896 LIB_CEC->AddLog(CEC_LOG_DEBUG, "key released: %1x", key.keycode);
897
898 if (m_configuration.callbacks && m_configuration.callbacks->CBCecKeyPress)
899 m_configuration.callbacks->CBCecKeyPress(m_configuration.callbackParam, key);
900 else
901 m_keyBuffer.Push(key);
902 m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
903 }
904
905 m_buttontime = 0;
906 }
907
908 void CCECClient::AddKey(const cec_keypress &key)
909 {
910 CLockObject lock(m_mutex);
911
912 LIB_CEC->AddLog(CEC_LOG_DEBUG, "key pressed: %1x", key.keycode);
913
914 if (m_configuration.callbacks && m_configuration.callbacks->CBCecKeyPress)
915 m_configuration.callbacks->CBCecKeyPress(m_configuration.callbackParam, key);
916 else
917 m_keyBuffer.Push(key);
918
919 m_iCurrentButton = key.duration > 0 ? CEC_USER_CONTROL_CODE_UNKNOWN : key.keycode;
920 m_buttontime = key.duration > 0 ? 0 : GetTimeMs();
921 }
922
923 void CCECClient::SetCurrentButton(const cec_user_control_code iButtonCode)
924 {
925 // push a keypress to the buffer with 0 duration and another with the duration set when released
926 cec_keypress key;
927 key.duration = 0;
928 key.keycode = iButtonCode;
929
930 AddKey(key);
931 }
932
933 void CCECClient::CheckKeypressTimeout(void)
934 {
935 if (m_iCurrentButton != CEC_USER_CONTROL_CODE_UNKNOWN && GetTimeMs() - m_buttontime > CEC_BUTTON_TIMEOUT)
936 {
937 AddKey();
938 m_iCurrentButton = CEC_USER_CONTROL_CODE_UNKNOWN;
939 }
940 }
941
942 void CCECClient::ConfigurationChanged(const libcec_configuration &config)
943 {
944 CLockObject lock(m_mutex);
945
946 if (m_configuration.callbacks &&
947 m_configuration.clientVersion >= CEC_CLIENT_VERSION_1_5_0 &&
948 m_configuration.callbacks->CBCecConfigurationChanged &&
949 m_processor->CECInitialised())
950 m_configuration.callbacks->CBCecConfigurationChanged(m_configuration.callbackParam, config);
951 }
952
953 bool CCECClient::EnableCallbacks(void *cbParam, ICECCallbacks *callbacks)
954 {
955 CLockObject lock(m_mutex);
956 m_configuration.callbackParam = cbParam;
957 m_configuration.callbacks = callbacks;
958 return true;
959 }
960
961 bool CCECClient::PingAdapter(void)
962 {
963 return m_processor ? m_processor->PingAdapter() : false;
964 }
965
966 bool CCECClient::GetNextLogMessage(cec_log_message *message)
967 {
968 return (m_logBuffer.Pop(*message));
969 }
970
971 bool CCECClient::GetNextKeypress(cec_keypress *key)
972 {
973 return m_keyBuffer.Pop(*key);
974 }
975
976 bool CCECClient::GetNextCommand(cec_command *command)
977 {
978 return m_commandBuffer.Pop(*command);
979 }
980
981 CStdString CCECClient::GetConnectionInfo(void)
982 {
983 CStdString strLog;
984 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);
985 if (m_configuration.iFirmwareBuildDate != CEC_FW_BUILD_UNKNOWN)
986 {
987 time_t buildTime = (time_t)m_configuration.iFirmwareBuildDate;
988 strLog.AppendFormat(", firmware build date: %s", asctime(gmtime(&buildTime)));
989 strLog = strLog.Left((int)strLog.length() - 1); // strip \n added by asctime
990 strLog.append(" +0000");
991 }
992
993 // log the addresses that are being used
994 if (!m_configuration.logicalAddresses.IsEmpty())
995 {
996 strLog.append(", logical address(es) = ");
997 CECDEVICEVEC devices;
998 m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
999 for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
1000 strLog.AppendFormat("%s (%X) ", (*it)->GetLogicalAddressName(), (*it)->GetLogicalAddress());
1001 }
1002
1003 if (!CLibCEC::IsValidPhysicalAddress(m_configuration.iPhysicalAddress))
1004 strLog.AppendFormat(", base device: %s (%X), HDMI port number: %d", ToString(m_configuration.baseDevice), m_configuration.baseDevice, m_configuration.iHDMIPort);
1005 else
1006 strLog.AppendFormat(", physical address: %04x", m_configuration.iPhysicalAddress);
1007
1008 return strLog;
1009 }
1010
1011 void CCECClient::SetTVVendorOverride(const cec_vendor_id id)
1012 {
1013 {
1014 CLockObject lock(m_mutex);
1015 m_configuration.tvVendor = id;
1016 }
1017
1018 if (id != CEC_VENDOR_UNKNOWN)
1019 {
1020 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - vendor id '%s'", __FUNCTION__, ToString(id));
1021
1022 CCECBusDevice *tv = m_processor ? m_processor->GetTV() : NULL;
1023 if (tv)
1024 tv->SetVendorId((uint64_t)id);
1025 }
1026 }
1027
1028 cec_vendor_id CCECClient::GetTVVendorOverride(void)
1029 {
1030 CLockObject lock(m_mutex);
1031 return (cec_vendor_id)m_configuration.tvVendor;
1032 }
1033
1034 void CCECClient::SetOSDName(const CStdString &strDeviceName)
1035 {
1036 {
1037 CLockObject lock(m_mutex);
1038 snprintf(m_configuration.strDeviceName, 13, "%s", strDeviceName.c_str());
1039 }
1040
1041 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using OSD name '%s'", __FUNCTION__, strDeviceName.c_str());
1042
1043 CCECBusDevice *primary = GetPrimaryDevice();
1044 if (primary && !primary->GetCurrentOSDName().Equals(strDeviceName))
1045 {
1046 primary->SetOSDName(strDeviceName);
1047 if (m_processor && m_processor->CECInitialised())
1048 primary->TransmitOSDName(CECDEVICE_TV);
1049 }
1050 }
1051
1052 CStdString CCECClient::GetOSDName(void)
1053 {
1054 CLockObject lock(m_mutex);
1055 CStdString strOSDName(m_configuration.strDeviceName);
1056 return strOSDName;
1057 }
1058
1059 void CCECClient::SetWakeDevices(const cec_logical_addresses &addresses)
1060 {
1061 CLockObject lock(m_mutex);
1062 m_configuration.wakeDevices = addresses;
1063 }
1064
1065 cec_logical_addresses CCECClient::GetWakeDevices(void)
1066 {
1067 CLockObject lock(m_mutex);
1068 return m_configuration.wakeDevices;
1069 }
1070
1071 bool CCECClient::AutodetectPhysicalAddress(void)
1072 {
1073 bool bPhysicalAutodetected(false);
1074 uint16_t iPhysicalAddress = m_processor ? m_processor->GetDetectedPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS;
1075
1076 if (CLibCEC::IsValidPhysicalAddress(iPhysicalAddress))
1077 {
1078 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - autodetected physical address '%04X'", __FUNCTION__, iPhysicalAddress);
1079
1080 CLockObject lock(m_mutex);
1081 m_configuration.iPhysicalAddress = iPhysicalAddress;
1082 m_configuration.iHDMIPort = CEC_HDMI_PORTNUMBER_NONE;
1083 m_configuration.baseDevice = CECDEVICE_UNKNOWN;
1084 bPhysicalAutodetected = true;
1085 }
1086
1087 SetDevicePhysicalAddress(iPhysicalAddress);
1088
1089 return bPhysicalAutodetected;
1090 }
1091
1092 void CCECClient::SetClientVersion(const cec_client_version version)
1093 {
1094 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using client version '%s'", __FUNCTION__, ToString(version));
1095
1096 CLockObject lock(m_mutex);
1097 m_configuration.clientVersion = (uint32_t)version;
1098 }
1099
1100 cec_client_version CCECClient::GetClientVersion(void)
1101 {
1102 CLockObject lock(m_mutex);
1103 return (cec_client_version)m_configuration.clientVersion;
1104 }
1105
1106 bool CCECClient::SetDeviceTypes(const cec_device_type_list &deviceTypes)
1107 {
1108 bool bNeedReinit(false);
1109
1110 {
1111 CLockObject lock(m_mutex);
1112 bNeedReinit = m_processor && m_processor->CECInitialised() &&
1113 (m_configuration.deviceTypes != deviceTypes);
1114 m_configuration.deviceTypes = deviceTypes;
1115 }
1116
1117 if (bNeedReinit)
1118 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s - using primary device type '%s'", __FUNCTION__, ToString(deviceTypes[0]));
1119
1120 return bNeedReinit;
1121 }
1122
1123 cec_device_type_list CCECClient::GetDeviceTypes(void)
1124 {
1125 cec_device_type_list retVal;
1126 CLockObject lock(m_mutex);
1127 retVal = m_configuration.deviceTypes;
1128 return retVal;
1129 }
1130
1131 bool CCECClient::SetDevicePhysicalAddress(const uint16_t iPhysicalAddress)
1132 {
1133 if (!CLibCEC::IsValidPhysicalAddress(iPhysicalAddress))
1134 return false;
1135
1136 // reconfigure all devices
1137 cec_logical_address reactivateSource(CECDEVICE_UNKNOWN);
1138 CECDEVICEVEC devices;
1139 m_processor->GetDevices()->GetByLogicalAddresses(devices, m_configuration.logicalAddresses);
1140 for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
1141 {
1142 // if this device was the active source, reactivate it afterwards
1143 if ((*it)->IsActiveSource())
1144 reactivateSource = (*it)->GetLogicalAddress();
1145
1146 // mark the device as inactive source
1147 if (IsInitialised())
1148 (*it)->MarkAsInactiveSource();
1149
1150 // set the new physical address
1151 (*it)->SetPhysicalAddress(iPhysicalAddress);
1152
1153 // and transmit it
1154 if (IsInitialised())
1155 (*it)->TransmitPhysicalAddress();
1156 }
1157
1158 // reactivate the previous active source
1159 if (reactivateSource != CECDEVICE_UNKNOWN &&
1160 m_processor->CECInitialised() &&
1161 IsInitialised())
1162 {
1163 CCECBusDevice *device = m_processor->GetDevice(reactivateSource);
1164 if (device)
1165 device->ActivateSource();
1166 }
1167
1168 return true;
1169 }
1170
1171 bool CCECClient::SwitchMonitoring(bool bEnable)
1172 {
1173 LIB_CEC->AddLog(CEC_LOG_NOTICE, "== %s monitoring mode ==", bEnable ? "enabling" : "disabling");
1174
1175 if (m_processor)
1176 {
1177 if (bEnable)
1178 return m_processor->UnregisterClient(this);
1179 else
1180 return m_processor->RegisterClient(this);
1181 }
1182
1183 return false;
1184 }
1185
1186 bool CCECClient::PollDevice(const cec_logical_address iAddress)
1187 {
1188 // try to find the primary device
1189 CCECBusDevice *primary = GetPrimaryDevice();
1190 // poll the destination, with the primary as source
1191 if (primary)
1192 return primary->TransmitPoll(iAddress);
1193
1194 return m_processor ? m_processor->PollDevice(iAddress) : false;
1195 }
1196
1197 cec_logical_addresses CCECClient::GetActiveDevices(void)
1198 {
1199 CECDEVICEVEC activeDevices;
1200 if (m_processor)
1201 m_processor->GetDevices()->GetActive(activeDevices);
1202 return CCECDeviceMap::ToLogicalAddresses(activeDevices);
1203 }
1204
1205 bool CCECClient::IsActiveDevice(const cec_logical_address iAddress)
1206 {
1207 cec_logical_addresses activeDevices = GetActiveDevices();
1208 return activeDevices.IsSet(iAddress);
1209 }
1210
1211 bool CCECClient::IsActiveDeviceType(const cec_device_type type)
1212 {
1213 CECDEVICEVEC activeDevices;
1214 if (m_processor)
1215 m_processor->GetDevices()->GetActive(activeDevices);
1216 CCECDeviceMap::FilterType(type, activeDevices);
1217 return !activeDevices.empty();
1218 }
1219
1220 cec_logical_address CCECClient::GetActiveSource(void)
1221 {
1222 return m_processor ? m_processor->GetActiveSource() : CECDEVICE_UNKNOWN;
1223 }
1224
1225 bool CCECClient::IsActiveSource(const cec_logical_address iAddress)
1226 {
1227 return m_processor ? m_processor->IsActiveSource(iAddress) : false;
1228 }
1229
1230 bool CCECClient::SetStreamPath(const cec_logical_address iAddress)
1231 {
1232 uint16_t iPhysicalAddress = GetDevicePhysicalAddress(iAddress);
1233 if (iPhysicalAddress != CEC_INVALID_PHYSICAL_ADDRESS)
1234 return SetStreamPath(iPhysicalAddress);
1235 return false;
1236 }
1237
1238 bool CCECClient::SetStreamPath(const uint16_t iPhysicalAddress)
1239 {
1240 return m_processor ? m_processor->SetStreamPath(iPhysicalAddress) : false;
1241 }
1242
1243 cec_logical_addresses CCECClient::GetLogicalAddresses(void)
1244 {
1245 cec_logical_addresses addresses;
1246 CLockObject lock(m_mutex);
1247 addresses = m_configuration.logicalAddresses;
1248 return addresses;
1249 }
1250
1251 bool CCECClient::CanPersistConfiguration(void)
1252 {
1253 return m_processor ? m_processor->CanPersistConfiguration() : false;
1254 }
1255
1256 bool CCECClient::PersistConfiguration(const libcec_configuration &configuration)
1257 {
1258 return m_processor ? m_processor->PersistConfiguration(configuration) : false;
1259 }
1260
1261 void CCECClient::RescanActiveDevices(void)
1262 {
1263 if (m_processor)
1264 m_processor->RescanActiveDevices();
1265 }
1266
1267 bool CCECClient::IsLibCECActiveSource(void)
1268 {
1269 bool bReturn(false);
1270 if (m_processor)
1271 {
1272 cec_logical_address activeSource = m_processor->GetActiveSource();
1273 CCECBusDevice *device = m_processor->GetDevice(activeSource);
1274 if (device)
1275 bReturn = device->IsHandledByLibCEC();
1276 }
1277 return bReturn;
1278 }