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)
571 m_is_pvr = !ref.path.empty();
573 m_timeshift_enabled = m_timeshift_active = 0;
576 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
577 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
578 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
580 m_cuesheet_changed = 0;
581 m_cutlist_enabled = 1;
584 eDVBServicePlay::~eDVBServicePlay()
588 void eDVBServicePlay::gotNewEvent()
592 ePtr<eServiceEvent> m_event_now, m_event_next;
593 getEvent(m_event_now, 0);
594 getEvent(m_event_next, 1);
597 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
599 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
601 m_event((iPlayableService*)this, evUpdatedEventInfo);
604 void eDVBServicePlay::serviceEvent(int event)
608 case eDVBServicePMTHandler::eventTuned:
610 ePtr<iDVBDemux> m_demux;
611 if (!m_service_handler.getDataDemux(m_demux))
613 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
614 int sid = ref.getParentServiceID().get();
616 sid = ref.getServiceID().get();
617 if ( ref.getParentTransportStreamID().get() &&
618 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
619 m_event_handler.startOther(m_demux, sid);
621 m_event_handler.start(m_demux, sid);
625 case eDVBServicePMTHandler::eventTuneFailed:
627 eDebug("DVB service failed to tune");
628 m_event((iPlayableService*)this, evTuneFailed);
631 case eDVBServicePMTHandler::eventNewProgramInfo:
633 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
634 if (m_timeshift_enabled)
635 updateTimeshiftPids();
636 if (!m_timeshift_active)
638 if (m_first_program_info && m_is_pvr)
640 m_first_program_info = 0;
643 m_event((iPlayableService*)this, evUpdatedInfo);
646 case eDVBServicePMTHandler::eventEOF:
647 m_event((iPlayableService*)this, evEOF);
649 case eDVBServicePMTHandler::eventSOF:
650 m_event((iPlayableService*)this, evSOF);
655 void eDVBServicePlay::serviceEventTimeshift(int event)
659 case eDVBServicePMTHandler::eventNewProgramInfo:
660 if (m_timeshift_active)
663 case eDVBServicePMTHandler::eventSOF:
664 m_event((iPlayableService*)this, evSOF);
666 case eDVBServicePMTHandler::eventEOF:
672 RESULT eDVBServicePlay::start()
675 /* in pvr mode, we only want to use one demux. in tv mode, we're using
676 two (one for decoding, one for data source), as we must be prepared
677 to start recording from the data demux. */
678 m_cue = new eCueSheet();
680 m_first_program_info = 1;
681 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
682 r = m_service_handler.tune(service, m_is_pvr, m_cue);
684 /* inject EIT if there is a stored one */
687 std::string filename = service.path;
688 filename.erase(filename.length()-2, 2);
690 int fd = ::open( filename.c_str(), O_RDONLY );
694 int rd = ::read(fd, buf, 4096);
696 if ( rd > 12 /*EIT_LOOP_SIZE*/ )
699 ePtr<eServiceEvent> event = new eServiceEvent;
700 ePtr<eServiceEvent> empty;
701 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
702 m_event_handler.inject(event, 0);
703 m_event_handler.inject(empty, 1);
712 m_event(this, evStart);
713 m_event((iPlayableService*)this, evSeekableStatusChanged);
717 RESULT eDVBServicePlay::stop()
719 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
721 m_service_handler_timeshift.free();
722 m_service_handler.free();
724 if (m_is_pvr && m_cuesheet_changed)
730 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
732 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
736 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
738 /* note: we check for timeshift to be enabled,
739 not neccessary active. if you pause when timeshift
740 is not active, you should activate it when unpausing */
741 if ((!m_is_pvr) && (!m_timeshift_enabled))
751 RESULT eDVBServicePlay::setSlowMotion(int ratio)
754 return m_decoder->setSlowMotion(ratio);
759 RESULT eDVBServicePlay::setFastForward(int ratio)
761 int skipmode, ffratio;
767 } else if (ratio > 0)
775 } else // if (ratio < 0)
781 if (m_skipmode != skipmode)
783 eDebug("setting cue skipmode to %d", skipmode);
785 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
788 m_skipmode = skipmode;
793 return m_decoder->setFastForward(ffratio);
796 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
798 if (m_is_pvr || m_timeshift_enabled)
808 /* TODO: when timeshift is enabled but not active, this doesn't work. */
809 RESULT eDVBServicePlay::getLength(pts_t &len)
811 ePtr<iDVBPVRChannel> pvr_channel;
813 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
816 return pvr_channel->getLength(len);
819 RESULT eDVBServicePlay::pause()
821 if (!m_is_paused && m_decoder)
824 return m_decoder->freeze(0);
829 RESULT eDVBServicePlay::unpause()
831 if (m_is_paused && m_decoder)
834 return m_decoder->unfreeze();
839 RESULT eDVBServicePlay::seekTo(pts_t to)
841 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
846 ePtr<iDVBPVRChannel> pvr_channel;
848 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
854 m_cue->seekTo(0, to);
858 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
860 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
865 ePtr<iDVBPVRChannel> pvr_channel;
867 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
872 /* HACK until we have skip-AP api */
873 if ((to > 0) && (to < 100))
881 m_cue->seekTo(mode, to);
885 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
887 ePtr<iDVBPVRChannel> pvr_channel;
892 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
897 /* if there is a decoder, use audio or video PTS */
900 r = m_decoder->getPTS(0, pos);
906 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
909 RESULT eDVBServicePlay::setTrickmode(int trick)
912 m_decoder->setTrickmode(trick);
916 RESULT eDVBServicePlay::isCurrentlySeekable()
918 return m_is_pvr || m_timeshift_active;
921 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
927 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
933 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
939 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
945 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
948 if (m_timeshift_enabled || !m_is_pvr)
950 if (!m_timeshift_enabled)
952 /* we need enough diskspace */
954 if (statfs(TSPATH "/.", &fs) < 0)
956 eDebug("statfs failed!");
960 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
962 eDebug("not enough diskspace for timeshift! (less than 1GB)");
972 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
983 RESULT eDVBServicePlay::getName(std::string &name)
987 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
988 return i->getName(m_reference, name);
992 m_dvb_service->getName(m_reference, name);
996 else if (!m_reference.name.empty())
997 eStaticServiceDVBInformation().getName(m_reference, name);
999 name = "DVB service";
1003 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1005 return m_event_handler.getEvent(evt, nownext);
1008 int eDVBServicePlay::getInfo(int w)
1010 eDVBServicePMTHandler::program program;
1012 if (m_service_handler.getProgramInfo(program))
1018 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1020 ePtr<eServiceEvent> evt;
1021 if (!m_event_handler.getEvent(evt, 0))
1023 ePtr<eComponentData> data;
1024 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1026 if ( data->getStreamContent() == 1 )
1028 switch(data->getComponentType())
1031 case 1: // 4:3 SD PAL
1033 case 3: // 16:9 SD PAL
1034 case 4: // > 16:9 PAL
1035 case 5: // 4:3 SD NTSC
1037 case 7: // 16:9 SD NTSC
1038 case 8: // > 16:9 NTSC
1041 case 9: // 4:3 HD PAL
1043 case 0xB: // 16:9 HD PAL
1044 case 0xC: // > 16:9 HD PAL
1045 case 0xD: // 4:3 HD NTSC
1047 case 0xF: // 16:9 HD NTSC
1048 case 0x10: // > 16:9 HD PAL
1049 return data->getComponentType();
1056 case sIsCrypted: return program.isCrypted;
1057 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1058 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1059 case sPCRPID: return program.pcrPid;
1060 case sPMTPID: return program.pmtPid;
1061 case sTXTPID: return program.textPid;
1062 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1063 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1064 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1065 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1066 case sProvider: if (!m_dvb_service) return -1; return -2;
1072 std::string eDVBServicePlay::getInfoString(int w)
1077 if (!m_dvb_service) return "";
1078 return m_dvb_service->m_provider_name;
1084 int eDVBServicePlay::getNumberOfTracks()
1086 eDVBServicePMTHandler::program program;
1087 if (m_service_handler.getProgramInfo(program))
1089 return program.audioStreams.size();
1092 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1094 int ret = selectAudioStream(i);
1096 if (m_decoder->start())
1102 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1104 eDVBServicePMTHandler::program program;
1106 if (m_service_handler.getProgramInfo(program))
1109 if (i >= program.audioStreams.size())
1112 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1113 info.m_description = "MPEG";
1114 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1115 info.m_description = "AC3";
1116 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1117 info.m_description = "DTS";
1119 info.m_description = "???";
1121 if (program.audioStreams[i].component_tag != -1)
1123 ePtr<eServiceEvent> evt;
1124 if (!m_event_handler.getEvent(evt, 0))
1126 ePtr<eComponentData> data;
1127 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1128 info.m_language = data->getText();
1132 if (info.m_language.empty())
1133 info.m_language = program.audioStreams[i].language_code;
1138 int eDVBServicePlay::selectAudioStream(int i)
1140 eDVBServicePMTHandler::program program;
1142 if (m_service_handler.getProgramInfo(program))
1145 if ((unsigned int)i >= program.audioStreams.size())
1151 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1154 if (m_dvb_service && !m_is_pvr)
1156 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1158 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1159 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1162 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1163 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1167 m_current_audio_stream = i;
1172 int eDVBServicePlay::getFrontendInfo(int w)
1176 eUsePtr<iDVBChannel> channel;
1177 if(m_service_handler.getChannel(channel))
1179 ePtr<iDVBFrontend> fe;
1180 if(channel->getFrontend(fe))
1182 return fe->readFrontendData(w);
1185 PyObject *eDVBServicePlay::getFrontendData(bool original)
1189 eUsePtr<iDVBChannel> channel;
1190 if(!m_service_handler.getChannel(channel))
1192 ePtr<iDVBFrontend> fe;
1193 if(!channel->getFrontend(fe))
1195 ret = fe->readTransponderData(original);
1198 ePtr<iDVBFrontendParameters> feparm;
1199 channel->getCurrentFrontendParameters(feparm);
1202 eDVBFrontendParametersSatellite osat;
1203 if (!feparm->getDVBS(osat))
1205 void PutToDict(PyObject *, const char*, long);
1206 void PutToDict(PyObject *, const char*, const char*);
1207 PutToDict(ret, "orbital_position", osat.orbital_position);
1208 const char *tmp = "UNKNOWN";
1209 switch(osat.polarisation)
1211 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1212 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1213 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1214 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1217 PutToDict(ret, "polarization", tmp);
1231 int eDVBServicePlay::getNumberOfSubservices()
1233 ePtr<eServiceEvent> evt;
1234 if (!m_event_handler.getEvent(evt, 0))
1235 return evt->getNumOfLinkageServices();
1239 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1241 ePtr<eServiceEvent> evt;
1242 if (!m_event_handler.getEvent(evt, 0))
1244 if (!evt->getLinkageService(sub, m_reference, n))
1247 sub.type=eServiceReference::idInvalid;
1251 RESULT eDVBServicePlay::startTimeshift()
1253 ePtr<iDVBDemux> demux;
1255 eDebug("Start timeshift!");
1257 if (m_timeshift_enabled)
1260 /* start recording with the data demux. */
1261 if (m_service_handler.getDataDemux(demux))
1264 demux->createTSRecorder(m_record);
1268 char templ[]=TSPATH "/timeshift.XXXXXX";
1269 m_timeshift_fd = mkstemp(templ);
1270 m_timeshift_file = templ;
1272 eDebug("recording to %s", templ);
1274 if (m_timeshift_fd < 0)
1280 m_record->setTargetFD(m_timeshift_fd);
1282 m_timeshift_enabled = 1;
1284 updateTimeshiftPids();
1290 RESULT eDVBServicePlay::stopTimeshift()
1292 if (!m_timeshift_enabled)
1297 m_timeshift_enabled = 0;
1302 close(m_timeshift_fd);
1303 eDebug("remove timeshift file");
1304 remove(m_timeshift_file.c_str());
1309 int eDVBServicePlay::isTimeshiftActive()
1311 return m_timeshift_enabled && m_timeshift_active;
1314 RESULT eDVBServicePlay::activateTimeshift()
1316 if (!m_timeshift_enabled)
1319 if (!m_timeshift_active)
1321 switchToTimeshift();
1328 PyObject *eDVBServicePlay::getCutList()
1330 PyObject *list = PyList_New(0);
1332 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1334 PyObject *tuple = PyTuple_New(2);
1335 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1336 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1337 PyList_Append(list, tuple);
1344 void eDVBServicePlay::setCutList(PyObject *list)
1346 if (!PyList_Check(list))
1348 int size = PyList_Size(list);
1351 m_cue_entries.clear();
1353 for (i=0; i<size; ++i)
1355 PyObject *tuple = PyList_GetItem(list, i);
1356 if (!PyTuple_Check(tuple))
1358 eDebug("non-tuple in cutlist");
1361 if (PyTuple_Size(tuple) != 2)
1363 eDebug("cutlist entries need to be a 2-tuple");
1366 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1367 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1369 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1372 pts_t pts = PyLong_AsLongLong(ppts);
1373 int type = PyInt_AsLong(ptype);
1374 m_cue_entries.insert(cueEntry(pts, type));
1375 eDebug("adding %08llx, %d", pts, type);
1377 m_cuesheet_changed = 1;
1379 cutlistToCuesheet();
1380 m_event((iPlayableService*)this, evCuesheetChanged);
1383 void eDVBServicePlay::setCutListEnable(int enable)
1385 m_cutlist_enabled = enable;
1386 cutlistToCuesheet();
1389 void eDVBServicePlay::updateTimeshiftPids()
1394 eDVBServicePMTHandler::program program;
1395 if (m_service_handler.getProgramInfo(program))
1399 std::set<int> pids_to_record;
1400 pids_to_record.insert(0); // PAT
1401 if (program.pmtPid != -1)
1402 pids_to_record.insert(program.pmtPid); // PMT
1404 if (program.textPid != -1)
1405 pids_to_record.insert(program.textPid); // Videotext
1407 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1408 i(program.videoStreams.begin());
1409 i != program.videoStreams.end(); ++i)
1410 pids_to_record.insert(i->pid);
1412 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1413 i(program.audioStreams.begin());
1414 i != program.audioStreams.end(); ++i)
1415 pids_to_record.insert(i->pid);
1417 std::set<int> new_pids, obsolete_pids;
1419 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1420 m_pids_active.begin(), m_pids_active.end(),
1421 std::inserter(new_pids, new_pids.begin()));
1423 std::set_difference(
1424 m_pids_active.begin(), m_pids_active.end(),
1425 pids_to_record.begin(), pids_to_record.end(),
1426 std::inserter(new_pids, new_pids.begin())
1429 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1430 m_record->addPID(*i);
1432 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1433 m_record->removePID(*i);
1437 void eDVBServicePlay::switchToLive()
1439 if (!m_timeshift_active)
1444 /* free the timeshift service handler, we need the resources */
1445 m_service_handler_timeshift.free();
1446 m_timeshift_active = 0;
1448 m_event((iPlayableService*)this, evSeekableStatusChanged);
1453 void eDVBServicePlay::switchToTimeshift()
1455 if (m_timeshift_active)
1461 m_timeshift_active = 1;
1463 m_event((iPlayableService*)this, evSeekableStatusChanged);
1465 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1466 r.path = m_timeshift_file;
1468 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1469 updateDecoder(); /* mainly to switch off PCR */
1472 void eDVBServicePlay::updateDecoder()
1474 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1475 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1477 eDVBServicePMTHandler::program program;
1478 if (h.getProgramInfo(program))
1479 eDebug("getting program info failed.");
1482 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1483 if (!program.videoStreams.empty())
1485 eDebugNoNewLine(" (");
1486 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1487 i(program.videoStreams.begin());
1488 i != program.videoStreams.end(); ++i)
1492 if (i != program.videoStreams.begin())
1493 eDebugNoNewLine(", ");
1494 eDebugNoNewLine("%04x", i->pid);
1496 eDebugNoNewLine(")");
1498 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1499 if (!program.audioStreams.empty())
1501 eDebugNoNewLine(" (");
1502 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1503 i(program.audioStreams.begin());
1504 i != program.audioStreams.end(); ++i)
1511 if (i != program.audioStreams.begin())
1512 eDebugNoNewLine(", ");
1513 eDebugNoNewLine("%04x", i->pid);
1515 eDebugNoNewLine(")");
1517 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1518 pcrpid = program.pcrPid;
1519 eDebug(", and the text pid is %04x", program.textPid);
1520 tpid = program.textPid;
1525 h.getDecodeDemux(m_decode_demux);
1527 m_decode_demux->getMPEGDecoder(m_decoder);
1529 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1534 m_decoder->setVideoPID(vpid);
1535 m_current_audio_stream = 0;
1536 m_decoder->setAudioPID(apid, apidtype);
1537 if (!(m_is_pvr || m_timeshift_active))
1538 m_decoder->setSyncPCR(pcrpid);
1540 m_decoder->setSyncPCR(-1);
1541 m_decoder->setTextPID(tpid);
1543 // how we can do this better?
1544 // update cache pid when the user changed the audio track or video track
1545 // TODO handling of difference audio types.. default audio types..
1547 /* don't worry about non-existing services, nor pvr services */
1548 if (m_dvb_service && !m_is_pvr)
1550 if (apidtype == eDVBAudio::aMPEG)
1552 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1553 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1557 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1558 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1560 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1561 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1562 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1567 void eDVBServicePlay::loadCuesheet()
1569 std::string filename = m_reference.path + ".cuts";
1571 m_cue_entries.clear();
1573 FILE *f = fopen(filename.c_str(), "rb");
1577 eDebug("loading cuts..");
1580 unsigned long long where;
1583 if (!fread(&where, sizeof(where), 1, f))
1585 if (!fread(&what, sizeof(what), 1, f))
1588 #if BYTE_ORDER == LITTLE_ENDIAN
1589 where = bswap_64(where);
1596 m_cue_entries.insert(cueEntry(where, what));
1599 eDebug("%d entries", m_cue_entries.size());
1601 eDebug("cutfile not found!");
1603 m_cuesheet_changed = 0;
1604 cutlistToCuesheet();
1605 m_event((iPlayableService*)this, evCuesheetChanged);
1608 void eDVBServicePlay::saveCuesheet()
1610 std::string filename = m_reference.path + ".cuts";
1612 FILE *f = fopen(filename.c_str(), "wb");
1616 unsigned long long where;
1619 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1621 #if BYTE_ORDER == BIG_ENDIAN
1624 where = bswap_64(i->where);
1626 what = htonl(i->what);
1627 fwrite(&where, sizeof(where), 1, f);
1628 fwrite(&what, sizeof(what), 1, f);
1634 m_cuesheet_changed = 0;
1637 void eDVBServicePlay::cutlistToCuesheet()
1641 eDebug("no cue sheet");
1646 if (!m_cutlist_enabled)
1648 m_cue->commitSpans();
1649 eDebug("cutlists where disabled");
1653 pts_t in = 0, out = 0, length = 0;
1657 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1661 if (i == m_cue_entries.end())
1664 if (i->what == 0) /* in */
1668 } else if (i->what == 1) /* out */
1678 m_cue->addSourceSpan(in, out);
1682 if (i == m_cue_entries.end())
1685 m_cue->commitSpans();
1688 DEFINE_REF(eDVBServicePlay)
1690 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");