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/dvb/metaparser.h>
15 #include <lib/dvb/tstools.h>
16 #include <lib/python/python.h>
21 #include <netinet/in.h>
24 #error no byte order defined!
27 #define TSPATH "/media/hdd"
29 class eStaticServiceDVBInformation: public iStaticServiceInformation
31 DECLARE_REF(eStaticServiceDVBInformation);
33 RESULT getName(const eServiceReference &ref, std::string &name);
34 int getLength(const eServiceReference &ref);
37 DEFINE_REF(eStaticServiceDVBInformation);
39 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
41 eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
42 if ( !ref.name.empty() )
44 if (service.getParentTransportStreamID().get()) // linkage subservice
46 ePtr<iServiceHandler> service_center;
47 if (!eServiceCenter::getInstance(service_center))
49 eServiceReferenceDVB parent = service;
50 parent.setTransportStreamID( service.getParentTransportStreamID() );
51 parent.setServiceID( service.getParentServiceID() );
52 parent.setParentTransportStreamID(eTransportStreamID(0));
53 parent.setParentServiceID(eServiceID(0));
55 ePtr<iStaticServiceInformation> service_info;
56 if (!service_center->info(parent, service_info))
58 if (!service_info->getName(parent, name))
60 // just show short name
61 unsigned int pos = name.find("\xc2\x86");
62 if ( pos != std::string::npos )
64 pos = name.find("\xc2\x87");
65 if ( pos != std::string::npos )
81 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
86 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
88 DECLARE_REF(eStaticServiceDVBBouquetInformation);
90 RESULT getName(const eServiceReference &ref, std::string &name);
91 int getLength(const eServiceReference &ref);
94 DEFINE_REF(eStaticServiceDVBBouquetInformation);
96 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
98 ePtr<iDVBChannelList> db;
99 ePtr<eDVBResourceManager> res;
102 if ((err = eDVBResourceManager::getInstance(res)) != 0)
104 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
107 if ((err = res->getChannelList(db)) != 0)
109 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
114 if ((err = db->getBouquet(ref, bouquet)) != 0)
116 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
120 if ( bouquet && bouquet->m_bouquet_name.length() )
122 name = bouquet->m_bouquet_name;
129 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
134 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
136 DECLARE_REF(eStaticServiceDVBPVRInformation);
137 eServiceReference m_ref;
138 eDVBMetaParser m_parser;
140 eStaticServiceDVBPVRInformation(const eServiceReference &ref);
141 RESULT getName(const eServiceReference &ref, std::string &name);
142 int getLength(const eServiceReference &ref);
144 int getInfo(const eServiceReference &ref, int w);
145 std::string getInfoString(const eServiceReference &ref,int w);
148 DEFINE_REF(eStaticServiceDVBPVRInformation);
150 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
153 m_parser.parseFile(ref.path);
156 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
158 ASSERT(ref == m_ref);
159 name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
163 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
165 ASSERT(ref == m_ref);
169 if (tstools.openFile(ref.path.c_str()))
173 if (tstools.calcLen(len))
179 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
183 case iServiceInformation::sDescription:
184 return iServiceInformation::resIsString;
185 case iServiceInformation::sTimeCreate:
186 if (m_parser.m_time_create)
187 return m_parser.m_time_create;
189 return iServiceInformation::resNA;
191 return iServiceInformation::resNA;
195 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
199 case iServiceInformation::sDescription:
200 return m_parser.m_description;
206 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
208 DECLARE_REF(eDVBPVRServiceOfflineOperations);
209 eServiceReferenceDVB m_ref;
211 eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
213 RESULT deleteFromDisk(int simulate);
214 RESULT getListOfFilenames(std::list<std::string> &);
217 DEFINE_REF(eDVBPVRServiceOfflineOperations);
219 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
223 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
229 std::list<std::string> res;
230 if (getListOfFilenames(res))
233 /* TODO: deferred removing.. */
234 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
236 eDebug("Removing %s...", i->c_str());
237 ::unlink(i->c_str());
244 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
247 res.push_back(m_ref.path);
248 res.push_back(m_ref.path + ".meta");
252 DEFINE_REF(eServiceFactoryDVB)
254 eServiceFactoryDVB::eServiceFactoryDVB()
256 ePtr<eServiceCenter> sc;
258 eServiceCenter::getPrivInstance(sc);
260 sc->addServiceFactory(eServiceFactoryDVB::id, this);
263 eServiceFactoryDVB::~eServiceFactoryDVB()
265 ePtr<eServiceCenter> sc;
267 eServiceCenter::getPrivInstance(sc);
269 sc->removeServiceFactory(eServiceFactoryDVB::id);
272 DEFINE_REF(eDVBServiceList);
274 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
278 eDVBServiceList::~eDVBServiceList()
282 RESULT eDVBServiceList::startQuery()
284 ePtr<iDVBChannelList> db;
285 ePtr<eDVBResourceManager> res;
288 if ((err = eDVBResourceManager::getInstance(res)) != 0)
290 eDebug("no resource manager");
293 if ((err = res->getChannelList(db)) != 0)
295 eDebug("no channel list");
299 ePtr<eDVBChannelQuery> q;
301 if (!m_parent.path.empty())
303 eDVBChannelQuery::compile(q, m_parent.path);
306 eDebug("compile query failed");
311 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
313 eDebug("startQuery failed");
320 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
322 eServiceReferenceDVB ref;
324 if (!m_query || !list || !PyList_Check(list))
327 std::list<eServiceReferenceDVB> tmplist;
329 while (!m_query->getNextResult(ref))
330 tmplist.push_back(ref);
333 tmplist.sort(iListableServiceCompare(this));
335 for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
336 it != tmplist.end(); ++it)
338 PyObject *refobj = New_eServiceReference(*it);
339 PyList_Append(list, refobj);
345 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
347 eServiceReferenceDVB ref;
352 while (!m_query->getNextResult(ref))
356 list.sort(iListableServiceCompare(this));
361 RESULT eDVBServiceList::getNext(eServiceReference &ref)
366 return m_query->getNextResult((eServiceReferenceDVB&)ref);
369 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
371 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
374 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
376 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
378 ePtr<iDVBChannelList> db;
379 ePtr<eDVBResourceManager> resm;
381 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
384 if (db->getBouquet(m_parent, m_bouquet) != 0)
395 RESULT eDVBServiceList::addService(eServiceReference &ref)
399 return m_bouquet->addService(ref);
402 RESULT eDVBServiceList::removeService(eServiceReference &ref)
406 return m_bouquet->removeService(ref);
409 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
413 return m_bouquet->moveService(ref, pos);
416 RESULT eDVBServiceList::flushChanges()
420 return m_bouquet->flushChanges();
423 RESULT eDVBServiceList::setListName(const std::string &name)
427 return m_bouquet->setListName(name);
430 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
432 ePtr<eDVBService> service;
433 int r = lookupService(service, ref);
436 // check resources...
437 ptr = new eDVBServicePlay(ref, service);
441 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
443 if (ref.path.empty())
445 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
454 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
456 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
457 if (list->startQuery())
467 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
469 /* is a listable service? */
470 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
472 if ( !ref.name.empty() ) // satellites or providers list
473 ptr = new eStaticServiceDVBInformation;
474 else // a dvb bouquet
475 ptr = new eStaticServiceDVBBouquetInformation;
477 else if (!ref.path.empty()) /* do we have a PVR service? */
478 ptr = new eStaticServiceDVBPVRInformation(ref);
479 else // normal dvb service
481 ePtr<eDVBService> service;
482 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
483 ptr = new eStaticServiceDVBInformation;
485 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
491 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
493 if (ref.path.empty())
499 ptr = new eDVBPVRServiceOfflineOperations(ref);
504 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
506 // TODO: handle the listing itself
507 // if (ref.... == -1) .. return "... bouquets ...";
508 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
510 ePtr<iDVBChannelList> db;
511 ePtr<eDVBResourceManager> res;
514 if ((err = eDVBResourceManager::getInstance(res)) != 0)
516 eDebug("no resource manager");
519 if ((err = res->getChannelList(db)) != 0)
521 eDebug("no channel list");
525 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
526 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
528 eDebug("getService failed!");
535 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
536 m_reference(ref), m_dvb_service(service), m_is_paused(0)
538 m_is_pvr = !ref.path.empty();
540 m_timeshift_enabled = m_timeshift_active = 0;
543 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
544 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
545 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
547 m_cuesheet_changed = 0;
553 eDVBServicePlay::~eDVBServicePlay()
557 void eDVBServicePlay::gotNewEvent()
561 ePtr<eServiceEvent> m_event_now, m_event_next;
562 getEvent(m_event_now, 0);
563 getEvent(m_event_next, 1);
566 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
568 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
570 m_event((iPlayableService*)this, evUpdatedEventInfo);
573 void eDVBServicePlay::serviceEvent(int event)
577 case eDVBServicePMTHandler::eventTuned:
579 ePtr<iDVBDemux> m_demux;
580 if (!m_service_handler.getDataDemux(m_demux))
582 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
583 int sid = ref.getParentServiceID().get();
585 sid = ref.getServiceID().get();
586 if ( ref.getParentTransportStreamID().get() &&
587 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
588 m_event_handler.startOther(m_demux, sid);
590 m_event_handler.start(m_demux, sid);
594 case eDVBServicePMTHandler::eventTuneFailed:
596 eDebug("DVB service failed to tune");
597 m_event((iPlayableService*)this, evTuneFailed);
600 case eDVBServicePMTHandler::eventNewProgramInfo:
602 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
603 if (m_timeshift_enabled)
604 updateTimeshiftPids();
605 if (!m_timeshift_active)
607 m_event((iPlayableService*)this, evUpdatedInfo);
610 case eDVBServicePMTHandler::eventEOF:
611 m_event((iPlayableService*)this, evEOF);
613 case eDVBServicePMTHandler::eventSOF:
614 m_event((iPlayableService*)this, evSOF);
619 void eDVBServicePlay::serviceEventTimeshift(int event)
623 case eDVBServicePMTHandler::eventNewProgramInfo:
624 if (m_timeshift_active)
627 case eDVBServicePMTHandler::eventEOF:
633 RESULT eDVBServicePlay::start()
636 /* in pvr mode, we only want to use one demux. in tv mode, we're using
637 two (one for decoding, one for data source), as we must be prepared
638 to start recording from the data demux. */
639 m_cue = new eCueSheet();
640 r = m_service_handler.tune((eServiceReferenceDVB&)m_reference, m_is_pvr, m_cue);
641 m_event(this, evStart);
642 m_event((iPlayableService*)this, evSeekableStatusChanged);
646 RESULT eDVBServicePlay::stop()
648 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
650 m_service_handler_timeshift.free();
651 m_service_handler.free();
653 if (m_is_pvr && m_cuesheet_changed)
659 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
661 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
665 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
667 /* note: we check for timeshift to be enabled,
668 not neccessary active. if you pause when timeshift
669 is not active, you should activate it when unpausing */
670 if ((!m_is_pvr) && (!m_timeshift_enabled))
680 RESULT eDVBServicePlay::setSlowMotion(int ratio)
683 return m_decoder->setSlowMotion(ratio);
688 RESULT eDVBServicePlay::setFastForward(int ratio)
690 int skipmode, ffratio;
696 } else if (ratio > 0)
704 } else // if (ratio < 0)
710 if (m_skipmode != skipmode)
712 eDebug("setting cue skipmode to %d", skipmode);
714 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
717 m_skipmode = skipmode;
722 return m_decoder->setFastForward(ffratio);
725 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
727 if (m_is_pvr || m_timeshift_enabled)
737 /* TODO: when timeshift is enabled but not active, this doesn't work. */
738 RESULT eDVBServicePlay::getLength(pts_t &len)
740 ePtr<iDVBPVRChannel> pvr_channel;
742 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
745 return pvr_channel->getLength(len);
748 RESULT eDVBServicePlay::pause()
750 if (!m_is_paused && m_decoder)
753 return m_decoder->freeze(0);
758 RESULT eDVBServicePlay::unpause()
760 if (m_is_paused && m_decoder)
763 return m_decoder->unfreeze();
768 RESULT eDVBServicePlay::seekTo(pts_t to)
770 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
775 ePtr<iDVBPVRChannel> pvr_channel;
777 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
783 m_cue->seekTo(0, to);
787 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
789 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
794 ePtr<iDVBPVRChannel> pvr_channel;
796 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
804 m_cue->seekTo(1, to);
808 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
810 ePtr<iDVBPVRChannel> pvr_channel;
815 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
818 return pvr_channel->getCurrentPosition(m_decode_demux, pos, 1);
821 RESULT eDVBServicePlay::setTrickmode(int trick)
824 m_decoder->setTrickmode(trick);
828 RESULT eDVBServicePlay::isCurrentlySeekable()
830 return m_is_pvr || m_timeshift_active;
833 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
839 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
845 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
851 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
857 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
860 if (m_timeshift_enabled || !m_is_pvr)
862 if (!m_timeshift_enabled)
864 /* we need enough diskspace */
866 if (statfs(TSPATH "/.", &fs) < 0)
868 eDebug("statfs failed!");
872 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
874 eDebug("not enough diskspace for timeshift! (less than 1GB)");
884 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
895 RESULT eDVBServicePlay::getName(std::string &name)
899 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
900 return i->getName(m_reference, name);
904 m_dvb_service->getName(m_reference, name);
908 else if (!m_reference.name.empty())
909 eStaticServiceDVBInformation().getName(m_reference, name);
911 name = "DVB service";
915 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
917 return m_event_handler.getEvent(evt, nownext);
920 int eDVBServicePlay::getInfo(int w)
922 eDVBServicePMTHandler::program program;
924 if (m_service_handler.getProgramInfo(program))
930 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
932 ePtr<eServiceEvent> evt;
933 if (!m_event_handler.getEvent(evt, 0))
935 ePtr<eComponentData> data;
936 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
938 if ( data->getStreamContent() == 1 )
940 switch(data->getComponentType())
943 case 1: // 4:3 SD PAL
945 case 3: // 16:9 SD PAL
946 case 4: // > 16:9 PAL
947 case 5: // 4:3 SD NTSC
949 case 7: // 16:9 SD NTSC
950 case 8: // > 16:9 NTSC
953 case 9: // 4:3 HD PAL
955 case 0xB: // 16:9 HD PAL
956 case 0xC: // > 16:9 HD PAL
957 case 0xD: // 4:3 HD NTSC
959 case 0xF: // 16:9 HD NTSC
960 case 0x10: // > 16:9 HD PAL
961 return data->getComponentType();
968 case sIsCrypted: return program.isCrypted;
969 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
970 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
971 case sPCRPID: return program.pcrPid;
972 case sPMTPID: return program.pmtPid;
973 case sTXTPID: return program.textPid;
974 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
975 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
976 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
977 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
978 case sProvider: if (!m_dvb_service) return -1; return -2;
984 std::string eDVBServicePlay::getInfoString(int w)
989 if (!m_dvb_service) return "";
990 return m_dvb_service->m_provider_name;
996 int eDVBServicePlay::getNumberOfTracks()
998 eDVBServicePMTHandler::program program;
999 if (m_service_handler.getProgramInfo(program))
1001 return program.audioStreams.size();
1004 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1006 int ret = selectAudioStream(i);
1008 if (m_decoder->start())
1014 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1016 eDVBServicePMTHandler::program program;
1018 if (m_service_handler.getProgramInfo(program))
1021 if (i >= program.audioStreams.size())
1024 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1025 info.m_description = "MPEG";
1026 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1027 info.m_description = "AC3";
1028 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1029 info.m_description = "DTS";
1031 info.m_description = "???";
1033 if (program.audioStreams[i].component_tag != -1)
1035 ePtr<eServiceEvent> evt;
1036 if (!m_event_handler.getEvent(evt, 0))
1038 ePtr<eComponentData> data;
1039 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1040 info.m_language = data->getText();
1044 if (info.m_language.empty())
1045 info.m_language = program.audioStreams[i].language_code;
1050 int eDVBServicePlay::selectAudioStream(int i)
1052 eDVBServicePMTHandler::program program;
1054 if (m_service_handler.getProgramInfo(program))
1057 if ((unsigned int)i >= program.audioStreams.size())
1063 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1066 if (m_dvb_service && !m_is_pvr)
1068 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1070 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1071 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1074 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1075 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1079 m_current_audio_stream = i;
1084 int eDVBServicePlay::getFrontendInfo(int w)
1088 eUsePtr<iDVBChannel> channel;
1089 if(m_service_handler.getChannel(channel))
1091 ePtr<iDVBFrontend> fe;
1092 if(channel->getFrontend(fe))
1094 return fe->readFrontendData(w);
1097 int eDVBServicePlay::getNumberOfSubservices()
1099 ePtr<eServiceEvent> evt;
1100 if (!m_event_handler.getEvent(evt, 0))
1101 return evt->getNumOfLinkageServices();
1105 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1107 ePtr<eServiceEvent> evt;
1108 if (!m_event_handler.getEvent(evt, 0))
1110 if (!evt->getLinkageService(sub, m_reference, n))
1113 sub.type=eServiceReference::idInvalid;
1117 RESULT eDVBServicePlay::startTimeshift()
1119 ePtr<iDVBDemux> demux;
1121 eDebug("Start timeshift!");
1123 if (m_timeshift_enabled)
1126 /* start recording with the data demux. */
1127 if (m_service_handler.getDataDemux(demux))
1130 demux->createTSRecorder(m_record);
1134 char templ[]=TSPATH "/timeshift.XXXXXX";
1135 m_timeshift_fd = mkstemp(templ);
1136 m_timeshift_file = templ;
1138 eDebug("recording to %s", templ);
1140 if (m_timeshift_fd < 0)
1146 m_record->setTargetFD(m_timeshift_fd);
1148 m_timeshift_enabled = 1;
1150 updateTimeshiftPids();
1156 RESULT eDVBServicePlay::stopTimeshift()
1158 if (!m_timeshift_enabled)
1163 m_timeshift_enabled = 0;
1168 close(m_timeshift_fd);
1169 eDebug("remove timeshift file");
1170 remove(m_timeshift_file.c_str());
1175 int eDVBServicePlay::isTimeshiftActive()
1177 return m_timeshift_enabled && m_timeshift_active;
1180 RESULT eDVBServicePlay::activateTimeshift()
1182 if (!m_timeshift_enabled)
1185 if (!m_timeshift_active)
1187 switchToTimeshift();
1194 PyObject *eDVBServicePlay::getCutList()
1196 PyObject *list = PyList_New(0);
1198 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1200 PyObject *tuple = PyTuple_New(2);
1201 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1202 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1203 PyList_Append(list, tuple);
1210 void eDVBServicePlay::setCutList(PyObject *list)
1212 if (!PyList_Check(list))
1214 int size = PyList_Size(list);
1217 m_cue_entries.clear();
1219 for (i=0; i<size; ++i)
1221 PyObject *tuple = PyList_GetItem(list, i);
1222 if (!PyTuple_Check(tuple))
1224 eDebug("non-tuple in cutlist");
1227 if (PyTuple_Size(tuple) != 2)
1229 eDebug("cutlist entries need to be a 2-tuple");
1232 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1233 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1235 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1238 pts_t pts = PyLong_AsLongLong(ppts);
1239 int type = PyInt_AsLong(ptype);
1240 m_cue_entries.insert(cueEntry(pts, type));
1241 eDebug("adding %08llx, %d", pts, type);
1243 m_cuesheet_changed = 1;
1246 void eDVBServicePlay::updateTimeshiftPids()
1251 eDVBServicePMTHandler::program program;
1252 if (m_service_handler.getProgramInfo(program))
1256 std::set<int> pids_to_record;
1257 pids_to_record.insert(0); // PAT
1258 if (program.pmtPid != -1)
1259 pids_to_record.insert(program.pmtPid); // PMT
1261 if (program.textPid != -1)
1262 pids_to_record.insert(program.textPid); // Videotext
1264 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1265 i(program.videoStreams.begin());
1266 i != program.videoStreams.end(); ++i)
1267 pids_to_record.insert(i->pid);
1269 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1270 i(program.audioStreams.begin());
1271 i != program.audioStreams.end(); ++i)
1272 pids_to_record.insert(i->pid);
1274 std::set<int> new_pids, obsolete_pids;
1276 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1277 m_pids_active.begin(), m_pids_active.end(),
1278 std::inserter(new_pids, new_pids.begin()));
1280 std::set_difference(
1281 m_pids_active.begin(), m_pids_active.end(),
1282 pids_to_record.begin(), pids_to_record.end(),
1283 std::inserter(new_pids, new_pids.begin())
1286 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1287 m_record->addPID(*i);
1289 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1290 m_record->removePID(*i);
1294 void eDVBServicePlay::switchToLive()
1296 if (!m_timeshift_active)
1301 /* free the timeshift service handler, we need the resources */
1302 m_service_handler_timeshift.free();
1303 m_timeshift_active = 0;
1305 m_event((iPlayableService*)this, evSeekableStatusChanged);
1310 void eDVBServicePlay::switchToTimeshift()
1312 if (m_timeshift_active)
1318 m_timeshift_active = 1;
1320 m_event((iPlayableService*)this, evSeekableStatusChanged);
1322 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1323 r.path = m_timeshift_file;
1325 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1328 void eDVBServicePlay::updateDecoder()
1330 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1331 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1333 eDVBServicePMTHandler::program program;
1334 if (h.getProgramInfo(program))
1335 eDebug("getting program info failed.");
1338 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1339 if (!program.videoStreams.empty())
1341 eDebugNoNewLine(" (");
1342 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1343 i(program.videoStreams.begin());
1344 i != program.videoStreams.end(); ++i)
1348 if (i != program.videoStreams.begin())
1349 eDebugNoNewLine(", ");
1350 eDebugNoNewLine("%04x", i->pid);
1352 eDebugNoNewLine(")");
1354 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1355 if (!program.audioStreams.empty())
1357 eDebugNoNewLine(" (");
1358 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1359 i(program.audioStreams.begin());
1360 i != program.audioStreams.end(); ++i)
1367 if (i != program.audioStreams.begin())
1368 eDebugNoNewLine(", ");
1369 eDebugNoNewLine("%04x", i->pid);
1371 eDebugNoNewLine(")");
1373 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1374 pcrpid = program.pcrPid;
1375 eDebug(", and the text pid is %04x", program.textPid);
1376 tpid = program.textPid;
1381 h.getDecodeDemux(m_decode_demux);
1383 m_decode_demux->getMPEGDecoder(m_decoder);
1385 m_cue->setDecodingDemux(m_decode_demux);
1390 m_decoder->setVideoPID(vpid);
1391 m_current_audio_stream = 0;
1392 m_decoder->setAudioPID(apid, apidtype);
1393 if (!(m_is_pvr || m_timeshift_active))
1394 m_decoder->setSyncPCR(pcrpid);
1396 m_decoder->setSyncPCR(-1);
1397 m_decoder->setTextPID(tpid);
1399 // how we can do this better?
1400 // update cache pid when the user changed the audio track or video track
1401 // TODO handling of difference audio types.. default audio types..
1403 /* don't worry about non-existing services, nor pvr services */
1404 if (m_dvb_service && !m_is_pvr)
1406 if (apidtype == eDVBAudio::aMPEG)
1408 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1409 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1413 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1414 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1416 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1417 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1418 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1423 void eDVBServicePlay::loadCuesheet()
1425 std::string filename = m_reference.path + ".cuts";
1427 m_cue_entries.clear();
1429 FILE *f = fopen(filename.c_str(), "rb");
1433 eDebug("loading cuts..");
1436 unsigned long long where;
1439 if (!fread(&where, sizeof(where), 1, f))
1441 if (!fread(&what, sizeof(what), 1, f))
1444 #if BYTE_ORDER == LITTLE_ENDIAN
1445 where = bswap_64(where);
1452 m_cue_entries.insert(cueEntry(where, what));
1455 eDebug("%d entries", m_cue_entries.size());
1457 eDebug("cutfile not found!");
1459 m_cuesheet_changed = 0;
1462 void eDVBServicePlay::saveCuesheet()
1464 std::string filename = m_reference.path + ".cuts";
1466 FILE *f = fopen(filename.c_str(), "wb");
1470 unsigned long long where;
1473 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1475 #if BYTE_ORDER == BIG_ENDIAN
1478 where = bswap_64(i->where);
1480 what = htonl(i->what);
1481 fwrite(&where, sizeof(where), 1, f);
1482 fwrite(&what, sizeof(what), 1, f);
1488 m_cuesheet_changed = 0;
1491 DEFINE_REF(eDVBServicePlay)
1493 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");