X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fimplementations%2FCECCommandHandler.cpp;h=da578b1173fa394d9c389dbe9cef427f5746945b;hb=b509ba1aecf87e94e3408429014937443ade5314;hp=395aacec69f4baa3dc80df13379cf128a9e78d1f;hpb=bf1b57e032c24e4175511c0d9263f366edeee914;p=deb_libcec.git diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index 395aace..da578b1 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -30,15 +30,17 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECCommandHandler.h" -#include "../devices/CECBusDevice.h" -#include "../devices/CECAudioSystem.h" -#include "../devices/CECPlaybackDevice.h" -#include "../CECClient.h" -#include "../CECProcessor.h" -#include "../LibCEC.h" -#include "../CECTypeUtils.h" -#include "../platform/util/util.h" + +#include "lib/devices/CECBusDevice.h" +#include "lib/devices/CECAudioSystem.h" +#include "lib/devices/CECPlaybackDevice.h" +#include "lib/CECClient.h" +#include "lib/CECProcessor.h" +#include "lib/LibCEC.h" +#include "lib/CECTypeUtils.h" +#include "lib/platform/util/util.h" using namespace CEC; using namespace std; @@ -47,23 +49,21 @@ using namespace PLATFORM; #define LIB_CEC m_busDevice->GetProcessor()->GetLib() #define ToString(p) CCECTypeUtils::ToString(p) -CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice) : +CCECCommandHandler::CCECCommandHandler(CCECBusDevice *busDevice, + int32_t iTransmitTimeout /* = CEC_DEFAULT_TRANSMIT_TIMEOUT */, + int32_t iTransmitWait /* = CEC_DEFAULT_TRANSMIT_WAIT */, + int8_t iTransmitRetries /* = CEC_DEFAULT_TRANSMIT_RETRIES */, + int64_t iActiveSourcePending /* = 0 */) : m_busDevice(busDevice), m_processor(m_busDevice->GetProcessor()), - m_iTransmitTimeout(CEC_DEFAULT_TRANSMIT_TIMEOUT), - m_iTransmitWait(CEC_DEFAULT_TRANSMIT_WAIT), - m_iTransmitRetries(CEC_DEFAULT_TRANSMIT_RETRIES), + m_iTransmitTimeout(iTransmitTimeout), + m_iTransmitWait(iTransmitWait), + m_iTransmitRetries(iTransmitRetries), m_bHandlerInited(false), m_bOPTSendDeckStatusUpdateOnActiveSource(false), m_vendorId(CEC_VENDOR_UNKNOWN), - m_waitForResponse(new CWaitForResponse), - m_bActiveSourcePending(false) -{ -} - -CCECCommandHandler::~CCECCommandHandler(void) + m_iActiveSourcePending(iActiveSourcePending) { - DELETE_AND_NULL(m_waitForResponse); } bool CCECCommandHandler::HandleCommand(const cec_command &command) @@ -73,9 +73,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) int iHandled(CEC_ABORT_REASON_UNRECOGNIZED_OPCODE); - CCECClient *client = m_busDevice->GetClient(); - if (client) - client->AddCommand(command); + LIB_CEC->AddCommand(command); switch(command.opcode) { @@ -197,7 +195,7 @@ bool CCECCommandHandler::HandleCommand(const cec_command &command) } if (iHandled == COMMAND_HANDLED) - m_waitForResponse->Received((command.opcode == CEC_OPCODE_FEATURE_ABORT && command.parameters.size > 0) ? (cec_opcode)command.parameters[0] : command.opcode); + m_busDevice->SignalOpcode((command.opcode == CEC_OPCODE_FEATURE_ABORT && command.parameters.size > 0) ? (cec_opcode)command.parameters[0] : command.opcode); else UnhandledCommand(command, (cec_abort_reason)iHandled); @@ -271,7 +269,7 @@ int CCECCommandHandler::HandleGetCecVersion(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitCECVersion(command.initiator)) + if (device && device->TransmitCECVersion(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -284,7 +282,7 @@ int CCECCommandHandler::HandleGiveAudioStatus(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination)); - if (device && device->TransmitAudioStatus(command.initiator)) + if (device && device->TransmitAudioStatus(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -297,7 +295,7 @@ int CCECCommandHandler::HandleGiveDeckStatus(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECPlaybackDevice *device = CCECBusDevice::AsPlaybackDevice(GetDevice(command.destination)); - if (device && device->TransmitDeckStatus(command.initiator)) + if (device && device->TransmitDeckStatus(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -310,7 +308,7 @@ int CCECCommandHandler::HandleGiveDevicePowerStatus(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitPowerState(command.initiator)) + if (device && device->TransmitPowerState(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -323,7 +321,7 @@ int CCECCommandHandler::HandleGiveDeviceVendorId(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitVendorID(command.initiator)) + if (device && device->TransmitVendorID(command.initiator, true, true)) return COMMAND_HANDLED; } @@ -335,7 +333,7 @@ int CCECCommandHandler::HandleGiveOSDName(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitOSDName(command.initiator)) + if (device && device->TransmitOSDName(command.initiator, true)) return COMMAND_HANDLED; } @@ -347,7 +345,7 @@ int CCECCommandHandler::HandleGivePhysicalAddress(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitPhysicalAddress()) + if (device && device->TransmitPhysicalAddress(true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -360,7 +358,7 @@ int CCECCommandHandler::HandleGiveMenuLanguage(const cec_command &command) if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECBusDevice *device = GetDevice(command.destination); - if (device && device->TransmitSetMenuLanguage(command.initiator)) + if (device && device->TransmitSetMenuLanguage(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -373,7 +371,7 @@ int CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &comma if (m_processor->CECInitialised() && m_processor->IsHandledByLibCEC(command.destination)) { CCECAudioSystem *device = CCECBusDevice::AsAudioSystem(GetDevice(command.destination)); - if (device && device->TransmitSystemAudioModeStatus(command.initiator)) + if (device && device->TransmitSystemAudioModeStatus(command.initiator, true)) return COMMAND_HANDLED; return CEC_ABORT_REASON_INVALID_OPERAND; } @@ -383,7 +381,14 @@ int CCECCommandHandler::HandleGiveSystemAudioModeStatus(const cec_command &comma int CCECCommandHandler::HandleImageViewOn(const cec_command &command) { - m_processor->GetDevice(command.initiator)->MarkAsActiveSource(); + CCECBusDevice *device = GetDevice(command.destination); + if (device && (device->GetCurrentStatus() == CEC_DEVICE_STATUS_PRESENT || + device->GetCurrentStatus() == CEC_DEVICE_STATUS_HANDLED_BY_LIBCEC)) + { + if (device->GetCurrentPowerStatus() == CEC_POWER_STATUS_STANDBY || + device->GetCurrentPowerStatus() == CEC_POWER_STATUS_IN_TRANSITION_ON_TO_STANDBY) + device->SetPowerStatus(CEC_POWER_STATUS_IN_TRANSITION_STANDBY_TO_ON); + } return COMMAND_HANDLED; } @@ -408,7 +413,7 @@ int CCECCommandHandler::HandleMenuRequest(const cec_command &command) device->SetMenuState(CEC_MENU_STATE_DEACTIVATED); } } - if (device->TransmitMenuState(command.initiator)) + if (device->TransmitMenuState(command.initiator, true)) return COMMAND_HANDLED; } return CEC_ABORT_REASON_INVALID_OPERAND; @@ -471,7 +476,7 @@ int CCECCommandHandler::HandleRequestActiveSource(const cec_command &command) vector devices; for (size_t iDevicePtr = 0; iDevicePtr < GetMyDevices(devices); iDevicePtr++) - devices[iDevicePtr]->TransmitActiveSource(); + devices[iDevicePtr]->TransmitActiveSource(true); } return COMMAND_HANDLED; @@ -593,13 +598,13 @@ int CCECCommandHandler::HandleSystemAudioModeRequest(const cec_command &command) CCECBusDevice *newActiveDevice = GetDeviceByPhysicalAddress(iNewAddress); if (newActiveDevice) newActiveDevice->MarkAsActiveSource(); - if (device->TransmitSetSystemAudioMode(command.initiator)) + if (device->TransmitSetSystemAudioMode(command.initiator, true)) return COMMAND_HANDLED; } else { device->SetSystemAudioModeStatus(CEC_SYSTEM_AUDIO_STATUS_OFF); - if (device->TransmitSetSystemAudioMode(command.initiator)) + if (device->TransmitSetSystemAudioMode(command.initiator, true)) return COMMAND_HANDLED; } } @@ -668,9 +673,6 @@ int CCECCommandHandler::HandleUserControlPressed(const cec_command &command) 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 || @@ -813,7 +815,7 @@ bool CCECCommandHandler::TransmitImageViewOn(const cec_logical_address iInitiato cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_IMAGE_VIEW_ON); - return Transmit(command); + return Transmit(command, false, false); } bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, const cec_logical_address iDestination) @@ -821,7 +823,7 @@ bool CCECCommandHandler::TransmitStandby(const cec_logical_address iInitiator, c cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_STANDBY); - return Transmit(command); + return Transmit(command, false, false); } bool CCECCommandHandler::TransmitRequestActiveSource(const cec_logical_address iInitiator, bool bWaitForResponse /* = true */) @@ -829,7 +831,7 @@ bool CCECCommandHandler::TransmitRequestActiveSource(const cec_logical_address i cec_command command; cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_REQUEST_ACTIVE_SOURCE); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -837,7 +839,7 @@ bool CCECCommandHandler::TransmitRequestCecVersion(const cec_logical_address iIn cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_CEC_VERSION); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -845,7 +847,7 @@ bool CCECCommandHandler::TransmitRequestMenuLanguage(const cec_logical_address i cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GET_MENU_LANGUAGE); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -853,7 +855,7 @@ bool CCECCommandHandler::TransmitRequestOSDName(const cec_logical_address iIniti cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_OSD_NAME); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -861,7 +863,7 @@ bool CCECCommandHandler::TransmitRequestPhysicalAddress(const cec_logical_addres cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_PHYSICAL_ADDRESS); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -869,7 +871,7 @@ bool CCECCommandHandler::TransmitRequestPowerStatus(const cec_logical_address iI cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_POWER_STATUS); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWaitForResponse /* = true */) @@ -877,26 +879,26 @@ bool CCECCommandHandler::TransmitRequestVendorId(const cec_logical_address iInit cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_GIVE_DEVICE_VENDOR_ID); - return Transmit(command, !bWaitForResponse); + return Transmit(command, !bWaitForResponse, false); } -bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress) +bool CCECCommandHandler::TransmitActiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_ACTIVE_SOURCE); command.parameters.PushBack((uint8_t) ((iPhysicalAddress >> 8) & 0xFF)); command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF)); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion) +bool CCECCommandHandler::TransmitCECVersion(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_version cecVersion, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_CEC_VERSION); command.parameters.PushBack((uint8_t)cecVersion); - return Transmit(command); + return Transmit(command, false, bIsReply); } bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iInitiator, uint16_t iPhysicalAddress) @@ -906,29 +908,29 @@ bool CCECCommandHandler::TransmitInactiveSource(const cec_logical_address iIniti command.parameters.PushBack((iPhysicalAddress >> 8) & 0xFF); command.parameters.PushBack(iPhysicalAddress & 0xFF); - return Transmit(command); + return Transmit(command, false, false); } -bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState) +bool CCECCommandHandler::TransmitMenuState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_menu_state menuState, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_MENU_STATUS); command.parameters.PushBack((uint8_t)menuState); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, CStdString strDeviceName) +bool CCECCommandHandler::TransmitOSDName(const cec_logical_address iInitiator, const cec_logical_address iDestination, std::string strDeviceName, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_NAME); for (size_t iPtr = 0; iPtr < strDeviceName.length(); iPtr++) command.parameters.PushBack(strDeviceName.at(iPtr)); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage) +bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_display_control duration, const char *strMessage, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_OSD_STRING); @@ -940,10 +942,10 @@ bool CCECCommandHandler::TransmitOSDString(const cec_logical_address iInitiator, for (size_t iPtr = 0; iPtr < iLen; iPtr++) command.parameters.PushBack(strMessage[iPtr]); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type) +bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInitiator, uint16_t iPhysicalAddress, cec_device_type type, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_REPORT_PHYSICAL_ADDRESS); @@ -951,10 +953,10 @@ bool CCECCommandHandler::TransmitPhysicalAddress(const cec_logical_address iInit command.parameters.PushBack((uint8_t) (iPhysicalAddress & 0xFF)); command.parameters.PushBack((uint8_t) (type)); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[3]) +bool CCECCommandHandler::TransmitSetMenuLanguage(const cec_logical_address iInitiator, const char lang[3], bool bIsReply) { cec_command command; command.Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_SET_MENU_LANGUAGE); @@ -962,27 +964,27 @@ bool CCECCommandHandler::TransmitSetMenuLanguage(const cec_logical_address iInit command.parameters.PushBack((uint8_t) lang[1]); command.parameters.PushBack((uint8_t) lang[2]); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination) +bool CCECCommandHandler::TransmitPoll(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_NONE); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state) +bool CCECCommandHandler::TransmitPowerState(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_power_status state, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_POWER_STATUS); command.parameters.PushBack((uint8_t) state); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId) +bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, uint64_t iVendorId, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, CECDEVICE_BROADCAST, CEC_OPCODE_DEVICE_VENDOR_ID); @@ -991,53 +993,58 @@ bool CCECCommandHandler::TransmitVendorID(const cec_logical_address iInitiator, command.parameters.PushBack((uint8_t) (((uint64_t)iVendorId >> 8) & 0xFF)); command.parameters.PushBack((uint8_t) ((uint64_t)iVendorId & 0xFF)); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state) +bool CCECCommandHandler::TransmitAudioStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, uint8_t state, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_REPORT_AUDIO_STATUS); command.parameters.PushBack(state); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state) +bool CCECCommandHandler::TransmitSetSystemAudioMode(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SET_SYSTEM_AUDIO_MODE); command.parameters.PushBack((uint8_t)state); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitSetStreamPath(uint16_t iStreamPath) +bool CCECCommandHandler::TransmitSetStreamPath(uint16_t iStreamPath, bool bIsReply) { + if (m_busDevice->GetLogicalAddress() != CECDEVICE_TV) + { + LIB_CEC->AddLog(CEC_LOG_ERROR, "only the TV is allowed to send CEC_OPCODE_SET_STREAM_PATH"); + return false; + } cec_command command; cec_command::Format(command, m_busDevice->GetLogicalAddress(), CECDEVICE_BROADCAST, CEC_OPCODE_SET_STREAM_PATH); command.parameters.PushBack((uint8_t) ((iStreamPath >> 8) & 0xFF)); command.parameters.PushBack((uint8_t) (iStreamPath & 0xFF)); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state) +bool CCECCommandHandler::TransmitSystemAudioModeStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_system_audio_status state, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS); command.parameters.PushBack((uint8_t)state); - return Transmit(command); + return Transmit(command, false, bIsReply); } -bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state) +bool CCECCommandHandler::TransmitDeckStatus(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_deck_info state, bool bIsReply) { cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_DECK_STATUS); command.PushBack((uint8_t)state); - return Transmit(command); + return Transmit(command, false, bIsReply); } bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, const cec_logical_address iDestination, cec_user_control_code key, bool bWait /* = true */) @@ -1046,7 +1053,7 @@ bool CCECCommandHandler::TransmitKeypress(const cec_logical_address iInitiator, cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_PRESSED); command.parameters.PushBack((uint8_t)key); - return Transmit(command, !bWait); + return Transmit(command, !bWait, false); } bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator, const cec_logical_address iDestination, bool bWait /* = true */) @@ -1054,10 +1061,10 @@ bool CCECCommandHandler::TransmitKeyRelease(const cec_logical_address iInitiator cec_command command; cec_command::Format(command, iInitiator, iDestination, CEC_OPCODE_USER_CONTROL_RELEASE); - return Transmit(command, !bWait); + return Transmit(command, !bWait, false); } -bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* = false */) +bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait, bool bIsReply) { bool bReturn(false); cec_opcode expectedResponse(cec_command::GetResponseOpcode(command.opcode)); @@ -1070,16 +1077,35 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* = 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)) == true) + if ((bReturn = m_processor->Transmit(command, bIsReply)) == true) { +#ifdef CEC_DEBUGGING LIB_CEC->AddLog(CEC_LOG_DEBUG, "command transmitted"); +#endif if (bExpectResponse) { - bReturn = m_waitForResponse->Wait(expectedResponse); + bReturn = m_busDevice->WaitForOpcode(expectedResponse); LIB_CEC->AddLog(CEC_LOG_DEBUG, bReturn ? "expected response received (%X: %s)" : "expected response not received (%X: %s)", (int)expectedResponse, ToString(expectedResponse)); } } @@ -1089,50 +1115,92 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bSuppressWait /* = return bReturn; } -bool CCECCommandHandler::ActivateSource(void) +bool CCECCommandHandler::ActivateSource(bool bTransmitDelayedCommandsOnly /* = false */) { if (m_busDevice->IsActiveSource() && - m_busDevice->IsHandledByLibCEC()) + m_busDevice->IsHandledByLibCEC()) { { CLockObject lock(m_mutex); - m_bActiveSourcePending = false; + // check if we need to send a delayed source switch + if (bTransmitDelayedCommandsOnly) + { + if (m_iActiveSourcePending == 0 || GetTimeMs() < m_iActiveSourcePending) + return false; + + LIB_CEC->AddLog(CEC_LOG_DEBUG, "transmitting delayed activate source command"); + } } - m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON); - m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED); + // update the power state and menu state + if (!bTransmitDelayedCommandsOnly) + { + m_busDevice->SetPowerStatus(CEC_POWER_STATUS_ON); + m_busDevice->SetMenuState(CEC_MENU_STATE_ACTIVATED); + } + + // vendor specific hook + VendorPreActivateSourceHook(); + + // power on the TV + 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'"); - bool bActiveSourceFailed = !m_busDevice->TransmitImageViewOn() || - !m_busDevice->TransmitActiveSource() || - !m_busDevice->TransmitMenuState(CECDEVICE_TV); + // check if we're allowed to switch sources + bool bSourceSwitchAllowed = SourceSwitchAllowed(); + if (!bSourceSwitchAllowed) + LIB_CEC->AddLog(CEC_LOG_DEBUG, "source switch is currently not allowed by command handler"); - if (!bActiveSourceFailed) + // switch sources (if allowed) + if (!bActiveSourceFailed && bSourceSwitchAllowed) { - CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice(); - if (playbackDevice && SendDeckStatusUpdateOnActiveSource()) - bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV); + bActiveSourceFailed = !m_busDevice->TransmitActiveSource(false); + if (bTvPresent && !bActiveSourceFailed) + bActiveSourceFailed = !m_busDevice->TransmitMenuState(CECDEVICE_TV, false); + + // update the deck status for playback devices + if (bTvPresent && !bActiveSourceFailed) + { + CCECPlaybackDevice *playbackDevice = m_busDevice->AsPlaybackDevice(); + if (playbackDevice && SendDeckStatusUpdateOnActiveSource()) + bActiveSourceFailed = !playbackDevice->TransmitDeckStatus(CECDEVICE_TV, false); + } } - if (bActiveSourceFailed) + // retry later + 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_bActiveSourcePending = true; + 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); m_bHandlerInited = true; } return true; } -void CCECCommandHandler::SignalOpcode(cec_opcode opcode) -{ - m_waitForResponse->Received(opcode); -} - -bool CCECCommandHandler::ActiveSourcePending(void) +void CCECCommandHandler::ScheduleActivateSource(uint64_t iDelay) { CLockObject lock(m_mutex); - return m_bActiveSourcePending; + m_iActiveSourcePending = GetTimeMs() + iDelay; }