X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2FCECProcessor.cpp;h=76c2465fb2dd74419822d63cf5991e4c4814af95;hb=3ead056c503f92e9c4352c41d51e613d4fa7b00e;hp=e90d5cb59038a62f8917bbb8cab61f52e24bc43e;hpb=0b8c7eab61e750b7dd6370e7d75e2c6a0cf0da12;p=deb_libcec.git diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index e90d5cb..76c2465 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -30,9 +30,10 @@ * http://www.pulse-eight.net/ */ +#include "env.h" #include "CECProcessor.h" -#include "adapter/USBCECAdapterCommunication.h" +#include "adapter/AdapterFactory.h" #include "devices/CECBusDevice.h" #include "devices/CECAudioSystem.h" #include "devices/CECPlaybackDevice.h" @@ -42,15 +43,18 @@ #include "implementations/CECCommandHandler.h" #include "LibCEC.h" #include "CECClient.h" +#include "CECTypeUtils.h" #include "platform/util/timeutils.h" +#include "platform/util/util.h" using namespace CEC; using namespace std; using namespace PLATFORM; #define CEC_PROCESSOR_SIGNAL_WAIT_TIME 1000 +#define ACTIVE_SOURCE_CHECK_INTERVAL 500 -#define ToString(x) m_libcec->ToString(x) +#define ToString(x) CCECTypeUtils::ToString(x) CCECProcessor::CCECProcessor(CLibCEC *libcec) : m_bInitialised(false), @@ -66,7 +70,7 @@ CCECProcessor::CCECProcessor(CLibCEC *libcec) : CCECProcessor::~CCECProcessor(void) { Close(); - delete m_busDevices; + DELETE_AND_NULL(m_busDevices); } bool CCECProcessor::Start(const char *strPort, uint16_t iBaudRate /* = CEC_SERIAL_DEFAULT_BAUDRATE */, uint32_t iTimeoutMs /* = CEC_DEFAULT_CONNECT_TIMEOUT */) @@ -98,21 +102,13 @@ void CCECProcessor::Close(void) StopThread(); // close the connection - if (m_communication) - { - delete m_communication; - m_communication = NULL; - } + DELETE_AND_NULL(m_communication); } void CCECProcessor::ResetMembers(void) { // close the connection - if (m_communication) - { - delete m_communication; - m_communication = NULL; - } + DELETE_AND_NULL(m_communication); // reset the other members to the initial state m_iStandardLineTimeout = 3; @@ -140,7 +136,7 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint } // create a new connection - m_communication = new CUSBCECAdapterCommunication(this, strPort, iBaudRate); + m_communication = CAdapterFactory(this->m_libcec).GetInstance(strPort, iBaudRate); // open a new connection unsigned iConnectTry(0); @@ -175,7 +171,7 @@ void CCECProcessor::SetCECInitialised(bool bSetTo /* = true */) UnregisterClients(); } -bool CCECProcessor::TryLogicalAddress(cec_logical_address address) +bool CCECProcessor::TryLogicalAddress(cec_logical_address address, cec_version libCECSpecVersion /* = CEC_VERSION_1_4 */) { // find the device CCECBusDevice *device = m_busDevices->At(address); @@ -186,8 +182,7 @@ bool CCECProcessor::TryLogicalAddress(cec_logical_address address) return false; // poll the LA if not - SetAckMask(0); - return device->TryLogicalAddress(); + return device->TryLogicalAddress(libCECSpecVersion); } return false; @@ -212,7 +207,8 @@ void *CCECProcessor::Process(void) { m_libcec->AddLog(CEC_LOG_DEBUG, "processor thread started"); - cec_command command; + cec_command command; command.Clear(); + CTimeout activeSourceCheck(ACTIVE_SOURCE_CHECK_INTERVAL); // as long as we're not being stopped and the connection is open while (!IsStopped() && m_communication->IsOpen()) @@ -228,6 +224,14 @@ void *CCECProcessor::Process(void) // check if we need to replace handlers ReplaceHandlers(); + + // check whether we need to activate a source, if it failed before + if (activeSourceCheck.TimeLeft() == 0) + { + if (CECInitialised()) + TransmitPendingActiveSourceCommands(); + activeSourceCheck.Init(ACTIVE_SOURCE_CHECK_INTERVAL); + } } } @@ -304,13 +308,11 @@ bool CCECProcessor::PollDevice(cec_logical_address iAddress) CCECBusDevice *primary = GetPrimaryDevice(); // poll the destination, with the primary as source if (primary) - return primary->TransmitPoll(iAddress); + return primary->TransmitPoll(iAddress, false); - // try to find the destination - CCECBusDevice *device = m_busDevices->At(iAddress); - // and poll the destination, with the same LA as source + CCECBusDevice *device = m_busDevices->At(CECDEVICE_UNREGISTERED); if (device) - return device->TransmitPoll(iAddress); + return device->TransmitPoll(iAddress, false); return false; } @@ -357,8 +359,9 @@ bool CCECProcessor::IsActiveSource(cec_logical_address iAddress) return device && device->IsActiveSource(); } -bool CCECProcessor::Transmit(const cec_command &data) +bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply) { + cec_command transmitData(data); uint8_t iMaxTries(0); bool bRetry(true); uint8_t iTries(0); @@ -369,10 +372,24 @@ bool CCECProcessor::Transmit(const cec_command &data) // reset the state of this message to 'unknown' cec_adapter_message_state adapterState = ADAPTER_MESSAGE_STATE_UNKNOWN; - LogOutput(data); + if (!m_communication->SupportsSourceLogicalAddress(transmitData.initiator)) + { + if (transmitData.initiator == CECDEVICE_UNREGISTERED && m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE)) + { + m_libcec->AddLog(CEC_LOG_DEBUG, "initiator '%s' is not supported by the CEC adapter. using '%s' instead", ToString(transmitData.initiator), ToString(CECDEVICE_FREEUSE)); + transmitData.initiator = CECDEVICE_FREEUSE; + } + else + { + m_libcec->AddLog(CEC_LOG_DEBUG, "initiator '%s' is not supported by the CEC adapter", ToString(transmitData.initiator)); + return false; + } + } + + LogOutput(transmitData); // find the initiator device - CCECBusDevice *initiator = m_busDevices->At(data.initiator); + CCECBusDevice *initiator = m_busDevices->At(transmitData.initiator); if (!initiator) { m_libcec->AddLog(CEC_LOG_WARNING, "invalid initiator"); @@ -380,10 +397,10 @@ bool CCECProcessor::Transmit(const cec_command &data) } // find the destination device, if it's not the broadcast address - if (data.destination != CECDEVICE_BROADCAST) + if (transmitData.destination != CECDEVICE_BROADCAST) { // check if the device is marked as handled by libCEC - CCECBusDevice *destination = m_busDevices->At(data.destination); + CCECBusDevice *destination = m_busDevices->At(transmitData.destination); if (destination && destination->IsHandledByLibCEC()) { // and reject the command if it's trying to send data to a device that is handled by libCEC @@ -397,16 +414,17 @@ bool CCECProcessor::Transmit(const cec_command &data) m_iLastTransmission = GetTimeMs(); // set the number of tries iMaxTries = initiator->GetHandler()->GetTransmitRetries() + 1; + initiator->MarkHandlerReady(); } // and try to send the command while (bRetry && ++iTries < iMaxTries) { - if (initiator->IsUnsupportedFeature(data.opcode)) + if (initiator->IsUnsupportedFeature(transmitData.opcode)) return false; adapterState = !IsStopped() && m_communication && m_communication->IsOpen() ? - m_communication->Write(data, bRetry, iLineTimeout) : + m_communication->Write(transmitData, bRetry, iLineTimeout, bIsReply) : ADAPTER_MESSAGE_STATE_ERROR; iLineTimeout = m_iRetryLineTimeout; } @@ -423,7 +441,7 @@ void CCECProcessor::TransmitAbort(cec_logical_address source, cec_logical_addres command.parameters.PushBack((uint8_t)opcode); command.parameters.PushBack((uint8_t)reason); - Transmit(command); + Transmit(command, true); } void CCECProcessor::ProcessCommand(const cec_command &command) @@ -463,9 +481,15 @@ uint16_t CCECProcessor::GetDetectedPhysicalAddress(void) const return m_communication ? m_communication->GetPhysicalAddress() : CEC_INVALID_PHYSICAL_ADDRESS; } -bool CCECProcessor::SetAckMask(uint16_t iMask) +bool CCECProcessor::ClearLogicalAddresses(void) { - return m_communication ? m_communication->SetAckMask(iMask) : false; + cec_logical_addresses addresses; addresses.Clear(); + return SetLogicalAddresses(addresses); +} + +bool CCECProcessor::SetLogicalAddresses(const cec_logical_addresses &addresses) +{ + return m_communication ? m_communication->SetLogicalAddresses(addresses) : false; } bool CCECProcessor::StandbyDevices(const cec_logical_address initiator, const CECDEVICEVEC &devices) @@ -502,7 +526,8 @@ bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */) // open a connection if no connection has been opened if (!m_communication && strPort) { - IAdapterCommunication *comm = new CUSBCECAdapterCommunication(this, strPort); + CAdapterFactory factory(this->m_libcec); + IAdapterCommunication *comm = factory.GetInstance(strPort); CTimeout timeout(CEC_DEFAULT_CONNECT_TIMEOUT); int iConnectTry(0); while (timeout.TimeLeft() > 0 && (bReturn = comm->Open(timeout.TimeLeft() / CEC_CONNECT_TRIES, true)) == false) @@ -514,7 +539,7 @@ bool CCECProcessor::StartBootloader(const char *strPort /* = NULL */) if (comm->IsOpen()) { bReturn = comm->StartBootloader(); - delete comm; + DELETE_AND_NULL(comm); } return bReturn; } @@ -546,12 +571,6 @@ bool CCECProcessor::HandleReceiveFailed(cec_logical_address initiator) return !device || !device->HandleReceiveFailed(); } -bool CCECProcessor::SetStreamPath(uint16_t iPhysicalAddress) -{ - // stream path changes are sent by the TV - return GetTV()->GetHandler()->TransmitSetStreamPath(iPhysicalAddress); -} - bool CCECProcessor::CanPersistConfiguration(void) { return m_communication ? m_communication->GetFirmwareVersion() >= 2 : false; @@ -559,7 +578,15 @@ bool CCECProcessor::CanPersistConfiguration(void) bool CCECProcessor::PersistConfiguration(const libcec_configuration &configuration) { - return m_communication ? m_communication->PersistConfiguration(configuration) : false; + libcec_configuration persistConfiguration = configuration; + if (!CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress)) + { + CCECBusDevice *device = GetPrimaryDevice(); + if (device) + persistConfiguration.iPhysicalAddress = device->GetCurrentPhysicalAddress(); + } + + return m_communication ? m_communication->PersistConfiguration(persistConfiguration) : false; } void CCECProcessor::RescanActiveDevices(void) @@ -615,7 +642,15 @@ CCECTuner *CCECProcessor::GetTuner(cec_logical_address address) const bool CCECProcessor::RegisterClient(CCECClient *client) { - if (!client || !CECInitialised()) + if (!client) + return false; + + libcec_configuration &configuration = *client->GetConfiguration(); + + if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_3 && configuration.bMonitorOnly == 1) + return true; + + if (!CECInitialised()) { m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: CEC processor is not initialised"); return false; @@ -625,8 +660,17 @@ bool CCECProcessor::RegisterClient(CCECClient *client) if (client->IsRegistered()) UnregisterClient(client); + // ensure that controlled mode is enabled + m_communication->SetControlledMode(true); + + // ensure that we know the vendor id of the TV + CCECBusDevice *tv = GetTV(); + if (m_communication->SupportsSourceLogicalAddress(CECDEVICE_UNREGISTERED)) + tv->GetVendorId(CECDEVICE_UNREGISTERED); + else if (m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE)) + tv->GetVendorId(CECDEVICE_FREEUSE); + // get the configuration from the client - libcec_configuration &configuration = *client->GetConfiguration(); m_libcec->AddLog(CEC_LOG_NOTICE, "registering new CEC client - v%s", ToString((cec_client_version)configuration.clientVersion)); // mark as uninitialised and unregistered @@ -634,13 +678,13 @@ bool CCECProcessor::RegisterClient(CCECClient *client) client->SetInitialised(false); // get the current ackmask, so we can restore it if polling fails - uint16_t iPreviousMask(m_communication->GetAckMask()); + cec_logical_addresses previousMask = GetLogicalAddresses(); // find logical addresses for this client if (!client->AllocateLogicalAddresses()) { m_libcec->AddLog(CEC_LOG_ERROR, "failed to register the new CEC client - cannot allocate the requested device types"); - SetAckMask(iPreviousMask); + SetLogicalAddresses(previousMask); return false; } @@ -649,6 +693,10 @@ bool CCECProcessor::RegisterClient(CCECClient *client) m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses); for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++) { + // set the physical address of the device at this LA + if (CLibCEC::IsValidPhysicalAddress(configuration.iPhysicalAddress)) + (*it)->SetPhysicalAddress(configuration.iPhysicalAddress); + // replace a previous client CLockObject lock(m_mutex); m_clients.erase((*it)->GetLogicalAddress()); @@ -658,7 +706,7 @@ bool CCECProcessor::RegisterClient(CCECClient *client) // get the settings from the rom if (configuration.bGetSettingsFromROM == 1) { - libcec_configuration config; + libcec_configuration config; config.Clear(); m_communication->GetConfiguration(config); CLockObject lock(m_mutex); @@ -678,7 +726,7 @@ bool CCECProcessor::RegisterClient(CCECClient *client) client->SetRegistered(true); // set the new ack mask - bool bReturn = SetAckMask(GetLogicalAddresses().AckMask()) && + bool bReturn = SetLogicalAddresses(GetLogicalAddresses()) && // and initialise the client client->OnRegister(); @@ -697,6 +745,15 @@ bool CCECProcessor::RegisterClient(CCECClient *client) client->Alert(CEC_ALERT_SERVICE_DEVICE, param); } + // ensure that the command handler for the TV is initialised + if (bReturn) + { + CCECCommandHandler *handler = GetTV()->GetHandler(); + if (handler) + handler->InitHandler(); + GetTV()->MarkHandlerReady(); + } + return bReturn; } @@ -730,7 +787,17 @@ bool CCECProcessor::UnregisterClient(CCECClient *client) } // set the new ackmask - return SetAckMask(GetLogicalAddresses().AckMask()); + cec_logical_addresses addresses = GetLogicalAddresses(); + if (SetLogicalAddresses(addresses)) + { + // no more clients left, disable controlled mode + if (addresses.IsEmpty()) + m_communication->SetControlledMode(false); + + return true; + } + + return false; } void CCECProcessor::UnregisterClients(void)