1 #include <lib/base/eerror.h>
2 #include <lib/base/filepush.h>
3 #include <lib/dvb/idvb.h>
4 #include <lib/dvb/dvb.h>
5 #include <lib/dvb/sec.h>
13 DEFINE_REF(eDVBRegisteredFrontend);
14 DEFINE_REF(eDVBRegisteredDemux);
16 DEFINE_REF(eDVBAllocatedFrontend);
18 eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe)
23 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
28 DEFINE_REF(eDVBAllocatedDemux);
30 eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux)
35 eDVBAllocatedDemux::~eDVBAllocatedDemux()
40 DEFINE_REF(eDVBResourceManager);
42 eDVBResourceManager *eDVBResourceManager::instance;
44 eDVBResourceManager::eDVBResourceManager()
48 m_sec = new eDVBSatelliteEquipmentControl;
52 /* search available adapters... */
57 while (eDVBAdapterLinux::exist(num_adapter))
59 addAdapter(new eDVBAdapterLinux(num_adapter));
63 eDebug("found %d adapter, %d frontends and %d demux",
64 m_adapter.size(), m_frontend.size(), m_demux.size());
68 DEFINE_REF(eDVBAdapterLinux);
69 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
74 eDebug("scanning for frontends..");
79 #if HAVE_DVB_API_VERSION < 3
80 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
82 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
84 if (stat(filename, &s))
86 ePtr<eDVBFrontend> fe;
89 fe = new eDVBFrontend(m_nr, num_fe, ok);
91 m_frontend.push_back(fe);
101 #if HAVE_DVB_API_VERSION < 3
102 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
104 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
106 if (stat(filename, &s))
108 ePtr<eDVBDemux> demux;
110 demux = new eDVBDemux(m_nr, num_demux);
111 m_demux.push_back(demux);
117 int eDVBAdapterLinux::getNumDemux()
119 return m_demux.size();
122 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
124 eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
125 while (nr && (i != m_demux.end()))
131 if (i != m_demux.end())
139 int eDVBAdapterLinux::getNumFrontends()
141 return m_frontend.size();
144 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr)
146 eSmartPtrList<eDVBFrontend>::iterator i(m_frontend.begin());
147 while (nr && (i != m_frontend.end()))
153 if (i != m_frontend.end())
161 int eDVBAdapterLinux::exist(int nr)
165 #if HAVE_DVB_API_VERSION < 3
166 sprintf(filename, "/dev/dvb/card%d", nr);
168 sprintf(filename, "/dev/dvb/adapter%d", nr);
170 if (!stat(filename, &s))
175 eDVBResourceManager::~eDVBResourceManager()
177 if (instance == this)
182 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
184 int num_fe = adapter->getNumFrontends();
185 int num_demux = adapter->getNumDemux();
187 m_adapter.push_back(adapter);
190 for (i=0; i<num_demux; ++i)
192 ePtr<eDVBDemux> demux;
193 if (!adapter->getDemux(demux, i))
194 m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
197 for (i=0; i<num_fe; ++i)
199 ePtr<eDVBFrontend> frontend;
200 if (!adapter->getFrontend(frontend, i))
201 m_frontend.push_back(new eDVBRegisteredFrontend(frontend, adapter));
205 RESULT eDVBResourceManager::allocateFrontend(const eDVBChannelID &chid, ePtr<eDVBAllocatedFrontend> &fe)
207 /* find first unused frontend. we ignore compatibility for now. */
208 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
211 fe = new eDVBAllocatedFrontend(i);
217 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux)
219 /* find first unused demux which is on same adapter as frontend (or any, if PVR) */
220 for (eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin()); i != m_demux.end(); ++i)
221 if ((!i->m_inuse) && ((!fe) || (i->m_adapter == fe->m_adapter)))
223 demux = new eDVBAllocatedDemux(i);
229 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
235 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
245 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
247 /* first, check if a channel is already existing. */
249 // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
250 for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
252 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
253 if (i->m_channel_id == channelid)
255 // eDebug("found shared channel..");
256 channel = i->m_channel;
261 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
263 /* allocate a frontend. */
265 ePtr<eDVBAllocatedFrontend> fe;
267 if (allocateFrontend(channelid, fe))
268 return errNoFrontend;
270 ePtr<eDVBAllocatedDemux> demux;
272 if (allocateDemux(*fe, demux))
277 ch = new eDVBChannel(this, fe, demux);
279 ePtr<iDVBFrontend> myfe;
280 if (!ch->getFrontend(myfe))
283 res = ch->setChannel(channelid);
287 return errChidNotFound;
294 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel)
296 ePtr<eDVBAllocatedFrontend> fe;
298 if (allocateFrontend(eDVBChannelID(), fe))
299 return errNoFrontend;
301 ePtr<eDVBAllocatedDemux> demux;
303 if (allocateDemux(*fe, demux))
307 ch = new eDVBChannel(this, fe, demux);
309 ePtr<iDVBFrontend> myfe;
310 if (!ch->getFrontend(myfe))
318 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
320 ePtr<eDVBAllocatedDemux> demux;
322 if (allocateDemux(0, demux))
326 ch = new eDVBChannel(this, 0, demux);
332 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
334 eDebug("add channel %p", ch);
335 m_active_channels.push_back(active_channel(chid, ch));
336 /* emit */ m_channelAdded(ch);
340 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
343 for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
345 if (i->m_channel == ch)
347 i = m_active_channels.erase(i);
358 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
360 connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
364 DEFINE_REF(eDVBChannel);
366 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend, eDVBAllocatedDemux *demux): m_state(state_idle), m_mgr(mgr)
368 m_frontend = frontend;
374 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
377 eDVBChannel::~eDVBChannel()
380 m_mgr->removeChannel(this);
384 m_pvr_thread->stop();
385 ::close(m_pvr_fd_src);
386 ::close(m_pvr_fd_dst);
391 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
393 eDebug("fe state changed!");
394 int state, ourstate = 0;
396 /* if we are already in shutdown, don't change state. */
397 if (m_state == state_release)
400 if (fe->getState(state))
403 if (state == iDVBFrontend::stateLock)
405 eDebug("OURSTATE: ok");
407 } else if (state == iDVBFrontend::stateTuning)
409 eDebug("OURSTATE: tuning");
410 ourstate = state_tuning;
411 } else if (state == iDVBFrontend::stateFailed)
413 eDebug("OURSTATE: failed/unavailable");
414 ourstate = state_unavailable;
416 eFatal("state unknown");
418 if (ourstate != m_state)
421 m_stateChanged(this);
425 void eDVBChannel::AddUse()
430 void eDVBChannel::ReleaseUse()
434 m_state = state_release;
435 m_stateChanged(this);
439 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid)
442 m_mgr->removeChannel(this);
447 ePtr<iDVBChannelList> list;
449 if (m_mgr->getChannelList(list))
451 eDebug("no channel list set!");
455 eDebug("tuning to chid: ns: %08x tsid %04x onid %04x",
456 channelid.dvbnamespace.get(), channelid.transport_stream_id.get(), channelid.original_network_id.get());
458 ePtr<iDVBFrontendParameters> feparm;
459 if (list->getChannelFrontendData(channelid, feparm))
461 eDebug("channel not found!");
464 eDebug("allocateChannel: channel found..");
468 eDebug("no frontend to tune!");
472 m_channel_id = channelid;
473 m_mgr->addChannel(channelid, this);
474 m_state = state_tuning;
475 return m_frontend->get().tune(*feparm);
478 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
480 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
484 RESULT eDVBChannel::getState(int &state)
490 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
495 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux)
497 demux = &m_demux->get();
501 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
503 frontend = &m_frontend->get();
510 RESULT eDVBChannel::playFile(const char *file)
515 m_pvr_thread->stop();
520 m_tstools.openFile(file);
522 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
523 THEN DO A REAL FIX HERE! */
525 /* (this codepath needs to be improved anyway.) */
526 m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
527 if (m_pvr_fd_dst < 0)
529 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)");
533 m_pvr_fd_src = open(file, O_RDONLY);
534 if (m_pvr_fd_src < 0)
536 eDebug("can't open PVR m_pvr_fd_src file %s (%m)", file);
542 m_stateChanged(this);
544 m_pvr_thread = new eFilePushThread();
545 m_pvr_thread->start(m_pvr_fd_src, m_pvr_fd_dst);
548 RESULT eDVBChannel::getLength(pts_t &len)
550 return m_tstools.calcLen(len);
553 RESULT eDVBChannel::getCurrentPosition(pts_t &pos)
556 /* getPTS for offset 0 is cached, so it doesn't harm. */
557 int r = m_tstools.getPTS(begin, pos);
560 eDebug("tstools getpts(0) failed!");
566 r = m_demux->get().getSTC(now);
570 eDebug("demux getSTC failed");
574 eDebug("STC: %08llx PTS: %08llx, diff %lld", now, pos, now - pos);
576 /* when we are less than 10 seconds before the start, return 0. */
577 /* (we're just waiting for the timespam to start) */
578 if ((now < pos) && ((pos - now) < 90000 * 10))
584 if (now < pos) /* wrap around */
585 pos = now + ((pts_t)1)<<33 - pos;