cec: safe deletes for members
[deb_libcec.git] / src / lib / devices / CECBusDevice.cpp
CommitLineData
e9de9629
LOK
1/*
2 * This file is part of the libCEC(R) library.
3 *
b492c10e 4 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
e9de9629
LOK
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"
eafa9d46
LOK
34#include "../CECProcessor.h"
35#include "../implementations/ANCommandHandler.h"
36#include "../implementations/CECCommandHandler.h"
37#include "../implementations/SLCommandHandler.h"
11621576 38#include "../implementations/VLCommandHandler.h"
5477a250 39#include "../LibCEC.h"
ba65909d 40#include "../platform/util/timeutils.h"
c9d15485 41#include "../platform/util/util.h"
e9de9629 42
004b8382
LOK
43#include "CECAudioSystem.h"
44#include "CECPlaybackDevice.h"
45#include "CECRecordingDevice.h"
46#include "CECTuner.h"
47#include "CECTV.h"
48
49using namespace std;
e9de9629 50using namespace CEC;
f00ff009 51using namespace PLATFORM;
e9de9629 52
004b8382
LOK
53#define LIB_CEC m_processor->GetLib()
54#define ToString(p) LIB_CEC->ToString(p)
c4098482 55
d2d1660c 56CCECBusDevice::CCECBusDevice(CCECProcessor *processor, cec_logical_address iLogicalAddress, uint16_t iPhysicalAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */) :
ecc676ca
LOK
57 m_type (CEC_DEVICE_TYPE_RESERVED),
58 m_iPhysicalAddress (iPhysicalAddress),
b32ffd87 59 m_iStreamPath (CEC_INVALID_PHYSICAL_ADDRESS),
ecc676ca
LOK
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),
ebb6ddb3 72 m_bAwaitingReceiveFailed(false),
ecc676ca 73 m_bVendorIdRequested (false)
e9de9629
LOK
74{
75 m_handler = new CCECCommandHandler(this);
51b2a094 76
a3269a0a
LOK
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;
1fcf5a3f 81
c4098482 82 m_strDeviceName = ToString(m_iLogicalAddress);
e9de9629
LOK
83}
84
85CCECBusDevice::~CCECBusDevice(void)
86{
c9d15485 87 DELETE_AND_NULL(m_handler);
e9de9629
LOK
88}
89
004b8382
LOK
90bool 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());
c9d15485 109 DELETE_AND_NULL(m_handler);
004b8382
LOK
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
93729720 146bool CCECBusDevice::HandleCommand(const cec_command &command)
f8513317 147{
7f919115
LOK
148 bool bHandled(false);
149
150 /* update "last active" */
8fa35473 151 {
f00ff009 152 CLockObject lock(m_mutex);
8fa35473 153 m_iLastActive = GetTimeMs();
f4b7b1dc 154
ba427965 155 /* don't call GetStatus() here, just read the value with the mutex locked */
d297cbd4 156 if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC && command.opcode_set == 1)
f4b7b1dc 157 m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
1344fd1a
LOK
158
159 MarkBusy();
8fa35473
LOK
160 }
161
7f919115
LOK
162 /* handle the command */
163 bHandled = m_handler->HandleCommand(command);
8fa35473 164
7f919115 165 /* change status to present */
004b8382 166 if (bHandled && GetLogicalAddress() != CECDEVICE_BROADCAST)
8d915412 167 {
f00ff009 168 CLockObject lock(m_mutex);
8fa35473 169 if (m_deviceStatus != CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
8d915412 170 {
8fa35473 171 if (m_deviceStatus != CEC_DEVICE_STATUS_PRESENT)
004b8382 172 LIB_CEC->AddLog(CEC_LOG_DEBUG, "device %s (%x) status changed to present after command %s", GetLogicalAddressName(), (uint8_t)GetLogicalAddress(), ToString(command.opcode));
8fa35473 173 m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
8d915412 174 }
8d915412 175 }
7f919115 176
1344fd1a 177 MarkReady();
7f919115 178 return bHandled;
93729720
LOK
179}
180
004b8382 181const char* CCECBusDevice::GetLogicalAddressName(void) const
93729720 182{
004b8382
LOK
183 return ToString(m_iLogicalAddress);
184}
185
186bool CCECBusDevice::IsPresent(void)
187{
188 CLockObject lock(m_mutex);
189 return m_deviceStatus == CEC_DEVICE_STATUS_PRESENT;
190}
191
192bool CCECBusDevice::IsHandledByLibCEC(void)
193{
194 CLockObject lock(m_mutex);
195 return m_deviceStatus == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC;
196}
197
198void 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;
c6d7f0e1 209
5e5637c6 210 {
004b8382
LOK
211 CLockObject lock(m_mutex);
212 if (m_unsupportedFeatures.find(opcode) == m_unsupportedFeatures.end())
8670c970 213 {
004b8382
LOK
214 LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking opcode '%s' as unsupported feature for device '%s'", ToString(opcode), GetLogicalAddressName());
215 m_unsupportedFeatures.insert(opcode);
8670c970
LOK
216 }
217 }
f437e4be 218
004b8382
LOK
219 // signal threads that are waiting for a reponse
220 MarkBusy();
221 m_handler->SignalOpcode(cec_command::GetResponseOpcode(opcode));
222 MarkReady();
223}
224
225bool 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
234bool 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);
1344fd1a
LOK
238 MarkReady();
239 return bReturn;
93729720
LOK
240}
241
004b8382 242bool CCECBusDevice::TransmitKeyRelease(const cec_logical_address initiator, bool bWait /* = true */)
93729720 243{
1344fd1a 244 MarkBusy();
004b8382 245 bool bReturn = m_handler->TransmitKeyRelease(initiator, m_iLogicalAddress, bWait);
1344fd1a
LOK
246 MarkReady();
247 return bReturn;
93729720
LOK
248}
249
004b8382 250cec_version CCECBusDevice::GetCecVersion(const cec_logical_address initiator, bool bUpdate /* = false */)
93729720 251{
6bbfc3f7 252 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
97fc4ffb
LOK
253 bool bRequestUpdate(false);
254 {
f00ff009 255 CLockObject lock(m_mutex);
ddb6ac5b 256 bRequestUpdate = bIsPresent &&
6bbfc3f7 257 (bUpdate || m_cecVersion == CEC_VERSION_UNKNOWN);
97fc4ffb
LOK
258 }
259
260 if (bRequestUpdate)
ebb6ddb3 261 {
004b8382
LOK
262 CheckVendorIdRequested(initiator);
263 RequestCecVersion(initiator);
ebb6ddb3 264 }
f294b22f 265
f00ff009 266 CLockObject lock(m_mutex);
f294b22f
LOK
267 return m_cecVersion;
268}
269
004b8382 270void CCECBusDevice::SetCecVersion(const cec_version newVersion)
5734016c 271{
004b8382
LOK
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;
5734016c
LOK
276}
277
004b8382 278bool CCECBusDevice::RequestCecVersion(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
f294b22f
LOK
279{
280 bool bReturn(false);
b64db02e 281
004b8382 282 if (!IsHandledByLibCEC() &&
66c3ef5a 283 !IsUnsupportedFeature(CEC_OPCODE_GET_CEC_VERSION))
93729720 284 {
1344fd1a 285 MarkBusy();
004b8382
LOK
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);
1344fd1a 288 MarkReady();
93729720 289 }
f294b22f 290 return bReturn;
93729720
LOK
291}
292
004b8382 293bool CCECBusDevice::TransmitCECVersion(const cec_logical_address destination)
62f5527d 294{
004b8382
LOK
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;
62f5527d
LOK
306}
307
004b8382 308cec_menu_language &CCECBusDevice::GetMenuLanguage(const cec_logical_address initiator, bool bUpdate /* = false */)
93729720 309{
6bbfc3f7 310 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
97fc4ffb
LOK
311 bool bRequestUpdate(false);
312 {
f00ff009 313 CLockObject lock(m_mutex);
ddb6ac5b 314 bRequestUpdate = (bIsPresent &&
97fc4ffb
LOK
315 (bUpdate || !strcmp(m_menuLanguage.language, "???")));
316 }
317
318 if (bRequestUpdate)
ebb6ddb3 319 {
004b8382
LOK
320 CheckVendorIdRequested(initiator);
321 RequestMenuLanguage(initiator);
ebb6ddb3 322 }
5e5637c6 323
f00ff009 324 CLockObject lock(m_mutex);
f294b22f
LOK
325 return m_menuLanguage;
326}
327
004b8382
LOK
328void 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);
60c28d82 337 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): menu language set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, m_menuLanguage.language);
004b8382
LOK
338 }
339}
340
341void CCECBusDevice::SetMenuLanguage(const cec_menu_language &language)
342{
343 if (language.device == m_iLogicalAddress)
344 SetMenuLanguage(language.language);
345}
346
347bool CCECBusDevice::RequestMenuLanguage(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
f294b22f
LOK
348{
349 bool bReturn(false);
b64db02e 350
004b8382 351 if (!IsHandledByLibCEC() &&
4d738fe3 352 !IsUnsupportedFeature(CEC_OPCODE_GET_MENU_LANGUAGE))
93729720 353 {
1344fd1a 354 MarkBusy();
004b8382
LOK
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);
1344fd1a 357 MarkReady();
93729720 358 }
f294b22f 359 return bReturn;
93729720
LOK
360}
361
004b8382 362bool CCECBusDevice::TransmitSetMenuLanguage(const cec_logical_address destination)
3e61b350 363{
004b8382
LOK
364 bool bReturn(false);
365 cec_menu_language language;
366 {
367 CLockObject lock(m_mutex);
368 language = m_menuLanguage;
369 }
3e61b350 370
004b8382
LOK
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;
f8513317
LOK
393}
394
004b8382 395bool CCECBusDevice::TransmitOSDString(const cec_logical_address destination, cec_display_control duration, const char *strMessage)
e9de9629 396{
004b8382
LOK
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;
e9de9629
LOK
406}
407
c0152c09
LOK
408CStdString CCECBusDevice::GetCurrentOSDName(void)
409{
410 CLockObject lock(m_mutex);
411 return m_strDeviceName;
412}
413
004b8382 414CStdString CCECBusDevice::GetOSDName(const cec_logical_address initiator, bool bUpdate /* = false */)
ed21be2a 415{
6bbfc3f7 416 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
97fc4ffb
LOK
417 bool bRequestUpdate(false);
418 {
f00ff009 419 CLockObject lock(m_mutex);
ddb6ac5b 420 bRequestUpdate = bIsPresent &&
97fc4ffb 421 (bUpdate || m_strDeviceName.Equals(ToString(m_iLogicalAddress))) &&
ddb6ac5b 422 m_type != CEC_DEVICE_TYPE_TV;
97fc4ffb
LOK
423 }
424
425 if (bRequestUpdate)
ebb6ddb3 426 {
004b8382
LOK
427 CheckVendorIdRequested(initiator);
428 RequestOSDName(initiator);
ebb6ddb3 429 }
5e5637c6 430
f00ff009 431 CLockObject lock(m_mutex);
ed21be2a
LOK
432 return m_strDeviceName;
433}
434
004b8382
LOK
435void CCECBusDevice::SetOSDName(CStdString strName)
436{
437 CLockObject lock(m_mutex);
438 if (m_strDeviceName != strName)
439 {
60c28d82 440 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): osd name set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, strName.c_str());
004b8382
LOK
441 m_strDeviceName = strName;
442 }
443}
444
445bool CCECBusDevice::RequestOSDName(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
ed21be2a
LOK
446{
447 bool bReturn(false);
b64db02e 448
004b8382 449 if (!IsHandledByLibCEC() &&
4d738fe3 450 !IsUnsupportedFeature(CEC_OPCODE_GIVE_OSD_NAME))
ed21be2a 451 {
1344fd1a 452 MarkBusy();
004b8382
LOK
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);
1344fd1a 455 MarkReady();
ed21be2a
LOK
456 }
457 return bReturn;
458}
459
004b8382
LOK
460bool 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
475bool CCECBusDevice::HasValidPhysicalAddress(void)
476{
477 CLockObject lock(m_mutex);
478 return CLibCEC::IsValidPhysicalAddress(m_iPhysicalAddress);
479}
480
481uint16_t CCECBusDevice::GetCurrentPhysicalAddress(void)
482{
483 CLockObject lock(m_mutex);
484 return m_iPhysicalAddress;
485}
486
487uint16_t CCECBusDevice::GetPhysicalAddress(const cec_logical_address initiator, bool bSuppressUpdate /* = false */)
16b1e052 488{
0680dab3 489 if (!bSuppressUpdate)
16b1e052 490 {
0680dab3
LOK
491 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
492 bool bRequestUpdate(false);
493 {
494 CLockObject lock(m_mutex);
b32ffd87 495 bRequestUpdate = bIsPresent && m_iPhysicalAddress == CEC_INVALID_PHYSICAL_ADDRESS;
0680dab3 496 }
16b1e052 497
0680dab3
LOK
498 if (bRequestUpdate)
499 {
004b8382
LOK
500 CheckVendorIdRequested(initiator);
501 if (!RequestPhysicalAddress(initiator))
502 LIB_CEC->AddLog(CEC_LOG_ERROR, "failed to request the physical address");
0680dab3 503 }
ebb6ddb3 504 }
97fc4ffb 505
f00ff009 506 CLockObject lock(m_mutex);
16b1e052
LOK
507 return m_iPhysicalAddress;
508}
509
004b8382
LOK
510bool CCECBusDevice::SetPhysicalAddress(uint16_t iNewAddress)
511{
512 CLockObject lock(m_mutex);
513 if (iNewAddress > 0 && m_iPhysicalAddress != iNewAddress)
514 {
60c28d82 515 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): physical address changed from %04x to %04x", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress, iNewAddress);
004b8382
LOK
516 m_iPhysicalAddress = iNewAddress;
517 }
518 return true;
519}
520
521bool CCECBusDevice::RequestPhysicalAddress(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
16b1e052
LOK
522{
523 bool bReturn(false);
b64db02e 524
004b8382 525 if (!IsHandledByLibCEC())
16b1e052 526 {
1344fd1a 527 MarkBusy();
004b8382
LOK
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);
1344fd1a 530 MarkReady();
16b1e052
LOK
531 }
532 return bReturn;
533}
534
004b8382
LOK
535bool 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
555cec_power_status CCECBusDevice::GetCurrentPowerStatus(void)
556{
557 CLockObject lock(m_mutex);
558 return m_powerStatus;
559}
560
561cec_power_status CCECBusDevice::GetPowerStatus(const cec_logical_address initiator, bool bUpdate /* = false */)
e9de9629 562{
6bbfc3f7 563 bool bIsPresent(GetStatus() == CEC_DEVICE_STATUS_PRESENT);
97fc4ffb
LOK
564 bool bRequestUpdate(false);
565 {
f00ff009 566 CLockObject lock(m_mutex);
ddb6ac5b 567 bRequestUpdate = (bIsPresent &&
c8f0eef0 568 (bUpdate || m_powerStatus == CEC_POWER_STATUS_UNKNOWN ||
2efa39b7
LOK
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));
97fc4ffb
LOK
572 }
573
574 if (bRequestUpdate)
ebb6ddb3 575 {
004b8382
LOK
576 CheckVendorIdRequested(initiator);
577 RequestPowerStatus(initiator);
ebb6ddb3 578 }
5e5637c6 579
f00ff009 580 CLockObject lock(m_mutex);
f294b22f
LOK
581 return m_powerStatus;
582}
583
004b8382
LOK
584void CCECBusDevice::SetPowerStatus(const cec_power_status powerStatus)
585{
586 CLockObject lock(m_mutex);
587 if (m_powerStatus != powerStatus)
588 {
589 m_iLastPowerStateUpdate = GetTimeMs();
60c28d82 590 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): power status changed from '%s' to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_powerStatus), ToString(powerStatus));
004b8382
LOK
591 m_powerStatus = powerStatus;
592 }
593}
594
595bool CCECBusDevice::RequestPowerStatus(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
f294b22f
LOK
596{
597 bool bReturn(false);
b64db02e 598
004b8382 599 if (!IsHandledByLibCEC() &&
4d738fe3 600 !IsUnsupportedFeature(CEC_OPCODE_GIVE_DEVICE_POWER_STATUS))
93729720 601 {
1344fd1a 602 MarkBusy();
004b8382
LOK
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);
1344fd1a 605 MarkReady();
93729720 606 }
f294b22f
LOK
607 return bReturn;
608}
93729720 609
004b8382 610bool CCECBusDevice::TransmitPowerState(const cec_logical_address destination)
f294b22f 611{
004b8382 612 cec_power_status state;
97fc4ffb 613 {
f00ff009 614 CLockObject lock(m_mutex);
004b8382
LOK
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;
97fc4ffb
LOK
617 }
618
004b8382
LOK
619 MarkBusy();
620 bool bReturn = m_handler->TransmitPowerState(m_iLogicalAddress, destination, state);
621 MarkReady();
622 return bReturn;
623}
624
625cec_vendor_id CCECBusDevice::GetCurrentVendorId(void)
626{
627 CLockObject lock(m_mutex);
f294b22f 628 return m_vendor;
e9de9629
LOK
629}
630
004b8382
LOK
631cec_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
648const char *CCECBusDevice::GetVendorName(const cec_logical_address initiator, bool bUpdate /* = false */)
649{
650 return ToString(GetVendorId(initiator, bUpdate));
651}
652
653bool 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
669bool CCECBusDevice::RequestVendorId(const cec_logical_address initiator, bool bWaitForResponse /* = true */)
a3269a0a 670{
f294b22f 671 bool bReturn(false);
b64db02e 672
004b8382 673 if (!IsHandledByLibCEC() && initiator != CECDEVICE_UNKNOWN)
a3269a0a 674 {
1344fd1a 675 MarkBusy();
004b8382
LOK
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);
1344fd1a 678 MarkReady();
3e61b350 679
a75e3a5a
LOK
680 if (bWaitForResponse)
681 ReplaceHandler(true);
a3269a0a 682 }
f294b22f 683 return bReturn;
93729720
LOK
684}
685
004b8382 686bool CCECBusDevice::TransmitVendorID(const cec_logical_address destination, bool bSendAbort /* = true */)
93729720 687{
004b8382
LOK
688 bool bReturn(false);
689 uint64_t iVendorId;
690 {
691 CLockObject lock(m_mutex);
692 iVendorId = (uint64_t)m_vendor;
693 }
a3269a0a 694
004b8382
LOK
695 MarkBusy();
696 if (iVendorId == CEC_VENDOR_UNKNOWN)
9fd73dd4 697 {
004b8382 698 if (bSendAbort)
c6d7f0e1 699 {
004b8382
LOK
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;
c6d7f0e1 703 }
9fd73dd4 704 }
004b8382
LOK
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;
9fd73dd4
LOK
712}
713
a75e3a5a 714cec_bus_device_status CCECBusDevice::GetStatus(bool bForcePoll /* = false */, bool bSuppressPoll /* = false */)
f8ae3295 715{
ba427965
LOK
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;
a75e3a5a
LOK
722 bNeedsPoll = !bSuppressPoll &&
723 (bForcePoll || m_deviceStatus == CEC_DEVICE_STATUS_UNKNOWN);
ba427965
LOK
724 }
725
726 if (bNeedsPoll)
f8ae3295 727 {
9fd73dd4 728 bool bPollAcked(false);
7b62b76e 729 if (bNeedsPoll && NeedsPoll())
9fd73dd4 730 bPollAcked = m_processor->PollDevice(m_iLogicalAddress);
95a73fa7 731
ba427965
LOK
732 status = bPollAcked ? CEC_DEVICE_STATUS_PRESENT : CEC_DEVICE_STATUS_NOT_PRESENT;
733 SetDeviceStatus(status);
f8ae3295
LOK
734 }
735
ba427965 736 return status;
f8ae3295
LOK
737}
738
93fff5c1
LOK
739void CCECBusDevice::SetDeviceStatus(const cec_bus_device_status newStatus)
740{
93fff5c1 741 {
ee17ad58
LOK
742 CLockObject lock(m_mutex);
743 switch (newStatus)
744 {
ee17ad58
LOK
745 case CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC:
746 if (m_deviceStatus != newStatus)
f5aa7e4c 747 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'handled by libCEC'", GetLogicalAddressName(), m_iLogicalAddress);
a20d808d
LOK
748 SetPowerStatus (CEC_POWER_STATUS_ON);
749 SetVendorId (CEC_VENDOR_UNKNOWN);
750 SetMenuState (CEC_MENU_STATE_ACTIVATED);
751 SetCecVersion (CEC_VERSION_1_3A);
b32ffd87 752 SetStreamPath (CEC_INVALID_PHYSICAL_ADDRESS);
004b8382 753 MarkAsInactiveSource();
a20d808d
LOK
754 m_iLastActive = 0;
755 m_deviceStatus = newStatus;
ee17ad58
LOK
756 break;
757 case CEC_DEVICE_STATUS_PRESENT:
758 if (m_deviceStatus != newStatus)
f5aa7e4c 759 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'present'", GetLogicalAddressName(), m_iLogicalAddress);
ee17ad58
LOK
760 m_deviceStatus = newStatus;
761 break;
762 case CEC_DEVICE_STATUS_NOT_PRESENT:
763 if (m_deviceStatus != newStatus)
a20d808d 764 {
f5aa7e4c 765 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): device status changed into 'not present'", GetLogicalAddressName(), m_iLogicalAddress);
a20d808d
LOK
766 ResetDeviceStatus();
767 m_deviceStatus = newStatus;
768 }
ee17ad58 769 break;
f5aa7e4c
LOK
770 default:
771 ResetDeviceStatus();
772 break;
ee17ad58 773 }
93fff5c1
LOK
774 }
775}
776
004b8382 777void CCECBusDevice::ResetDeviceStatus(void)
93729720 778{
f00ff009 779 CLockObject lock(m_mutex);
004b8382
LOK
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();
f5aa7e4c 787
004b8382
LOK
788 m_iLastActive = 0;
789 m_bVendorIdRequested = false;
790 m_unsupportedFeatures.clear();
f5aa7e4c
LOK
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;
93729720
LOK
795}
796
004b8382 797bool CCECBusDevice::TransmitPoll(const cec_logical_address dest)
9dc04b07 798{
004b8382
LOK
799 bool bReturn(false);
800 cec_logical_address destination(dest);
801 if (destination == CECDEVICE_UNKNOWN)
802 destination = m_iLogicalAddress;
96274140 803
004b8382
LOK
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)
5f2068fe 815 {
004b8382
LOK
816 m_iLastActive = GetTimeMs();
817 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_PRESENT;
5f2068fe
LOK
818 }
819 else
004b8382
LOK
820 destDevice->m_deviceStatus = CEC_DEVICE_STATUS_NOT_PRESENT;
821
822 MarkReady();
823 return bReturn;
824}
825
826void CCECBusDevice::HandlePoll(const cec_logical_address destination)
827{
828 if (destination >= 0 && destination < CECDEVICE_BROADCAST)
5f2068fe 829 {
004b8382 830 CCECBusDevice *device = m_processor->GetDevice(destination);
0cb55c43 831 if (device)
004b8382 832 device->HandlePollFrom(m_iLogicalAddress);
9dc04b07
LOK
833 }
834}
835
004b8382 836void CCECBusDevice::HandlePollFrom(const cec_logical_address initiator)
e55f3f70 837{
004b8382
LOK
838 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< POLL: %s (%x) -> %s (%x)", ToString(initiator), initiator, ToString(m_iLogicalAddress), m_iLogicalAddress);
839 m_bAwaitingReceiveFailed = true;
e55f3f70
LOK
840}
841
004b8382 842bool CCECBusDevice::HandleReceiveFailed(void)
1344fd1a 843{
004b8382
LOK
844 bool bReturn = m_bAwaitingReceiveFailed;
845 m_bAwaitingReceiveFailed = false;
846 return bReturn;
1344fd1a
LOK
847}
848
004b8382 849cec_menu_state CCECBusDevice::GetMenuState(const cec_logical_address UNUSED(initiator))
1344fd1a 850{
004b8382
LOK
851 CLockObject lock(m_mutex);
852 return m_menuState;
1344fd1a
LOK
853}
854
004b8382 855void CCECBusDevice::SetMenuState(const cec_menu_state state)
e9de9629 856{
004b8382
LOK
857 CLockObject lock(m_mutex);
858 if (m_menuState != state)
94e9a2af 859 {
60c28d82 860 LIB_CEC->AddLog(CEC_LOG_DEBUG, "%s (%X): menu state set to '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(m_menuState));
004b8382
LOK
861 m_menuState = state;
862 }
863}
d211708b 864
004b8382
LOK
865bool 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 }
104125dc 873
004b8382
LOK
874 MarkBusy();
875 bool bReturn = m_handler->TransmitMenuState(m_iLogicalAddress, dest, menuState);
876 MarkReady();
877 return bReturn;
878}
94e9a2af 879
004b8382
LOK
880bool 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}
94e9a2af 889
004b8382
LOK
890bool CCECBusDevice::RequestActiveSource(bool bWaitForResponse /* = true */)
891{
892 bool bReturn(false);
e9de9629 893
004b8382 894 if (IsHandledByLibCEC())
104125dc 895 {
004b8382
LOK
896 MarkBusy();
897 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< requesting active source");
104125dc 898
004b8382
LOK
899 bReturn = m_handler->TransmitRequestActiveSource(m_iLogicalAddress, bWaitForResponse);
900 MarkReady();
104125dc 901 }
004b8382
LOK
902 return bReturn;
903}
104125dc 904
004b8382
LOK
905void 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);
104125dc 912
004b8382
LOK
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);
b64db02e
LOK
921}
922
004b8382 923void CCECBusDevice::MarkAsInactiveSource(void)
b64db02e 924{
b64db02e 925 {
f00ff009 926 CLockObject lock(m_mutex);
004b8382
LOK
927 if (m_bActiveSource)
928 LIB_CEC->AddLog(CEC_LOG_DEBUG, "marking %s (%X) as inactive source", GetLogicalAddressName(), m_iLogicalAddress);
929 m_bActiveSource = false;
b64db02e 930 }
e9de9629
LOK
931}
932
93729720 933bool CCECBusDevice::TransmitActiveSource(void)
0f23c85c 934{
8fa35473 935 bool bSendActiveSource(false);
0f23c85c 936
8747dd4f 937 {
f00ff009 938 CLockObject lock(m_mutex);
49c8f2e4 939 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
004b8382 940 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
8fa35473
LOK
941 else if (m_bActiveSource)
942 {
004b8382 943 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): active source (%4x)", GetLogicalAddressName(), m_iLogicalAddress, m_iPhysicalAddress);
8fa35473
LOK
944 bSendActiveSource = true;
945 }
946 else
004b8382 947 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not the active source", GetLogicalAddressName(), m_iLogicalAddress);
8747dd4f
LOK
948 }
949
b64db02e
LOK
950 if (bSendActiveSource)
951 {
1344fd1a 952 MarkBusy();
468a1414 953 m_handler->TransmitActiveSource(m_iLogicalAddress, m_iPhysicalAddress);
1344fd1a 954 MarkReady();
b64db02e
LOK
955 return true;
956 }
957
958 return false;
0f23c85c
LOK
959}
960
49c8f2e4
LOK
961bool CCECBusDevice::TransmitImageViewOn(void)
962{
49c8f2e4 963 {
9a2f12df
LOK
964 CLockObject lock(m_mutex);
965 if (m_powerStatus != CEC_POWER_STATUS_ON && m_powerStatus != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
966 {
004b8382 967 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< %s (%X) is not powered on", GetLogicalAddressName(), m_iLogicalAddress);
9a2f12df
LOK
968 return false;
969 }
49c8f2e4 970 }
9a2f12df
LOK
971
972 MarkBusy();
973 m_handler->TransmitImageViewOn(m_iLogicalAddress, CECDEVICE_TV);
974 MarkReady();
975 return true;
49c8f2e4
LOK
976}
977
ab27363d 978bool CCECBusDevice::TransmitInactiveSource(void)
93729720 979{
8fa35473
LOK
980 uint16_t iPhysicalAddress;
981 {
f00ff009 982 CLockObject lock(m_mutex);
004b8382 983 LIB_CEC->AddLog(CEC_LOG_NOTICE, "<< %s (%X) -> broadcast (F): inactive source", GetLogicalAddressName(), m_iLogicalAddress);
8fa35473
LOK
984 iPhysicalAddress = m_iPhysicalAddress;
985 }
93729720 986
1344fd1a
LOK
987 MarkBusy();
988 bool bReturn = m_handler->TransmitInactiveSource(m_iLogicalAddress, iPhysicalAddress);
989 MarkReady();
990 return bReturn;
93729720
LOK
991}
992
004b8382 993bool CCECBusDevice::TransmitPendingActiveSourceCommands(void)
0f23c85c 994{
1344fd1a 995 MarkBusy();
004b8382 996 bool bReturn = m_handler->TransmitPendingActiveSourceCommands();
1344fd1a
LOK
997 MarkReady();
998 return bReturn;
0f23c85c
LOK
999}
1000
004b8382 1001void CCECBusDevice::SetStreamPath(uint16_t iNewAddress, uint16_t iOldAddress /* = CEC_INVALID_PHYSICAL_ADDRESS */)
0f23c85c 1002{
004b8382
LOK
1003 CLockObject lock(m_mutex);
1004 if (iNewAddress != m_iStreamPath)
8fa35473 1005 {
60c28d82 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);
004b8382 1007 m_iStreamPath = iNewAddress;
8fa35473 1008 }
0f23c85c 1009
99aeafb9
LOK
1010 if (!LIB_CEC->IsValidPhysicalAddress(iNewAddress))
1011 return;
1012
004b8382
LOK
1013 CCECBusDevice *device = m_processor->GetDeviceByPhysicalAddress(iNewAddress);
1014 if (device)
4d738fe3 1015 {
004b8382
LOK
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();
4d738fe3 1018 }
004b8382 1019 else
8fa35473 1020 {
004b8382
LOK
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();
8fa35473 1025 }
0f23c85c
LOK
1026}
1027
004b8382 1028bool CCECBusDevice::PowerOn(const cec_logical_address initiator)
fbdea54c
MK
1029{
1030 bool bReturn(false);
004b8382 1031 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
fbdea54c
MK
1032
1033 MarkBusy();
004b8382
LOK
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)
fbdea54c 1037 {
004b8382
LOK
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);
fbdea54c 1042 bReturn = true;
004b8382 1043 }
fbdea54c
MK
1044 }
1045 else
1046 {
004b8382 1047 LIB_CEC->AddLog(CEC_LOG_NOTICE, "'%s' (%X) is already '%s'", GetLogicalAddressName(), m_iLogicalAddress, ToString(currentStatus));
fbdea54c 1048 }
004b8382 1049
fbdea54c
MK
1050 MarkReady();
1051 return bReturn;
1052}
1053
004b8382 1054bool CCECBusDevice::Standby(const cec_logical_address initiator)
57f45e6c 1055{
004b8382 1056 GetVendorId(initiator); // ensure that we got the vendor id, because the implementations vary per vendor
b750a5c3 1057
004b8382 1058 LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< putting '%s' (%X) in standby mode", GetLogicalAddressName(), m_iLogicalAddress);
1344fd1a 1059 MarkBusy();
004b8382 1060 bool bReturn = m_handler->TransmitStandby(initiator, m_iLogicalAddress);
1344fd1a 1061 MarkReady();
57f45e6c
LOK
1062 return bReturn;
1063}
93729720 1064
004b8382 1065bool CCECBusDevice::NeedsPoll(void)
93729720 1066{
004b8382
LOK
1067 bool bSendPoll(false);
1068 cec_logical_address pollAddress(CECDEVICE_UNKNOWN);
1069 switch (m_iLogicalAddress)
8fa35473 1070 {
004b8382
LOK
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;
8fa35473 1101 }
93729720 1102
004b8382
LOK
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;
93729720
LOK
1118}
1119
004b8382 1120void CCECBusDevice::CheckVendorIdRequested(const cec_logical_address initiator)
93729720 1121{
004b8382 1122 bool bRequestVendorId(false);
8fa35473 1123 {
f00ff009 1124 CLockObject lock(m_mutex);
004b8382
LOK
1125 bRequestVendorId = !m_bVendorIdRequested;
1126 m_bVendorIdRequested = true;
8fa35473
LOK
1127 }
1128
004b8382 1129 if (bRequestVendorId)
c4098482 1130 {
004b8382
LOK
1131 ReplaceHandler(false);
1132 GetVendorId(initiator);
c4098482 1133 }
93729720 1134}
004b8382 1135//@}
a33794d8 1136
004b8382 1137CCECAudioSystem *CCECBusDevice::AsAudioSystem(void)
a33794d8 1138{
004b8382 1139 return AsAudioSystem(this);
a33794d8
LOK
1140}
1141
004b8382 1142CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(void)
a33794d8 1143{
004b8382 1144 return AsPlaybackDevice(this);
a33794d8 1145}
4d738fe3 1146
004b8382 1147CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(void)
4d738fe3 1148{
004b8382 1149 return AsRecordingDevice(this);
4d738fe3
LOK
1150}
1151
004b8382 1152CCECTuner *CCECBusDevice::AsTuner(void)
4d738fe3 1153{
004b8382
LOK
1154 return AsTuner(this);
1155}
ad7e0696 1156
004b8382
LOK
1157CCECTV *CCECBusDevice::AsTV(void)
1158{
1159 return AsTV(this);
1160}
b499cf16 1161
004b8382
LOK
1162CCECAudioSystem *CCECBusDevice::AsAudioSystem(CCECBusDevice *device)
1163{
1164 if (device && device->GetType() == CEC_DEVICE_TYPE_AUDIO_SYSTEM)
1165 return static_cast<CCECAudioSystem *>(device);
1166 return NULL;
4d738fe3 1167}
b64db02e 1168
004b8382 1169CCECPlaybackDevice *CCECBusDevice::AsPlaybackDevice(CCECBusDevice *device)
b64db02e 1170{
004b8382
LOK
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;
b64db02e
LOK
1176}
1177
004b8382 1178CCECRecordingDevice *CCECBusDevice::AsRecordingDevice(CCECBusDevice *device)
a75e3a5a 1179{
004b8382
LOK
1180 if (device && device->GetType() == CEC_DEVICE_TYPE_RECORDING_DEVICE)
1181 return static_cast<CCECRecordingDevice *>(device);
1182 return NULL;
a75e3a5a
LOK
1183}
1184
004b8382 1185CCECTuner *CCECBusDevice::AsTuner(CCECBusDevice *device)
0cfdeb5a 1186{
004b8382
LOK
1187 if (device && device->GetType() == CEC_DEVICE_TYPE_TUNER)
1188 return static_cast<CCECTuner *>(device);
1189 return NULL;
0cfdeb5a
LOK
1190}
1191
004b8382 1192CCECTV *CCECBusDevice::AsTV(CCECBusDevice *device)
0cfdeb5a 1193{
004b8382
LOK
1194 if (device && device->GetType() == CEC_DEVICE_TYPE_TV)
1195 return static_cast<CCECTV *>(device);
1196 return NULL;
0cfdeb5a
LOK
1197}
1198
004b8382 1199void CCECBusDevice::MarkBusy(void)
ebb6ddb3 1200{
004b8382
LOK
1201 CLockObject handlerLock(m_handlerMutex);
1202 ++m_iHandlerUseCount;
1203}
ebb6ddb3 1204
004b8382
LOK
1205void CCECBusDevice::MarkReady(void)
1206{
1207 CLockObject handlerLock(m_handlerMutex);
1208 if (m_iHandlerUseCount > 0)
1209 --m_iHandlerUseCount;
1210}
1211
1212bool CCECBusDevice::TryLogicalAddress(void)
1213{
1214 LIB_CEC->AddLog(CEC_LOG_DEBUG, "trying logical address '%s'", GetLogicalAddressName());
1215
1216 if (!TransmitPoll(m_iLogicalAddress))
ebb6ddb3 1217 {
004b8382
LOK
1218 LIB_CEC->AddLog(CEC_LOG_NOTICE, "using logical address '%s'", GetLogicalAddressName());
1219 SetDeviceStatus(CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC);
1220
1221 return true;
ebb6ddb3 1222 }
004b8382
LOK
1223
1224 LIB_CEC->AddLog(CEC_LOG_DEBUG, "logical address '%s' already taken", GetLogicalAddressName());
1225 SetDeviceStatus(CEC_DEVICE_STATUS_PRESENT);
1226 return false;
ebb6ddb3
LOK
1227}
1228
004b8382 1229CCECClient *CCECBusDevice::GetClient(void)
b78b4e33 1230{
004b8382 1231 return m_processor->GetClient(m_iLogicalAddress);
b78b4e33 1232}