]> git.vomp.tv Git - vompclient.git/commitdiff
Rewrite timers class using std::thread/mutex/cond/chrono
authorChris Tallon <chris@vomp.tv>
Thu, 20 Feb 2020 23:29:36 +0000 (23:29 +0000)
committerChris Tallon <chris@vomp.tv>
Thu, 20 Feb 2020 23:29:36 +0000 (23:29 +0000)
38 files changed:
CREDITS
audioplayer.cc
audioplayer.h
command.cc
main.cc
playermedia.cc
playermedia.h
timers.cc
timers.h
vchannelselect.cc
vchannelselect.h
vdr.cc
vepg.cc
vepg.h
vmedialist.h
vmediaview.cc
vmediaview.h
vmute.cc
vmute.h
vradiorec.cc
vradiorec.h
vsleeptimer.cc
vsleeptimer.h
vteletextview.cc
vteletextview.h
vtimeredit.cc
vtimerlist.cc
vtimerlist.h
vvideolivetv.cc
vvideolivetv.h
vvideomedia.cc
vvideomedia.h
vvideorec.cc
vvideorec.h
vvolume.cc
vvolume.h
vwelcome.cc
vwelcome.h

diff --git a/CREDITS b/CREDITS
index 9de0c9974e2ef8cf199f4e945c2fa32e9f70cb68..4fc847075e64a63114b22609e04385a823c94620 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -43,6 +43,7 @@ Marten Richter
   Reporting of many bugs
   Audio channel selection
   VDR 1.7 compatibility
+  Raspberry Pi port
 
 Andreas Vogel
   Media player
index e6001e708d8e1d0c897323e9367940fbe8d0f23f..9f3f9a3a0c9c18f9aaa96b08eeaa2888abc42520 100644 (file)
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-#include "audioplayer.h"
 #include "demuxeraudio.h"
-#include "timers.h"
 #include "video.h"
 #include "messagequeue.h"
 #include "i18n.h"
@@ -29,6 +26,8 @@
 #include "media.h"
 #include "mediaplayer.h"
 
+#include "audioplayer.h"
+
 //how often do we retry if there is no data in stream
 #define MAXTRY 50 
 
index 08af3d9db7724c06edbe95b8501ecade379b4ee2..f39df372e73be79f9da1314097262f55c1e8712d 100644 (file)
@@ -14,8 +14,7 @@
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
 #ifndef AUDIOPLAYER_H
@@ -36,7 +35,7 @@
 #include "messagequeue.h"
 #include "thread.h"
 #include "afeed.h"
-#include "timerreceiver.h"
+#include "timers.h"
 
 #ifdef WIN32
 #include "threadwin.h"
@@ -45,7 +44,6 @@
 #endif
 
 
-
 class Boxx;
 class DemuxerAudio;
 class MediaURI;
index e5c767be62cc7399d8ecd386c93135b3a11dabf6..b38569d88cc40dfda61d080ae2efa19a877f5be2 100644 (file)
@@ -41,7 +41,6 @@
 #include "colour.h"
 #include "osd.h"
 #include "i18n.h"
-#include "timerreceiver.h"
 #include "timers.h"
 #include "wol.h"
 #include "vconnect.h"
diff --git a/main.cc b/main.cc
index 924d9a7d3dde179b90091643ebba4344691fa9b0..b727db3be6b03ff16d9e45fd6540bff64267ed94 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -141,7 +141,7 @@ int main(int argc, char** argv)
   wol        = new Wol();
   sleeptimer = new Sleeptimer();
 
