From 470415ad230d8455439edadb07dae0a21978783b Mon Sep 17 00:00:00 2001
From: Klaus Schmidinger <vdr@tvdr.de>
Date: Fri, 16 Aug 2002 09:22:29 +0200
Subject: Using cPoller instead of NeedsData

---
 HISTORY      |   4 +-
 PLUGINS.html |   4 +-
 device.c     |   4 +-
 device.h     |   9 +--
 dvbdevice.c  |  17 ++---
 dvbdevice.h  |   4 +-
 dvbplayer.c  | 203 ++++++++++++++++++++++++++++++-----------------------------
 player.h     |   4 +-
 tools.c      |  38 ++++++++++-
 tools.h      |  14 ++++-
 10 files changed, 173 insertions(+), 128 deletions(-)

diff --git a/HISTORY b/HISTORY
index 7ab0708f..87d19d58 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1405,8 +1405,8 @@ Video Disk Recorder Revision History
 - Temporarily made cDevice::ProvidesCa() virtual (Andreas Schultz needs this
   in his DXR3 plugin).
 - cDevice no longer exposes a file handle to cPlayer. A derived cPlayer class
-  can now call DeviceNeedsData() to see whether the replay device is ready for
-  further data. A derived cDevice class must implement NeedsData() and shall
+  can now call DevicePoll() to see whether the replay device is ready for
+  further data. A derived cDevice class must implement Poll() and shall
   check if any of its file handles is ready for data.
 - Implemented several replay modes to allow players that play only audio (thanks
   to Stefan Huelswitt).
diff --git a/PLUGINS.html b/PLUGINS.html
index 105865b0..e1f73f55 100644
--- a/PLUGINS.html
+++ b/PLUGINS.html
@@ -962,7 +962,7 @@ DVB device doesn't run out of data.
 To avoid busy loops the player should call its member function
 
 <p><table><tr><td bgcolor=#F0F0F0><pre><br>
-bool DeviceNeedsData(int Wait = 0);
+bool DevicePoll(cPoller &amp;Poller, int TimeoutMs = 0);
 </pre></td></tr></table><p>
 
 to determine whether the device is ready for further data.
@@ -1238,7 +1238,7 @@ virtual void Play(void);
 virtual void Freeze(void);
 virtual void Mute(void);
 virtual void StillPicture(const uchar *Data, int Length);
-virtual bool NeedsData(int Wait = 0);
+virtual bool Poll(cPoller &amp;Poller, int TimeoutMs = 0);
 virtual int PlayVideo(const uchar *Data, int Length);
 </pre></td></tr></table><p>
 <!--X1.1.7--></td></tr></table>
diff --git a/device.c b/device.c
index 40304618..ff18aebf 100644
--- a/device.c
+++ b/device.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: device.c 1.10 2002/08/15 10:30:08 kls Exp $
+ * $Id: device.c 1.11 2002/08/16 08:52:56 kls Exp $
  */
 
 #include "device.h"
@@ -397,7 +397,7 @@ void cDevice::StopReplay(void)
      }
 }
 
-bool cDevice::NeedsData(int Wait)
+bool cDevice::Poll(cPoller &Poller, int TimeoutMs)
 {
   return false;
 }
diff --git a/device.h b/device.h
index bba828a5..14d8ec50 100644
--- a/device.h
+++ b/device.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: device.h 1.8 2002/08/15 11:09:21 kls Exp $
+ * $Id: device.h 1.9 2002/08/16 08:52:27 kls Exp $
  */
 
 #ifndef __DEVICE_H
@@ -226,9 +226,10 @@ public:
        // Turns off audio while replaying.
   virtual void StillPicture(const uchar *Data, int Length);
        // Displays the given I-frame as a still picture.
-  virtual bool NeedsData(int Wait = 0);
-       // Returns true if the device needs further data for replaying.
-       // If Wait is not zero, the device will wait up to the given number
+  virtual bool Poll(cPoller &Poller, int TimeoutMs = 0);
+       // Returns true if the device itself or any of the file handles in
+       // Poller is ready for further action.
+       // If TimeoutMs is not zero, the device will wait up to the given number
        // of milleseconds before returning in case there is no immediate
        // need for data.
   virtual int PlayVideo(const uchar *Data, int Length);
