added a callback for clients that is called when a source is (de)activated, so the...
[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 "../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
51 using namespace std;
52 using namespace CEC;
53 using namespace PLATFORM;
54
55 #define LIB_CEC m_processor->GetLib()
56 #define ToString(p) CCECTypeUtils::ToString(p)
57
58 CCECBusDevice::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
87 CCECBusDevice::~CCECBusDevice(void)
88 {
89 DELETE_AND_NULL(m_handler);
90 }
91
92 bool 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
152 CCECCommandHandler *CCECBusDevice::GetHandler(void)
153 {
154 ReplaceHandler(false);
155 MarkBusy();
156 return m_handler;
157 }
158
159 bool 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
194 const char* CCECBusDevice::GetLogicalAddressName(void) const
195 {
196 return ToString(m_iLogicalAddress);
197 }
198
199 bool CCECBusDevice::IsPresent(void)
200 {
201 CLockObject lock(m_mutex);
202 return m_deviceStatus == CEC_DEVICE_STATUS_PRESENT;
203 }
204
205 bool CCECBusDevice::IsHandledByLibCEC(void)
206 {
207 CLockObject lock(m_mutex);
208 return m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC;
209 }
210
211 void 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
238 bool 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
247 bool 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
255 bool 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
263 cec_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
283 void 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
291 bool 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
306 bool 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
321 cec_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
341 void 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
354 void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
355 {
356 if (language.device == m_iLogicalAddress)
357 SetMenuLanguage(language.language);
358 }
359
360 bool 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
375 bool 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
408 bool 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
421 CStdString CCECBusDevice::GetCurrentOSDName(void)
422 {
423 CLockObject lock(m_mutex);
424 return m_strDeviceName;
425 }
426
427 CStdString 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
448 void 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
458 bool 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
473 bool 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
488 bool CCECBusDevice::HasValidPhysicalAddress(void)
489 {
490 CLockObject lock(m_mutex);
491 return CLibCEC::IsValidPhysicalAddress(m_iPhysicalAddress);
492 }
493
494 uint16_t CCECBusDevice::GetCurrentPhysicalAddress(void)
495 {
496 CLockObject lock(m_mutex);
497 return m_iPhysicalAddress;
498 }
499
500 uint16_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
523 bool 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
534 bool 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
548 bool 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
568 cec_power_status CCECBusDevice::GetCurrentPowerStatus(void)
569 {
570 CLockObject lock(m_mutex);
571 return m_powerStatus;
572 }
573
574 cec_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
597 void 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
608 bool 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
623 bool 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
638 cec_vendor_id CCECBusDevice::GetCurrentVendorId(void)
639 {
640 CLockObject lock(m_mutex);
641 return m_vendor;
642 }
643
644 cec_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
661 const char *CCECBusDevice::GetVendorName(const cec_logical_address initiator, bool bUpdate /* = false */)
662 {
663 return ToString(GetVendorId(initiator, bUpdate));
664 }
665
666 bool 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
682 bool 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
699 bool 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
727 cec_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
752 void 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
790 void 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
810 bool 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
839 void 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
849 void 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
855 bool CCECBusDevice::HandleReceiveFailed(void)
856 {
857 bool bReturn = m_bAwaitingReceiveFailed;
858 m_bAwaitingReceiveFailed = false;
859 return bReturn;
860 }
861
862 cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
863 {
864 CLockObject lock(m_mutex);
865 return m_menuState;
866 }
867
868 void 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
878 bool 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
893 bool 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
903 bool 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
918 void 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
954 void 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
975 bool 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
1012 bool 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
1030 bool 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
1045 bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
1046 {
1047 MarkBusy();
1048 bool bReturn = m_handler->ActivateSource(true);
1049 MarkReady();
1050 return bReturn;
1051 }
1052
1053 void 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
1080 bool 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
1106 bool 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
1117 bool 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
1172 void 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
1189 CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
1190 {
1191 return AsAudioSystem(this);
1192 }
1193
1194 CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
1195 {
1196 return AsPlaybackDevice(this);
1197 }
1198
1199 CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
1200 {
1201 return AsRecordingDevice(this);
1202 }
1203
1204 CCECTuner *CCECBusDevice::AsTuner(void)
1205 {
1206 return AsTuner(this);
1207 }
1208
1209 CCECTV *CCECBusDevice::AsTV(void)
1210 {
1211 return AsTV(this);
1212 }
1213
1214 CCECAudioSystem *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
1221 CCECPlaybackDevice *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
1230 CCECRecordingDevice *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
1237 CCECTuner *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
1244 CCECTV *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
1251 void CCECBusDevice::MarkBusy(void)
1252 {
1253 CLockObject handlerLock(m_handlerMutex);
1254 ++m_iHandlerUseCount;
1255 }
1256
1257 void CCECBusDevice::MarkReady(void)
1258 {
1259 CLockObject handlerLock(m_handlerMutex);
1260 if (m_iHandlerUseCount > 0)
1261 --m_iHandlerUseCount;
1262 }
1263
1264 bool 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
1281 CCECClient *CCECBusDevice::GetClient(void)
1282 {
1283 return m_processor->GetClient(m_iLogicalAddress);
1284 }