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. */
680 m_cue = new eCueSheet();
682 m_first_program_info = 1;
683 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
684 r = m_service_handler.tune(service, m_is_pvr, m_cue);
686 /* inject EIT if there is a stored one */
689 std::string filename = service.path;
690 filename.erase(filename.length()-2, 2);
692 int fd = ::open( filename.c_str(), O_RDONLY );
696 int rd = ::read(fd, buf, 4096);
698 if ( rd > 12 /*EIT_LOOP_SIZE*/ )
701 ePtr<eServiceEvent> event = new eServiceEvent;
702 ePtr<eServiceEvent> empty;
703 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
704 m_event_handler.inject(event, 0);
705 m_event_handler.inject(empty, 1);
714 m_event(this, evStart);
715 m_event((iPlayableService*)this, evSeekableStatusChanged);
719 RESULT eDVBServicePlay::stop()
721 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
723 m_service_handler_timeshift.free();
724 m_service_handler.free();
726 if (m_is_pvr && m_cuesheet_changed)
732 RESULT eDVBServicePlay::setTarget(int target)
734 m_is_primary = !target;
738 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
740 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
744 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
746 /* note: we check for timeshift to be enabled,
747 not neccessary active. if you pause when timeshift
748 is not active, you should activate it when unpausing */
749 if ((!m_is_pvr) && (!m_timeshift_enabled))
759 RESULT eDVBServicePlay::setSlowMotion(int ratio)
762 return m_decoder->setSlowMotion(ratio);
767 RESULT eDVBServicePlay::setFastForward(int ratio)
769 int skipmode, ffratio;
775 } else if (ratio > 0)
783 } else // if (ratio < 0)
789 if (m_skipmode != skipmode)
791 eDebug("setting cue skipmode to %d", skipmode);
793 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
796 m_skipmode = skipmode;
801 return m_decoder->setFastForward(ffratio);
804 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
806 if (m_is_pvr || m_timeshift_enabled)
816 /* TODO: when timeshift is enabled but not active, this doesn't work. */
817 RESULT eDVBServicePlay::getLength(pts_t &len)
819 ePtr<iDVBPVRChannel> pvr_channel;
821 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
824 return pvr_channel->getLength(len);
827 RESULT eDVBServicePlay::pause()
829 if (!m_is_paused && m_decoder)
832 return m_decoder->freeze(0);
837 RESULT eDVBServicePlay::unpause()
839 if (m_is_paused && m_decoder)
842 return m_decoder->unfreeze();
847 RESULT eDVBServicePlay::seekTo(pts_t to)
849 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
854 ePtr<iDVBPVRChannel> pvr_channel;
856 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
862 m_cue->seekTo(0, to);
866 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
868 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
873 ePtr<iDVBPVRChannel> pvr_channel;
875 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
880 /* HACK until we have skip-AP api */
881 if ((to > 0) && (to < 100))
889 m_cue->seekTo(mode, to);
893 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
895 ePtr<iDVBPVRChannel> pvr_channel;
900 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
905 /* if there is a decoder, use audio or video PTS */
908 r = m_decoder->getPTS(0, pos);
914 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
917 RESULT eDVBServicePlay::setTrickmode(int trick)
920 m_decoder->setTrickmode(trick);
924 RESULT eDVBServicePlay::isCurrentlySeekable()
926 return m_is_pvr || m_timeshift_active;
929 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
935 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
941 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
947 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
953 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
956 if (m_timeshift_enabled || !m_is_pvr)
958 if (!m_timeshift_enabled)
960 /* we need enough diskspace */
962 if (statfs(TSPATH "/.", &fs) < 0)
964 eDebug("statfs failed!");
968 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
970 eDebug("not enough diskspace for timeshift! (less than 1GB)");
980 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
991 RESULT eDVBServicePlay::getName(std::string &name)
995 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
996 return i->getName(m_reference, name);
1000 m_dvb_service->getName(m_reference, name);
1004 else if (!m_reference.name.empty())
1005 eStaticServiceDVBInformation().getName(m_reference, name);
1007 name = "DVB service";
1011 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1013 return m_event_handler.getEvent(evt, nownext);
1016 int eDVBServicePlay::getInfo(int w)
1018 eDVBServicePMTHandler::program program;
1021 return resIsPyObject;
1023 if (m_service_handler.getProgramInfo(program))
1029 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1031 ePtr<eServiceEvent> evt;
1032 if (!m_event_handler.getEvent(evt, 0))
1034 ePtr<eComponentData> data;
1035 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1037 if ( data->getStreamContent() == 1 )
1039 switch(data->getComponentType())
1042 case 1: // 4:3 SD PAL
1044 case 3: // 16:9 SD PAL
1045 case 4: // > 16:9 PAL
1046 case 5: // 4:3 SD NTSC
1048 case 7: // 16:9 SD NTSC
1049 case 8: // > 16:9 NTSC
1052 case 9: // 4:3 HD PAL
1054 case 0xB: // 16:9 HD PAL
1055 case 0xC: // > 16:9 HD PAL
1056 case 0xD: // 4:3 HD NTSC
1058 case 0xF: // 16:9 HD NTSC
1059 case 0x10: // > 16:9 HD PAL
1060 return data->getComponentType();
1067 case sIsCrypted: return program.isCrypted;
1068 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1069 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1070 case sPCRPID: return program.pcrPid;
1071 case sPMTPID: return program.pmtPid;
1072 case sTXTPID: return program.textPid;
1073 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1074 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1075 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1076 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1077 case sProvider: if (!m_dvb_service) return -1; return -2;
1083 std::string eDVBServicePlay::getInfoString(int w)
1088 if (!m_dvb_service) return "";
1089 return m_dvb_service->m_provider_name;
1093 return iServiceInformation::getInfoString(w);
1096 PyObject *eDVBServicePlay::getInfoObject(int w)
1102 return m_service_handler.getCaIds();
1106 return iServiceInformation::getInfoObject(w);
1109 int eDVBServicePlay::getNumberOfTracks()
1111 eDVBServicePMTHandler::program program;
1112 if (m_service_handler.getProgramInfo(program))
1114 return program.audioStreams.size();
1117 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1119 int ret = selectAudioStream(i);
1121 if (m_decoder->start())
1127 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1129 eDVBServicePMTHandler::program program;
1131 if (m_service_handler.getProgramInfo(program))
1134 if (i >= program.audioStreams.size())
1137 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1138 info.m_description = "MPEG";
1139 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1140 info.m_description = "AC3";
1141 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1142 info.m_description = "DTS";
1144 info.m_description = "???";
1146 if (program.audioStreams[i].component_tag != -1)
1148 ePtr<eServiceEvent> evt;
1149 if (!m_event_handler.getEvent(evt, 0))
1151 ePtr<eComponentData> data;
1152 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1153 info.m_language = data->getText();
1157 if (info.m_language.empty())
1158 info.m_language = program.audioStreams[i].language_code;
1163 int eDVBServicePlay::selectAudioStream(int i)
1165 eDVBServicePMTHandler::program program;
1167 if (m_service_handler.getProgramInfo(program))
1170 if ((unsigned int)i >= program.audioStreams.size())
1176 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1179 if (m_dvb_service && !m_is_pvr)
1181 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1183 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1184 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1187 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1188 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1192 m_current_audio_stream = i;
1197 int eDVBServicePlay::getFrontendInfo(int w)
1201 eUsePtr<iDVBChannel> channel;
1202 if(m_service_handler.getChannel(channel))
1204 ePtr<iDVBFrontend> fe;
1205 if(channel->getFrontend(fe))
1207 return fe->readFrontendData(w);
1210 PyObject *eDVBServicePlay::getFrontendData(bool original)
1214 eUsePtr<iDVBChannel> channel;
1215 if(!m_service_handler.getChannel(channel))
1217 ePtr<iDVBFrontend> fe;
1218 if(!channel->getFrontend(fe))
1220 ret = fe->readTransponderData(original);
1223 ePtr<iDVBFrontendParameters> feparm;
1224 channel->getCurrentFrontendParameters(feparm);
1227 eDVBFrontendParametersSatellite osat;
1228 if (!feparm->getDVBS(osat))
1230 void PutToDict(PyObject *, const char*, long);
1231 void PutToDict(PyObject *, const char*, const char*);
1232 PutToDict(ret, "orbital_position", osat.orbital_position);
1233 const char *tmp = "UNKNOWN";
1234 switch(osat.polarisation)
1236 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1237 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1238 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1239 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1242 PutToDict(ret, "polarization", tmp);
1256 int eDVBServicePlay::getNumberOfSubservices()
1258 ePtr<eServiceEvent> evt;
1259 if (!m_event_handler.getEvent(evt, 0))
1260 return evt->getNumOfLinkageServices();
1264 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1266 ePtr<eServiceEvent> evt;
1267 if (!m_event_handler.getEvent(evt, 0))
1269 if (!evt->getLinkageService(sub, m_reference, n))
1272 sub.type=eServiceReference::idInvalid;
1276 RESULT eDVBServicePlay::startTimeshift()
1278 ePtr<iDVBDemux> demux;
1280 eDebug("Start timeshift!");
1282 if (m_timeshift_enabled)
1285 /* start recording with the data demux. */
1286 if (m_service_handler.getDataDemux(demux))
1289 demux->createTSRecorder(m_record);
1293 char templ[]=TSPATH "/timeshift.XXXXXX";
1294 m_timeshift_fd = mkstemp(templ);
1295 m_timeshift_file = templ;
1297 eDebug("recording to %s", templ);
1299 if (m_timeshift_fd < 0)
1305 m_record->setTargetFD(m_timeshift_fd);
1307 m_timeshift_enabled = 1;
1309 updateTimeshiftPids();
1315 RESULT eDVBServicePlay::stopTimeshift()
1317 if (!m_timeshift_enabled)
1322 m_timeshift_enabled = 0;
1327 close(m_timeshift_fd);
1328 eDebug("remove timeshift file");
1329 remove(m_timeshift_file.c_str());
1334 int eDVBServicePlay::isTimeshiftActive()
1336 return m_timeshift_enabled && m_timeshift_active;
1339 RESULT eDVBServicePlay::activateTimeshift()
1341 if (!m_timeshift_enabled)
1344 if (!m_timeshift_active)
1346 switchToTimeshift();
1353 PyObject *eDVBServicePlay::getCutList()
1355 PyObject *list = PyList_New(0);
1357 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1359 PyObject *tuple = PyTuple_New(2);
1360 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1361 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1362 PyList_Append(list, tuple);
1369 void eDVBServicePlay::setCutList(PyObject *list)
1371 if (!PyList_Check(list))
1373 int size = PyList_Size(list);
1376 m_cue_entries.clear();
1378 for (i=0; i<size; ++i)
1380 PyObject *tuple = PyList_GetItem(list, i);
1381 if (!PyTuple_Check(tuple))
1383 eDebug("non-tuple in cutlist");
1386 if (PyTuple_Size(tuple) != 2)
1388 eDebug("cutlist entries need to be a 2-tuple");
1391 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1392 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1394 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1397 pts_t pts = PyLong_AsLongLong(ppts);
1398 int type = PyInt_AsLong(ptype);
1399 m_cue_entries.insert(cueEntry(pts, type));
1400 eDebug("adding %08llx, %d", pts, type);
1402 m_cuesheet_changed = 1;
1404 cutlistToCuesheet();
1405 m_event((iPlayableService*)this, evCuesheetChanged);
1408 void eDVBServicePlay::setCutListEnable(int enable)
1410 m_cutlist_enabled = enable;
1411 cutlistToCuesheet();
1414 void eDVBServicePlay::updateTimeshiftPids()
1419 eDVBServicePMTHandler::program program;
1420 if (m_service_handler.getProgramInfo(program))
1424 std::set<int> pids_to_record;
1425 pids_to_record.insert(0); // PAT
1426 if (program.pmtPid != -1)
1427 pids_to_record.insert(program.pmtPid); // PMT
1429 if (program.textPid != -1)
1430 pids_to_record.insert(program.textPid); // Videotext
1432 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1433 i(program.videoStreams.begin());
1434 i != program.videoStreams.end(); ++i)
1435 pids_to_record.insert(i->pid);
1437 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1438 i(program.audioStreams.begin());
1439 i != program.audioStreams.end(); ++i)
1440 pids_to_record.insert(i->pid);
1442 std::set<int> new_pids, obsolete_pids;
1444 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1445 m_pids_active.begin(), m_pids_active.end(),
1446 std::inserter(new_pids, new_pids.begin()));
1448 std::set_difference(
1449 m_pids_active.begin(), m_pids_active.end(),
1450 pids_to_record.begin(), pids_to_record.end(),
1451 std::inserter(new_pids, new_pids.begin())
1454 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1455 m_record->addPID(*i);
1457 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1458 m_record->removePID(*i);
1462 void eDVBServicePlay::switchToLive()
1464 if (!m_timeshift_active)
1470 /* free the timeshift service handler, we need the resources */
1471 m_service_handler_timeshift.free();
1472 m_timeshift_active = 0;
1474 m_event((iPlayableService*)this, evSeekableStatusChanged);
1479 void eDVBServicePlay::switchToTimeshift()
1481 if (m_timeshift_active)
1487 m_timeshift_active = 1;
1489 m_event((iPlayableService*)this, evSeekableStatusChanged);
1491 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1492 r.path = m_timeshift_file;
1494 m_cue = new eCueSheet();
1495 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1496 updateDecoder(); /* mainly to switch off PCR */
1499 void eDVBServicePlay::updateDecoder()
1501 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1502 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1504 eDVBServicePMTHandler::program program;
1505 if (h.getProgramInfo(program))
1506 eDebug("getting program info failed.");
1509 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1510 if (!program.videoStreams.empty())
1512 eDebugNoNewLine(" (");
1513 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1514 i(program.videoStreams.begin());
1515 i != program.videoStreams.end(); ++i)
1519 if (i != program.videoStreams.begin())
1520 eDebugNoNewLine(", ");
1521 eDebugNoNewLine("%04x", i->pid);
1523 eDebugNoNewLine(")");
1525 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1526 if (!program.audioStreams.empty())
1528 eDebugNoNewLine(" (");
1529 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1530 i(program.audioStreams.begin());
1531 i != program.audioStreams.end(); ++i)
1538 if (i != program.audioStreams.begin())
1539 eDebugNoNewLine(", ");
1540 eDebugNoNewLine("%04x", i->pid);
1542 eDebugNoNewLine(")");
1544 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1545 pcrpid = program.pcrPid;
1546 eDebug(", and the text pid is %04x", program.textPid);
1547 tpid = program.textPid;
1552 h.getDecodeDemux(m_decode_demux);
1554 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1556 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1561 m_decoder->setVideoPID(vpid);
1562 m_current_audio_stream = 0;
1563 m_decoder->setAudioPID(apid, apidtype);
1564 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1565 m_decoder->setSyncPCR(pcrpid);
1567 m_decoder->setSyncPCR(-1);
1568 m_decoder->setTextPID(tpid);
1570 m_decoder->setTrickmode(1);
1572 // how we can do this better?
1573 // update cache pid when the user changed the audio track or video track
1574 // TODO handling of difference audio types.. default audio types..
1576 /* don't worry about non-existing services, nor pvr services */
1577 if (m_dvb_service && !m_is_pvr)
1579 if (apidtype == eDVBAudio::aMPEG)
1581 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1582 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1586 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1587 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1589 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1590 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1591 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1596 void eDVBServicePlay::loadCuesheet()
1598 std::string filename = m_reference.path + ".cuts";
1600 m_cue_entries.clear();
1602 FILE *f = fopen(filename.c_str(), "rb");
1606 eDebug("loading cuts..");
1609 unsigned long long where;
1612 if (!fread(&where, sizeof(where), 1, f))
1614 if (!fread(&what, sizeof(what), 1, f))
1617 #if BYTE_ORDER == LITTLE_ENDIAN
1618 where = bswap_64(where);
1625 m_cue_entries.insert(cueEntry(where, what));
1628 eDebug("%d entries", m_cue_entries.size());
1630 eDebug("cutfile not found!");
1632 m_cuesheet_changed = 0;
1633 cutlistToCuesheet();
1634 m_event((iPlayableService*)this, evCuesheetChanged);
1637 void eDVBServicePlay::saveCuesheet()
1639 std::string filename = m_reference.path + ".cuts";
1641 FILE *f = fopen(filename.c_str(), "wb");
1645 unsigned long long where;
1648 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1650 #if BYTE_ORDER == BIG_ENDIAN
1653 where = bswap_64(i->where);
1655 what = htonl(i->what);
1656 fwrite(&where, sizeof(where), 1, f);
1657 fwrite(&what, sizeof(what), 1, f);
1663 m_cuesheet_changed = 0;
1666 void eDVBServicePlay::cutlistToCuesheet()
1670 eDebug("no cue sheet");
1675 if (!m_cutlist_enabled)
1677 m_cue->commitSpans();
1678 eDebug("cutlists where disabled");
1682 pts_t in = 0, out = 0, length = 0;
1686 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1690 if (i == m_cue_entries.end())
1693 if (i->what == 0) /* in */
1697 } else if (i->what == 1) /* out */
1707 m_cue->addSourceSpan(in, out);
1711 if (i == m_cue_entries.end())
1714 m_cue->commitSpans();
1717 DEFINE_REF(eDVBServicePlay)
1719 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");