-  if (!logger || !inputMan || !led || !osd || !video || !audio || !boxstack || !command || !wol || !sleeptimer)
+  if (!logger || !timers || !inputMan || !led || !osd || !video || !audio || !boxstack || !command || !wol || !sleeptimer)
   {
     printf("Could not create objects. Memory problems?\n");
     shutdown(1);
index 692dd207b3e5b533625063d9052ea7c10df03332..ecaad251c63686c2b0cf6835e45bcecf0c33fe3e 100644 (file)
@@ -20,7 +20,6 @@
 #include "playermedia.h"
 //we most probably need a new demux...
 #include "demuxermedia.h"
-#include "timers.h"
 #include "video.h"
 #include "messagequeue.h"
 #include "i18n.h"
index d97e17b24e781ebf5e5d7c132a3d9f2c66fa5c14..6012c66cf2c751d1d66502543d2f9e42b5b3c9c9 100644 (file)
@@ -37,7 +37,7 @@
 #include "thread.h"
 #include "afeed.h"
 #include "vfeed.h"
-#include "timerreceiver.h"
+#include "timers.h"
 #include "video.h"
 
 #ifdef WIN32
index 115cacb5027905dd1bf3c496c9b68cb8fe6752ea..f1f73da3db29ec6cfd745ce11cd565bf7f244770 100644 (file)
--- a/timers.cc
+++ b/timers.cc
@@ -1,5 +1,5 @@
 /*
-    Copyright 2004-2007 Chris Tallon
+    Copyright 2004-2020 Chris Tallon
 
     This file is part of VOMP.
 
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-#include "timers.h"
-
 #include "log.h"
-#include "command.h"
-#include "timerreceiver.h"
+
+#include "timers.h"
 
 Timers* Timers::instance = NULL;
 
@@ -30,7 +27,6 @@ Timers::Timers()
 {
   if (instance) return;
   instance = this;
-  initted = false;
 }
 
 Timers::~Timers()
@@ -45,87 +41,106 @@ Timers* Timers::getInstance()
 
 int Timers::init()
 {
-  if (initted) return 0;
-  initted = true;
+  if (initted) return false;
   logger = Log::getInstance();
 
-  if (!threadStart())
-  {
-    shutdown();
-    return 0;
-  }
-
-  return 1;
+  timersMutex.lock(); // Start thread with mutex locked
+  recalc = true;
+  timersThread = std::thread([this] { masterLoop(); });
+  logger->log("Timers", Log::DEBUG, "Timers started");
+  initted = true;
+  return true;
 }
 
-int Timers::shutdown()
+void Timers::shutdown()
 {
-  if (!initted) return 0;
-  initted = false;
+  if (!initted) return;
+
+  std::unique_lock<std::mutex> lockWrapper(timersMutex); // lock the mutex
+  // main loop is in cond.wait/_until
 
-  logger->log("Timers", Log::DEBUG, "Timers shutdown start");
+  // stop the main thread
+  quitThread = true;  // main loop effectively dead, but join it later
 
-  threadStop();
+  // Remove any future timer events from the list
+  for(auto i = timerList.begin(); i != timerList.end(); )
+  {
+    TimerEvent* te = *i;
 
-  TimerEvent* timerEvent = NULL;
-  TimerReceiver* client = NULL;
-  int clientReference = 0;
+    if (!te->running)
+    {
+      delete te;
+      i = timerList.erase(i);
+    }
+    else
+      ++i;
+  }
 
+  // Now wait for all timer event threads to end
   while(timerList.size())
   {
-    threadLock();
-    timerEvent = timerList.front();
-    client = timerEvent->client;
-    clientReference = timerEvent->clientReference;
-    threadUnlock();
-
-    cancelTimer(client, clientReference);
+    timersCond.wait(lockWrapper); // unlocks in wait. waiting for reap signals
+    // locked
+    // Assume there has been a reap signal. Could be spurious but no harm done
+    reap();
+    timersCond.notify_all(); // In case of waiting cancelTimers
   }
 
-  logger->log("Timers", Log::DEBUG, "Timers shutdown end");
+  timersCond.notify_one(); // In case there were no TimerEvents to reap, wake the masterLoop thread
+  lockWrapper.unlock(); // main loop exits if it hasn't already
+  timersThread.join();
+}
 
-  return 1;
+bool Timers::setTimerD(TimerReceiver* client, int clientReference, long int requestedSecs, long int requestedNSecs)
+{
+  std::chrono::system_clock::time_point fireTime = std::chrono::system_clock::now();
+  fireTime += std::chrono::seconds(requestedSecs);
+  fireTime += std::chrono::nanoseconds(requestedNSecs);
+
+  return setTimerC(client, clientReference, fireTime);
+}
+
+bool Timers::setTimerT(TimerReceiver* client, int clientReference, long int requestedTime, long int requestedTimeNSecs)
+{
+  std::chrono::system_clock::time_point fireTime = std::chrono::system_clock::from_time_t(requestedTime);
+  fireTime += std::chrono::nanoseconds(requestedTimeNSecs);
+
+  return setTimerC(client, clientReference, fireTime);
 }
 
-bool Timers::setTimerT(TimerReceiver* client, int clientReference, long int requestedTime, long int requestedTimeNSEC)
+bool Timers::setTimerC(TimerReceiver* client, int clientReference, std::chrono::system_clock::time_point& fireTime)
 {
   if (!initted) return 0;
 
-  logger->log("Timers", Log::DEBUG, "Starting set timer 1");
+  logger->log("Timers", Log::DEBUG, "Starting set timer chrono");
 
-  //logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 2");
-  threadLock();
+  std::lock_guard<std::mutex> lock(timersMutex);
 
   // Check that this timer is not already in the list
-  TimerList::iterator i;
-  TimerEvent* currentTimerEvent = NULL;
-  for(i = timerList.begin(); i != timerList.end(); i++)
+  for(auto foundTimerEvent : timerList)
   {
-    currentTimerEvent = *i;
-
-    if ((currentTimerEvent->client == client) && (currentTimerEvent->clientReference == clientReference))
+    if ((foundTimerEvent->client == client) && (foundTimerEvent->clientReference == clientReference))
     {
       // Timer exists already, either waiting or running
-      // Update the clocks
-      currentTimerEvent->requestedTime.tv_sec = requestedTime;
-      currentTimerEvent->requestedTime.tv_nsec = requestedTimeNSEC;
+      // Update requestedTime
+      foundTimerEvent->requestedTime = fireTime;
 
-      if (currentTimerEvent->running)
+      if (foundTimerEvent->running)
       {
         // If this timerEvent is currently running, update the clocks and set the restart flag.
         // Instead of being deleted in timerEventFinished it will be restarted
-        currentTimerEvent->restartAfterFinish = true;
+        foundTimerEvent->restartAfterFinish = true;
         // Don't need to resetThreadFlag because this timer isn't re-live yet
-        threadUnlock();
-        return true;
+        return true; // unlock
       }
       else
       {
+        logger->log("Timers", Log::DEBUG, "Editing existing timer");
+
         // A waiting timer has been edited
-        resetThreadFlag = true;
-        threadSignalNoLock();
-        threadUnlock();
-        return true;
+        recalc = true;
+        timersCond.notify_all();
+        return true; // unlock
       }
     }
   }
@@ -135,40 +150,132 @@ bool Timers::setTimerT(TimerReceiver* client, int clientReference, long int requ
   TimerEvent* t = new TimerEvent();
   t->client = client;
   t->clientReference = clientReference;
-  t->requestedTime.tv_sec = requestedTime;
-  t->requestedTime.tv_nsec = requestedTimeNSEC;
+  t->requestedTime = fireTime;
 
-  //logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 2");
   timerList.push_back(t);
-  resetThreadFlag = true;
-  threadSignalNoLock();
-  //logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 2");
-  threadUnlock();
-
+  recalc = true;
+  timersCond.notify_all();
   logger->log("Timers", Log::DEBUG, "Timer set for %p ref %i", client, clientReference);
-
-  return true;
+  return true; // unlock
 }
 
-bool Timers::setTimerD(TimerReceiver* client, int clientReference, long int requestedSecs, long int requestedNSecs)
+void Timers::masterLoop()
 {
-  struct timespec currentTime;
+  // mutex is locked already
+  std::unique_lock<std::mutex> lockWrapper(timersMutex, std::defer_lock);
 
-  getClockRealTime(&currentTime);
+  TimerEvent* nextTimer = NULL;
+
+  while(1)
+  {
+    if (recalc)
+    {
+      // work out the next fire time
+      nextTimer = NULL;
 
-  long int requestedTime;
-  long int requestedTimeNSEC;
+      for(TimerEvent* thisTimer : timerList)
+      {
+        if (thisTimer->running) continue; // has already been timercall'd
 
-  requestedTime = currentTime.tv_sec + requestedSecs;
-  requestedTimeNSEC = currentTime.tv_nsec + requestedNSecs;
-  if (requestedTimeNSEC > 999999999)
+        if (!nextTimer)
+        {
+          nextTimer = thisTimer;
+        }
+        else
+        {
+          if (thisTimer->requestedTime < nextTimer->requestedTime)
+          {
+            nextTimer = thisTimer;
+          }
+        }
+      }
+
+      recalc = false;
+    }
+
+    std::cv_status cvs;
+    if (nextTimer)
+    {
+      // wait for signal timed
+      cvs = timersCond.wait_until(lockWrapper, nextTimer->requestedTime); //unlocks in wait
+    }
+    else
+    {
+      // wait for signal
+      timersCond.wait(lockWrapper); //unlocks in wait
+    }
+
+    // and we're back - we've been signalled (quit, recalc, reap) or the time ran out, or spurious. mutex locked.
+
+    // quit? -> quit
+    if (quitThread) return; // unlocks motex
+
+    if (doReap)
+    {
+      reap();
+      timersCond.notify_all(); // in case of waiting cancelTimers
+    }
+
+    // recalc? -> restart loop
+    if (recalc) continue;
+
+    // time ran out? -> fire a timer
+    if (nextTimer && (cvs == std::cv_status::timeout))
+    {
+      nextTimer->run();
+      recalc = true;
+    }
+//  else
+//  {
+      // not quit, not recalc, and either:
+      // 1. there is no next timer
+      // 2. there is a next timer but the timeout didn't expire
+      // therefore, this is a spurious wakeup. Leave recalc == false, go around, and do wait/wait_until again.
+//    continue;
+//  }
+  }
+
+  // If you want to do any cleanup after the main loop, change the quitthread return to break and put cleanup here. mutex will be locked
+}
+
+void Timers::reap() // Master timers thread, mutex locked (or shutdown, mutex locked)
+{
+  for(auto i = timerList.begin(); i != timerList.end(); )
   {
-    ++requestedTime;
-    requestedTimeNSEC -= 1000000000;
-    logger->log("Timers", Log::DEBUG, "Second rollover - CHECK FIXME");
+    TimerEvent* te = *i;
+
+    if (te->completed)
+    {
+      te->timerThread.join();
+
+      if (te->restartAfterFinish)
+      {
+        logger->log("Timers", Log::DEBUG, "timerEventFinished RESTART for %p %i", te->client, te->clientReference);
+        te->restartAfterFinish = false;
+        te->running = false;
+        te->completed = false;
+        recalc = true;
+        ++i;
+      }
+      else
+      {
+        delete te;
+        i = timerList.erase(i);
+      }
+    }
+    else
+      ++i;
   }
+}
 
-  return setTimerT(client, clientReference, requestedTime, requestedTimeNSEC);
+void Timers::reapTimerEvent(TimerEvent* te) // Called by a TimerEvent thread
+{
+  std::lock_guard<std::mutex> lock(timersMutex);
+  te->completed = true;
+  doReap = true;
+  timersCond.notify_all(); // Would be notify_one, but in the case of shutdown the thread within shutdown() will be
+  // handling the reaping. The notify that goes to the masterLoop will cause it to return from wait and sit waiting
+  // for the lock so it can examine quitThread and return. Doesn't matter which thread is unblocked first
 }
 
 bool Timers::cancelTimer(TimerReceiver* client, int clientReference)
@@ -176,7 +283,7 @@ bool Timers::cancelTimer(TimerReceiver* client, int clientReference)
   /* This method locks the timers mutex
      Then one of three things can happen:
      1. The TimerEvent is found, running = false. This means it hasn't started yet.
-        Delete the timer normally, set resetFlag
+        Delete the timer normally, set recalc
      2. The TimerEvent is found, running = true. This means the timer is currently firing,
         timercall on the client is being called.
         a. Thread calling cancelTimer is an external thread: In this case, this thread
@@ -199,225 +306,80 @@ bool Timers::cancelTimer(TimerReceiver* client, int clientReference)
 
   logger->log("Timers", Log::DEBUG, "Starting cancel timer %p %i, list size = %i", client, clientReference, timerList.size());
 
+  std::unique_lock<std::mutex> lockWrapper(timersMutex); // lock
+
   while(1)
   {
-    threadLock();
-
+    TimerEvent* foundTimerEvent = NULL;
     TimerList::iterator i;
-    TimerEvent* currentTimerEvent = NULL;
     for(i = timerList.begin(); i != timerList.end(); i++)
     {
-      currentTimerEvent = *i;
-      if ((currentTimerEvent->client == client) && (currentTimerEvent->clientReference == clientReference))
+      if (((*i)->client == client) && ((*i)->clientReference == clientReference))
       {
+        foundTimerEvent = *i;
         break;
       }
     }
 
-    if (i == timerList.end())
+    if (!foundTimerEvent)
     {
       // Case 3, no timer found
-      threadUnlock();
-      return true;
+      return true; // unlock
     }
-    else
-    {
-      // Timer found, Case 1 or 2
 
-      if (currentTimerEvent->running == false)
-      {
-        // Case 1. Just delete the timer and reset the thread.
-        timerList.erase(i);
-        delete currentTimerEvent;
-        logger->log("Timers", Log::DEBUG, "Removed timer for %p ref %i", client, clientReference);
-        resetThreadFlag = true;
-        threadSignalNoLock();
-        threadUnlock();
-        return true;
-      }
-      else
-      {
-        if (Thread_TYPE::thisThreadID() == currentTimerEvent->getThreadID())
-        {
-          // Case 2 b.
-          // The thread requesting cancelTimer is the timer thread itself, the timer has already fired.
-          logger->log("Timers", Log::DEBUG, "%p ref %i cancelTimer itself calling - ignore", client, clientReference);
-          currentTimerEvent->restartAfterFinish = false; // in case a restart had already been set.
-          threadUnlock();
-          return true;
-        }
-
-        // Case 2 a. For now, use polling with a 50ms delay.
-        // Don't delete a running timer.
-        // FIXME upgrade me to signalling
-
-        logger->log("Timers", Log::DEBUG, "%p ref %i cancelTimer WAITING", client, clientReference);
-
-        threadUnlock();
-        MILLISLEEP(50);
-      }
-    }
-  } // end of the big while loop
-}
+    // Timer found, case 1 or 2
 
-void Timers::timerEventFinished(TimerEvent* timerEvent)
-{
-  // This function takes out the already timercall'd TimerEvent from the list
-  // Or resets it if restart flag is true
-
-
-  if (!initted) return;
-  threadLock();
-
-  logger->log("Timers", Log::DEBUG, "timerEventFinished for %p", timerEvent->client);
-
-  for(TimerList::iterator i = timerList.begin(); i != timerList.end(); i++)
-  {
-    if (timerEvent != *i) continue;
-
-    if (timerEvent->restartAfterFinish)
+    if (!foundTimerEvent->running)
     {
-      logger->log("Timers", Log::DEBUG, "timerEventFinished RESTART for %p", timerEvent->client);
+      // Case 1. Timer was just waiting. Delete and set recalc.
 
-      timerEvent->restartAfterFinish = false;
-      timerEvent->running = false;
-      resetThreadFlag = true;
-      threadSignalNoLock();
-    }
-    else
-    {
-      // The removal of a called and non-restart TimerEvent doesn't need the threadMethod to be reset
       timerList.erase(i);
-      logger->log("Timers", Log::DEBUG, "timerEventFinished for %p %i - remove done", timerEvent->client, timerEvent->clientReference);
-      delete timerEvent;
+      delete foundTimerEvent;
+      logger->log("Timers", Log::DEBUG, "Removed timer for %p ref %i", client, clientReference);
+      recalc = true;
+      timersCond.notify_all(); // shutdown could be being called? notify_all guarantees we wake masterLoop
+      return true; // unlock
     }
 
-    break;
-  }
-  // FIXME At this point, this should signal all threads waiting on cancelTimer
-  threadUnlock();
-
-  // Kill this thread, as it's the one started for the timer event
-  Thread_TYPE::threadSuicide();
-}
-
-void Timers::threadMethod()
-{
-  struct timespec nextTime;
-  TimerEvent* nextTimer = NULL;
-  resetThreadFlag = true;
-
-  threadLock();
-
-  while(1)
-  {
-    if (resetThreadFlag)
+    if (std::this_thread::get_id() == foundTimerEvent->timerThread.get_id())
     {
-      resetThreadFlag = false;
-
-      // Work out the next Timer
-
-      nextTime.tv_sec = 0;
-      nextTime.tv_nsec = 0;
-      nextTimer = NULL;
-
-      TimerList::iterator i;
-      TimerEvent* currentTimer = NULL;
-      for(i = timerList.begin(); i != timerList.end(); i++)
-      {
-        currentTimer = *i;
-        if (currentTimer->running) continue; // has already been timercall'd
-
-        if (!nextTimer)
-        {
-          nextTime.tv_sec = currentTimer->requestedTime.tv_sec;
-          nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;
-          nextTimer = currentTimer;
-        }
-        else
-        {
-          if (currentTimer->requestedTime.tv_sec < nextTime.tv_sec)
-          {
-            nextTime.tv_sec = currentTimer->requestedTime.tv_sec;
-            nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;
-            nextTimer = currentTimer;
-          }
-          else if (currentTimer->requestedTime.tv_sec == nextTime.tv_sec)
-          {
-            if (currentTimer->requestedTime.tv_nsec < nextTime.tv_nsec)
-            {
-              nextTime.tv_sec = currentTimer->requestedTime.tv_sec;
-              nextTime.tv_nsec = currentTimer->requestedTime.tv_nsec;
-              nextTimer = currentTimer;
-            }
-          }
-        }
-      }
-    }
-
-    if (nextTimer)
-    {
-//##      logger->log("Timers", Log::DEBUG, "List size: %i. nextTimerClient: %p/%i. nextTime.tv_sec: %li. nextTime.tv_nsec: %li", timerList.size(), nextTimer->client, nextTimer->clientReference, nextTime.tv_sec, nextTime.tv_nsec);
-
-
-      //logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX (1)");
-      threadWaitForSignalTimed(&nextTime);
-      //logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 5");
-
-      // unlocks in the wait
-    }
-    else
-    {
-      //logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX (2)");
-      threadWaitForSignal();
-      //logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 6");
-      // unlocks in the wait
+      // Case 2 b.
+      // The thread requesting cancelTimer is the timer thread itself, the timer has already fired.
+      logger->log("Timers", Log::DEBUG, "%p ref %i cancelTimer itself calling - ignore", client, clientReference);
+      foundTimerEvent->restartAfterFinish = false; // in case a restart had already been set.
+      return true; // unlock
     }
 
-    // Mutex locked again here by exit of wait or timedwait above
-
-    // ok. we have been signalled or the time has run out
-    // This only gets signalled if it is to reset or die
-
-    // First check for die..
-    threadCheckExit(); // exiting thread with mutex locked
-
-    // Check for reset..
-    // This can be caused by an addition or deletion to the list
-    if (resetThreadFlag || (nextTimer == NULL)) continue;
+    // Case 2 a. An external thread is calling cancelTimer for a timer which has already fired and is still running.
+    // Want to block here until we know the thread has completed.
 
-    // timer ran out
+    // A broadcast notify goes out after each reap (whether in main loop or shutdown)
+    // So, wait on the cond and go around each time we wake. One of them will have been after the timerThread finished,
+    // which turns it into a case 3.
 
-    Log::getInstance()->log("Timers", Log::DEBUG, "Timer firing for client %p ref %i", nextTimer->client, nextTimer->clientReference);
+    logger->log("Timers", Log::DEBUG, "%p ref %i cancelTimer WAITING", client, clientReference);
+    timersCond.wait(lockWrapper); //unlocks in wait
+    // locked
+    logger->log("Timers", Log::DEBUG, "%p ref %i cancelTimer go-around", client, clientReference);
 
-    nextTimer->run(); // sets timerevent to running and starts it
-    resetThreadFlag = true; // find a new timer to wait on
-  }
+  } // end of the big while loop
 }
 
 
-
 // Class TimerEvent
 
-TimerEvent::TimerEvent()
-{
-  running = false;
-  restartAfterFinish = false;
-  client = NULL;
-  clientReference = 0;
-  requestedTime.tv_sec = 0;
-  requestedTime.tv_nsec = 0;
-}
-
-void TimerEvent::threadMethod()
-{
-  Log::getInstance()->log("Timers", Log::DEBUG, "sending timer to %p with parameter %u", client, clientReference);
-  client->timercall(clientReference);
-  Timers::getInstance()->timerEventFinished(this); // does not return
-}
-
 void TimerEvent::run()
 {
   running = true;
-  threadStart();
+  threadStartProtect.lock();
+  timerThread = std::thread([this]
+  {
+    threadStartProtect.lock();
+    threadStartProtect.unlock();
+
+    Log::getInstance()->log("Timers", Log::DEBUG, "sending timer to %p with parameter %u", client, clientReference);
+    client->timercall(clientReference);
+    Timers::getInstance()->reapTimerEvent(this);
+  });
+  threadStartProtect.unlock(); // Ensures timerThread is valid before run() returns
 }
index d15ef30eb8b752dd983e211c44e5d48e57229417..bf746b9e9edbed52c9a8d48a0c1d0a20cf840dc5 100644 (file)
--- a/timers.h
+++ b/timers.h
@@ -1,60 +1,5 @@
-
-
-
-
-
-
-
-
-
-/*
-
-
-FYI
-
-Fixed:
-
-The main problem was that timers only seemed to launch messages which went into The Big Mutex.
-This has been fixed a different way by implementing locking in BoxStack - meaning timercalls
-can now draw and update their displays without locking The Big Mutex. Problem solved. I think
-the whole program might move more towards classes keeping more mutexes and rely less on The
-Big Mutex.
-
-
-
->      Timers ... deprecated. Maybe.
-
->      This whole thing will be replaced with a timed-message idea. It will be possible
->      to send yourself (or whoever) a message with a delay, or delivery time. The message
->      will be handed to Command as usual, but command will do the right thing. The messages
->      will be delivered to the recipient _with the gui mutex locked_, meaning updates can
->      be done there and then in the message handler.
-
->      Good points:
->      * Cuts down on code lines
->      * Most (all?) timercall()s eventually send a message to command in order to
->        do something within The Big Mutex. This makes it easier and simpler code wise
->      * Gets rid of Timers.
-
->      Bad points:
->      * Timers become gui only features. Solve this with a MessageReceiver interface and
->        have command deliver messages straight to the recipients rather than through BoxStack.
->      * Timer delivery accuracy becomes dependant on everything that uses The Big Mutex.
->        It will become more important to not block The Big Mutex.
->      * Cancelling timers... hmm
-
->      If you have any comments about the new design, like, "It's just as flawed as the old one",
->      then I'd appreciate hearing it before I start writing it all :)
-
-
-*/
-
-
-
-
-
 /*
-    Copyright 2004-2005 Chris Tallon
+    Copyright 2004-2020 Chris Tallon
 
     This file is part of VOMP.
 
@@ -69,30 +14,15 @@ Big Mutex.
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-#ifndef TIMERS_H
-#define TIMERS_H
-
-#include <stdio.h>
-#include <list>
-
-#include "threadsystem.h"
-
-#include "defines.h"
-
-
-class Log;
-class TimerReceiver;
-
 /*
 
 Timers documentation
 
 Call setTimer to set a timer.... cancelTimer to delete a running timer.
-Derive your object from TimerReceiver (timerreceiver.h), implement timercall() in your class
+Derive your object from TimerReceiver, implement timercall() in your class
 and supply your 'this' pointer to setTimer.
 
 Once a timer has fired it does not exist anymore, you have to keep creating them if you want
@@ -103,36 +33,52 @@ so you can identify which timer has fired if you have more than one.
 
 You can reset a timer by calling setTimer again. This will not create 2 timers, it will overwrite the first one.
 
-You must not allow a timer to fire on an object that has been deleted already, unless you want
-segfaulty hell.
-
-??
+You must not allow a timer to fire on an object that has been deleted already.
 
 You must call cancelTimer before deleting object. cancelTimer guarantees that timercall
 will not be called again.
 
 */
 
-class TimerEvent : public Thread_TYPE
-{
-  public:
-    TimerEvent();
+#ifndef TIMERS_H
+#define TIMERS_H
 
-    virtual void run();
-    virtual void threadMethod();
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <list>
+#include <chrono>
 
-    TimerReceiver* client;
-    int clientReference;
-    struct timespec requestedTime;
+#include "defines.h"
 
-    bool running;
-    bool restartAfterFinish;
+class TimerReceiver
+{
+  public:
+    virtual ~TimerReceiver() {}
+    virtual void timercall(int clientReference)=0;
 };
 
+class TimerEvent
+{
+  friend class Timers;
+  public:
+  private:
+    TimerReceiver* client{};
+    int clientReference{};
+    std::chrono::system_clock::time_point requestedTime;
+    bool running{};
+    bool completed{};
+    bool restartAfterFinish{};
+    std::thread timerThread;
+    std::mutex threadStartProtect;
+
+    void run();
+};
 
+class Log;
 typedef std::list<TimerEvent*> TimerList;
 
-class Timers : public Thread_TYPE
+class Timers
 {
   public:
     Timers();
@@ -140,23 +86,29 @@ class Timers : public Thread_TYPE
     static Timers* getInstance();
 
     int init();
-    int shutdown();
+    void shutdown();
 
     bool setTimerT(TimerReceiver* client, int clientReference, long int requestedTime, long int requestedTimeNSEC=0);
     bool setTimerD(TimerReceiver* client, int clientReference, long int requestedSecs, long int requestedNSecs=0);
+    bool setTimerC(TimerReceiver* client, int clientReference, std::chrono::system_clock::time_point& requestedTime);
     bool cancelTimer(TimerReceiver* client, int clientReference);
 
-    // Thread stuff
-    virtual void threadMethod();
-
-    void timerEventFinished(TimerEvent* timerEvent); // internal use only, does not return
-
+    void reapTimerEvent(TimerEvent*); // Internal only
   private:
     static Timers* instance;
-    Log* logger;
-    bool initted;
+    Log* logger{};
+    bool initted{};
+    bool quitThread{};
+    bool recalc{};
+    bool doReap{};
     TimerList timerList;
-    bool resetThreadFlag;
+
+    std::thread timersThread;
+    std::mutex timersMutex;
+    std::condition_variable timersCond;
+
+    void masterLoop();
+    void reap();
 };
 
 #endif
index bc6c4928a8270db2d2ba6592a82d376f377dde41..d53d4aa53795bc841b41dcdc12a7431a1ae9271b 100644 (file)
     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-#include "vchannelselect.h"
 
 #include "input.h"
 #include "message.h"
 #include "boxstack.h"
 #include "colour.h"
 #include "log.h"
-#include "timers.h"
 #include "vdr.h"
 #include "messagequeue.h"
 
+#include "vchannelselect.h"
+
 // this class only works as it does because the remote command
 // values for the numbers are the numbers themselves !
 
@@ -37,7 +37,7 @@ VChannelSelect::VChannelSelect(Boxx* v)
   numGot = 0;
   ignoreTimer = false;
 
-  numWidth = (int)VDR::getInstance()->getChannelNumberWidth();
+  numWidth = static_cast<int>(VDR::getInstance()->getChannelNumberWidth());
   if (numWidth > 10) numWidth = 10;
   for (int i = 0; i < numWidth; i++) input[i] = -1;
 
@@ -54,7 +54,6 @@ VChannelSelect::~VChannelSelect()
 
 void VChannelSelect::timercall(int /*clientReference*/)
 {
-  Log::getInstance()->log("VChannelSelect", Log::DEBUG, "Timer call");
   if (ignoreTimer) return;
   changeChannel();
 }
@@ -112,7 +111,7 @@ void VChannelSelect::changeChannel()
 
     for(i = numGot - 1; i >= 0; i--)
     {
-      m->parameter += input[i] * (ULONG)pow(10., i);
+      m->parameter += input[i] * static_cast<ULONG>(pow(10., i));
     }
 
     MessageQueue::getInstance()->postMessage(m);
index ab22182f82ab240303088f556a300d49fba1941e..00b84a6dd52bd1dcc22e7a7da3c134078a4d60df 100644 (file)
@@ -24,7 +24,7 @@
 #include <math.h>
 
 #include "boxx.h"
-#include "timerreceiver.h"
+#include "timers.h"
 
 class VChannelSelect : public Boxx, public TimerReceiver
 {
diff --git a/vdr.cc b/vdr.cc
index 3f218b771e48909c629dba2a8c1cae723b40c2ff..c54e8f4318d4aa35b4f5a0ae9a882c709b3954a3 100644 (file)
--- a/vdr.cc
+++ b/vdr.cc
@@ -598,12 +598,12 @@ VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp)
   }
 
   // Sleep and block this thread. The sleep unlocks the mutex
-  logger->log("VDR", Log::DEBUG, "RR sleep - opcode %lu", vrp->getOpcode());
+//  logger->log("VDR", Log::DEBUG, "RR sleep - opcode %lu", vrp->getOpcode());
   edSleepThisReceiver(&vdrpr);
-  logger->log("VDR", Log::DEBUG, "RR unsleep");
+//  logger->log("VDR", Log::DEBUG, "RR unsleep");
     
   // Woken because a response packet has arrived, mutex will be locked
-  logger->log("VDR", Log::DEBUG, "Packet delivered to me, requestID: %lu", vdrpr.save_vresp->getRequestID());
+//  logger->log("VDR", Log::DEBUG, "Packet delivered to me, requestID: %lu", vdrpr.save_vresp->getRequestID());
   
   edUnlock();
   return vdrpr.save_vresp;
diff --git a/vepg.cc b/vepg.cc
index 4069109fa18abd9324ca1ab05def811f34f77cb0..62705b348dac204baef007ddd17478a9d9911f19 100644 (file)
--- a/vepg.cc
+++ b/vepg.cc
     The video stream currently being viewed is shown as quarter screen in the top right.
 */
 
-#include "vepg.h"
-
 #include "input.h"
 #include "vchannellist.h"
 #include "messagequeue.h"
 #include "video.h"
 #include "vepgsettimer.h"
-#include "timers.h"
 #include "wsymbol.h"
 #include "message.h"
 #include "colour.h"
@@ -46,6 +43,7 @@
 #include "i18n.h"
 #include "log.h"
 
+#include "vepg.h"
 
 VEpg* VEpg::instance = NULL;
 
diff --git a/vepg.h b/vepg.h
index adc6f7eb2b1a0671091fc82aae554cf755ff67bd..098e5d517c6519729322644d001481f001569ebd 100644 (file)
--- a/vepg.h
+++ b/vepg.h
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
 #ifndef VEPG_H
 #define VEPG_H
 
-#include <stdio.h>
-#include <string.h>
 #include <vector>
 
 #include "boxx.h"
 #include "defines.h"
-#include "timerreceiver.h"
+#include "timers.h"
 #include "wtextbox.h"
 #include "vdr.h"
 #include "wselectlist.h"
index 4cda3cd348c652388c3fc4c1c101348214c0e08e..070754726d9b5065c19bbdfd853d1e6252d28a31 100644 (file)
@@ -28,7 +28,6 @@
 #include "tbboxx.h"
 #include "wselectlist.h"
 #include "timers.h"
-#include "timerreceiver.h"
 
 class DirList;
 class Message;
index 403c68d3bd33e6ebfc517782e22d4ccf0f7161c1..87e0f10783a82e1bf611f73ff931527d553dc28b 100644 (file)
@@ -24,7 +24,6 @@
 #include "vpicturebanner.h"
 #include "vcolourtuner.h"
 #include "audioplayer.h"
-#include "timers.h"
 #include "boxx.h"
 #include "wselectlist.h"
 #include "input.h"
index 7e6d10aaa13c96cf91d6d1e2f50a424d86350aee..7d0bf63b4b93e26ad6634d9bebd6c3f85f5ea61f 100644 (file)
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
 #ifndef VMEDIAVIEW_H
 #define VMEDIAVIEW_H
 
-#include <stdio.h>
-#include <string.h>
-#include <vector>
-
 #include "boxx.h"
-#include "timerreceiver.h"
+#include "timers.h"
 #include "vmedialist.h"
 #include "colour.h"
 #include "wjpeg.h"
index b2fd4dfeb4be5827e3f1937c89f52d19cd96c9c2..9a8ccdc14086a88b3dc55a1252fd23b74d90d1e1 100644 (file)
--- a/vmute.cc
+++ b/vmute.cc
     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-#include "vmute.h"
-
 #include "input.h"
 #include "audio.h"
 #include "video.h"
 #include "wsymbol.h"
 #include "colour.h"
-#include "timers.h"
 #include "boxstack.h"
 #include "messagequeue.h"
 
+#include "vmute.h"
+
 VMute::VMute()
 {
   isMuted = Audio::getInstance()->toggleUserMute();
diff --git a/vmute.h b/vmute.h
index 850dbb92ec7851c776bfcb25b3063c1fe35b00e5..ebeb2428107ac7fe895289304eadb6e2f8e4f1a0 100644 (file)
--- a/vmute.h
+++ b/vmute.h
@@ -14,8 +14,7 @@
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
 #ifndef VMUTE_H
@@ -24,7 +23,7 @@
 #include <stdio.h>
 
 #include "boxx.h"
-#include "timerreceiver.h"
+#include "timers.h"
 
 class VMute : public Boxx, public TimerReceiver
 {
index 416a1e3086613f52d3c542550897bc6471daf2d9..d53b7fa84f22c7e9d2567daac0fa8e1c8874958c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright 2004-2019 Chris Tallon
+    Copyright 2004-2020 Chris Tallon
 
     This file is part of VOMP.
 
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-#include "vradiorec.h"
-
 #include "command.h"
 #include "osd.h"
 #include "player.h"
@@ -29,7 +26,6 @@
 #include "message.h"
 #include "vdr.h"
 #include "video.h"
-#include "timers.h"
 #include "playerradio.h"
 #include "boxstack.h"
 #include "input.h"
@@ -38,6 +34,8 @@
 #include "log.h"
 #include "messagequeue.h"
 
+#include "vradiorec.h"
+
 VRadioRec::VRadioRec(Recording* rec)
 {
   boxstack = BoxStack::getInstance();
index a5529013f729c56505ac7c197647ff6cf64ebf9a..dfff16d8eadeebc0a701032db43bbcba83463226 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright 2004-2006 Chris Tallon
+    Copyright 2004-2020 Chris Tallon
 
     This file is part of VOMP.
 
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
 #ifndef VRADIOREC_H
 #define VRADIOREC_H
 
-#include <stdio.h>
-
 #include "boxx.h"
-#include "timerreceiver.h"
+#include "timers.h"
 #include "defines.h"
 #include "colour.h"
 #include "region.h"
@@ -34,7 +31,6 @@ class Message;
 class VDR;
 class Video;
 class PlayerRadio;
-class Timers;
 class BoxStack;
 
 class VRadioRec : public Boxx, public TimerReceiver
index 45136a898f0cb8598ffd5006c67a903586600c97..9ba949f8ddc593f196b560c31608692752afae1e 100644 (file)
@@ -23,7 +23,6 @@
 #include "wsymbol.h"
 #include "colour.h"
 #include "video.h"
-#include "timers.h"
 #include "boxstack.h"
 #include "command.h"
 #include "messagequeue.h"
index 3ca76f0396c39dcb46b282b7ef1890b88530236a..bf0785e9a2657c4bfad2a83e869c6ab2ffb0720f 100644 (file)
@@ -23,7 +23,7 @@
 #include <stdio.h>
 
 #include "boxx.h"
-#include "timerreceiver.h"
+#include "timers.h"
 
 #include "threadsystem.h"
 
index 5e47bc475bd853b45e8ce799e37c9409361942a5..15a1ce63e60fcb5c2d67a4bfba2f1eb0b71e983d 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright 2005-2008 Chris Tallon, Marten Richter
+    Copyright 2005-2020 Chris Tallon, Marten Richter
 
     This file is part of VOMP.
 
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
+
 #include <math.h>
-#include "vteletextview.h"
+
 #include "video.h"
-#include "timers.h"
 #include "boxstack.h"
 #include "input.h"
 #include "playerlivetv.h"
 
+#include "vteletextview.h"
 
-VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder,Boxx* playerview, PlayerLiveTV* playerObj)
+VTeletextView::VTeletextView(TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview, PlayerLiveTV* playerObj)
 {   
-    ttdecoder=TTdecoder;
-    pv=playerview;
-    player=playerObj;
-    subtitlemode=false;
-    
-    
-
-    if (Video::getInstance()->getFormat() == Video::PAL)
-    { 
-        //setSize(680, 550);
-        setSize(680,22); //Only first line
-        setPosition(40, 26);
-    }
-    else
-    {
-        setPosition(40, 30);
-        //setSize(680, 450);
-        setSize(680,18);//only first line
-    }
-    createBuffer();
-    keyindigit=1;
-    page=0x100;
-    
+  ttdecoder = TTdecoder;
+  pv = playerview;
+  player = playerObj;
+
+  if (Video::getInstance()->getFormat() == Video::PAL)
+  {
+    //setSize(680, 550);
+    setSize(680,22); //Only first line
+    setPosition(40, 26);
+  }
+  else
+  {
+    setPosition(40, 30);
+    //setSize(680, 450);
+    setSize(680,18);//only first line
+  }
+
+  createBuffer();
+  keyindigit = 1;
+  page = 0x100;
 }
 
-VTeletextView::~VTeletextView ()
+VTeletextView::~VTeletextView()
 {
-    // Make sure the timer is deleted
-       Log::getInstance()->log("VTeletextView", Log::DEBUG, "VTeletextView destruct");
+  Log::getInstance()->log("VTeletextView", Log::DEBUG, "VTeletextView destruct");
   pv->draw();
   BoxStack::getInstance()->update(pv);
-  Timers::getInstance()->cancelTimer(this, 1);
   ttdecoder->unRegisterTeletextView(this);
-    
 }
 
 void VTeletextView::draw(bool completedraw, bool onlyfirstline)
 {
-       //Log::getInstance()->log("VTeletextView", Log::ERR, "Start draw");
-    Boxx::draw();
-    int x,y;
+  //Log::getInstance()->log("VTeletextView", Log::ERR, "Start draw");
+  Boxx::draw();
+  int x, y;
     
-    Boxx *drawtarget=NULL;
-    int ox,oy;
-    for (y=0;y<25;y++) {
-       if (y==0) {
-               drawtarget=this;
-               ox=0;
-               oy=0;
-       } else {
-               drawtarget=pv;
-               ox=this->getScreenX();
-               oy=this->getScreenY();
-       }
-
-        for (x=0;x<40;x++) {
-            if (ttdecoder->isDirty(x,y) || completedraw) {
-                cTeletextChar c=ttdecoder->getChar(x,y);
-                c.SetDirty(false);
-                //Skip Blinking and conceal
-                drawtarget->drawTTChar(ox,oy,x,y,c);
-                ttdecoder->setChar(x,y,c);
-            }
-        }
-    //    Log::getInstance()->log("VTeletextView", Log::ERR, "Line %d",y);
-        if (onlyfirstline) break;
+  Boxx* drawtarget = NULL;
+  int ox, oy;
+  for (y = 0; y < 25; y++)
+  {
+    if (y == 0)
+    {
+      drawtarget = this;
+      ox = 0;
+      oy = 0;
+    }
+    else
+    {
+      drawtarget = pv;
+      ox = this->getScreenX();
+      oy = this->getScreenY();
+    }
+
+    for (x = 0; x < 40; x++)
+    {
+      if (ttdecoder->isDirty(x, y) || completedraw)
+      {
+        cTeletextChar c = ttdecoder->getChar(x, y);
+        c.SetDirty(false);
+        //Skip Blinking and conceal
+        drawtarget->drawTTChar(ox, oy, x, y, c);
+        ttdecoder->setChar(x, y, c);
+      }
     }
+//    Log::getInstance()->log("VTeletextView", Log::ERR, "Line %d",y);
+    if (onlyfirstline) break;
+  }
   //  Log::getInstance()->log("VTeletextView", Log::ERR, "Start end");
-   
-    
 }
 
-
-
-
-
-int VTeletextView::handleCommand(int command) {
-    if (subtitlemode) return 0; //Ok we are in  subtitle mode, we are a slave of the player
-    switch (command) {
-    case Input::OK:
+int VTeletextView::handleCommand(int command)
+{
+    if (subtitlemode) return 0; //Ok we are in subtitle mode, we are a slave of the player
+    switch (command)
+    {
+      case Input::OK:
         return 2;
-    case Input::BACK:
+      case Input::BACK:
         if(player) player->tellSubtitlesOSDVisible(false); // Only on liveTV
         return 4;
-    case Input::ZERO:
-    case Input::ONE:
-    case Input::TWO:
-    case Input::THREE:
-    case Input::FOUR:
-    case Input::FIVE:
-    case Input::SIX:
-    case Input::SEVEN:
-    case Input::EIGHT:
-    case Input::NINE:
-    {
-      // key in teletext page
-      doKey(command);
-      return 2;
+      case Input::ZERO:
+      case Input::ONE:
+      case Input::TWO:
+      case Input::THREE:
+      case Input::FOUR:
+      case Input::FIVE:
+      case Input::SIX:
+      case Input::SEVEN:
+      case Input::EIGHT:
+      case Input::NINE:
+      {
+        // key in teletext page
+        doKey(command);
+        return 2;
+      }
     }
-    };
 
     return 0;
-    
 }
 
 void VTeletextView::doKey(int command)
 {
-    char pagenums[3];
-    if (keyindigit==1){
-        if (command==9) return; //not allowed
-        page=command<<8;
-        pagenums[0]=command+ 48;
-        pagenums[1]='-';
-        pagenums[2]='-';
-        keyindigit++;
-    } else if (keyindigit==2) {
-        page|=command<<4;
-        pagenums[0]=48+((page &0xF00)>>8);
-        pagenums[1]=command+ 48;
-        pagenums[2]='-';
-        keyindigit++;
-    } else if (keyindigit==3) {
-        page|=command;
-        pagenums[0]=48+((page &0xF00)>>8);
-        pagenums[1]=48+((page &0x0F0)>>4);
-        pagenums[2]=48+command;
-        keyindigit=1;
-        ttdecoder->setPage(page);
-    }
-    ttdecoder->setKeyinDigits(pagenums,true);
-    Region toupdate;
-    toupdate.w=16*40;
-    if (Video::getInstance()->getFormat() == Video::PAL) {
-        toupdate.h=22;
-        
-     } else {
-        toupdate.h=18;
-        
-      }
-     toupdate.x=0;
-     toupdate.y=0;
-            
-     draw(false,true);
-     BoxStack::getInstance()->update(this,&toupdate);
-
-}
-
-void VTeletextView::timercall(int /* clientReference */)
-{
-    
+  char pagenums[3];
+  if (keyindigit == 1)
+  {
+    if (command == 9) return; //not allowed
+    page = command << 8;
+    pagenums[0] = static_cast<char>(command + 48);
+    pagenums[1] = '-';
+    pagenums[2] = '-';
+    keyindigit++;
+  }
+  else if (keyindigit == 2)
+  {
+    page |= command << 4;
+    pagenums[0] = static_cast<char>(48 + ((page & 0xF00) >> 8));
+    pagenums[1] = static_cast<char>(command + 48);
+    pagenums[2] = '-';
+    keyindigit++;
+  }
+  else if (keyindigit == 3)
+  {
+    page |= command;
+    pagenums[0] = static_cast<char>(48 + ((page & 0xF00) >> 8));
+    pagenums[1] = static_cast<char>(48 + ((page & 0x0F0) >> 4));
+    pagenums[2] = static_cast<char>(48 + command);
+    keyindigit = 1;
+    ttdecoder->setPage(page);
+  }
+
+  ttdecoder->setKeyinDigits(pagenums, true);
+  Region toupdate;
+  toupdate.w = 16 * 40;
+  if (Video::getInstance()->getFormat() == Video::PAL)
+  {
+    toupdate.h = 22;
+  }
+  else
+  {
+    toupdate.h = 18;
+  }
+  toupdate.x = 0;
+  toupdate.y = 0;
+
+  draw(false, true);
+  BoxStack::getInstance()->update(this, &toupdate);
 }
 
 void VTeletextView::processMessage(Message* m)
 {
-    if (m->message == Message::TELETEXTUPDATE)
+  if (m->message == Message::TELETEXTUPDATE)
+  {
+    draw(false, false);
+    BoxStack::getInstance()->update(this);
+    BoxStack::getInstance()->update(pv);
+  }
+  else if (m->message == Message::TELETEXTUPDATEFIRSTLINE)
+  {
+    Region toupdate;
+    toupdate.w = 16 * 40;
+    if (Video::getInstance()->getFormat() == Video::PAL)
     {
-        draw(false,false);
-        BoxStack::getInstance()->update(this);
-        BoxStack::getInstance()->update(pv);
-
-    } else if (m->message == Message::TELETEXTUPDATEFIRSTLINE) 
+      toupdate.h = 22;
+    }
+    else
     {
-        Region toupdate;
-        toupdate.w=16*40;
-        if (Video::getInstance()->getFormat() == Video::PAL) {
-            toupdate.h=22;
-            
-        } else {
-            toupdate.h=18;
-            
-        }
-        toupdate.x=0;
-        toupdate.y=0;
-
-
-            
-        draw(false,true);
-        BoxStack::getInstance()->update(this,&toupdate);
-
+      toupdate.h = 18;
     }
-}
-
+    toupdate.x = 0;
+    toupdate.y = 0;
 
+    draw(false, true);
+    BoxStack::getInstance()->update(this, &toupdate);
+  }
+}
index d3d1f35aee9cebd89ee1d2e03421a397765747a7..5e7ac4589ec15c1b17bf0941c2732576ce461129 100644 (file)
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with VOMP; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
 #ifndef VTELETEXTVIEW_H
 #define VTELETEXTVIEW_H
 
-#include <stdio.h>
-
 #include "boxx.h"
-#include "timerreceiver.h"
+
 #include "teletextdecodervbiebu.h"
 
 class PlayerLiveTV;
 
-class VTeletextView : public Boxx, public TimerReceiver
+class VTeletextView : public Boxx
 {
   public:
-    VTeletextView (TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview,
-       PlayerLiveTV* palyerObj);
-    ~VTeletextView ();
+    VTeletextView(TeletextDecoderVBIEBU* TTdecoder, Boxx* playerview, PlayerLiveTV* palyerObj);
+    ~VTeletextView();
     void draw(bool completedraw, bool onlyfirstline);
-    void draw() {draw(true,false);};
-
-
-
-
+    void draw() { draw(true, false); }
     void processMessage(Message* m);
 
-    void setSubtitleMode(bool mode) {subtitlemode=mode;};
-    bool isInSubtitleMode() {return subtitlemode;};
+    void setSubtitleMode(bool mode) { subtitlemode = mode; }
+    bool isInSubtitleMode() { return subtitlemode; }
 
     int handleCommand(int command);
-    void timercall(int clientReference);
-   
 
   private:
-      void doKey(int command);
-    
+    void doKey(int command);
 
   protected:
-      TeletextDecoderVBIEBU* ttdecoder;
-      int keyindigit;
-      int page;
-      bool subtitlemode;
-      Boxx* pv;
-      PlayerLiveTV* player;
-    
-
+    TeletextDecoderVBIEBU* ttdecoder;
+    int keyindigit;
+    int page;
+    bool subtitlemode{};
+    Boxx* pv;
+    PlayerLiveTV* player;
 };
 
 #endif
index 0d2f97b45f3cb0988f6285dcff7b6a850fd682cb..a66aca04d94cd386c719deee7ada960c9b972915 100644 (file)
@@ -27,7 +27,6 @@
 #include "colour.h"
 #include "video.h"
 #include "i18n.h"
-#include "timers.h"
 #include "vquestion.h"
 #include "messagequeue.h"
 #include "staticartwork.h"
index c96c8b038b2bc4b936edd8e39c05693e0307b70a..59bdd218e110e68790fde1ccba52f8270ec22045 100644 (file)
@@ -28,7 +28,6 @@
 #include "colour.h"
 #include "video.h"
 #include "i18n.h"
-#include "timers.h"
 #include "vtimeredit.h"
 #include "command.h"
 #include "boxstack.h"
index 21219bf6e5bae2391da3c5cdeba1b1161ee00efc..966ac375e6f6bdd97b2b873359cac96ba1cb9a9f 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "vdr.h"
 #include "tbboxx.h"
-#include "timerreceiver.h"
+#include "timers.h"
 #include "wselectlist.h"
 #include "region.h"
 
index bce617f17d86fea68515938ce680f72a18fa0d50..c09a0baa417369db0913792e6f686e0c0fcaa15a 100644 (file)
@@ -17,7 +17,7 @@
     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-#include "vvideolivetv.h"
+#include <sstream>
 
 #include "vchannellist.h"
 #include "video.h"
@@ -37,7 +37,6 @@
 #include "vaudioselector.h"
 #include "colour.h"
 #include "event.h"
-#include "timers.h"
 #include "vepg.h"
 #include "bitmap.h"
 #include "log.h"
@@ -48,7 +47,8 @@
 #include "demuxer.h"
 #include "messagequeue.h"
 
-#include <sstream>
+#include "vvideolivetv.h"
+
 
 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
 {
index 22077dff2289ab3a95bd7712088680b4472f2c48..7d083c2405085cc5dda84c12b47bf4152fabc0ac 100644 (file)
@@ -30,7 +30,7 @@
 #include "vdr.h"
 #include "wtextbox.h"
 #include "wselectlist.h"
-#include "timerreceiver.h"
+#include "timers.h"
 #include "wsymbol.h"
 #include "wprogressbar.h"
 #include "osdreceiver.h"
index efb2bdcfb6145f083defc45cd56e4ad91d9a5d0e..b2f26c89f37cb5ad0331b64dae3656e2c1ea5626 100644 (file)
@@ -27,7 +27,6 @@
 #include "wsymbol.h"
 #include "audio.h"
 #include "video.h"
-#include "timers.h"
 #include "playermedia.h"
 #include "recording.h"
 #include "vaudioselector.h"
index f45c2227632cfdf321234167d522652e524b04ba..da513379c064328676a6c18b20ed179ed84c32d1 100644 (file)
 #include <stdio.h>
 
 #include "boxx.h"
-#include "timerreceiver.h"
+#include "timers.h"
 #include "wwss.h"
 #include "region.h"
 #include "colour.h"
 #include "recinfo.h"
 
-class Timers;
 class PlayerMedia;
 class Recording;
 class VAudioSelector;
index 478f8a01d4ad8c346881f5c99001d241818aa814..f212b94629f70c6276dc2acf18c5e0c1c813480b 100644 (file)
@@ -25,7 +25,6 @@
 #include "audio.h"
 #include "vdr.h"
 #include "video.h"
-#include "timers.h"
 #include "player.h"
 #include "recording.h"
 #include "vaudioselector.h"
@@ -40,6 +39,7 @@
 #include "channel.h"
 #include "vteletextview.h"
 #include "messagequeue.h"
+
 #include "vvideorec.h"
 
 VVideoRec::VVideoRec(Recording* rec, bool ish264)
@@ -59,10 +59,6 @@ VVideoRec::VVideoRec(Recording* rec, bool ish264)
   player = new Player(Command::getInstance(), this, this);
   player->init(myRec->IsPesRecording,myRec->recInfo->fps);
 
-  playing = false;
-
-  startMargin = 0;
-  endMargin = 0;
   char* cstartMargin = vdr->configLoad("Timers", "Start margin");
   char* cendMargin = vdr->configLoad("Timers", "End margin");
   if (!cstartMargin)
@@ -95,7 +91,7 @@ VVideoRec::VVideoRec(Recording* rec, bool ish264)
   OsdVector* osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
   if (osdv)
   {
-         osdv->updateBackgroundColor(DrawStyle::BLACK);
+    osdv->updateBackgroundColor(DrawStyle::BLACK);
   }
 
   barRegion.x = 0;
@@ -121,8 +117,6 @@ VVideoRec::VVideoRec(Recording* rec, bool ish264)
   vdisplay.y=0;
   vdisplay.width=0;
   vdisplay.height=0;
-
-  lastbar = -1;
 }
 
 void VVideoRec::preDelete()
index 6c2823c4a61bac2efd748810daaa7e930199fc9f..9dfa4fdd78f1de009cbc78d24c6c9beb33b933df 100644 (file)
@@ -23,7 +23,7 @@
 #include <stdio.h>
 
 #include "boxx.h"
-#include "timerreceiver.h"
+#include "timers.h"
 #include "region.h"
 #include "colour.h"
 #include "osdreceiver.h"
@@ -31,7 +31,6 @@
 #include "video.h"
 
 class VDR;
-class Timers;
 class Player;
 class Recording;
 class VAudioSelector;
@@ -77,7 +76,7 @@ class VVideoRec : public Boxx, public TimerReceiver, public OSDReceiver
     UCHAR videoMode;
     void toggleChopSides();
 
-    bool playing;
+    bool playing{};
 
     bool barShowing;
     bool barGenHold;
@@ -94,10 +93,10 @@ class VVideoRec : public Boxx, public TimerReceiver, public OSDReceiver
     Region barRegion;
     Region clocksRegion;
 
-    UINT startMargin;
-    UINT endMargin;
+    UINT startMargin{};
+    UINT endMargin{};
 
-    int lastbar;
+    int lastbar{-1};
     
     VInfo* vsummary;
 };
index 3728a542f19b05db5ea92390b555139cd24951f5..c0fc58afbcd91ac0c37f0ee086808e7b191f75a0 100644 (file)
@@ -24,7 +24,6 @@
 #include "wsymbol.h"
 #include "colour.h"
 #include "video.h"
-#include "timers.h"
 #include "boxstack.h"
 #include "messagequeue.h"
 
index a1a670b7e1dc212f525ad0e2cfd83e076b1b7af9..400cd8c0f9f19e3a26b1b23b073327e960b5f735 100644 (file)
--- a/vvolume.h
+++ b/vvolume.h
@@ -24,7 +24,7 @@
 #include <stdio.h>
 
 #include "boxx.h"
-#include "timerreceiver.h"
+#include "timers.h"
 
 class VVolume : public Boxx, public TimerReceiver
 {
index bb8b0707f4f00e2c520bdf8e49d3a43d03e8b07e..efc1d2b9961bb34590b6367e071e6383c7ebf8d6 100644 (file)
@@ -17,8 +17,8 @@
     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-#include "vwelcome.h"
 
+#include "log.h"
 #include "input.h"
 #include "vdr.h"
 #include "vchannellist.h"
 #include "colour.h"
 #include "video.h"
 #include "i18n.h"
-#include "timers.h"
 #include "vscreensaver.h"
 #include "vmedialist.h"
 #include "boxstack.h"
 #include "vopts.h"
 #include "staticartwork.h"
 
-#include "log.h"
+#include "vwelcome.h"
 
 VWelcome::VWelcome()
 {
index fd70295825fffdf92557aa56819cdfce304364a9..a0dfeccf17e5e39208772f222e11af0115f2ceb8 100644 (file)
@@ -25,7 +25,7 @@
 #include <string.h>
 
 #include "tbboxx.h"
-#include "timerreceiver.h"
+#include "timers.h"
 #include "wselectlist.h"
 #ifndef GRADIENT_DRAWING
 #include "wjpeg.h"