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, int cap)
219 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
220 never use the first one unless we need a decoding demux. */
222 eDebug("allocate demux");
223 eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
225 if (i == m_demux.end())
228 /* FIXME: hardware demux policy */
229 if (!(cap & iDVBChannel::capDecode))
232 for (; i != m_demux.end(); ++i)
233 if ((!i->m_inuse) && ((!fe) || (i->m_adapter == fe->m_adapter)))
235 demux = new eDVBAllocatedDemux(i);
236 eDebug("demux found");
239 eDebug("demux not found");
243 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
249 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
259 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
261 /* first, check if a channel is already existing. */
263 // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
264 for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
266 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
267 if (i->m_channel_id == channelid)
269 // eDebug("found shared channel..");
270 channel = i->m_channel;
275 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
277 /* allocate a frontend. */
279 ePtr<eDVBAllocatedFrontend> fe;
281 if (allocateFrontend(channelid, fe))
282 return errNoFrontend;
284 // will be allocated on demand:
285 // ePtr<eDVBAllocatedDemux> demux;
287 // if (allocateDemux(*fe, demux))
288 // return errNoDemux;
292 ch = new eDVBChannel(this, fe);
294 ePtr<iDVBFrontend> myfe;
295 if (!ch->getFrontend(myfe))
298 res = ch->setChannel(channelid);
302 return errChidNotFound;
309 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel)
311 ePtr<eDVBAllocatedFrontend> fe;
313 if (allocateFrontend(eDVBChannelID(), fe))
314 return errNoFrontend;
316 // ePtr<eDVBAllocatedDemux> demux;
318 // if (allocateDemux(*fe, demux))
319 // return errNoDemux;
322 ch = new eDVBChannel(this, fe);
324 ePtr<iDVBFrontend> myfe;
325 if (!ch->getFrontend(myfe))
333 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
335 ePtr<eDVBAllocatedDemux> demux;
337 // if (allocateDemux(0, demux))
338 // return errNoDemux;
341 ch = new eDVBChannel(this, 0);
347 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
349 eDebug("add channel %p", ch);
350 m_active_channels.push_back(active_channel(chid, ch));
351 /* emit */ m_channelAdded(ch);
355 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
358 for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
360 if (i->m_channel == ch)
362 i = m_active_channels.erase(i);
373 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
375 connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
379 DEFINE_REF(eDVBChannel);
381 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
383 m_frontend = frontend;
388 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
391 eDVBChannel::~eDVBChannel()
394 m_mgr->removeChannel(this);
398 m_pvr_thread->stop();
399 ::close(m_pvr_fd_src);
400 ::close(m_pvr_fd_dst);
405 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
407 eDebug("fe state changed!");
408 int state, ourstate = 0;
410 /* if we are already in shutdown, don't change state. */
411 if (m_state == state_release)
414 if (fe->getState(state))
417 if (state == iDVBFrontend::stateLock)
419 eDebug("OURSTATE: ok");
421 } else if (state == iDVBFrontend::stateTuning)
423 eDebug("OURSTATE: tuning");
424 ourstate = state_tuning;
425 } else if (state == iDVBFrontend::stateFailed)
427 eDebug("OURSTATE: failed/unavailable");
428 ourstate = state_unavailable;
430 eFatal("state unknown");
432 if (ourstate != m_state)
435 m_stateChanged(this);
439 void eDVBChannel::AddUse()
444 void eDVBChannel::ReleaseUse()
448 m_state = state_release;
449 m_stateChanged(this);
453 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid)
456 m_mgr->removeChannel(this);
461 ePtr<iDVBChannelList> list;
463 if (m_mgr->getChannelList(list))
465 eDebug("no channel list set!");
469 eDebug("tuning to chid: ns: %08x tsid %04x onid %04x",
470 channelid.dvbnamespace.get(), channelid.transport_stream_id.get(), channelid.original_network_id.get());
472 ePtr<iDVBFrontendParameters> feparm;
473 if (list->getChannelFrontendData(channelid, feparm))
475 eDebug("channel not found!");
478 eDebug("allocateChannel: channel found..");
482 eDebug("no frontend to tune!");
486 m_channel_id = channelid;
487 m_mgr->addChannel(channelid, this);
488 m_state = state_tuning;
489 return m_frontend->get().tune(*feparm);
492 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
494 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
498 RESULT eDVBChannel::getState(int &state)
504 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
509 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
511 ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
517 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
525 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
527 frontend = &m_frontend->get();
534 RESULT eDVBChannel::playFile(const char *file)
539 m_pvr_thread->stop();
544 m_tstools.openFile(file);
546 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
547 THEN DO A REAL FIX HERE! */
549 /* (this codepath needs to be improved anyway.) */
550 m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
551 if (m_pvr_fd_dst < 0)
553 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)");
557 m_pvr_fd_src = open(file, O_RDONLY);
558 if (m_pvr_fd_src < 0)
560 eDebug("can't open PVR m_pvr_fd_src file %s (%m)", file);
566 m_stateChanged(this);
568 m_pvr_thread = new eFilePushThread();
569 m_pvr_thread->start(m_pvr_fd_src, m_pvr_fd_dst);
574 RESULT eDVBChannel::getLength(pts_t &len)
576 return m_tstools.calcLen(len);
579 RESULT eDVBChannel::getCurrentPosition(pts_t &pos)
581 if (!m_decoder_demux)
585 /* getPTS for offset 0 is cached, so it doesn't harm. */
586 int r = m_tstools.getPTS(begin, pos);
589 eDebug("tstools getpts(0) failed!");
595 r = m_decoder_demux->get().getSTC(now);
599 eDebug("demux getSTC failed");
603 // eDebug("STC: %08llx PTS: %08llx, diff %lld", now, pos, now - pos);
604 /* when we are less than 10 seconds before the start, return 0. */
605 /* (we're just waiting for the timespam to start) */
606 if ((now < pos) && ((pos - now) < 90000 * 10))
612 if (now < pos) /* wrap around */
613 pos = now + ((pts_t)1)<<33 - pos;