vdr
1.7.27
|
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 }