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/pmt.h>
6 #include <lib/dvb/sec.h>
7 #include <lib/dvb/specs.h>
10 #include <sys/types.h>
14 #include <sys/ioctl.h>
16 DEFINE_REF(eDVBRegisteredFrontend);
17 DEFINE_REF(eDVBRegisteredDemux);
19 DEFINE_REF(eDVBAllocatedFrontend);
21 eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe)
26 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
31 DEFINE_REF(eDVBAllocatedDemux);
33 eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux)
38 eDVBAllocatedDemux::~eDVBAllocatedDemux()
43 DEFINE_REF(eDVBResourceManager);
45 eDVBResourceManager *eDVBResourceManager::instance;
47 RESULT eDVBResourceManager::getInstance(ePtr<eDVBResourceManager> &ptr)
57 ePtr<eDVBResourceManager> NewResourceManagerPtr(void)
59 ePtr<eDVBResourceManager> ptr;
60 eDVBResourceManager::getInstance(ptr);
64 eDVBResourceManager::eDVBResourceManager()
65 :m_releaseCachedChannelTimer(eTimer::create(eApp))
69 m_sec = new eDVBSatelliteEquipmentControl(m_frontend, m_simulate_frontend);
74 /* search available adapters... */
79 while (eDVBAdapterLinux::exist(num_adapter))
81 addAdapter(new eDVBAdapterLinux(num_adapter));
85 int fd = open("/proc/stb/info/model", O_RDONLY);
87 int rd = fd >= 0 ? read(fd, tmp, 255) : 0;
91 if (!strncmp(tmp, "dm7025\n", rd))
93 else if (!strncmp(tmp, "dm8000\n", rd))
95 else if (!strncmp(tmp, "dm800\n", rd))
97 else if (!strncmp(tmp, "dm500hd\n", rd))
100 eDebug("boxtype detection via /proc/stb/info not possible... use fallback via demux count!\n");
101 if (m_demux.size() == 3)
103 else if (m_demux.size() < 5)
109 eDebug("found %d adapter, %d frontends(%d sim) and %d demux, boxtype %d",
110 m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size(), m_boxtype);
112 eDVBCAService::registerChannelCallback(this);
114 CONNECT(m_releaseCachedChannelTimer->timeout, eDVBResourceManager::releaseCachedChannel);
117 void eDVBResourceManager::feStateChanged()
120 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
122 mask |= ( 1 << i->m_frontend->getSlotID() );
123 /* emit */ frontendUseMaskChanged(mask);
126 DEFINE_REF(eDVBAdapterLinux);
127 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
132 eDebug("scanning for frontends..");
137 #if HAVE_DVB_API_VERSION < 3
138 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
140 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
142 if (stat(filename, &s))
144 ePtr<eDVBFrontend> fe;
148 fe = new eDVBFrontend(m_nr, num_fe, ok);
150 m_frontend.push_back(fe);
154 fe = new eDVBFrontend(m_nr, num_fe, ok, true);
156 m_simulate_frontend.push_back(fe);
167 #if HAVE_DVB_API_VERSION < 3
168 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
170 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
172 if (stat(filename, &s))
174 ePtr<eDVBDemux> demux;
176 demux = new eDVBDemux(m_nr, num_demux);
177 m_demux.push_back(demux);
183 int eDVBAdapterLinux::getNumDemux()
185 return m_demux.size();
188 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
190 eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
191 while (nr && (i != m_demux.end()))
197 if (i != m_demux.end())
205 int eDVBAdapterLinux::getNumFrontends()
207 return m_frontend.size();
210 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr, bool simulate)
212 eSmartPtrList<eDVBFrontend>::iterator i(simulate ? m_simulate_frontend.begin() : m_frontend.begin());
213 while (nr && (i != m_frontend.end()))
219 if (i != m_frontend.end())
227 int eDVBAdapterLinux::exist(int nr)
231 #if HAVE_DVB_API_VERSION < 3
232 sprintf(filename, "/dev/dvb/card%d", nr);
234 sprintf(filename, "/dev/dvb/adapter%d", nr);
236 if (!stat(filename, &s))
241 eDVBResourceManager::~eDVBResourceManager()
243 if (instance == this)
247 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
249 int num_fe = adapter->getNumFrontends();
250 int num_demux = adapter->getNumDemux();
252 m_adapter.push_back(adapter);
255 for (i=0; i<num_demux; ++i)
257 ePtr<eDVBDemux> demux;
258 if (!adapter->getDemux(demux, i))
259 m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
262 ePtr<eDVBRegisteredFrontend> prev_dvbt_frontend;
263 for (i=0; i<num_fe; ++i)
265 ePtr<eDVBFrontend> frontend;
266 if (!adapter->getFrontend(frontend, i))
269 frontend->getFrontendType(frontendType);
270 eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
271 CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
272 m_frontend.push_back(new_fe);
273 frontend->setSEC(m_sec);
274 // we must link all dvb-t frontends ( for active antenna voltage )
275 if (frontendType == iDVBFrontend::feTerrestrial)
277 if (prev_dvbt_frontend)
279 prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
280 frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
282 prev_dvbt_frontend = new_fe;
287 prev_dvbt_frontend = 0;
288 for (i=0; i<num_fe; ++i)
290 ePtr<eDVBFrontend> frontend;
291 if (!adapter->getFrontend(frontend, i, true))
294 frontend->getFrontendType(frontendType);
295 eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
296 // CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
297 m_simulate_frontend.push_back(new_fe);
298 frontend->setSEC(m_sec);
299 // we must link all dvb-t frontends ( for active antenna voltage )
300 if (frontendType == iDVBFrontend::feTerrestrial)
302 if (prev_dvbt_frontend)
304 prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
305 frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
307 prev_dvbt_frontend = new_fe;
314 PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
316 if (!PyList_Check(list))
318 PyErr_SetString(PyExc_StandardError, "eDVBResourceManager::setFrontendSlotInformations argument should be a python list");
321 if ((unsigned int)PyList_Size(list) != m_frontend.size())
324 sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations list size incorrect %d frontends avail, but %d entries in slotlist",
325 m_frontend.size(), PyList_Size(list));
326 PyErr_SetString(PyExc_StandardError, blasel);
330 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
332 ePyObject obj = PyList_GET_ITEM(list, pos++);
333 if (!i->m_frontend->setSlotInfo(obj))
337 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_simulate_frontend.begin()); i != m_simulate_frontend.end(); ++i)
339 ePyObject obj = PyList_GET_ITEM(list, pos++);
340 if (!i->m_frontend->setSlotInfo(obj))
346 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm, bool simulate)
348 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
349 ePtr<eDVBRegisteredFrontend> best;
353 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
355 int c = i->m_frontend->isCompatibleWith(feparm);
357 if (c) /* if we have at least one frontend which is compatible with the source, flag this. */
362 // eDebug("Slot %d, score %d", i->m_frontend->getSlotID(), c);
370 // eDebug("Slot %d, score %d... but BUSY!!!!!!!!!!!", i->m_frontend->getSlotID(), c);
375 fe = new eDVBAllocatedFrontend(best);
382 return errAllSourcesBusy;
384 return errNoSourceFound;
387 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index)
389 int err = errNoSourceFound;
390 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
391 if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index)
393 // check if another slot linked to this is in use
395 i->m_frontend->getData(eDVBFrontend::SATPOS_DEPENDS_PTR, tmp);
398 eDVBRegisteredFrontend *satpos_depends_to_fe = (eDVBRegisteredFrontend *)tmp;
399 if (satpos_depends_to_fe->m_inuse)
401 eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!");
402 err = errAllSourcesBusy;
403 goto alloc_fe_by_id_not_possible;
406 else // check linked tuners
408 i->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
411 eDVBRegisteredFrontend *next = (eDVBRegisteredFrontend *) tmp;
414 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
415 err = errAllSourcesBusy;
416 goto alloc_fe_by_id_not_possible;
418 next->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
420 i->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
423 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *) tmp;
426 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
427 err = errAllSourcesBusy;
428 goto alloc_fe_by_id_not_possible;
430 prev->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
433 fe = new eDVBAllocatedFrontend(i);
436 alloc_fe_by_id_not_possible:
441 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int cap)
443 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
444 never use the first one unless we need a decoding demux. */
446 eDebug("allocate demux");
447 eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
451 if (i == m_demux.end())
454 ePtr<eDVBRegisteredDemux> unused;
456 if (m_boxtype == DM800 || m_boxtype == DM500HD) // dm800 / 500hd
458 for (; i != m_demux.end(); ++i, ++n)
469 if (i->m_adapter == fe->m_adapter &&
470 i->m_demux->getSource() == fe->m_frontend->getDVBID())
472 demux = new eDVBAllocatedDemux(i);
476 else if (i->m_demux->getSource() == -1) // PVR
478 demux = new eDVBAllocatedDemux(i);
484 else if (m_boxtype == DM7025) // ATI
486 /* FIXME: hardware demux policy */
487 if (!(cap & iDVBChannel::capDecode))
489 if (m_demux.size() > 2) /* assumed to be true, otherwise we have lost anyway */
496 for (; i != m_demux.end(); ++i, ++n)
498 int is_decode = n < 2;
500 int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
502 if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
504 if ((cap & iDVBChannel::capDecode) && !is_decode)
511 else if (m_boxtype == DM8000)
513 for (; i != m_demux.end(); ++i, ++n)
522 else if (i->m_adapter == fe->m_adapter &&
523 i->m_demux->getSource() == fe->m_frontend->getDVBID())
525 demux = new eDVBAllocatedDemux(i);
529 else if (n == 4) // always use demux4 for PVR (demux 4 can not descramble...)
532 demux = new eDVBAllocatedDemux(i);
542 demux = new eDVBAllocatedDemux(unused);
544 demux->get().setSourceFrontend(fe->m_frontend->getDVBID());
546 demux->get().setSourcePVR(0);
550 eDebug("demux not found");
554 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
560 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
569 #define eDebugNoSimulate(x...) \
576 // eDebugNoNewLine("SIMULATE:"); \
581 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel, bool simulate)
583 /* first, check if a channel is already existing. */
584 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
586 if (!simulate && m_cached_channel)
588 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
589 if(channelid==cache_chan->getChannelID())
591 eDebug("use cached_channel");
592 channel = m_cached_channel;
595 m_cached_channel_state_changed_conn.disconnect();
597 m_releaseCachedChannelTimer->stop();
600 eDebugNoSimulate("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
601 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
603 eDebugNoSimulate("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
604 if (i->m_channel_id == channelid)
606 eDebugNoSimulate("found shared channel..");
607 channel = i->m_channel;
612 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
616 eDebugNoSimulate("no channel list set!");
617 return errNoChannelList;
620 ePtr<iDVBFrontendParameters> feparm;
621 if (m_list->getChannelFrontendData(channelid, feparm))
623 eDebugNoSimulate("channel not found!");
624 return errChannelNotInList;
627 /* allocate a frontend. */
629 ePtr<eDVBAllocatedFrontend> fe;
631 int err = allocateFrontend(fe, feparm, simulate);
636 ePtr<eDVBChannel> ch = new eDVBChannel(this, fe);
638 res = ch->setChannel(channelid, feparm);
642 return errChidNotFound;
649 m_cached_channel = channel = ch;
650 m_cached_channel_state_changed_conn =
651 CONNECT(ch->m_stateChanged,eDVBResourceManager::DVBChannelStateChanged);
657 void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
660 chan->getState(state);
663 case iDVBChannel::state_release:
664 case iDVBChannel::state_ok:
666 eDebug("stop release channel timer");
667 m_releaseCachedChannelTimer->stop();
670 case iDVBChannel::state_last_instance:
672 eDebug("start release channel timer");
673 m_releaseCachedChannelTimer->start(3000, true);
676 default: // ignore all other events
681 void eDVBResourceManager::releaseCachedChannel()
683 eDebug("release cached channel (timer timeout)");
687 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int slot_index)
689 ePtr<eDVBAllocatedFrontend> fe;
691 if (m_cached_channel)
693 m_cached_channel_state_changed_conn.disconnect();
695 m_releaseCachedChannelTimer->stop();
698 int err = allocateFrontendByIndex(fe, slot_index);
702 channel = new eDVBChannel(this, fe);
707 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
709 ePtr<eDVBAllocatedDemux> demux;
711 if (m_cached_channel && m_releaseCachedChannelTimer->isActive())
713 m_cached_channel_state_changed_conn.disconnect();
715 m_releaseCachedChannelTimer->stop();
718 channel = new eDVBChannel(this, 0);
722 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
724 ePtr<iDVBFrontend> fe;
725 if (!ch->getFrontend(fe))
727 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
728 if (frontend->is_simulate())
729 m_active_simulate_channels.push_back(active_channel(chid, ch));
732 m_active_channels.push_back(active_channel(chid, ch));
733 /* emit */ m_channelAdded(ch);
739 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
741 ePtr<iDVBFrontend> fe;
742 if (!ch->getFrontend(fe))
744 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
745 std::list<active_channel> &active_channels = frontend->is_simulate() ? m_active_simulate_channels : m_active_channels;
747 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end();)
749 if (i->m_channel == ch)
751 i = active_channels.erase(i);
763 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
765 connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
769 int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm, bool simulate)
771 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
772 ePtr<eDVBRegisteredFrontend> best;
775 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
778 int c = i->m_frontend->isCompatibleWith(feparm);
785 int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
789 ePtr<iDVBFrontendParameters> feparm;
790 if (!channellist->getChannelFrontendData(chid, feparm))
793 if (!feparm->getSystem(system))
797 case iDVBFrontend::feSatellite:
799 case iDVBFrontend::feCable:
801 case iDVBFrontend::feTerrestrial:
812 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore, bool simulate)
814 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
816 if (!simulate && m_cached_channel)
818 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
819 if(channelid==cache_chan->getChannelID())
820 return tuner_type_channel_default(m_list, channelid);
823 /* first, check if a channel is already existing. */
824 // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
825 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
827 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
828 if (i->m_channel_id == channelid)
830 // eDebug("found shared channel..");
831 return tuner_type_channel_default(m_list, channelid);
835 int *decremented_cached_channel_fe_usecount=NULL,
836 *decremented_fe_usecount=NULL;
838 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
840 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
841 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
842 if (i->m_channel_id == ignore)
844 eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
845 // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
846 // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
847 // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
848 // or 2 when the cached channel is not equal to the compared channel
849 if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2) // channel only used once..
851 ePtr<iDVBFrontend> fe;
852 if (!i->m_channel->getFrontend(fe))
854 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
856 if ( &(*fe) == &(*ii->m_frontend) )
859 decremented_fe_usecount = &ii->m_inuse;
860 if (channel == &(*m_cached_channel))
861 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
871 if (!decremented_cached_channel_fe_usecount)
873 if (m_cached_channel)
875 eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
876 if (channel->getUseCount() == 1)
878 ePtr<iDVBFrontend> fe;
879 if (!channel->getFrontend(fe))
881 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
882 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
884 if ( &(*fe) == &(*ii->m_frontend) )
887 decremented_cached_channel_fe_usecount = &ii->m_inuse;
896 decremented_cached_channel_fe_usecount=NULL;
898 ePtr<iDVBFrontendParameters> feparm;
902 eDebug("no channel list set!");
906 if (m_list->getChannelFrontendData(channelid, feparm))
908 eDebug("channel not found!");
912 ret = canAllocateFrontend(feparm, simulate);
915 if (decremented_fe_usecount)
916 ++(*decremented_fe_usecount);
917 if (decremented_cached_channel_fe_usecount)
918 ++(*decremented_cached_channel_fe_usecount);
923 bool eDVBResourceManager::canMeasureFrontendInputPower()
925 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
927 return i->m_frontend->readInputpower() >= 0;
932 class eDVBChannelFilePush: public eFilePushThread
935 eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); }
936 void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
938 /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */
939 /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */
940 void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */
942 int m_iframe_search, m_iframe_state, m_pid;
943 int m_timebase_change;
944 int filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining);
947 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t ¤t_span_remaining)
950 if (m_timebase_change)
952 eDebug("timebase change: %d", m_timebase_change);
954 for (offset = 0; offset < len; offset += 188)
956 unsigned char *pkt = (unsigned char*)_data + offset;
957 if (pkt[1] & 0x40) /* pusi */
959 if (pkt[3] & 0x20) // adaption field present?
960 pkt += pkt[4] + 4 + 1; /* skip adaption field and header */
962 pkt += 4; /* skip header */
963 if (pkt[0] || pkt[1] || (pkt[2] != 1))
965 eWarning("broken startcode");
971 if (pkt[7] & 0x80) // PTS present?
973 pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29;
974 pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
975 pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
976 pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
977 pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
981 RESULT r = m_tstools.fixupPTS(off, pts);
983 eWarning("fixup PTS while trickmode playback failed.\n");
986 int sec = pts / 90000;
987 int frm = pts % 90000;
995 // eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
998 pts *= m_timebase_change;
1010 // eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1018 pkt[9] |= (pts >> 29) & 0xE;
1019 pkt[10] |= (pts >> 22) & 0xFF;
1020 pkt[11] |= (pts >> 14) & 0xFE;
1021 pkt[12] |= (pts >> 7) & 0xFF;
1022 pkt[13] |= (pts << 1) & 0xFE;
1030 if (!m_iframe_search)
1033 unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
1035 // eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
1037 unsigned char *d = data;
1038 while ((d + 3 < data + len) && (d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
1040 int offset = d - data;
1041 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
1042 unsigned char *ts = data + ts_offset;
1043 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
1045 if ((d[3] == 0 || d[3] == 0x09 && d[-1] == 0 && (ts[1] & 0x40)) && (m_pid == pid)) /* picture start */
1047 int picture_type = (d[3]==0 ? (d[5] >> 3) & 7 : (d[4] >> 5) + 1);
1050 // eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
1052 if (m_iframe_state == 1)
1054 /* we are allowing data, and stop allowing data on the next frame.
1055 we now found a frame. so stop here. */
1056 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
1057 current_span_remaining = 0;
1059 unsigned char *fts = ts + 188;
1060 while (fts < (data + len))
1063 fts[2] |= 0xff; /* drop packet */
1067 return len; // ts_offset + 188; /* deliver this packet, but not more. */
1070 if (picture_type != 1) /* we are only interested in I frames */
1073 unsigned char *fts = data;
1077 fts[2] |= 0xff; /* drop packet */
1084 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
1086 /* verify that this is actually a PES header, not just some ES data */
1087 if (ts[1] & 0x40) /* PUSI set */
1089 int payload_start = 4;
1090 if (ts[3] & 0x20) /* adaptation field present */
1091 payload_start += ts[4] + 1; /* skip AF */
1092 if (payload_start == (offset%188)) /* the 00 00 01 should be directly at the payload start, otherwise it's not a PES header */
1096 eDebug("now locked to pid %04x (%02x %02x %02x %02x)", pid, ts[0], ts[1], ts[2], ts[3]);
1104 d += 4; /* ignore */
1107 if (m_iframe_state == 1)
1110 return 0; /* we need find an iframe first */
1116 DEFINE_REF(eDVBChannel);
1118 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
1120 m_frontend = frontend;
1124 m_skipmode_n = m_skipmode_m = m_skipmode_frames = 0;
1127 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
1130 eDVBChannel::~eDVBChannel()
1133 m_mgr->removeChannel(this);
1138 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
1140 int state, ourstate = 0;
1142 /* if we are already in shutdown, don't change state. */
1143 if (m_state == state_release)
1146 if (fe->getState(state))
1149 if (state == iDVBFrontend::stateLock)
1151 eDebug("OURSTATE: ok");
1152 ourstate = state_ok;
1153 } else if (state == iDVBFrontend::stateTuning)
1155 eDebug("OURSTATE: tuning");
1156 ourstate = state_tuning;
1157 } else if (state == iDVBFrontend::stateLostLock)
1159 /* on managed channels, we try to retune in order to re-acquire lock. */
1160 if (m_current_frontend_parameters)
1162 eDebug("OURSTATE: lost lock, trying to retune");
1163 ourstate = state_tuning;
1164 m_frontend->get().tune(*m_current_frontend_parameters);
1166 /* on unmanaged channels, we don't do this. the client will do this. */
1168 eDebug("OURSTATE: lost lock, unavailable now.");
1169 ourstate = state_unavailable;
1171 } else if (state == iDVBFrontend::stateFailed)
1173 eDebug("OURSTATE: failed");
1174 ourstate = state_failed;
1176 eFatal("state unknown");
1178 if (ourstate != m_state)
1181 m_stateChanged(this);
1185 void eDVBChannel::pvrEvent(int event)
1189 case eFilePushThread::evtEOF:
1190 eDebug("eDVBChannel: End of file!");
1191 m_event(this, evtEOF);
1193 case eFilePushThread::evtUser: /* start */
1195 m_event(this, evtSOF);
1200 void eDVBChannel::cueSheetEvent(int event)
1202 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1207 case eCueSheet::evtSeek:
1209 flushPVR(m_cue->m_decoding_demux);
1211 case eCueSheet::evtSkipmode:
1214 m_cue->m_lock.WrLock();
1215 m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1216 m_cue->m_lock.Unlock();
1217 eRdLocker l(m_cue->m_lock);
1218 if (m_cue->m_skipmode_ratio)
1220 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1221 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1222 /* i agree that this might look a bit like black magic. */
1223 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1224 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1225 m_skipmode_frames = m_cue->m_skipmode_ratio / 90000;
1226 m_skipmode_frames_remainder = 0;
1228 if (m_cue->m_skipmode_ratio < 0)
1229 m_skipmode_m -= m_skipmode_n;
1231 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1233 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1235 eWarning("something is wrong with this calculation");
1236 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1240 eDebug("skipmode ratio is 0, normal play");
1241 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1244 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1245 if (m_cue->m_skipmode_ratio != 0)
1246 m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1248 m_pvr_thread->setTimebaseChange(0); /* normal playback */
1249 eDebug("flush pvr");
1250 flushPVR(m_cue->m_decoding_demux);
1254 case eCueSheet::evtSpanChanged:
1256 m_source_span.clear();
1257 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1259 off_t offset_in, offset_out;
1260 pts_t pts_in = i->first, pts_out = i->second;
1261 if (m_tstools.getOffset(offset_in, pts_in, -1) || m_tstools.getOffset(offset_out, pts_out, 1))
1263 eDebug("span translation failed.\n");
1266 eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1267 m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1274 /* align toward zero */
1275 static inline long long align(long long x, int align)
1290 /* align toward zero */
1291 static inline long long align_with_len(long long x, int align, size_t &len)
1307 /* remember, this gets called from another thread. */
1308 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1310 const int blocksize = 188;
1311 unsigned int max = align(10*1024*1024, blocksize);
1312 current_offset = align(current_offset, blocksize);
1316 eDebug("no cue sheet. forcing normal play");
1317 start = current_offset;
1322 m_cue->m_lock.RdLock();
1323 if (!m_cue->m_decoding_demux)
1325 start = current_offset;
1327 eDebug("getNextSourceSpan, no decoding demux. forcing normal play");
1328 m_cue->m_lock.Unlock();
1334 eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames);
1335 max = align(m_skipmode_n, blocksize);
1338 eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1340 int frame_skip_success = 0;
1344 int frames_to_skip = m_skipmode_frames + m_skipmode_frames_remainder;
1345 eDebug("we are at %llx, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder);
1347 off_t iframe_start = current_offset;
1348 int frames_skipped = frames_to_skip;
1349 if (!m_tstools.findNextPicture(iframe_start, iframe_len, frames_skipped))
1351 m_skipmode_frames_remainder = frames_to_skip - frames_skipped;
1352 eDebug("successfully skipped %d (out of %d, rem now %d) frames.", frames_skipped, frames_to_skip, m_skipmode_frames_remainder);
1353 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1354 max = align(iframe_len + 187, blocksize);
1355 frame_skip_success = 1;
1358 m_skipmode_frames_remainder = 0;
1359 eDebug("frame skipping failed, reverting to byte-skipping");
1363 if (!frame_skip_success)
1365 current_offset += align(m_skipmode_m, blocksize);
1369 eDebug("we are at %llx, and we try to find the iframe here:", current_offset);
1371 off_t iframe_start = current_offset;
1373 int direction = (m_skipmode_m < 0) ? -1 : +1;
1374 if (m_tstools.findFrame(iframe_start, iframe_len, direction))
1378 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1379 max = align(iframe_len, blocksize);
1384 while (!m_cue->m_seek_requests.empty())
1386 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1387 m_cue->m_lock.Unlock();
1388 m_cue->m_lock.WrLock();
1389 m_cue->m_seek_requests.pop_front();
1390 m_cue->m_lock.Unlock();
1391 m_cue->m_lock.RdLock();
1392 int relative = seek.first;
1393 pts_t pts = seek.second;
1398 if (!m_cue->m_decoder)
1400 eDebug("no decoder - can't seek relative");
1403 if (m_cue->m_decoder->getPTS(0, now))
1405 eDebug("decoder getPTS failed, can't seek relative");
1408 if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1410 eDebug("seekTo: getCurrentPosition failed!");
1413 } else if (pts < 0) /* seek relative to end */
1416 if (!getLength(len))
1418 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1422 eWarning("getLength failed - can't seek relative to end!");
1427 if (relative == 1) /* pts relative */
1438 if (relative == 2) /* AP relative */
1440 eDebug("AP relative seeking: %lld, at %lld", pts, now);
1442 if (m_tstools.getNextAccessPoint(nextap, now, pts))
1444 pts = now - 90000; /* approx. 1s */
1445 eDebug("AP relative seeking failed!");
1449 eDebug("next ap is %llx\n", pts);
1454 if (m_tstools.getOffset(offset, pts, -1))
1456 eDebug("get offset for pts=%lld failed!", pts);
1461 /* try to align to iframe */
1462 int direction = pts < 0 ? -1 : 1;
1463 m_tstools.findFrame(offset, iframe_len, direction);
1465 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx (skipped additional %d frames due to iframe re-align)", relative, pts, offset, direction);
1466 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1469 m_cue->m_lock.Unlock();
1471 for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1473 long long aligned_start = align(i->first, blocksize);
1474 long long aligned_end = align(i->second, blocksize);
1476 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1478 start = current_offset;
1479 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1480 if ((aligned_end - current_offset) > max)
1483 size = aligned_end - current_offset;
1484 eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
1487 if (current_offset < aligned_start)
1489 /* ok, our current offset is in an 'out' zone. */
1490 if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1492 /* in normal playback, just start at the next zone. */
1495 /* size is not 64bit! */
1496 if ((i->second - i->first) > max)
1499 size = aligned_end - aligned_start;
1502 if (m_skipmode_m < 0)
1504 eDebug("reached SOF");
1507 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1511 /* when skipping reverse, however, choose the zone before. */
1513 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1516 aligned_start = align(i->first, blocksize);
1517 aligned_end = align(i->second, blocksize);
1519 if ((aligned_end - aligned_start) > max)
1522 len = aligned_end - aligned_start;
1524 start = aligned_end - len;
1525 eDebug("skipping to %llx, %d", start, len);
1528 eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
1533 if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1535 eDebug("reached SOF");
1537 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1540 if (m_source_span.empty())
1542 start = current_offset;
1544 eDebug("NO CUESHEET. (%08llx, %d)", start, size);
1547 start = current_offset;
1553 void eDVBChannel::AddUse()
1555 if (++m_use_count > 1 && m_state == state_last_instance)
1558 m_stateChanged(this);
1562 void eDVBChannel::ReleaseUse()
1566 m_state = state_release;
1567 m_stateChanged(this);
1569 else if (m_use_count == 1)
1571 m_state = state_last_instance;
1572 m_stateChanged(this);
1576 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1579 m_mgr->removeChannel(this);
1586 eDebug("no frontend to tune!");
1590 m_channel_id = channelid;
1591 m_mgr->addChannel(channelid, this);
1592 m_state = state_tuning;
1593 /* if tuning fails, shutdown the channel immediately. */
1595 res = m_frontend->get().tune(*feparm);
1596 m_current_frontend_parameters = feparm;
1600 m_state = state_release;
1601 m_stateChanged(this);
1608 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1610 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1614 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1616 connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1620 RESULT eDVBChannel::getState(int &state)
1626 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1631 void eDVBChannel::SDTready(int result)
1633 ePyObject args = PyTuple_New(2), ret;
1637 for (std::vector<ServiceDescriptionSection*>::const_iterator i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
1640 PyTuple_SET_ITEM(args, 0, PyInt_FromLong((*i)->getTransportStreamId()));
1641 PyTuple_SET_ITEM(args, 1, PyInt_FromLong((*i)->getOriginalNetworkId()));
1647 PyTuple_SET_ITEM(args, 0, Py_None);
1648 PyTuple_SET_ITEM(args, 1, Py_None);
1652 ret = PyObject_CallObject(m_tsid_onid_callback, args);
1656 Py_DECREF(m_tsid_onid_callback);
1657 m_tsid_onid_callback = ePyObject();
1658 m_tsid_onid_demux = 0;
1662 RESULT eDVBChannel::requestTsidOnid(ePyObject callback)
1664 if (PyCallable_Check(callback))
1666 if (!getDemux(m_tsid_onid_demux, 0))
1668 m_SDT = new eTable<ServiceDescriptionSection>;
1669 CONNECT(m_SDT->tableReady, eDVBChannel::SDTready);
1670 if (m_SDT->start(m_tsid_onid_demux, eDVBSDTSpec()))
1672 m_tsid_onid_demux = 0;
1677 Py_INCREF(callback);
1678 m_tsid_onid_callback = callback;
1686 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1688 ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1694 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1699 /* don't hold a reference to the decoding demux, we don't need it. */
1701 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1702 the refcount is lost. thus, decoding demuxes are never allocated.
1704 this poses a big problem for PiP. */
1705 if (cap & capDecode)
1710 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1715 frontend = &m_frontend->get();
1721 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> ¶m)
1723 param = m_current_frontend_parameters;
1727 RESULT eDVBChannel::playFile(const char *file)
1729 ASSERT(!m_frontend);
1732 m_pvr_thread->stop();
1733 delete m_pvr_thread;
1737 m_tstools.openFile(file);
1739 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1740 THEN DO A REAL FIX HERE! */
1742 /* (this codepath needs to be improved anyway.) */
1743 #if HAVE_DVB_API_VERSION < 3
1744 m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1746 m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
1748 if (m_pvr_fd_dst < 0)
1750 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1754 m_pvr_thread = new eDVBChannelFilePush();
1755 m_pvr_thread->enablePVRCommit(1);
1756 m_pvr_thread->setStreamMode(1);
1757 m_pvr_thread->setScatterGather(this);
1759 if (m_pvr_thread->start(file, m_pvr_fd_dst))
1761 delete m_pvr_thread;
1763 eDebug("can't open PVR file %s (%m)", file);
1766 CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1769 m_stateChanged(this);
1774 void eDVBChannel::stopFile()
1778 m_pvr_thread->stop();
1779 ::close(m_pvr_fd_dst);
1780 delete m_pvr_thread;
1785 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1787 m_conn_cueSheetEvent = 0;
1790 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1793 RESULT eDVBChannel::getLength(pts_t &len)
1795 return m_tstools.calcLen(len);
1798 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1800 if (!decoding_demux)
1807 if (mode == 0) /* demux */
1809 r = decoding_demux->getSTC(now, 0);
1812 eDebug("demux getSTC failed");
1816 now = pos; /* fixup supplied */
1818 off_t off = 0; /* TODO: fixme */
1819 r = m_tstools.fixupPTS(off, now);
1822 eDebug("fixup PTS failed");
1831 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1833 /* when seeking, we have to ensure that all buffers are flushed.
1834 there are basically 3 buffers:
1835 a.) the filepush's internal buffer
1836 b.) the PVR buffer (before demux)
1837 c.) the ratebuffer (after demux)
1839 it's important to clear them in the correct order, otherwise
1840 the ratebuffer (for example) would immediately refill from
1841 the not-yet-flushed PVR buffer.
1844 m_pvr_thread->pause();
1845 /* flush internal filepush buffer */
1846 m_pvr_thread->flush();
1847 /* HACK: flush PVR buffer */
1848 ::ioctl(m_pvr_fd_dst, 0);
1850 /* flush ratebuffers (video, audio) */
1852 decoding_demux->flush();
1854 /* demux will also flush all decoder.. */
1855 /* resume will re-query the SG */
1856 m_pvr_thread->resume();
1859 DEFINE_REF(eCueSheet);
1861 eCueSheet::eCueSheet()
1863 m_skipmode_ratio = 0;
1866 void eCueSheet::seekTo(int relative, const pts_t &pts)
1869 m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1874 void eCueSheet::clear()
1881 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
1883 ASSERT(begin < end);
1885 m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
1889 void eCueSheet::commitSpans()
1891 m_event(evtSpanChanged);
1894 void eCueSheet::setSkipmode(const pts_t &ratio)
1897 m_skipmode_ratio = ratio;
1899 m_event(evtSkipmode);
1902 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
1904 m_decoding_demux = demux;
1905 m_decoder = decoder;
1908 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
1910 connection = new eConnection(this, m_event.connect(event));