1 #include <lib/service/servicedvbrecord.h>
2 #include <lib/base/eerror.h>
3 #include <lib/dvb/epgcache.h>
4 #include <lib/dvb/metaparser.h>
5 #include <lib/base/httpstream.h>
6 #include <lib/base/nconfig.h>
12 #include <netinet/in.h>
15 #error no byte order defined!
18 DEFINE_REF(eDVBServiceRecord);
20 eDVBServiceRecord::eDVBServiceRecord(const eServiceReferenceDVB &ref, bool isstreamclient):
21 m_ref(ref),m_is_stream_client(isstreamclient)
23 CONNECT(m_service_handler.serviceEvent, eDVBServiceRecord::serviceEvent);
24 CONNECT(m_event_handler.m_eit_changed, eDVBServiceRecord::gotNewEvent);
29 m_pvr_descramble = false;
36 m_serviceType = eDVBServicePMTHandler::recording;
39 void eDVBServiceRecord::serviceEvent(int event)
41 eDebug("RECORD service event %d", event);
44 case eDVBServicePMTHandler::eventTuned:
49 /* start feeding EIT updates */
50 ePtr<iDVBDemux> m_demux;
51 if (!m_service_handler.getDataDemux(m_demux))
53 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_ref;
54 int sid = ref.getParentServiceID().get();
56 sid = ref.getServiceID().get();
57 if ( ref.getParentTransportStreamID().get() &&
58 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
59 m_event_handler.startOther(m_demux, sid);
61 m_event_handler.start(m_demux, sid);
64 if (m_state == stateRecording && m_want_record)
66 m_event((iRecordableService*)this, evTunedIn);
69 case eDVBServicePMTHandler::eventTuneFailed:
71 eDebug("record failed to tune");
72 m_event((iRecordableService*)this, evTuneFailed);
75 case eDVBServicePMTHandler::eventNewProgramInfo:
77 if (m_state == stateIdle)
79 else if (m_want_record) /* doRecord can be called from Prepared and Recording state */
86 m_event((iRecordableService*)this, evNewProgramInfo);
89 case eDVBServicePMTHandler::eventMisconfiguration:
90 m_error = errMisconfiguration;
91 m_event((iRecordableService*)this, evTuneFailed);
93 case eDVBServicePMTHandler::eventNoResources:
94 m_error = errNoResources;
95 m_event((iRecordableService*)this, evTuneFailed);
97 case eDVBServicePMTHandler::eventEOF:
98 m_event((iRecordableService*)this, evPvrEof);
100 case eDVBServicePMTHandler::eventStartPvrDescramble:
109 RESULT eDVBServiceRecord::prepare(const char *filename, time_t begTime, time_t endTime, int eit_event_id, const char *name, const char *descr, const char *tags, bool descramble, bool recordecm)
111 bool config_recording_always_ecm = ePythonConfigQuery::getConfigBoolValue("config.recording.always_ecm", false);
112 bool config_recording_never_decrypt = ePythonConfigQuery::getConfigBoolValue("config.recording.never_decrypt", false);
113 m_filename = filename;
115 m_descramble = config_recording_never_decrypt ? false : descramble;
116 m_record_ecm = config_recording_always_ecm ? true : recordecm;
118 // force descramble for _pvrdesc.ts
119 if (strstr(filename, "_pvrdesc.ts"))
121 m_pvr_descramble = true;
125 if (m_state == stateIdle)
127 int ret = doPrepare();
130 eServiceReferenceDVB ref = m_ref.getParentServiceReference();
131 ePtr<eDVBResourceManager> res_mgr;
133 std::string service_data;
136 if (!eDVBResourceManager::getInstance(res_mgr))
138 ePtr<iDVBChannelList> db;
139 if (!res_mgr->getChannelList(db))
141 ePtr<eDVBService> service;
142 if (!db->getService(ref, service))
145 sprintf(tmp, "f:%x", service->m_flags);
148 for (int x=0; x < eDVBService::cacheMax; ++x)
150 int entry = service->getCacheEntry((eDVBService::cacheID)x);
153 sprintf(tmp, ",c:%02d%04x", x, entry);
160 meta.m_time_create = begTime;
163 meta.m_service_data = service_data;
167 meta.m_description = descr;
170 meta.m_scrambled = !m_descramble;
171 ret = meta.updateMeta(m_filename) ? -255 : 0;
174 const eit_event_struct *event = 0;
175 eEPGCache::getInstance()->Lock();
176 if ( eit_event_id != -1 )
178 eDebug("query epg event id %d", eit_event_id);
179 eEPGCache::getInstance()->lookupEventId(ref, eit_event_id, event);
181 if ( !event && (begTime != -1 && endTime != -1) )
183 time_t queryTime = begTime + ((endTime-begTime)/2);
185 localtime_r(&begTime, &beg);
186 localtime_r(&endTime, &end);
187 localtime_r(&queryTime, &query);
188 eDebug("query stime %d:%d:%d, etime %d:%d:%d, qtime %d:%d:%d",
189 beg.tm_hour, beg.tm_min, beg.tm_sec,
190 end.tm_hour, end.tm_min, end.tm_sec,
191 query.tm_hour, query.tm_min, query.tm_sec);
192 eEPGCache::getInstance()->lookupEventTime(ref, queryTime, event);
196 eDebug("found event.. store to disc");
197 std::string fname = m_filename;
198 fname.erase(fname.length()-2, 2);
200 int fd = open(fname.c_str(), O_CREAT|O_WRONLY, 0777);
203 int evLen=HILO(event->descriptors_loop_length)+12/*EIT_LOOP_SIZE*/;
204 int wr = ::write( fd, (unsigned char*)event, evLen );
206 eDebug("eit write error (%m)");
210 eEPGCache::getInstance()->Unlock();
218 RESULT eDVBServiceRecord::prepareStreaming()
222 if (m_state == stateIdle)
227 RESULT eDVBServiceRecord::start(bool simulate)
229 m_simulate = simulate;
231 /* when tune wasn't yet successfully, doRecord stays in "prepared"-state which is fine. */
232 m_event((iRecordableService*)this, evStart);
236 RESULT eDVBServiceRecord::stop()
239 eDebug("stop recording!");
240 if (m_state == stateRecording)
244 if (m_target_fd >= 0)
246 ::close(m_target_fd);
252 m_state = statePrepared;
253 } else if (!m_simulate)
254 eDebug("(was not recording)");
255 if (m_state == statePrepared)
260 m_event((iRecordableService*)this, evRecordStopped);
264 int eDVBServiceRecord::doPrepare()
266 /* allocate a ts recorder if we don't already have one. */
267 if (m_state == stateIdle)
269 int use_decode_demux = 0;
273 m_serviceType = m_record_ecm ? eDVBServicePMTHandler::scrambled_streamserver : eDVBServicePMTHandler::streamserver;
277 m_serviceType = m_record_ecm ? eDVBServicePMTHandler::scrambled_recording : eDVBServicePMTHandler::recording;
280 m_pids_active.clear();
281 m_state = statePrepared;
282 ePtr<iTsSource> source;
283 if (!m_simulate && !m_ref.path.empty())
285 if (m_is_stream_client)
287 m_descramble = true; // assume stream is scrambled
288 m_record_ecm = false;
289 m_serviceType = eDVBServicePMTHandler::streamclient;
290 eHttpStream *f = new eHttpStream();
291 f->open(m_ref.path.c_str());
292 source = ePtr<iTsSource>(f);
296 use_decode_demux = 1;
298 /* re-record a recording */
300 if (!meta.parseFile(m_ref.path))
302 m_descramble = meta.m_scrambled;
307 m_serviceType = eDVBServicePMTHandler::pvrDescramble;
311 m_serviceType = eDVBServicePMTHandler::offline;
314 eRawFile *f = new eRawFile();
315 f->open(m_ref.path.c_str());
316 source = ePtr<iTsSource>(f);
318 m_event((iRecordableService*)this, evPvrTuneStart);
322 m_event((iRecordableService*)this, evTuneStart);
324 return m_service_handler.tuneExt(m_ref, use_decode_demux, source, m_ref.path.c_str(), 0, m_simulate, 0, m_serviceType, m_descramble);
329 int eDVBServiceRecord::doRecord()
331 int err = doPrepare();
334 m_error = errTuneFailed;
335 m_event((iRecordableService*)this, evRecordFailed);
340 return 0; /* try it again when we are tuned in */
342 if (!m_record && m_tuned && !m_streaming && !m_simulate)
344 if (m_pvr_descramble)
346 if (m_service_handler.isPmtReady())
348 if (!m_service_handler.isCiConnected())
350 m_event((iRecordableService*)this, evRecordFailed);
351 return errNoCiConnected;
360 eDebug("Recording to %s...", m_filename.c_str());
361 ::remove(m_filename.c_str());
362 int fd = ::open(m_filename.c_str(), O_WRONLY|O_CREAT|O_LARGEFILE, 0644);
365 eDebug("eDVBServiceRecord - can't open recording file!");
366 m_error = errOpenRecordFile;
367 m_event((iRecordableService*)this, evRecordFailed);
368 return errOpenRecordFile;
371 /* turn off kernel caching strategies */
372 posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM);
374 ePtr<iDVBDemux> demux;
375 if (m_service_handler.getDataDemux(demux))
377 eDebug("eDVBServiceRecord - NO DEMUX available!");
378 m_error = errNoDemuxAvailable;
379 m_event((iRecordableService*)this, evRecordFailed);
380 return errNoDemuxAvailable;
382 demux->createTSRecorder(m_record);
385 eDebug("eDVBServiceRecord - no ts recorder available.");
386 m_error = errNoTsRecorderAvailable;
387 m_event((iRecordableService*)this, evRecordFailed);
388 return errNoTsRecorderAvailable;
390 m_record->setTargetFD(fd);
391 m_record->setTargetFilename(m_filename.c_str());
392 m_record->connectEvent(slot(*this, &eDVBServiceRecord::recordEvent), m_con_record_event);
399 m_state = stateRecording;
400 eDebug("start streaming...");
403 eDebug("start recording...");
405 eDVBServicePMTHandler::program program;
406 if (m_service_handler.getProgramInfo(program))
407 eDebug("getting program info failed.");
410 std::set<int> pids_to_record;
412 pids_to_record.insert(0); // PAT
414 if (program.pmtPid != -1)
415 pids_to_record.insert(program.pmtPid); // PMT
417 int timing_pid = -1, timing_pid_type = -1;
419 eDebugNoNewLine("RECORD: have %zd video stream(s)", program.videoStreams.size());
420 if (!program.videoStreams.empty())
422 eDebugNoNewLine(" (");
423 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
424 i(program.videoStreams.begin());
425 i != program.videoStreams.end(); ++i)
427 pids_to_record.insert(i->pid);
429 if (timing_pid == -1)
432 timing_pid_type = i->type;
435 if (i != program.videoStreams.begin())
436 eDebugNoNewLine(", ");
437 eDebugNoNewLine("%04x", i->pid);
439 eDebugNoNewLine(")");
441 eDebugNoNewLine(", and %zd audio stream(s)", program.audioStreams.size());
442 if (!program.audioStreams.empty())
444 eDebugNoNewLine(" (");
445 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
446 i(program.audioStreams.begin());
447 i != program.audioStreams.end(); ++i)
449 pids_to_record.insert(i->pid);
451 if (timing_pid == -1)
454 timing_pid_type = -1;
457 if (i != program.audioStreams.begin())
458 eDebugNoNewLine(", ");
459 eDebugNoNewLine("%04x", i->pid);
461 eDebugNoNewLine(")");
463 if (!program.subtitleStreams.empty())
465 eDebugNoNewLine(" (");
466 for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
467 i(program.subtitleStreams.begin());
468 i != program.subtitleStreams.end(); ++i)
470 pids_to_record.insert(i->pid);
472 if (i != program.subtitleStreams.begin())
473 eDebugNoNewLine(", ");
474 eDebugNoNewLine("%04x", i->pid);
476 eDebugNoNewLine(")");
478 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
479 if (program.pcrPid != 0x1fff)
480 pids_to_record.insert(program.pcrPid);
481 eDebug(", and the text pid is %04x", program.textPid);
482 if (program.textPid != -1)
483 pids_to_record.insert(program.textPid); // Videotext
487 for (std::list<eDVBServicePMTHandler::program::capid_pair>::const_iterator i(program.caids.begin());
488 i != program.caids.end(); ++i)
490 if (i->capid >= 0) pids_to_record.insert(i->capid);
492 pids_to_record.insert(EventInformationSection::PID);
493 pids_to_record.insert(TimeAndDateSection::PID);
497 int isCrypted = (int)program.isCrypted();
498 int scrambled = !m_descramble;
501 scrambled = isCrypted;
507 else // m_descramble && isCrypted
509 if (!m_service_handler.isCiConnected())
514 eDVBMetaParser dvbParser;
515 dvbParser.parseFile(m_filename);
516 dvbParser.m_scrambled = scrambled;
517 dvbParser.updateMeta(m_filename);
520 /* find out which pids are NEW and which pids are obsolete.. */
521 std::set<int> new_pids, obsolete_pids;
523 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
524 m_pids_active.begin(), m_pids_active.end(),
525 std::inserter(new_pids, new_pids.begin()));
528 m_pids_active.begin(), m_pids_active.end(),
529 pids_to_record.begin(), pids_to_record.end(),
530 std::inserter(obsolete_pids, obsolete_pids.begin())
533 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
535 eDebug("ADD PID: %04x", *i);
536 m_record->addPID(*i);
539 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
541 eDebug("REMOVED PID: %04x", *i);
542 m_record->removePID(*i);
545 if (timing_pid != -1)
546 m_record->setTimingPID(timing_pid, timing_pid_type);
548 m_pids_active = pids_to_record;
550 if (m_state != stateRecording)
553 m_state = stateRecording;
558 m_event((iRecordableService*)this, evRecordRunning);
562 void eDVBServiceRecord::updateDecoder()
564 int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1;
566 eDVBServicePMTHandler &h = m_service_handler;
568 eDVBServicePMTHandler::program program;
569 if (m_service_handler.getProgramInfo(program))
570 eDebug("getting program info failed.");
573 eDebugNoNewLine("have %zd video stream(s)", program.videoStreams.size());
574 if (!program.videoStreams.empty())
576 eDebugNoNewLine(" (");
577 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
578 i(program.videoStreams.begin());
579 i != program.videoStreams.end(); ++i)
586 if (i != program.videoStreams.begin())
587 eDebugNoNewLine(", ");
588 eDebugNoNewLine("%04x", i->pid);
590 eDebugNoNewLine(")");
593 eDebugNoNewLine(", and %zd audio stream(s)", program.audioStreams.size());
594 if (!program.audioStreams.empty())
596 eDebugNoNewLine(" (");
597 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
598 i(program.audioStreams.begin());
599 i != program.audioStreams.end(); ++i)
601 if (i != program.audioStreams.begin())
602 eDebugNoNewLine(", ");
603 eDebugNoNewLine("%04x", i->pid);
605 eDebugNoNewLine(")");
608 apid = program.audioStreams[program.defaultAudioStream].pid;
609 apidtype = program.audioStreams[program.defaultAudioStream].type;
611 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
612 pcrpid = program.pcrPid;
617 h.getDecodeDemux(m_decode_demux);
620 m_decode_demux->getMPEGDecoder(m_decoder, 0);
626 m_decoder->setVideoPID(vpid, vpidtype);
627 m_decoder->setAudioPID(apid, apidtype);
628 m_decoder->setSyncPCR(-1);
633 RESULT eDVBServiceRecord::frontendInfo(ePtr<iFrontendInformation> &ptr)
639 RESULT eDVBServiceRecord::connectEvent(const Slot2<void,iRecordableService*,int> &event, ePtr<eConnection> &connection)
641 connection = new eConnection((iRecordableService*)this, m_event.connect(event));
645 RESULT eDVBServiceRecord::stream(ePtr<iStreamableService> &ptr)
651 extern void PutToDict(ePyObject &dict, const char*key, long val); // defined in dvb/frontend.cpp
653 PyObject *eDVBServiceRecord::getStreamingData()
655 eDVBServicePMTHandler::program program;
656 if (!m_tuned || m_service_handler.getProgramInfo(program))
661 ePyObject r = program.createPythonObject();
662 ePtr<iDVBDemux> demux;
663 if (!m_service_handler.getDataDemux(demux))
666 if (!demux->getCADemuxID(demux_id))
667 PutToDict(r, "demux", demux_id);
673 void eDVBServiceRecord::recordEvent(int event)
677 case iDVBTSRecorder::eventWriteError:
678 eWarning("[eDVBServiceRecord] record write error");
680 m_event((iRecordableService*)this, evRecordWriteError);
683 eDebug("unhandled record event %d", event);
687 void eDVBServiceRecord::gotNewEvent()
689 ePtr<eServiceEvent> event_now;
690 m_event_handler.getEvent(event_now, 0);
695 int event_id = event_now->getEventId();
701 if (m_record->getCurrentPCR(p))
702 eDebug("getting PCR failed!");
705 m_event_timestamps[event_id] = p;
706 eDebug("pcr of eit change: %llx", p);
710 if (event_id != m_last_event_id)
711 eDebug("[eDVBServiceRecord] now running: %s (%d seconds)", event_now->getEventName().c_str(), event_now->getDuration());
713 m_last_event_id = event_id;
715 m_event((iRecordableService*)this, evNewEventInfo);
718 void eDVBServiceRecord::saveCutlist()
720 /* XXX: dupe of eDVBServicePlay::saveCuesheet, refactor plz */
721 std::string filename = m_filename + ".cuts";
725 if (tstools.openFile(m_filename.c_str()))
727 eDebug("[eDVBServiceRecord] saving cutlist failed because tstools failed");
731 FILE *f = fopen(filename.c_str(), "wb");
735 unsigned long long where;
738 for (std::map<int,pts_t>::iterator i(m_event_timestamps.begin()); i != m_event_timestamps.end(); ++i)
741 off_t offset = 0; // fixme, we need to note down both
742 if (tstools.fixupPTS(offset, p))
744 eDebug("[eDVBServiceRecord] fixing up PTS failed, not saving");
747 eDebug("fixed up %llx to %llx (offset %llx)", i->second, p, offset);
748 #if BYTE_ORDER == BIG_ENDIAN
753 what = htonl(2); /* mark */
754 fwrite(&where, sizeof(where), 1, f);
755 fwrite(&what, sizeof(what), 1, f);
762 RESULT eDVBServiceRecord::subServices(ePtr<iSubserviceList> &ptr)
768 int eDVBServiceRecord::getNumberOfSubservices()
770 ePtr<eServiceEvent> evt;
771 if (!m_event_handler.getEvent(evt, 0))
772 return evt->getNumOfLinkageServices();
776 RESULT eDVBServiceRecord::getSubservice(eServiceReference &sub, unsigned int n)
778 ePtr<eServiceEvent> evt;
779 if (!m_event_handler.getEvent(evt, 0))
781 if (!evt->getLinkageService(sub, m_ref, n))
784 sub.type=eServiceReference::idInvalid;