#define LIB_CEC m_busDevice->GetProcessor()->GetLib()
#define ToString(p) CCECTypeUtils::ToString(p)
+#define REQUEST_POWER_STATUS_TIMEOUT 5000
CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice,
int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */,
m_bHandlerInited(false),
m_bOPTSendDeckStatusUpdateOnActiveSource(false),
m_vendorId(CEC_VENDOR_UNKNOWN),
- m_iActiveSourcePending(iActiveSourcePending)
+ m_iActiveSourcePending(iActiveSourcePending),
+ m_iPowerStatusRequested(0)
{
}
CCECClient *client = device->GetClient();
if (client)
- client->AddKey();
-
- if (command.parameters[0] <= CEC_USER_CONTROL_CODE_MAX)
client->SetCurrentButton((cec_user_control_code) command.parameters[0]);
if (command.parameters[0] == CEC_USER_CONTROL_CODE_POWER ||
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON);
- return Transmit(command, false, false);
+ if (Transmit(command, false, false))
+ {
+ CCECBusDevice* dest = m_processor->GetDevice(iDestination);
+ if (dest && dest->GetCurrentPowerStatus() != CEC_POWER_STATUS_ON)
+ dest->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON);
+ return true;
+ }
+ return false;
}
bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination)
bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */)
{
+ if (iDestination == CECDEVICE_TV)
+ {
+ int64_t now(GetTimeMs());
+ if (now - m_iPowerStatusRequested < REQUEST_POWER_STATUS_TIMEOUT)
+ return true;
+ m_iPowerStatusRequested = now;
+ }
+
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "<< requesting power status of '%s' (%X)", m_busDevice->GetLogicalAddressName(), iDestination);
+
cec_command command;
cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS);
return bReturn;
}
+ // check whether the destination is not marked as not present or handled by libCEC
+ if (command.destination != CECDEVICE_BROADCAST && command.opcode_set)
+ {
+ CCECBusDevice* destinationDevice = m_processor->GetDevice(command.destination);
+ cec_bus_device_status status = destinationDevice ? destinationDevice->GetStatus() : CEC_DEVICE_STATUS_NOT_PRESENT;
+ if (status == CEC_DEVICE_STATUS_NOT_PRESENT)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "not sending command '%s': destination device '%s' marked as not present", ToString(command.opcode),ToString(command.destination));
+ return bReturn;
+ }
+ else if (status == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)
+ {
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "not sending command '%s': destination device '%s' marked as handled by libCEC", ToString(command.opcode),ToString(command.destination));
+ return bReturn;
+ }
+ }
+
{
uint8_t iTries(0), iMaxTries(!command.opcode_set ? 1 : m_iTransmitRetries + 1);
while (!bReturn && ++iTries <= iMaxTries && !m_busDevice->IsUnsupportedFeature(command.opcode))
{
if ((bReturn = m_processor->Transmit(command, bIsReply)) == true)
{
+#ifdef CEC_DEBUGGING
LIB_CEC->AddLog(CEC_LOG_DEBUG, "command transmitted");
+#endif
if (bExpectResponse)
{
bReturn = m_busDevice->WaitForOpcode(expectedResponse);
if (m_iActiveSourcePending == 0 || GetTimeMs() < m_iActiveSourcePending)
return false;
+#ifdef CEC_DEBUGGING
LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command");
+#endif
}
-
- // clear previous pending active source command
- m_iActiveSourcePending = 0;
}
// update the power state and menu state
- m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON);
- m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED); // TODO: LG
+ if (!bTransmitDelayedCommandsOnly)
+ {
+ m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON);
+ m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED);
+ }
+
+ // vendor specific hook
+ VendorPreActivateSourceHook();
// power on the TV
- bool bActiveSourceFailed = !m_busDevice->TransmitImageViewOn();
+ CCECBusDevice* tv = m_processor->GetDevice(CECDEVICE_TV);
+ bool bTvPresent = (tv && tv->GetStatus() == CEC_DEVICE_STATUS_PRESENT);
+ bool bActiveSourceFailed(false);
+ if (bTvPresent)
+ {
+ if (tv->GetCurrentPowerStatus() != CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON)
+ bActiveSourceFailed = !m_busDevice->TransmitImageViewOn();
+ }
+ else
+ LIB_CEC->AddLog(CEC_LOG_DEBUG, "TV not present, not sending 'image view on'");
// check if we're allowed to switch sources
bool bSourceSwitchAllowed = SourceSwitchAllowed();
// switch sources (if allowed)
if (!bActiveSourceFailed && bSourceSwitchAllowed)
{
- bActiveSourceFailed = !m_busDevice->TransmitActiveSource(false) ||
- !m_busDevice->TransmitMenuState(CECDEVICE_TV, false);
+ bActiveSourceFailed = !m_busDevice->TransmitActiveSource(false);
+ if (bTvPresent && !bActiveSourceFailed)
+ bActiveSourceFailed = !m_busDevice->TransmitMenuState(CECDEVICE_TV, false);
// update the deck status for playback devices
- if (!bActiveSourceFailed)
+ if (bTvPresent && !bActiveSourceFailed)
{
CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice();
if (playbackDevice && SendDeckStatusUpdateOnActiveSource())
if (bActiveSourceFailed || !bSourceSwitchAllowed)
{
LIB_CEC->AddLog(CEC_LOG_DEBUG, "failed to make '%s' the active source. will retry later", m_busDevice->GetLogicalAddressName());
+ int64_t now(GetTimeMs());
CLockObject lock(m_mutex);
- m_iActiveSourcePending = GetTimeMs() + (int64_t)CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS;
+ if (m_iActiveSourcePending == 0 || m_iActiveSourcePending < now)
+ m_iActiveSourcePending = now + (int64_t)CEC_ACTIVE_SOURCE_SWITCH_RETRY_TIME_MS;
return false;
}
+ else
+ {
+ CLockObject lock(m_mutex);
+ // clear previous pending active source command
+ m_iActiveSourcePending = 0;
+ }
// mark the handler as initialised
CLockObject lock(m_mutex);