vdr  1.7.27
sections.c
Go to the documentation of this file.
00001 /*
00002  * sections.c: Section data handling
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: sections.c 2.0 2007/10/14 12:52:07 kls Exp $
00008  */
00009 
00010 #include "sections.h"
00011 #include <unistd.h>
00012 #include "channels.h"
00013 #include "device.h"
00014 #include "thread.h"
00015 
00016 // --- cFilterHandle----------------------------------------------------------
00017 
00018 class cFilterHandle : public cListObject {
00019 public:
00020   cFilterData filterData;
00021   int handle;
00022   int used;
00023   cFilterHandle(const cFilterData &FilterData);
00024   };
00025 
00026 cFilterHandle::cFilterHandle(const cFilterData &FilterData)
00027 {
00028   filterData = FilterData;
00029   handle = -1;
00030   used = 0;
00031 }
00032 
00033 // --- cSectionHandlerPrivate ------------------------------------------------
00034 
00035 class cSectionHandlerPrivate {
00036 public:
00037   cChannel channel;
00038   };
00039 
00040 // --- cSectionHandler -------------------------------------------------------
00041 
00042 cSectionHandler::cSectionHandler(cDevice *Device)
00043 :cThread("section handler")
00044 {
00045   shp = new cSectionHandlerPrivate;
00046   device = Device;
00047   statusCount = 0;
00048   on = false;
00049   waitForLock = false;
00050   lastIncompleteSection = 0;
00051   Start();
00052 }
00053 
00054 cSectionHandler::~cSectionHandler()
00055 {
00056   Cancel(3);
00057   cFilter *fi;
00058   while ((fi = filters.First()) != NULL)
00059         Detach(fi);
00060   delete shp;
00061 }
00062 
00063 int cSectionHandler::Source(void)
00064 {
00065   return shp->channel.Source();
00066 }
00067 
00068 int cSectionHandler::Transponder(void)
00069 {
00070   return shp->channel.Transponder();
00071 }
00072 
00073 const cChannel *cSectionHandler::Channel(void)
00074 {
00075   return &shp->channel;
00076 }
00077 
00078 void cSectionHandler::Add(const cFilterData *FilterData)
00079 {
00080   Lock();
00081   statusCount++;
00082   cFilterHandle *fh;
00083   for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
00084       if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask))
00085          break;
00086       }
00087   if (!fh) {
00088      int handle = device->OpenFilter(FilterData->pid, FilterData->tid, FilterData->mask);
00089      if (handle >= 0) {
00090         fh = new cFilterHandle(*FilterData);
00091         fh->handle = handle;
00092         filterHandles.Add(fh);
00093         }
00094      }
00095   if (fh)
00096      fh->used++;
00097   Unlock();
00098 }
00099 
00100 void cSectionHandler::Del(const cFilterData *FilterData)
00101 {
00102   Lock();
00103   statusCount++;
00104   cFilterHandle *fh;
00105   for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
00106       if (fh->filterData.Is(FilterData->pid, FilterData->tid, FilterData->mask)) {
00107          if (--fh->used <= 0) {
00108             device->CloseFilter(fh->handle);
00109             filterHandles.Del(fh);
00110             break;
00111             }
00112          }
00113       }
00114   Unlock();
00115 }
00116 
00117 void cSectionHandler::Attach(cFilter *Filter)
00118 {
00119   Lock();
00120   statusCount++;
00121   filters.Add(Filter);
00122   Filter->sectionHandler = this;
00123   if (on)
00124      Filter->SetStatus(true);
00125   Unlock();
00126 }
00127 
00128 void cSectionHandler::Detach(cFilter *Filter)
00129 {
00130   Lock();
00131   statusCount++;
00132   Filter->SetStatus(false);
00133   Filter->sectionHandler = NULL;
00134   filters.Del(Filter, false);
00135   Unlock();
00136 }
00137 
00138 void cSectionHandler::SetChannel(const cChannel *Channel)
00139 {
00140   Lock();
00141   shp->channel = Channel ? *Channel : cChannel();
00142   Unlock();
00143 }
00144 
00145 void cSectionHandler::SetStatus(bool On)
00146 {
00147   Lock();
00148   if (on != On) {
00149      if (!On || device->HasLock()) {
00150         statusCount++;
00151         for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
00152             fi->SetStatus(false);
00153             if (On)
00154                fi->SetStatus(true);
00155             }
00156         on = On;
00157         waitForLock = false;
00158         }
00159      else
00160         waitForLock = On;
00161      }
00162   Unlock();
00163 }
00164 
00165 void cSectionHandler::Action(void)
00166 {
00167   SetPriority(19);
00168   while (Running()) {
00169 
00170         Lock();
00171         if (waitForLock)
00172            SetStatus(true);
00173         int NumFilters = filterHandles.Count();
00174         pollfd pfd[NumFilters];
00175         for (cFilterHandle *fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
00176             int i = fh->Index();
00177             pfd[i].fd = fh->handle;
00178             pfd[i].events = POLLIN;
00179             pfd[i].revents = 0;
00180             }
00181         int oldStatusCount = statusCount;
00182         Unlock();
00183 
00184         if (poll(pfd, NumFilters, 1000) > 0) {
00185            bool DeviceHasLock = device->HasLock();
00186            if (!DeviceHasLock)
00187               cCondWait::SleepMs(100);
00188            for (int i = 0; i < NumFilters; i++) {
00189                if (pfd[i].revents & POLLIN) {
00190                   cFilterHandle *fh = NULL;
00191                   LOCK_THREAD;
00192                   if (statusCount != oldStatusCount)
00193                      break;
00194                   for (fh = filterHandles.First(); fh; fh = filterHandles.Next(fh)) {
00195                       if (pfd[i].fd == fh->handle)
00196                          break;
00197                       }
00198                   if (fh) {
00199                      // Read section data:
00200                      unsigned char buf[4096]; // max. allowed size for any EIT section
00201                      int r = safe_read(fh->handle, buf, sizeof(buf));
00202                      if (!DeviceHasLock)
00203                         continue; // we do the read anyway, to flush any data that might have come from a different transponder
00204                      if (r > 3) { // minimum number of bytes necessary to get section length
00205                         int len = (((buf[1] & 0x0F) << 8) | (buf[2] & 0xFF)) + 3;
00206                         if (len == r) {
00207                            // Distribute data to all attached filters:
00208                            int pid = fh->filterData.pid;
00209                            int tid = buf[0];
00210                            for (cFilter *fi = filters.First(); fi; fi = filters.Next(fi)) {
00211                                if (fi->Matches(pid, tid))
00212                                   fi->Process(pid, tid, buf, len);
00213                                }
00214                            }
00215                         else if (time(NULL) - lastIncompleteSection > 10) { // log them only every 10 seconds
00216                            dsyslog("read incomplete section - len = %d, r = %d", len, r);
00217                            lastIncompleteSection = time(NULL);
00218                            }
00219                         }
00220                      }
00221                   }
00222                }
00223            }
00224         }
00225 }