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