#include #include #include #include #include #include #include #include #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.empty() ) { 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) eServiceFactoryDVB::eServiceFactoryDVB() { ePtr sc; eServiceCenter::getPrivInstance(sc); if (sc) sc->addServiceFactory(eServiceFactoryDVB::id, this); } eServiceFactoryDVB::~eServiceFactoryDVB() { ePtr sc; eServiceCenter::getPrivInstance(sc); if (sc) sc->removeServiceFactory(eServiceFactoryDVB::id); } DEFINE_REF(eDVBServiceList); eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent) { } eDVBServiceList::~eDVBServiceList() { } RESULT eDVBServiceList::startQuery() { ePtr db; ePtr res; int err; if ((err = eDVBResourceManager::getInstance(res)) != 0) { eDebug("no resource manager"); return err; } if ((err = res->getChannelList(db)) != 0) { eDebug("no channel list"); return err; } ePtr q; if (!m_parent.path.empty()) { eDVBChannelQuery::compile(q, m_parent.path); if (!q) { eDebug("compile query failed"); return err; } } 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; 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, service); return 0; } RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr &ptr) { if (ref.path.empty()) { ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref); return 0; } else { ptr = 0; return -1; } } RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr &ptr) { ePtr list = new eDVBServiceList(ref); if (list->startQuery()) { ptr = 0; return -1; } ptr = list; return 0; } RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr &ptr) { /* is a listable service? */ if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet { if ( !ref.name.empty() ) // satellites or providers list ptr = new eStaticServiceDVBInformation; else // a dvb bouquet ptr = new eStaticServiceDVBBouquetInformation; return 0; } else if (!ref.path.empty()) /* do we have a PVR service? */ { ptr = new eStaticServiceDVBPVRInformation(ref); return 0; } else // normal dvb service { ePtr service; int r = lookupService(service, ref); if (r) // no eDVBService avail for this reference ( Linkage Services... ) 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 // TODO: cache ePtr db; ePtr res; int err; if ((err = eDVBResourceManager::getInstance(res)) != 0) { eDebug("no resource manager"); return err; } if ((err = res->getChannelList(db)) != 0) { eDebug("no channel list"); return err; } /* 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; } return 0; } 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); } eDVBServicePlay::~eDVBServicePlay() { } void eDVBServicePlay::gotNewEvent() { #if 0 // debug only ePtr m_event_now, m_event_next; getEvent(m_event_now, 0); getEvent(m_event_next, 1); if (m_event_now) eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration); if (m_event_next) eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration); #endif m_event((iPlayableService*)this, evUpdatedEventInfo); } void eDVBServicePlay::serviceEvent(int event) { switch (event) { case eDVBServicePMTHandler::eventTuned: { ePtr m_demux; if (!m_service_handler.getDemux(m_demux)) { // eventStartedEventAcquisition m_event_handler.start(m_demux, ((eServiceReferenceDVB&)m_reference).getServiceID().get()); } // 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, apidtype = -1, pcrpid = -1; eDVBServicePMTHandler::program program; if (m_service_handler.getProgramInfo(program)) eDebug("getting program info failed."); else { eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size()); if (!program.videoStreams.empty()) { eDebugNoNewLine(" ("); for (std::vector::const_iterator i(program.videoStreams.begin()); i != program.videoStreams.end(); ++i) { if (vpid == -1) vpid = i->pid; if (i != program.videoStreams.begin()) eDebugNoNewLine(", "); eDebugNoNewLine("%04x", i->pid); } eDebugNoNewLine(")"); } eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size()); if (!program.audioStreams.empty()) { eDebugNoNewLine(" ("); for (std::vector::const_iterator i(program.audioStreams.begin()); i != program.audioStreams.end(); ++i) { if (apid == -1) { apid = i->pid; apidtype = i->type; } if (i != program.audioStreams.begin()) eDebugNoNewLine(", "); eDebugNoNewLine("%04x", i->pid); } eDebugNoNewLine(")"); } eDebug(", and the pcr pid is %04x", program.pcrPid); if (program.pcrPid != 0x1fff) pcrpid = program.pcrPid; } if (!m_decoder) { ePtr demux; m_service_handler.getDemux(demux); if (demux) demux->getMPEGDecoder(m_decoder); } if (m_decoder) { m_decoder->setVideoPID(vpid); m_current_audio_stream = 0; 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; } } } RESULT eDVBServicePlay::start() { int r; eDebug("starting DVB service"); r = m_service_handler.tune((eServiceReferenceDVB&)m_reference); eDebug("tune result: %d", r); m_event(this, evStart); return 0; } RESULT eDVBServicePlay::stop() { eDebug("stopping.."); return 0; } RESULT eDVBServicePlay::connectEvent(const Slot2 &event, ePtr &connection) { connection = new eConnection((iPlayableService*)this, m_event.connect(event)); return 0; } RESULT eDVBServicePlay::pause(ePtr &ptr) { 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::frontendStatusInfo(ePtr &ptr) { ptr = this; return 0; } RESULT eDVBServicePlay::info(ePtr &ptr) { ptr = this; return 0; } RESULT eDVBServicePlay::audioTracks(ePtr &ptr) { 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; } RESULT eDVBServicePlay::getEvent(ePtr &evt, int nownext) { return m_event_handler.getEvent(evt, nownext); } int eDVBServicePlay::getInfo(int w) { eDVBServicePMTHandler::program program; if (m_service_handler.getProgramInfo(program)) return -1; switch (w) { case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid; case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid; case sPCRPID: return program.pcrPid; case sPMTPID: return program.pmtPid; case sTXTPID: return -1; case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get(); case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get(); case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get(); case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get(); case sProvider: if (!m_dvb_service) return -1; return -2; default: return -1; } } std::string eDVBServicePlay::getInfoString(int w) { switch (w) { case sProvider: if (!m_dvb_service) return ""; return m_dvb_service->m_provider_name; default: return ""; } } int eDVBServicePlay::getNumberOfTracks() { eDVBServicePMTHandler::program program; if (m_service_handler.getProgramInfo(program)) return 0; return program.audioStreams.size(); } RESULT eDVBServicePlay::selectTrack(unsigned int i) { int ret = selectAudioStream(i); if (m_decoder->start()) return -5; return ret; } 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 = "???"; /* CHECK here for component tag override. */ info.m_language = program.audioStreams[i].language_code; return 0; } int eDVBServicePlay::selectAudioStream(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; m_current_audio_stream = i; return 0; } int eDVBServicePlay::getFrontendInfo(int w) { if (m_is_pvr) return 0; eUsePtr channel; if(m_service_handler.getChannel(channel)) return 0; ePtr fe; if(channel->getFrontend(fe)) return 0; return fe->readFrontendData(w); } DEFINE_REF(eDVBServicePlay) eAutoInitPtr init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");