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