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