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