cec: give priority to messages from the TV. removed the global lock in CCECProcessor...
authorLars Op den Kamp <lars@opdenkamp.eu>
Wed, 28 Mar 2012 18:46:09 +0000 (20:46 +0200)
committerLars Op den Kamp <lars@opdenkamp.eu>
Wed, 28 Mar 2012 18:47:07 +0000 (20:47 +0200)
src/lib/CECProcessor.cpp
src/lib/CECProcessor.h
src/lib/implementations/CECCommandHandler.cpp

index 378b221910dff99e0430d21e7f711271386bb6cf..96b5c7349db3a7253250d172f0fc87970ed638c0 100644 (file)
@@ -456,23 +456,27 @@ void CCECProcessor::ReplaceHandlers(void)
 
 bool CCECProcessor::OnCommandReceived(const cec_command &command)
 {
-  ParseCommand(command);
-  return true;
+  return m_inBuffer.Push(command);
 }
 
 void *CCECProcessor::Process(void)
 {
   CLibCEC::AddLog(CEC_LOG_DEBUG, "processor thread started");
 
+  cec_command command;
+  command.Clear();
+
   while (!IsStopped() && m_communication->IsOpen())
   {
+    if (m_inBuffer.Pop(command, 500))
+      ParseCommand(command);
+
     if (IsInitialised())
     {
       ReplaceHandlers();
 
       m_controller->CheckKeypressTimeout();
     }
-    Sleep(5);
   }
 
   return NULL;
index 41f3fde8ed224d7ff93d9b2919d1c7bbf5feca33..ce32fea53d516794c4224304d8836a3784ced31b 100644 (file)
@@ -43,6 +43,58 @@ namespace CEC
   class IAdapterCommunication;
   class CCECBusDevice;
 
+  // a buffer that priotises the input from the TV.
+  // if we need more than this, we'll have to change it into a priority_queue
+  class CCECInputBuffer
+  {
+  public:
+    CCECInputBuffer(void) : m_bHasData(false) {}
+    virtual ~CCECInputBuffer(void)
+    {
+      m_condition.Broadcast();
+    }
+
+    bool Push(const cec_command &command)
+    {
+      bool bReturn(false);
+      PLATFORM::CLockObject lock(m_mutex);
+      if (command.initiator == CECDEVICE_TV)
+        bReturn = m_tvInBuffer.Push(command);
+      else
+        bReturn = m_inBuffer.Push(command);
+
+      m_bHasData |= bReturn;
+      if (bReturn)
+        m_condition.Signal();
+
+      return bReturn;
+    }
+
+    bool Pop(cec_command &command, uint16_t iTimeout = 10000)
+    {
+      bool bReturn(false);
+      PLATFORM::CLockObject lock(m_mutex);
+      if (m_tvInBuffer.IsEmpty() && m_inBuffer.IsEmpty() &&
+          !m_condition.Wait(m_mutex, m_bHasData, iTimeout))
+        return bReturn;
+
+      if (m_tvInBuffer.Pop(command))
+        bReturn = true;
+      else if (m_inBuffer.Pop(command))
+        bReturn = true;
+
+      m_bHasData = !m_tvInBuffer.IsEmpty() || !m_inBuffer.IsEmpty();
+      return bReturn;
+    }
+
+  private:
+    PLATFORM::CMutex                    m_mutex;
+    PLATFORM::CCondition<volatile bool> m_condition;
+    volatile bool                       m_bHasData;
+    PLATFORM::SyncedBuffer<cec_command> m_tvInBuffer;
+    PLATFORM::SyncedBuffer<cec_command> m_inBuffer;
+  };
+
   class CCECProcessor : public PLATFORM::CThread, public IAdapterCommunicationCallback
   {
     public:
@@ -145,7 +197,6 @@ namespace CEC
       virtual bool GetDeviceInformation(const char *strPort, libcec_configuration *config, uint32_t iTimeoutMs = 10000);
 
       CCECBusDevice *  m_busDevices[16];
-      PLATFORM::CMutex m_transmitMutex;
 
   private:
       bool OpenConnection(const char *strPort, uint16_t iBaudRate, uint32_t iTimeoutMs, bool bStartListening = true);
@@ -175,6 +226,7 @@ namespace CEC
       uint8_t                             m_iStandardLineTimeout;
       uint8_t                             m_iRetryLineTimeout;
       uint64_t                            m_iLastTransmission;
+      CCECInputBuffer                     m_inBuffer;
       libcec_configuration                m_configuration;
   };
 
index 6e1aaac68711b198168120c44ec310d905076eeb..0668ee793bd16e3e6c1b47c58b3f8b76df251302 100644 (file)
@@ -974,7 +974,6 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /*
 
   {
     uint8_t iTries(0), iMaxTries(command.opcode == CEC_OPCODE_NONE ? 1 : m_iTransmitRetries + 1);
-    CLockObject writeLock(m_processor->m_transmitMutex);
     while (!bReturn && ++iTries <= iMaxTries)
     {
       if ((bReturn = m_processor->Transmit(command)) == true)