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/service/servicedvbrecord.h>
14 #include <lib/service/event.h>
15 #include <lib/dvb/metaparser.h>
16 #include <lib/dvb/tstools.h>
17 #include <lib/python/python.h>
22 #include <netinet/in.h>
24 #include <dvbsi++/event_information_section.h>
27 #error no byte order defined!
30 #define TSPATH "/media/hdd"
32 class eStaticServiceDVBInformation: public iStaticServiceInformation
34 DECLARE_REF(eStaticServiceDVBInformation);
36 RESULT getName(const eServiceReference &ref, std::string &name);
37 int getLength(const eServiceReference &ref);
40 DEFINE_REF(eStaticServiceDVBInformation);
42 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
44 eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
45 if ( !ref.name.empty() )
47 if (service.getParentTransportStreamID().get()) // linkage subservice
49 ePtr<iServiceHandler> service_center;
50 if (!eServiceCenter::getInstance(service_center))
52 eServiceReferenceDVB parent = service;
53 parent.setTransportStreamID( service.getParentTransportStreamID() );
54 parent.setServiceID( service.getParentServiceID() );
55 parent.setParentTransportStreamID(eTransportStreamID(0));
56 parent.setParentServiceID(eServiceID(0));
58 ePtr<iStaticServiceInformation> service_info;
59 if (!service_center->info(parent, service_info))
61 if (!service_info->getName(parent, name))
63 // just show short name
64 unsigned int pos = name.find("\xc2\x86");
65 if ( pos != std::string::npos )
67 pos = name.find("\xc2\x87");
68 if ( pos != std::string::npos )
84 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
89 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
91 DECLARE_REF(eStaticServiceDVBBouquetInformation);
93 RESULT getName(const eServiceReference &ref, std::string &name);
94 int getLength(const eServiceReference &ref);
97 DEFINE_REF(eStaticServiceDVBBouquetInformation);
99 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
101 ePtr<iDVBChannelList> db;
102 ePtr<eDVBResourceManager> res;
105 if ((err = eDVBResourceManager::getInstance(res)) != 0)
107 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
110 if ((err = res->getChannelList(db)) != 0)
112 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
117 if ((err = db->getBouquet(ref, bouquet)) != 0)
119 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
123 if ( bouquet && bouquet->m_bouquet_name.length() )
125 name = bouquet->m_bouquet_name;
132 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
137 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
139 DECLARE_REF(eStaticServiceDVBPVRInformation);
140 eServiceReference m_ref;
141 eDVBMetaParser m_parser;
143 eStaticServiceDVBPVRInformation(const eServiceReference &ref);
144 RESULT getName(const eServiceReference &ref, std::string &name);
145 int getLength(const eServiceReference &ref);
147 int getInfo(const eServiceReference &ref, int w);
148 std::string getInfoString(const eServiceReference &ref,int w);
151 DEFINE_REF(eStaticServiceDVBPVRInformation);
153 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
156 m_parser.parseFile(ref.path);
159 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
161 ASSERT(ref == m_ref);
162 name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
166 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
168 ASSERT(ref == m_ref);
172 if (tstools.openFile(ref.path.c_str()))
176 if (tstools.calcLen(len))
182 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
186 case iServiceInformation::sDescription:
187 return iServiceInformation::resIsString;
188 case iServiceInformation::sTimeCreate:
189 if (m_parser.m_time_create)
190 return m_parser.m_time_create;
192 return iServiceInformation::resNA;
194 return iServiceInformation::resNA;
198 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
202 case iServiceInformation::sDescription:
203 return m_parser.m_description;
209 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
211 DECLARE_REF(eDVBPVRServiceOfflineOperations);
212 eServiceReferenceDVB m_ref;
214 eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
216 RESULT deleteFromDisk(int simulate);
217 RESULT getListOfFilenames(std::list<std::string> &);
220 DEFINE_REF(eDVBPVRServiceOfflineOperations);
222 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
226 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
232 std::list<std::string> res;
233 if (getListOfFilenames(res))
236 /* TODO: deferred removing.. */
237 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
239 eDebug("Removing %s...", i->c_str());
240 ::unlink(i->c_str());
247 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
250 res.push_back(m_ref.path);
251 res.push_back(m_ref.path + ".meta");
252 res.push_back(m_ref.path + ".ap");
253 res.push_back(m_ref.path + ".cuts");
254 res.push_back(m_ref.path + ".eit");
258 DEFINE_REF(eServiceFactoryDVB)
260 eServiceFactoryDVB::eServiceFactoryDVB()
262 ePtr<eServiceCenter> sc;
264 eServiceCenter::getPrivInstance(sc);
266 sc->addServiceFactory(eServiceFactoryDVB::id, this);
269 eServiceFactoryDVB::~eServiceFactoryDVB()
271 ePtr<eServiceCenter> sc;
273 eServiceCenter::getPrivInstance(sc);
275 sc->removeServiceFactory(eServiceFactoryDVB::id);
278 DEFINE_REF(eDVBServiceList);
280 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
284 eDVBServiceList::~eDVBServiceList()
288 RESULT eDVBServiceList::startQuery()
290 ePtr<iDVBChannelList> db;
291 ePtr<eDVBResourceManager> res;
294 if ((err = eDVBResourceManager::getInstance(res)) != 0)
296 eDebug("no resource manager");
299 if ((err = res->getChannelList(db)) != 0)
301 eDebug("no channel list");
305 ePtr<eDVBChannelQuery> q;
307 if (!m_parent.path.empty())
309 eDVBChannelQuery::compile(q, m_parent.path);
312 eDebug("compile query failed");
317 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
319 eDebug("startQuery failed");
326 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
328 eServiceReferenceDVB ref;
330 if (!m_query || !list || !PyList_Check(list))
333 std::list<eServiceReferenceDVB> tmplist;
335 while (!m_query->getNextResult(ref))
336 tmplist.push_back(ref);
339 tmplist.sort(iListableServiceCompare(this));
341 for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
342 it != tmplist.end(); ++it)
344 PyObject *refobj = New_eServiceReference(*it);
345 PyList_Append(list, refobj);
351 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
353 eServiceReferenceDVB ref;
358 while (!m_query->getNextResult(ref))
362 list.sort(iListableServiceCompare(this));
367 RESULT eDVBServiceList::getNext(eServiceReference &ref)
372 return m_query->getNextResult((eServiceReferenceDVB&)ref);
375 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
377 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
380 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
382 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
384 ePtr<iDVBChannelList> db;
385 ePtr<eDVBResourceManager> resm;
387 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
390 if (db->getBouquet(m_parent, m_bouquet) != 0)
401 RESULT eDVBServiceList::addService(eServiceReference &ref)
405 return m_bouquet->addService(ref);
408 RESULT eDVBServiceList::removeService(eServiceReference &ref)
412 return m_bouquet->removeService(ref);
415 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
419 return m_bouquet->moveService(ref, pos);
422 RESULT eDVBServiceList::flushChanges()
426 return m_bouquet->flushChanges();
429 RESULT eDVBServiceList::setListName(const std::string &name)
433 return m_bouquet->setListName(name);
436 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
438 ePtr<eDVBService> service;
439 int r = lookupService(service, ref);
442 // check resources...
443 ptr = new eDVBServicePlay(ref, service);
447 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
449 if (ref.path.empty())
451 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
460 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
462 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
463 if (list->startQuery())
473 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
475 /* is a listable service? */
476 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
478 if ( !ref.name.empty() ) // satellites or providers list
479 ptr = new eStaticServiceDVBInformation;
480 else // a dvb bouquet
481 ptr = new eStaticServiceDVBBouquetInformation;
483 else if (!ref.path.empty()) /* do we have a PVR service? */
484 ptr = new eStaticServiceDVBPVRInformation(ref);
485 else // normal dvb service
487 ePtr<eDVBService> service;
488 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
489 ptr = new eStaticServiceDVBInformation;
491 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
497 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
499 if (ref.path.empty())
505 ptr = new eDVBPVRServiceOfflineOperations(ref);
510 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
512 // TODO: handle the listing itself
513 // if (ref.... == -1) .. return "... bouquets ...";
514 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
516 ePtr<iDVBChannelList> db;
517 ePtr<eDVBResourceManager> res;
520 if ((err = eDVBResourceManager::getInstance(res)) != 0)
522 eDebug("no resource manager");
525 if ((err = res->getChannelList(db)) != 0)
527 eDebug("no channel list");
531 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
532 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
534 eDebug("getService failed!");
541 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
542 m_reference(ref), m_dvb_service(service), m_is_paused(0)
544 m_is_pvr = !ref.path.empty();
546 m_timeshift_enabled = m_timeshift_active = 0;
549 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
550 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
551 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
553 m_cuesheet_changed = 0;
554 m_cutlist_enabled = 1;
557 eDVBServicePlay::~eDVBServicePlay()
561 void eDVBServicePlay::gotNewEvent()
565 ePtr<eServiceEvent> m_event_now, m_event_next;
566 getEvent(m_event_now, 0);
567 getEvent(m_event_next, 1);
570 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
572 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
574 m_event((iPlayableService*)this, evUpdatedEventInfo);
577 void eDVBServicePlay::serviceEvent(int event)
581 case eDVBServicePMTHandler::eventTuned:
583 ePtr<iDVBDemux> m_demux;
584 if (!m_service_handler.getDataDemux(m_demux))
586 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
587 int sid = ref.getParentServiceID().get();
589 sid = ref.getServiceID().get();
590 if ( ref.getParentTransportStreamID().get() &&
591 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
592 m_event_handler.startOther(m_demux, sid);
594 m_event_handler.start(m_demux, sid);
598 case eDVBServicePMTHandler::eventTuneFailed:
600 eDebug("DVB service failed to tune");
601 m_event((iPlayableService*)this, evTuneFailed);
604 case eDVBServicePMTHandler::eventNewProgramInfo:
606 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
607 if (m_timeshift_enabled)
608 updateTimeshiftPids();
609 if (!m_timeshift_active)
611 if (m_first_program_info && m_is_pvr)
613 m_first_program_info = 0;
616 m_event((iPlayableService*)this, evUpdatedInfo);
619 case eDVBServicePMTHandler::eventEOF:
620 m_event((iPlayableService*)this, evEOF);
622 case eDVBServicePMTHandler::eventSOF:
623 m_event((iPlayableService*)this, evSOF);
628 void eDVBServicePlay::serviceEventTimeshift(int event)
632 case eDVBServicePMTHandler::eventNewProgramInfo:
633 if (m_timeshift_active)
636 case eDVBServicePMTHandler::eventSOF:
637 m_event((iPlayableService*)this, evSOF);
639 case eDVBServicePMTHandler::eventEOF:
645 RESULT eDVBServicePlay::start()
648 /* in pvr mode, we only want to use one demux. in tv mode, we're using
649 two (one for decoding, one for data source), as we must be prepared
650 to start recording from the data demux. */
651 m_cue = new eCueSheet();
653 m_first_program_info = 1;
654 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
655 r = m_service_handler.tune(service, m_is_pvr, m_cue);
657 /* inject EIT if there is a stored one */
660 std::string filename = service.path;
661 filename.erase(filename.length()-2, 2);
663 int fd = ::open( filename.c_str(), O_RDONLY );
667 int rd = ::read(fd, buf, 4096);
669 if ( rd > 12 /*EIT_LOOP_SIZE*/ )
672 ePtr<eServiceEvent> event = new eServiceEvent;
673 ePtr<eServiceEvent> empty;
674 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
675 m_event_handler.inject(event, 0);
676 m_event_handler.inject(empty, 1);
685 m_event(this, evStart);
686 m_event((iPlayableService*)this, evSeekableStatusChanged);
690 RESULT eDVBServicePlay::stop()
692 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
694 m_service_handler_timeshift.free();
695 m_service_handler.free();
697 if (m_is_pvr && m_cuesheet_changed)
703 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
705 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
709 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
711 /* note: we check for timeshift to be enabled,
712 not neccessary active. if you pause when timeshift
713 is not active, you should activate it when unpausing */
714 if ((!m_is_pvr) && (!m_timeshift_enabled))
724 RESULT eDVBServicePlay::setSlowMotion(int ratio)
727 return m_decoder->setSlowMotion(ratio);
732 RESULT eDVBServicePlay::setFastForward(int ratio)
734 int skipmode, ffratio;
740 } else if (ratio > 0)
748 } else // if (ratio < 0)
754 if (m_skipmode != skipmode)
756 eDebug("setting cue skipmode to %d", skipmode);
758 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
761 m_skipmode = skipmode;
766 return m_decoder->setFastForward(ffratio);
769 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
771 if (m_is_pvr || m_timeshift_enabled)
781 /* TODO: when timeshift is enabled but not active, this doesn't work. */
782 RESULT eDVBServicePlay::getLength(pts_t &len)
784 ePtr<iDVBPVRChannel> pvr_channel;
786 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
789 return pvr_channel->getLength(len);
792 RESULT eDVBServicePlay::pause()
794 if (!m_is_paused && m_decoder)
797 return m_decoder->freeze(0);
802 RESULT eDVBServicePlay::unpause()
804 if (m_is_paused && m_decoder)
807 return m_decoder->unfreeze();
812 RESULT eDVBServicePlay::seekTo(pts_t to)
814 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
819 ePtr<iDVBPVRChannel> pvr_channel;
821 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
827 m_cue->seekTo(0, to);
831 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
833 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
838 ePtr<iDVBPVRChannel> pvr_channel;
840 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
845 /* HACK until we have skip-AP api */
846 if ((to > 0) && (to < 100))
854 m_cue->seekTo(mode, to);
858 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
860 ePtr<iDVBPVRChannel> pvr_channel;
865 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
870 /* if there is a decoder, use audio or video PTS */
873 r = m_decoder->getPTS(0, pos);
879 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
882 RESULT eDVBServicePlay::setTrickmode(int trick)
885 m_decoder->setTrickmode(trick);
889 RESULT eDVBServicePlay::isCurrentlySeekable()
891 return m_is_pvr || m_timeshift_active;
894 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
900 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
906 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
912 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
918 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
921 if (m_timeshift_enabled || !m_is_pvr)
923 if (!m_timeshift_enabled)
925 /* we need enough diskspace */
927 if (statfs(TSPATH "/.", &fs) < 0)
929 eDebug("statfs failed!");
933 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
935 eDebug("not enough diskspace for timeshift! (less than 1GB)");
945 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
956 RESULT eDVBServicePlay::getName(std::string &name)
960 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
961 return i->getName(m_reference, name);
965 m_dvb_service->getName(m_reference, name);
969 else if (!m_reference.name.empty())
970 eStaticServiceDVBInformation().getName(m_reference, name);
972 name = "DVB service";
976 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
978 return m_event_handler.getEvent(evt, nownext);
981 int eDVBServicePlay::getInfo(int w)
983 eDVBServicePMTHandler::program program;
985 if (m_service_handler.getProgramInfo(program))
991 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
993 ePtr<eServiceEvent> evt;
994 if (!m_event_handler.getEvent(evt, 0))
996 ePtr<eComponentData> data;
997 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
999 if ( data->getStreamContent() == 1 )
1001 switch(data->getComponentType())
1004 case 1: // 4:3 SD PAL
1006 case 3: // 16:9 SD PAL
1007 case 4: // > 16:9 PAL
1008 case 5: // 4:3 SD NTSC
1010 case 7: // 16:9 SD NTSC
1011 case 8: // > 16:9 NTSC
1014 case 9: // 4:3 HD PAL
1016 case 0xB: // 16:9 HD PAL
1017 case 0xC: // > 16:9 HD PAL
1018 case 0xD: // 4:3 HD NTSC
1020 case 0xF: // 16:9 HD NTSC
1021 case 0x10: // > 16:9 HD PAL
1022 return data->getComponentType();
1029 case sIsCrypted: return program.isCrypted;
1030 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1031 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1032 case sPCRPID: return program.pcrPid;
1033 case sPMTPID: return program.pmtPid;
1034 case sTXTPID: return program.textPid;
1035 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1036 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1037 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1038 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1039 case sProvider: if (!m_dvb_service) return -1; return -2;
1045 std::string eDVBServicePlay::getInfoString(int w)
1050 if (!m_dvb_service) return "";
1051 return m_dvb_service->m_provider_name;
1057 int eDVBServicePlay::getNumberOfTracks()
1059 eDVBServicePMTHandler::program program;
1060 if (m_service_handler.getProgramInfo(program))
1062 return program.audioStreams.size();
1065 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1067 int ret = selectAudioStream(i);
1069 if (m_decoder->start())
1075 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1077 eDVBServicePMTHandler::program program;
1079 if (m_service_handler.getProgramInfo(program))
1082 if (i >= program.audioStreams.size())
1085 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1086 info.m_description = "MPEG";
1087 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1088 info.m_description = "AC3";
1089 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1090 info.m_description = "DTS";
1092 info.m_description = "???";
1094 if (program.audioStreams[i].component_tag != -1)
1096 ePtr<eServiceEvent> evt;
1097 if (!m_event_handler.getEvent(evt, 0))
1099 ePtr<eComponentData> data;
1100 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1101 info.m_language = data->getText();
1105 if (info.m_language.empty())
1106 info.m_language = program.audioStreams[i].language_code;
1111 int eDVBServicePlay::selectAudioStream(int i)
1113 eDVBServicePMTHandler::program program;
1115 if (m_service_handler.getProgramInfo(program))
1118 if ((unsigned int)i >= program.audioStreams.size())
1124 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1127 if (m_dvb_service && !m_is_pvr)
1129 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1131 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1132 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1135 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1136 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1140 m_current_audio_stream = i;
1145 int eDVBServicePlay::getFrontendInfo(int w)
1149 eUsePtr<iDVBChannel> channel;
1150 if(m_service_handler.getChannel(channel))
1152 ePtr<iDVBFrontend> fe;
1153 if(channel->getFrontend(fe))
1155 return fe->readFrontendData(w);
1158 PyObject *eDVBServicePlay::getFrontendData(bool original)
1162 eUsePtr<iDVBChannel> channel;
1163 if(!m_service_handler.getChannel(channel))
1165 ePtr<iDVBFrontend> fe;
1166 if(!channel->getFrontend(fe))
1168 ret = fe->readTransponderData(original);
1171 ePtr<iDVBFrontendParameters> feparm;
1172 channel->getCurrentFrontendParameters(feparm);
1175 eDVBFrontendParametersSatellite osat;
1176 if (!feparm->getDVBS(osat))
1178 void PutToDict(PyObject *, const char*, long);
1179 void PutToDict(PyObject *, const char*, const char*);
1180 PutToDict(ret, "orbital_position", osat.orbital_position);
1181 const char *tmp = "UNKNOWN";
1182 switch(osat.polarisation)
1184 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1185 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1186 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1187 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1190 PutToDict(ret, "polarization", tmp);
1204 int eDVBServicePlay::getNumberOfSubservices()
1206 ePtr<eServiceEvent> evt;
1207 if (!m_event_handler.getEvent(evt, 0))
1208 return evt->getNumOfLinkageServices();
1212 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1214 ePtr<eServiceEvent> evt;
1215 if (!m_event_handler.getEvent(evt, 0))
1217 if (!evt->getLinkageService(sub, m_reference, n))
1220 sub.type=eServiceReference::idInvalid;
1224 RESULT eDVBServicePlay::startTimeshift()
1226 ePtr<iDVBDemux> demux;
1228 eDebug("Start timeshift!");
1230 if (m_timeshift_enabled)
1233 /* start recording with the data demux. */
1234 if (m_service_handler.getDataDemux(demux))
1237 demux->createTSRecorder(m_record);
1241 char templ[]=TSPATH "/timeshift.XXXXXX";
1242 m_timeshift_fd = mkstemp(templ);
1243 m_timeshift_file = templ;
1245 eDebug("recording to %s", templ);
1247 if (m_timeshift_fd < 0)
1253 m_record->setTargetFD(m_timeshift_fd);
1255 m_timeshift_enabled = 1;
1257 updateTimeshiftPids();
1263 RESULT eDVBServicePlay::stopTimeshift()
1265 if (!m_timeshift_enabled)
1270 m_timeshift_enabled = 0;
1275 close(m_timeshift_fd);
1276 eDebug("remove timeshift file");
1277 remove(m_timeshift_file.c_str());
1282 int eDVBServicePlay::isTimeshiftActive()
1284 return m_timeshift_enabled && m_timeshift_active;
1287 RESULT eDVBServicePlay::activateTimeshift()
1289 if (!m_timeshift_enabled)
1292 if (!m_timeshift_active)
1294 switchToTimeshift();
1301 PyObject *eDVBServicePlay::getCutList()
1303 PyObject *list = PyList_New(0);
1305 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1307 PyObject *tuple = PyTuple_New(2);
1308 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1309 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1310 PyList_Append(list, tuple);
1317 void eDVBServicePlay::setCutList(PyObject *list)
1319 if (!PyList_Check(list))
1321 int size = PyList_Size(list);
1324 m_cue_entries.clear();
1326 for (i=0; i<size; ++i)
1328 PyObject *tuple = PyList_GetItem(list, i);
1329 if (!PyTuple_Check(tuple))
1331 eDebug("non-tuple in cutlist");
1334 if (PyTuple_Size(tuple) != 2)
1336 eDebug("cutlist entries need to be a 2-tuple");
1339 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1340 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1342 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1345 pts_t pts = PyLong_AsLongLong(ppts);
1346 int type = PyInt_AsLong(ptype);
1347 m_cue_entries.insert(cueEntry(pts, type));
1348 eDebug("adding %08llx, %d", pts, type);
1350 m_cuesheet_changed = 1;
1352 cutlistToCuesheet();
1353 m_event((iPlayableService*)this, evCuesheetChanged);
1356 void eDVBServicePlay::setCutListEnable(int enable)
1358 m_cutlist_enabled = enable;
1359 cutlistToCuesheet();
1362 void eDVBServicePlay::updateTimeshiftPids()
1367 eDVBServicePMTHandler::program program;
1368 if (m_service_handler.getProgramInfo(program))
1372 std::set<int> pids_to_record;
1373 pids_to_record.insert(0); // PAT
1374 if (program.pmtPid != -1)
1375 pids_to_record.insert(program.pmtPid); // PMT
1377 if (program.textPid != -1)
1378 pids_to_record.insert(program.textPid); // Videotext
1380 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1381 i(program.videoStreams.begin());
1382 i != program.videoStreams.end(); ++i)
1383 pids_to_record.insert(i->pid);
1385 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1386 i(program.audioStreams.begin());
1387 i != program.audioStreams.end(); ++i)
1388 pids_to_record.insert(i->pid);
1390 std::set<int> new_pids, obsolete_pids;
1392 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1393 m_pids_active.begin(), m_pids_active.end(),
1394 std::inserter(new_pids, new_pids.begin()));
1396 std::set_difference(
1397 m_pids_active.begin(), m_pids_active.end(),
1398 pids_to_record.begin(), pids_to_record.end(),
1399 std::inserter(new_pids, new_pids.begin())
1402 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1403 m_record->addPID(*i);
1405 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1406 m_record->removePID(*i);
1410 void eDVBServicePlay::switchToLive()
1412 if (!m_timeshift_active)
1417 /* free the timeshift service handler, we need the resources */
1418 m_service_handler_timeshift.free();
1419 m_timeshift_active = 0;
1421 m_event((iPlayableService*)this, evSeekableStatusChanged);
1426 void eDVBServicePlay::switchToTimeshift()
1428 if (m_timeshift_active)
1434 m_timeshift_active = 1;
1436 m_event((iPlayableService*)this, evSeekableStatusChanged);
1438 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1439 r.path = m_timeshift_file;
1441 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1442 updateDecoder(); /* mainly to switch off PCR */
1445 void eDVBServicePlay::updateDecoder()
1447 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1448 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1450 eDVBServicePMTHandler::program program;
1451 if (h.getProgramInfo(program))
1452 eDebug("getting program info failed.");
1455 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1456 if (!program.videoStreams.empty())
1458 eDebugNoNewLine(" (");
1459 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1460 i(program.videoStreams.begin());
1461 i != program.videoStreams.end(); ++i)
1465 if (i != program.videoStreams.begin())
1466 eDebugNoNewLine(", ");
1467 eDebugNoNewLine("%04x", i->pid);
1469 eDebugNoNewLine(")");
1471 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1472 if (!program.audioStreams.empty())
1474 eDebugNoNewLine(" (");
1475 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1476 i(program.audioStreams.begin());
1477 i != program.audioStreams.end(); ++i)
1484 if (i != program.audioStreams.begin())
1485 eDebugNoNewLine(", ");
1486 eDebugNoNewLine("%04x", i->pid);
1488 eDebugNoNewLine(")");
1490 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1491 pcrpid = program.pcrPid;
1492 eDebug(", and the text pid is %04x", program.textPid);
1493 tpid = program.textPid;
1498 h.getDecodeDemux(m_decode_demux);
1500 m_decode_demux->getMPEGDecoder(m_decoder);
1502 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1507 m_decoder->setVideoPID(vpid);
1508 m_current_audio_stream = 0;
1509 m_decoder->setAudioPID(apid, apidtype);
1510 if (!(m_is_pvr || m_timeshift_active))
1511 m_decoder->setSyncPCR(pcrpid);
1513 m_decoder->setSyncPCR(-1);
1514 m_decoder->setTextPID(tpid);
1516 // how we can do this better?
1517 // update cache pid when the user changed the audio track or video track
1518 // TODO handling of difference audio types.. default audio types..
1520 /* don't worry about non-existing services, nor pvr services */
1521 if (m_dvb_service && !m_is_pvr)
1523 if (apidtype == eDVBAudio::aMPEG)
1525 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1526 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1530 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1531 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1533 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1534 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1535 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1540 void eDVBServicePlay::loadCuesheet()
1542 std::string filename = m_reference.path + ".cuts";
1544 m_cue_entries.clear();
1546 FILE *f = fopen(filename.c_str(), "rb");
1550 eDebug("loading cuts..");
1553 unsigned long long where;
1556 if (!fread(&where, sizeof(where), 1, f))
1558 if (!fread(&what, sizeof(what), 1, f))
1561 #if BYTE_ORDER == LITTLE_ENDIAN
1562 where = bswap_64(where);
1569 m_cue_entries.insert(cueEntry(where, what));
1572 eDebug("%d entries", m_cue_entries.size());
1574 eDebug("cutfile not found!");
1576 m_cuesheet_changed = 0;
1577 cutlistToCuesheet();
1578 m_event((iPlayableService*)this, evCuesheetChanged);
1581 void eDVBServicePlay::saveCuesheet()
1583 std::string filename = m_reference.path + ".cuts";
1585 FILE *f = fopen(filename.c_str(), "wb");
1589 unsigned long long where;
1592 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1594 #if BYTE_ORDER == BIG_ENDIAN
1597 where = bswap_64(i->where);
1599 what = htonl(i->what);
1600 fwrite(&where, sizeof(where), 1, f);
1601 fwrite(&what, sizeof(what), 1, f);
1607 m_cuesheet_changed = 0;
1610 void eDVBServicePlay::cutlistToCuesheet()
1614 eDebug("no cue sheet");
1619 if (!m_cutlist_enabled)
1621 m_cue->commitSpans();
1622 eDebug("cutlists where disabled");
1626 pts_t in = 0, out = 0, length = 0;
1630 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1634 if (i == m_cue_entries.end())
1637 if (i->what == 0) /* in */
1641 } else if (i->what == 1) /* out */
1651 m_cue->addSourceSpan(in, out);
1655 if (i == m_cue_entries.end())
1658 m_cue->commitSpans();
1661 DEFINE_REF(eDVBServicePlay)
1663 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");