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)
573 if (m_reference.path == "s")
575 m_reference.path = "";
579 m_is_pvr = !m_reference.path.empty();
581 m_timeshift_enabled = m_timeshift_active = 0;
584 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
585 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
586 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
588 m_cuesheet_changed = 0;
589 m_cutlist_enabled = 1;
592 eDVBServicePlay::~eDVBServicePlay()
596 void eDVBServicePlay::gotNewEvent()
600 ePtr<eServiceEvent> m_event_now, m_event_next;
601 getEvent(m_event_now, 0);
602 getEvent(m_event_next, 1);
605 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
607 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
609 m_event((iPlayableService*)this, evUpdatedEventInfo);
612 void eDVBServicePlay::serviceEvent(int event)
616 case eDVBServicePMTHandler::eventTuned:
618 ePtr<iDVBDemux> m_demux;
619 if (!m_service_handler.getDataDemux(m_demux))
621 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
622 int sid = ref.getParentServiceID().get();
624 sid = ref.getServiceID().get();
625 if ( ref.getParentTransportStreamID().get() &&
626 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
627 m_event_handler.startOther(m_demux, sid);
629 m_event_handler.start(m_demux, sid);
633 case eDVBServicePMTHandler::eventTuneFailed:
635 eDebug("DVB service failed to tune");
636 m_event((iPlayableService*)this, evTuneFailed);
639 case eDVBServicePMTHandler::eventNewProgramInfo:
641 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
642 if (m_timeshift_enabled)
643 updateTimeshiftPids();
644 if (!m_timeshift_active)
646 if (m_first_program_info && m_is_pvr)
648 m_first_program_info = 0;
651 m_event((iPlayableService*)this, evUpdatedInfo);
654 case eDVBServicePMTHandler::eventEOF:
655 m_event((iPlayableService*)this, evEOF);
657 case eDVBServicePMTHandler::eventSOF:
658 m_event((iPlayableService*)this, evSOF);
663 void eDVBServicePlay::serviceEventTimeshift(int event)
667 case eDVBServicePMTHandler::eventNewProgramInfo:
668 if (m_timeshift_active)
671 case eDVBServicePMTHandler::eventSOF:
672 m_event((iPlayableService*)this, evSOF);
674 case eDVBServicePMTHandler::eventEOF:
680 RESULT eDVBServicePlay::start()
683 /* in pvr mode, we only want to use one demux. in tv mode, we're using
684 two (one for decoding, one for data source), as we must be prepared
685 to start recording from the data demux. */
686 m_cue = new eCueSheet();
688 m_first_program_info = 1;
689 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
690 r = m_service_handler.tune(service, m_is_pvr, m_cue);
692 /* inject EIT if there is a stored one */
695 std::string filename = service.path;
696 filename.erase(filename.length()-2, 2);
698 int fd = ::open( filename.c_str(), O_RDONLY );
702 int rd = ::read(fd, buf, 4096);
704 if ( rd > 12 /*EIT_LOOP_SIZE*/ )
707 ePtr<eServiceEvent> event = new eServiceEvent;
708 ePtr<eServiceEvent> empty;
709 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
710 m_event_handler.inject(event, 0);
711 m_event_handler.inject(empty, 1);
720 m_event(this, evStart);
721 m_event((iPlayableService*)this, evSeekableStatusChanged);
725 RESULT eDVBServicePlay::stop()
727 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
729 m_service_handler_timeshift.free();
730 m_service_handler.free();
732 if (m_is_pvr && m_cuesheet_changed)
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;
1020 if (m_service_handler.getProgramInfo(program))
1026 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1028 ePtr<eServiceEvent> evt;
1029 if (!m_event_handler.getEvent(evt, 0))
1031 ePtr<eComponentData> data;
1032 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1034 if ( data->getStreamContent() == 1 )
1036 switch(data->getComponentType())
1039 case 1: // 4:3 SD PAL
1041 case 3: // 16:9 SD PAL
1042 case 4: // > 16:9 PAL
1043 case 5: // 4:3 SD NTSC
1045 case 7: // 16:9 SD NTSC
1046 case 8: // > 16:9 NTSC
1049 case 9: // 4:3 HD PAL
1051 case 0xB: // 16:9 HD PAL
1052 case 0xC: // > 16:9 HD PAL
1053 case 0xD: // 4:3 HD NTSC
1055 case 0xF: // 16:9 HD NTSC
1056 case 0x10: // > 16:9 HD PAL
1057 return data->getComponentType();
1064 case sIsCrypted: return program.isCrypted;
1065 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1066 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1067 case sPCRPID: return program.pcrPid;
1068 case sPMTPID: return program.pmtPid;
1069 case sTXTPID: return program.textPid;
1070 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1071 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1072 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1073 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1074 case sProvider: if (!m_dvb_service) return -1; return -2;
1080 std::string eDVBServicePlay::getInfoString(int w)
1085 if (!m_dvb_service) return "";
1086 return m_dvb_service->m_provider_name;
1092 int eDVBServicePlay::getNumberOfTracks()
1094 eDVBServicePMTHandler::program program;
1095 if (m_service_handler.getProgramInfo(program))
1097 return program.audioStreams.size();
1100 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1102 int ret = selectAudioStream(i);
1104 if (m_decoder->start())
1110 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1112 eDVBServicePMTHandler::program program;
1114 if (m_service_handler.getProgramInfo(program))
1117 if (i >= program.audioStreams.size())
1120 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1121 info.m_description = "MPEG";
1122 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1123 info.m_description = "AC3";
1124 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1125 info.m_description = "DTS";
1127 info.m_description = "???";
1129 if (program.audioStreams[i].component_tag != -1)
1131 ePtr<eServiceEvent> evt;
1132 if (!m_event_handler.getEvent(evt, 0))
1134 ePtr<eComponentData> data;
1135 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1136 info.m_language = data->getText();
1140 if (info.m_language.empty())
1141 info.m_language = program.audioStreams[i].language_code;
1146 int eDVBServicePlay::selectAudioStream(int i)
1148 eDVBServicePMTHandler::program program;
1150 if (m_service_handler.getProgramInfo(program))
1153 if ((unsigned int)i >= program.audioStreams.size())
1159 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1162 if (m_dvb_service && !m_is_pvr)
1164 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1166 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1167 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1170 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1171 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1175 m_current_audio_stream = i;
1180 int eDVBServicePlay::getFrontendInfo(int w)
1184 eUsePtr<iDVBChannel> channel;
1185 if(m_service_handler.getChannel(channel))
1187 ePtr<iDVBFrontend> fe;
1188 if(channel->getFrontend(fe))
1190 return fe->readFrontendData(w);
1193 PyObject *eDVBServicePlay::getFrontendData(bool original)
1197 eUsePtr<iDVBChannel> channel;
1198 if(!m_service_handler.getChannel(channel))
1200 ePtr<iDVBFrontend> fe;
1201 if(!channel->getFrontend(fe))
1203 ret = fe->readTransponderData(original);
1206 ePtr<iDVBFrontendParameters> feparm;
1207 channel->getCurrentFrontendParameters(feparm);
1210 eDVBFrontendParametersSatellite osat;
1211 if (!feparm->getDVBS(osat))
1213 void PutToDict(PyObject *, const char*, long);
1214 void PutToDict(PyObject *, const char*, const char*);
1215 PutToDict(ret, "orbital_position", osat.orbital_position);
1216 const char *tmp = "UNKNOWN";
1217 switch(osat.polarisation)
1219 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1220 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1221 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1222 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1225 PutToDict(ret, "polarization", tmp);
1239 int eDVBServicePlay::getNumberOfSubservices()
1241 ePtr<eServiceEvent> evt;
1242 if (!m_event_handler.getEvent(evt, 0))
1243 return evt->getNumOfLinkageServices();
1247 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1249 ePtr<eServiceEvent> evt;
1250 if (!m_event_handler.getEvent(evt, 0))
1252 if (!evt->getLinkageService(sub, m_reference, n))
1255 sub.type=eServiceReference::idInvalid;
1259 RESULT eDVBServicePlay::startTimeshift()
1261 ePtr<iDVBDemux> demux;
1263 eDebug("Start timeshift!");
1265 if (m_timeshift_enabled)
1268 /* start recording with the data demux. */
1269 if (m_service_handler.getDataDemux(demux))
1272 demux->createTSRecorder(m_record);
1276 char templ[]=TSPATH "/timeshift.XXXXXX";
1277 m_timeshift_fd = mkstemp(templ);
1278 m_timeshift_file = templ;
1280 eDebug("recording to %s", templ);
1282 if (m_timeshift_fd < 0)
1288 m_record->setTargetFD(m_timeshift_fd);
1290 m_timeshift_enabled = 1;
1292 updateTimeshiftPids();
1298 RESULT eDVBServicePlay::stopTimeshift()
1300 if (!m_timeshift_enabled)
1305 m_timeshift_enabled = 0;
1310 close(m_timeshift_fd);
1311 eDebug("remove timeshift file");
1312 remove(m_timeshift_file.c_str());
1317 int eDVBServicePlay::isTimeshiftActive()
1319 return m_timeshift_enabled && m_timeshift_active;
1322 RESULT eDVBServicePlay::activateTimeshift()
1324 if (!m_timeshift_enabled)
1327 if (!m_timeshift_active)
1329 switchToTimeshift();
1336 PyObject *eDVBServicePlay::getCutList()
1338 PyObject *list = PyList_New(0);
1340 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1342 PyObject *tuple = PyTuple_New(2);
1343 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1344 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1345 PyList_Append(list, tuple);
1352 void eDVBServicePlay::setCutList(PyObject *list)
1354 if (!PyList_Check(list))
1356 int size = PyList_Size(list);
1359 m_cue_entries.clear();
1361 for (i=0; i<size; ++i)
1363 PyObject *tuple = PyList_GetItem(list, i);
1364 if (!PyTuple_Check(tuple))
1366 eDebug("non-tuple in cutlist");
1369 if (PyTuple_Size(tuple) != 2)
1371 eDebug("cutlist entries need to be a 2-tuple");
1374 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1375 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1377 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1380 pts_t pts = PyLong_AsLongLong(ppts);
1381 int type = PyInt_AsLong(ptype);
1382 m_cue_entries.insert(cueEntry(pts, type));
1383 eDebug("adding %08llx, %d", pts, type);
1385 m_cuesheet_changed = 1;
1387 cutlistToCuesheet();
1388 m_event((iPlayableService*)this, evCuesheetChanged);
1391 void eDVBServicePlay::setCutListEnable(int enable)
1393 m_cutlist_enabled = enable;
1394 cutlistToCuesheet();
1397 void eDVBServicePlay::updateTimeshiftPids()
1402 eDVBServicePMTHandler::program program;
1403 if (m_service_handler.getProgramInfo(program))
1407 std::set<int> pids_to_record;
1408 pids_to_record.insert(0); // PAT
1409 if (program.pmtPid != -1)
1410 pids_to_record.insert(program.pmtPid); // PMT
1412 if (program.textPid != -1)
1413 pids_to_record.insert(program.textPid); // Videotext
1415 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1416 i(program.videoStreams.begin());
1417 i != program.videoStreams.end(); ++i)
1418 pids_to_record.insert(i->pid);
1420 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1421 i(program.audioStreams.begin());
1422 i != program.audioStreams.end(); ++i)
1423 pids_to_record.insert(i->pid);
1425 std::set<int> new_pids, obsolete_pids;
1427 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1428 m_pids_active.begin(), m_pids_active.end(),
1429 std::inserter(new_pids, new_pids.begin()));
1431 std::set_difference(
1432 m_pids_active.begin(), m_pids_active.end(),
1433 pids_to_record.begin(), pids_to_record.end(),
1434 std::inserter(new_pids, new_pids.begin())
1437 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1438 m_record->addPID(*i);
1440 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1441 m_record->removePID(*i);
1445 void eDVBServicePlay::switchToLive()
1447 if (!m_timeshift_active)
1452 /* free the timeshift service handler, we need the resources */
1453 m_service_handler_timeshift.free();
1454 m_timeshift_active = 0;
1456 m_event((iPlayableService*)this, evSeekableStatusChanged);
1461 void eDVBServicePlay::switchToTimeshift()
1463 if (m_timeshift_active)
1469 m_timeshift_active = 1;
1471 m_event((iPlayableService*)this, evSeekableStatusChanged);
1473 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1474 r.path = m_timeshift_file;
1476 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1477 updateDecoder(); /* mainly to switch off PCR */
1480 void eDVBServicePlay::updateDecoder()
1482 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1483 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1485 eDVBServicePMTHandler::program program;
1486 if (h.getProgramInfo(program))
1487 eDebug("getting program info failed.");
1490 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1491 if (!program.videoStreams.empty())
1493 eDebugNoNewLine(" (");
1494 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1495 i(program.videoStreams.begin());
1496 i != program.videoStreams.end(); ++i)
1500 if (i != program.videoStreams.begin())
1501 eDebugNoNewLine(", ");
1502 eDebugNoNewLine("%04x", i->pid);
1504 eDebugNoNewLine(")");
1506 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1507 if (!program.audioStreams.empty())
1509 eDebugNoNewLine(" (");
1510 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1511 i(program.audioStreams.begin());
1512 i != program.audioStreams.end(); ++i)
1519 if (i != program.audioStreams.begin())
1520 eDebugNoNewLine(", ");
1521 eDebugNoNewLine("%04x", i->pid);
1523 eDebugNoNewLine(")");
1525 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1526 pcrpid = program.pcrPid;
1527 eDebug(", and the text pid is %04x", program.textPid);
1528 tpid = program.textPid;
1533 h.getDecodeDemux(m_decode_demux);
1535 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1537 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1542 m_decoder->setVideoPID(vpid);
1543 m_current_audio_stream = 0;
1544 m_decoder->setAudioPID(apid, apidtype);
1545 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1546 m_decoder->setSyncPCR(pcrpid);
1548 m_decoder->setSyncPCR(-1);
1549 m_decoder->setTextPID(tpid);
1551 m_decoder->setTrickmode(1);
1553 // how we can do this better?
1554 // update cache pid when the user changed the audio track or video track
1555 // TODO handling of difference audio types.. default audio types..
1557 /* don't worry about non-existing services, nor pvr services */
1558 if (m_dvb_service && !m_is_pvr)
1560 if (apidtype == eDVBAudio::aMPEG)
1562 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1563 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1567 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1568 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1570 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1571 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1572 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1577 void eDVBServicePlay::loadCuesheet()
1579 std::string filename = m_reference.path + ".cuts";
1581 m_cue_entries.clear();
1583 FILE *f = fopen(filename.c_str(), "rb");
1587 eDebug("loading cuts..");
1590 unsigned long long where;
1593 if (!fread(&where, sizeof(where), 1, f))
1595 if (!fread(&what, sizeof(what), 1, f))
1598 #if BYTE_ORDER == LITTLE_ENDIAN
1599 where = bswap_64(where);
1606 m_cue_entries.insert(cueEntry(where, what));
1609 eDebug("%d entries", m_cue_entries.size());
1611 eDebug("cutfile not found!");
1613 m_cuesheet_changed = 0;
1614 cutlistToCuesheet();
1615 m_event((iPlayableService*)this, evCuesheetChanged);
1618 void eDVBServicePlay::saveCuesheet()
1620 std::string filename = m_reference.path + ".cuts";
1622 FILE *f = fopen(filename.c_str(), "wb");
1626 unsigned long long where;
1629 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1631 #if BYTE_ORDER == BIG_ENDIAN
1634 where = bswap_64(i->where);
1636 what = htonl(i->what);
1637 fwrite(&where, sizeof(where), 1, f);
1638 fwrite(&what, sizeof(what), 1, f);
1644 m_cuesheet_changed = 0;
1647 void eDVBServicePlay::cutlistToCuesheet()
1651 eDebug("no cue sheet");
1656 if (!m_cutlist_enabled)
1658 m_cue->commitSpans();
1659 eDebug("cutlists where disabled");
1663 pts_t in = 0, out = 0, length = 0;
1667 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1671 if (i == m_cue_entries.end())
1674 if (i->what == 0) /* in */
1678 } else if (i->what == 1) /* out */
1688 m_cue->addSourceSpan(in, out);
1692 if (i == m_cue_entries.end())
1695 m_cue->commitSpans();
1698 DEFINE_REF(eDVBServicePlay)
1700 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");