fix comment
[enigma2.git] / lib / dvb / dvb.cpp
index f163230e3b8bf12b479276f4cfd75259a12d2cf7..4dd5526a2d16baf0033e6d5f8d4f5618d9e9d08e 100644 (file)
@@ -4,6 +4,7 @@
 #include <lib/dvb/dvb.h>
 #include <lib/dvb/pmt.h>
 #include <lib/dvb/sec.h>
 #include <lib/dvb/dvb.h>
 #include <lib/dvb/pmt.h>
 #include <lib/dvb/sec.h>
+#include <lib/dvb/specs.h>
 
 #include <errno.h>
 #include <sys/types.h>
 
 #include <errno.h>
 #include <sys/types.h>
@@ -61,7 +62,7 @@ ePtr<eDVBResourceManager> NewResourceManagerPtr(void)
 }
 
 eDVBResourceManager::eDVBResourceManager()
 }
 
 eDVBResourceManager::eDVBResourceManager()
-       :m_releaseCachedChannelTimer(eApp)
+       :m_releaseCachedChannelTimer(eTimer::create(eApp))
 {
        avail = 1;
        busy = 0;
 {
        avail = 1;
        busy = 0;
@@ -69,24 +70,24 @@ eDVBResourceManager::eDVBResourceManager()
 
        if (!instance)
                instance = this;
 
        if (!instance)
                instance = this;
-               
+
                /* search available adapters... */
 
                // add linux devices
                /* search available adapters... */
 
                // add linux devices
-       
+
        int num_adapter = 0;
        while (eDVBAdapterLinux::exist(num_adapter))
        {
                addAdapter(new eDVBAdapterLinux(num_adapter));
                num_adapter++;
        }
        int num_adapter = 0;
        while (eDVBAdapterLinux::exist(num_adapter))
        {
                addAdapter(new eDVBAdapterLinux(num_adapter));
                num_adapter++;
        }
-       
-       eDebug("found %d adapter, %d frontends(%d sim) and %d demux", 
+
+       eDebug("found %d adapter, %d frontends(%d sim) and %d demux",
                m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size());
 
        eDVBCAService::registerChannelCallback(this);
 
                m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size());
 
        eDVBCAService::registerChannelCallback(this);
 
-       CONNECT(m_releaseCachedChannelTimer.timeout, eDVBResourceManager::releaseCachedChannel);
+       CONNECT(m_releaseCachedChannelTimer->timeout, eDVBResourceManager::releaseCachedChannel);
 }
 
 void eDVBResourceManager::feStateChanged()
 }
 
 void eDVBResourceManager::feStateChanged()
@@ -103,7 +104,7 @@ eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
 {
                // scan frontends
        int num_fe = 0;
 {
                // scan frontends
        int num_fe = 0;
-       
+
        eDebug("scanning for frontends..");
        while (1)
        {
        eDebug("scanning for frontends..");
        while (1)
        {
@@ -132,7 +133,7 @@ eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
                }
                ++num_fe;
        }
                }
                ++num_fe;
        }
-       
+
                // scan demux
        int num_demux = 0;
        while (1)
                // scan demux
        int num_demux = 0;
        while (1)
@@ -147,10 +148,10 @@ eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
                if (stat(filename, &s))
                        break;
                ePtr<eDVBDemux> demux;
                if (stat(filename, &s))
                        break;
                ePtr<eDVBDemux> demux;
-               
+
                demux = new eDVBDemux(m_nr, num_demux);
                m_demux.push_back(demux);
                demux = new eDVBDemux(m_nr, num_demux);
                m_demux.push_back(demux);
-                       
+
                ++num_demux;
        }
 }
                ++num_demux;
        }
 }
@@ -168,12 +169,12 @@ RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
                --nr;
                ++i;
        }
                --nr;
                ++i;
        }
-       
+
        if (i != m_demux.end())
                demux = *i;
        else
                return -1;
        if (i != m_demux.end())
                demux = *i;
        else
                return -1;
-               
+
        return 0;
 }
 
        return 0;
 }
 
@@ -190,12 +191,12 @@ RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr, bool simula
                --nr;
                ++i;
        }
                --nr;
                ++i;
        }
-       
+
        if (i != m_frontend.end())
                fe = *i;
        else
                return -1;
        if (i != m_frontend.end())
                fe = *i;
        else
                return -1;
-               
+
        return 0;
 }
 
        return 0;
 }
 
@@ -223,9 +224,9 @@ void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
 {
        int num_fe = adapter->getNumFrontends();
        int num_demux = adapter->getNumDemux();
 {
        int num_fe = adapter->getNumFrontends();
        int num_demux = adapter->getNumDemux();
-       
+
        m_adapter.push_back(adapter);
        m_adapter.push_back(adapter);
-       
+
        int i;
        for (i=0; i<num_demux; ++i)
        {
        int i;
        for (i=0; i<num_demux; ++i)
        {
@@ -425,9 +426,9 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBA
 
        if (i == m_demux.end())
                return -1;
 
        if (i == m_demux.end())
                return -1;
-       
+
        ePtr<eDVBRegisteredDemux> unused;
        ePtr<eDVBRegisteredDemux> unused;
-       
+
        if (m_demux.size() < 5)
        {
                /* FIXME: hardware demux policy */
        if (m_demux.size() < 5)
        {
                /* FIXME: hardware demux policy */
@@ -443,14 +444,14 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBA
                for (; i != m_demux.end(); ++i, ++n)
                {
                        int is_decode = n < 2;
                for (; i != m_demux.end(); ++i, ++n)
                {
                        int is_decode = n < 2;
-               
+
                        int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
                        int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
-               
+
                        if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
                        {
                                if ((cap & iDVBChannel::capDecode) && !is_decode)
                                        continue;
                        if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
                        {
                                if ((cap & iDVBChannel::capDecode) && !is_decode)
                                        continue;
-                               unused = i;     
+                               unused = i;
                                break;
                        }
                }
                                break;
                        }
                }
@@ -466,7 +467,7 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBA
                                        if (!unused)
                                                unused = i;
                                }
                                        if (!unused)
                                                unused = i;
                                }
-                               else if (i->m_adapter == fe->m_adapter && 
+                               else if (i->m_adapter == fe->m_adapter &&
                                    i->m_demux->getSource() == fe->m_frontend->getDVBID())
                                {
                                        demux = new eDVBAllocatedDemux(i);
                                    i->m_demux->getSource() == fe->m_frontend->getDVBID())
                                {
                                        demux = new eDVBAllocatedDemux(i);
@@ -541,7 +542,7 @@ RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUse
                }
                m_cached_channel_state_changed_conn.disconnect();
                m_cached_channel=0;
                }
                m_cached_channel_state_changed_conn.disconnect();
                m_cached_channel=0;
-               m_releaseCachedChannelTimer.stop();
+               m_releaseCachedChannelTimer->stop();
        }
 
        eDebugNoSimulate("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
        }
 
        eDebugNoSimulate("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
@@ -572,7 +573,7 @@ RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUse
        }
 
        /* allocate a frontend. */
        }
 
        /* allocate a frontend. */
-       
+
        ePtr<eDVBAllocatedFrontend> fe;
 
        int err = allocateFrontend(fe, feparm, simulate);
        ePtr<eDVBAllocatedFrontend> fe;
 
        int err = allocateFrontend(fe, feparm, simulate);
@@ -580,8 +581,7 @@ RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUse
                return err;
 
        RESULT res;
                return err;
 
        RESULT res;
-       ePtr<eDVBChannel> ch;
-       ch = new eDVBChannel(this, fe);
+       ePtr<eDVBChannel> ch = new eDVBChannel(this, fe);
 
        res = ch->setChannel(channelid, feparm);
        if (res)
 
        res = ch->setChannel(channelid, feparm);
        if (res)
@@ -612,13 +612,13 @@ void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
                case iDVBChannel::state_ok:
                {
                        eDebug("stop release channel timer");
                case iDVBChannel::state_ok:
                {
                        eDebug("stop release channel timer");
-                       m_releaseCachedChannelTimer.stop();
+                       m_releaseCachedChannelTimer->stop();
                        break;
                }
                case iDVBChannel::state_last_instance:
                {
                        eDebug("start release channel timer");
                        break;
                }
                case iDVBChannel::state_last_instance:
                {
                        eDebug("start release channel timer");
-                       m_releaseCachedChannelTimer.start(3000, true);
+                       m_releaseCachedChannelTimer->start(3000, true);
                        break;
                }
                default: // ignore all other events
                        break;
                }
                default: // ignore all other events
@@ -640,17 +640,14 @@ RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, in
        {
                m_cached_channel_state_changed_conn.disconnect();
                m_cached_channel=0;
        {
                m_cached_channel_state_changed_conn.disconnect();
                m_cached_channel=0;
-               m_releaseCachedChannelTimer.stop();
+               m_releaseCachedChannelTimer->stop();
        }
 
        int err = allocateFrontendByIndex(fe, slot_index);
        if (err)
                return err;
 
        }
 
        int err = allocateFrontendByIndex(fe, slot_index);
        if (err)
                return err;
 
-       eDVBChannel *ch;
-       ch = new eDVBChannel(this, fe);
-
-       channel = ch;
+       channel = new eDVBChannel(this, fe);
        return 0;
 }
 
        return 0;
 }
 
@@ -659,17 +656,14 @@ RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
 {
        ePtr<eDVBAllocatedDemux> demux;
 
 {
        ePtr<eDVBAllocatedDemux> demux;
 
-       if (m_cached_channel && m_releaseCachedChannelTimer.isActive())
+       if (m_cached_channel && m_releaseCachedChannelTimer->isActive())
        {
                m_cached_channel_state_changed_conn.disconnect();
                m_cached_channel=0;
        {
                m_cached_channel_state_changed_conn.disconnect();
                m_cached_channel=0;
-               m_releaseCachedChannelTimer.stop();
+               m_releaseCachedChannelTimer->stop();
        }
 
        }
 
-       eDVBChannel *ch;
-       ch = new eDVBChannel(this, 0);
-
-       channel = ch;
+       channel = new eDVBChannel(this, 0);
        return 0;
 }
 
        return 0;
 }
 
@@ -720,12 +714,13 @@ RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &
        return 0;
 }
 
        return 0;
 }
 
-int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm)
+int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm, bool simulate)
 {
 {
+       eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
        ePtr<eDVBRegisteredFrontend> best;
        int bestval = 0;
 
        ePtr<eDVBRegisteredFrontend> best;
        int bestval = 0;
 
-       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
                if (!i->m_inuse)
                {
                        int c = i->m_frontend->isCompatibleWith(feparm);
                if (!i->m_inuse)
                {
                        int c = i->m_frontend->isCompatibleWith(feparm);
@@ -762,10 +757,11 @@ int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBCha
        return 0;
 }
 
        return 0;
 }
 
-int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore)
+int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore, bool simulate)
 {
 {
+       std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
        int ret=0;
        int ret=0;
-       if (m_cached_channel)
+       if (!simulate && m_cached_channel)
        {
                eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
                if(channelid==cache_chan->getChannelID())
        {
                eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
                if(channelid==cache_chan->getChannelID())
@@ -774,7 +770,7 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
 
                /* first, check if a channel is already existing. */
 //     eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
 
                /* 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<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
+       for (std::list<active_channel>::iterator i(active_channels.begin()); i != 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("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)
@@ -787,8 +783,9 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
        int *decremented_cached_channel_fe_usecount=NULL,
                *decremented_fe_usecount=NULL;
 
        int *decremented_cached_channel_fe_usecount=NULL,
                *decremented_fe_usecount=NULL;
 
-       for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
+       for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
        {
        {
+               eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
 //             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 == ignore)
                {
 //             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 == ignore)
                {
@@ -802,7 +799,7 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
                                ePtr<iDVBFrontend> fe;
                                if (!i->m_channel->getFrontend(fe))
                                {
                                ePtr<iDVBFrontend> fe;
                                if (!i->m_channel->getFrontend(fe))
                                {
-                                       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(m_frontend.begin()); ii != m_frontend.end(); ++ii)
+                                       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
                                        {
                                                if ( &(*fe) == &(*ii->m_frontend) )
                                                {
                                        {
                                                if ( &(*fe) == &(*ii->m_frontend) )
                                                {
@@ -829,7 +826,8 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
                                ePtr<iDVBFrontend> fe;
                                if (!channel->getFrontend(fe))
                                {
                                ePtr<iDVBFrontend> fe;
                                if (!channel->getFrontend(fe))
                                {
-                                       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(m_frontend.begin()); ii != m_frontend.end(); ++ii)
+                                       eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
+                                       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
                                        {
                                                if ( &(*fe) == &(*ii->m_frontend) )
                                                {
                                        {
                                                if ( &(*fe) == &(*ii->m_frontend) )
                                                {
@@ -859,7 +857,7 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
                goto error;
        }
 
                goto error;
        }
 
-       ret = canAllocateFrontend(feparm);
+       ret = canAllocateFrontend(feparm, simulate);
 
 error:
        if (decremented_fe_usecount)
 
 error:
        if (decremented_fe_usecount)
@@ -976,7 +974,7 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s
        }
 #endif
 
        }
 #endif
 
-#if 1 /* not yet */
+#if 1 /* This codepath is required on Broadcom-based Dreamboxes (DM800, DM8000) and strips away non-I-frames. */
        if (!m_iframe_search)
                return len;
 
        if (!m_iframe_search)
                return len;
 
@@ -985,7 +983,7 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s
 //     eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
 
        unsigned char *d = data;
 //     eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
 
        unsigned char *d = data;
-       while ((d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
+       while ((d + 3 < data + len) && (d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
        {
                int offset = d - data;
                int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
        {
                int offset = d - data;
                int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
@@ -1001,7 +999,7 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s
 
                        if (m_iframe_state == 1)
                        {
 
                        if (m_iframe_state == 1)
                        {
-                                       /* we are allowing data, and stop allowing data on the next frame. 
+                                       /* we are allowing data, and stop allowing data on the next frame.
                                           we now found a frame. so stop here. */
                                memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
                                current_span_remaining = 0;
                                           we now found a frame. so stop here. */
                                memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
                                current_span_remaining = 0;
@@ -1047,7 +1045,6 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s
                        d += 4;
                } else
                        d += 4; /* ignore */
                        d += 4;
                } else
                        d += 4; /* ignore */
-
        }
 
        if (m_iframe_state == 1)
        }
 
        if (m_iframe_state == 1)
@@ -1066,9 +1063,9 @@ eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *fronte
        m_frontend = frontend;
 
        m_pvr_thread = 0;
        m_frontend = frontend;
 
        m_pvr_thread = 0;
-       
+
        m_skipmode_n = m_skipmode_m = 0;
        m_skipmode_n = m_skipmode_m = 0;
-       
+
        if (m_frontend)
                m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
 }
        if (m_frontend)
                m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
 }
@@ -1084,14 +1081,14 @@ eDVBChannel::~eDVBChannel()
 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
 {
        int state, ourstate = 0;
 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
 {
        int state, ourstate = 0;
-       
+
                /* if we are already in shutdown, don't change state. */
        if (m_state == state_release)
                return;
                /* if we are already in shutdown, don't change state. */
        if (m_state == state_release)
                return;
-       
+
        if (fe->getState(state))
                return;
        if (fe->getState(state))
                return;
-       
+
        if (state == iDVBFrontend::stateLock)
        {
                eDebug("OURSTATE: ok");
        if (state == iDVBFrontend::stateLock)
        {
                eDebug("OURSTATE: ok");
@@ -1120,7 +1117,7 @@ void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
                ourstate = state_failed;
        } else
                eFatal("state unknown");
                ourstate = state_failed;
        } else
                eFatal("state unknown");
-       
+
        if (ourstate != m_state)
        {
                m_state = ourstate;
        if (ourstate != m_state)
        {
                m_state = ourstate;
@@ -1237,7 +1234,7 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
        const int blocksize = 188;
        unsigned int max = align(10*1024*1024, blocksize);
        current_offset = align(current_offset, blocksize);
        const int blocksize = 188;
        unsigned int max = align(10*1024*1024, blocksize);
        current_offset = align(current_offset, blocksize);
-       
+
        if (!m_cue)
        {
                eDebug("no cue sheet. forcing normal play");
        if (!m_cue)
        {
                eDebug("no cue sheet. forcing normal play");
@@ -1308,7 +1305,7 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                                continue;
                        }
                }
                                continue;
                        }
                }
-               
+
                if (relative == 1) /* pts relative */
                {
                        pts += now;
                if (relative == 1) /* pts relative */
                {
                        pts += now;
@@ -1319,7 +1316,7 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                if (relative != 2)
                        if (pts < 0)
                                pts = 0;
                if (relative != 2)
                        if (pts < 0)
                                pts = 0;
-               
+
                if (relative == 2) /* AP relative */
                {
                        eDebug("AP relative seeking: %lld, at %lld", pts, now);
                if (relative == 2) /* AP relative */
                {
                        eDebug("AP relative seeking: %lld, at %lld", pts, now);
@@ -1334,7 +1331,7 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                                pts = nextap;
                        }
                }
                                pts = nextap;
                        }
                }
-               
+
                off_t offset = 0;
                if (m_tstools.getOffset(offset, pts))
                {
                off_t offset = 0;
                if (m_tstools.getOffset(offset, pts))
                {
@@ -1352,7 +1349,7 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
        {
                long long aligned_start = align(i->first, blocksize);
                long long aligned_end = align(i->second, blocksize);
        {
                long long aligned_start = align(i->first, blocksize);
                long long aligned_end = align(i->second, blocksize);
-       
+
                if ((current_offset >= aligned_start) && (current_offset < aligned_end))
                {
                        start = current_offset;
                if ((current_offset >= aligned_start) && (current_offset < aligned_end))
                {
                        start = current_offset;
@@ -1451,7 +1448,7 @@ RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontend
 {
        if (m_channel_id)
                m_mgr->removeChannel(this);
 {
        if (m_channel_id)
                m_mgr->removeChannel(this);
-               
+
        if (!channelid)
                return 0;
 
        if (!channelid)
                return 0;
 
@@ -1460,7 +1457,7 @@ RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontend
                eDebug("no frontend to tune!");
                return -ENODEV;
        }
                eDebug("no frontend to tune!");
                return -ENODEV;
        }
-       
+
        m_channel_id = channelid;
        m_mgr->addChannel(channelid, this);
        m_state = state_tuning;
        m_channel_id = channelid;
        m_mgr->addChannel(channelid, this);
        m_state = state_tuning;
@@ -1468,14 +1465,14 @@ RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontend
        int res;
        res = m_frontend->get().tune(*feparm);
        m_current_frontend_parameters = feparm;
        int res;
        res = m_frontend->get().tune(*feparm);
        m_current_frontend_parameters = feparm;
-       
+
        if (res)
        {
                m_state = state_release;
                m_stateChanged(this);
                return res;
        }
        if (res)
        {
                m_state = state_release;
                m_stateChanged(this);
                return res;
        }
-       
+
        return 0;
 }
 
        return 0;
 }
 
@@ -1502,24 +1499,79 @@ RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
        return -1;
 }
 
        return -1;
 }
 
+void eDVBChannel::SDTready(int result)
+{
+       ePyObject args = PyTuple_New(2), ret;
+       bool ok=false;
+       if (!result)
+       {
+               for (std::vector<ServiceDescriptionSection*>::const_iterator i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
+               {
+                       ok = true;
+                       PyTuple_SET_ITEM(args, 0, PyInt_FromLong((*i)->getTransportStreamId()));
+                       PyTuple_SET_ITEM(args, 1, PyInt_FromLong((*i)->getOriginalNetworkId()));
+                       break;
+               }
+       }
+       if (!ok)
+       {
+               PyTuple_SET_ITEM(args, 0, Py_None);
+               PyTuple_SET_ITEM(args, 1, Py_None);
+               Py_INCREF(Py_None);
+               Py_INCREF(Py_None);
+       }
+       ret = PyObject_CallObject(m_tsid_onid_callback, args);
+       if (ret)
+               Py_DECREF(ret);
+       Py_DECREF(args);
+       Py_DECREF(m_tsid_onid_callback);
+       m_tsid_onid_callback = ePyObject();
+       m_tsid_onid_demux = 0;
+       m_SDT = 0;
+}
+
+RESULT eDVBChannel::requestTsidOnid(ePyObject callback)
+{
+       if (PyCallable_Check(callback))
+       {
+               if (!getDemux(m_tsid_onid_demux, 0))
+               {
+                       m_SDT = new eTable<ServiceDescriptionSection>;
+                       CONNECT(m_SDT->tableReady, eDVBChannel::SDTready);
+                       if (m_SDT->start(m_tsid_onid_demux, eDVBSDTSpec()))
+                       {
+                               m_tsid_onid_demux = 0;
+                               m_SDT = 0;
+                       }
+                       else
+                       {
+                               Py_INCREF(callback);
+                               m_tsid_onid_callback = callback;
+                               return 0;
+                       }
+               }
+       }
+       return -1;
+}
+
 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
 {
        ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
 {
        ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
-       
+
        if (!our_demux)
        {
                demux = 0;
        if (!our_demux)
        {
                demux = 0;
-               
+
                if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
                        return -1;
        }
                if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
                        return -1;
        }
-       
+
        demux = *our_demux;
                /* don't hold a reference to the decoding demux, we don't need it. */
        demux = *our_demux;
                /* don't hold a reference to the decoding demux, we don't need it. */
-               
+
                /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
                /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
-                  the refcount is lost. thus, decoding demuxes are never allocated. 
-                  
+                  the refcount is lost. thus, decoding demuxes are never allocated.
+
                   this poses a big problem for PiP. */
        if (cap & capDecode)
                our_demux = 0;
                   this poses a big problem for PiP. */
        if (cap & capDecode)
                our_demux = 0;
@@ -1552,12 +1604,12 @@ RESULT eDVBChannel::playFile(const char *file)
                delete m_pvr_thread;
                m_pvr_thread = 0;
        }
                delete m_pvr_thread;
                m_pvr_thread = 0;
        }
-       
+
        m_tstools.openFile(file);
        m_tstools.openFile(file);
-       
+
                /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
                   THEN DO A REAL FIX HERE! */
                /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
                   THEN DO A REAL FIX HERE! */
-       
+
                /* (this codepath needs to be improved anyway.) */
 #if HAVE_DVB_API_VERSION < 3
        m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
                /* (this codepath needs to be improved anyway.) */
 #if HAVE_DVB_API_VERSION < 3
        m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
@@ -1618,11 +1670,11 @@ RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, in
 {
        if (!decoding_demux)
                return -1;
 {
        if (!decoding_demux)
                return -1;
-       
+
        pts_t now;
        pts_t now;
-       
+
        int r;
        int r;
-       
+
        if (mode == 0) /* demux */
        {
                r = decoding_demux->getSTC(now, 0);
        if (mode == 0) /* demux */
        {
                r = decoding_demux->getSTC(now, 0);
@@ -1633,7 +1685,7 @@ RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, in
                }
        } else
                now = pos; /* fixup supplied */
                }
        } else
                now = pos; /* fixup supplied */
-       
+
        off_t off = 0; /* TODO: fixme */
        r = m_tstools.fixupPTS(off, now);
        if (r)
        off_t off = 0; /* TODO: fixme */
        r = m_tstools.fixupPTS(off, now);
        if (r)
@@ -1641,9 +1693,9 @@ RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, in
                eDebug("fixup PTS failed");
                return -1;
        }
                eDebug("fixup PTS failed");
                return -1;
        }
-       
+
        pos = now;
        pos = now;
-       
+
        return 0;
 }
 
        return 0;
 }
 
@@ -1654,7 +1706,7 @@ void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
                           a.) the filepush's internal buffer
                           b.) the PVR buffer (before demux)
                           c.) the ratebuffer (after demux)
                           a.) the filepush's internal buffer
                           b.) the PVR buffer (before demux)
                           c.) the ratebuffer (after demux)
-                          
+
                           it's important to clear them in the correct order, otherwise
                           the ratebuffer (for example) would immediately refill from
                           the not-yet-flushed PVR buffer.
                           it's important to clear them in the correct order, otherwise
                           the ratebuffer (for example) would immediately refill from
                           the not-yet-flushed PVR buffer.
@@ -1665,7 +1717,7 @@ void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
        m_pvr_thread->flush();
                /* HACK: flush PVR buffer */
        ::ioctl(m_pvr_fd_dst, 0);
        m_pvr_thread->flush();
                /* HACK: flush PVR buffer */
        ::ioctl(m_pvr_fd_dst, 0);
-       
+
                /* flush ratebuffers (video, audio) */
        if (decoding_demux)
                decoding_demux->flush();
                /* flush ratebuffers (video, audio) */
        if (decoding_demux)
                decoding_demux->flush();
@@ -1689,7 +1741,7 @@ void eCueSheet::seekTo(int relative, const pts_t &pts)
        m_lock.Unlock();
        m_event(evtSeek);
 }
        m_lock.Unlock();
        m_event(evtSeek);
 }
-       
+
 void eCueSheet::clear()
 {
        m_lock.WrLock();
 void eCueSheet::clear()
 {
        m_lock.WrLock();