diff --git a/dvbdevice.c b/dvbdevice.c
index 82587286..54da3bde 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: dvbdevice.c 1.5 2002/08/15 11:13:46 kls Exp $
+ * $Id: dvbdevice.c 1.6 2002/08/16 09:22:29 kls Exp $
  */
 
 #include "dvbdevice.h"
@@ -27,7 +27,6 @@ extern "C" {
 #include <ost/sec.h>
 #include <ost/video.h>
 #endif
-#include <poll.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include "dvbosd.h"
@@ -694,9 +693,10 @@ void cDvbDevice::StillPicture(const uchar *Data, int Length)
 #endif
 }
 
-bool cDvbDevice::NeedsData(int Wait)
+bool cDvbDevice::Poll(cPoller &Poller, int TimeoutMs)
 {
-  return cFile::FileReadyForWriting(fd_video, Wait);
+  Poller.Add(playMode == pmAudioOnly ? fd_audio : fd_video, true);
+  return Poller.Poll(TimeoutMs);
 }
 
 int cDvbDevice::PlayVideo(const uchar *Data, int Length)
@@ -731,13 +731,8 @@ void cDvbDevice::CloseDvr(void)
 int cDvbDevice::GetTSPacket(uchar *Data)
 {
   if (fd_dvr >= 0) {
-     pollfd pfd;
-     pfd.fd = fd_dvr;
-     pfd.events = POLLIN;
-
-     poll(&pfd, 1, 100);
-
-     if (pfd.revents & POLLIN != 0) {
+     cPoller Poller(fd_dvr, false);
+     if (Poller.Poll(100)) {
         int r = read(fd_dvr, Data, TS_SIZE);
         if (r >= 0)
            return r;
diff --git a/dvbdevice.h b/dvbdevice.h
index cbc9b164..ece1b454 100644
--- a/dvbdevice.h
+++ b/dvbdevice.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: dvbdevice.h 1.4 2002/08/15 10:59:25 kls Exp $
+ * $Id: dvbdevice.h 1.5 2002/08/16 08:53:30 kls Exp $
  */
 
 #ifndef __DVBDEVICE_H
@@ -92,7 +92,7 @@ public:
   virtual void Freeze(void);
   virtual void Mute(void);
   virtual void StillPicture(const uchar *Data, int Length);
-  virtual bool NeedsData(int Wait = 0);
+  virtual bool Poll(cPoller &Poller, int TimeoutMs = 0);
   virtual int PlayVideo(const uchar *Data, int Length);
   virtual int PlayAudio(const uchar *Data, int Length);
 
diff --git a/dvbplayer.c b/dvbplayer.c
index e2d011db..2ca5a62d 100644
--- a/dvbplayer.c
+++ b/dvbplayer.c
@@ -4,11 +4,10 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: dvbplayer.c 1.10 2002/08/15 10:00:28 kls Exp $
+ * $Id: dvbplayer.c 1.11 2002/08/16 09:16:38 kls Exp $
  */
 
 #include "dvbplayer.h"
-#include <poll.h>
 #include <stdlib.h>
 #include "recording.h"
 #include "ringbuffer.h"
@@ -65,7 +64,7 @@ int cBackTrace::Get(bool Forward)
            p = BACKTRACE_ENTRIES - 1;
         i = index[p] - 1;
         l -= length[p];
-        n--; 
+        n--;
         }
   return i;
 }
@@ -302,7 +301,6 @@ void cDvbPlayer::Action(void)
   uchar b[MAXFRAMESIZE];
   const uchar *p = NULL;
   int pc = 0;
-  bool CanWrite = true;
 
   readIndex = Resume();
   if (readIndex >= 0)
@@ -310,103 +308,106 @@ void cDvbPlayer::Action(void)
 
   running = true;
   while (running && NextFile()) {
-        {
-          LOCK_THREAD;
-
-          // Read the next frame from the file:
-
-          if (!readFrame) {
-             if (playMode != pmStill) {
-                int r = 0;
-                if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) {
-                   uchar FileNumber;
-                   int FileOffset, Length;
-                   int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, true);
-                   if (Index >= 0) {
-                      if (!NextFile(FileNumber, FileOffset))
-                         break;
-                      }
-                   else {
-                      // can't call Play() here, because those functions may only be
-                      // called from the foreground thread - and we also don't need
-                      // to empty the buffer here
-                      DevicePlay();
-                      playMode = pmPlay;
-                      playDir = pdForward;
-                      continue;
-                      }
-                   readIndex = Index;
-                   r = ReadFrame(replayFile, b, Length, sizeof(b));
-                   // must call StripAudioPackets() here because the buffer is not emptied
-                   // when falling back from "fast forward" to "play" (see above)
-                   StripAudioPackets(b, r);
-                   }
-                else if (index) {
-                   uchar FileNumber;
-                   int FileOffset, Length;
-                   readIndex++;
-                   if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset)))
-                      break;
-                   r = ReadFrame(replayFile, b, Length, sizeof(b));
-                   }
-                else // allows replay even if the index file is missing
-                   r = read(replayFile, b, sizeof(b));
-                if (r > 0)
-                   readFrame = new cFrame(b, r, ftUnknown, readIndex);
-                else if (r == 0)
-                   eof = true;
-                else if (r < 0 && FATALERRNO) {
-                   LOG_ERROR;
-                   break;
-                   }
-                }
-             else//XXX
-                usleep(1); // this keeps the CPU load low
-             }
-
-          // Store the frame in the buffer:
-
-          if (readFrame) {
-             if (ringBuffer->Put(readFrame))
-                readFrame = NULL;
-             }
-
-          // Get the next frame from the buffer:
-        
-          if (!playFrame) {
-             playFrame = ringBuffer->Get();
-             p = NULL;
-             pc = 0;
-             }
-
-          // Play the frame:
-
-          if (playFrame && CanWrite) {
-             if (!p) {
-                p = playFrame->Data();
-                pc = playFrame->Count();
-                }
-             if (p) {
-                int w = PlayVideo(p, pc);
-                if (w > 0) {
-                   p += w;
-                   pc -= w;
-                   }
-                else if (w < 0 && FATALERRNO) {
-                   LOG_ERROR;
-                   break;
-                   }
-                }
-             if (pc == 0) {
-                writeIndex = playFrame->Index();
-                backTrace->Add(playFrame->Index(), playFrame->Count());
-                ringBuffer->Drop(playFrame);
-                playFrame = NULL;
-                p = 0;
-                }
-             }
-        }
-        CanWrite = DeviceNeedsData(readFrame ? 10 : 0);
+        cPoller Poller;
+        if (!readFrame)
+           Poller.Add(replayFile, false);
+        if (DevicePoll(Poller, 100)) {
+
+           LOCK_THREAD;
+
+           // Read the next frame from the file:
+
+           if (!readFrame) {
+              if (playMode != pmStill) {
+                 int r = 0;
+                 if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) {
+                    uchar FileNumber;
+                    int FileOffset, Length;
+                    int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, true);
+                    if (Index >= 0) {
+                       if (!NextFile(FileNumber, FileOffset))
+                          break;
+                       }
+                    else {
+                       // can't call Play() here, because those functions may only be
+                       // called from the foreground thread - and we also don't need
+                       // to empty the buffer here
+                       DevicePlay();
+                       playMode = pmPlay;
+                       playDir = pdForward;
+                       continue;
+                       }
+                    readIndex = Index;
+                    r = ReadFrame(replayFile, b, Length, sizeof(b));
+                    // must call StripAudioPackets() here because the buffer is not emptied
+                    // when falling back from "fast forward" to "play" (see above)
+                    StripAudioPackets(b, r);
+                    }
+                 else if (index) {
+                    uchar FileNumber;
+                    int FileOffset, Length;
+                    readIndex++;
+                    if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset)))
+                       break;
+                    r = ReadFrame(replayFile, b, Length, sizeof(b));
+                    }
+                 else // allows replay even if the index file is missing
+                    r = read(replayFile, b, sizeof(b));
+                 if (r > 0)
+                    readFrame = new cFrame(b, r, ftUnknown, readIndex);
+                 else if (r == 0)
+                    eof = true;
+                 else if (r < 0 && FATALERRNO) {
+                    LOG_ERROR;
+                    break;
+                    }
+                 }
+              else//XXX
+                 usleep(1); // this keeps the CPU load low
+              }
+
+           // Store the frame in the buffer:
+
+           if (readFrame) {
+              if (ringBuffer->Put(readFrame))
+                 readFrame = NULL;
+              }
+
+           // Get the next frame from the buffer:
+
+           if (!playFrame) {
+              playFrame = ringBuffer->Get();
+              p = NULL;
+              pc = 0;
+              }
+
+           // Play the frame:
+
+           if (playFrame) {
+              if (!p) {
+                 p = playFrame->Data();
+                 pc = playFrame->Count();
+                 }
+              if (p) {
+                 int w = PlayVideo(p, pc);
+                 if (w > 0) {
+                    p += w;
+                    pc -= w;
+                    }
+                 else if (w < 0 && FATALERRNO) {
+                    LOG_ERROR;
+                    break;
+                    }
+                 }
+              if (pc == 0) {
+                 writeIndex = playFrame->Index();
+                 backTrace->Add(playFrame->Index(), playFrame->Count());
+                 ringBuffer->Drop(playFrame);
+                 playFrame = NULL;
+                 p = 0;
+                 }
+              }
+           }
         }
   active = running = false;
 
