|
SASC-NG
DVBSoftCAM
|
00001 /* 00002 * Softcam plugin to VDR (C++) 00003 * 00004 * This code is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This code is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00018 */ 00019 00020 #include <stdlib.h> 00021 #include <stdio.h> 00022 #include <errno.h> 00023 #include <fcntl.h> 00024 #include <sys/ioctl.h> 00025 #include <sys/poll.h> 00026 #include <unistd.h> 00027 00028 #include <linux/dvb/dmx.h> 00029 00030 #include <vdr/device.h> 00031 #include <vdr/tools.h> 00032 00033 #include "filter.h" 00034 #include "misc.h" 00035 #include "log-core.h" 00036 00037 // -- cPidFilter ------------------------------------------------------------------ 00038 00039 cPidFilter::cPidFilter(const char *Id, int Num, cDevice *Device, unsigned int IdleTime) 00040 { 00041 device=Device; 00042 idleTime=IdleTime; 00043 id=0; fd=-1; forceRun=false; userData=0; 00044 id=bprintf("%s/%d",Id,Num); 00045 PRINTF(L_CORE_ACTION,"new filter '%s' (%d ms)",id,idleTime); 00046 } 00047 00048 cPidFilter::~cPidFilter() 00049 { 00050 cMutexLock lock(this); 00051 Stop(); 00052 PRINTF(L_CORE_ACTION,"filter '%s' removed",id); 00053 free(id); 00054 } 00055 00056 void cPidFilter::Flush(void) 00057 { 00058 cMutexLock lock(this); 00059 if(fd>=0) { 00060 unsigned char buff[MAX_SECT_SIZE]; 00061 while(read(fd,buff,sizeof(buff))>0); 00062 } 00063 } 00064 00065 void cPidFilter::Start(int Pid, int Section, int Mask) 00066 { 00067 cMutexLock lock(this); 00068 Stop(); 00069 fd=device->OpenFilter(Pid,Section,Mask); 00070 if(fd>=0) { 00071 pid=Pid; 00072 00073 LBSTART(L_CORE_ACTION); 00074 LBPUT("filter '%s' -> pid=0x%04x sct=0x%02x/0x%02x matching",id,Pid,Section,Mask); 00075 int Mode=0; 00076 int mam =Mask & (~Mode); 00077 int manm=Mask & ~(~Mode); 00078 for(int i=0; i<256; i++) { 00079 int xxxor=Section ^ i; 00080 if((mam&xxxor) || (manm && !(manm&xxxor))) {} 00081 else 00082 LBPUT(" 0x%02x",i); 00083 } 00084 LBEND(); 00085 } 00086 } 00087 00088 void cPidFilter::Stop(void) 00089 { 00090 cMutexLock lock(this); 00091 if(fd>=0) { device->CloseFilter(fd); fd=-1; } 00092 } 00093 00094 void cPidFilter::SetBuffSize(int BuffSize) 00095 { 00096 cMutexLock lock(this); 00097 if(fd>=0) { 00098 Stop(); 00099 int s=max(BuffSize,8192); 00100 CHECK(ioctl(fd,DMX_SET_BUFFER_SIZE,s)); 00101 } 00102 } 00103 00104 int cPidFilter::SetIdleTime(unsigned int IdleTime) 00105 { 00106 int i=idleTime; 00107 idleTime=IdleTime; 00108 return i; 00109 } 00110 00111 void cPidFilter::Wakeup(void) 00112 { 00113 cMutexLock lock(this); 00114 forceRun=true; 00115 PRINTF(L_CORE_ACTION,"filter '%s': wakeup",id); 00116 } 00117 00118 int cPidFilter::Pid(void) 00119 { 00120 return Active() ? pid : -1; 00121 } 00122 00123 // -- cAction ------------------------------------------------------------------ 00124 00125 cAction::cAction(const char *Id, cDevice *Device, const char *DevId) 00126 { 00127 device=Device; devId=DevId; 00128 id=bprintf("%s %s",Id,DevId); 00129 unique=0; pri=-1; 00130 SetDescription("%s filter",id); 00131 } 00132 00133 cAction::~cAction() 00134 { 00135 Cancel(2); 00136 DelAllFilter(); 00137 PRINTF(L_CORE_ACTION,"%s: stopped",id); 00138 free(id); 00139 } 00140 00141 cPidFilter *cAction::CreateFilter(int Num, int IdleTime) 00142 { 00143 return new cPidFilter(id,Num,device,IdleTime); 00144 } 00145 00146 cPidFilter *cAction::NewFilter(int IdleTime) 00147 { 00148 Lock(); 00149 cPidFilter *filter=CreateFilter(unique++,IdleTime); 00150 if(filter) { 00151 if(!Active()) { 00152 Start(); 00153 PRINTF(L_CORE_ACTION,"%s: started",id); 00154 } 00155 filters.Add(filter); 00156 } 00157 else 00158 PRINTF(L_CORE_ACTION,"%s: failed to create filter",id); 00159 Unlock(); 00160 return filter; 00161 } 00162 00163 cPidFilter *cAction::IdleFilter(void) 00164 { 00165 Lock(); 00166 cPidFilter *filter; 00167 for(filter=filters.First(); filter; filter=filters.Next(filter)) 00168 if(!filter->Active()) break; 00169 Unlock(); 00170 return filter; 00171 } 00172 00173 void cAction::DelFilter(cPidFilter *filter) 00174 { 00175 Lock(); 00176 filters.Del(filter); 00177 Unlock(); 00178 } 00179 00180 void cAction::DelAllFilter(void) 00181 { 00182 Lock(); 00183 filters.Clear(); 00184 unique=0; 00185 Unlock(); 00186 } 00187 00188 void cAction::Priority(int Pri) 00189 { 00190 pri=Pri; 00191 } 00192 00193 void cAction::Action(void) 00194 { 00195 if(pri>0) SetPriority(pri); 00196 struct pollfd *pfd=0; 00197 while(Running()) { 00198 if(filters.Count()<=0) { 00199 cCondWait::SleepMs(100); 00200 } 00201 else { 00202 // first build pfd data 00203 Lock(); 00204 delete[] pfd; pfd=new struct pollfd[filters.Count()]; 00205 if(!pfd) { 00206 PRINTF(L_GEN_ERROR,"action %s: pollfd: out of memory",id); 00207 break; 00208 } 00209 int num=0; 00210 cPidFilter *filter; 00211 for(filter=filters.First(); filter; filter=filters.Next(filter)) 00212 if(filter->Active()) { 00213 memset(&pfd[num],0,sizeof(struct pollfd)); 00214 pfd[num].fd=filter->fd; 00215 pfd[num].events=POLLIN; 00216 num++; 00217 } 00218 Unlock(); 00219 00220 // now poll for data 00221 int r=poll(pfd,num,60); 00222 if(r<0 && errno!=EINTR) { 00223 PRINTF(L_GEN_ERROR,"action %s poll: %s",id,strerror(errno)); 00224 break; 00225 } 00226 if(r>0) { 00227 for(r=0 ; r<num ; r++) 00228 if(pfd[r].revents&POLLIN) { 00229 Lock(); 00230 for(filter=filters.First(); filter; filter=filters.Next(filter)) { 00231 if(filter->fd==pfd[r].fd) { 00232 unsigned char buff[MAX_SECT_SIZE]; 00233 int n=read(filter->fd,buff,sizeof(buff)); 00234 if(n<0 && errno!=EAGAIN) { 00235 if(errno==EOVERFLOW) { 00236 filter->Flush(); 00237 //PRINTF(L_GEN_ERROR,"action %s read: Buffer overflow",filter->id); 00238 } 00239 else PRINTF(L_GEN_ERROR,"action %s read: %s",filter->id,strerror(errno)); 00240 } 00241 if(n>0) { 00242 filter->lastTime.Set(); filter->forceRun=false; 00243 Process(filter,buff,n); 00244 // don't make any assumption about data-structs here 00245 // Process() may have changed them 00246 } 00247 break; 00248 } 00249 } 00250 Unlock(); 00251 } 00252 } 00253 00254 // call filters which are idle too long 00255 Lock(); 00256 do { 00257 r=0; 00258 for(filter=filters.First(); filter; filter=filters.Next(filter)) { 00259 if(filter->forceRun || (filter->idleTime && filter->lastTime.Elapsed()>filter->idleTime)) { 00260 filter->lastTime.Set(); filter->forceRun=false; 00261 Process(filter,0,0); 00262 // don't make any assumption about data-structs here 00263 // Process() may have changed them 00264 r=1; break; 00265 } 00266 } 00267 } while(r); 00268 Unlock(); 00269 } 00270 } 00271 delete[] pfd; 00272 }