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