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