trunk 20080912
[gitenigma.git] / lib / dvb / record.cpp
blob0a3883cc2f4ec9a50276ac228770fcca6fb04384
1 #ifndef DISABLE_FILE
2 #include <lib/dvb/record.h>
3 #include <config.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <sys/ioctl.h>
8 #include <sys/stat.h>
9 #include <lib/dvb/dvbservice.h>
10 #include <lib/dvb/servicedvb.h>
11 #include <lib/system/file_eraser.h>
12 #include <lib/system/econfig.h>
13 #include <signal.h>
15 #ifndef DMX_LOW_BITRATE
16 #define DMX_LOW_BITRATE 0x4000
17 #endif
19 #if HAVE_DVB_API_VERSION < 3
20 #include <ost/dmx.h>
21 #define DVR_DEV "/dev/dvb/card0/dvr1"
22 #define DEMUX1_DEV "/dev/dvb/card0/demux1"
23 #else
24 #include <linux/dvb/dmx.h>
25 #if HAVE_DBOX2_DRIVER
26 #define DVR_DEV "/dev/dvb/adapter0/dvr0"
27 #define DEMUX1_DEV "/dev/dvb/adapter0/demux0"
28 #else
29 #define DVR_DEV "/dev/dvb/adapter0/dvr1"
30 #define DEMUX1_DEV "/dev/dvb/adapter0/demux1"
31 #endif
32 #endif
34 extern ePermanentTimeshift permanentTimeshift;
36 static pthread_mutex_t PMTLock =
37 PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
39 inline void lock_pmt()
41 pthread_mutex_lock(&PMTLock);
44 inline void unlock_pmt(void*)
46 pthread_mutex_unlock(&PMTLock);
49 static int section_length(const unsigned char *buf)
51 return ((buf[1] << 8) | buf[2]) & 0x0fff;
54 static int ts_header(unsigned char *dest, int pusi, int pid, int scrmbl, int adap, unsigned int &cc)
56 dest[0] = 0x47;
57 dest[1] = (!!pusi << 6) | (pid >> 8);
58 dest[2] = pid;
59 dest[3] = (scrmbl << 6) | (adap << 4) | (cc++ & 0x0f);
61 return 4;
64 static int section2ts(unsigned char *dest, const unsigned char *src, int pid, unsigned int &ccount )
66 unsigned char *orig = dest;
67 int pusi = 1;
68 int len, cplen;
70 orig = dest;
72 for (len = section_length(src) + 3; len > 0; len -= cplen) {
73 dest += ts_header(dest, pusi, pid, 0, 1, ccount);
75 if (pusi) {
76 *dest++ = 0x00; /* pointer_field */
77 cplen = MIN(len, 183);
78 pusi = 0;
80 else {
81 cplen = MIN(len, 184);
84 memcpy(dest, src, cplen);
85 dest += cplen;
86 src += cplen;
89 if ((cplen = (dest - orig) % 188)) {
90 cplen = 188 - cplen;
91 memset(dest, 0xff, cplen);
92 dest += cplen;
95 return dest - orig;
98 int eDVBRecorder::flushBuffer()
100 if (!bufptr)
101 return 0;
103 int towrite = splitsize-size>bufptr ? bufptr : splitsize-size;
105 int retrycount=5; // 5 write retrys..
106 int written=0;
107 int dosplit = 0;
108 while( written < towrite )
110 int wr = ::write(outfd, buf+written, towrite-written);
111 if ( wr < towrite ) // to less bytes written?
113 if ( wr < 0 )
115 if (errno == EINTR) continue;
116 goto Error;
118 if ( !retrycount-- )
119 goto Error;
121 written += wr;
122 size += wr;
123 written_since_last_sync += wr;
125 permanentTimeshift.lock.lock();
126 if (permanentTimeshift.IsTimeshifting)
128 int minutes = 30;
129 eConfig::getInstance()->getKey("/enigma/timeshift/permanentminutes", minutes );
130 if (permanentTimeshift.CheckSlice(minutes))
132 if ( openFile(permanentTimeshift.getCurrentRecordingSlice()) )
133 goto Error;
134 dosplit = 1;
136 permanentTimeshift.lock.unlock();
138 else
140 permanentTimeshift.lock.unlock();
141 if (size >= splitsize)
143 splitlock.lock();
144 if ( openFile(++splits) ) // file creation failed?
145 goto Error;
146 splitlock.unlock();
147 dosplit = 1;
150 if (dosplit)
152 retrycount=5; // 5 write retrys..
153 while ( written < bufptr ) // must flush remaining bytes from buffer..
155 towrite=bufptr-written;
156 int wr = ::write(outfd, buf+written, towrite);
157 if ( wr < towrite ) // to less bytes written?
159 if ( wr < 0 )
161 if (errno == EINTR) continue;
162 goto Error;
164 if ( !retrycount-- )
165 goto Error;
167 written += wr;
168 written_since_last_sync += wr;
169 size += wr;
172 else
174 if (written_since_last_sync >= 1024*1024) // 1M
176 int toflush = written_since_last_sync > 1024*1024 ? 1024*1024 :
177 written_since_last_sync & ~4095;
178 off64_t dest_pos = lseek64(outfd, 0, SEEK_CUR);
179 dest_pos -= toflush;
180 posix_fadvise64(outfd, dest_pos, toflush, POSIX_FADV_DONTNEED);
181 written_since_last_sync -= toflush;
184 bufptr=0;
185 return 0;
187 Error:
188 splitlock.unlock();
189 permanentTimeshift.lock.unlock();
190 eDebug("recording write error, maybe disk full");
191 state = stateError;
192 rmessagepump.send(eDVBRecorderMessage(eDVBRecorderMessage::rWriteError));
193 return -1;
196 void SAHandler(int ptr)
198 if ( eDVB::getInstance() && eDVB::getInstance()->recorder )
199 eDVB::getInstance()->recorder->setWritePatPmtFlag();
203 #ifndef EBUFFEROVERFLOW
204 #define EBUFFEROVERFLOW 769
205 #endif
207 void eDVBRecorder::thread()
209 signal(SIGALRM, SAHandler);
210 PatPmtWrite();
211 while (state == stateRunning)
213 int rd = 524144-bufptr;
214 if ( rd > 65424 )
215 rd = 65424;
216 int r = ::read(dvrfd, buf+bufptr, rd);
217 if ( r < 0 )
219 #if HAVE_DVB_API_VERSION < 3
220 // workaround for driver bug....
221 if (r == -EBUFFEROVERFLOW)
222 continue;
223 #endif
224 switch(errno)
226 case EINTR:
227 case EOVERFLOW:
228 continue;
229 default:
231 * any other error will immediately cause the same error
232 * when we would call 'read' again with the same arguments
234 eDebug("recording read error %d", errno);
235 state = stateError;
236 rmessagepump.send(eDVBRecorderMessage(eDVBRecorderMessage::rWriteError));
237 break;
239 break;
241 /* note that some dvr devices occasionally return EOF, we should ignore that */
243 bufptr += r;
245 if ( writePatPmt ) // is set in SAHandler
247 PatPmtWrite();
248 writePatPmt=false;
250 else if ( bufptr > 524143 )
251 flushBuffer();
253 alarm(0);
254 signal(SIGALRM, SIG_DFL );
257 void eDVBRecorder::PMTready(int error)
259 eDebug("eDVBRecorder PMTready");
260 if ( !error )
262 PMT *pmt=tPMT.ready()?tPMT.getCurrent():0;
263 if ( pmt )
265 eDVBCaPMTClientHandler::distribute_gotPMT(recRef, pmt);
266 eDebug("UpdatePIDs");
267 // addNewPID(0); // PAT
268 // addNewPID(pmt->pid); // PMT
269 addNewPID(pmt->PCR_PID); // PCR
271 for (ePtrList<PMTEntry>::iterator i(pmt->streams); i != pmt->streams.end(); ++i)
273 int record=0;
274 switch (i->stream_type)
276 case 1: // video..
277 case 2:
278 record=1;
279 break;
280 case 3: // audio..
281 case 4:
282 record=1;
283 break;
284 case 6:
285 for (ePtrList<Descriptor>::iterator it(i->ES_info); it != i->ES_info.end(); ++it)
287 switch (it->Tag())
289 case DESCR_AC3:
291 record=1;
292 break;
294 #ifdef RECORD_TELETEXT
295 case DESCR_TELETEXT:
297 record=2; // low bti
298 break;
300 #endif
301 #ifdef RECORD_SUBTITLES
302 case DESCR_SUBTITLING:
304 record=2;
305 break;
307 #endif
310 break;
312 if (record)
313 addNewPID(i->elementary_PID, record==2?DMX_LOW_BITRATE:0);
314 #ifdef RECORD_ECM
315 for (ePtrList<Descriptor>::iterator it(i->ES_info); it != i->ES_info.end(); ++it)
316 if (it->Tag() == 9)
317 addNewPID(((CADescriptor*)*it)->CA_PID);
318 #endif
320 validatePIDs();
322 pthread_cleanup_push( unlock_pmt, 0 );
323 lock_pmt();
324 if (PmtData) delete [] PmtData;
325 PmtData = pmt->getRAW();
326 pthread_cleanup_pop(1);
328 pmt->unlock();
333 void eDVBRecorder::gotBackMessage(const eDVBRecorderMessage &msg)
335 switch (msg.code)
337 case eDVBRecorderMessage::rWriteError:
338 /* emit */ recMessage(recWriteError);
339 break;
340 default:
341 break;
345 int eDVBRecorder::openFile(int suffix)
347 eString tfilename=filename;
348 if (suffix)
349 tfilename+=eString().sprintf(".%03d", suffix);
351 size=0;
352 written_since_last_sync=0;
354 if (outfd >= 0)
355 ::close(outfd);
357 struct stat64 s;
358 if ( !stat64(tfilename.c_str(), &s) )
360 rename(tfilename.c_str(), (tfilename+".$$$").c_str() );
361 if (eBackgroundFileEraser::getInstance())
362 eBackgroundFileEraser::getInstance()->erase((tfilename+".$$$").c_str());
365 #ifdef HAVE_DREAMBOX_HARDWARE
366 outfd=::open(tfilename.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE, 0555);
367 #else
368 if (access("/var/etc/.no_o_sync", R_OK) == 0)
369 outfd=::open(tfilename.c_str(),O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE, 0555);
370 else
371 outfd=::open(tfilename.c_str(),O_SYNC|O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE, 0555);
372 #endif
374 if (outfd < 0)
376 eDebug("failed to open DVR file: %s (%m)", tfilename.c_str());
377 return -1;
380 /* turn off kernel caching strategies */
381 posix_fadvise64(outfd, 0, 0, POSIX_FADV_RANDOM);
383 return 0;
386 void eDVBRecorder::open(const char *_filename)
388 eDebug("eDVBRecorder::open(%s)", _filename);
389 pids.clear();
390 newpids.clear();
392 filename=_filename;
394 int tmp=1024*1024; // 1G
395 if (eConfig::getInstance()) eConfig::getInstance()->getKey("/extras/record_splitsize", tmp);
397 splitsize=tmp;
398 splitsize*=1024;
399 splitsize/=188; // align to 188 bytes..
400 splitsize*=188;
402 openFile(splits=0);
404 if ( dvrfd >= 0 )
405 ::close(dvrfd);
407 dvrfd=::open(DVR_DEV, O_RDONLY);
408 if (dvrfd < 0)
410 eDebug("failed to open "DVR_DEV" (%m)");
411 ::close(outfd);
412 outfd=-1;
413 return;
415 if (outfd < 0)
416 rmessagepump.send(eDVBRecorderMessage(eDVBRecorderMessage::rWriteError));
419 std::pair<std::set<eDVBRecorder::pid_t>::iterator,bool> eDVBRecorder::addPID(int pid, int flags)
421 eDebugNoNewLine("eDVBRecorder::addPID(0x%x)...", pid );
422 pid_t p;
423 p.pid=pid;
424 if ( pids.find(p) != pids.end() )
426 eDebug("we already have this pid... skip!");
427 return std::pair<std::set<pid_t>::iterator, bool>(pids.end(),false);
429 p.fd=::open(DEMUX1_DEV, O_RDWR);
430 if (p.fd < 0)
432 eDebug("failed to open demux1");
433 return std::pair<std::set<pid_t>::iterator, bool>(pids.end(),false);
435 #if HAVE_DVB_API_VERSION < 3
436 dmxPesFilterParams flt;
437 flt.pesType=DMX_PES_OTHER;
438 #else
439 dmx_pes_filter_params flt;
440 flt.pes_type=DMX_PES_OTHER;
441 #endif
442 flt.pid=p.pid;
443 flt.input=DMX_IN_FRONTEND;
444 flt.output=DMX_OUT_TS_TAP;
446 flt.flags=flags;
447 eDebug("flags %08x", flags);
449 if (::ioctl(p.fd, DMX_SET_PES_FILTER, &flt)<0)
451 eDebug("DMX_SET_PES_FILTER failed (for pid %d)", flt.pid);
452 ::close(p.fd);
453 return std::pair<std::set<pid_t>::iterator, bool>(pids.end(),false);
456 return pids.insert(p);
459 void eDVBRecorder::addNewPID(int pid, int flags)
461 pid_t p;
462 p.pid = pid;
463 p.flags = flags;
464 newpids.insert(p);
467 void eDVBRecorder::validatePIDs()
469 for (std::set<pid_t>::iterator it(pids.begin()); it != pids.end();)
471 std::set<pid_t>::iterator i = newpids.find(*it);
472 if ( i == newpids.end() ) // no more existing pid...
473 removePID((it++)->pid);
474 else
475 ++it;
477 for (std::set<pid_t>::iterator it(newpids.begin()); it != newpids.end(); ++it )
479 std::pair<std::set<pid_t>::iterator,bool> newpid = addPID(it->pid, it->flags);
480 if ( newpid.second )
482 if ( state == stateRunning )
484 if (newpid.first->fd >= 0)
486 if (::ioctl(newpid.first->fd, DMX_START, 0)<0)
488 eDebug("DMX_START failed (%m)");
489 removePID(it->pid);
494 else
495 eDebug("error during add new pid");
497 newpids.clear();
500 void eDVBRecorder::removePID(int pid)
502 pid_t p;
503 p.pid=pid;
504 std::set<pid_t>::iterator pi=pids.find(p);
505 if (pi != pids.end())
507 if (pi->fd >= 0)
508 ::close(pi->fd);
509 pids.erase(pi);
510 eDebug("eDVBRecorder::removePID(0x%x)", pid);
514 void eDVBRecorder::start()
516 if ( state == stateRunning )
517 return;
519 eDebug("eDVBRecorder::start()");
521 state = stateRunning;
523 if ( !thread_running() )
525 eDebug("run thread");
526 run();
529 for (std::set<pid_t>::iterator i(pids.begin()); i != pids.end(); ++i)
531 eDebug("starting pidfilter for pid %d", i->pid );
533 if (i->fd >= 0)
535 if (::ioctl(i->fd, DMX_START, 0)<0)
537 eDebug("DMX_START failed");
538 ::close(i->fd);
539 pids.erase(i);
545 void eDVBRecorder::stop()
547 if ( state == stateStopped )
548 return;
550 eDebug("eDVBRecorder::stop()");
552 state = stateStopped;
554 int timeout=20;
555 while ( thread_running() && timeout )
557 usleep(100000); // 2 sec time for thread shutdown
558 --timeout;
561 for (std::set<pid_t>::iterator i(pids.begin()); i != pids.end(); ++i)
562 if (i->fd >= 0)
563 ::ioctl(i->fd, DMX_STOP, 0);
565 flushBuffer();
568 void eDVBRecorder::close()
570 if (state != stateStopped)
571 stop();
573 eDebug("eDVBRecorder::close()");
575 for (std::set<pid_t>::iterator i(pids.begin()); i != pids.end(); ++i)
576 if (i->fd >= 0)
577 ::close(i->fd);
579 pids.clear();
581 if (dvrfd >= 0)
583 ::close(dvrfd);
584 dvrfd = -1;
586 if (outfd >= 0)
588 ::close(outfd);
589 outfd = -1;
592 if ( thread_running() )
593 kill(true);
596 eDVBRecorder::eDVBRecorder(PMT *pmt,PAT *pat)
597 :state(stateStopped), rmessagepump(eApp, 1), dvrfd(-1) ,outfd(-1)
598 ,bufptr(0), PmtData(NULL), PatData(NULL)
599 ,PmtCC(0), PatCC(0), writePatPmt(true)
601 CONNECT(rmessagepump.recv_msg, eDVBRecorder::gotBackMessage);
602 rmessagepump.start();
604 if (pmt)
606 CONNECT( tPMT.tableReady, eDVBRecorder::PMTready );
607 tPMT.start((PMT*)pmt->createNext(), DEMUX1_DEV );
608 PmtData=pmt->getRAW();
609 pmtpid=pmt->pid;
610 if (pat)
612 PAT p;
613 p.entries.setAutoDelete(false);
614 p.version=pat->version;
615 p.transport_stream_id=pat->transport_stream_id;
616 for (ePtrList<PATEntry>::iterator it(pat->entries);
617 it != pat->entries.end(); ++it)
619 if ( it->program_number == pmt->program_number )
621 p.entries.push_back(*it);
622 PatData=p.getRAW();
623 break;
630 eDVBRecorder::~eDVBRecorder()
632 if (PatData) delete [] PatData;
633 if (PmtData) delete [] PmtData;
634 eDVBServiceController *sapi = NULL;
635 if (eDVB::getInstance()) sapi = eDVB::getInstance()->getServiceAPI();
637 if (sapi)
639 // workaround for faked service types..
640 eServiceReferenceDVB tmp = sapi->service;
641 tmp.data[0] = recRef.getServiceType();
643 if ( tmp != recRef )
645 eServiceReferenceDVB ref=sapi->service;
646 eDVBCaPMTClientHandler::distribute_leaveService(recRef);
649 close();
652 void eDVBRecorder::writeSection(void *data, int pid, unsigned int &cc)
654 if ( !data )
655 return;
657 __u8 secbuf[4300]; // with ts overhead...
659 int len = section2ts(secbuf, (__u8*)data, pid, cc);
661 if ( len )
663 if ( (bufptr+len) > 524143 )
664 flushBuffer();
666 memcpy(buf+bufptr, secbuf, len);
667 bufptr+=len;
671 void eDVBRecorder::PatPmtWrite()
673 //eDebug("PatPmtWrite");
674 if ( PatData )
675 writeSection(PatData, 0, PatCC );
677 pthread_cleanup_push( unlock_pmt, 0 );
678 lock_pmt();
679 if ( PmtData )
680 writeSection(PmtData, pmtpid, PmtCC );
681 pthread_cleanup_pop(1);
683 alarm(2);
685 void eDVBRecorder::SetSlice(int slice)
687 splitlock.lock();
688 eString oldfilename=filename;
689 if (splits)
690 oldfilename+=eString().sprintf(".%03d", splits);
691 splits = slice;
692 splitlock.unlock();
693 eString newfilename=filename;
694 if (slice)
695 newfilename+=eString().sprintf(".%03d", slice);
696 eDebug("rename current recording:%s|%s",oldfilename.c_str(),newfilename.c_str());
697 ::rename(oldfilename.c_str(),newfilename.c_str());
700 #endif //DISABLE_FILE