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)
572 m_is_pvr = !m_reference.path.empty();
574 m_timeshift_enabled = m_timeshift_active = 0;
577 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
578 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
579 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
581 m_cuesheet_changed = 0;
582 m_cutlist_enabled = 1;
585 eDVBServicePlay::~eDVBServicePlay()
589 void eDVBServicePlay::gotNewEvent()
593 ePtr<eServiceEvent> m_event_now, m_event_next;
594 getEvent(m_event_now, 0);
595 getEvent(m_event_next, 1);
598 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
600 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
602 m_event((iPlayableService*)this, evUpdatedEventInfo);
605 void eDVBServicePlay::serviceEvent(int event)
609 case eDVBServicePMTHandler::eventTuned:
611 ePtr<iDVBDemux> m_demux;
612 if (!m_service_handler.getDataDemux(m_demux))
614 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
615 int sid = ref.getParentServiceID().get();
617 sid = ref.getServiceID().get();
618 if ( ref.getParentTransportStreamID().get() &&
619 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
620 m_event_handler.startOther(m_demux, sid);
622 m_event_handler.start(m_demux, sid);
626 case eDVBServicePMTHandler::eventTuneFailed:
628 eDebug("DVB service failed to tune");
629 m_event((iPlayableService*)this, evTuneFailed);
632 case eDVBServicePMTHandler::eventNewProgramInfo:
634 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
635 if (m_timeshift_enabled)
636 updateTimeshiftPids();
637 if (!m_timeshift_active)
639 if (m_first_program_info && m_is_pvr)
641 m_first_program_info = 0;
644 m_event((iPlayableService*)this, evUpdatedInfo);
647 case eDVBServicePMTHandler::eventEOF:
648 m_event((iPlayableService*)this, evEOF);
650 case eDVBServicePMTHandler::eventSOF:
651 m_event((iPlayableService*)this, evSOF);
656 void eDVBServicePlay::serviceEventTimeshift(int event)
660 case eDVBServicePMTHandler::eventNewProgramInfo:
661 if (m_timeshift_active)
664 case eDVBServicePMTHandler::eventSOF:
665 m_event((iPlayableService*)this, evSOF);
667 case eDVBServicePMTHandler::eventEOF:
673 RESULT eDVBServicePlay::start()
676 /* in pvr mode, we only want to use one demux. in tv mode, we're using
677 two (one for decoding, one for data source), as we must be prepared
678 to start recording from the data demux. */
679 m_cue = new eCueSheet();
681 m_first_program_info = 1;
682 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
683 r = m_service_handler.tune(service, m_is_pvr, m_cue);
685 /* inject EIT if there is a stored one */
688 std::string filename = service.path;
689 filename.erase(filename.length()-2, 2);
691 int fd = ::open( filename.c_str(), O_RDONLY );
695 int rd = ::read(fd, buf, 4096);
697 if ( rd > 12 /*EIT_LOOP_SIZE*/ )
700 ePtr<eServiceEvent> event = new eServiceEvent;
701 ePtr<eServiceEvent> empty;
702 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
703 m_event_handler.inject(event, 0);
704 m_event_handler.inject(empty, 1);
713 m_event(this, evStart);
714 m_event((iPlayableService*)this, evSeekableStatusChanged);
718 RESULT eDVBServicePlay::stop()
720 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
722 m_service_handler_timeshift.free();
723 m_service_handler.free();
725 if (m_is_pvr && m_cuesheet_changed)
731 RESULT eDVBServicePlay::setTarget(int target)
733 m_is_primary = !target;
737 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
739 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
743 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
745 /* note: we check for timeshift to be enabled,
746 not neccessary active. if you pause when timeshift
747 is not active, you should activate it when unpausing */
748 if ((!m_is_pvr) && (!m_timeshift_enabled))
758 RESULT eDVBServicePlay::setSlowMotion(int ratio)
761 return m_decoder->setSlowMotion(ratio);
766 RESULT eDVBServicePlay::setFastForward(int ratio)
768 int skipmode, ffratio;
774 } else if (ratio > 0)
782 } else // if (ratio < 0)
788 if (m_skipmode != skipmode)
790 eDebug("setting cue skipmode to %d", skipmode);
792 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
795 m_skipmode = skipmode;
800 return m_decoder->setFastForward(ffratio);
803 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
805 if (m_is_pvr || m_timeshift_enabled)
815 /* TODO: when timeshift is enabled but not active, this doesn't work. */
816 RESULT eDVBServicePlay::getLength(pts_t &len)
818 ePtr<iDVBPVRChannel> pvr_channel;
820 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
823 return pvr_channel->getLength(len);
826 RESULT eDVBServicePlay::pause()
828 if (!m_is_paused && m_decoder)
831 return m_decoder->freeze(0);
836 RESULT eDVBServicePlay::unpause()
838 if (m_is_paused && m_decoder)
841 return m_decoder->unfreeze();
846 RESULT eDVBServicePlay::seekTo(pts_t to)
848 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
853 ePtr<iDVBPVRChannel> pvr_channel;
855 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
861 m_cue->seekTo(0, to);
865 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
867 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
872 ePtr<iDVBPVRChannel> pvr_channel;
874 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
879 /* HACK until we have skip-AP api */
880 if ((to > 0) && (to < 100))
888 m_cue->seekTo(mode, to);
892 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
894 ePtr<iDVBPVRChannel> pvr_channel;
899 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
904 /* if there is a decoder, use audio or video PTS */
907 r = m_decoder->getPTS(0, pos);
913 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
916 RESULT eDVBServicePlay::setTrickmode(int trick)
919 m_decoder->setTrickmode(trick);
923 RESULT eDVBServicePlay::isCurrentlySeekable()
925 return m_is_pvr || m_timeshift_active;
928 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
934 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
940 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
946 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
952 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
955 if (m_timeshift_enabled || !m_is_pvr)
957 if (!m_timeshift_enabled)
959 /* we need enough diskspace */
961 if (statfs(TSPATH "/.", &fs) < 0)
963 eDebug("statfs failed!");
967 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
969 eDebug("not enough diskspace for timeshift! (less than 1GB)");
979 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
990 RESULT eDVBServicePlay::getName(std::string &name)
994 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
995 return i->getName(m_reference, name);
999 m_dvb_service->getName(m_reference, name);
1003 else if (!m_reference.name.empty())
1004 eStaticServiceDVBInformation().getName(m_reference, name);
1006 name = "DVB service";
1010 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1012 return m_event_handler.getEvent(evt, nownext);
1015 int eDVBServicePlay::getInfo(int w)
1017 eDVBServicePMTHandler::program program;
1019 if (m_service_handler.getProgramInfo(program))
1025 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1027 ePtr<eServiceEvent> evt;
1028 if (!m_event_handler.getEvent(evt, 0))
1030 ePtr<eComponentData> data;
1031 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1033 if ( data->getStreamContent() == 1 )
1035 switch(data->getComponentType())
1038 case 1: // 4:3 SD PAL
1040 case 3: // 16:9 SD PAL
1041 case 4: // > 16:9 PAL
1042 case 5: // 4:3 SD NTSC
1044 case 7: // 16:9 SD NTSC
1045 case 8: // > 16:9 NTSC
1048 case 9: // 4:3 HD PAL
1050 case 0xB: // 16:9 HD PAL
1051 case 0xC: // > 16:9 HD PAL
1052 case 0xD: // 4:3 HD NTSC
1054 case 0xF: // 16:9 HD NTSC
1055 case 0x10: // > 16:9 HD PAL
1056 return data->getComponentType();
1063 case sIsCrypted: return program.isCrypted;
1064 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1065 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1066 case sPCRPID: return program.pcrPid;
1067 case sPMTPID: return program.pmtPid;
1068 case sTXTPID: return program.textPid;
1069 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1070 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1071 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1072 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1073 case sProvider: if (!m_dvb_service) return -1; return -2;
1079 std::string eDVBServicePlay::getInfoString(int w)
1084 if (!m_dvb_service) return "";
1085 return m_dvb_service->m_provider_name;
1091 int eDVBServicePlay::getNumberOfTracks()
1093 eDVBServicePMTHandler::program program;
1094 if (m_service_handler.getProgramInfo(program))
1096 return program.audioStreams.size();
1099 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1101 int ret = selectAudioStream(i);
1103 if (m_decoder->start())
1109 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1111 eDVBServicePMTHandler::program program;
1113 if (m_service_handler.getProgramInfo(program))
1116 if (i >= program.audioStreams.size())
1119 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1120 info.m_description = "MPEG";
1121 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1122 info.m_description = "AC3";
1123 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1124 info.m_description = "DTS";
1126 info.m_description = "???";
1128 if (program.audioStreams[i].component_tag != -1)
1130 ePtr<eServiceEvent> evt;
1131 if (!m_event_handler.getEvent(evt, 0))
1133 ePtr<eComponentData> data;
1134 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1135 info.m_language = data->getText();
1139 if (info.m_language.empty())
1140 info.m_language = program.audioStreams[i].language_code;
1145 int eDVBServicePlay::selectAudioStream(int i)
1147 eDVBServicePMTHandler::program program;
1149 if (m_service_handler.getProgramInfo(program))
1152 if ((unsigned int)i >= program.audioStreams.size())
1158 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1161 if (m_dvb_service && !m_is_pvr)
1163 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1165 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1166 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1169 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1170 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1174 m_current_audio_stream = i;
1179 int eDVBServicePlay::getFrontendInfo(int w)
1183 eUsePtr<iDVBChannel> channel;
1184 if(m_service_handler.getChannel(channel))
1186 ePtr<iDVBFrontend> fe;
1187 if(channel->getFrontend(fe))
1189 return fe->readFrontendData(w);
1192 PyObject *eDVBServicePlay::getFrontendData(bool original)
1196 eUsePtr<iDVBChannel> channel;
1197 if(!m_service_handler.getChannel(channel))
1199 ePtr<iDVBFrontend> fe;
1200 if(!channel->getFrontend(fe))
1202 ret = fe->readTransponderData(original);
1205 ePtr<iDVBFrontendParameters> feparm;
1206 channel->getCurrentFrontendParameters(feparm);
1209 eDVBFrontendParametersSatellite osat;
1210 if (!feparm->getDVBS(osat))
1212 void PutToDict(PyObject *, const char*, long);
1213 void PutToDict(PyObject *, const char*, const char*);
1214 PutToDict(ret, "orbital_position", osat.orbital_position);
1215 const char *tmp = "UNKNOWN";
1216 switch(osat.polarisation)
1218 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1219 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1220 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1221 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1224 PutToDict(ret, "polarization", tmp);
1238 int eDVBServicePlay::getNumberOfSubservices()
1240 ePtr<eServiceEvent> evt;
1241 if (!m_event_handler.getEvent(evt, 0))
1242 return evt->getNumOfLinkageServices();
1246 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1248 ePtr<eServiceEvent> evt;
1249 if (!m_event_handler.getEvent(evt, 0))
1251 if (!evt->getLinkageService(sub, m_reference, n))
1254 sub.type=eServiceReference::idInvalid;
1258 RESULT eDVBServicePlay::startTimeshift()
1260 ePtr<iDVBDemux> demux;
1262 eDebug("Start timeshift!");
1264 if (m_timeshift_enabled)
1267 /* start recording with the data demux. */
1268 if (m_service_handler.getDataDemux(demux))
1271 demux->createTSRecorder(m_record);
1275 char templ[]=TSPATH "/timeshift.XXXXXX";
1276 m_timeshift_fd = mkstemp(templ);
1277 m_timeshift_file = templ;
1279 eDebug("recording to %s", templ);
1281 if (m_timeshift_fd < 0)
1287 m_record->setTargetFD(m_timeshift_fd);
1289 m_timeshift_enabled = 1;
1291 updateTimeshiftPids();
1297 RESULT eDVBServicePlay::stopTimeshift()
1299 if (!m_timeshift_enabled)
1304 m_timeshift_enabled = 0;
1309 close(m_timeshift_fd);
1310 eDebug("remove timeshift file");
1311 remove(m_timeshift_file.c_str());
1316 int eDVBServicePlay::isTimeshiftActive()
1318 return m_timeshift_enabled && m_timeshift_active;
1321 RESULT eDVBServicePlay::activateTimeshift()
1323 if (!m_timeshift_enabled)
1326 if (!m_timeshift_active)
1328 switchToTimeshift();
1335 PyObject *eDVBServicePlay::getCutList()
1337 PyObject *list = PyList_New(0);
1339 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1341 PyObject *tuple = PyTuple_New(2);
1342 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1343 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1344 PyList_Append(list, tuple);
1351 void eDVBServicePlay::setCutList(PyObject *list)
1353 if (!PyList_Check(list))
1355 int size = PyList_Size(list);
1358 m_cue_entries.clear();
1360 for (i=0; i<size; ++i)
1362 PyObject *tuple = PyList_GetItem(list, i);
1363 if (!PyTuple_Check(tuple))
1365 eDebug("non-tuple in cutlist");
1368 if (PyTuple_Size(tuple) != 2)
1370 eDebug("cutlist entries need to be a 2-tuple");
1373 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1374 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1376 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1379 pts_t pts = PyLong_AsLongLong(ppts);
1380 int type = PyInt_AsLong(ptype);
1381 m_cue_entries.insert(cueEntry(pts, type));
1382 eDebug("adding %08llx, %d", pts, type);
1384 m_cuesheet_changed = 1;
1386 cutlistToCuesheet();
1387 m_event((iPlayableService*)this, evCuesheetChanged);
1390 void eDVBServicePlay::setCutListEnable(int enable)
1392 m_cutlist_enabled = enable;
1393 cutlistToCuesheet();
1396 void eDVBServicePlay::updateTimeshiftPids()
1401 eDVBServicePMTHandler::program program;
1402 if (m_service_handler.getProgramInfo(program))
1406 std::set<int> pids_to_record;
1407 pids_to_record.insert(0); // PAT
1408 if (program.pmtPid != -1)
1409 pids_to_record.insert(program.pmtPid); // PMT
1411 if (program.textPid != -1)
1412 pids_to_record.insert(program.textPid); // Videotext
1414 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1415 i(program.videoStreams.begin());
1416 i != program.videoStreams.end(); ++i)
1417 pids_to_record.insert(i->pid);
1419 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1420 i(program.audioStreams.begin());
1421 i != program.audioStreams.end(); ++i)
1422 pids_to_record.insert(i->pid);
1424 std::set<int> new_pids, obsolete_pids;
1426 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1427 m_pids_active.begin(), m_pids_active.end(),
1428 std::inserter(new_pids, new_pids.begin()));
1430 std::set_difference(
1431 m_pids_active.begin(), m_pids_active.end(),
1432 pids_to_record.begin(), pids_to_record.end(),
1433 std::inserter(new_pids, new_pids.begin())
1436 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1437 m_record->addPID(*i);
1439 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1440 m_record->removePID(*i);
1444 void eDVBServicePlay::switchToLive()
1446 if (!m_timeshift_active)
1451 /* free the timeshift service handler, we need the resources */
1452 m_service_handler_timeshift.free();
1453 m_timeshift_active = 0;
1455 m_event((iPlayableService*)this, evSeekableStatusChanged);
1460 void eDVBServicePlay::switchToTimeshift()
1462 if (m_timeshift_active)
1468 m_timeshift_active = 1;
1470 m_event((iPlayableService*)this, evSeekableStatusChanged);
1472 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1473 r.path = m_timeshift_file;
1475 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1476 updateDecoder(); /* mainly to switch off PCR */
1479 void eDVBServicePlay::updateDecoder()
1481 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1482 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1484 eDVBServicePMTHandler::program program;
1485 if (h.getProgramInfo(program))
1486 eDebug("getting program info failed.");
1489 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1490 if (!program.videoStreams.empty())
1492 eDebugNoNewLine(" (");
1493 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1494 i(program.videoStreams.begin());
1495 i != program.videoStreams.end(); ++i)
1499 if (i != program.videoStreams.begin())
1500 eDebugNoNewLine(", ");
1501 eDebugNoNewLine("%04x", i->pid);
1503 eDebugNoNewLine(")");
1505 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1506 if (!program.audioStreams.empty())
1508 eDebugNoNewLine(" (");
1509 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1510 i(program.audioStreams.begin());
1511 i != program.audioStreams.end(); ++i)
1518 if (i != program.audioStreams.begin())
1519 eDebugNoNewLine(", ");
1520 eDebugNoNewLine("%04x", i->pid);
1522 eDebugNoNewLine(")");
1524 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1525 pcrpid = program.pcrPid;
1526 eDebug(", and the text pid is %04x", program.textPid);
1527 tpid = program.textPid;
1532 h.getDecodeDemux(m_decode_demux);
1534 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1536 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1541 m_decoder->setVideoPID(vpid);
1542 m_current_audio_stream = 0;
1543 m_decoder->setAudioPID(apid, apidtype);
1544 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1545 m_decoder->setSyncPCR(pcrpid);
1547 m_decoder->setSyncPCR(-1);
1548 m_decoder->setTextPID(tpid);
1550 m_decoder->setTrickmode(1);
1552 // how we can do this better?
1553 // update cache pid when the user changed the audio track or video track
1554 // TODO handling of difference audio types.. default audio types..
1556 /* don't worry about non-existing services, nor pvr services */
1557 if (m_dvb_service && !m_is_pvr)
1559 if (apidtype == eDVBAudio::aMPEG)
1561 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1562 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1566 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1567 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1569 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1570 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1571 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1576 void eDVBServicePlay::loadCuesheet()
1578 std::string filename = m_reference.path + ".cuts";
1580 m_cue_entries.clear();
1582 FILE *f = fopen(filename.c_str(), "rb");
1586 eDebug("loading cuts..");
1589 unsigned long long where;
1592 if (!fread(&where, sizeof(where), 1, f))
1594 if (!fread(&what, sizeof(what), 1, f))
1597 #if BYTE_ORDER == LITTLE_ENDIAN
1598 where = bswap_64(where);
1605 m_cue_entries.insert(cueEntry(where, what));
1608 eDebug("%d entries", m_cue_entries.size());
1610 eDebug("cutfile not found!");
1612 m_cuesheet_changed = 0;
1613 cutlistToCuesheet();
1614 m_event((iPlayableService*)this, evCuesheetChanged);
1617 void eDVBServicePlay::saveCuesheet()
1619 std::string filename = m_reference.path + ".cuts";
1621 FILE *f = fopen(filename.c_str(), "wb");
1625 unsigned long long where;
1628 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1630 #if BYTE_ORDER == BIG_ENDIAN
1633 where = bswap_64(i->where);
1635 what = htonl(i->what);
1636 fwrite(&where, sizeof(where), 1, f);
1637 fwrite(&what, sizeof(what), 1, f);
1643 m_cuesheet_changed = 0;
1646 void eDVBServicePlay::cutlistToCuesheet()
1650 eDebug("no cue sheet");
1655 if (!m_cutlist_enabled)
1657 m_cue->commitSpans();
1658 eDebug("cutlists where disabled");
1662 pts_t in = 0, out = 0, length = 0;
1666 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1670 if (i == m_cue_entries.end())
1673 if (i->what == 0) /* in */
1677 } else if (i->what == 1) /* out */
1687 m_cue->addSourceSpan(in, out);
1691 if (i == m_cue_entries.end())
1694 m_cue->commitSpans();
1697 DEFINE_REF(eDVBServicePlay)
1699 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");