|
SASC-NG
DVBSoftCAM
|
00001 /* 00002 DVBLoopback 00003 Copyright Alan Nisota 2006 00004 00005 This file is part of DVBLoopback. 00006 00007 DVBLoopback is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or 00010 (at your option) any later version. 00011 00012 DVBLoopback is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with DVBLoopback; if not, write to the Free Software 00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 #include <stdlib.h> 00022 #include <stdio.h> 00023 #include <fcntl.h> 00024 #include <pthread.h> 00025 #include <sys/mman.h> 00026 #include <sys/poll.h> 00027 #include <sys/ioctl.h> 00028 #include <signal.h> 00029 #include <string.h> 00030 #include <getopt.h> 00031 #include <unistd.h> 00032 #include <errno.h> 00033 #include <assert.h> 00034 00035 #include "list.h" 00036 #include <linux/dvb/dmx.h> 00037 #include <linux/dvb/frontend.h> 00038 #include <linux/dvb/version.h> 00039 #include "plugin_getsid.h" 00040 #include "msg_passing.h" 00041 00042 #ifndef FE_SET_FRONTEND2 00043 #define FE_SET_FRONTEND2 FE_SET_FRONTEND 00044 #endif 00045 00046 static LIST_HEAD(getsidlist); 00047 00048 #define DBG_NAME "CHANNEL" 00049 #define PLUGIN_ID PLUGIN_GETSID 00050 #include "debug.h" //This is required to happen AFTER PLUGIN_ID is defined 00051 00052 struct filter { 00053 struct list_head list; //this must remain first!!! 00054 struct list_head sids; //contains sids to find for this fd 00055 __u16 pid; 00056 int fd; 00057 int used; 00058 int parse_err; 00059 }; 00060 00061 struct sidnum { 00062 struct list_head list; 00063 int sid; 00064 int seen; 00065 }; 00066 00067 //ISO 13818.1 says there can only be one PAT section, but I've already coded 00068 //it so let's leave the capability 00069 #define MAX_PAT_SECTIONS 5 00070 struct pat { 00071 int patfd; 00072 int version; 00073 unsigned char last_section; 00074 unsigned char section_seen[MAX_PAT_SECTIONS]; 00075 int has_nit; 00076 struct list_head dmx_filter_ll; 00077 }; 00078 00079 #define MAX_SIMULTANEOUS_PMT 32 00080 00081 static int sid_opt = 0; 00082 static int opt_maxfilters = 2; 00083 static int opt_max_fail = 20; 00084 static int opt_allpids = 0; 00085 static int opt_resetpidmap = 0; 00086 static int opt_experimental = 0; 00087 static int opt_orbit = 0; 00088 static char *opt_ignore = 0; 00089 static char *opt_unseen = 0; 00090 static int opt_maxrestart = 0; 00091 static struct option Sid_Opts[] = { 00092 {"sid-filt", 1, &sid_opt, 'f'}, 00093 {"sid-allpid", 0, &sid_opt, 'p'}, 00094 {"sid-nocache", 0, &sid_opt, 'c'}, 00095 {"sid-orbit", 1, &sid_opt, 'o'}, 00096 {"sid-experimental", 0, &sid_opt, 'e'}, 00097 {"sid-ignore", 1, &sid_opt, 'i'}, 00098 {"sid-restart", 1, &sid_opt, 'r'}, 00099 {"sid-unseen", 1, &sid_opt, 'u'}, 00100 {0, 0, 0, 0}, 00101 }; 00102 00103 static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER; 00104 LIST_HEAD(sid_empty_queue); 00105 LIST_HEAD(sidnum_empty_queue); 00106 LIST_HEAD(epid_empty_queue); 00107 LIST_HEAD(dmxcmd_empty_queue); 00108 LIST_HEAD(sidmsg_empty_queue); 00109 LIST_HEAD(filt_empty_queue); 00110 00111 void free_sidmsg(struct sid_msg *sidmsg) { 00112 list_add_l(&sidmsg->list, &sidmsg_empty_queue, &list_lock); 00113 } 00114 00115 void free_addsid_msg(void *msg) { 00116 struct sid_msg *sidmsg = (struct sid_msg *)msg; 00117 free_sidmsg(sidmsg); 00118 } 00119 00120 static int add_pid(int patfd, int pid) { 00121 struct dmx_sct_filter_params sct_filter; 00122 00123 bzero(&sct_filter, sizeof(struct dmx_sct_filter_params)); 00124 sct_filter.pid = (__u16) pid; 00125 sct_filter.flags = DMX_IMMEDIATE_START; 00126 if(ioctl(patfd, DMX_SET_BUFFER_SIZE, 0x40000) < 0) { 00127 dprintf0("Failed to set buffersize on fd:%d, pid:%d (err:%d)\n", 00128 patfd,pid, errno); 00129 return 1; 00130 } 00131 if (ioctl(patfd, DMX_SET_FILTER, &sct_filter) < 0) { 00132 dprintf0("Failed to set filter on fd:%d pid:%d (err: %d)\n", 00133 patfd, pid, errno); 00134 return 1; 00135 } 00136 return 0; 00137 } 00138 00139 static void free_sid(struct sid *sid_ll) { 00140 struct epid *epid_ll; 00141 pthread_mutex_lock(&list_lock); 00142 while(! list_empty(&sid_ll->epid)) { 00143 epid_ll = list_entry(sid_ll->epid.next, struct epid); 00144 list_del(&epid_ll->list); 00145 list_add(&epid_ll->list, &epid_empty_queue); 00146 } 00147 list_add(&sid_ll->list, &sid_empty_queue); 00148 pthread_mutex_unlock(&list_lock); 00149 } 00150 00151 static void free_pat(struct pat *pat) 00152 { 00153 while(! list_empty(&pat->dmx_filter_ll)) { 00154 struct filter *filt = list_entry(pat->dmx_filter_ll.next, struct filter); 00155 list_del(&filt->list); 00156 while(! list_empty(&filt->sids)) { 00157 struct sidnum *sidnum = list_entry(filt->sids.next, struct sidnum); 00158 list_del(&sidnum->list); 00159 list_add_l(&sidnum->list, &sidnum_empty_queue, &list_lock); 00160 } 00161 if(filt->fd > 0) { 00162 close(filt->fd); 00163 } 00164 list_add_l(&filt->list, &filt_empty_queue, &list_lock); 00165 } 00166 } 00167 00168 static int read_pat(unsigned char *pes, struct pat *pat, unsigned int size) { 00169 unsigned int sec, end; 00170 int version; 00171 unsigned char *ptr, last_sec; 00172 struct sidnum *sidnum; 00173 00174 if (pes[0] != 0x00) { 00175 dprintf0( 00176 "read_pat: expected PAT table 0x00 but got 0x%02x\n", pes[0]); 00177 return 1; 00178 } 00179 end = (((pes[1] & 0x03) << 8 | pes[2]) + 3 - 4); 00180 if(end > size-4) { 00181 dprintf0("read_pat: invalid PAT table size (%d > %d)\n", end, size-4); 00182 return 1; 00183 } 00184 version = (pes[5] >> 1) & 0x1f; 00185 sec = pes[6]; 00186 last_sec = pes[7]; 00187 if(last_sec >= MAX_PAT_SECTIONS) { 00188 dprintf0("read_pat: illegal section count %d > %d\n", 00189 last_sec, MAX_PAT_SECTIONS); 00190 return 1; 00191 } 00192 if (pat->version != version || last_sec != pat->last_section) { 00193 pat->version = version; 00194 pat->last_section = last_sec; 00195 while(! list_empty(&pat->dmx_filter_ll)) { 00196 struct filter *filt = list_entry(pat->dmx_filter_ll.next, struct filter); 00197 list_del(&filt->list); 00198 while(! list_empty(&filt->sids)) { 00199 sidnum = list_entry(filt->sids.next, struct sidnum); 00200 list_del(&sidnum->list); 00201 list_add_l(&sidnum->list, &sidnum_empty_queue, &list_lock); 00202 } 00203 list_add_l(&filt->list, &filt_empty_queue, &list_lock); 00204 } 00205 } 00206 if(pat->section_seen[sec]) 00207 return 0; 00208 pat->section_seen[sec] = 1; 00209 for(ptr = pes + 8; ptr < pes + end; ptr += 4) { 00210 int sid, pid; 00211 struct filter *filt; 00212 sid = (ptr[0] << 8) | ptr[1]; 00213 pid = ((ptr[2] & 0x1F) << 8) | ptr[3]; 00214 if(sid != 0) { 00215 dprintf2("found PID: %d for sid: %d\n", pid, sid); 00216 ll_find_elem(filt, pat->dmx_filter_ll, pid, pid, struct filter); 00217 if(! filt) { 00218 pop_entry_from_queue_l(filt, &filt_empty_queue, struct filter, 00219 &list_lock); 00220 bzero(filt, sizeof(struct filter)); 00221 INIT_LIST_HEAD(&filt->sids); 00222 list_add(&filt->list, &pat->dmx_filter_ll); 00223 filt->pid = pid; 00224 } 00225 pop_entry_from_queue_l(sidnum, &sidnum_empty_queue, struct sidnum, 00226 &list_lock); 00227 sidnum->sid = sid; 00228 sidnum->seen = 0; 00229 list_add(&sidnum->list, &filt->sids); 00230 } else { 00231 pat->has_nit = pid; 00232 dprintf2("found NIT at PID: %d", pid); 00233 } 00234 } 00235 return 0; 00236 } 00237 /* 00238 static int get_type(int type) 00239 { 00240 switch (type) { 00241 case 2: //video 00242 return 1; 00243 case 4: //audio 00244 return 0; 00245 } 00246 return 5; 00247 } 00248 */ 00249 unsigned char *parse_ca(unsigned char *buf, unsigned char *ca, int len) 00250 { 00251 unsigned char *ptr = buf; 00252 int count = 0; 00253 while (len >= 2) { 00254 count = 2 + *(ca +1 ); 00255 if (*ca != 0x09) { 00256 ca += count; 00257 len -= count; 00258 continue; 00259 } 00260 if(len < 0) 00261 return NULL; 00262 memcpy(ptr, ca, count); 00263 len -= count; 00264 ca += count; 00265 ptr += count; 00266 } 00267 return ptr; 00268 } 00269 00270 static int read_nit(unsigned char *buf, struct nit_data *nit, unsigned int size) { 00271 int len, tsl_len, td_len, tag_len, network_desc_len; 00272 int network_id, pos, tag; 00273 if (buf[0] != 0x40 && buf[0] != 0x41 && buf[0] != 0x72) { 00274 dprintf0( 00275 "read_nit expected table 0x40 or 0x41 but got 0x%02x\n", buf[0]); 00276 return -1; 00277 } 00278 if (buf[0] != 0x40) { 00279 return 0; 00280 } 00281 len = ((buf[1] & 0x07) << 8) | buf[2]; 00282 network_id = (buf[3]<<8) | buf[4]; 00283 network_desc_len = ((buf[8] & 0x0f) << 8) | buf[9]; 00284 tsl_len = ((buf[10+network_desc_len] & 0x0f) << 8) | buf[11+network_desc_len]; 00285 pos = 12+network_desc_len; 00286 while (pos-network_desc_len-12 < tsl_len - 6 && pos < len - 3) { 00287 td_len = ((buf[pos+4] & 0x0f) << 8) | buf[pos+5]; 00288 while (td_len > 0) { 00289 tag = buf[pos+6]; 00290 tag_len = buf[pos+7]; 00291 if(tag == 0x43 && tag_len >= 11) { //satellite descriptor 00292 nit->type = tag; 00293 nit->frequency = (buf[pos+8] << 24) | (buf[pos+9]<<16) | (buf[pos+10]<<8) | buf[pos+11]; 00294 nit->orbit = (buf[pos+12] << 8) | buf[pos+13]; 00295 nit->is_east = buf[pos+14] >> 7; 00296 nit->polarization = (buf[pos+14] >> 5) & 0x03; 00297 nit->modulation = buf[pos+14] & 0x1f; 00298 nit->symbolrate = (buf[pos+15]<<16) | (buf[pos+16]<<8) | buf[pos+17]; 00299 nit->fec = buf[pos+18]; 00300 printf("Orbit: %08x%c\n", nit->orbit, nit->is_east ? 'E' : 'W'); 00301 return 1; 00302 } else if(tag == 0x44 && tag_len >= 11) { //cable descriptor 00303 nit->type = tag; 00304 nit->frequency = (buf[pos+8] << 24) | (buf[pos+9]<<16) | (buf[pos+10]<<8) | buf[pos+11]; 00305 nit->modulation = buf[pos+14]; 00306 nit->symbolrate = (buf[pos+15]<<16) | (buf[pos+16]<<8) | buf[pos+17]; 00307 nit->fec = buf[pos+18]; 00308 printf("Cable: %08x\n", nit->frequency); 00309 return 1; 00310 } 00311 pos += tag_len+2; 00312 td_len -= tag_len+2; 00313 } 00314 pos += 6; 00315 } 00316 return 0; 00317 } 00318 00319 static bool cmp_wild(const char *pat, const char *s) 00320 { 00321 while(1) { 00322 if (!*s || !*pat) return *pat==*s; // true if length matched 00323 if (*pat!='?' && *pat!=*s) return false; 00324 pat++; s++; 00325 } 00326 } 00327 00328 static bool match_sid(int sid, const char *param) 00329 { 00330 bool ret = false; 00331 if (param) { 00332 char s_sid[32]; 00333 sprintf(s_sid,"%u",sid); 00334 00335 char *save, *ignored = strdup(param); 00336 char *tok = strtok_r(ignored, ",", &save); 00337 while(tok) { 00338 if (cmp_wild(tok,s_sid)) { 00339 ret = true; 00340 break; 00341 } 00342 tok = strtok_r(0, ",", &save); 00343 } 00344 free(ignored); 00345 } 00346 return ret; 00347 } 00348 00349 static int read_pmt(unsigned char *buf, struct filter *filt, 00350 struct sid_data *sid_data, unsigned int size) { 00351 // 00352 // NOTE we aren't using last_sec here yet! 00353 // 00354 struct sid *sid_ll; 00355 struct epid *epid_ll; 00356 struct sidnum *sidnum; 00357 00358 unsigned char *captr; 00359 unsigned int count, skip, pos; 00360 int sid, sec, last_sec, pcrpid, epid, type; 00361 if (buf[0] != 0x02) { 00362 dprintf0( 00363 "read_pmt expected table 0x02 but got 0x%02x\n", buf[0]); 00364 return -1; 00365 } 00366 count = (((buf[1] & 0x03) << 8) | buf[2]) + 3 - 4; 00367 sid = (buf[3] << 8) | buf[4]; 00368 sec = buf[6]; 00369 last_sec = buf[7]; 00370 pcrpid = ((buf[8] & 0x1F) << 8) | buf[9]; 00371 skip = ((buf[10] & 0x03) << 8) | buf[11]; 00372 if(skip > count - 12 || count > size) { 00373 dprintf0("skip: %d > count: %d - 12 || count > size: %d\n", 00374 skip, count, size); 00375 return -1; 00376 } 00377 00378 pop_entry_from_queue_l(sid_ll, &sid_empty_queue, struct sid, &list_lock); 00379 INIT_LIST_HEAD(&sid_ll->epid); 00380 00381 captr = parse_ca(sid_ll->ca, buf + 12, skip); 00382 if(captr == NULL) { 00383 dprintf0("Bad CA found\n"); 00384 free_sid(sid_ll); 00385 return -1; 00386 } 00387 dprintf3("read_pmt: sid: %d pcrpid: %d skip: %d count: %d\n", sid, pcrpid, skip, count); 00388 ll_find_elem(sidnum, filt->sids, sid, sid, struct sidnum); 00389 if(sidnum == NULL) { 00390 dprintf1("Sid %d is unexpected\n", sid); 00391 free_sid(sid_ll); 00392 return -1; 00393 } 00394 if (match_sid(sid,opt_ignore)) { 00395 dprintf0("Ignoring SID %d.\n", sid); 00396 free_sid(sid_ll); 00397 return -1; 00398 } 00399 if(sidnum->seen && !match_sid(sid,opt_unseen)) { 00400 dprintf0("Already seen sid: %d\n", sid); 00401 free_sid(sid_ll); 00402 return -1; 00403 } 00404 sidnum->seen = 1; 00405 sid_ll->sid = sid; 00406 for(pos = 12 + skip; pos < count;) { 00407 type = buf[pos]; 00408 epid = ((buf[pos+1] & 0x1F) << 8) | buf[pos+2]; 00409 skip = ((buf[pos+3] & 0x03) << 8) | buf[pos+4]; 00410 captr = parse_ca(captr, buf+pos+5, skip); 00411 pop_entry_from_queue_l(epid_ll, &epid_empty_queue, struct epid, &list_lock); 00412 00413 epid_ll->epid = epid; 00414 epid_ll->type = type; 00415 list_add_tail(&epid_ll->list, &sid_ll->epid); 00416 dprintf3("read_pmt: epid %d (type %d) mapped to sid %d\n", epid, type, sid); 00417 pos += 5 + skip; 00418 } 00419 sid_ll->calen = captr - sid_ll->ca; 00420 pthread_mutex_lock(&sid_data->mutex); 00421 if(! sid_data->has_map) { 00422 pthread_mutex_unlock(&sid_data->mutex); 00423 free_sid(sid_ll); 00424 return -1; 00425 } 00426 list_add(&sid_ll->list, &sid_data->sidlist); 00427 pthread_mutex_unlock(&sid_data->mutex); 00428 return 0; 00429 } 00430 00431 static int start(char *dmxdev, struct sid_data *sid_data, int timeout) { 00432 unsigned char pes[4096]; 00433 struct pollfd pfd, pollfd[MAX_SIMULTANEOUS_PMT]; 00434 int pat_restart = 0, done = 0, size, i; 00435 int ret; 00436 00437 struct pat pat; 00438 struct list_head *lptr; 00439 00440 restart: 00441 00442 bzero(&pat, sizeof(struct pat)); 00443 INIT_LIST_HEAD(&pat.dmx_filter_ll); 00444 pat.patfd = open(dmxdev, O_RDWR | O_NONBLOCK); 00445 if(pat.patfd < 0) { 00446 perror("start: open returned:"); 00447 free_pat(&pat); 00448 return 1; 00449 } 00450 if(add_pid(pat.patfd, 0x00)) { 00451 perror("start: failed to initialize pat demux:"); 00452 free_pat(&pat); 00453 return 1; 00454 } 00455 00456 pfd.fd = pat.patfd; 00457 pfd.events = POLLIN; 00458 pfd.revents = 0; 00459 while(! done) { 00460 if (poll(&pfd, 1, timeout) <= 0) continue; 00461 if ((size = read(pat.patfd, pes, sizeof(pes))) < 0) { 00462 dprintf0("start: pat read pes returned err: %d\n", errno); 00463 perror("start: pat read pes returned"); 00464 close(pat.patfd); 00465 free_pat(&pat); 00466 return 1; 00467 } 00469 if(read_pat(pes, &pat, size)) { 00470 close(pat.patfd); 00471 free_pat(&pat); 00472 return 1; 00473 } 00474 done = 1; 00475 for (int i = 0; i < MAX_PAT_SECTIONS; i++) { 00476 if(pat.section_seen == 0) { 00477 done = 0; 00478 break; 00479 } 00480 } 00481 } 00482 close(pat.patfd); 00483 00484 if(opt_orbit) { 00485 sid_data->nit.orbit = opt_orbit; 00486 pat.has_nit = 0; 00487 } 00488 00489 if(pat.has_nit) { 00490 int fd; 00491 fd=open(dmxdev, O_RDWR | O_NONBLOCK); 00492 if (fd <= 0) { 00493 dprintf0("start: Failed to open demux device for NIT!\n"); 00494 perror("demux open failed:"); 00495 } 00496 else if (add_pid(fd, pat.has_nit)) { 00497 char str[80]; 00498 sprintf(str, "start: Failed to initialize NIT demux"); 00499 perror(str); 00500 } else { 00501 pfd.fd = fd; 00502 pfd.events = POLLIN; 00503 pfd.revents = 0; 00504 done = 0; 00505 int nit_retries = 0; 00506 while(done <= 0) { 00507 if (poll(&pfd, 1, timeout) <= 0) continue; 00508 if ((size = read(fd, pes, sizeof(pes))) < 0) { 00509 dprintf0("start: nit read pes returned err: %d\n", errno); 00510 perror("start: nit read pes returned"); 00511 } 00512 done = read_nit(pes, &sid_data->nit, size); 00513 if (done <= 0) 00514 nit_retries++; 00515 if (nit_retries == 10) { 00516 if(++pat_restart<=opt_maxrestart) { 00517 dprintf0("start: giving up reading nit and restarting...\n"); 00518 close(fd); 00519 free_pat(&pat); 00520 done = 0; 00521 goto restart; 00522 } 00523 dprintf0("start: giving up reading nit\n"); 00524 done = 1; 00525 } 00526 } 00527 } 00528 close(fd); 00529 } 00530 00531 while(1) { 00532 int num_filters = 0, found = 0; 00533 ret = 0; 00534 00535 list_for_each(lptr, &pat.dmx_filter_ll) { 00536 struct filter *filt = list_entry(lptr, struct filter); 00537 if(filt->used) { 00538 if(filt->fd >0) { 00539 close(filt->fd); 00540 filt->fd = -1; 00541 } 00542 continue; 00543 } 00544 filt->fd=open(dmxdev, O_RDWR | O_NONBLOCK); 00545 if (filt->fd <= 0) { 00546 dprintf0("start: Failed to open %dth demux device!\n", num_filters); 00547 perror("demux open failed:"); 00548 ret = 1; 00549 break; 00550 } 00551 if (add_pid(filt->fd, filt->pid)) { 00552 char str[80]; 00553 sprintf(str, "start: Failed to initialize %dth pmt demux", num_filters); 00554 perror(str); 00555 close(filt->fd); 00556 filt->fd = -1; 00557 ret = 1; 00558 break; 00559 } 00560 filt->used = 1; 00561 num_filters++; 00562 if(num_filters >= opt_maxfilters) { 00563 ret = 1; 00564 break; 00565 } 00566 } 00567 00568 if(! num_filters) 00569 break; 00570 00571 dprintf2("Reading %d of %d filters\n", num_filters, opt_maxfilters); 00572 while(found != num_filters) { 00573 int count = 0; 00574 list_for_each(lptr, &pat.dmx_filter_ll) { 00575 struct filter *filt = list_entry(lptr, struct filter); 00576 if (filt->used && filt->fd > 0 && ! list_empty(&filt->sids)) { 00577 pollfd[count].fd=filt->fd; 00578 pollfd[count].events = POLLIN; 00579 pollfd[count].revents = 0; 00580 count++; 00581 } 00582 } 00583 dprintf3("polling %d fds\n", count); 00584 poll(pollfd, count, timeout); 00585 for(i = 0; i < count; i++) { 00586 if(! (pollfd[i].revents & POLLIN)) 00587 continue; 00588 // read pmt 00589 while((size = read(pollfd[i].fd, pes, sizeof(pes))) >= 3) { 00590 struct filter *filt; 00591 dprintf3("Read %d bytes\n", size); 00592 ll_find_elem(filt, pat.dmx_filter_ll, fd, pollfd[i].fd, struct filter); 00593 int ret = read_pmt(pes, filt, sid_data, size); 00594 if(ret < 0) { 00595 filt->parse_err++; 00596 if (filt->parse_err > opt_max_fail) 00597 goto exit; 00598 } 00599 if(ret == 0) { 00600 struct sidnum *sidnum; 00601 filt->parse_err = 0; 00602 ll_find_elem(sidnum, filt->sids, seen, 0, struct sidnum); 00603 if(sidnum == NULL) { 00604 found ++; 00605 break; 00606 } 00607 } else { 00608 pthread_mutex_lock(&sid_data->mutex); 00609 ret = ! sid_data->has_map; 00610 pthread_mutex_unlock(&sid_data->mutex); 00611 if(ret) 00612 goto exit; 00613 } 00614 } 00615 } 00616 pthread_mutex_lock(&sid_data->mutex); 00617 ret = ! sid_data->has_map; 00618 pthread_mutex_unlock(&sid_data->mutex); 00619 if(ret) 00620 goto exit; 00621 } 00622 } 00623 exit: 00624 free_pat(&pat); 00625 return ret; 00626 } 00627 00628 static int check_av(unsigned char type) { 00629 switch(type) { 00630 case MPEG1Video: 00631 case MPEG2Video: 00632 case MPEG4Video: 00633 case H264Video: 00634 case OpenCableVideo: 00635 return 1; 00636 case MPEG1Audio: 00637 case MPEG2Audio: 00638 case MPEG2AudioAmd1: 00639 case AACAudio: 00640 case AC3Audio: 00641 case DTSAudio: 00642 return 1; 00643 case MHEG: 00644 case H222_1: 00645 return 1; 00646 default: 00647 return 0; 00648 } 00649 return 0; 00650 } 00651 00652 struct sid* find_pid(struct list_head *sidlist, unsigned int pid) { 00653 struct list_head *ptr, *ptr1; 00654 struct sid *sid_ll; 00655 struct epid *epid_ll; 00656 list_for_each(ptr, sidlist) { 00657 sid_ll = list_entry(ptr, struct sid); 00658 list_for_each(ptr1, &sid_ll->epid) { 00659 epid_ll = list_entry(ptr1, struct epid); 00660 if(epid_ll->epid == pid) { 00661 if(opt_allpids || check_av(epid_ll->type)) { 00662 return sid_ll; 00663 } else { 00664 dprintf3("Skipping pid %d because type is %d\n", epid_ll->epid, 00665 epid_ll->type); 00666 return NULL; 00667 } 00668 } 00669 } 00670 } 00671 return NULL; 00672 } 00673 static void *read_sid(void *arg) 00674 { 00675 struct sid_data *sid_data = (struct sid_data *)arg; 00676 struct sid *sid_ll; 00677 struct dmxcmd *dmxcmd; 00678 char dmxdev[256]; 00679 int ret; 00680 00681 sprintf(dmxdev, "/dev/dvb/adapter%d/demux0", sid_data->common->real_adapt); 00682 pthread_mutex_lock(&sid_data->mutex); 00683 while(1) { 00684 while(1) { 00685 ll_find_elem(dmxcmd, sid_data->cmdqueue, checked, 0, struct dmxcmd); 00686 if(dmxcmd) { 00687 break; 00688 } 00689 pthread_cond_wait(&sid_data->cond, &sid_data->mutex); 00690 } 00691 //pop_entry_from_queue_l(dmxcmd, &sid_data->cmdqueue, struct dmxcmd, 00692 // &list_lock); 00693 //dmxcmd_stored = 0; 00694 if(dmxcmd->fd == -1 && dmxcmd->sid == 0 && dmxcmd->sid == NULL) 00695 return NULL; 00696 if(! sid_data->has_map) { 00697 //Try to read pmt, use a short-timeout in case the lock 00698 //hasn't happened yet 00699 pthread_mutex_unlock(&sid_data->mutex); 00700 dprintf2("Got Start!\n"); 00701 //set has_map first, since it could get invalidated... 00702 sid_data->has_map = 1; 00703 ret = start(dmxdev, sid_data, 200 /*ms*/); 00704 dprintf2("returned: %d\n", ret); 00705 if(ret) 00706 usleep(200000); /*200ms*/ 00707 pthread_mutex_lock(&sid_data->mutex); 00708 if(ret || sid_data->has_map == 0) { 00709 sid_data->has_map = 0; 00710 while(! list_empty(&sid_data->sidlist)) { 00711 sid_ll = list_entry(sid_data->sidlist.next, struct sid); 00712 list_del(&sid_ll->list); 00713 free_sid(sid_ll); 00714 } 00715 } 00716 //We skip processing in case the dmx was closed while pmt parsing 00717 continue; 00718 } 00719 dprintf2("Got Pid: %d\n", dmxcmd->pid); 00720 dmxcmd->checked = 1; 00721 if((sid_ll = find_pid(&sid_data->sidlist, dmxcmd->pid))) { 00722 dprintf1("Found sid: %lu\n", sid_ll->sid); 00723 dmxcmd->sid = sid_ll; 00724 if (sid_data->sendmsg) { 00725 struct list_head *lptr; 00726 struct sid_msg *sidmsg; 00727 struct epid *epid; 00728 int count = 0; 00729 //Duplicate dmxcmds to prevent a race 00730 pop_entry_from_queue_l(sidmsg, &sidmsg_empty_queue, struct sid_msg, 00731 &list_lock); 00732 sidmsg->sid = dmxcmd->sid->sid; 00733 sidmsg->calen = dmxcmd->sid->calen; 00734 memcpy(sidmsg->ca, dmxcmd->sid->ca, dmxcmd->sid->calen); 00735 list_for_each(lptr, &dmxcmd->sid->epid) { 00736 epid = list_entry(lptr, struct epid); 00737 sidmsg->epid[count] = epid->epid; 00738 sidmsg->epidtype[count] = epid->type; 00739 count++; 00740 } 00741 sidmsg->epid_count = count; 00742 sidmsg->nit = sid_data->nit; 00743 msg_send(MSG_LOW_PRIORITY, MSG_ADDSID, sid_data->common->real_adapt, 00744 sidmsg); 00745 } else { 00746 dprintf0("Didn't find sid for pid: %d\n", dmxcmd->pid); 00747 } 00748 } 00749 } 00750 } 00751 00752 static struct sid_data *find_siddata_from_pc(struct parser_cmds *pc) 00753 { 00754 struct list_head *ptr; 00755 list_for_each(ptr, &getsidlist) { 00756 struct sid_data *sid_data = list_entry(ptr, struct sid_data); 00757 if(sid_data->common == pc->common) 00758 return sid_data; 00759 } 00760 return NULL; 00761 } 00762 00763 static void clear_sid_data(struct sid_data *sid_data) 00764 { 00765 int adapt; 00766 struct sid *sid_ll; 00767 struct dmxcmd *dmxcmd; 00768 00769 00770 adapt = sid_data->common->real_adapt; 00771 while(! list_empty(&sid_data->sidlist)) { 00772 sid_ll = list_entry(sid_data->sidlist.next, struct sid); 00773 list_del(&sid_ll->list); 00774 free_sid(sid_ll); 00775 } 00776 00777 //reset queued pids 00778 { 00779 struct list_head *lptr; 00780 list_for_each(lptr, &sid_data->cmdqueue) { 00781 dmxcmd = list_entry(lptr, struct dmxcmd); 00782 dmxcmd->checked = 0; 00783 dmxcmd->sid = NULL; 00784 } 00785 } 00786 //force a rescan of pmts 00787 sid_data->has_map = 0; 00788 00789 pthread_cond_signal(&sid_data->cond); 00790 } 00791 00792 static void fe_tune(struct parser_cmds *pc, struct poll_ll *fdptr, 00793 cmdret_t *result, int *ret, 00794 unsigned long int cmd, unsigned char *data) 00795 { 00796 struct sid_data *sid_data; 00797 int adapt; 00798 00799 sid_data = find_siddata_from_pc(pc); 00800 adapt = sid_data->common->real_adapt; 00801 if(sid_data == NULL) 00802 return; 00803 00804 if(cmd == FE_SET_FRONTEND || cmd == FE_SET_FRONTEND2) { 00805 dprintf0("Tuning frontend\n"); 00806 if(memcmp(&sid_data->tunecache, data, sizeof(struct dvb_frontend_parameters))) { 00807 pthread_mutex_lock(&sid_data->mutex); 00808 memcpy(&sid_data->tunecache, data, sizeof(struct dvb_frontend_parameters)); 00809 if(sid_data->sendmsg) { 00810 msg_remove_type_from_list(MSG_LOW_PRIORITY, MSG_ADDSID, adapt, 00811 free_addsid_msg); 00812 msg_remove_type_from_list(MSG_LOW_PRIORITY, MSG_REMOVESID, adapt, NULL); 00813 msg_remove_type_from_list(MSG_LOW_PRIORITY, MSG_RESETSID, adapt, NULL); 00814 } 00815 msg_send(MSG_LOW_PRIORITY, MSG_RESETSID, adapt, NULL); 00816 00817 clear_sid_data(sid_data); 00818 00819 pthread_mutex_unlock(&sid_data->mutex); 00820 } else { 00821 dprintf0("Skipping cache reset since tuning matches last tune\n"); 00822 if(opt_experimental) 00823 *result = CMD_SKIPCALL; 00824 } 00825 #if DVB_API_VERSION >=5 00826 } else if (cmd == FE_SET_PROPERTY) { 00827 dprintf0("Tuning frontend (new)\n"); 00828 pthread_mutex_lock(&sid_data->mutex); 00829 if(sid_data->sendmsg) { 00830 msg_remove_type_from_list(MSG_LOW_PRIORITY, MSG_ADDSID, adapt, 00831 free_addsid_msg); 00832 msg_remove_type_from_list(MSG_LOW_PRIORITY, MSG_REMOVESID, adapt, NULL); 00833 msg_remove_type_from_list(MSG_LOW_PRIORITY, MSG_RESETSID, adapt, NULL); 00834 } 00835 msg_send(MSG_LOW_PRIORITY, MSG_RESETSID, adapt, NULL); 00836 clear_sid_data(sid_data); 00837 pthread_mutex_unlock(&sid_data->mutex); 00838 memset(&sid_data->tunecache, 0, sizeof(struct dvb_frontend_parameters)); 00839 #endif 00840 } else if(cmd == FE_DISEQC_SEND_MASTER_CMD 00841 || cmd == FE_DISEQC_SEND_BURST 00842 || cmd == FE_SET_TONE 00843 || cmd == FE_SET_VOLTAGE 00844 #ifdef FE_SET_STANDARD 00845 || cmd == FE_SET_STANDARD 00846 #endif 00847 #ifdef FE_DISHNETWORK_SEND_LEGACY_CMD 00848 || cmd == FE_DISHNETWORK_SEND_LEGACY_CMD 00849 #endif 00850 ) 00851 { 00852 dprintf0("Clearing tuning cache due to switch cmd\n"); 00853 memset(&sid_data->tunecache, 0, sizeof(struct dvb_frontend_parameters)); 00854 } 00855 } 00856 00857 static void fe_close(struct parser_cmds *pc, struct poll_ll *fdptr, 00858 cmdret_t *result, int *ret, 00859 unsigned long int cmd, unsigned char *data) 00860 { 00861 struct sid_data *sid_data; 00862 int adapt; 00863 00864 sid_data = find_siddata_from_pc(pc); 00865 adapt = sid_data->common->real_adapt; 00866 00867 if(sid_data == NULL) 00868 return; 00869 00870 if((fdptr->flags & O_ACCMODE) == O_RDONLY) 00871 return; 00872 00873 pthread_mutex_lock(&sid_data->mutex); 00874 if(sid_data->sendmsg) { 00875 msg_remove_type_from_list(MSG_LOW_PRIORITY, MSG_ADDSID, adapt, 00876 free_addsid_msg); 00877 msg_remove_type_from_list(MSG_LOW_PRIORITY, MSG_REMOVESID, adapt, NULL); 00878 msg_remove_type_from_list(MSG_LOW_PRIORITY, MSG_RESETSID, adapt, NULL); 00879 } 00880 msg_send(MSG_LOW_PRIORITY, MSG_RESETSID, adapt, NULL); 00881 pthread_mutex_unlock(&sid_data->mutex); 00882 } 00883 00884 //if a demux is closed, we really don't want to clear the pid<->sid map 00885 //insead we should only do something when a mapped pid is closed, and the 00886 //'something' should be to invalidate the associated sid 00887 static void close_demux(struct parser_cmds *pc, struct poll_ll *fdptr, 00888 cmdret_t *result, int *ret, 00889 unsigned long int cmd, unsigned char *data) 00890 { 00891 struct sid_data *sid_data; 00892 struct dmxcmd *dmxcmd, *tmpdmx; 00893 00894 sid_data = find_siddata_from_pc(pc); 00895 if(sid_data == NULL) 00896 return; 00897 00898 pthread_mutex_lock(&sid_data->mutex); 00899 //if(sid_data->sendmsg) 00900 //remove only GETSID on this demux! 00901 //msg_remove_type_from_list(MSG_LOW_PRIORITY, MSG_ADDSID, free_addsid_msg); 00902 00903 //removed this fd from the cmdqueue 00904 ll_find_elem(dmxcmd, sid_data->cmdqueue, fd, fdptr->fd, struct dmxcmd); 00905 if(dmxcmd) { 00906 list_del(&dmxcmd->list); 00907 if(dmxcmd->checked && dmxcmd->sid) { 00908 msg_send(MSG_LOW_PRIORITY, MSG_REMOVESID, sid_data->common->real_adapt, 00909 (void *)(dmxcmd->sid->sid)); 00910 //check that this sid is no longer being viewed 00911 ll_find_elem(tmpdmx, sid_data->cmdqueue, sid, dmxcmd->sid, struct dmxcmd); 00912 if(! tmpdmx) { 00913 sid_data->removed_sid = 1; 00914 } 00915 } 00916 list_add_l(&dmxcmd->list, &dmxcmd_empty_queue, &list_lock); 00917 } 00918 pthread_mutex_unlock(&sid_data->mutex); 00919 } 00920 00921 static void set_demux(struct parser_cmds *pc, struct poll_ll *fdptr, 00922 cmdret_t *result, int *ret, 00923 unsigned long int cmd, unsigned char *data) 00924 { 00925 struct sid_data *sid_data; 00926 struct dmxcmd *dmxcmd; 00927 int pid; 00928 00929 sid_data = find_siddata_from_pc(pc); 00930 if(sid_data == NULL) 00931 return; 00932 00933 if(cmd == DMX_SET_PES_FILTER) { 00934 pid = *(unsigned short *)data; //get pid from *filter_params 00935 pthread_mutex_lock(&sid_data->mutex); 00936 00937 if(opt_resetpidmap && sid_data->removed_sid) { 00938 sid_data->removed_sid = 0; 00939 //NOTE: If this occurs while a 'ADD_SID' is in the message queue, 00940 //then the message will be corrupted! We should deep-copy the epids 00941 clear_sid_data(sid_data); 00942 } 00943 00944 //Make sure we didn't just change pids on the same fd 00945 ll_find_elem(dmxcmd, sid_data->cmdqueue, fd, fdptr->fd, struct dmxcmd); 00946 if(dmxcmd) { 00947 if(dmxcmd->sid) 00948 msg_send(MSG_LOW_PRIORITY, MSG_REMOVESID, sid_data->common->real_adapt, 00949 (void *)(dmxcmd->sid->sid)); 00950 list_del(&dmxcmd->list); 00951 list_add_l(&dmxcmd->list, &dmxcmd_empty_queue, &list_lock); 00952 } 00953 00954 pop_entry_from_queue_l(dmxcmd, &dmxcmd_empty_queue, struct dmxcmd, 00955 &list_lock); 00956 dmxcmd->pid = pid; 00957 dmxcmd->fd = fdptr->fd; 00958 dmxcmd->sid = NULL; 00959 dmxcmd->checked = 0; 00960 list_add_tail(&dmxcmd->list, &sid_data->cmdqueue); 00961 00962 dprintf1("Sending PID: %d\n", pid); 00963 pthread_cond_signal(&sid_data->cond); 00964 pthread_mutex_unlock(&sid_data->mutex); 00965 } 00966 } 00967 00968 static void enable_msg(struct parser_cmds *pc, int enable) 00969 { 00970 struct sid_data *sid_data = find_siddata_from_pc(pc); 00971 if(sid_data) 00972 sid_data->sendmsg = enable; 00973 } 00974 00975 static void connect_sid(struct parser_adpt *pc_all) 00976 { 00977 struct sid_data *sid_data; 00978 00979 sid_data = (struct sid_data *)malloc(sizeof(struct sid_data)); 00980 if(! sid_data) 00981 return; 00982 bzero(sid_data, sizeof(struct sid_data)); 00983 //these shouldn't be needed 00984 sid_data->sendmsg = 0; 00985 sid_data->has_map = 0; 00986 sid_data->common = pc_all->frontend->common; 00987 pthread_mutex_init(&sid_data->mutex, NULL); 00988 pthread_cond_init(&sid_data->cond, NULL); 00989 INIT_LIST_HEAD(&sid_data->sidlist); 00990 INIT_LIST_HEAD(&sid_data->cmdqueue); 00991 if(opt_experimental) { 00992 ATTACH_CALLBACK(&pc_all->frontend->pre_ioctl, fe_tune, -1); 00993 } else { 00994 ATTACH_CALLBACK(&pc_all->frontend->post_ioctl, fe_tune, -1); 00995 } 00996 ATTACH_CALLBACK(&pc_all->frontend->post_close, fe_close, -1); 00997 ATTACH_CALLBACK(&pc_all->demux->post_ioctl, set_demux, -1); 00998 ATTACH_CALLBACK(&pc_all->demux->post_close, close_demux, -1); 00999 list_add_tail(&sid_data->list, &getsidlist); 01000 } 01001 01002 static void launch_sid() 01003 { 01004 struct list_head *ptr; 01005 list_for_each(ptr, &getsidlist) { 01006 struct sid_data *sid_data = list_entry(ptr, struct sid_data); 01007 pthread_create(&sid_data->thread, &default_attr, read_sid, sid_data); 01008 } 01009 } 01010 01011 static void shutdown_sid() 01012 { 01013 struct dmxcmd *dmxcmd; 01014 struct list_head *ptr; 01015 list_for_each(ptr, &getsidlist) { 01016 struct sid_data *sid_data = list_entry(ptr, struct sid_data); 01017 if(sid_data->thread) { 01018 pthread_mutex_lock(&sid_data->mutex); 01019 pop_entry_from_queue_l(dmxcmd, &dmxcmd_empty_queue, struct dmxcmd, 01020 &list_lock); 01021 dmxcmd->pid = 0; 01022 dmxcmd->fd = -1; //Send a terminate command 01023 dmxcmd->sid = NULL; 01024 dmxcmd->checked = 0; 01025 list_add(&dmxcmd->list, &sid_data->cmdqueue); 01026 pthread_cond_signal(&sid_data->cond); 01027 pthread_mutex_unlock(&sid_data->mutex); 01028 pthread_join(sid_data->thread, NULL); 01029 } 01030 } 01031 } 01032 01033 static struct option *parseopt_sid(arg_enum_t cmd) 01034 { 01035 if(cmd == ARG_INIT) { 01036 return Sid_Opts; 01037 } 01038 if(cmd == ARG_HELP) { 01039 printf(" --sid-filt <num> : Maximum number of open filters (default 2)\n"); 01040 printf(" --sid-allpid : Parse all pids instead of just A/V\n"); 01041 printf(" --sid-ignore <sid1,sid2,...>\n"); 01042 printf(" : When tuning, ignore given SIDs\n"); 01043 printf(" --sid-unseen <sid1,sid2,...>\n"); 01044 printf(" : When tuning, treat given SIDs as unseen allways\n"); 01045 printf(" --sid-nocache : Don't cache pid<->sid mapping\n"); 01046 printf(" --sid-orbit <val> : Set the satellit orbit to 'val' and don't scan the NIT\n"); 01047 printf(" --sid-experimental: Enable experimental tuning code\n"); 01048 printf(" --sid-restart <n> : Max number of PAT/NIT read restarts\n"); 01049 } 01050 if(! sid_opt) 01051 return NULL; 01052 01053 switch(sid_opt) { 01054 case 'f': 01055 opt_maxfilters = atoi(optarg); 01056 if (opt_maxfilters < 1) 01057 opt_maxfilters = 1; 01058 else if (opt_maxfilters > MAX_SIMULTANEOUS_PMT) 01059 opt_maxfilters = MAX_SIMULTANEOUS_PMT; 01060 break; 01061 case 'p': 01062 opt_allpids = 1; 01063 break; 01064 case 'o': 01065 opt_orbit = strtol(optarg, NULL, 0); 01066 break; 01067 case 'c': 01068 opt_resetpidmap = 1; 01069 break; 01070 case 'e': 01071 opt_experimental = 1; 01072 break; 01073 case 'i': 01074 opt_ignore = optarg; 01075 break; 01076 case 'u': 01077 opt_unseen = optarg; 01078 break; 01079 case 'r': 01080 opt_maxrestart = atoi(optarg); 01081 break; 01082 } 01083 //must reset sid_opt after every call 01084 sid_opt = 0; 01085 return NULL; 01086 } 01087 01088 //list, plugin_id, name, parse_args, connect, launch, message, send_msg 01089 static struct plugin_cmd plugin_cmds = {{NULL, NULL}, PLUGIN_ID, "channel", 01090 parseopt_sid, connect_sid, launch_sid, NULL, enable_msg, 01091 shutdown_sid, NULL}; 01092 int __attribute__((constructor)) __getsid_init(void) 01093 { 01094 list_add(&plugin_cmds.list, &plugin_cmdlist); 01095 return 0; 01096 }