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