X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2FCECProcessor.cpp;h=707b8eb2d6e767a13c527d62b4d23ac21fa803ea;hb=9890892dd4d8164acaf84e0ef00cb26618207c5d;hp=b4445f42f921881edb6361d57f45a7498c62136f;hpb=9768d06119e3f2f835e0814624485ec631e31e62;p=deb_libcec.git diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index b4445f4..707b8eb 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -63,13 +63,17 @@ CCECProcessor::CCECProcessor(CLibCEC *libcec) : m_iStandardLineTimeout(3), m_iRetryLineTimeout(3), m_iLastTransmission(0), - m_bMonitor(true) + m_bMonitor(true), + m_addrAllocator(NULL), + m_bStallCommunication(false) { m_busDevices = new CCECDeviceMap(this); } CCECProcessor::~CCECProcessor(void) { + m_bStallCommunication = false; + DELETE_AND_NULL(m_addrAllocator); Close(); DELETE_AND_NULL(m_busDevices); } @@ -100,6 +104,8 @@ void CCECProcessor::Close(void) SetCECInitialised(false); // stop the processor + StopThread(-1); + m_inBuffer.Broadcast(); StopThread(); // close the connection @@ -218,7 +224,7 @@ void *CCECProcessor::Process(void) if (m_inBuffer.Pop(command, CEC_PROCESSOR_SIGNAL_WAIT_TIME)) ProcessCommand(command); - if (CECInitialised()) + if (CECInitialised() && !IsStopped()) { // check clients for keypress timeouts m_libcec->CheckKeypressTimeout(); @@ -254,6 +260,12 @@ bool CCECProcessor::ActivateSource(uint16_t iStreamPath) return bReturn; } +void CCECProcessor::SetActiveSource(bool bSetTo, bool bClientUnregistered) +{ + if (m_communication) + m_communication->SetActiveSource(bSetTo, bClientUnregistered); +} + void CCECProcessor::SetStandardLineTimeout(uint8_t iTimeout) { CLockObject lock(m_mutex); @@ -309,11 +321,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, false); + return primary->TransmitPoll(iAddress, true); CCECBusDevice *device = m_busDevices->At(CECDEVICE_UNREGISTERED); if (device) - return device->TransmitPoll(iAddress, false); + return device->TransmitPoll(iAddress, true); return false; } @@ -410,6 +422,9 @@ bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply) } } + // wait until we finished allocating a new LA if it got lost + while (m_bStallCommunication) Sleep(5); + { CLockObject lock(m_mutex); m_iLastTransmission = GetTimeMs(); @@ -430,7 +445,9 @@ bool CCECProcessor::Transmit(const cec_command &data, bool bIsReply) iLineTimeout = m_iRetryLineTimeout; } - return adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED; + return bIsReply ? + adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED || adapterState == ADAPTER_MESSAGE_STATE_SENT || adapterState == ADAPTER_MESSAGE_STATE_WAITING_TO_BE_SENT : + adapterState == ADAPTER_MESSAGE_STATE_SENT_ACKED; } void CCECProcessor::TransmitAbort(cec_logical_address source, cec_logical_address destination, cec_opcode opcode, cec_abort_reason reason /* = CEC_ABORT_REASON_UNRECOGNIZED_OPCODE */) @@ -642,6 +659,62 @@ CCECTuner *CCECProcessor::GetTuner(cec_logical_address address) const return CCECBusDevice::AsTuner(m_busDevices->At(address)); } +bool CCECProcessor::AllocateLogicalAddresses(CCECClient* client) +{ + libcec_configuration &configuration = *client->GetConfiguration(); + + // mark as unregistered + client->SetRegistered(false); + + // unregister this client from the old addresses + CECDEVICEVEC devices; + m_busDevices->GetByLogicalAddresses(devices, configuration.logicalAddresses); + for (CECDEVICEVEC::const_iterator it = devices.begin(); it != devices.end(); it++) + { + // remove client entry + CLockObject lock(m_mutex); + m_clients.erase((*it)->GetLogicalAddress()); + } + + // find logical addresses for this client + if (!client->AllocateLogicalAddresses()) + { + m_libcec->AddLog(CEC_LOG_ERROR, "failed to find a free logical address for the client"); + return false; + } + + // register this client on the new addresses + devices.clear(); + 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()); + m_clients.insert(make_pair((*it)->GetLogicalAddress(), client)); + } + + // set the new ackmask + SetLogicalAddresses(GetLogicalAddresses()); + + // resume outgoing communication + m_bStallCommunication = false; + + return true; +} + +uint16_t CCECProcessor::GetPhysicalAddressFromEeprom(void) +{ + libcec_configuration config; config.Clear(); + if (m_communication) + m_communication->GetConfiguration(config); + return config.iPhysicalAddress; +} + bool CCECProcessor::RegisterClient(CCECClient *client) { if (!client) @@ -649,7 +722,13 @@ bool CCECProcessor::RegisterClient(CCECClient *client) libcec_configuration &configuration = *client->GetConfiguration(); - if (configuration.clientVersion >= CEC_CLIENT_VERSION_1_6_3 && configuration.bMonitorOnly == 1) + if (configuration.clientVersion < CEC_CLIENT_VERSION_2_0_0) + { + m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: client version %s is no longer supported", ToString((cec_client_version)configuration.clientVersion)); + return false; + } + + if (configuration.bMonitorOnly == 1) return true; if (!CECInitialised()) @@ -664,14 +743,24 @@ bool CCECProcessor::RegisterClient(CCECClient *client) // ensure that controlled mode is enabled m_communication->SetControlledMode(true); + m_bMonitor = false; + + // source logical address for requests + cec_logical_address sourceAddress(CECDEVICE_UNREGISTERED); + if (!m_communication->SupportsSourceLogicalAddress(CECDEVICE_UNREGISTERED)) + { + if (m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE)) + sourceAddress = CECDEVICE_FREEUSE; + else + { + m_libcec->AddLog(CEC_LOG_ERROR, "failed to register a new CEC client: both unregistered and free use are not supported by the device"); + return false; + } + } // ensure that we know the vendor id of the TV CCECBusDevice *tv = GetTV(); - cec_vendor_id tvVendor = CEC_VENDOR_UNKNOWN; - if (m_communication->SupportsSourceLogicalAddress(CECDEVICE_UNREGISTERED)) - tvVendor = tv->GetVendorId(CECDEVICE_UNREGISTERED); - else if (m_communication->SupportsSourceLogicalAddress(CECDEVICE_FREEUSE)) - tvVendor = tv->GetVendorId(CECDEVICE_FREEUSE); + cec_vendor_id tvVendor(tv->GetVendorId(sourceAddress)); // wait until the handler is replaced, to avoid double registrations if (tvVendor != CEC_VENDOR_UNKNOWN && @@ -684,36 +773,20 @@ bool CCECProcessor::RegisterClient(CCECClient *client) // get the configuration from the client m_libcec->AddLog(CEC_LOG_NOTICE, "registering new CEC client - v%s", ToString((cec_client_version)configuration.clientVersion)); - // mark as uninitialised and unregistered - client->SetRegistered(false); - client->SetInitialised(false); - // get the current ackmask, so we can restore it if polling fails cec_logical_addresses previousMask = GetLogicalAddresses(); + // mark as uninitialised + client->SetInitialised(false); + // find logical addresses for this client - if (!client->AllocateLogicalAddresses()) + if (!AllocateLogicalAddresses(client)) { m_libcec->AddLog(CEC_LOG_ERROR, "failed to register the new CEC client - cannot allocate the requested device types"); SetLogicalAddresses(previousMask); return false; } - // register this client on the new addresses - CECDEVICEVEC devices; - 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()); - m_clients.insert(make_pair((*it)->GetLogicalAddress(), client)); - } - // get the settings from the rom if (configuration.bGetSettingsFromROM == 1) { @@ -737,10 +810,10 @@ bool CCECProcessor::RegisterClient(CCECClient *client) // mark the client as registered client->SetRegistered(true); - // set the new ack mask - bool bReturn = SetLogicalAddresses(GetLogicalAddresses()) && - // and initialise the client - client->OnRegister(); + sourceAddress = client->GetPrimaryLogicalAdddress(); + + // initialise the client + bool bReturn = client->OnRegister(); // log the new registration CStdString strLog; @@ -766,6 +839,12 @@ bool CCECProcessor::RegisterClient(CCECClient *client) GetTV()->MarkHandlerReady(); } + // report our OSD name to the TV, since some TVs don't request it + client->GetPrimaryDevice()->TransmitOSDName(CECDEVICE_TV, false); + + // request the power status of the TV + tv->RequestPowerStatus(sourceAddress, true); + return bReturn; } @@ -794,7 +873,7 @@ bool CCECProcessor::UnregisterClient(CCECClient *client) m_clients.erase(entry); // reset the device status - (*it)->ResetDeviceStatus(); + (*it)->ResetDeviceStatus(true); } } @@ -814,7 +893,7 @@ bool CCECProcessor::UnregisterClient(CCECClient *client) void CCECProcessor::UnregisterClients(void) { - m_libcec->AddLog(CEC_LOG_NOTICE, "unregistering all CEC clients"); + m_libcec->AddLog(CEC_LOG_DEBUG, "unregistering all CEC clients"); vector clients = m_libcec->GetClients(); for (vector::iterator client = clients.begin(); client != clients.end(); client++) @@ -887,10 +966,42 @@ void CCECProcessor::SwitchMonitoring(bool bSwitchTo) UnregisterClients(); } -void CCECProcessor::HandleLogicalAddressLost(cec_logical_address address) +void CCECProcessor::HandleLogicalAddressLost(cec_logical_address oldAddress) { - m_libcec->AddLog(CEC_LOG_NOTICE, "logical address %x was taken by another device, re-registering the client"); - CCECClient* client = GetClient(address); + // stall outgoing messages until we know our new LA + m_bStallCommunication = true; + + m_libcec->AddLog(CEC_LOG_NOTICE, "logical address %x was taken by another device, allocating a new address", oldAddress); + CCECClient* client = GetClient(oldAddress); + if (!client) + client = GetPrimaryClient(); if (client) - RegisterClient(client); + { + if (m_addrAllocator) + while (m_addrAllocator->IsRunning()) Sleep(5); + delete m_addrAllocator; + + m_addrAllocator = new CCECAllocateLogicalAddress(this, client); + m_addrAllocator->CreateThread(); + } +} + +uint16_t CCECProcessor::GetAdapterVendorId(void) const +{ + return m_communication ? m_communication->GetAdapterVendorId() : 0; +} + +uint16_t CCECProcessor::GetAdapterProductId(void) const +{ + return m_communication ? m_communication->GetAdapterProductId() : 0; +} + +CCECAllocateLogicalAddress::CCECAllocateLogicalAddress(CCECProcessor* processor, CCECClient* client) : + m_processor(processor), + m_client(client) { } + +void* CCECAllocateLogicalAddress::Process(void) +{ + m_processor->AllocateLogicalAddresses(m_client); + return NULL; }