a0d20a8a43d5ebfab551715993734b9e9e033438
[deb_libcec.git] / src / lib / devices / CECBusDevice.cpp
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 "CECBusDevice.h"
34 #include "../CECProcessor.h"
35 #include "../implementations/ANCommandHandler.h"
36 #include "../implementations/CECCommandHandler.h"
37 #include "../implementations/SLCommandHandler.h"
38 #include "../implementations/VLCommandHandler.h"
39 #include "../LibCEC.h"
40 #include "../platform/util/timeutils.h"
41
42 #include "CECAudioSystem.h"
43 #include "CECPlaybackDevice.h"
44 #include "CECRecordingDevice.h"
45 #include "CECTuner.h"
46 #include "CECTV.h"
47
48 using namespace std;
49 using namespace CEC;
50 using namespace PLATFORM;
51
52 #define LIB_CEC m_processor->GetLib()
53 #define ToString(p) LIB_CEC->ToString(p)
54
55 CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
56 m_type (CEC_DEVICE_TYPE_RESERVED),
57 m_iPhysicalAddress (iPhysicalAddress),
58 m_iStreamPath (CEC_INVALID_PHYSICAL_ADDRESS),
59 m_iLogicalAddress (iLogicalAddress),
60 m_powerStatus (CEC_POWER_STATUS_UNKNOWN),
61 m_processor (processor),
62 m_vendor (CEC_VENDOR_UNKNOWN),
63 m_bReplaceHandler (false),
64 m_menuState (CEC_MENU_STATE_ACTIVATED),
65 m_bActiveSource (false),
66 m_iLastActive (0),
67 m_iLastPowerStateUpdate (0),
68 m_cecVersion (CEC_VERSION_UNKNOWN),
69 m_deviceStatus (CEC_DEVICE_STATUS_UNKNOWN),
70 m_iHandlerUseCount (0),
71 m_bAwaitingReceiveFailed(false),
72 m_bVendorIdRequested (false)
73 {
74 m_handler = new CCECCommandHandler(this);
75
76 for (unsigned int iPtr = 0; iPtr < 4; iPtr++)
77 m_menuLanguage.language[iPtr] = '?';
78 m_menuLanguage.language[3] = 0;
79 m_menuLanguage.device = iLogicalAddress;
80
81 m_strDeviceName = ToString(m_iLogicalAddress);
82 }
83
84 CCECBusDevice::~CCECBusDevice(void)
85 {
86 delete m_handler;
87 }
88
89 bool CCECBusDevice::ReplaceHandler(bool bActivateSource /* = true */)
90 {
91 bool bInitHandler(false);
92 {
93 CTryLockObject lock(m_mutex);
94 if (!lock.IsLocked())
95 return false;
96
97 CLockObject handlerLock(m_handlerMutex);
98 if (m_iHandlerUseCount > 0)
99 return false;
100
101 MarkBusy();
102
103 if (m_vendor != m_handler->GetVendorId())
104 {
105 if (CCECCommandHandler::HasSpecificHandler(m_vendor))
106 {
107 LIB_CEC->AddLog(CEC_LOG_DEBUG, "replacing the command handler for device '%s' (%x)", GetLogicalAddressName(), GetLogicalAddress());
108 delete m_handler;
109
110 switch (m_vendor)
111 {
112 case CEC_VENDOR_SAMSUNG:
113 m_handler = new CANCommandHandler(this);
114 break;
115 case CEC_VENDOR_LG:
116 m_handler = new CSLCommandHandler(this);
117 break;
118 case CEC_VENDOR_PANASONIC:
119 m_handler = new CVLCommandHandler(this);
120 break;
121 default:
122 m_handler = new CCECCommandHandler(this);
123 break;
124 }
125
126 m_handler->SetVendorId(m_vendor);
127 bInitHandler = true;
128 }
129 }
130 }
131
132 if (bInitHandler)
133 {
134 m_handler->InitHandler();
135
136 if (bActivateSource && IsHandledByLibCEC() && IsActiveSource())
137 m_handler->ActivateSource();
138 }
139
140 MarkReady();
141
142 return true;
143 }
144
145 bool CCECBusDevice::HandleCommand(const cec_command &command)
146 {
147 bool bHandled(false);
148
149 /* update "last active" */
150 {
151 CLockObject lock(m_mutex);
152 m_iLastActive = GetTimeMs();
153
154 /* don't call GetStatus() here, just read the value with the mutex locked */
155 if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC && command.opcode_set == 1)
156 m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
157
158 MarkBusy();
159 }
160
161 /* handle the command */
162 bHandled = m_handler->HandleCommand(command);
163
164 /* change status to present */
165 if (bHandled && GetLogicalAddress() != CECDEVICE_BROADCAST)
166 {
167 CLockObject lock(m_mutex);
168 if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
169 {
170 if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT)
171 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
172 m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
173 }
174 }
175
176 MarkReady();
177 return bHandled;
178 }
179
180 const char* CCECBusDevice::GetLogicalAddressName(void) const
181 {
182 return ToString(m_iLogicalAddress);
183 }
184
185 bool CCECBusDevice::IsPresent(void)
186 {
187 CLockObject lock(m_mutex);
188 return m_deviceStatus == CEC_DEVICE_STATUS_PRESENT;
189 }
190
191 bool CCECBusDevice::IsHandledByLibCEC(void)
192 {
193 CLockObject lock(m_mutex);
194 return m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC;
195 }
196
197 void CCECBusDevice::SetUnsupportedFeature(cec_opcode opcode)
198 {
199 // some commands should never be marked as unsupported
200 if (opcode == CEC_OPCODE_VENDOR_COMMAND ||
201 opcode == CEC_OPCODE_VENDOR_COMMAND_WITH_ID ||
202 opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN ||
203 opcode == CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP ||
204 opcode == CEC_OPCODE_ABORT ||
205 opcode == CEC_OPCODE_FEATURE_ABORT ||
206 opcode == CEC_OPCODE_NONE)
207 return;
208
209 {
210 CLockObject lock(m_mutex);
211 if (m_unsupportedFeatures.find(opcode) == m_unsupportedFeatures.end())
212 {
213 LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking opcode '%s' as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
214 m_unsupportedFeatures.insert(opcode);
215 }
216 }
217
218 // signal threads that are waiting for a reponse
219 MarkBusy();
220 m_handler->SignalOpcode(cec_command::GetResponseOpcode(opcode));
221 MarkReady();
222 }
223
224 bool CCECBusDevice::IsUnsupportedFeature(cec_opcode opcode)
225 {
226 CLockObject lock(m_mutex);
227 bool bUnsupported = (m_unsupportedFeatures.find(opcode) != m_unsupportedFeatures.end());
228 if (bUnsupported)
229 LIB_CEC->AddLog(CEC_LOG_DEBUG, "'%s' is marked as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
230 return bUnsupported;
231 }
232
233 bool CCECBusDevice::TransmitKeypress(const cec_logical_address initiator, cec_user_control_code key, bool bWait /* = true */)
234 {
235 MarkBusy();
236 bool bReturn = m_handler->TransmitKeypress(initiator, m_iLogicalAddress, key, bWait);
237 MarkReady();
238 return bReturn;
239 }
240
241 bool CCECBusDevice::TransmitKeyRelease(const cec_logical_address initiator, bool bWait /* = true */)
242 {
243 MarkBusy();
244 bool bReturn = m_handler->TransmitKeyRelease(initiator, m_iLogicalAddress, bWait);
245 MarkReady();
246 return bReturn;
247 }
248
249 cec_version CCECBusDevice::GetCecVersion(const cec_logical_address initiator, bool bUpdate /* = false */)
250 {
251 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
252 bool bRequestUpdate(false);
253 {
254 CLockObject lock(m_mutex);
255 bRequestUpdate = bIsPresent &&
256 (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN);
257 }
258
259 if (bRequestUpdate)
260 {
261 CheckVendorIdRequested(initiator);
262 RequestCecVersion(initiator);
263 }
264
265 CLockObject lock(m_mutex);
266 return m_cecVersion;
267 }
268
269 void CCECBusDevice::SetCecVersion(const cec_version newVersion)
270 {
271 CLockObject lock(m_mutex);
272 if (m_cecVersion != newVersion)
273 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): CEC version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(newVersion));
274 m_cecVersion = newVersion;
275 }
276
277 bool CCECBusDevice::RequestCecVersion(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
278 {
279 bool bReturn(false);
280
281 if (!IsHandledByLibCEC() &&
282 !IsUnsupportedFeature(CEC_OPCODE_GET_CEC_VERSION))
283 {
284 MarkBusy();
285 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting CEC version of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
286 bReturn = m_handler->TransmitRequestCecVersion(initiator, m_iLogicalAddress, bWaitForResponse);
287 MarkReady();
288 }
289 return bReturn;
290 }
291
292 bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination)
293 {
294 cec_version version;
295 {
296 CLockObject lock(m_mutex);
297 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): cec version %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_cecVersion));
298 version = m_cecVersion;
299 }
300
301 MarkBusy();
302 bool bReturn = m_handler->TransmitCECVersion(m_iLogicalAddress, destination, version);
303 MarkReady();
304 return bReturn;
305 }
306
307 cec_menu_language &CCECBusDevice::GetMenuLanguage(const cec_logical_address initiator, bool bUpdate /* = false */)
308 {
309 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
310 bool bRequestUpdate(false);
311 {
312 CLockObject lock(m_mutex);
313 bRequestUpdate = (bIsPresent &&
314 (bUpdate || !strcmp(m_menuLanguage.language, "???")));
315 }
316
317 if (bRequestUpdate)
318 {
319 CheckVendorIdRequested(initiator);
320 RequestMenuLanguage(initiator);
321 }
322
323 CLockObject lock(m_mutex);
324 return m_menuLanguage;
325 }
326
327 void CCECBusDevice::SetMenuLanguage(const char *strLanguage)
328 {
329 if (!strLanguage)
330 return;
331
332 CLockObject lock(m_mutex);
333 if (strcmp(strLanguage, m_menuLanguage.language))
334 {
335 memcpy(m_menuLanguage.language, strLanguage, 3);
336 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu language set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, m_menuLanguage.language);
337 }
338 }
339
340 void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
341 {
342 if (language.device == m_iLogicalAddress)
343 SetMenuLanguage(language.language);
344 }
345
346 bool CCECBusDevice::RequestMenuLanguage(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
347 {
348 bool bReturn(false);
349
350 if (!IsHandledByLibCEC() &&
351 !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE))
352 {
353 MarkBusy();
354 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting menu language of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
355 bReturn = m_handler->TransmitRequestMenuLanguage(initiator, m_iLogicalAddress, bWaitForResponse);
356 MarkReady();
357 }
358 return bReturn;
359 }
360
361 bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destination)
362 {
363 bool bReturn(false);
364 cec_menu_language language;
365 {
366 CLockObject lock(m_mutex);
367 language = m_menuLanguage;
368 }
369
370 char lang[3];
371 {
372 CLockObject lock(m_mutex);
373 lang[0] = language.language[0];
374 lang[1] = language.language[1];
375 lang[2] = language.language[2];
376 }
377
378 MarkBusy();
379 if (lang[0] == '?' && lang[1] == '?' && lang[2] == '?')
380 {
381 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): Menu language feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
382 m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
383 bReturn = true;
384 }
385 else
386 {
387 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): Menu language '%s'", GetLogicalAddressName(), m_iLogicalAddress, lang);
388 bReturn = m_handler->TransmitSetMenuLanguage(m_iLogicalAddress, lang);
389 }
390 MarkReady();
391 return bReturn;
392 }
393
394 bool CCECBusDevice::TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage)
395 {
396 bool bReturn(false);
397 if (!m_processor->GetDevice(destination)->IsUnsupportedFeature(CEC_OPCODE_SET_OSD_STRING))
398 {
399 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): display OSD message '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, strMessage);
400 MarkBusy();
401 bReturn = m_handler->TransmitOSDString(m_iLogicalAddress, destination, duration, strMessage);
402 MarkReady();
403 }
404 return bReturn;
405 }
406
407 CStdString CCECBusDevice::GetOSDName(const cec_logical_address initiator, bool bUpdate /* = false */)
408 {
409 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
410 bool bRequestUpdate(false);
411 {
412 CLockObject lock(m_mutex);
413 bRequestUpdate = bIsPresent &&
414 (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
415 m_type != CEC_DEVICE_TYPE_TV;
416 }
417
418 if (bRequestUpdate)
419 {
420 CheckVendorIdRequested(initiator);
421 RequestOSDName(initiator);
422 }
423
424 CLockObject lock(m_mutex);
425 return m_strDeviceName;
426 }
427
428 void CCECBusDevice::SetOSDName(CStdString strName)
429 {
430 CLockObject lock(m_mutex);
431 if (m_strDeviceName != strName)
432 {
433 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName.c_str());
434 m_strDeviceName = strName;
435 }
436 }
437
438 bool CCECBusDevice::RequestOSDName(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
439 {
440 bool bReturn(false);
441
442 if (!IsHandledByLibCEC() &&
443 !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
444 {
445 MarkBusy();
446 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
447 bReturn = m_handler->TransmitRequestOSDName(initiator, m_iLogicalAddress, bWaitForResponse);
448 MarkReady();
449 }
450 return bReturn;
451 }
452
453 bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination)
454 {
455 CStdString strDeviceName;
456 {
457 CLockObject lock(m_mutex);
458 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, m_strDeviceName.c_str());
459 strDeviceName = m_strDeviceName;
460 }
461
462 MarkBusy();
463 bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName);
464 MarkReady();
465 return bReturn;
466 }
467
468 bool CCECBusDevice::HasValidPhysicalAddress(void)
469 {
470 CLockObject lock(m_mutex);
471 return CLibCEC::IsValidPhysicalAddress(m_iPhysicalAddress);
472 }
473
474 uint16_t CCECBusDevice::GetCurrentPhysicalAddress(void)
475 {
476 CLockObject lock(m_mutex);
477 return m_iPhysicalAddress;
478 }
479
480 uint16_t CCECBusDevice::GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate /* = false */)
481 {
482 if (!bSuppressUpdate)
483 {
484 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
485 bool bRequestUpdate(false);
486 {
487 CLockObject lock(m_mutex);
488 bRequestUpdate = bIsPresent && m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS;
489 }
490
491 if (bRequestUpdate)
492 {
493 CheckVendorIdRequested(initiator);
494 if (!RequestPhysicalAddress(initiator))
495 LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to request the physical address");
496 }
497 }
498
499 CLockObject lock(m_mutex);
500 return m_iPhysicalAddress;
501 }
502
503 bool CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
504 {
505 CLockObject lock(m_mutex);
506 if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
507 {
508 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
509 m_iPhysicalAddress = iNewAddress;
510 }
511 return true;
512 }
513
514 bool CCECBusDevice::RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
515 {
516 bool bReturn(false);
517
518 if (!IsHandledByLibCEC())
519 {
520 MarkBusy();
521 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
522 bReturn = m_handler->TransmitRequestPhysicalAddress(initiator, m_iLogicalAddress, bWaitForResponse);
523 MarkReady();
524 }
525 return bReturn;
526 }
527
528 bool CCECBusDevice::TransmitPhysicalAddress(void)
529 {
530 uint16_t iPhysicalAddress;
531 cec_device_type type;
532 {
533 CLockObject lock(m_mutex);
534 if (m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS)
535 return false;
536
537 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
538 iPhysicalAddress = m_iPhysicalAddress;
539 type = m_type;
540 }
541
542 MarkBusy();
543 bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
544 MarkReady();
545 return bReturn;
546 }
547
548 cec_power_status CCECBusDevice::GetCurrentPowerStatus(void)
549 {
550 CLockObject lock(m_mutex);
551 return m_powerStatus;
552 }
553
554 cec_power_status CCECBusDevice::GetPowerStatus(const cec_logical_address initiator, bool bUpdate /* = false */)
555 {
556 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
557 bool bRequestUpdate(false);
558 {
559 CLockObject lock(m_mutex);
560 bRequestUpdate = (bIsPresent &&
561 (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN ||
562 m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON ||
563 m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY ||
564 GetTimeMs() - m_iLastPowerStateUpdate >= CEC_POWER_STATE_REFRESH_TIME));
565 }
566
567 if (bRequestUpdate)
568 {
569 CheckVendorIdRequested(initiator);
570 RequestPowerStatus(initiator);
571 }
572
573 CLockObject lock(m_mutex);
574 return m_powerStatus;
575 }
576
577 void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
578 {
579 CLockObject lock(m_mutex);
580 if (m_powerStatus != powerStatus)
581 {
582 m_iLastPowerStateUpdate = GetTimeMs();
583 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
584 m_powerStatus = powerStatus;
585 }
586 }
587
588 bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
589 {
590 bool bReturn(false);
591
592 if (!IsHandledByLibCEC() &&
593 !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
594 {
595 MarkBusy();
596 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
597 bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bWaitForResponse);
598 MarkReady();
599 }
600 return bReturn;
601 }
602
603 bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination)
604 {
605 cec_power_status state;
606 {
607 CLockObject lock(m_mutex);
608 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_powerStatus));
609 state = m_powerStatus;
610 }
611
612 MarkBusy();
613 bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state);
614 MarkReady();
615 return bReturn;
616 }
617
618 cec_vendor_id CCECBusDevice::GetCurrentVendorId(void)
619 {
620 CLockObject lock(m_mutex);
621 return m_vendor;
622 }
623
624 cec_vendor_id CCECBusDevice::GetVendorId(const cec_logical_address initiator, bool bUpdate /* = false */)
625 {
626 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
627 bool bRequestUpdate(false);
628 {
629 CLockObject lock(m_mutex);
630 bRequestUpdate = (bIsPresent &&
631 (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
632 }
633
634 if (bRequestUpdate)
635 RequestVendorId(initiator);
636
637 CLockObject lock(m_mutex);
638 return m_vendor;
639 }
640
641 const char *CCECBusDevice::GetVendorName(const cec_logical_address initiator, bool bUpdate /* = false */)
642 {
643 return ToString(GetVendorId(initiator, bUpdate));
644 }
645
646 bool CCECBusDevice::SetVendorId(uint64_t iVendorId)
647 {
648 bool bVendorChanged(false);
649
650 {
651 CLockObject lock(m_mutex);
652 bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
653 m_vendor = (cec_vendor_id)iVendorId;
654 }
655
656 if (bVendorChanged)
657 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
658
659 return bVendorChanged;
660 }
661
662 bool CCECBusDevice::RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
663 {
664 bool bReturn(false);
665
666 if (!IsHandledByLibCEC() && initiator != CECDEVICE_UNKNOWN)
667 {
668 MarkBusy();
669 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
670 bReturn = m_handler->TransmitRequestVendorId(initiator, m_iLogicalAddress, bWaitForResponse);
671 MarkReady();
672
673 if (bWaitForResponse)
674 ReplaceHandler(true);
675 }
676 return bReturn;
677 }
678
679 bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort /* = true */)
680 {
681 bool bReturn(false);
682 uint64_t iVendorId;
683 {
684 CLockObject lock(m_mutex);
685 iVendorId = (uint64_t)m_vendor;
686 }
687
688 MarkBusy();
689 if (iVendorId == CEC_VENDOR_UNKNOWN)
690 {
691 if (bSendAbort)
692 {
693 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
694 m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
695 bReturn = true;
696 }
697 }
698 else
699 {
700 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id %s (%x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString((cec_vendor_id)iVendorId), iVendorId);
701 bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
702 }
703 MarkReady();
704 return bReturn;
705 }
706
707 cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bool bSuppressPoll /* = false */)
708 {
709 cec_bus_device_status status(CEC_DEVICE_STATUS_UNKNOWN);
710 bool bNeedsPoll(false);
711
712 {
713 CLockObject lock(m_mutex);
714 status = m_deviceStatus;
715 bNeedsPoll = !bSuppressPoll &&
716 (bForcePoll || m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN);
717 }
718
719 if (bNeedsPoll)
720 {
721 bool bPollAcked(false);
722 if (bNeedsPoll && NeedsPoll())
723 bPollAcked = m_processor->PollDevice(m_iLogicalAddress);
724
725 status = bPollAcked ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT;
726 SetDeviceStatus(status);
727 }
728
729 return status;
730 }
731
732 void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
733 {
734 {
735 CLockObject lock(m_mutex);
736 switch (newStatus)
737 {
738 case CEC_DEVICE_STATUS_UNKNOWN:
739 if (m_deviceStatus != newStatus)
740 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'unknown'", ToString(m_iLogicalAddress));
741 ResetDeviceStatus();
742 m_deviceStatus = newStatus;
743 break;
744 case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
745 if (m_deviceStatus != newStatus)
746 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'handled by libCEC'", ToString(m_iLogicalAddress));
747 SetPowerStatus (CEC_POWER_STATUS_ON);
748 SetVendorId (CEC_VENDOR_UNKNOWN);
749 SetMenuState (CEC_MENU_STATE_ACTIVATED);
750 SetCecVersion (CEC_VERSION_1_3A);
751 SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
752 MarkAsInactiveSource();
753 m_iLastActive = 0;
754 m_deviceStatus = newStatus;
755 break;
756 case CEC_DEVICE_STATUS_PRESENT:
757 if (m_deviceStatus != newStatus)
758 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'present'", ToString(m_iLogicalAddress));
759 m_deviceStatus = newStatus;
760 break;
761 case CEC_DEVICE_STATUS_NOT_PRESENT:
762 if (m_deviceStatus != newStatus)
763 {
764 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'not present'", ToString(m_iLogicalAddress));
765 ResetDeviceStatus();
766 m_deviceStatus = newStatus;
767 }
768 break;
769 }
770 }
771 }
772
773 void CCECBusDevice::ResetDeviceStatus(void)
774 {
775 CLockObject lock(m_mutex);
776 SetPowerStatus (CEC_POWER_STATUS_UNKNOWN);
777 SetVendorId (CEC_VENDOR_UNKNOWN);
778 SetMenuState (CEC_MENU_STATE_ACTIVATED);
779 SetCecVersion (CEC_VERSION_UNKNOWN);
780 SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
781 SetOSDName (ToString(m_iLogicalAddress));
782 MarkAsInactiveSource();
783 m_iLastActive = 0;
784 m_bVendorIdRequested = false;
785 m_unsupportedFeatures.clear();
786 }
787
788 bool CCECBusDevice::TransmitPoll(const cec_logical_address dest)
789 {
790 bool bReturn(false);
791 cec_logical_address destination(dest);
792 if (destination == CECDEVICE_UNKNOWN)
793 destination = m_iLogicalAddress;
794
795 CCECBusDevice *destDevice = m_processor->GetDevice(destination);
796 if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
797 return bReturn;
798
799 MarkBusy();
800 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
801 bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination);
802 LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
803
804 CLockObject lock(m_mutex);
805 if (bReturn)
806 {
807 m_iLastActive = GetTimeMs();
808 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
809 }
810 else
811 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
812
813 MarkReady();
814 return bReturn;
815 }
816
817 void CCECBusDevice::HandlePoll(const cec_logical_address destination)
818 {
819 if (destination >= 0 && destination < CECDEVICE_BROADCAST)
820 {
821 CCECBusDevice *device = m_processor->GetDevice(destination);
822 if (device)
823 device->HandlePollFrom(m_iLogicalAddress);
824 }
825 }
826
827 void CCECBusDevice::HandlePollFrom(const cec_logical_address initiator)
828 {
829 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
830 m_bAwaitingReceiveFailed = true;
831 }
832
833 bool CCECBusDevice::HandleReceiveFailed(void)
834 {
835 bool bReturn = m_bAwaitingReceiveFailed;
836 m_bAwaitingReceiveFailed = false;
837 return bReturn;
838 }
839
840 cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
841 {
842 CLockObject lock(m_mutex);
843 return m_menuState;
844 }
845
846 void CCECBusDevice::SetMenuState(const cec_menu_state state)
847 {
848 CLockObject lock(m_mutex);
849 if (m_menuState != state)
850 {
851 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
852 m_menuState = state;
853 }
854 }
855
856 bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest)
857 {
858 cec_menu_state menuState;
859 {
860 CLockObject lock(m_mutex);
861 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
862 menuState = m_menuState;
863 }
864
865 MarkBusy();
866 bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
867 MarkReady();
868 return bReturn;
869 }
870
871 bool CCECBusDevice::ActivateSource(void)
872 {
873 MarkAsActiveSource();
874 LIB_CEC->AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
875 MarkBusy();
876 bool bReturn = m_handler->ActivateSource();
877 MarkReady();
878 return bReturn;
879 }
880
881 bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
882 {
883 bool bReturn(false);
884
885 if (IsHandledByLibCEC())
886 {
887 MarkBusy();
888 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting active source");
889
890 bReturn = m_handler->TransmitRequestActiveSource(m_iLogicalAddress, bWaitForResponse);
891 MarkReady();
892 }
893 return bReturn;
894 }
895
896 void CCECBusDevice::MarkAsActiveSource(void)
897 {
898 CLockObject lock(m_mutex);
899 if (!m_bActiveSource)
900 LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
901 else
902 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
903
904 CECDEVICEVEC devices;
905 m_processor->GetDevices()->Get(devices);
906 for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
907 if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
908 (*it)->MarkAsInactiveSource();
909
910 m_bActiveSource = true;
911 SetPowerStatus(CEC_POWER_STATUS_ON);
912 }
913
914 void CCECBusDevice::MarkAsInactiveSource(void)
915 {
916 {
917 CLockObject lock(m_mutex);
918 if (m_bActiveSource)
919 LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
920 m_bActiveSource = false;
921 }
922 }
923
924 bool CCECBusDevice::TransmitActiveSource(void)
925 {
926 bool bSendActiveSource(false);
927
928 {
929 CLockObject lock(m_mutex);
930 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
931 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
932 else if (m_bActiveSource)
933 {
934 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
935 bSendActiveSource = true;
936 }
937 else
938 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
939 }
940
941 if (bSendActiveSource)
942 {
943 MarkBusy();
944 m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
945 MarkReady();
946 return true;
947 }
948
949 return false;
950 }
951
952 bool CCECBusDevice::TransmitImageViewOn(void)
953 {
954 {
955 CLockObject lock(m_mutex);
956 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
957 {
958 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
959 return false;
960 }
961 }
962
963 MarkBusy();
964 m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
965 MarkReady();
966 return true;
967 }
968
969 bool CCECBusDevice::TransmitInactiveSource(void)
970 {
971 uint16_t iPhysicalAddress;
972 {
973 CLockObject lock(m_mutex);
974 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
975 iPhysicalAddress = m_iPhysicalAddress;
976 }
977
978 MarkBusy();
979 bool bReturn = m_handler->TransmitInactiveSource(m_iLogicalAddress, iPhysicalAddress);
980 MarkReady();
981 return bReturn;
982 }
983
984 bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
985 {
986 MarkBusy();
987 bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
988 MarkReady();
989 return bReturn;
990 }
991
992 void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
993 {
994 CLockObject lock(m_mutex);
995 if (iNewAddress != m_iStreamPath)
996 {
997 LIB_CEC->AddLog(CEC_LOG_DEBUG, ">> %s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
998 m_iStreamPath = iNewAddress;
999 }
1000
1001 if (!LIB_CEC->IsValidPhysicalAddress(iNewAddress))
1002 return;
1003
1004 CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
1005 if (device)
1006 {
1007 // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
1008 device->MarkAsActiveSource();
1009 }
1010 else
1011 {
1012 // try to find the device with the old address, and mark it as inactive when found
1013 device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
1014 if (device)
1015 device->MarkAsInactiveSource();
1016 }
1017 }
1018
1019 bool CCECBusDevice::PowerOn(const cec_logical_address initiator)
1020 {
1021 bool bReturn(false);
1022 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
1023
1024 MarkBusy();
1025 cec_power_status currentStatus = GetPowerStatus(initiator, false);
1026 if (currentStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
1027 currentStatus != CEC_POWER_STATUS_ON)
1028 {
1029 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
1030 if (m_handler->PowerOn(initiator, m_iLogicalAddress))
1031 {
1032 SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
1033 bReturn = true;
1034 }
1035 }
1036 else
1037 {
1038 LIB_CEC->AddLog(CEC_LOG_NOTICE, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
1039 }
1040
1041 MarkReady();
1042 return bReturn;
1043 }
1044
1045 bool CCECBusDevice::Standby(const cec_logical_address initiator)
1046 {
1047 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
1048
1049 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
1050 MarkBusy();
1051 bool bReturn = m_handler->TransmitStandby(initiator, m_iLogicalAddress);
1052 MarkReady();
1053 return bReturn;
1054 }
1055
1056 bool CCECBusDevice::NeedsPoll(void)
1057 {
1058 bool bSendPoll(false);
1059 cec_logical_address pollAddress(CECDEVICE_UNKNOWN);
1060 switch (m_iLogicalAddress)
1061 {
1062 case CECDEVICE_PLAYBACKDEVICE3:
1063 pollAddress = CECDEVICE_PLAYBACKDEVICE2;
1064 break;
1065 case CECDEVICE_PLAYBACKDEVICE2:
1066 pollAddress = CECDEVICE_PLAYBACKDEVICE1;
1067 break;
1068 case CECDEVICE_RECORDINGDEVICE3:
1069 pollAddress = CECDEVICE_RECORDINGDEVICE2;
1070 break;
1071 case CECDEVICE_RECORDINGDEVICE2:
1072 pollAddress = CECDEVICE_RECORDINGDEVICE1;
1073 break;
1074 case CECDEVICE_TUNER4:
1075 pollAddress = CECDEVICE_TUNER3;
1076 break;
1077 case CECDEVICE_TUNER3:
1078 pollAddress = CECDEVICE_TUNER2;
1079 break;
1080 case CECDEVICE_TUNER2:
1081 pollAddress = CECDEVICE_TUNER1;
1082 break;
1083 case CECDEVICE_AUDIOSYSTEM:
1084 case CECDEVICE_PLAYBACKDEVICE1:
1085 case CECDEVICE_RECORDINGDEVICE1:
1086 case CECDEVICE_TUNER1:
1087 case CECDEVICE_TV:
1088 bSendPoll = true;
1089 break;
1090 default:
1091 break;
1092 }
1093
1094 if (!bSendPoll && pollAddress != CECDEVICE_UNKNOWN)
1095 {
1096 CCECBusDevice *device = m_processor->GetDevice(pollAddress);
1097 if (device)
1098 {
1099 cec_bus_device_status status = device->GetStatus();
1100 bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1101 }
1102 else
1103 {
1104 bSendPoll = true;
1105 }
1106 }
1107
1108 return bSendPoll;
1109 }
1110
1111 void CCECBusDevice::CheckVendorIdRequested(const cec_logical_address initiator)
1112 {
1113 bool bRequestVendorId(false);
1114 {
1115 CLockObject lock(m_mutex);
1116 bRequestVendorId = !m_bVendorIdRequested;
1117 m_bVendorIdRequested = true;
1118 }
1119
1120 if (bRequestVendorId)
1121 {
1122 ReplaceHandler(false);
1123 GetVendorId(initiator);
1124 }
1125 }
1126 //@}
1127
1128 CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
1129 {
1130 return AsAudioSystem(this);
1131 }
1132
1133 CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
1134 {
1135 return AsPlaybackDevice(this);
1136 }
1137
1138 CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
1139 {
1140 return AsRecordingDevice(this);
1141 }
1142
1143 CCECTuner *CCECBusDevice::AsTuner(void)
1144 {
1145 return AsTuner(this);
1146 }
1147
1148 CCECTV *CCECBusDevice::AsTV(void)
1149 {
1150 return AsTV(this);
1151 }
1152
1153 CCECAudioSystem *CCECBusDevice::AsAudioSystem(CCECBusDevice *device)
1154 {
1155 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
1156 return static_cast<CCECAudioSystem *>(device);
1157 return NULL;
1158 }
1159
1160 CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(CCECBusDevice *device)
1161 {
1162 if (device &&
1163 (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
1164 device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
1165 return static_cast<CCECPlaybackDevice *>(device);
1166 return NULL;
1167 }
1168
1169 CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(CCECBusDevice *device)
1170 {
1171 if (device && device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
1172 return static_cast<CCECRecordingDevice *>(device);
1173 return NULL;
1174 }
1175
1176 CCECTuner *CCECBusDevice::AsTuner(CCECBusDevice *device)
1177 {
1178 if (device && device->GetType() == CEC_DEVICE_TYPE_TUNER)
1179 return static_cast<CCECTuner *>(device);
1180 return NULL;
1181 }
1182
1183 CCECTV *CCECBusDevice::AsTV(CCECBusDevice *device)
1184 {
1185 if (device && device->GetType() == CEC_DEVICE_TYPE_TV)
1186 return static_cast<CCECTV *>(device);
1187 return NULL;
1188 }
1189
1190 void CCECBusDevice::MarkBusy(void)
1191 {
1192 CLockObject handlerLock(m_handlerMutex);
1193 ++m_iHandlerUseCount;
1194 }
1195
1196 void CCECBusDevice::MarkReady(void)
1197 {
1198 CLockObject handlerLock(m_handlerMutex);
1199 if (m_iHandlerUseCount > 0)
1200 --m_iHandlerUseCount;
1201 }
1202
1203 bool CCECBusDevice::TryLogicalAddress(void)
1204 {
1205 LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
1206
1207 if (!TransmitPoll(m_iLogicalAddress))
1208 {
1209 LIB_CEC->AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
1210 SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1211
1212 return true;
1213 }
1214
1215 LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
1216 SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
1217 return false;
1218 }
1219
1220 CCECClient *CCECBusDevice::GetClient(void)
1221 {
1222 return m_processor->GetClient(m_iLogicalAddress);
1223 }