cosmetics
[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_UNKNOWN:
745 if (m_deviceStatus != newStatus)
746 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'unknown'", ToString(m_iLogicalAddress));
747 ResetDeviceStatus();
748 m_deviceStatus = newStatus;
749 break;
750 case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
751 if (m_deviceStatus != newStatus)
752 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'handled by libCEC'", ToString(m_iLogicalAddress));
753 SetPowerStatus (CEC_POWER_STATUS_ON);
754 SetVendorId (CEC_VENDOR_UNKNOWN);
755 SetMenuState (CEC_MENU_STATE_ACTIVATED);
756 SetCecVersion (CEC_VERSION_1_3A);
757 SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
758 MarkAsInactiveSource();
759 m_iLastActive = 0;
760 m_deviceStatus = newStatus;
761 break;
762 case CEC_DEVICE_STATUS_PRESENT:
763 if (m_deviceStatus != newStatus)
764 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'present'", ToString(m_iLogicalAddress));
765 m_deviceStatus = newStatus;
766 break;
767 case CEC_DEVICE_STATUS_NOT_PRESENT:
768 if (m_deviceStatus != newStatus)
769 {
770 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device status of %s changed into 'not present'", ToString(m_iLogicalAddress));
771 ResetDeviceStatus();
772 m_deviceStatus = newStatus;
773 }
774 break;
775 }
776 }
777 }
778
779 void CCECBusDevice::ResetDeviceStatus(void)
780 {
781 CLockObject lock(m_mutex);
782 SetPowerStatus (CEC_POWER_STATUS_UNKNOWN);
783 SetVendorId (CEC_VENDOR_UNKNOWN);
784 SetMenuState (CEC_MENU_STATE_ACTIVATED);
785 SetCecVersion (CEC_VERSION_UNKNOWN);
786 SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
787 SetOSDName (ToString(m_iLogicalAddress));
788 MarkAsInactiveSource();
789 m_iLastActive = 0;
790 m_bVendorIdRequested = false;
791 m_unsupportedFeatures.clear();
792 }
793
794 bool CCECBusDevice::TransmitPoll(const cec_logical_address dest)
795 {
796 bool bReturn(false);
797 cec_logical_address destination(dest);
798 if (destination == CECDEVICE_UNKNOWN)
799 destination = m_iLogicalAddress;
800
801 CCECBusDevice *destDevice = m_processor->GetDevice(destination);
802 if (destDevice->m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
803 return bReturn;
804
805 MarkBusy();
806 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): POLL", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest);
807 bReturn = m_handler->TransmitPoll(m_iLogicalAddress, destination);
808 LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? ">> POLL sent" : ">> POLL not sent");
809
810 CLockObject lock(m_mutex);
811 if (bReturn)
812 {
813 m_iLastActive = GetTimeMs();
814 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
815 }
816 else
817 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
818
819 MarkReady();
820 return bReturn;
821 }
822
823 void CCECBusDevice::HandlePoll(const cec_logical_address destination)
824 {
825 if (destination >= 0 && destination < CECDEVICE_BROADCAST)
826 {
827 CCECBusDevice *device = m_processor->GetDevice(destination);
828 if (device)
829 device->HandlePollFrom(m_iLogicalAddress);
830 }
831 }
832
833 void CCECBusDevice::HandlePollFrom(const cec_logical_address initiator)
834 {
835 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
836 m_bAwaitingReceiveFailed = true;
837 }
838
839 bool CCECBusDevice::HandleReceiveFailed(void)
840 {
841 bool bReturn = m_bAwaitingReceiveFailed;
842 m_bAwaitingReceiveFailed = false;
843 return bReturn;
844 }
845
846 cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
847 {
848 CLockObject lock(m_mutex);
849 return m_menuState;
850 }
851
852 void CCECBusDevice::SetMenuState(const cec_menu_state state)
853 {
854 CLockObject lock(m_mutex);
855 if (m_menuState != state)
856 {
857 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
858 m_menuState = state;
859 }
860 }
861
862 bool CCECBusDevice::TransmitMenuState(const cec_logical_address dest)
863 {
864 cec_menu_state menuState;
865 {
866 CLockObject lock(m_mutex);
867 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> %s (%X): menu state '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(dest), dest, ToString(m_menuState));
868 menuState = m_menuState;
869 }
870
871 MarkBusy();
872 bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
873 MarkReady();
874 return bReturn;
875 }
876
877 bool CCECBusDevice::ActivateSource(void)
878 {
879 MarkAsActiveSource();
880 LIB_CEC->AddLog(CEC_LOG_DEBUG, "activating source '%s'", ToString(m_iLogicalAddress));
881 MarkBusy();
882 bool bReturn = m_handler->ActivateSource();
883 MarkReady();
884 return bReturn;
885 }
886
887 bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
888 {
889 bool bReturn(false);
890
891 if (IsHandledByLibCEC())
892 {
893 MarkBusy();
894 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting active source");
895
896 bReturn = m_handler->TransmitRequestActiveSource(m_iLogicalAddress, bWaitForResponse);
897 MarkReady();
898 }
899 return bReturn;
900 }
901
902 void CCECBusDevice::MarkAsActiveSource(void)
903 {
904 CLockObject lock(m_mutex);
905 if (!m_bActiveSource)
906 LIB_CEC->AddLog(CEC_LOG_DEBUG, "making %s (%x) the active source", GetLogicalAddressName(), m_iLogicalAddress);
907 else
908 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%x) was already marked as active source", GetLogicalAddressName(), m_iLogicalAddress);
909
910 CECDEVICEVEC devices;
911 m_processor->GetDevices()->Get(devices);
912 for (CECDEVICEVEC::iterator it = devices.begin(); it != devices.end(); it++)
913 if ((*it)->GetLogicalAddress() != m_iLogicalAddress)
914 (*it)->MarkAsInactiveSource();
915
916 m_bActiveSource = true;
917 SetPowerStatus(CEC_POWER_STATUS_ON);
918 }
919
920 void CCECBusDevice::MarkAsInactiveSource(void)
921 {
922 {
923 CLockObject lock(m_mutex);
924 if (m_bActiveSource)
925 LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
926 m_bActiveSource = false;
927 }
928 }
929
930 bool CCECBusDevice::TransmitActiveSource(void)
931 {
932 bool bSendActiveSource(false);
933
934 {
935 CLockObject lock(m_mutex);
936 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
937 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
938 else if (m_bActiveSource)
939 {
940 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
941 bSendActiveSource = true;
942 }
943 else
944 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
945 }
946
947 if (bSendActiveSource)
948 {
949 MarkBusy();
950 m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
951 MarkReady();
952 return true;
953 }
954
955 return false;
956 }
957
958 bool CCECBusDevice::TransmitImageViewOn(void)
959 {
960 {
961 CLockObject lock(m_mutex);
962 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
963 {
964 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
965 return false;
966 }
967 }
968
969 MarkBusy();
970 m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
971 MarkReady();
972 return true;
973 }
974
975 bool CCECBusDevice::TransmitInactiveSource(void)
976 {
977 uint16_t iPhysicalAddress;
978 {
979 CLockObject lock(m_mutex);
980 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
981 iPhysicalAddress = m_iPhysicalAddress;
982 }
983
984 MarkBusy();
985 bool bReturn = m_handler->TransmitInactiveSource(m_iLogicalAddress, iPhysicalAddress);
986 MarkReady();
987 return bReturn;
988 }
989
990 bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
991 {
992 MarkBusy();
993 bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
994 MarkReady();
995 return bReturn;
996 }
997
998 void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
999 {
1000 CLockObject lock(m_mutex);
1001 if (iNewAddress != m_iStreamPath)
1002 {
1003 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): stream path changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, iOldAddress == 0 ? m_iStreamPath : iOldAddress, iNewAddress);
1004 m_iStreamPath = iNewAddress;
1005 }
1006
1007 if (!LIB_CEC->IsValidPhysicalAddress(iNewAddress))
1008 return;
1009
1010 CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
1011 if (device)
1012 {
1013 // if a device is found with the new physical address, mark it as active, which will automatically mark all other devices as inactive
1014 device->MarkAsActiveSource();
1015 }
1016 else
1017 {
1018 // try to find the device with the old address, and mark it as inactive when found
1019 device = m_processor->GetDeviceByPhysicalAddress(iOldAddress);
1020 if (device)
1021 device->MarkAsInactiveSource();
1022 }
1023 }
1024
1025 bool CCECBusDevice::PowerOn(const cec_logical_address initiator)
1026 {
1027 bool bReturn(false);
1028 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
1029
1030 MarkBusy();
1031 cec_power_status currentStatus = GetPowerStatus(initiator, false);
1032 if (currentStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON &&
1033 currentStatus != CEC_POWER_STATUS_ON)
1034 {
1035 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< powering on '%s' (%X)", GetLogicalAddressName(), m_iLogicalAddress);
1036 if (m_handler->PowerOn(initiator, m_iLogicalAddress))
1037 {
1038 SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
1039 bReturn = true;
1040 }
1041 }
1042 else
1043 {
1044 LIB_CEC->AddLog(CEC_LOG_NOTICE, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
1045 }
1046
1047 MarkReady();
1048 return bReturn;
1049 }
1050
1051 bool CCECBusDevice::Standby(const cec_logical_address initiator)
1052 {
1053 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
1054
1055 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
1056 MarkBusy();
1057 bool bReturn = m_handler->TransmitStandby(initiator, m_iLogicalAddress);
1058 MarkReady();
1059 return bReturn;
1060 }
1061
1062 bool CCECBusDevice::NeedsPoll(void)
1063 {
1064 bool bSendPoll(false);
1065 cec_logical_address pollAddress(CECDEVICE_UNKNOWN);
1066 switch (m_iLogicalAddress)
1067 {
1068 case CECDEVICE_PLAYBACKDEVICE3:
1069 pollAddress = CECDEVICE_PLAYBACKDEVICE2;
1070 break;
1071 case CECDEVICE_PLAYBACKDEVICE2:
1072 pollAddress = CECDEVICE_PLAYBACKDEVICE1;
1073 break;
1074 case CECDEVICE_RECORDINGDEVICE3:
1075 pollAddress = CECDEVICE_RECORDINGDEVICE2;
1076 break;
1077 case CECDEVICE_RECORDINGDEVICE2:
1078 pollAddress = CECDEVICE_RECORDINGDEVICE1;
1079 break;
1080 case CECDEVICE_TUNER4:
1081 pollAddress = CECDEVICE_TUNER3;
1082 break;
1083 case CECDEVICE_TUNER3:
1084 pollAddress = CECDEVICE_TUNER2;
1085 break;
1086 case CECDEVICE_TUNER2:
1087 pollAddress = CECDEVICE_TUNER1;
1088 break;
1089 case CECDEVICE_AUDIOSYSTEM:
1090 case CECDEVICE_PLAYBACKDEVICE1:
1091 case CECDEVICE_RECORDINGDEVICE1:
1092 case CECDEVICE_TUNER1:
1093 case CECDEVICE_TV:
1094 bSendPoll = true;
1095 break;
1096 default:
1097 break;
1098 }
1099
1100 if (!bSendPoll && pollAddress != CECDEVICE_UNKNOWN)
1101 {
1102 CCECBusDevice *device = m_processor->GetDevice(pollAddress);
1103 if (device)
1104 {
1105 cec_bus_device_status status = device->GetStatus();
1106 bSendPoll = (status == CEC_DEVICE_STATUS_PRESENT || status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1107 }
1108 else
1109 {
1110 bSendPoll = true;
1111 }
1112 }
1113
1114 return bSendPoll;
1115 }
1116
1117 void CCECBusDevice::CheckVendorIdRequested(const cec_logical_address initiator)
1118 {
1119 bool bRequestVendorId(false);
1120 {
1121 CLockObject lock(m_mutex);
1122 bRequestVendorId = !m_bVendorIdRequested;
1123 m_bVendorIdRequested = true;
1124 }
1125
1126 if (bRequestVendorId)
1127 {
1128 ReplaceHandler(false);
1129 GetVendorId(initiator);
1130 }
1131 }
1132 //@}
1133
1134 CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
1135 {
1136 return AsAudioSystem(this);
1137 }
1138
1139 CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
1140 {
1141 return AsPlaybackDevice(this);
1142 }
1143
1144 CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
1145 {
1146 return AsRecordingDevice(this);
1147 }
1148
1149 CCECTuner *CCECBusDevice::AsTuner(void)
1150 {
1151 return AsTuner(this);
1152 }
1153
1154 CCECTV *CCECBusDevice::AsTV(void)
1155 {
1156 return AsTV(this);
1157 }
1158
1159 CCECAudioSystem *CCECBusDevice::AsAudioSystem(CCECBusDevice *device)
1160 {
1161 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
1162 return static_cast<CCECAudioSystem *>(device);
1163 return NULL;
1164 }
1165
1166 CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(CCECBusDevice *device)
1167 {
1168 if (device &&
1169 (device->GetType() == CEC_DEVICE_TYPE_PLAYBACK_DEVICE ||
1170 device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE))
1171 return static_cast<CCECPlaybackDevice *>(device);
1172 return NULL;
1173 }
1174
1175 CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(CCECBusDevice *device)
1176 {
1177 if (device && device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
1178 return static_cast<CCECRecordingDevice *>(device);
1179 return NULL;
1180 }
1181
1182 CCECTuner *CCECBusDevice::AsTuner(CCECBusDevice *device)
1183 {
1184 if (device && device->GetType() == CEC_DEVICE_TYPE_TUNER)
1185 return static_cast<CCECTuner *>(device);
1186 return NULL;
1187 }
1188
1189 CCECTV *CCECBusDevice::AsTV(CCECBusDevice *device)
1190 {
1191 if (device && device->GetType() == CEC_DEVICE_TYPE_TV)
1192 return static_cast<CCECTV *>(device);
1193 return NULL;
1194 }
1195
1196 void CCECBusDevice::MarkBusy(void)
1197 {
1198 CLockObject handlerLock(m_handlerMutex);
1199 ++m_iHandlerUseCount;
1200 }
1201
1202 void CCECBusDevice::MarkReady(void)
1203 {
1204 CLockObject handlerLock(m_handlerMutex);
1205 if (m_iHandlerUseCount > 0)
1206 --m_iHandlerUseCount;
1207 }
1208
1209 bool CCECBusDevice::TryLogicalAddress(void)
1210 {
1211 LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
1212
1213 if (!TransmitPoll(m_iLogicalAddress))
1214 {
1215 LIB_CEC->AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
1216 SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1217
1218 return true;
1219 }
1220
1221 LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
1222 SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
1223 return false;
1224 }
1225
1226 CCECClient *CCECBusDevice::GetClient(void)
1227 {
1228 return m_processor->GetClient(m_iLogicalAddress);
1229 }