#include #include #include #include #include #include #include #include DEFINE_REF(eDVBRegisteredFrontend); DEFINE_REF(eDVBRegisteredDemux); DEFINE_REF(eDVBAllocatedFrontend); eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe) { m_fe->m_inuse++; } eDVBAllocatedFrontend::~eDVBAllocatedFrontend() { --m_fe->m_inuse; } DEFINE_REF(eDVBAllocatedDemux); eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux) { m_demux->m_inuse++; } eDVBAllocatedDemux::~eDVBAllocatedDemux() { --m_demux->m_inuse; } DEFINE_REF(eDVBResourceManager); eDVBResourceManager *eDVBResourceManager::instance; eDVBResourceManager::eDVBResourceManager() { avail = 1; busy = 0; m_sec = new eDVBSatelliteEquipmentControl; if (!instance) instance = this; /* search available adapters... */ // add linux devices int num_adapter = 0; while (eDVBAdapterLinux::exist(num_adapter)) { addAdapter(new eDVBAdapterLinux(num_adapter)); num_adapter++; } eDebug("found %d adapter, %d frontends and %d demux", m_adapter.size(), m_frontend.size(), m_demux.size()); } DEFINE_REF(eDVBAdapterLinux); eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr) { // scan frontends int num_fe = 0; eDebug("scanning for frontends.."); while (1) { struct stat s; char filename[128]; #if HAVE_DVB_API_VERSION < 3 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe); #else sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe); #endif if (stat(filename, &s)) break; ePtr fe; int ok = 0; fe = new eDVBFrontend(m_nr, num_fe, ok); if (ok) m_frontend.push_back(fe); ++num_fe; } // scan demux int num_demux = 0; while (1) { struct stat s; char filename[128]; #if HAVE_DVB_API_VERSION < 3 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux); #else sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux); #endif if (stat(filename, &s)) break; ePtr demux; demux = new eDVBDemux(m_nr, num_demux); m_demux.push_back(demux); ++num_demux; } } int eDVBAdapterLinux::getNumDemux() { return m_demux.size(); } RESULT eDVBAdapterLinux::getDemux(ePtr &demux, int nr) { eSmartPtrList::iterator i(m_demux.begin()); while (nr && (i != m_demux.end())) { --nr; ++i; } if (i != m_demux.end()) demux = *i; else return -1; return 0; } int eDVBAdapterLinux::getNumFrontends() { return m_frontend.size(); } RESULT eDVBAdapterLinux::getFrontend(ePtr &fe, int nr) { eSmartPtrList::iterator i(m_frontend.begin()); while (nr && (i != m_frontend.end())) { --nr; ++i; } if (i != m_frontend.end()) fe = *i; else return -1; return 0; } int eDVBAdapterLinux::exist(int nr) { struct stat s; char filename[128]; #if HAVE_DVB_API_VERSION < 3 sprintf(filename, "/dev/dvb/card%d", nr); #else sprintf(filename, "/dev/dvb/adapter%d", nr); #endif if (!stat(filename, &s)) return 1; return 0; } eDVBResourceManager::~eDVBResourceManager() { if (instance == this) instance = 0; } void eDVBResourceManager::addAdapter(iDVBAdapter *adapter) { int num_fe = adapter->getNumFrontends(); int num_demux = adapter->getNumDemux(); m_adapter.push_back(adapter); int i; for (i=0; i demux; if (!adapter->getDemux(demux, i)) m_demux.push_back(new eDVBRegisteredDemux(demux, adapter)); } for (i=0; i frontend; if (!adapter->getFrontend(frontend, i)) m_frontend.push_back(new eDVBRegisteredFrontend(frontend, adapter)); } } RESULT eDVBResourceManager::allocateFrontend(const eDVBChannelID &chid, ePtr &fe) { /* find first unused frontend. we ignore compatibility for now. */ for (eSmartPtrList::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i) if (!i->m_inuse) { fe = new eDVBAllocatedFrontend(i); return 0; } return -1; } RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr &demux) { /* find first unused demux which is on same adapter as frontend */ for (eSmartPtrList::iterator i(m_demux.begin()); i != m_demux.end(); ++i) if ((!i->m_inuse) && (i->m_adapter == fe->m_adapter)) { demux = new eDVBAllocatedDemux(i); return 0; } return -1; } RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list) { m_list = list; return 0; } RESULT eDVBResourceManager::getChannelList(ePtr &list) { list = m_list; if (list) return 0; else return -ENOENT; } RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr &channel) { /* first, check if a channel is already existing. */ // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get()); for (std::list::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i) { // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get()); if (i->m_channel_id == channelid) { // eDebug("found shared channel.."); channel = i->m_channel; return 0; } } /* no currently available channel is tuned to this channelid. create a new one, if possible. */ /* allocate a frontend. */ ePtr fe; if (allocateFrontend(channelid, fe)) return errNoFrontend; ePtr demux; if (allocateDemux(*fe, demux)) return errNoDemux; RESULT res; eDVBChannel *ch; ch = new eDVBChannel(this, fe, demux); ePtr myfe; if (!ch->getFrontend(myfe)) myfe->setSEC(m_sec); res = ch->setChannel(channelid); if (res) { channel = 0; return errChidNotFound; } channel = ch; return 0; } RESULT eDVBResourceManager::allocateRawChannel(eUsePtr &channel) { ePtr fe; if (allocateFrontend(eDVBChannelID(), fe)) return errNoFrontend; ePtr demux; if (allocateDemux(*fe, demux)) return errNoDemux; eDVBChannel *ch; ch = new eDVBChannel(this, fe, demux); ePtr myfe; if (!ch->getFrontend(myfe)) myfe->setSEC(m_sec); channel = ch; return 0; } RESULT eDVBResourceManager::allocatePVRChannel(int caps) { return -1; // will nicht, mag nicht, und das interface ist auch kaputt } RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch) { eDebug("add channel %p", ch); m_active_channels.push_back(active_channel(chid, ch)); /* emit */ m_channelAdded(ch); return 0; } RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch) { int cnt = 0; for (std::list::iterator i(m_active_channels.begin()); i != m_active_channels.end();) { if (i->m_channel == ch) { i = m_active_channels.erase(i); ++cnt; } else ++i; } ASSERT(cnt == 1); if (cnt == 1) return 0; return -ENOENT; } RESULT eDVBResourceManager::connectChannelAdded(const Slot1 &channelAdded, ePtr &connection) { connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded)); return 0; } DEFINE_REF(eDVBChannel); eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend, eDVBAllocatedDemux *demux): m_state(state_idle), m_mgr(mgr) { m_frontend = frontend; m_demux = demux; if (m_frontend) m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged); } eDVBChannel::~eDVBChannel() { if (m_channel_id) m_mgr->removeChannel(this); } void eDVBChannel::frontendStateChanged(iDVBFrontend*fe) { eDebug("fe state changed!"); int state, ourstate = 0; /* if we are already in shutdown, don't change state. */ if (m_state == state_release) return; if (fe->getState(state)) return; if (state == iDVBFrontend::stateLock) { eDebug("OURSTATE: ok"); ourstate = state_ok; } else if (state == iDVBFrontend::stateTuning) { eDebug("OURSTATE: tuning"); ourstate = state_tuning; } else if (state == iDVBFrontend::stateFailed) { eDebug("OURSTATE: failed/unavailable"); ourstate = state_unavailable; } else eFatal("state unknown"); if (ourstate != m_state) { m_state = ourstate; m_stateChanged(this); } } void eDVBChannel::AddUse() { ++m_use_count; } void eDVBChannel::ReleaseUse() { if (!--m_use_count) { m_state = state_release; m_stateChanged(this); } } RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid) { if (m_channel_id) m_mgr->removeChannel(this); if (!channelid) return 0; ePtr list; if (m_mgr->getChannelList(list)) { eDebug("no channel list set!"); return -ENOENT; } eDebug("tuning to chid: ns: %08x tsid %04x onid %04x", channelid.dvbnamespace.get(), channelid.transport_stream_id.get(), channelid.original_network_id.get()); ePtr feparm; if (list->getChannelFrontendData(channelid, feparm)) { eDebug("channel not found!"); return -ENOENT; } eDebug("allocateChannel: channel found.."); if (!m_frontend) { eDebug("no frontend to tune!"); return -ENODEV; } m_channel_id = channelid; m_mgr->addChannel(channelid, this); m_state = state_tuning; return m_frontend->get().tune(*feparm); } RESULT eDVBChannel::connectStateChange(const Slot1 &stateChange, ePtr &connection) { connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange)); return 0; } RESULT eDVBChannel::getState(int &state) { state = m_state; return 0; } RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing) { return -1; } RESULT eDVBChannel::getDemux(ePtr &demux) { demux = &m_demux->get(); return 0; } RESULT eDVBChannel::getFrontend(ePtr &frontend) { frontend = &m_frontend->get(); if (frontend) return 0; else return -ENODEV; }