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