cec: also reset the device status itself in CCECBusDevice::ResetDeviceStatus()
[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::GetCurrentOSDName(void)
408 {
409 CLockObject lock(m_mutex);
410 return m_strDeviceName;
411 }
412
413 CStdString CCECBusDevice::GetOSDName(const cec_logical_address initiator, bool bUpdate /* = false */)
414 {
415 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
416 bool bRequestUpdate(false);
417 {
418 CLockObject lock(m_mutex);
419 bRequestUpdate = bIsPresent &&
420 (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
421 m_type != CEC_DEVICE_TYPE_TV;
422 }
423
424 if (bRequestUpdate)
425 {
426 CheckVendorIdRequested(initiator);
427 RequestOSDName(initiator);
428 }
429
430 CLockObject lock(m_mutex);
431 return m_strDeviceName;
432 }
433
434 void CCECBusDevice::SetOSDName(CStdString strName)
435 {
436 CLockObject lock(m_mutex);
437 if (m_strDeviceName != strName)
438 {
439 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName.c_str());
440 m_strDeviceName = strName;
441 }
442 }
443
444 bool CCECBusDevice::RequestOSDName(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
445 {
446 bool bReturn(false);
447
448 if (!IsHandledByLibCEC() &&
449 !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
450 {
451 MarkBusy();
452 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting OSD name of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
453 bReturn = m_handler->TransmitRequestOSDName(initiator, m_iLogicalAddress, bWaitForResponse);
454 MarkReady();
455 }
456 return bReturn;
457 }
458
459 bool CCECBusDevice::TransmitOSDName(const cec_logical_address destination)
460 {
461 CStdString strDeviceName;
462 {
463 CLockObject lock(m_mutex);
464 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): OSD name '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, m_strDeviceName.c_str());
465 strDeviceName = m_strDeviceName;
466 }
467
468 MarkBusy();
469 bool bReturn = m_handler->TransmitOSDName(m_iLogicalAddress, destination, strDeviceName);
470 MarkReady();
471 return bReturn;
472 }
473
474 bool CCECBusDevice::HasValidPhysicalAddress(void)
475 {
476 CLockObject lock(m_mutex);
477 return CLibCEC::IsValidPhysicalAddress(m_iPhysicalAddress);
478 }
479
480 uint16_t CCECBusDevice::GetCurrentPhysicalAddress(void)
481 {
482 CLockObject lock(m_mutex);
483 return m_iPhysicalAddress;
484 }
485
486 uint16_t CCECBusDevice::GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate /* = false */)
487 {
488 if (!bSuppressUpdate)
489 {
490 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
491 bool bRequestUpdate(false);
492 {
493 CLockObject lock(m_mutex);
494 bRequestUpdate = bIsPresent && m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS;
495 }
496
497 if (bRequestUpdate)
498 {
499 CheckVendorIdRequested(initiator);
500 if (!RequestPhysicalAddress(initiator))
501 LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to request the physical address");
502 }
503 }
504
505 CLockObject lock(m_mutex);
506 return m_iPhysicalAddress;
507 }
508
509 bool CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
510 {
511 CLockObject lock(m_mutex);
512 if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
513 {
514 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
515 m_iPhysicalAddress = iNewAddress;
516 }
517 return true;
518 }
519
520 bool CCECBusDevice::RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
521 {
522 bool bReturn(false);
523
524 if (!IsHandledByLibCEC())
525 {
526 MarkBusy();
527 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting physical address of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
528 bReturn = m_handler->TransmitRequestPhysicalAddress(initiator, m_iLogicalAddress, bWaitForResponse);
529 MarkReady();
530 }
531 return bReturn;
532 }
533
534 bool CCECBusDevice::TransmitPhysicalAddress(void)
535 {
536 uint16_t iPhysicalAddress;
537 cec_device_type type;
538 {
539 CLockObject lock(m_mutex);
540 if (m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS)
541 return false;
542
543 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): physical adddress %4x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
544 iPhysicalAddress = m_iPhysicalAddress;
545 type = m_type;
546 }
547
548 MarkBusy();
549 bool bReturn = m_handler->TransmitPhysicalAddress(m_iLogicalAddress, iPhysicalAddress, type);
550 MarkReady();
551 return bReturn;
552 }
553
554 cec_power_status CCECBusDevice::GetCurrentPowerStatus(void)
555 {
556 CLockObject lock(m_mutex);
557 return m_powerStatus;
558 }
559
560 cec_power_status CCECBusDevice::GetPowerStatus(const cec_logical_address initiator, bool bUpdate /* = false */)
561 {
562 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
563 bool bRequestUpdate(false);
564 {
565 CLockObject lock(m_mutex);
566 bRequestUpdate = (bIsPresent &&
567 (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN ||
568 m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON ||
569 m_powerStatus == CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY ||
570 GetTimeMs() - m_iLastPowerStateUpdate >= CEC_POWER_STATE_REFRESH_TIME));
571 }
572
573 if (bRequestUpdate)
574 {
575 CheckVendorIdRequested(initiator);
576 RequestPowerStatus(initiator);
577 }
578
579 CLockObject lock(m_mutex);
580 return m_powerStatus;
581 }
582
583 void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
584 {
585 CLockObject lock(m_mutex);
586 if (m_powerStatus != powerStatus)
587 {
588 m_iLastPowerStateUpdate = GetTimeMs();
589 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
590 m_powerStatus = powerStatus;
591 }
592 }
593
594 bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
595 {
596 bool bReturn(false);
597
598 if (!IsHandledByLibCEC() &&
599 !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
600 {
601 MarkBusy();
602 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting power status of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
603 bReturn = m_handler->TransmitRequestPowerStatus(initiator, m_iLogicalAddress, bWaitForResponse);
604 MarkReady();
605 }
606 return bReturn;
607 }
608
609 bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination)
610 {
611 cec_power_status state;
612 {
613 CLockObject lock(m_mutex);
614 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): %s", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination, ToString(m_powerStatus));
615 state = m_powerStatus;
616 }
617
618 MarkBusy();
619 bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state);
620 MarkReady();
621 return bReturn;
622 }
623
624 cec_vendor_id CCECBusDevice::GetCurrentVendorId(void)
625 {
626 CLockObject lock(m_mutex);
627 return m_vendor;
628 }
629
630 cec_vendor_id CCECBusDevice::GetVendorId(const cec_logical_address initiator, bool bUpdate /* = false */)
631 {
632 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
633 bool bRequestUpdate(false);
634 {
635 CLockObject lock(m_mutex);
636 bRequestUpdate = (bIsPresent &&
637 (bUpdate || m_vendor == CEC_VENDOR_UNKNOWN));
638 }
639
640 if (bRequestUpdate)
641 RequestVendorId(initiator);
642
643 CLockObject lock(m_mutex);
644 return m_vendor;
645 }
646
647 const char *CCECBusDevice::GetVendorName(const cec_logical_address initiator, bool bUpdate /* = false */)
648 {
649 return ToString(GetVendorId(initiator, bUpdate));
650 }
651
652 bool CCECBusDevice::SetVendorId(uint64_t iVendorId)
653 {
654 bool bVendorChanged(false);
655
656 {
657 CLockObject lock(m_mutex);
658 bVendorChanged = (m_vendor != (cec_vendor_id)iVendorId);
659 m_vendor = (cec_vendor_id)iVendorId;
660 }
661
662 if (bVendorChanged)
663 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): vendor = %s (%06x)", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_vendor), m_vendor);
664
665 return bVendorChanged;
666 }
667
668 bool CCECBusDevice::RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
669 {
670 bool bReturn(false);
671
672 if (!IsHandledByLibCEC() && initiator != CECDEVICE_UNKNOWN)
673 {
674 MarkBusy();
675 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting vendor ID of '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
676 bReturn = m_handler->TransmitRequestVendorId(initiator, m_iLogicalAddress, bWaitForResponse);
677 MarkReady();
678
679 if (bWaitForResponse)
680 ReplaceHandler(true);
681 }
682 return bReturn;
683 }
684
685 bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort /* = true */)
686 {
687 bool bReturn(false);
688 uint64_t iVendorId;
689 {
690 CLockObject lock(m_mutex);
691 iVendorId = (uint64_t)m_vendor;
692 }
693
694 MarkBusy();
695 if (iVendorId == CEC_VENDOR_UNKNOWN)
696 {
697 if (bSendAbort)
698 {
699 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): vendor id feature abort", GetLogicalAddressName(), m_iLogicalAddress, ToString(destination), destination);
700 m_processor->TransmitAbort(m_iLogicalAddress, destination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID);
701 bReturn = true;
702 }
703 }
704 else
705 {
706 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);
707 bReturn = m_handler->TransmitVendorID(m_iLogicalAddress, iVendorId);
708 }
709 MarkReady();
710 return bReturn;
711 }
712
713 cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bool bSuppressPoll /* = false */)
714 {
715 cec_bus_device_status status(CEC_DEVICE_STATUS_UNKNOWN);
716 bool bNeedsPoll(false);
717
718 {
719 CLockObject lock(m_mutex);
720 status = m_deviceStatus;
721 bNeedsPoll = !bSuppressPoll &&
722 (bForcePoll || m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN);
723 }
724
725 if (bNeedsPoll)
726 {
727 bool bPollAcked(false);
728 if (bNeedsPoll && NeedsPoll())
729 bPollAcked = m_processor->PollDevice(m_iLogicalAddress);
730
731 status = bPollAcked ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT;
732 SetDeviceStatus(status);
733 }
734
735 return status;
736 }
737
738 void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
739 {
740 {
741 CLockObject lock(m_mutex);
742 switch (newStatus)
743 {
744 case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
745 if (m_deviceStatus != newStatus)
746 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'handled by libCEC'", GetLogicalAddressName(), 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, "%s (%X): device status changed into 'present'", GetLogicalAddressName(), 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, "%s (%X): device status changed into 'not present'", GetLogicalAddressName(), m_iLogicalAddress);
765 ResetDeviceStatus();
766 m_deviceStatus = newStatus;
767 }
768 break;
769 default:
770 ResetDeviceStatus();
771 break;
772 }
773 }
774 }
775
776 void CCECBusDevice::ResetDeviceStatus(void)
777 {
778 CLockObject lock(m_mutex);
779 SetPowerStatus (CEC_POWER_STATUS_UNKNOWN);
780 SetVendorId (CEC_VENDOR_UNKNOWN);
781 SetMenuState (CEC_MENU_STATE_ACTIVATED);
782 SetCecVersion (CEC_VERSION_UNKNOWN);
783 SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
784 SetOSDName (ToString(m_iLogicalAddress));
785 MarkAsInactiveSource();
786
787 m_iLastActive = 0;
788 m_bVendorIdRequested = false;
789 m_unsupportedFeatures.clear();
790
791 if (m_deviceStatus != CEC_DEVICE_STATUS_UNKNOWN)
792 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'unknown'", GetLogicalAddressName(), m_iLogicalAddress);
793 m_deviceStatus = CEC_DEVICE_STATUS_UNKNOWN;
794 }
795
796 bool CCECBusDevice::TransmitPoll(const cec_logical_address dest)
797 {
798 bool bReturn(false);
799 cec_logical_address destination(dest);
800 if (destination == CECDEVICE_UNKNOWN)
801 destination = m_iLogicalAddress;
802
803 CCECBusDevice *destDevice = m_processor->GetDevice(destination);
804 if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
805 return bReturn;
806
807 MarkBusy();
808 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
809 bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination);
810 LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
811
812 CLockObject lock(m_mutex);
813 if (bReturn)
814 {
815 m_iLastActive = GetTimeMs();
816 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
817 }
818 else
819 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
820
821 MarkReady();
822 return bReturn;
823 }
824
825 void CCECBusDevice::HandlePoll(const cec_logical_address destination)
826 {
827 if (destination >= 0 && destination < CECDEVICE_BROADCAST)
828 {
829 CCECBusDevice *device = m_processor->GetDevice(destination);
830 if (device)
831 device->HandlePollFrom(m_iLogicalAddress);
832 }
833 }
834
835 void CCECBusDevice::HandlePollFrom(const cec_logical_address initiator)
836 {
837 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
838 m_bAwaitingReceiveFailed = true;
839 }
840
841 bool CCECBusDevice::HandleReceiveFailed(void)
842 {
843 bool bReturn = m_bAwaitingReceiveFailed;
844 m_bAwaitingReceiveFailed = false;
845 return bReturn;
846 }
847
848 cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
849 {
850 CLockObject lock(m_mutex);
851 return m_menuState;
852 }
853
854 void CCECBusDevice::SetMenuState(const cec_menu_state state)
855 {
856 CLockObject lock(m_mutex);
857 if (m_menuState != state)
858 {
859 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
860 m_menuState = state;
861 }
862 }
863
864 bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest)
865 {
866 cec_menu_state menuState;
867 {
868 CLockObject lock(m_mutex);
869 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
870 menuState = m_menuState;
871 }
872
873 MarkBusy();
874 bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
875 MarkReady();
876 return bReturn;
877 }
878
879 bool CCECBusDevice::ActivateSource(void)
880 {
881 MarkAsActiveSource();
882 LIB_CEC->AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
883 MarkBusy();
884 bool bReturn = m_handler->ActivateSource();
885 MarkReady();
886 return bReturn;
887 }
888
889 bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
890 {
891 bool bReturn(false);
892
893 if (IsHandledByLibCEC())
894 {
895 MarkBusy();
896 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting active source");
897
898 bReturn = m_handler->TransmitRequestActiveSource(m_iLogicalAddress, bWaitForResponse);
899 MarkReady();
900 }
901 return bReturn;
902 }
903
904 void CCECBusDevice::MarkAsActiveSource(void)
905 {
906 CLockObject lock(m_mutex);
907 if (!m_bActiveSource)
908 LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
909 else
910 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
911
912 CECDEVICEVEC devices;
913 m_processor->GetDevices()->Get(devices);
914 for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
915 if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
916 (*it)->MarkAsInactiveSource();
917
918 m_bActiveSource = true;
919 SetPowerStatus(CEC_POWER_STATUS_ON);
920 }
921
922 void CCECBusDevice::MarkAsInactiveSource(void)
923 {
924 {
925 CLockObject lock(m_mutex);
926 if (m_bActiveSource)
927 LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
928 m_bActiveSource = false;
929 }
930 }
931
932 bool CCECBusDevice::TransmitActiveSource(void)
933 {
934 bool bSendActiveSource(false);
935
936 {
937 CLockObject lock(m_mutex);
938 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
939 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
940 else if (m_bActiveSource)
941 {
942 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
943 bSendActiveSource = true;
944 }
945 else
946 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
947 }
948
949 if (bSendActiveSource)
950 {
951 MarkBusy();
952 m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
953 MarkReady();
954 return true;
955 }
956
957 return false;
958 }
959
960 bool CCECBusDevice::TransmitImageViewOn(void)
961 {
962 {
963 CLockObject lock(m_mutex);
964 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
965 {
966 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
967 return false;
968 }
969 }
970
971 MarkBusy();
972 m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
973 MarkReady();
974 return true;
975 }
976
977 bool CCECBusDevice::TransmitInactiveSource(void)
978 {
979 uint16_t iPhysicalAddress;
980 {
981 CLockObject lock(m_mutex);
982 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
983 iPhysicalAddress = m_iPhysicalAddress;
984 }
985
986 MarkBusy();
987 bool bReturn = m_handler->TransmitInactiveSource(m_iLogicalAddress, iPhysicalAddress);
988 MarkReady();
989 return bReturn;
990 }
991
992 bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
993 {
994 MarkBusy();
995 bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
996 MarkReady();
997 return bReturn;
998 }
999
1000 void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
1001 {
1002 CLockObject lock(m_mutex);
1003 if (iNewAddress != m_iStreamPath)
1004 {
1005 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
1006 m_iStreamPath = iNewAddress;
1007 }
1008
1009 if (!LIB_CEC->IsValidPhysicalAddress(iNewAddress))
1010 return;
1011
1012 CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
1013 if (device)
1014 {
1015 // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
1016 device->MarkAsActiveSource();
1017 }
1018 else
1019 {
1020 // try to find the device with the old address, and mark it as inactive when found
1021 device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
1022 if (device)
1023 device->MarkAsInactiveSource();
1024 }
1025 }
1026
1027 bool CCECBusDevice::PowerOn(const cec_logical_address initiator)
1028 {
1029 bool bReturn(false);
1030 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
1031
1032 MarkBusy();
1033 cec_power_status currentStatus = GetPowerStatus(initiator, false);
1034 if (currentStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
1035 currentStatus != CEC_POWER_STATUS_ON)
1036 {
1037 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
1038 if (m_handler->PowerOn(initiator, m_iLogicalAddress))
1039 {
1040 SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
1041 bReturn = true;
1042 }
1043 }
1044 else
1045 {
1046 LIB_CEC->AddLog(CEC_LOG_NOTICE, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
1047 }
1048
1049 MarkReady();
1050 return bReturn;
1051 }
1052
1053 bool CCECBusDevice::Standby(const cec_logical_address initiator)
1054 {
1055 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
1056
1057 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
1058 MarkBusy();
1059 bool bReturn = m_handler->TransmitStandby(initiator, m_iLogicalAddress);
1060 MarkReady();
1061 return bReturn;
1062 }
1063
1064 bool CCECBusDevice::NeedsPoll(void)
1065 {
1066 bool bSendPoll(false);
1067 cec_logical_address pollAddress(CECDEVICE_UNKNOWN);
1068 switch (m_iLogicalAddress)
1069 {
1070 case CECDEVICE_PLAYBACKDEVICE3:
1071 pollAddress = CECDEVICE_PLAYBACKDEVICE2;
1072 break;
1073 case CECDEVICE_PLAYBACKDEVICE2:
1074 pollAddress = CECDEVICE_PLAYBACKDEVICE1;
1075 break;
1076 case CECDEVICE_RECORDINGDEVICE3:
1077 pollAddress = CECDEVICE_RECORDINGDEVICE2;
1078 break;
1079 case CECDEVICE_RECORDINGDEVICE2:
1080 pollAddress = CECDEVICE_RECORDINGDEVICE1;
1081 break;
1082 case CECDEVICE_TUNER4:
1083 pollAddress = CECDEVICE_TUNER3;
1084 break;
1085 case CECDEVICE_TUNER3:
1086 pollAddress = CECDEVICE_TUNER2;
1087 break;
1088 case CECDEVICE_TUNER2:
1089 pollAddress = CECDEVICE_TUNER1;
1090 break;
1091 case CECDEVICE_AUDIOSYSTEM:
1092 case CECDEVICE_PLAYBACKDEVICE1:
1093 case CECDEVICE_RECORDINGDEVICE1:
1094 case CECDEVICE_TUNER1:
1095 case CECDEVICE_TV:
1096 bSendPoll = true;
1097 break;
1098 default:
1099 break;
1100 }
1101
1102 if (!bSendPoll && pollAddress != CECDEVICE_UNKNOWN)
1103 {
1104 CCECBusDevice *device = m_processor->GetDevice(pollAddress);
1105 if (device)
1106 {
1107 cec_bus_device_status status = device->GetStatus();
1108 bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1109 }
1110 else
1111 {
1112 bSendPoll = true;
1113 }
1114 }
1115
1116 return bSendPoll;
1117 }
1118
1119 void CCECBusDevice::CheckVendorIdRequested(const cec_logical_address initiator)
1120 {
1121 bool bRequestVendorId(false);
1122 {
1123 CLockObject lock(m_mutex);
1124 bRequestVendorId = !m_bVendorIdRequested;
1125 m_bVendorIdRequested = true;
1126 }
1127
1128 if (bRequestVendorId)
1129 {
1130 ReplaceHandler(false);
1131 GetVendorId(initiator);
1132 }
1133 }
1134 //@}
1135
1136 CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
1137 {
1138 return AsAudioSystem(this);
1139 }
1140
1141 CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
1142 {
1143 return AsPlaybackDevice(this);
1144 }
1145
1146 CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
1147 {
1148 return AsRecordingDevice(this);
1149 }
1150
1151 CCECTuner *CCECBusDevice::AsTuner(void)
1152 {
1153 return AsTuner(this);
1154 }
1155
1156 CCECTV *CCECBusDevice::AsTV(void)
1157 {
1158 return AsTV(this);
1159 }
1160
1161 CCECAudioSystem *CCECBusDevice::AsAudioSystem(CCECBusDevice *device)
1162 {
1163 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
1164 return static_cast<CCECAudioSystem *>(device);
1165 return NULL;
1166 }
1167
1168 CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(CCECBusDevice *device)
1169 {
1170 if (device &&
1171 (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
1172 device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
1173 return static_cast<CCECPlaybackDevice *>(device);
1174 return NULL;
1175 }
1176
1177 CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(CCECBusDevice *device)
1178 {
1179 if (device && device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
1180 return static_cast<CCECRecordingDevice *>(device);
1181 return NULL;
1182 }
1183
1184 CCECTuner *CCECBusDevice::AsTuner(CCECBusDevice *device)
1185 {
1186 if (device && device->GetType() == CEC_DEVICE_TYPE_TUNER)
1187 return static_cast<CCECTuner *>(device);
1188 return NULL;
1189 }
1190
1191 CCECTV *CCECBusDevice::AsTV(CCECBusDevice *device)
1192 {
1193 if (device && device->GetType() == CEC_DEVICE_TYPE_TV)
1194 return static_cast<CCECTV *>(device);
1195 return NULL;
1196 }
1197
1198 void CCECBusDevice::MarkBusy(void)
1199 {
1200 CLockObject handlerLock(m_handlerMutex);
1201 ++m_iHandlerUseCount;
1202 }
1203
1204 void CCECBusDevice::MarkReady(void)
1205 {
1206 CLockObject handlerLock(m_handlerMutex);
1207 if (m_iHandlerUseCount > 0)
1208 --m_iHandlerUseCount;
1209 }
1210
1211 bool CCECBusDevice::TryLogicalAddress(void)
1212 {
1213 LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
1214
1215 if (!TransmitPoll(m_iLogicalAddress))
1216 {
1217 LIB_CEC->AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
1218 SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1219
1220 return true;
1221 }
1222
1223 LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
1224 SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
1225 return false;
1226 }
1227
1228 CCECClient *CCECBusDevice::GetClient(void)
1229 {
1230 return m_processor->GetClient(m_iLogicalAddress);
1231 }