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>
8 #include <lib/base/nconfig.h> // access to python config
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>
21 #include <lib/gui/esubtitle.h>
26 #include <netinet/in.h>
28 #define INTERNAL_TELETEXT
31 #error no byte order defined!
34 #define TSPATH "/media/hdd"
36 class eStaticServiceDVBInformation: public iStaticServiceInformation
38 DECLARE_REF(eStaticServiceDVBInformation);
40 RESULT getName(const eServiceReference &ref, std::string &name);
41 int getLength(const eServiceReference &ref);
44 DEFINE_REF(eStaticServiceDVBInformation);
46 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
48 eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
49 if ( !ref.name.empty() )
51 if (service.getParentTransportStreamID().get()) // linkage subservice
53 ePtr<iServiceHandler> service_center;
54 if (!eServiceCenter::getInstance(service_center))
56 eServiceReferenceDVB parent = service;
57 parent.setTransportStreamID( service.getParentTransportStreamID() );
58 parent.setServiceID( service.getParentServiceID() );
59 parent.setParentTransportStreamID(eTransportStreamID(0));
60 parent.setParentServiceID(eServiceID(0));
62 ePtr<iStaticServiceInformation> service_info;
63 if (!service_center->info(parent, service_info))
65 if (!service_info->getName(parent, name))
67 // just show short name
68 unsigned int pos = name.find("\xc2\x86");
69 if ( pos != std::string::npos )
71 pos = name.find("\xc2\x87");
72 if ( pos != std::string::npos )
88 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
93 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
95 DECLARE_REF(eStaticServiceDVBBouquetInformation);
97 RESULT getName(const eServiceReference &ref, std::string &name);
98 int getLength(const eServiceReference &ref);
101 DEFINE_REF(eStaticServiceDVBBouquetInformation);
103 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
105 ePtr<iDVBChannelList> db;
106 ePtr<eDVBResourceManager> res;
109 if ((err = eDVBResourceManager::getInstance(res)) != 0)
111 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
114 if ((err = res->getChannelList(db)) != 0)
116 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
121 if ((err = db->getBouquet(ref, bouquet)) != 0)
123 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
127 if ( bouquet && bouquet->m_bouquet_name.length() )
129 name = bouquet->m_bouquet_name;
136 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
141 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
143 DECLARE_REF(eStaticServiceDVBPVRInformation);
144 eServiceReference m_ref;
145 eDVBMetaParser m_parser;
147 eStaticServiceDVBPVRInformation(const eServiceReference &ref);
148 RESULT getName(const eServiceReference &ref, std::string &name);
149 int getLength(const eServiceReference &ref);
150 RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
152 int getInfo(const eServiceReference &ref, int w);
153 std::string getInfoString(const eServiceReference &ref,int w);
156 DEFINE_REF(eStaticServiceDVBPVRInformation);
158 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
161 m_parser.parseFile(ref.path);
164 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
166 ASSERT(ref == m_ref);
167 name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
171 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
173 ASSERT(ref == m_ref);
177 if (tstools.openFile(ref.path.c_str()))
181 if (tstools.calcLen(len))
187 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
191 case iServiceInformation::sDescription:
192 return iServiceInformation::resIsString;
193 case iServiceInformation::sServiceref:
194 return iServiceInformation::resIsString;
195 case iServiceInformation::sTimeCreate:
196 if (m_parser.m_time_create)
197 return m_parser.m_time_create;
199 return iServiceInformation::resNA;
201 return iServiceInformation::resNA;
205 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
209 case iServiceInformation::sDescription:
210 return m_parser.m_description;
211 case iServiceInformation::sServiceref:
212 return m_parser.m_ref.toString();
218 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
220 if (!ref.path.empty())
222 ePtr<eServiceEvent> event = new eServiceEvent;
223 std::string filename = ref.path;
224 filename.erase(filename.length()-2, 2);
226 if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
236 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
238 DECLARE_REF(eDVBPVRServiceOfflineOperations);
239 eServiceReferenceDVB m_ref;
241 eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
243 RESULT deleteFromDisk(int simulate);
244 RESULT getListOfFilenames(std::list<std::string> &);
247 DEFINE_REF(eDVBPVRServiceOfflineOperations);
249 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
253 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
259 std::list<std::string> res;
260 if (getListOfFilenames(res))
263 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
265 eDebug("FATAL !! can't get background file eraser");
267 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
269 eDebug("Removing %s...", i->c_str());
271 eraser->erase(i->c_str());
273 ::unlink(i->c_str());
280 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
283 res.push_back(m_ref.path);
285 // handling for old splitted recordings (enigma 1)
290 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
292 if (stat(buf, &s) < 0)
297 res.push_back(m_ref.path + ".meta");
298 res.push_back(m_ref.path + ".ap");
299 res.push_back(m_ref.path + ".cuts");
300 std::string tmp = m_ref.path;
301 tmp.erase(m_ref.path.length()-3);
302 res.push_back(tmp + ".eit");
306 DEFINE_REF(eServiceFactoryDVB)
308 eServiceFactoryDVB::eServiceFactoryDVB()
310 ePtr<eServiceCenter> sc;
312 eServiceCenter::getPrivInstance(sc);
314 sc->addServiceFactory(eServiceFactoryDVB::id, this);
317 eServiceFactoryDVB::~eServiceFactoryDVB()
319 ePtr<eServiceCenter> sc;
321 eServiceCenter::getPrivInstance(sc);
323 sc->removeServiceFactory(eServiceFactoryDVB::id);
326 DEFINE_REF(eDVBServiceList);
328 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
332 eDVBServiceList::~eDVBServiceList()
336 RESULT eDVBServiceList::startQuery()
338 ePtr<iDVBChannelList> db;
339 ePtr<eDVBResourceManager> res;
342 if ((err = eDVBResourceManager::getInstance(res)) != 0)
344 eDebug("no resource manager");
347 if ((err = res->getChannelList(db)) != 0)
349 eDebug("no channel list");
353 ePtr<eDVBChannelQuery> q;
355 if (!m_parent.path.empty())
357 eDVBChannelQuery::compile(q, m_parent.path);
360 eDebug("compile query failed");
365 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
367 eDebug("startQuery failed");
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 // The first argument of this function is a format string to specify the order and
391 // the content of the returned list
392 // useable format options are
393 // R = Service Reference (as swig object .. this is very slow)
394 // S = Service Reference (as python string object .. same as ref.toString())
395 // N = Service Name (as python string object)
396 // when exactly one return value per service is selected in the format string,
397 // then each value is directly a list entry
398 // when more than one value is returned per service, then the list is a list of
400 // unknown format string chars are returned as python None values !
401 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
404 std::list<eServiceReference> tmplist;
407 if (!format || !(retcount=strlen(format)))
408 format = "R"; // just return service reference swig object ...
410 if (!getContent(tmplist, sorted))
412 int services=tmplist.size();
413 ePtr<iStaticServiceInformation> sptr;
414 eServiceCenterPtr service_center;
416 if (strchr(format, 'N'))
417 eServiceCenter::getPrivInstance(service_center);
419 ret = PyList_New(services);
420 std::list<eServiceReference>::iterator it(tmplist.begin());
422 for (int cnt=0; cnt < services; ++cnt)
424 eServiceReference &ref=*it++;
425 PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
426 for (int i=0; i < retcount; ++i)
431 case 'R': // service reference (swig)object
432 tmp = New_eServiceReference(ref);
434 case 'S': // service reference string
435 tmp = PyString_FromString(ref.toString().c_str());
437 case 'N': // service name
440 service_center->info(ref, sptr);
444 sptr->getName(ref, name);
446 tmp = PyString_FromString(name.c_str());
450 tmp = PyString_FromString("<n/a>");
463 PyTuple_SET_ITEM(tuple, i, tmp);
465 PyList_SET_ITEM(ret, cnt, tmp);
469 PyList_SET_ITEM(ret, cnt, tuple);
472 return ret ? ret : PyList_New(0);
475 RESULT eDVBServiceList::getNext(eServiceReference &ref)
480 return m_query->getNextResult((eServiceReferenceDVB&)ref);
483 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
485 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
488 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
490 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
492 ePtr<iDVBChannelList> db;
493 ePtr<eDVBResourceManager> resm;
495 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
498 if (db->getBouquet(m_parent, m_bouquet) != 0)
509 RESULT eDVBServiceList::addService(eServiceReference &ref)
513 return m_bouquet->addService(ref);
516 RESULT eDVBServiceList::removeService(eServiceReference &ref)
520 return m_bouquet->removeService(ref);
523 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
527 return m_bouquet->moveService(ref, pos);
530 RESULT eDVBServiceList::flushChanges()
534 return m_bouquet->flushChanges();
537 RESULT eDVBServiceList::setListName(const std::string &name)
541 return m_bouquet->setListName(name);
544 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
546 ePtr<eDVBService> service;
547 int r = lookupService(service, ref);
550 // check resources...
551 ptr = new eDVBServicePlay(ref, service);
555 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
557 if (ref.path.empty())
559 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
568 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
570 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
571 if (list->startQuery())
581 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
583 /* is a listable service? */
584 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
586 if ( !ref.name.empty() ) // satellites or providers list
587 ptr = new eStaticServiceDVBInformation;
588 else // a dvb bouquet
589 ptr = new eStaticServiceDVBBouquetInformation;
591 else if (!ref.path.empty()) /* do we have a PVR service? */
592 ptr = new eStaticServiceDVBPVRInformation(ref);
593 else // normal dvb service
595 ePtr<eDVBService> service;
596 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
597 ptr = new eStaticServiceDVBInformation;
599 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
605 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
607 if (ref.path.empty())
613 ptr = new eDVBPVRServiceOfflineOperations(ref);
618 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
620 // TODO: handle the listing itself
621 // if (ref.... == -1) .. return "... bouquets ...";
622 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
624 ePtr<iDVBChannelList> db;
625 ePtr<eDVBResourceManager> res;
628 if ((err = eDVBResourceManager::getInstance(res)) != 0)
630 eDebug("no resource manager");
633 if ((err = res->getChannelList(db)) != 0)
635 eDebug("no channel list");
639 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
640 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
642 eDebug("getService failed!");
649 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
650 m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
653 m_is_pvr = !m_reference.path.empty();
655 m_timeshift_enabled = m_timeshift_active = 0;
658 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
659 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
660 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
662 m_cuesheet_changed = 0;
663 m_cutlist_enabled = 1;
665 m_subtitle_widget = 0;
667 CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
670 eDVBServicePlay::~eDVBServicePlay()
672 delete m_subtitle_widget;
675 void eDVBServicePlay::gotNewEvent()
679 ePtr<eServiceEvent> m_event_now, m_event_next;
680 getEvent(m_event_now, 0);
681 getEvent(m_event_next, 1);
684 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
686 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
688 m_event((iPlayableService*)this, evUpdatedEventInfo);
691 void eDVBServicePlay::serviceEvent(int event)
695 case eDVBServicePMTHandler::eventTuned:
697 ePtr<iDVBDemux> m_demux;
698 if (!m_service_handler.getDataDemux(m_demux))
700 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
701 int sid = ref.getParentServiceID().get();
703 sid = ref.getServiceID().get();
704 if ( ref.getParentTransportStreamID().get() &&
705 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
706 m_event_handler.startOther(m_demux, sid);
708 m_event_handler.start(m_demux, sid);
712 case eDVBServicePMTHandler::eventTuneFailed:
714 eDebug("DVB service failed to tune");
715 m_event((iPlayableService*)this, evTuneFailed);
718 case eDVBServicePMTHandler::eventNewProgramInfo:
720 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
721 if (m_timeshift_enabled)
722 updateTimeshiftPids();
723 if (!m_timeshift_active)
725 if (m_first_program_info && m_is_pvr)
727 m_first_program_info = 0;
730 m_event((iPlayableService*)this, evUpdatedInfo);
733 case eDVBServicePMTHandler::eventEOF:
734 m_event((iPlayableService*)this, evEOF);
736 case eDVBServicePMTHandler::eventSOF:
737 m_event((iPlayableService*)this, evSOF);
742 void eDVBServicePlay::serviceEventTimeshift(int event)
746 case eDVBServicePMTHandler::eventNewProgramInfo:
747 if (m_timeshift_active)
750 case eDVBServicePMTHandler::eventSOF:
751 m_event((iPlayableService*)this, evSOF);
753 case eDVBServicePMTHandler::eventEOF:
759 RESULT eDVBServicePlay::start()
762 /* in pvr mode, we only want to use one demux. in tv mode, we're using
763 two (one for decoding, one for data source), as we must be prepared
764 to start recording from the data demux. */
766 m_cue = new eCueSheet();
768 m_first_program_info = 1;
769 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
770 r = m_service_handler.tune(service, m_is_pvr, m_cue);
772 /* inject EIT if there is a stored one */
775 std::string filename = service.path;
776 filename.erase(filename.length()-2, 2);
778 ePtr<eServiceEvent> event = new eServiceEvent;
779 if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
781 ePtr<eServiceEvent> empty;
782 m_event_handler.inject(event, 0);
783 m_event_handler.inject(empty, 1);
790 m_event(this, evStart);
791 m_event((iPlayableService*)this, evSeekableStatusChanged);
795 RESULT eDVBServicePlay::stop()
797 /* add bookmark for last play position */
801 if (!getPlayPosition(play_position))
803 /* remove last position */
804 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
806 if (i->what == 3) /* current play position */
808 m_cue_entries.erase(i);
809 i = m_cue_entries.begin();
815 m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
816 m_cuesheet_changed = 1;
820 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
822 m_service_handler_timeshift.free();
823 m_service_handler.free();
825 if (m_is_pvr && m_cuesheet_changed)
831 RESULT eDVBServicePlay::setTarget(int target)
833 m_is_primary = !target;
837 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
839 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
843 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
845 /* note: we check for timeshift to be enabled,
846 not neccessary active. if you pause when timeshift
847 is not active, you should activate it when unpausing */
848 if ((!m_is_pvr) && (!m_timeshift_enabled))
858 RESULT eDVBServicePlay::setSlowMotion(int ratio)
861 return m_decoder->setSlowMotion(ratio);
866 RESULT eDVBServicePlay::setFastForward(int ratio)
868 int skipmode, ffratio;
874 } else if (ratio > 0)
882 } else // if (ratio < 0)
888 if (m_skipmode != skipmode)
890 eDebug("setting cue skipmode to %d", skipmode);
892 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
895 m_skipmode = skipmode;
900 return m_decoder->setFastForward(ffratio);
903 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
905 if (m_is_pvr || m_timeshift_enabled)
915 /* TODO: when timeshift is enabled but not active, this doesn't work. */
916 RESULT eDVBServicePlay::getLength(pts_t &len)
918 ePtr<iDVBPVRChannel> pvr_channel;
920 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
923 return pvr_channel->getLength(len);
926 RESULT eDVBServicePlay::pause()
928 if (!m_is_paused && m_decoder)
931 return m_decoder->freeze(0);
936 RESULT eDVBServicePlay::unpause()
938 if (m_is_paused && m_decoder)
941 return m_decoder->unfreeze();
946 RESULT eDVBServicePlay::seekTo(pts_t to)
948 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
953 ePtr<iDVBPVRChannel> pvr_channel;
955 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
961 m_cue->seekTo(0, to);
965 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
967 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
972 ePtr<iDVBPVRChannel> pvr_channel;
974 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
979 /* HACK until we have skip-AP api */
980 if ((to > 0) && (to < 100))
988 m_cue->seekTo(mode, to);
992 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
994 ePtr<iDVBPVRChannel> pvr_channel;
999 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1004 /* if there is a decoder, use audio or video PTS */
1007 r = m_decoder->getPTS(0, pos);
1013 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
1016 RESULT eDVBServicePlay::setTrickmode(int trick)
1019 m_decoder->setTrickmode(trick);
1023 RESULT eDVBServicePlay::isCurrentlySeekable()
1025 return m_is_pvr || m_timeshift_active;
1028 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
1034 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1040 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1046 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1052 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1058 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1061 if (m_have_video_pid && // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
1062 (m_timeshift_enabled || !m_is_pvr))
1064 if (!m_timeshift_enabled)
1066 /* we need enough diskspace */
1068 if (statfs(TSPATH "/.", &fs) < 0)
1070 eDebug("statfs failed!");
1074 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1076 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1086 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1097 RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
1103 RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
1109 RESULT eDVBServicePlay::getName(std::string &name)
1113 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1114 return i->getName(m_reference, name);
1118 m_dvb_service->getName(m_reference, name);
1122 else if (!m_reference.name.empty())
1123 eStaticServiceDVBInformation().getName(m_reference, name);
1125 name = "DVB service";
1129 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1131 return m_event_handler.getEvent(evt, nownext);
1134 int eDVBServicePlay::getInfo(int w)
1136 eDVBServicePMTHandler::program program;
1139 return resIsPyObject;
1141 if (m_service_handler.getProgramInfo(program))
1147 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1149 ePtr<eServiceEvent> evt;
1150 if (!m_event_handler.getEvent(evt, 0))
1152 ePtr<eComponentData> data;
1153 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1155 if ( data->getStreamContent() == 1 )
1157 switch(data->getComponentType())
1160 case 1: // 4:3 SD PAL
1162 case 3: // 16:9 SD PAL
1163 case 4: // > 16:9 PAL
1164 case 5: // 4:3 SD NTSC
1166 case 7: // 16:9 SD NTSC
1167 case 8: // > 16:9 NTSC
1170 case 9: // 4:3 HD PAL
1172 case 0xB: // 16:9 HD PAL
1173 case 0xC: // > 16:9 HD PAL
1174 case 0xD: // 4:3 HD NTSC
1176 case 0xF: // 16:9 HD NTSC
1177 case 0x10: // > 16:9 HD PAL
1178 return data->getComponentType();
1185 case sIsCrypted: return program.isCrypted();
1186 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1187 case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1188 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1189 case sPCRPID: return program.pcrPid;
1190 case sPMTPID: return program.pmtPid;
1191 case sTXTPID: return program.textPid;
1192 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1193 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1194 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1195 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1196 case sProvider: if (!m_dvb_service) return -1; return -2;
1202 std::string eDVBServicePlay::getInfoString(int w)
1207 if (!m_dvb_service) return "";
1208 return m_dvb_service->m_provider_name;
1212 return iServiceInformation::getInfoString(w);
1215 PyObject *eDVBServicePlay::getInfoObject(int w)
1220 return m_service_handler.getCaIds();
1224 return iServiceInformation::getInfoObject(w);
1227 int eDVBServicePlay::getNumberOfTracks()
1229 eDVBServicePMTHandler::program program;
1230 if (m_service_handler.getProgramInfo(program))
1232 return program.audioStreams.size();
1235 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1237 int ret = selectAudioStream(i);
1239 if (m_decoder->start())
1245 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1247 eDVBServicePMTHandler::program program;
1249 if (m_service_handler.getProgramInfo(program))
1252 if (i >= program.audioStreams.size())
1255 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1256 info.m_description = "MPEG";
1257 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1258 info.m_description = "AC3";
1259 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1260 info.m_description = "AAC";
1261 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1262 info.m_description = "DTS";
1264 info.m_description = "???";
1266 if (program.audioStreams[i].component_tag != -1)
1268 ePtr<eServiceEvent> evt;
1269 if (!m_event_handler.getEvent(evt, 0))
1271 ePtr<eComponentData> data;
1272 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1273 info.m_language = data->getText();
1277 if (info.m_language.empty())
1278 info.m_language = program.audioStreams[i].language_code;
1283 int eDVBServicePlay::selectAudioStream(int i)
1285 eDVBServicePMTHandler::program program;
1287 if (m_service_handler.getProgramInfo(program))
1290 if ((unsigned int)i >= program.audioStreams.size())
1296 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1299 if (m_dvb_service && !m_is_pvr)
1301 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1303 m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
1304 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1307 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1308 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
1312 m_current_audio_stream = i;
1317 int eDVBServicePlay::getCurrentChannel()
1319 return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1322 RESULT eDVBServicePlay::selectChannel(int i)
1324 if (i < LEFT || i > RIGHT || i == STEREO)
1327 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1329 m_decoder->setAudioChannel(i);
1333 int eDVBServiceBase::getFrontendInfo(int w)
1335 eUsePtr<iDVBChannel> channel;
1336 if(m_service_handler.getChannel(channel))
1338 ePtr<iDVBFrontend> fe;
1339 if(channel->getFrontend(fe))
1341 return fe->readFrontendData(w);
1344 PyObject *eDVBServiceBase::getFrontendData(bool original)
1348 eUsePtr<iDVBChannel> channel;
1349 if(!m_service_handler.getChannel(channel))
1351 ePtr<iDVBFrontend> fe;
1352 if(!channel->getFrontend(fe))
1354 ret = fe->readTransponderData(original);
1357 ePtr<iDVBFrontendParameters> feparm;
1358 channel->getCurrentFrontendParameters(feparm);
1361 eDVBFrontendParametersSatellite osat;
1362 if (!feparm->getDVBS(osat))
1364 void PutToDict(PyObject *, const char*, long);
1365 void PutToDict(PyObject *, const char*, const char*);
1366 PutToDict(ret, "orbital_position", osat.orbital_position);
1367 const char *tmp = "UNKNOWN";
1368 switch(osat.polarisation)
1370 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1371 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1372 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1373 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1376 PutToDict(ret, "polarization", tmp);
1390 int eDVBServicePlay::getNumberOfSubservices()
1392 ePtr<eServiceEvent> evt;
1393 if (!m_event_handler.getEvent(evt, 0))
1394 return evt->getNumOfLinkageServices();
1398 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1400 ePtr<eServiceEvent> evt;
1401 if (!m_event_handler.getEvent(evt, 0))
1403 if (!evt->getLinkageService(sub, m_reference, n))
1406 sub.type=eServiceReference::idInvalid;
1410 RESULT eDVBServicePlay::startTimeshift()
1412 ePtr<iDVBDemux> demux;
1414 eDebug("Start timeshift!");
1416 if (m_timeshift_enabled)
1419 /* start recording with the data demux. */
1420 if (m_service_handler.getDataDemux(demux))
1423 demux->createTSRecorder(m_record);
1427 char templ[]=TSPATH "/timeshift.XXXXXX";
1428 m_timeshift_fd = mkstemp(templ);
1429 m_timeshift_file = templ;
1431 eDebug("recording to %s", templ);
1433 if (m_timeshift_fd < 0)
1439 m_record->setTargetFD(m_timeshift_fd);
1441 m_timeshift_enabled = 1;
1443 updateTimeshiftPids();
1449 RESULT eDVBServicePlay::stopTimeshift()
1451 if (!m_timeshift_enabled)
1456 m_timeshift_enabled = 0;
1461 close(m_timeshift_fd);
1462 eDebug("remove timeshift file");
1463 remove(m_timeshift_file.c_str());
1468 int eDVBServicePlay::isTimeshiftActive()
1470 return m_timeshift_enabled && m_timeshift_active;
1473 RESULT eDVBServicePlay::activateTimeshift()
1475 if (!m_timeshift_enabled)
1478 if (!m_timeshift_active)
1480 switchToTimeshift();
1487 PyObject *eDVBServicePlay::getCutList()
1489 PyObject *list = PyList_New(0);
1491 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1493 PyObject *tuple = PyTuple_New(2);
1494 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1495 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1496 PyList_Append(list, tuple);
1503 void eDVBServicePlay::setCutList(PyObject *list)
1505 if (!PyList_Check(list))
1507 int size = PyList_Size(list);
1510 m_cue_entries.clear();
1512 for (i=0; i<size; ++i)
1514 PyObject *tuple = PyList_GetItem(list, i);
1515 if (!PyTuple_Check(tuple))
1517 eDebug("non-tuple in cutlist");
1520 if (PyTuple_Size(tuple) != 2)
1522 eDebug("cutlist entries need to be a 2-tuple");
1525 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1526 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1528 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1531 pts_t pts = PyLong_AsLongLong(ppts);
1532 int type = PyInt_AsLong(ptype);
1533 m_cue_entries.insert(cueEntry(pts, type));
1534 eDebug("adding %08llx, %d", pts, type);
1536 m_cuesheet_changed = 1;
1538 cutlistToCuesheet();
1539 m_event((iPlayableService*)this, evCuesheetChanged);
1542 void eDVBServicePlay::setCutListEnable(int enable)
1544 m_cutlist_enabled = enable;
1545 cutlistToCuesheet();
1548 void eDVBServicePlay::updateTimeshiftPids()
1553 eDVBServicePMTHandler::program program;
1554 if (m_service_handler.getProgramInfo(program))
1558 std::set<int> pids_to_record;
1559 pids_to_record.insert(0); // PAT
1560 if (program.pmtPid != -1)
1561 pids_to_record.insert(program.pmtPid); // PMT
1563 if (program.textPid != -1)
1564 pids_to_record.insert(program.textPid); // Videotext
1566 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1567 i(program.videoStreams.begin());
1568 i != program.videoStreams.end(); ++i)
1569 pids_to_record.insert(i->pid);
1571 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1572 i(program.audioStreams.begin());
1573 i != program.audioStreams.end(); ++i)
1574 pids_to_record.insert(i->pid);
1576 std::set<int> new_pids, obsolete_pids;
1578 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1579 m_pids_active.begin(), m_pids_active.end(),
1580 std::inserter(new_pids, new_pids.begin()));
1582 std::set_difference(
1583 m_pids_active.begin(), m_pids_active.end(),
1584 pids_to_record.begin(), pids_to_record.end(),
1585 std::inserter(new_pids, new_pids.begin())
1588 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1589 m_record->addPID(*i);
1591 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1592 m_record->removePID(*i);
1596 void eDVBServicePlay::switchToLive()
1598 if (!m_timeshift_active)
1604 m_teletext_parser = 0;
1605 m_new_subtitle_page_connection = 0;
1607 /* free the timeshift service handler, we need the resources */
1608 m_service_handler_timeshift.free();
1609 m_timeshift_active = 0;
1611 m_event((iPlayableService*)this, evSeekableStatusChanged);
1616 void eDVBServicePlay::switchToTimeshift()
1618 if (m_timeshift_active)
1623 m_teletext_parser = 0;
1624 m_new_subtitle_page_connection = 0;
1626 m_timeshift_active = 1;
1628 m_event((iPlayableService*)this, evSeekableStatusChanged);
1630 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1631 r.path = m_timeshift_file;
1633 m_cue = new eCueSheet();
1634 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1635 updateDecoder(); /* mainly to switch off PCR */
1638 void eDVBServicePlay::updateDecoder()
1640 int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
1642 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1644 bool defaultac3=false;
1645 std::string default_ac3;
1647 if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
1648 defaultac3 = default_ac3 == "enable";
1650 eDVBServicePMTHandler::program program;
1651 if (h.getProgramInfo(program))
1652 eDebug("getting program info failed.");
1655 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1656 if (!program.videoStreams.empty())
1658 eDebugNoNewLine(" (");
1659 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1660 i(program.videoStreams.begin());
1661 i != program.videoStreams.end(); ++i)
1668 if (i != program.videoStreams.begin())
1669 eDebugNoNewLine(", ");
1670 eDebugNoNewLine("%04x", i->pid);
1672 eDebugNoNewLine(")");
1674 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1675 if (!program.audioStreams.empty())
1677 eDebugNoNewLine(" (");
1678 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1679 i(program.audioStreams.begin());
1680 i != program.audioStreams.end(); ++i)
1682 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
1684 if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
1690 if (i != program.audioStreams.begin())
1691 eDebugNoNewLine(", ");
1692 eDebugNoNewLine("%04x", i->pid);
1694 eDebugNoNewLine(")");
1696 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1697 pcrpid = program.pcrPid;
1698 eDebug(", and the text pid is %04x", program.textPid);
1699 tpid = program.textPid;
1704 h.getDecodeDemux(m_decode_demux);
1706 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1708 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1709 #ifdef INTERNAL_TELETEXT
1710 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
1711 m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
1719 achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
1720 ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
1721 pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
1723 else // subservice or recording
1725 eServiceReferenceDVB ref;
1726 m_service_handler.getServiceReference(ref);
1727 eServiceReferenceDVB parent = ref.getParentServiceReference();
1732 ePtr<eDVBResourceManager> res_mgr;
1733 if (!eDVBResourceManager::getInstance(res_mgr))
1735 ePtr<iDVBChannelList> db;
1736 if (!res_mgr->getChannelList(db))
1738 ePtr<eDVBService> origService;
1739 if (!db->getService(parent, origService))
1741 ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
1742 pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
1748 m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
1749 m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
1751 m_decoder->setVideoPID(vpid, vpidtype);
1752 m_current_audio_stream = 0;
1753 m_decoder->setAudioPID(apid, apidtype);
1754 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1755 m_decoder->setSyncPCR(pcrpid);
1757 m_decoder->setSyncPCR(-1);
1759 m_decoder->setTextPID(tpid);
1761 if (m_teletext_parser)
1762 m_teletext_parser->start(tpid);
1765 m_decoder->setTrickmode(1);
1769 if (vpid > 0 && vpid < 0x2000)
1773 std::string radio_pic;
1774 if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
1775 m_decoder->setRadioPic(radio_pic);
1778 m_decoder->setAudioChannel(achannel);
1780 // how we can do this better?
1781 // update cache pid when the user changed the audio track or video track
1782 // TODO handling of difference audio types.. default audio types..
1784 /* don't worry about non-existing services, nor pvr services */
1785 if (m_dvb_service && !m_is_pvr)
1787 if (apidtype == eDVBAudio::aMPEG)
1789 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1790 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1794 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1795 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1797 m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
1798 m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
1799 m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
1800 m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
1803 m_have_video_pid = (vpid > 0 && vpid < 0x2000);
1806 void eDVBServicePlay::loadCuesheet()
1808 std::string filename = m_reference.path + ".cuts";
1810 m_cue_entries.clear();
1812 FILE *f = fopen(filename.c_str(), "rb");
1816 eDebug("loading cuts..");
1819 unsigned long long where;
1822 if (!fread(&where, sizeof(where), 1, f))
1824 if (!fread(&what, sizeof(what), 1, f))
1827 #if BYTE_ORDER == LITTLE_ENDIAN
1828 where = bswap_64(where);
1835 m_cue_entries.insert(cueEntry(where, what));
1838 eDebug("%d entries", m_cue_entries.size());
1840 eDebug("cutfile not found!");
1842 m_cuesheet_changed = 0;
1843 cutlistToCuesheet();
1844 m_event((iPlayableService*)this, evCuesheetChanged);
1847 void eDVBServicePlay::saveCuesheet()
1849 std::string filename = m_reference.path + ".cuts";
1851 FILE *f = fopen(filename.c_str(), "wb");
1855 unsigned long long where;
1858 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1860 #if BYTE_ORDER == BIG_ENDIAN
1863 where = bswap_64(i->where);
1865 what = htonl(i->what);
1866 fwrite(&where, sizeof(where), 1, f);
1867 fwrite(&what, sizeof(what), 1, f);
1873 m_cuesheet_changed = 0;
1876 void eDVBServicePlay::cutlistToCuesheet()
1880 eDebug("no cue sheet");
1885 if (!m_cutlist_enabled)
1887 m_cue->commitSpans();
1888 eDebug("cutlists were disabled");
1892 pts_t in = 0, out = 0, length = 0;
1896 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1900 if (i == m_cue_entries.end())
1903 if (i->what == 0) /* in */
1907 } else if (i->what == 1) /* out */
1909 else /* mark (2) or last play position (3) */
1917 m_cue->addSourceSpan(in, out);
1921 if (i == m_cue_entries.end())
1924 m_cue->commitSpans();
1927 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
1929 if (m_subtitle_widget)
1930 disableSubtitles(parent);
1932 if (!m_teletext_parser)
1935 if (!PyInt_Check(entry))
1938 m_subtitle_widget = new eSubtitleWidget(parent);
1939 m_subtitle_widget->resize(parent->size()); /* full size */
1941 int page = PyInt_AsLong(entry);
1943 m_teletext_parser->setPage(page);
1948 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
1950 delete m_subtitle_widget;
1951 m_subtitle_widget = 0;
1955 PyObject *eDVBServicePlay::getSubtitleList()
1957 if (!m_teletext_parser)
1963 PyObject *l = PyList_New(0);
1965 for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
1967 PyObject *tuple = PyTuple_New(2);
1969 sprintf(desc, "Page %x", *i);
1970 PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
1971 PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
1972 PyList_Append(l, tuple);
1978 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
1980 if (m_subtitle_widget)
1982 m_subtitle_pages.push_back(page);
1984 checkSubtitleTiming();
1988 void eDVBServicePlay::checkSubtitleTiming()
1992 if (m_subtitle_pages.empty())
1995 eDVBTeletextSubtitlePage p = m_subtitle_pages.front();
2000 m_decoder->getPTS(0, pos);
2002 int diff = p.m_pts - pos;
2005 eDebug("[late (%d ms)]", -diff / 90);
2010 eDebug("[invalid]");
2016 m_subtitle_widget->setPage(p);
2017 m_subtitle_pages.pop_front();
2020 m_subtitle_sync_timer.start(diff / 90, 1);
2026 int eDVBServicePlay::getAC3Delay()
2029 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2031 return m_decoder->getAC3Delay();
2036 int eDVBServicePlay::getPCMDelay()
2039 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2041 return m_decoder->getPCMDelay();
2046 void eDVBServicePlay::setAC3Delay(int delay)
2049 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2051 m_decoder->setAC3Delay(delay);
2054 void eDVBServicePlay::setPCMDelay(int delay)
2057 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2059 m_decoder->setPCMDelay(delay);
2062 DEFINE_REF(eDVBServicePlay)
2064 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");