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