1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
4 #include <lib/service/servicedvb.h>
5 #include <lib/service/service.h>
6 #include <lib/base/init_num.h>
7 #include <lib/base/init.h>
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
13 #include <lib/components/file_eraser.h>
14 #include <lib/service/servicedvbrecord.h>
15 #include <lib/service/event.h>
16 #include <lib/dvb/metaparser.h>
17 #include <lib/dvb/tstools.h>
18 #include <lib/python/python.h>
23 #include <netinet/in.h>
25 #include <dvbsi++/event_information_section.h>
28 #error no byte order defined!
31 #define TSPATH "/media/hdd"
33 class eStaticServiceDVBInformation: public iStaticServiceInformation
35 DECLARE_REF(eStaticServiceDVBInformation);
37 RESULT getName(const eServiceReference &ref, std::string &name);
38 int getLength(const eServiceReference &ref);
41 DEFINE_REF(eStaticServiceDVBInformation);
43 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
45 eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
46 if ( !ref.name.empty() )
48 if (service.getParentTransportStreamID().get()) // linkage subservice
50 ePtr<iServiceHandler> service_center;
51 if (!eServiceCenter::getInstance(service_center))
53 eServiceReferenceDVB parent = service;
54 parent.setTransportStreamID( service.getParentTransportStreamID() );
55 parent.setServiceID( service.getParentServiceID() );
56 parent.setParentTransportStreamID(eTransportStreamID(0));
57 parent.setParentServiceID(eServiceID(0));
59 ePtr<iStaticServiceInformation> service_info;
60 if (!service_center->info(parent, service_info))
62 if (!service_info->getName(parent, name))
64 // just show short name
65 unsigned int pos = name.find("\xc2\x86");
66 if ( pos != std::string::npos )
68 pos = name.find("\xc2\x87");
69 if ( pos != std::string::npos )
85 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
90 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
92 DECLARE_REF(eStaticServiceDVBBouquetInformation);
94 RESULT getName(const eServiceReference &ref, std::string &name);
95 int getLength(const eServiceReference &ref);
98 DEFINE_REF(eStaticServiceDVBBouquetInformation);
100 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
102 ePtr<iDVBChannelList> db;
103 ePtr<eDVBResourceManager> res;
106 if ((err = eDVBResourceManager::getInstance(res)) != 0)
108 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
111 if ((err = res->getChannelList(db)) != 0)
113 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
118 if ((err = db->getBouquet(ref, bouquet)) != 0)
120 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
124 if ( bouquet && bouquet->m_bouquet_name.length() )
126 name = bouquet->m_bouquet_name;
133 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
138 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
140 DECLARE_REF(eStaticServiceDVBPVRInformation);
141 eServiceReference m_ref;
142 eDVBMetaParser m_parser;
144 eStaticServiceDVBPVRInformation(const eServiceReference &ref);
145 RESULT getName(const eServiceReference &ref, std::string &name);
146 int getLength(const eServiceReference &ref);
148 int getInfo(const eServiceReference &ref, int w);
149 std::string getInfoString(const eServiceReference &ref,int w);
152 DEFINE_REF(eStaticServiceDVBPVRInformation);
154 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
157 m_parser.parseFile(ref.path);
160 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
162 ASSERT(ref == m_ref);
163 name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
167 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
169 ASSERT(ref == m_ref);
173 if (tstools.openFile(ref.path.c_str()))
177 if (tstools.calcLen(len))
183 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
187 case iServiceInformation::sDescription:
188 return iServiceInformation::resIsString;
189 case iServiceInformation::sServiceref:
190 return iServiceInformation::resIsString;
191 case iServiceInformation::sTimeCreate:
192 if (m_parser.m_time_create)
193 return m_parser.m_time_create;
195 return iServiceInformation::resNA;
197 return iServiceInformation::resNA;
201 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
205 case iServiceInformation::sDescription:
206 return m_parser.m_description;
207 case iServiceInformation::sServiceref:
208 return m_parser.m_ref.toString();
214 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
216 DECLARE_REF(eDVBPVRServiceOfflineOperations);
217 eServiceReferenceDVB m_ref;
219 eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
221 RESULT deleteFromDisk(int simulate);
222 RESULT getListOfFilenames(std::list<std::string> &);
225 DEFINE_REF(eDVBPVRServiceOfflineOperations);
227 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
231 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
237 std::list<std::string> res;
238 if (getListOfFilenames(res))
241 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
243 eDebug("FATAL !! can't get background file eraser");
245 /* TODO: deferred removing.. */
246 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
248 eDebug("Removing %s...", i->c_str());
250 eraser->erase(i->c_str());
252 ::unlink(i->c_str());
259 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
262 res.push_back(m_ref.path);
264 // handling for old splitted recordings (enigma 1)
269 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
271 if (stat(buf, &s) < 0)
276 res.push_back(m_ref.path + ".meta");
277 res.push_back(m_ref.path + ".ap");
278 res.push_back(m_ref.path + ".cuts");
279 std::string tmp = m_ref.path;
280 tmp.erase(m_ref.path.length()-3);
281 res.push_back(tmp + ".eit");
285 DEFINE_REF(eServiceFactoryDVB)
287 eServiceFactoryDVB::eServiceFactoryDVB()
289 ePtr<eServiceCenter> sc;
291 eServiceCenter::getPrivInstance(sc);
293 sc->addServiceFactory(eServiceFactoryDVB::id, this);
296 eServiceFactoryDVB::~eServiceFactoryDVB()
298 ePtr<eServiceCenter> sc;
300 eServiceCenter::getPrivInstance(sc);
302 sc->removeServiceFactory(eServiceFactoryDVB::id);
305 DEFINE_REF(eDVBServiceList);
307 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
311 eDVBServiceList::~eDVBServiceList()
315 RESULT eDVBServiceList::startQuery()
317 ePtr<iDVBChannelList> db;
318 ePtr<eDVBResourceManager> res;
321 if ((err = eDVBResourceManager::getInstance(res)) != 0)
323 eDebug("no resource manager");
326 if ((err = res->getChannelList(db)) != 0)
328 eDebug("no channel list");
332 ePtr<eDVBChannelQuery> q;
334 if (!m_parent.path.empty())
336 eDVBChannelQuery::compile(q, m_parent.path);
339 eDebug("compile query failed");
344 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
346 eDebug("startQuery failed");
353 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
355 eServiceReferenceDVB ref;
357 if (!m_query || !list || !PyList_Check(list))
360 std::list<eServiceReferenceDVB> tmplist;
362 while (!m_query->getNextResult(ref))
363 tmplist.push_back(ref);
366 tmplist.sort(iListableServiceCompare(this));
368 for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
369 it != tmplist.end(); ++it)
371 PyObject *refobj = New_eServiceReference(*it);
372 PyList_Append(list, refobj);
378 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
380 eServiceReferenceDVB ref;
385 while (!m_query->getNextResult(ref))
389 list.sort(iListableServiceCompare(this));
394 RESULT eDVBServiceList::getNext(eServiceReference &ref)
399 return m_query->getNextResult((eServiceReferenceDVB&)ref);
402 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
404 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
407 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
409 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
411 ePtr<iDVBChannelList> db;
412 ePtr<eDVBResourceManager> resm;
414 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
417 if (db->getBouquet(m_parent, m_bouquet) != 0)
428 RESULT eDVBServiceList::addService(eServiceReference &ref)
432 return m_bouquet->addService(ref);
435 RESULT eDVBServiceList::removeService(eServiceReference &ref)
439 return m_bouquet->removeService(ref);
442 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
446 return m_bouquet->moveService(ref, pos);
449 RESULT eDVBServiceList::flushChanges()
453 return m_bouquet->flushChanges();
456 RESULT eDVBServiceList::setListName(const std::string &name)
460 return m_bouquet->setListName(name);
463 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
465 ePtr<eDVBService> service;
466 int r = lookupService(service, ref);
469 // check resources...
470 ptr = new eDVBServicePlay(ref, service);
474 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
476 if (ref.path.empty())
478 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
487 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
489 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
490 if (list->startQuery())
500 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
502 /* is a listable service? */
503 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
505 if ( !ref.name.empty() ) // satellites or providers list
506 ptr = new eStaticServiceDVBInformation;
507 else // a dvb bouquet
508 ptr = new eStaticServiceDVBBouquetInformation;
510 else if (!ref.path.empty()) /* do we have a PVR service? */
511 ptr = new eStaticServiceDVBPVRInformation(ref);
512 else // normal dvb service
514 ePtr<eDVBService> service;
515 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
516 ptr = new eStaticServiceDVBInformation;
518 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
524 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
526 if (ref.path.empty())
532 ptr = new eDVBPVRServiceOfflineOperations(ref);
537 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
539 // TODO: handle the listing itself
540 // if (ref.... == -1) .. return "... bouquets ...";
541 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
543 ePtr<iDVBChannelList> db;
544 ePtr<eDVBResourceManager> res;
547 if ((err = eDVBResourceManager::getInstance(res)) != 0)
549 eDebug("no resource manager");
552 if ((err = res->getChannelList(db)) != 0)
554 eDebug("no channel list");
558 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
559 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
561 eDebug("getService failed!");
568 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
569 m_reference(ref), m_dvb_service(service), m_is_paused(0)
573 if (m_reference.path == "s")
575 m_reference.path = "";
580 m_is_pvr = !ref.path.empty();
582 m_timeshift_enabled = m_timeshift_active = 0;
585 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
586 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
587 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
589 m_cuesheet_changed = 0;
590 m_cutlist_enabled = 1;
593 eDVBServicePlay::~eDVBServicePlay()
597 void eDVBServicePlay::gotNewEvent()
601 ePtr<eServiceEvent> m_event_now, m_event_next;
602 getEvent(m_event_now, 0);
603 getEvent(m_event_next, 1);
606 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
608 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
610 m_event((iPlayableService*)this, evUpdatedEventInfo);
613 void eDVBServicePlay::serviceEvent(int event)
617 case eDVBServicePMTHandler::eventTuned:
619 ePtr<iDVBDemux> m_demux;
620 if (!m_service_handler.getDataDemux(m_demux))
622 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
623 int sid = ref.getParentServiceID().get();
625 sid = ref.getServiceID().get();
626 if ( ref.getParentTransportStreamID().get() &&
627 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
628 m_event_handler.startOther(m_demux, sid);
630 m_event_handler.start(m_demux, sid);
634 case eDVBServicePMTHandler::eventTuneFailed:
636 eDebug("DVB service failed to tune");
637 m_event((iPlayableService*)this, evTuneFailed);
640 case eDVBServicePMTHandler::eventNewProgramInfo:
642 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
643 if (m_timeshift_enabled)
644 updateTimeshiftPids();
645 if (!m_timeshift_active)
647 if (m_first_program_info && m_is_pvr)
649 m_first_program_info = 0;
652 m_event((iPlayableService*)this, evUpdatedInfo);
655 case eDVBServicePMTHandler::eventEOF:
656 m_event((iPlayableService*)this, evEOF);
658 case eDVBServicePMTHandler::eventSOF:
659 m_event((iPlayableService*)this, evSOF);
664 void eDVBServicePlay::serviceEventTimeshift(int event)
668 case eDVBServicePMTHandler::eventNewProgramInfo:
669 if (m_timeshift_active)
672 case eDVBServicePMTHandler::eventSOF:
673 m_event((iPlayableService*)this, evSOF);
675 case eDVBServicePMTHandler::eventEOF:
681 RESULT eDVBServicePlay::start()
684 /* in pvr mode, we only want to use one demux. in tv mode, we're using
685 two (one for decoding, one for data source), as we must be prepared
686 to start recording from the data demux. */
687 m_cue = new eCueSheet();
689 m_first_program_info = 1;
690 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
691 r = m_service_handler.tune(service, m_is_pvr, m_cue);
693 /* inject EIT if there is a stored one */
696 std::string filename = service.path;
697 filename.erase(filename.length()-2, 2);
699 int fd = ::open( filename.c_str(), O_RDONLY );
703 int rd = ::read(fd, buf, 4096);
705 if ( rd > 12 /*EIT_LOOP_SIZE*/ )
708 ePtr<eServiceEvent> event = new eServiceEvent;
709 ePtr<eServiceEvent> empty;
710 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
711 m_event_handler.inject(event, 0);
712 m_event_handler.inject(empty, 1);
721 m_event(this, evStart);
722 m_event((iPlayableService*)this, evSeekableStatusChanged);
726 RESULT eDVBServicePlay::stop()
728 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
730 m_service_handler_timeshift.free();
731 m_service_handler.free();
733 if (m_is_pvr && m_cuesheet_changed)
739 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
741 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
745 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
747 /* note: we check for timeshift to be enabled,
748 not neccessary active. if you pause when timeshift
749 is not active, you should activate it when unpausing */
750 if ((!m_is_pvr) && (!m_timeshift_enabled))
760 RESULT eDVBServicePlay::setSlowMotion(int ratio)
763 return m_decoder->setSlowMotion(ratio);
768 RESULT eDVBServicePlay::setFastForward(int ratio)
770 int skipmode, ffratio;
776 } else if (ratio > 0)
784 } else // if (ratio < 0)
790 if (m_skipmode != skipmode)
792 eDebug("setting cue skipmode to %d", skipmode);
794 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
797 m_skipmode = skipmode;
802 return m_decoder->setFastForward(ffratio);
805 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
807 if (m_is_pvr || m_timeshift_enabled)
817 /* TODO: when timeshift is enabled but not active, this doesn't work. */
818 RESULT eDVBServicePlay::getLength(pts_t &len)
820 ePtr<iDVBPVRChannel> pvr_channel;
822 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
825 return pvr_channel->getLength(len);
828 RESULT eDVBServicePlay::pause()
830 if (!m_is_paused && m_decoder)
833 return m_decoder->freeze(0);
838 RESULT eDVBServicePlay::unpause()
840 if (m_is_paused && m_decoder)
843 return m_decoder->unfreeze();
848 RESULT eDVBServicePlay::seekTo(pts_t to)
850 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
855 ePtr<iDVBPVRChannel> pvr_channel;
857 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
863 m_cue->seekTo(0, to);
867 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
869 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
874 ePtr<iDVBPVRChannel> pvr_channel;
876 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
881 /* HACK until we have skip-AP api */
882 if ((to > 0) && (to < 100))
890 m_cue->seekTo(mode, to);
894 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
896 ePtr<iDVBPVRChannel> pvr_channel;
901 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
906 /* if there is a decoder, use audio or video PTS */
909 r = m_decoder->getPTS(0, pos);
915 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
918 RESULT eDVBServicePlay::setTrickmode(int trick)
921 m_decoder->setTrickmode(trick);
925 RESULT eDVBServicePlay::isCurrentlySeekable()
927 return m_is_pvr || m_timeshift_active;
930 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
936 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
942 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
948 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
954 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
957 if (m_timeshift_enabled || !m_is_pvr)
959 if (!m_timeshift_enabled)
961 /* we need enough diskspace */
963 if (statfs(TSPATH "/.", &fs) < 0)
965 eDebug("statfs failed!");
969 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
971 eDebug("not enough diskspace for timeshift! (less than 1GB)");
981 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
992 RESULT eDVBServicePlay::getName(std::string &name)
996 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
997 return i->getName(m_reference, name);
1001 m_dvb_service->getName(m_reference, name);
1005 else if (!m_reference.name.empty())
1006 eStaticServiceDVBInformation().getName(m_reference, name);
1008 name = "DVB service";
1012 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1014 return m_event_handler.getEvent(evt, nownext);
1017 int eDVBServicePlay::getInfo(int w)
1019 eDVBServicePMTHandler::program program;
1021 if (m_service_handler.getProgramInfo(program))
1027 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1029 ePtr<eServiceEvent> evt;
1030 if (!m_event_handler.getEvent(evt, 0))
1032 ePtr<eComponentData> data;
1033 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1035 if ( data->getStreamContent() == 1 )
1037 switch(data->getComponentType())
1040 case 1: // 4:3 SD PAL
1042 case 3: // 16:9 SD PAL
1043 case 4: // > 16:9 PAL
1044 case 5: // 4:3 SD NTSC
1046 case 7: // 16:9 SD NTSC
1047 case 8: // > 16:9 NTSC
1050 case 9: // 4:3 HD PAL
1052 case 0xB: // 16:9 HD PAL
1053 case 0xC: // > 16:9 HD PAL
1054 case 0xD: // 4:3 HD NTSC
1056 case 0xF: // 16:9 HD NTSC
1057 case 0x10: // > 16:9 HD PAL
1058 return data->getComponentType();
1065 case sIsCrypted: return program.isCrypted;
1066 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1067 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1068 case sPCRPID: return program.pcrPid;
1069 case sPMTPID: return program.pmtPid;
1070 case sTXTPID: return program.textPid;
1071 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1072 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1073 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1074 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1075 case sProvider: if (!m_dvb_service) return -1; return -2;
1081 std::string eDVBServicePlay::getInfoString(int w)
1086 if (!m_dvb_service) return "";
1087 return m_dvb_service->m_provider_name;
1093 int eDVBServicePlay::getNumberOfTracks()
1095 eDVBServicePMTHandler::program program;
1096 if (m_service_handler.getProgramInfo(program))
1098 return program.audioStreams.size();
1101 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1103 int ret = selectAudioStream(i);
1105 if (m_decoder->start())
1111 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1113 eDVBServicePMTHandler::program program;
1115 if (m_service_handler.getProgramInfo(program))
1118 if (i >= program.audioStreams.size())
1121 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1122 info.m_description = "MPEG";
1123 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1124 info.m_description = "AC3";
1125 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1126 info.m_description = "DTS";
1128 info.m_description = "???";
1130 if (program.audioStreams[i].component_tag != -1)
1132 ePtr<eServiceEvent> evt;
1133 if (!m_event_handler.getEvent(evt, 0))
1135 ePtr<eComponentData> data;
1136 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1137 info.m_language = data->getText();
1141 if (info.m_language.empty())
1142 info.m_language = program.audioStreams[i].language_code;
1147 int eDVBServicePlay::selectAudioStream(int i)
1149 eDVBServicePMTHandler::program program;
1151 if (m_service_handler.getProgramInfo(program))
1154 if ((unsigned int)i >= program.audioStreams.size())
1160 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1163 if (m_dvb_service && !m_is_pvr)
1165 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1167 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1168 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1171 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1172 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1176 m_current_audio_stream = i;
1181 int eDVBServicePlay::getFrontendInfo(int w)
1185 eUsePtr<iDVBChannel> channel;
1186 if(m_service_handler.getChannel(channel))
1188 ePtr<iDVBFrontend> fe;
1189 if(channel->getFrontend(fe))
1191 return fe->readFrontendData(w);
1194 PyObject *eDVBServicePlay::getFrontendData(bool original)
1198 eUsePtr<iDVBChannel> channel;
1199 if(!m_service_handler.getChannel(channel))
1201 ePtr<iDVBFrontend> fe;
1202 if(!channel->getFrontend(fe))
1204 ret = fe->readTransponderData(original);
1207 ePtr<iDVBFrontendParameters> feparm;
1208 channel->getCurrentFrontendParameters(feparm);
1211 eDVBFrontendParametersSatellite osat;
1212 if (!feparm->getDVBS(osat))
1214 void PutToDict(PyObject *, const char*, long);
1215 void PutToDict(PyObject *, const char*, const char*);
1216 PutToDict(ret, "orbital_position", osat.orbital_position);
1217 const char *tmp = "UNKNOWN";
1218 switch(osat.polarisation)
1220 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1221 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1222 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1223 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1226 PutToDict(ret, "polarization", tmp);
1240 int eDVBServicePlay::getNumberOfSubservices()
1242 ePtr<eServiceEvent> evt;
1243 if (!m_event_handler.getEvent(evt, 0))
1244 return evt->getNumOfLinkageServices();
1248 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1250 ePtr<eServiceEvent> evt;
1251 if (!m_event_handler.getEvent(evt, 0))
1253 if (!evt->getLinkageService(sub, m_reference, n))
1256 sub.type=eServiceReference::idInvalid;
1260 RESULT eDVBServicePlay::startTimeshift()
1262 ePtr<iDVBDemux> demux;
1264 eDebug("Start timeshift!");
1266 if (m_timeshift_enabled)
1269 /* start recording with the data demux. */
1270 if (m_service_handler.getDataDemux(demux))
1273 demux->createTSRecorder(m_record);
1277 char templ[]=TSPATH "/timeshift.XXXXXX";
1278 m_timeshift_fd = mkstemp(templ);
1279 m_timeshift_file = templ;
1281 eDebug("recording to %s", templ);
1283 if (m_timeshift_fd < 0)
1289 m_record->setTargetFD(m_timeshift_fd);
1291 m_timeshift_enabled = 1;
1293 updateTimeshiftPids();
1299 RESULT eDVBServicePlay::stopTimeshift()
1301 if (!m_timeshift_enabled)
1306 m_timeshift_enabled = 0;
1311 close(m_timeshift_fd);
1312 eDebug("remove timeshift file");
1313 remove(m_timeshift_file.c_str());
1318 int eDVBServicePlay::isTimeshiftActive()
1320 return m_timeshift_enabled && m_timeshift_active;
1323 RESULT eDVBServicePlay::activateTimeshift()
1325 if (!m_timeshift_enabled)
1328 if (!m_timeshift_active)
1330 switchToTimeshift();
1337 PyObject *eDVBServicePlay::getCutList()
1339 PyObject *list = PyList_New(0);
1341 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1343 PyObject *tuple = PyTuple_New(2);
1344 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1345 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1346 PyList_Append(list, tuple);
1353 void eDVBServicePlay::setCutList(PyObject *list)
1355 if (!PyList_Check(list))
1357 int size = PyList_Size(list);
1360 m_cue_entries.clear();
1362 for (i=0; i<size; ++i)
1364 PyObject *tuple = PyList_GetItem(list, i);
1365 if (!PyTuple_Check(tuple))
1367 eDebug("non-tuple in cutlist");
1370 if (PyTuple_Size(tuple) != 2)
1372 eDebug("cutlist entries need to be a 2-tuple");
1375 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1376 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1378 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1381 pts_t pts = PyLong_AsLongLong(ppts);
1382 int type = PyInt_AsLong(ptype);
1383 m_cue_entries.insert(cueEntry(pts, type));
1384 eDebug("adding %08llx, %d", pts, type);
1386 m_cuesheet_changed = 1;
1388 cutlistToCuesheet();
1389 m_event((iPlayableService*)this, evCuesheetChanged);
1392 void eDVBServicePlay::setCutListEnable(int enable)
1394 m_cutlist_enabled = enable;
1395 cutlistToCuesheet();
1398 void eDVBServicePlay::updateTimeshiftPids()
1403 eDVBServicePMTHandler::program program;
1404 if (m_service_handler.getProgramInfo(program))
1408 std::set<int> pids_to_record;
1409 pids_to_record.insert(0); // PAT
1410 if (program.pmtPid != -1)
1411 pids_to_record.insert(program.pmtPid); // PMT
1413 if (program.textPid != -1)
1414 pids_to_record.insert(program.textPid); // Videotext
1416 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1417 i(program.videoStreams.begin());
1418 i != program.videoStreams.end(); ++i)
1419 pids_to_record.insert(i->pid);
1421 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1422 i(program.audioStreams.begin());
1423 i != program.audioStreams.end(); ++i)
1424 pids_to_record.insert(i->pid);
1426 std::set<int> new_pids, obsolete_pids;
1428 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1429 m_pids_active.begin(), m_pids_active.end(),
1430 std::inserter(new_pids, new_pids.begin()));
1432 std::set_difference(
1433 m_pids_active.begin(), m_pids_active.end(),
1434 pids_to_record.begin(), pids_to_record.end(),
1435 std::inserter(new_pids, new_pids.begin())
1438 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1439 m_record->addPID(*i);
1441 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1442 m_record->removePID(*i);
1446 void eDVBServicePlay::switchToLive()
1448 if (!m_timeshift_active)
1453 /* free the timeshift service handler, we need the resources */
1454 m_service_handler_timeshift.free();
1455 m_timeshift_active = 0;
1457 m_event((iPlayableService*)this, evSeekableStatusChanged);
1462 void eDVBServicePlay::switchToTimeshift()
1464 if (m_timeshift_active)
1470 m_timeshift_active = 1;
1472 m_event((iPlayableService*)this, evSeekableStatusChanged);
1474 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1475 r.path = m_timeshift_file;
1477 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1478 updateDecoder(); /* mainly to switch off PCR */
1481 void eDVBServicePlay::updateDecoder()
1483 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1484 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1486 eDVBServicePMTHandler::program program;
1487 if (h.getProgramInfo(program))
1488 eDebug("getting program info failed.");
1491 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1492 if (!program.videoStreams.empty())
1494 eDebugNoNewLine(" (");
1495 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1496 i(program.videoStreams.begin());
1497 i != program.videoStreams.end(); ++i)
1501 if (i != program.videoStreams.begin())
1502 eDebugNoNewLine(", ");
1503 eDebugNoNewLine("%04x", i->pid);
1505 eDebugNoNewLine(")");
1507 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1508 if (!program.audioStreams.empty())
1510 eDebugNoNewLine(" (");
1511 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1512 i(program.audioStreams.begin());
1513 i != program.audioStreams.end(); ++i)
1520 if (i != program.audioStreams.begin())
1521 eDebugNoNewLine(", ");
1522 eDebugNoNewLine("%04x", i->pid);
1524 eDebugNoNewLine(")");
1526 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1527 pcrpid = program.pcrPid;
1528 eDebug(", and the text pid is %04x", program.textPid);
1529 tpid = program.textPid;
1534 h.getDecodeDemux(m_decode_demux);
1536 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1538 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1543 m_decoder->setVideoPID(vpid);
1544 m_current_audio_stream = 0;
1545 m_decoder->setAudioPID(apid, apidtype);
1546 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1547 m_decoder->setSyncPCR(pcrpid);
1549 m_decoder->setSyncPCR(-1);
1550 m_decoder->setTextPID(tpid);
1552 m_decoder->setTrickmode(1);
1554 // how we can do this better?
1555 // update cache pid when the user changed the audio track or video track
1556 // TODO handling of difference audio types.. default audio types..
1558 /* don't worry about non-existing services, nor pvr services */
1559 if (m_dvb_service && !m_is_pvr)
1561 if (apidtype == eDVBAudio::aMPEG)
1563 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1564 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1568 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1569 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1571 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1572 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1573 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1578 void eDVBServicePlay::loadCuesheet()
1580 std::string filename = m_reference.path + ".cuts";
1582 m_cue_entries.clear();
1584 FILE *f = fopen(filename.c_str(), "rb");
1588 eDebug("loading cuts..");
1591 unsigned long long where;
1594 if (!fread(&where, sizeof(where), 1, f))
1596 if (!fread(&what, sizeof(what), 1, f))
1599 #if BYTE_ORDER == LITTLE_ENDIAN
1600 where = bswap_64(where);
1607 m_cue_entries.insert(cueEntry(where, what));
1610 eDebug("%d entries", m_cue_entries.size());
1612 eDebug("cutfile not found!");
1614 m_cuesheet_changed = 0;
1615 cutlistToCuesheet();
1616 m_event((iPlayableService*)this, evCuesheetChanged);
1619 void eDVBServicePlay::saveCuesheet()
1621 std::string filename = m_reference.path + ".cuts";
1623 FILE *f = fopen(filename.c_str(), "wb");
1627 unsigned long long where;
1630 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1632 #if BYTE_ORDER == BIG_ENDIAN
1635 where = bswap_64(i->where);
1637 what = htonl(i->what);
1638 fwrite(&where, sizeof(where), 1, f);
1639 fwrite(&what, sizeof(what), 1, f);
1645 m_cuesheet_changed = 0;
1648 void eDVBServicePlay::cutlistToCuesheet()
1652 eDebug("no cue sheet");
1657 if (!m_cutlist_enabled)
1659 m_cue->commitSpans();
1660 eDebug("cutlists where disabled");
1664 pts_t in = 0, out = 0, length = 0;
1668 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1672 if (i == m_cue_entries.end())
1675 if (i->what == 0) /* in */
1679 } else if (i->what == 1) /* out */
1689 m_cue->addSourceSpan(in, out);
1693 if (i == m_cue_entries.end())
1696 m_cue->commitSpans();
1699 DEFINE_REF(eDVBServicePlay)
1701 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");