X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/1d7e5720b3e8653604323b981e37af1f6aa61709..d2ceae9583bc62daa872c316f8952b9a6a416a69:/lib/service/servicedvb.cpp diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp index 2fb051c1..d8206b9a 100644 --- a/lib/service/servicedvb.cpp +++ b/lib/service/servicedvb.cpp @@ -10,6 +10,172 @@ #include #include +#include +#include + +class eStaticServiceDVBInformation: public iStaticServiceInformation +{ + DECLARE_REF(eStaticServiceDVBInformation); +public: + RESULT getName(const eServiceReference &ref, std::string &name); + int getLength(const eServiceReference &ref); +}; + +DEFINE_REF(eStaticServiceDVBInformation); + +RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name) +{ + if ( ref.name.length() ) + { + name = ref.name; + return 0; + } + else + return -1; +} + +int eStaticServiceDVBInformation::getLength(const eServiceReference &ref) +{ + return -1; +} + +class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation +{ + DECLARE_REF(eStaticServiceDVBBouquetInformation); +public: + RESULT getName(const eServiceReference &ref, std::string &name); + int getLength(const eServiceReference &ref); +}; + +DEFINE_REF(eStaticServiceDVBBouquetInformation); + +RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name) +{ + ePtr db; + ePtr res; + + int err; + if ((err = eDVBResourceManager::getInstance(res)) != 0) + { + eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!"); + return err; + } + if ((err = res->getChannelList(db)) != 0) + { + eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!"); + return err; + } + + eBouquet *bouquet=0; + if ((err = db->getBouquet(ref, bouquet)) != 0) + { + eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!"); + return -1; + } + + if ( bouquet && bouquet->m_bouquet_name.length() ) + { + name = "[Bouquet] " + bouquet->m_bouquet_name; + return 0; + } + else + return -1; +} + +int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref) +{ + return -1; +} + +class eStaticServiceDVBPVRInformation: public iStaticServiceInformation +{ + DECLARE_REF(eStaticServiceDVBPVRInformation); + eServiceReference m_ref; + eDVBMetaParser m_parser; +public: + eStaticServiceDVBPVRInformation(const eServiceReference &ref); + RESULT getName(const eServiceReference &ref, std::string &name); + int getLength(const eServiceReference &ref); +}; + +DEFINE_REF(eStaticServiceDVBPVRInformation); + +eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref) +{ + m_ref = ref; + m_parser.parseFile(ref.path); +} + +RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name) +{ + ASSERT(ref == m_ref); + name = m_parser.m_name.size() ? m_parser.m_name : ref.path; + return 0; +} + +int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref) +{ + ASSERT(ref == m_ref); + + eDVBTSTools tstools; + + if (tstools.openFile(ref.path.c_str())) + return 0; + + pts_t len; + if (tstools.calcLen(len)) + return 0; + + return len / 90000; +} + + + +class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations +{ + DECLARE_REF(eDVBPVRServiceOfflineOperations); + eServiceReferenceDVB m_ref; +public: + eDVBPVRServiceOfflineOperations(const eServiceReference &ref); + + RESULT deleteFromDisk(int simulate); + RESULT getListOfFilenames(std::list &); +}; + +DEFINE_REF(eDVBPVRServiceOfflineOperations); + +eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref) +{ +} + +RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate) +{ + if (simulate) + return 0; + else + { + std::list res; + if (getListOfFilenames(res)) + return -1; + + /* TODO: deferred removing.. */ + for (std::list::iterator i(res.begin()); i != res.end(); ++i) + { + eDebug("Removing %s...", i->c_str()); + ::unlink(i->c_str()); + } + + return 0; + } +} + +RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list &res) +{ + res.clear(); + res.push_back(m_ref.path); + res.push_back(m_ref.path + ".meta"); + return 0; +} DEFINE_REF(eServiceFactoryDVB) @@ -17,7 +183,7 @@ eServiceFactoryDVB::eServiceFactoryDVB() { ePtr sc; - eServiceCenter::getInstance(sc); + eServiceCenter::getPrivInstance(sc); if (sc) sc->addServiceFactory(eServiceFactoryDVB::id, this); } @@ -26,7 +192,7 @@ eServiceFactoryDVB::~eServiceFactoryDVB() { ePtr sc; - eServiceCenter::getInstance(sc); + eServiceCenter::getPrivInstance(sc); if (sc) sc->removeServiceFactory(eServiceFactoryDVB::id); } @@ -41,7 +207,7 @@ eDVBServiceList::~eDVBServiceList() { } -RESULT eDVBServiceList::getContent(std::list &list) +RESULT eDVBServiceList::startQuery() { ePtr db; ePtr res; @@ -58,48 +224,179 @@ RESULT eDVBServiceList::getContent(std::list &list) return err; } - ePtr query; - ePtr q; - if (m_parent.path.size()) + if (!m_parent.path.empty()) + { eDVBChannelQuery::compile(q, m_parent.path); + if (!q) + { + eDebug("compile query failed"); + return err; + } + } - if ((err = db->startQuery(query, q)) != 0) + if ((err = db->startQuery(m_query, q, m_parent)) != 0) { eDebug("startQuery failed"); return err; } - + + return 0; +} + +RESULT eDVBServiceList::getContent(std::list &list) +{ eServiceReferenceDVB ref; - while (!query->getNextResult(ref)) + if (!m_query) + return -1; + + while (!m_query->getNextResult(ref)) list.push_back(ref); return 0; } +RESULT eDVBServiceList::getNext(eServiceReference &ref) +{ + if (!m_query) + return -1; + + return m_query->getNextResult((eServiceReferenceDVB&)ref); +} + +int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b) +{ + return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b); +} + +RESULT eDVBServiceList::startEdit(ePtr &res) +{ + if (m_parent.flags & eServiceReference::flagDirectory) // bouquet + { + ePtr db; + ePtr resm; + + if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db)) + return -1; + + if (db->getBouquet(m_parent, m_bouquet) != 0) + return -1; + + res = this; + + return 0; + } + res = 0; + return -1; +} + +RESULT eDVBServiceList::addService(eServiceReference &ref) +{ + if (!m_bouquet) + return -1; + return m_bouquet->addService(ref); +} + +RESULT eDVBServiceList::removeService(eServiceReference &ref) +{ + if (!m_bouquet) + return -1; + return m_bouquet->removeService(ref); +} + +RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos) +{ + if (!m_bouquet) + return -1; + return m_bouquet->moveService(ref, pos); +} + +RESULT eDVBServiceList::flushChanges() +{ + if (!m_bouquet) + return -1; + return m_bouquet->flushChanges(); +} + RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr &ptr) { + ePtr service; + int r = lookupService(service, ref); + if (r) + service = 0; // check resources... - ptr = new eDVBServicePlay(ref); + ptr = new eDVBServicePlay(ref, service); return 0; } RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr &ptr) { - ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref); - return 0; + if (ref.path.empty()) + { + ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref); + return 0; + } else + { + ptr = 0; + return -1; + } } RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr &ptr) { - ptr = new eDVBServiceList(ref); + ePtr list = new eDVBServiceList(ref); + if (list->startQuery()) + { + ptr = 0; + return -1; + } + + ptr = list; return 0; } RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr &ptr) { - ptr = 0; + /* do we have a PVR service? */ + if (ref.flags & eServiceReference::flagDirectory) // bouquet + { + ptr = new eStaticServiceDVBBouquetInformation; + return 0; + } + else if (!ref.path.empty()) + { + ptr = new eStaticServiceDVBPVRInformation(ref); + return 0; + } + else + { + ePtr service; + int r = lookupService(service, ref); + if (r) + ptr = new eStaticServiceDVBInformation; + else + /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */ + ptr = service; + return 0; + } +} + +RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr &ptr) +{ + if (ref.path.empty()) + { + ptr = 0; + return -1; + } else + { + ptr = new eDVBPVRServiceOfflineOperations(ref); + return 0; + } +} + +RESULT eServiceFactoryDVB::lookupService(ePtr &service, const eServiceReference &ref) +{ // TODO: handle the listing itself // if (ref.... == -1) .. return "... bouquets ..."; // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists @@ -119,31 +416,27 @@ RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr service; - /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */ if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0) { eDebug("getService failed!"); return err; } - - /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */ - ptr = service; + return 0; } -eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref): - m_reference(ref) +eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): + m_reference(ref), m_dvb_service(service), m_service_handler(0), m_is_paused(0) { + m_is_pvr = !ref.path.empty(); + CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent); CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent); - eDebug("DVB start (play)"); } eDVBServicePlay::~eDVBServicePlay() { - eDebug("DVB stop (play)"); } void eDVBServicePlay::gotNewEvent() @@ -164,7 +457,6 @@ void eDVBServicePlay::gotNewEvent() void eDVBServicePlay::serviceEvent(int event) { - eDebug("service event %d", event); switch (event) { case eDVBServicePMTHandler::eventTuned: @@ -174,14 +466,19 @@ void eDVBServicePlay::serviceEvent(int event) { // eventStartedEventAcquisition m_event_handler.start(m_demux, ((eServiceReferenceDVB&)m_reference).getServiceID().get()); - } else - eDebug("no event data available :( "); + } // eventNoEvent break; } + case eDVBServicePMTHandler::eventTuneFailed: + { + eDebug("DVB service failed to tune"); + m_event((iPlayableService*)this, evTuneFailed); + break; + } case eDVBServicePMTHandler::eventNewProgramInfo: { - int vpid = -1, apid = -1, pcrpid = -1; + int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1; eDVBServicePMTHandler::program program; if (m_service_handler.getProgramInfo(program)) eDebug("getting program info failed."); @@ -212,7 +509,10 @@ void eDVBServicePlay::serviceEvent(int event) i != program.audioStreams.end(); ++i) { if (apid == -1) + { apid = i->pid; + apidtype = i->type; + } if (i != program.audioStreams.begin()) eDebugNoNewLine(", "); eDebugNoNewLine("%04x", i->pid); @@ -235,9 +535,23 @@ void eDVBServicePlay::serviceEvent(int event) if (m_decoder) { m_decoder->setVideoPID(vpid); - m_decoder->setAudioPID(apid, 0); - m_decoder->setSyncPCR(pcrpid); + m_decoder->setAudioPID(apid, apidtype); + if (!m_is_pvr) + m_decoder->setSyncPCR(pcrpid); + else + m_decoder->setSyncPCR(-1); m_decoder->start(); +// how we can do this better? +// update cache pid when the user changed the audio track or video track +// TODO handling of difference audio types.. default audio types.. + + /* don't worry about non-existing services, nor pvr services */ + if (m_dvb_service && !m_is_pvr) + { + m_dvb_service->setCachePID(eDVBService::cVPID, vpid); + m_dvb_service->setCachePID(eDVBService::cAPID, apid); + m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid); + } } break; @@ -247,8 +561,12 @@ void eDVBServicePlay::serviceEvent(int event) RESULT eDVBServicePlay::start() { + int r; eDebug("starting DVB service"); - return m_service_handler.tune((eServiceReferenceDVB&)m_reference); + r = m_service_handler.tune((eServiceReferenceDVB&)m_reference); + eDebug("tune result: %d", r); + m_event(this, evStart); + return 0; } RESULT eDVBServicePlay::stop() @@ -265,20 +583,121 @@ RESULT eDVBServicePlay::connectEvent(const Slot2 &ev RESULT eDVBServicePlay::pause(ePtr &ptr) { - // not yet possible, maybe later... + if (m_is_pvr) + { + ptr = this; + return 0; + } + + ptr = 0; + return -1; +} + +RESULT eDVBServicePlay::seek(ePtr &ptr) +{ + if (m_is_pvr) + { + ptr = this; + return 0; + } + ptr = 0; return -1; } +RESULT eDVBServicePlay::getLength(pts_t &len) +{ + ePtr pvr_channel; + + if (m_service_handler.getPVRChannel(pvr_channel)) + { + eDebug("getPVRChannel failed!"); + return -1; + } + + return pvr_channel->getLength(len); +} + +RESULT eDVBServicePlay::pause() +{ + if (!m_is_paused && m_decoder) + { + m_is_paused = 1; + return m_decoder->freeze(0); + } else + return -1; +} + +RESULT eDVBServicePlay::unpause() +{ + if (m_is_paused && m_decoder) + { + m_is_paused = 0; + return m_decoder->unfreeze(); + } else + return -1; +} + +RESULT eDVBServicePlay::seekTo(pts_t to) +{ + return -1; +} + +RESULT eDVBServicePlay::seekRelative(int direction, pts_t to) +{ + eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to); + + ePtr pvr_channel; + + if (m_service_handler.getPVRChannel(pvr_channel)) + return -1; + + to *= direction; + + ePtr demux; + m_service_handler.getDemux(demux); + if (!demux) + return -1; + + return pvr_channel->seekTo(demux, 1, to); +} + +RESULT eDVBServicePlay::getPlayPosition(pts_t &pos) +{ + ePtr pvr_channel; + + if (m_service_handler.getPVRChannel(pvr_channel)) + return -1; + + ePtr demux; + m_service_handler.getDemux(demux); + if (!demux) + return -1; + + return pvr_channel->getCurrentPosition(demux, pos); +} + RESULT eDVBServicePlay::info(ePtr &ptr) { ptr = this; return 0; } -RESULT eDVBServicePlay::getName(const eServiceReference &ref, std::string &name) +RESULT eDVBServicePlay::audioTracks(ePtr &ptr) { - name = "DVB service"; + ptr = this; + return 0; +} + +RESULT eDVBServicePlay::getName(std::string &name) +{ + if (m_dvb_service) + { + m_dvb_service->getName(m_reference, name); + if (name.empty()) + name = "(...)"; + } else + name = "DVB service"; return 0; } @@ -287,6 +706,58 @@ RESULT eDVBServicePlay::getEvent(ePtr &evt, int nownext) return m_event_handler.getEvent(evt, nownext); } +int eDVBServicePlay::getNumberOfTracks() +{ + eDVBServicePMTHandler::program program; + if (m_service_handler.getProgramInfo(program)) + return 0; + return program.audioStreams.size(); +} + +RESULT eDVBServicePlay::selectTrack(unsigned int i) +{ + eDVBServicePMTHandler::program program; + + if (m_service_handler.getProgramInfo(program)) + return -1; + + if (i >= program.audioStreams.size()) + return -2; + + if (!m_decoder) + return -3; + + if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type)) + return -4; + + if (m_decoder->start()) + return -5; + + return 0; +} + +RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i) +{ + eDVBServicePMTHandler::program program; + + if (m_service_handler.getProgramInfo(program)) + return -1; + + if (i >= program.audioStreams.size()) + return -2; + + if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG) + info.m_description = "MPEG"; + else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3) + info.m_description = "AC3"; + else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS) + info.m_description = "DTS"; + else + info.m_description = "???"; + + return 0; +} + DEFINE_REF(eDVBServicePlay) eAutoInitPtr init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");