diff --git a/player.h b/player.h
index 1eed0b70..12cc2a37 100644
--- a/player.h
+++ b/player.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: player.h 1.7 2002/08/15 11:10:09 kls Exp $
+ * $Id: player.h 1.8 2002/08/16 09:14:12 kls Exp $
  */
 
 #ifndef __PLAYER_H
@@ -19,7 +19,7 @@ private:
   cDevice *device;
   ePlayMode playMode;
 protected:
-  bool DeviceNeedsData(int Wait = 0) { return device ? device->NeedsData(Wait) : false; }
+  bool DevicePoll(cPoller &Poller, int TimeoutMs = 0) { return device ? device->Poll(Poller, TimeoutMs) : false; }
   void DeviceTrickSpeed(int Speed) { if (device) device->TrickSpeed(Speed); }
   void DeviceClear(void) { if (device) device->Clear(); }
   void DevicePlay(void) { if (device) device->Play(); }
diff --git a/tools.c b/tools.c
index 40aad70a..f5545c34 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.c 1.69 2002/08/11 11:49:08 kls Exp $
+ * $Id: tools.c 1.70 2002/08/16 08:52:01 kls Exp $
  */
 
 #include "tools.h"
@@ -482,6 +482,42 @@ const char *DayDateTime(time_t t)
   return buffer;
 }
 
