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::sTimeCreate:
190 if (m_parser.m_time_create)
191 return m_parser.m_time_create;
193 return iServiceInformation::resNA;
195 return iServiceInformation::resNA;
199 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
203 case iServiceInformation::sDescription:
204 return m_parser.m_description;
210 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
212 DECLARE_REF(eDVBPVRServiceOfflineOperations);
213 eServiceReferenceDVB m_ref;
215 eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
217 RESULT deleteFromDisk(int simulate);
218 RESULT getListOfFilenames(std::list<std::string> &);
221 DEFINE_REF(eDVBPVRServiceOfflineOperations);
223 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
227 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
233 std::list<std::string> res;
234 if (getListOfFilenames(res))
237 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
239 eDebug("FATAL !! can't get background file eraser");
241 /* TODO: deferred removing.. */
242 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
244 eDebug("Removing %s...", i->c_str());
246 eraser->erase(i->c_str());
248 ::unlink(i->c_str());
255 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
258 res.push_back(m_ref.path);
260 // handling for old splitted recordings (enigma 1)
265 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
267 if (stat(buf, &s) < 0)
272 res.push_back(m_ref.path + ".meta");
273 res.push_back(m_ref.path + ".ap");
274 res.push_back(m_ref.path + ".cuts");
275 std::string tmp = m_ref.path;
276 tmp.erase(m_ref.path.length()-3);
277 res.push_back(tmp + ".eit");
281 DEFINE_REF(eServiceFactoryDVB)
283 eServiceFactoryDVB::eServiceFactoryDVB()
285 ePtr<eServiceCenter> sc;
287 eServiceCenter::getPrivInstance(sc);
289 sc->addServiceFactory(eServiceFactoryDVB::id, this);
292 eServiceFactoryDVB::~eServiceFactoryDVB()
294 ePtr<eServiceCenter> sc;
296 eServiceCenter::getPrivInstance(sc);
298 sc->removeServiceFactory(eServiceFactoryDVB::id);
301 DEFINE_REF(eDVBServiceList);
303 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
307 eDVBServiceList::~eDVBServiceList()
311 RESULT eDVBServiceList::startQuery()
313 ePtr<iDVBChannelList> db;
314 ePtr<eDVBResourceManager> res;
317 if ((err = eDVBResourceManager::getInstance(res)) != 0)
319 eDebug("no resource manager");
322 if ((err = res->getChannelList(db)) != 0)
324 eDebug("no channel list");
328 ePtr<eDVBChannelQuery> q;
330 if (!m_parent.path.empty())
332 eDVBChannelQuery::compile(q, m_parent.path);
335 eDebug("compile query failed");
340 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
342 eDebug("startQuery failed");
349 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
351 eServiceReferenceDVB ref;
353 if (!m_query || !list || !PyList_Check(list))
356 std::list<eServiceReferenceDVB> tmplist;
358 while (!m_query->getNextResult(ref))
359 tmplist.push_back(ref);
362 tmplist.sort(iListableServiceCompare(this));
364 for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
365 it != tmplist.end(); ++it)
367 PyObject *refobj = New_eServiceReference(*it);
368 PyList_Append(list, refobj);
374 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
376 eServiceReferenceDVB ref;
381 while (!m_query->getNextResult(ref))
385 list.sort(iListableServiceCompare(this));
390 RESULT eDVBServiceList::getNext(eServiceReference &ref)
395 return m_query->getNextResult((eServiceReferenceDVB&)ref);
398 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
400 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
403 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
405 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
407 ePtr<iDVBChannelList> db;
408 ePtr<eDVBResourceManager> resm;
410 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
413 if (db->getBouquet(m_parent, m_bouquet) != 0)
424 RESULT eDVBServiceList::addService(eServiceReference &ref)
428 return m_bouquet->addService(ref);
431 RESULT eDVBServiceList::removeService(eServiceReference &ref)
435 return m_bouquet->removeService(ref);
438 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
442 return m_bouquet->moveService(ref, pos);
445 RESULT eDVBServiceList::flushChanges()
449 return m_bouquet->flushChanges();
452 RESULT eDVBServiceList::setListName(const std::string &name)
456 return m_bouquet->setListName(name);
459 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
461 ePtr<eDVBService> service;
462 int r = lookupService(service, ref);
465 // check resources...
466 ptr = new eDVBServicePlay(ref, service);
470 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
472 if (ref.path.empty())
474 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
483 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
485 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
486 if (list->startQuery())
496 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
498 /* is a listable service? */
499 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
501 if ( !ref.name.empty() ) // satellites or providers list
502 ptr = new eStaticServiceDVBInformation;
503 else // a dvb bouquet
504 ptr = new eStaticServiceDVBBouquetInformation;
506 else if (!ref.path.empty()) /* do we have a PVR service? */
507 ptr = new eStaticServiceDVBPVRInformation(ref);
508 else // normal dvb service
510 ePtr<eDVBService> service;
511 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
512 ptr = new eStaticServiceDVBInformation;
514 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
520 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
522 if (ref.path.empty())
528 ptr = new eDVBPVRServiceOfflineOperations(ref);
533 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
535 // TODO: handle the listing itself
536 // if (ref.... == -1) .. return "... bouquets ...";
537 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
539 ePtr<iDVBChannelList> db;
540 ePtr<eDVBResourceManager> res;
543 if ((err = eDVBResourceManager::getInstance(res)) != 0)
545 eDebug("no resource manager");
548 if ((err = res->getChannelList(db)) != 0)
550 eDebug("no channel list");
554 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
555 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
557 eDebug("getService failed!");
564 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
565 m_reference(ref), m_dvb_service(service), m_is_paused(0)
567 m_is_pvr = !ref.path.empty();
569 m_timeshift_enabled = m_timeshift_active = 0;
572 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
573 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
574 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
576 m_cuesheet_changed = 0;
577 m_cutlist_enabled = 1;
580 eDVBServicePlay::~eDVBServicePlay()
584 void eDVBServicePlay::gotNewEvent()
588 ePtr<eServiceEvent> m_event_now, m_event_next;
589 getEvent(m_event_now, 0);
590 getEvent(m_event_next, 1);
593 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
595 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
597 m_event((iPlayableService*)this, evUpdatedEventInfo);
600 void eDVBServicePlay::serviceEvent(int event)
604 case eDVBServicePMTHandler::eventTuned:
606 ePtr<iDVBDemux> m_demux;
607 if (!m_service_handler.getDataDemux(m_demux))
609 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
610 int sid = ref.getParentServiceID().get();
612 sid = ref.getServiceID().get();
613 if ( ref.getParentTransportStreamID().get() &&
614 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
615 m_event_handler.startOther(m_demux, sid);
617 m_event_handler.start(m_demux, sid);
621 case eDVBServicePMTHandler::eventTuneFailed:
623 eDebug("DVB service failed to tune");
624 m_event((iPlayableService*)this, evTuneFailed);
627 case eDVBServicePMTHandler::eventNewProgramInfo:
629 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
630 if (m_timeshift_enabled)
631 updateTimeshiftPids();
632 if (!m_timeshift_active)
634 if (m_first_program_info && m_is_pvr)
636 m_first_program_info = 0;
639 m_event((iPlayableService*)this, evUpdatedInfo);
642 case eDVBServicePMTHandler::eventEOF:
643 m_event((iPlayableService*)this, evEOF);
645 case eDVBServicePMTHandler::eventSOF:
646 m_event((iPlayableService*)this, evSOF);
651 void eDVBServicePlay::serviceEventTimeshift(int event)
655 case eDVBServicePMTHandler::eventNewProgramInfo:
656 if (m_timeshift_active)
659 case eDVBServicePMTHandler::eventSOF:
660 m_event((iPlayableService*)this, evSOF);
662 case eDVBServicePMTHandler::eventEOF:
668 RESULT eDVBServicePlay::start()
671 /* in pvr mode, we only want to use one demux. in tv mode, we're using
672 two (one for decoding, one for data source), as we must be prepared
673 to start recording from the data demux. */
674 m_cue = new eCueSheet();
676 m_first_program_info = 1;
677 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
678 r = m_service_handler.tune(service, m_is_pvr, m_cue);
680 /* inject EIT if there is a stored one */
683 std::string filename = service.path;
684 filename.erase(filename.length()-2, 2);
686 int fd = ::open( filename.c_str(), O_RDONLY );
690 int rd = ::read(fd, buf, 4096);
692 if ( rd > 12 /*EIT_LOOP_SIZE*/ )
695 ePtr<eServiceEvent> event = new eServiceEvent;
696 ePtr<eServiceEvent> empty;
697 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
698 m_event_handler.inject(event, 0);
699 m_event_handler.inject(empty, 1);
708 m_event(this, evStart);
709 m_event((iPlayableService*)this, evSeekableStatusChanged);
713 RESULT eDVBServicePlay::stop()
715 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
717 m_service_handler_timeshift.free();
718 m_service_handler.free();
720 if (m_is_pvr && m_cuesheet_changed)
726 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
728 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
732 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
734 /* note: we check for timeshift to be enabled,
735 not neccessary active. if you pause when timeshift
736 is not active, you should activate it when unpausing */
737 if ((!m_is_pvr) && (!m_timeshift_enabled))
747 RESULT eDVBServicePlay::setSlowMotion(int ratio)
750 return m_decoder->setSlowMotion(ratio);
755 RESULT eDVBServicePlay::setFastForward(int ratio)
757 int skipmode, ffratio;
763 } else if (ratio > 0)
771 } else // if (ratio < 0)
777 if (m_skipmode != skipmode)
779 eDebug("setting cue skipmode to %d", skipmode);
781 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
784 m_skipmode = skipmode;
789 return m_decoder->setFastForward(ffratio);
792 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
794 if (m_is_pvr || m_timeshift_enabled)
804 /* TODO: when timeshift is enabled but not active, this doesn't work. */
805 RESULT eDVBServicePlay::getLength(pts_t &len)
807 ePtr<iDVBPVRChannel> pvr_channel;
809 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
812 return pvr_channel->getLength(len);
815 RESULT eDVBServicePlay::pause()
817 if (!m_is_paused && m_decoder)
820 return m_decoder->freeze(0);
825 RESULT eDVBServicePlay::unpause()
827 if (m_is_paused && m_decoder)
830 return m_decoder->unfreeze();
835 RESULT eDVBServicePlay::seekTo(pts_t to)
837 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
842 ePtr<iDVBPVRChannel> pvr_channel;
844 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
850 m_cue->seekTo(0, to);
854 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
856 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
861 ePtr<iDVBPVRChannel> pvr_channel;
863 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
868 /* HACK until we have skip-AP api */
869 if ((to > 0) && (to < 100))
877 m_cue->seekTo(mode, to);
881 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
883 ePtr<iDVBPVRChannel> pvr_channel;
888 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
893 /* if there is a decoder, use audio or video PTS */
896 r = m_decoder->getPTS(0, pos);
902 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
905 RESULT eDVBServicePlay::setTrickmode(int trick)
908 m_decoder->setTrickmode(trick);
912 RESULT eDVBServicePlay::isCurrentlySeekable()
914 return m_is_pvr || m_timeshift_active;
917 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
923 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
929 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
935 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
941 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
944 if (m_timeshift_enabled || !m_is_pvr)
946 if (!m_timeshift_enabled)
948 /* we need enough diskspace */
950 if (statfs(TSPATH "/.", &fs) < 0)
952 eDebug("statfs failed!");
956 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
958 eDebug("not enough diskspace for timeshift! (less than 1GB)");
968 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
979 RESULT eDVBServicePlay::getName(std::string &name)
983 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
984 return i->getName(m_reference, name);
988 m_dvb_service->getName(m_reference, name);
992 else if (!m_reference.name.empty())
993 eStaticServiceDVBInformation().getName(m_reference, name);
995 name = "DVB service";
999 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1001 return m_event_handler.getEvent(evt, nownext);
1004 int eDVBServicePlay::getInfo(int w)
1006 eDVBServicePMTHandler::program program;
1008 if (m_service_handler.getProgramInfo(program))
1014 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1016 ePtr<eServiceEvent> evt;
1017 if (!m_event_handler.getEvent(evt, 0))
1019 ePtr<eComponentData> data;
1020 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1022 if ( data->getStreamContent() == 1 )
1024 switch(data->getComponentType())
1027 case 1: // 4:3 SD PAL
1029 case 3: // 16:9 SD PAL
1030 case 4: // > 16:9 PAL
1031 case 5: // 4:3 SD NTSC
1033 case 7: // 16:9 SD NTSC
1034 case 8: // > 16:9 NTSC
1037 case 9: // 4:3 HD PAL
1039 case 0xB: // 16:9 HD PAL
1040 case 0xC: // > 16:9 HD PAL
1041 case 0xD: // 4:3 HD NTSC
1043 case 0xF: // 16:9 HD NTSC
1044 case 0x10: // > 16:9 HD PAL
1045 return data->getComponentType();
1052 case sIsCrypted: return program.isCrypted;
1053 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1054 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1055 case sPCRPID: return program.pcrPid;
1056 case sPMTPID: return program.pmtPid;
1057 case sTXTPID: return program.textPid;
1058 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1059 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1060 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1061 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1062 case sProvider: if (!m_dvb_service) return -1; return -2;
1068 std::string eDVBServicePlay::getInfoString(int w)
1073 if (!m_dvb_service) return "";
1074 return m_dvb_service->m_provider_name;
1080 int eDVBServicePlay::getNumberOfTracks()
1082 eDVBServicePMTHandler::program program;
1083 if (m_service_handler.getProgramInfo(program))
1085 return program.audioStreams.size();
1088 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1090 int ret = selectAudioStream(i);
1092 if (m_decoder->start())
1098 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1100 eDVBServicePMTHandler::program program;
1102 if (m_service_handler.getProgramInfo(program))
1105 if (i >= program.audioStreams.size())
1108 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1109 info.m_description = "MPEG";
1110 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1111 info.m_description = "AC3";
1112 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1113 info.m_description = "DTS";
1115 info.m_description = "???";
1117 if (program.audioStreams[i].component_tag != -1)
1119 ePtr<eServiceEvent> evt;
1120 if (!m_event_handler.getEvent(evt, 0))
1122 ePtr<eComponentData> data;
1123 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1124 info.m_language = data->getText();
1128 if (info.m_language.empty())
1129 info.m_language = program.audioStreams[i].language_code;
1134 int eDVBServicePlay::selectAudioStream(int i)
1136 eDVBServicePMTHandler::program program;
1138 if (m_service_handler.getProgramInfo(program))
1141 if ((unsigned int)i >= program.audioStreams.size())
1147 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1150 if (m_dvb_service && !m_is_pvr)
1152 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1154 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1155 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1158 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1159 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1163 m_current_audio_stream = i;
1168 int eDVBServicePlay::getFrontendInfo(int w)
1172 eUsePtr<iDVBChannel> channel;
1173 if(m_service_handler.getChannel(channel))
1175 ePtr<iDVBFrontend> fe;
1176 if(channel->getFrontend(fe))
1178 return fe->readFrontendData(w);
1181 PyObject *eDVBServicePlay::getFrontendData(bool original)
1185 eUsePtr<iDVBChannel> channel;
1186 if(!m_service_handler.getChannel(channel))
1188 ePtr<iDVBFrontend> fe;
1189 if(!channel->getFrontend(fe))
1191 ret = fe->readTransponderData(original);
1194 ePtr<iDVBFrontendParameters> feparm;
1195 channel->getCurrentFrontendParameters(feparm);
1198 eDVBFrontendParametersSatellite osat;
1199 if (!feparm->getDVBS(osat))
1201 void PutToDict(PyObject *, const char*, long);
1202 void PutToDict(PyObject *, const char*, const char*);
1203 PutToDict(ret, "orbital_position", osat.orbital_position);
1204 const char *tmp = "UNKNOWN";
1205 switch(osat.polarisation)
1207 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1208 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1209 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1210 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1213 PutToDict(ret, "polarization", tmp);
1227 int eDVBServicePlay::getNumberOfSubservices()
1229 ePtr<eServiceEvent> evt;
1230 if (!m_event_handler.getEvent(evt, 0))
1231 return evt->getNumOfLinkageServices();
1235 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1237 ePtr<eServiceEvent> evt;
1238 if (!m_event_handler.getEvent(evt, 0))
1240 if (!evt->getLinkageService(sub, m_reference, n))
1243 sub.type=eServiceReference::idInvalid;
1247 RESULT eDVBServicePlay::startTimeshift()
1249 ePtr<iDVBDemux> demux;
1251 eDebug("Start timeshift!");
1253 if (m_timeshift_enabled)
1256 /* start recording with the data demux. */
1257 if (m_service_handler.getDataDemux(demux))
1260 demux->createTSRecorder(m_record);
1264 char templ[]=TSPATH "/timeshift.XXXXXX";
1265 m_timeshift_fd = mkstemp(templ);
1266 m_timeshift_file = templ;
1268 eDebug("recording to %s", templ);
1270 if (m_timeshift_fd < 0)
1276 m_record->setTargetFD(m_timeshift_fd);
1278 m_timeshift_enabled = 1;
1280 updateTimeshiftPids();
1286 RESULT eDVBServicePlay::stopTimeshift()
1288 if (!m_timeshift_enabled)
1293 m_timeshift_enabled = 0;
1298 close(m_timeshift_fd);
1299 eDebug("remove timeshift file");
1300 remove(m_timeshift_file.c_str());
1305 int eDVBServicePlay::isTimeshiftActive()
1307 return m_timeshift_enabled && m_timeshift_active;
1310 RESULT eDVBServicePlay::activateTimeshift()
1312 if (!m_timeshift_enabled)
1315 if (!m_timeshift_active)
1317 switchToTimeshift();
1324 PyObject *eDVBServicePlay::getCutList()
1326 PyObject *list = PyList_New(0);
1328 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1330 PyObject *tuple = PyTuple_New(2);
1331 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1332 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1333 PyList_Append(list, tuple);
1340 void eDVBServicePlay::setCutList(PyObject *list)
1342 if (!PyList_Check(list))
1344 int size = PyList_Size(list);
1347 m_cue_entries.clear();
1349 for (i=0; i<size; ++i)
1351 PyObject *tuple = PyList_GetItem(list, i);
1352 if (!PyTuple_Check(tuple))
1354 eDebug("non-tuple in cutlist");
1357 if (PyTuple_Size(tuple) != 2)
1359 eDebug("cutlist entries need to be a 2-tuple");
1362 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1363 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1365 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1368 pts_t pts = PyLong_AsLongLong(ppts);
1369 int type = PyInt_AsLong(ptype);
1370 m_cue_entries.insert(cueEntry(pts, type));
1371 eDebug("adding %08llx, %d", pts, type);
1373 m_cuesheet_changed = 1;
1375 cutlistToCuesheet();
1376 m_event((iPlayableService*)this, evCuesheetChanged);
1379 void eDVBServicePlay::setCutListEnable(int enable)
1381 m_cutlist_enabled = enable;
1382 cutlistToCuesheet();
1385 void eDVBServicePlay::updateTimeshiftPids()
1390 eDVBServicePMTHandler::program program;
1391 if (m_service_handler.getProgramInfo(program))
1395 std::set<int> pids_to_record;
1396 pids_to_record.insert(0); // PAT
1397 if (program.pmtPid != -1)
1398 pids_to_record.insert(program.pmtPid); // PMT
1400 if (program.textPid != -1)
1401 pids_to_record.insert(program.textPid); // Videotext
1403 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1404 i(program.videoStreams.begin());
1405 i != program.videoStreams.end(); ++i)
1406 pids_to_record.insert(i->pid);
1408 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1409 i(program.audioStreams.begin());
1410 i != program.audioStreams.end(); ++i)
1411 pids_to_record.insert(i->pid);
1413 std::set<int> new_pids, obsolete_pids;
1415 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1416 m_pids_active.begin(), m_pids_active.end(),
1417 std::inserter(new_pids, new_pids.begin()));
1419 std::set_difference(
1420 m_pids_active.begin(), m_pids_active.end(),
1421 pids_to_record.begin(), pids_to_record.end(),
1422 std::inserter(new_pids, new_pids.begin())
1425 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1426 m_record->addPID(*i);
1428 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1429 m_record->removePID(*i);
1433 void eDVBServicePlay::switchToLive()
1435 if (!m_timeshift_active)
1440 /* free the timeshift service handler, we need the resources */
1441 m_service_handler_timeshift.free();
1442 m_timeshift_active = 0;
1444 m_event((iPlayableService*)this, evSeekableStatusChanged);
1449 void eDVBServicePlay::switchToTimeshift()
1451 if (m_timeshift_active)
1457 m_timeshift_active = 1;
1459 m_event((iPlayableService*)this, evSeekableStatusChanged);
1461 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1462 r.path = m_timeshift_file;
1464 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1465 updateDecoder(); /* mainly to switch off PCR */
1468 void eDVBServicePlay::updateDecoder()
1470 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1471 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1473 eDVBServicePMTHandler::program program;
1474 if (h.getProgramInfo(program))
1475 eDebug("getting program info failed.");
1478 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1479 if (!program.videoStreams.empty())
1481 eDebugNoNewLine(" (");
1482 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1483 i(program.videoStreams.begin());
1484 i != program.videoStreams.end(); ++i)
1488 if (i != program.videoStreams.begin())
1489 eDebugNoNewLine(", ");
1490 eDebugNoNewLine("%04x", i->pid);
1492 eDebugNoNewLine(")");
1494 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1495 if (!program.audioStreams.empty())
1497 eDebugNoNewLine(" (");
1498 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1499 i(program.audioStreams.begin());
1500 i != program.audioStreams.end(); ++i)
1507 if (i != program.audioStreams.begin())
1508 eDebugNoNewLine(", ");
1509 eDebugNoNewLine("%04x", i->pid);
1511 eDebugNoNewLine(")");
1513 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1514 pcrpid = program.pcrPid;
1515 eDebug(", and the text pid is %04x", program.textPid);
1516 tpid = program.textPid;
1521 h.getDecodeDemux(m_decode_demux);
1523 m_decode_demux->getMPEGDecoder(m_decoder);
1525 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1530 m_decoder->setVideoPID(vpid);
1531 m_current_audio_stream = 0;
1532 m_decoder->setAudioPID(apid, apidtype);
1533 if (!(m_is_pvr || m_timeshift_active))
1534 m_decoder->setSyncPCR(pcrpid);
1536 m_decoder->setSyncPCR(-1);
1537 m_decoder->setTextPID(tpid);
1539 // how we can do this better?
1540 // update cache pid when the user changed the audio track or video track
1541 // TODO handling of difference audio types.. default audio types..
1543 /* don't worry about non-existing services, nor pvr services */
1544 if (m_dvb_service && !m_is_pvr)
1546 if (apidtype == eDVBAudio::aMPEG)
1548 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1549 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1553 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1554 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1556 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1557 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1558 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1563 void eDVBServicePlay::loadCuesheet()
1565 std::string filename = m_reference.path + ".cuts";
1567 m_cue_entries.clear();
1569 FILE *f = fopen(filename.c_str(), "rb");
1573 eDebug("loading cuts..");
1576 unsigned long long where;
1579 if (!fread(&where, sizeof(where), 1, f))
1581 if (!fread(&what, sizeof(what), 1, f))
1584 #if BYTE_ORDER == LITTLE_ENDIAN
1585 where = bswap_64(where);
1592 m_cue_entries.insert(cueEntry(where, what));
1595 eDebug("%d entries", m_cue_entries.size());
1597 eDebug("cutfile not found!");
1599 m_cuesheet_changed = 0;
1600 cutlistToCuesheet();
1601 m_event((iPlayableService*)this, evCuesheetChanged);
1604 void eDVBServicePlay::saveCuesheet()
1606 std::string filename = m_reference.path + ".cuts";
1608 FILE *f = fopen(filename.c_str(), "wb");
1612 unsigned long long where;
1615 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1617 #if BYTE_ORDER == BIG_ENDIAN
1620 where = bswap_64(i->where);
1622 what = htonl(i->what);
1623 fwrite(&where, sizeof(where), 1, f);
1624 fwrite(&what, sizeof(what), 1, f);
1630 m_cuesheet_changed = 0;
1633 void eDVBServicePlay::cutlistToCuesheet()
1637 eDebug("no cue sheet");
1642 if (!m_cutlist_enabled)
1644 m_cue->commitSpans();
1645 eDebug("cutlists where disabled");
1649 pts_t in = 0, out = 0, length = 0;
1653 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1657 if (i == m_cue_entries.end())
1660 if (i->what == 0) /* in */
1664 } else if (i->what == 1) /* out */
1674 m_cue->addSourceSpan(in, out);
1678 if (i == m_cue_entries.end())
1681 m_cue->commitSpans();
1684 DEFINE_REF(eDVBServicePlay)
1686 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");