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)
181 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
183 int num_fe = adapter->getNumFrontends();
184 int num_demux = adapter->getNumDemux();
186 m_adapter.push_back(adapter);
189 for (i=0; i<num_demux; ++i)
191 ePtr<eDVBDemux> demux;
192 if (!adapter->getDemux(demux, i))
193 m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
196 for (i=0; i<num_fe; ++i)
198 ePtr<eDVBFrontend> frontend;
199 if (!adapter->getFrontend(frontend, i))
200 m_frontend.push_back(new eDVBRegisteredFrontend(frontend, adapter));
204 RESULT eDVBResourceManager::allocateFrontend(const eDVBChannelID &chid, ePtr<eDVBAllocatedFrontend> &fe)
206 /* find first unused frontend. we ignore compatibility for now. */
207 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
210 fe = new eDVBAllocatedFrontend(i);
216 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int cap)
218 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
219 never use the first one unless we need a decoding demux. */
221 eDebug("allocate demux");
222 eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
224 if (i == m_demux.end())
227 /* FIXME: hardware demux policy */
228 if (!(cap & iDVBChannel::capDecode))
231 for (; i != m_demux.end(); ++i)
232 if ((!i->m_inuse) && ((!fe) || (i->m_adapter == fe->m_adapter)))
234 demux = new eDVBAllocatedDemux(i);
235 eDebug("demux found");
238 eDebug("demux not found");
242 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
248 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
258 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
260 /* first, check if a channel is already existing. */
262 // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
263 for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
265 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
266 if (i->m_channel_id == channelid)
268 // eDebug("found shared channel..");
269 channel = i->m_channel;
274 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
276 /* allocate a frontend. */
278 ePtr<eDVBAllocatedFrontend> fe;
280 if (allocateFrontend(channelid, fe))
281 return errNoFrontend;
283 // will be allocated on demand:
284 // ePtr<eDVBAllocatedDemux> demux;
286 // if (allocateDemux(*fe, demux))
287 // return errNoDemux;
290 ePtr<eDVBChannel> ch;
291 ch = new eDVBChannel(this, fe);
293 ePtr<iDVBFrontend> myfe;
294 if (!ch->getFrontend(myfe))
297 res = ch->setChannel(channelid);
301 return errChidNotFound;
308 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel)
310 ePtr<eDVBAllocatedFrontend> fe;
312 if (allocateFrontend(eDVBChannelID(), fe))
313 return errNoFrontend;
315 // ePtr<eDVBAllocatedDemux> demux;
317 // if (allocateDemux(*fe, demux))
318 // return errNoDemux;
321 ch = new eDVBChannel(this, fe);
323 ePtr<iDVBFrontend> myfe;
324 if (!ch->getFrontend(myfe))
332 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
334 ePtr<eDVBAllocatedDemux> demux;
336 // if (allocateDemux(0, demux))
337 // return errNoDemux;
340 ch = new eDVBChannel(this, 0);
346 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
348 m_active_channels.push_back(active_channel(chid, ch));
349 /* emit */ m_channelAdded(ch);
353 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
356 for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
358 if (i->m_channel == ch)
360 i = m_active_channels.erase(i);
371 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
373 connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
377 DEFINE_REF(eDVBChannel);
379 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
381 m_frontend = frontend;
386 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
389 eDVBChannel::~eDVBChannel()
392 m_mgr->removeChannel(this);
396 m_pvr_thread->stop();
397 ::close(m_pvr_fd_src);
398 ::close(m_pvr_fd_dst);
403 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
405 int state, ourstate = 0;
407 /* if we are already in shutdown, don't change state. */
408 if (m_state == state_release)
411 if (fe->getState(state))
414 if (state == iDVBFrontend::stateLock)
416 eDebug("OURSTATE: ok");
418 } else if (state == iDVBFrontend::stateTuning)
420 eDebug("OURSTATE: tuning");
421 ourstate = state_tuning;
422 } else if (state == iDVBFrontend::stateLostLock)
424 eDebug("OURSTATE: lost lock");
425 ourstate = state_unavailable;
426 } else if (state == iDVBFrontend::stateFailed)
428 eDebug("OURSTATE: failed");
429 ourstate = state_failed;
431 eFatal("state unknown");
433 if (ourstate != m_state)
436 m_stateChanged(this);
440 void eDVBChannel::AddUse()
445 void eDVBChannel::ReleaseUse()
449 m_state = state_release;
450 m_stateChanged(this);
454 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid)
457 m_mgr->removeChannel(this);
462 ePtr<iDVBChannelList> list;
464 if (m_mgr->getChannelList(list))
466 eDebug("no channel list set!");
470 eDebug("tuning to chid: ns: %08x tsid %04x onid %04x",
471 channelid.dvbnamespace.get(), channelid.transport_stream_id.get(), channelid.original_network_id.get());
473 ePtr<iDVBFrontendParameters> feparm;
474 if (list->getChannelFrontendData(channelid, feparm))
476 eDebug("channel not 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;
620 RESULT eDVBChannel::seekTo(pts_t &pts)
622 m_pvr_thread->pause();
624 m_decoder_demux->get().flush();
625 /* demux will also flush all decoder.. */
626 // m_pvr_thread->seek(pts);
627 m_pvr_thread->resume();