+// --- cPoller ---------------------------------------------------------------
+
+cPoller::cPoller(int FileHandle, bool Out)
+{
+  numFileHandles = 0;
+  Add(FileHandle, Out);
+}
+
+bool cPoller::Add(int FileHandle, bool Out)
+{
+  if (FileHandle >= 0) {
+     for (int i = 0; i < numFileHandles; i++) {
+         if (pfd[i].fd == FileHandle)
+            return true;
+         }
+     if (numFileHandles < MaxPollFiles) {
+        pfd[numFileHandles].fd = FileHandle;
+        pfd[numFileHandles].events = Out ? POLLOUT : POLLIN;
+        numFileHandles++;
+        return true;
+        }
+     esyslog("ERROR: too many file handles in cPoller");
+     }
+  return false;
+}
+
+bool cPoller::Poll(int TimeoutMs)
+{
+  if (numFileHandles) {
+     if (poll(pfd, numFileHandles, TimeoutMs) != 0)
+        return true; // returns true even in case of an error, to let the caller
+                     // access the file and thus see the error code
+     }
+  return false;
+}
+
 // --- cFile -----------------------------------------------------------------
 
 bool cFile::files[FD_SETSIZE] = { false };
diff --git a/tools.h b/tools.h
index c61d2f57..ebabb470 100644
--- a/tools.h
+++ b/tools.h
@@ -4,7 +4,7 @@
  * See the main source file 'vdr.c' for copyright information and
  * how to reach the author.
  *
- * $Id: tools.h 1.48 2002/08/11 11:34:26 kls Exp $
+ * $Id: tools.h 1.49 2002/08/16 08:52:01 kls Exp $
  */
 
 #ifndef __TOOLS_H
@@ -12,6 +12,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <poll.h>
 #include <stdio.h>
 #include <string.h>
 #include <syslog.h>
@@ -76,6 +77,17 @@ bool SpinUpDisk(const char *FileName);
 const char *WeekDayName(int WeekDay); // returns a statically allocated string!
 const char *DayDateTime(time_t t = 0); // returns a statically allocated string!
 
+class cPoller {
+private:
+  enum { MaxPollFiles = 16 };
+  pollfd pfd[MaxPollFiles];
+  int numFileHandles;
+public:
+  cPoller(int FileHandle = -1, bool Out = false);
+  bool Add(int FileHandle, bool Out);
+  bool Poll(int TimeoutMs = 0);
+  };
+  
 class cFile {
 private:
   static bool files[];
-- 
cgit v1.2.3