SASC-NG
DVBSoftCAM

plugin_ringbuf.c

Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines