|
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 <errno.h> 00026 #include <assert.h> 00027 #include <sys/mman.h> 00028 #include <sys/poll.h> 00029 #include <sys/ioctl.h> 00030 #include <sys/timeb.h> 00031 #include <signal.h> 00032 #include <string.h> 00033 #include <getopt.h> 00034 #include <unistd.h> 00035 #include "process_req.h" 00036 #include "plugin_ringbuf.h" 00037 #include "msg_passing.h" 00038 00039 #define PLUGIN_ID PLUGIN_RINGBUF 00040 #define DBG_NAME "RINGBUF" 00041 #include "debug.h" //This is required to happen AFTER PLUGIN_ID is defined 00042 00043 //#define CHECK_READ_OK 00044 //#define POLL_WORKS 00045 00046 //defining WRITE_RAW_DVR will creat /tmp/rawdvr.mpg and write out all data 00047 //read from the 'real' dvr to that file 00048 //#define WRITE_RAW_DVR 00049 #ifdef WRITE_RAW_DVR 00050 static int rawdvr; 00051 #endif 00052 00053 static LIST_HEAD(ringbuflist); 00054 static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER; 00055 static int rb_sendmsg; 00056 static int (* rb_check_read_callback)(struct ringbuffer *, int) = NULL; 00057 #define min(a,b) ((a) < (b) ? (a) : (b)) 00058 inline int min1(int a, int b) { return min(a, b); } 00059 unsigned int mtime() { 00060 struct timeb tp; 00061 unsigned int time0; 00062 ftime(&tp); 00063 time0 = tp.time * 1000 + tp.millitm; 00064 return time0; 00065 } 00066 00067 static int rb_max_free(struct ringbuffer *rb) 00068 { 00069 int allowed_bytes; 00070 if(rb->wrPtr >= rb->rdPtr) 00071 allowed_bytes = rb->end - rb->wrPtr + min1(rb->rdPtr - rb->buffer, rb->reserved) - TSPacketSIZE; 00072 else 00073 allowed_bytes = rb->rdPtr - rb->wrPtr - TSPacketSIZE; 00074 return allowed_bytes; 00075 } 00076 00077 static int rb_free(struct ringbuffer *rb, int numbytes) 00078 { 00079 return (rb_max_free(rb) >= numbytes); 00080 } 00081 00082 static int rb_avail(struct ringbuffer *rb, int numbytes) 00083 { 00084 int avail_bytes; 00085 if(rb->rdPtr > rb->wrPtr) 00086 avail_bytes = rb->end - rb->rdPtr + rb->wrPtr - rb->buffer - TSPacketSIZE; 00087 else 00088 avail_bytes = rb->wrPtr - rb->rdPtr - TSPacketSIZE; 00089 if (avail_bytes && avail_bytes >= numbytes && rb_check_read_callback) { 00090 avail_bytes = rb_check_read_callback(rb, numbytes); 00091 } 00092 return (avail_bytes); 00093 } 00094 00095 static void rb_fill_bytes(struct ringbuffer *rb, int numbytes) { 00096 int bytes; 00097 unsigned char *newptr; 00098 //printf("Start read on dvr t:%lu\n", pthread_self()); 00099 //wrPtr must always be an integer number of packets! 00100 numbytes -= numbytes % TSPacketSIZE; 00101 bytes = read(rb->fd, rb->wrPtr, numbytes); 00102 //printf("Read done\n"); 00103 if (bytes <= 0) { 00104 if (!(rb->flags & O_NONBLOCK)) 00105 perror("Read Failed"); 00106 return; 00107 } 00108 #ifdef WRITE_RAW_DVR 00109 write(rawdvr, rb->wrPtr, bytes); 00110 #endif 00111 newptr = rb->wrPtr + bytes; 00112 if (newptr > rb->end) 00113 memcpy(rb->buffer, rb->end, newptr - rb->end); 00114 if (newptr >= rb->end) 00115 newptr = rb->buffer + (newptr - rb->end); 00116 00117 pthread_mutex_lock(&rb->rw_lock); 00118 rb->wrPtr = newptr; 00119 pthread_mutex_unlock(&rb->rw_lock); 00120 if(rb_sendmsg) 00121 msg_replace(MSG_HIGH_PRIORITY, MSG_RINGBUF, rb->num, rb); 00122 } 00123 00124 static int rb_fill_bytes_block(struct ringbuffer *rb, int numbytes) { 00125 int bytes = 0, ret, size; 00126 unsigned char *newptr; 00127 struct pollfd ufd[2]; 00128 ufd[0].fd = rb->fd; 00129 ufd[0].events = POLLIN | POLLPRI; 00130 ufd[1].fd = rb->virtfd; 00131 ufd[1].events = POLLIN | POLLPRI; 00132 //printf("Start read on dvr t:%lu\n", pthread_self()); 00133 //wrPtr must always be an integer number of packets! 00134 numbytes -= numbytes % TSPacketSIZE; 00135 while( bytes < numbytes && (size = rb_max_free(rb)) > 0) { 00136 dprintf1("Starting loop %d of %d\n", bytes, numbytes); 00137 //poll dvr fd and dvblb fd 00138 ufd[0].revents = 0; 00139 ufd[1].revents = 0; 00140 if(poll(&ufd[0], 2, -1) < 0 || ufd[1].revents) { 00141 //We should abort 00142 dprintf0("Aborting block read!\n"); 00143 return (errno ? errno : EFAULT); 00144 } 00145 //opportunistically read as many bytes as possible 00146 ret = read(rb->fd, rb->wrPtr, size); 00147 if (ret <= 0) { 00148 break; 00149 } 00150 #ifdef WRITE_RAW_DVR 00151 write(rawdvr, rb->wrPtr, ret); 00152 #endif 00153 bytes += ret; 00154 newptr = rb->wrPtr + ret; 00155 if (newptr > rb->end) 00156 memcpy(rb->buffer, rb->end, newptr - rb->end); 00157 if (newptr >= rb->end) 00158 newptr = rb->buffer + (newptr - rb->end); 00159 00160 pthread_mutex_lock(&rb->rw_lock); 00161 rb->wrPtr = newptr; 00162 pthread_mutex_unlock(&rb->rw_lock); 00163 } 00164 if(bytes && rb_sendmsg) 00165 msg_replace(MSG_HIGH_PRIORITY, MSG_RINGBUF, rb->num, rb); 00166 return 0; 00167 } 00168 00169 static void rb_get_bytes(struct ringbuffer *rb, unsigned char *ptr, 00170 int numbytes) 00171 { 00172 unsigned char *newptr; 00173 newptr = rb->rdPtr; 00174 if (newptr + numbytes > rb->end) { 00175 memcpy(ptr, newptr, rb->end - newptr); 00176 numbytes -= rb->end - newptr; 00177 ptr += rb->end - newptr; 00178 newptr = rb->buffer; 00179 } 00180 memcpy(ptr, newptr, numbytes); 00181 pthread_mutex_lock(&rb->rw_lock); 00182 rb->rdPtr = newptr + numbytes; 00183 pthread_mutex_unlock(&rb->rw_lock); 00184 } 00185 00186 static struct ringbuffer *find_rb_from_pc(struct parser_cmds *pc) { 00187 struct list_head *ptr; 00188 int num = pc->common->virt_adapt; 00189 list_for_each(ptr, &ringbuflist) { 00190 struct ringbuffer *rb = list_entry(ptr, struct ringbuffer); 00191 if (rb->num == num) 00192 return rb; 00193 } 00194 return NULL; 00195 } 00196 00197 static void rb_release(struct ringbuffer *rb) 00198 { 00199 dprintf1("Releasing ringbuffer: %d\n", rb->num); 00200 if(rb->state != RB_CLOSING) { 00201 dprintf0("Ringbuffer state should have been RB_CLOSING but was '%d;'\n", 00202 rb->state); 00203 } 00204 pthread_mutex_lock(&list_lock); 00205 rb->state = RB_CLOSED; 00206 pthread_mutex_unlock(&list_lock); 00207 #ifdef WRITE_RAW_DVR 00208 close(rawdvr); 00209 #endif 00210 } 00211 00212 static void open_call(struct parser_cmds *pc, struct poll_ll *fdptr, 00213 cmdret_t *result, int *ret, 00214 unsigned long int cmd, unsigned char *data) 00215 { 00216 char realdev[256]; 00217 00218 struct ringbuffer *rb = find_rb_from_pc(pc); 00219 if(! rb) 00220 return; 00221 00222 *result = CMD_SKIPCALL; 00223 if(rb->state == RB_OPEN) { 00224 dprintf0("Cannot open dvr; it is already open.\n"); 00225 fdptr->fd = -EMFILE; 00226 return; 00227 } 00228 while(rb->state == RB_CLOSING) { 00229 //This isn't ideal, but the situation shouldn't last too long 00230 sched_yield(); 00231 } 00232 sprintf(realdev, "/dev/dvb/adapter%d/%s0", pc->common->real_adapt, 00233 dnames[pc->type]); 00234 //we need to open nonblocking so we never get deadlocked 00235 fdptr->fd = open(realdev, fdptr->flags | O_NONBLOCK); 00236 if(fdptr->fd < 0) { 00237 fdptr->fd = -errno; 00238 perror("Failed to open dvr"); 00239 return; 00240 } 00241 00242 rb->virtfd = pc->virtfd; 00243 rb->fd = fdptr->fd; 00244 rb->flags = fdptr->flags; 00245 rb->rdPtr = rb->wrPtr = rb->buffer; 00246 pthread_mutex_lock(&list_lock); 00247 rb->state = RB_OPEN; 00248 rb->readok = 0; 00249 pthread_mutex_unlock(&list_lock); 00250 dprintf1("Creating ringbuffer: %d\n", rb->num); 00251 #ifdef WRITE_RAW_DVR 00252 rawdvr = open("/tmp/rawdvr.mpg", O_WRONLY | O_CREAT | O_TRUNC, 0666); 00253 #endif 00254 } 00255 00256 static void close_call(struct parser_cmds *pc, struct poll_ll *fdptr, 00257 cmdret_t *result, int *ret, 00258 unsigned long int cmd, unsigned char *data) 00259 { 00260 struct ringbuffer *rb = find_rb_from_pc(pc); 00261 if(rb == NULL || rb->state != RB_OPEN) 00262 return; 00263 pthread_mutex_lock(&list_lock); 00264 rb->state = RB_CLOSING; 00265 pthread_mutex_unlock(&list_lock); 00266 //NOTE: need to use high priority queue to prevent a read/close race 00267 //MSG_RINGCLOSE MUST release the ringbuffer! 00268 if(rb_sendmsg) 00269 msg_replace(MSG_HIGH_PRIORITY, MSG_RINGCLOSE, rb->num, rb); 00270 else 00271 rb_release(rb); 00272 } 00273 00274 static void poll_call(struct parser_cmds *pc, struct poll_ll *fdptr, 00275 cmdret_t *result, int *ret, 00276 unsigned long int cmd, unsigned char *data) 00277 { 00278 struct dvblb_custommsg *ci = (struct dvblb_custommsg *)data; 00279 int avail; 00280 struct ringbuffer *rb = find_rb_from_pc(pc); 00281 00282 if(! rb || rb->state != RB_OPEN) 00283 { 00284 dprintf0("Shouldn't be here!\n"); 00285 rb->readok = (*ret ? 1 : 0); 00286 return; 00287 } 00288 if(*ret) { 00289 //oportunistically fill the buffer, doesn't matter if we're blocking or not 00290 rb_fill_bytes(rb, rb_max_free(rb)); 00291 } 00292 avail = rb_avail(rb, 0); 00293 if(avail > 0) { 00294 *ret = 1; 00295 ci->u.mode |= POLLIN; 00296 rb->readok = 1; 00297 } else { 00298 *ret = 0; 00299 ci->u.mode &= ~(POLLIN | POLLPRI); 00300 rb->readok = 0; 00301 } 00302 } 00303 00304 static void read_call(struct parser_cmds *pc, struct poll_ll *fdptr, 00305 cmdret_t *result, int *ret, 00306 unsigned long int cmd, unsigned char *data) 00307 { 00308 struct dvblb_custommsg *ci = (struct dvblb_custommsg *)data; 00309 unsigned int trybytes, small = TSPacketSIZE * 1; 00310 int avail, err; 00311 struct ringbuffer *rb = find_rb_from_pc(pc); 00312 00313 if(! rb || rb->state != RB_OPEN) 00314 return; 00315 00316 *result = CMD_SKIPCALL; 00317 // ci->u.count -= ci->u.count % TSPacketSIZE; 00318 //trybytes must be multiple of TSPacketSIZE and > 0 00319 trybytes = ci->u.count % TSPacketSIZE; 00320 if(trybytes) 00321 trybytes = ci->u.count + TSPacketSIZE - trybytes; 00322 else 00323 trybytes = ci->u.count; 00324 avail = rb_avail(rb, 0); 00325 if (rb->flags & O_NONBLOCK) { 00326 if (avail > 0) { 00327 if ((unsigned int)avail > ci->u.count) 00328 avail = ci->u.count ; 00329 else 00330 ci->u.count = avail; 00331 rb_get_bytes(rb, pc->mmap, avail); 00332 *ret = ci->u.count; 00333 } else { 00334 #ifdef CHECK_READ_OK 00335 assert(rb->readok != 1); 00336 #endif 00337 *ret = -EAGAIN; 00338 } 00339 rb->readok = 0; 00340 rb_fill_bytes(rb, rb_max_free(rb)); 00341 return; 00342 } 00343 //Blocking read 00344 if(avail > 0 && (unsigned int)avail >= ci->u.count) { 00345 // enough bytes can be read from ring buffer 00346 rb_get_bytes(rb, pc->mmap, ci->u.count); 00347 if((unsigned int)avail > ci->u.count * 16) 00348 trybytes = ci->u.count >> 2; 00349 else if((unsigned int)avail > ci->u.count * 4) 00350 trybytes = ci->u.count >> 1; 00351 if (trybytes >= TSPacketSIZE) { 00352 //NOTE: because trybytes < ci->u.count, and we just read 00353 // ci->u.count bytes from the ringbuffer, we KNOW that 00354 // there is room to read at least trybytes into the buffer 00355 trybytes -= trybytes % TSPacketSIZE; 00356 if((err = rb_fill_bytes_block(rb, trybytes)) != 0) { 00357 *ret = -err; 00358 return; 00359 } 00360 } 00361 *ret = ci->u.count; 00362 return; 00363 } 00364 // not enough bytes can be read from ring buffer 00365 while(1) { 00366 if(rb_free(rb, trybytes)) { 00367 //the ring buffer has room to get 'trybytes' bytes 00368 printf("Buffer has room, reading %d bytes\n", trybytes); 00369 if((err = rb_fill_bytes_block(rb, trybytes)) != 0) { 00370 *ret = -err; 00371 return; 00372 } 00373 if(trybytes < ci->u.count) 00374 sched_yield(); //give up the rest of our timeslice 00375 } else { 00376 // signal decryptor 00377 // wait for decryptor 00378 dprintf0("Buffer is full, waiting for decode on %d bytes\n", trybytes); 00379 rb_avail(rb, ci->u.count); 00380 } 00381 if (rb_avail(rb, 0) >= (int)ci->u.count) { 00382 // enough bytes can be read from ring buffer 00383 rb_get_bytes(rb, pc->mmap, ci->u.count); 00384 *ret = ci->u.count; 00385 printf("Returning %d\n", *ret); 00386 return; 00387 } 00388 trybytes = small; 00389 } 00390 } 00391 00392 static void enable_msg(struct parser_cmds *pc, int enable) 00393 { 00394 rb_sendmsg = enable; 00395 } 00396 00397 void ringbuf_register_callback(int (* cb)(struct ringbuffer *, int)) { 00398 rb_check_read_callback = cb; 00399 } 00400 00401 static void connect_rb(struct parser_adpt *pc_all) { 00402 struct ringbuffer *rb; 00403 00404 unsigned long rbsize = (1 + pc_all->dvr->common->buffersize / TSPacketSIZE) 00405 * TSPacketSIZE; 00406 unsigned long rbextra = rbsize / 20; 00407 rb = (struct ringbuffer *)malloc(sizeof(struct ringbuffer)+rbsize+rbextra); 00408 memset(rb, 0, sizeof(struct ringbuffer)); 00409 pthread_mutex_init(&rb->rw_lock, NULL); 00410 rb->release = rb_release; 00411 rb->num = pc_all->dvr->common->virt_adapt; 00412 rb->buffer = (unsigned char *)&rb->buffer + sizeof(rb->buffer); 00413 rb->end = rb->buffer + rbsize; 00414 rb->state = RB_CLOSED; 00415 rb->reserved = rbextra; 00416 list_add_tail(&rb->list, &ringbuflist); 00417 00418 ATTACH_CALLBACK(&pc_all->dvr->pre_open, open_call, -1); 00419 ATTACH_CALLBACK(&pc_all->dvr->pre_close, close_call, -1); 00420 ATTACH_CALLBACK(&pc_all->dvr->post_poll, poll_call, -1); 00421 ATTACH_CALLBACK(&pc_all->dvr->pre_read, read_call, -1); 00422 } 00423 00424 //list, plugin_id, name, parse_args, connect, launch, message, send_msg 00425 static struct plugin_cmd plugin_cmds = {{NULL, NULL}, PLUGIN_RINGBUF, 00426 "ringbuffer", 00427 NULL, connect_rb, NULL, NULL, enable_msg, NULL, NULL}; 00428 int __attribute__((constructor)) __ringbuf_init(void) 00429 { 00430 #ifndef NO_RINGBUF 00431 list_add(&plugin_cmds.list, &plugin_cmdlist); 00432 #endif 00433 return 0; 00434 }