pass more information about why a channel alloc fails, and display proper error messa...
[enigma2.git] / lib / dvb / dvb.cpp
index 6e87585e9fe58dbdfc3ffe7f8e866ed23dc941df..0eb614db0626d34aa9181f1a0d626e16e8b9f339 100644 (file)
@@ -2,6 +2,7 @@
 #include <lib/base/filepush.h>
 #include <lib/dvb/idvb.h>
 #include <lib/dvb/dvb.h>
+#include <lib/dvb/pmt.h>
 #include <lib/dvb/sec.h>
 
 #include <errno.h>
@@ -82,6 +83,8 @@ eDVBResourceManager::eDVBResourceManager()
        eDebug("found %d adapter, %d frontends and %d demux", 
                m_adapter.size(), m_frontend.size(), m_demux.size());
 
+       eDVBCAService::registerChannelCallback(this);
+
        CONNECT(m_releaseCachedChannelTimer.timeout, eDVBResourceManager::releaseCachedChannel);
 }
 
@@ -248,12 +251,12 @@ void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
        }
 }
 
-void eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
+PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
 {
        if (!PyList_Check(list))
        {
                PyErr_SetString(PyExc_StandardError, "eDVBResourceManager::setFrontendSlotInformations argument should be a python list");
-               return;
+               return NULL;
        }
        if ((unsigned int)PyList_Size(list) != m_frontend.size())
        {
@@ -261,45 +264,58 @@ void eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
                sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations list size incorrect %d frontends avail, but %d entries in slotlist",
                        m_frontend.size(), PyList_Size(list));
                PyErr_SetString(PyExc_StandardError, blasel);
-               return;
+               return NULL;
        }
        int pos=0;
        for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
        {
                ePyObject obj = PyList_GET_ITEM(list, pos++);
-               i->m_frontend->setSlotInfo(obj);
+               if (!i->m_frontend->setSlotInfo(obj))
+                       return NULL;
        }
+       Py_RETURN_NONE;
 }
 
 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm)
 {
        ePtr<eDVBRegisteredFrontend> best;
        int bestval = 0;
+       int foundone = 0;
 
        for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
+       {
+               int c = i->m_frontend->isCompatibleWith(feparm);
+
+               if (c)  /* if we have at least one frontend which is compatible with the source, flag this. */
+                       foundone = 1;
+
                if (!i->m_inuse)
                {
-                       int c = i->m_frontend->isCompatibleWith(feparm);
                        if (c > bestval)
                        {
                                bestval = c;
                                best = i;
                        }
                }
+       }
 
        if (best)
        {
                fe = new eDVBAllocatedFrontend(best);
                return 0;
        }
-       
+
        fe = 0;
-       
-       return -1;
+
+       if (foundone)
+               return errAllSourcesBusy;
+       else
+               return errNoSourceFound;
 }
 
 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index)
 {
+       int err = errNoSourceFound;
        for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
                if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index)
                {
@@ -311,6 +327,7 @@ RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend>
                                if (satpos_depends_to_fe->m_inuse)
                                {
                                        eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!");
+                                       err = errAllSourcesBusy;
                                        goto alloc_fe_by_id_not_possible;
                                }
                        }
@@ -323,6 +340,7 @@ RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend>
                                        if (next->m_inuse)
                                        {
                                                eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
+                                               err = errAllSourcesBusy;
                                                goto alloc_fe_by_id_not_possible;
                                        }
                                        next = (eDVBRegisteredFrontend *)next->m_frontend->m_data[eDVBFrontend::LINKED_NEXT_PTR];
@@ -334,6 +352,7 @@ RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend>
                                        if (prev->m_inuse)
                                        {
                                                eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
+                                               err = errAllSourcesBusy;
                                                goto alloc_fe_by_id_not_possible;
                                        }
                                        prev = (eDVBRegisteredFrontend *)prev->m_frontend->m_data[eDVBFrontend::LINKED_PREV_PTR];
@@ -344,7 +363,7 @@ RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend>
                }
 alloc_fe_by_id_not_possible:
        fe = 0;
-       return -1;
+       return err;
 }
 
 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int cap)
@@ -442,22 +461,23 @@ RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUse
        if (!m_list)
        {
                eDebug("no channel list set!");
-               return -ENOENT;
+               return errNoChannelList;
        }
 
        ePtr<iDVBFrontendParameters> feparm;
        if (m_list->getChannelFrontendData(channelid, feparm))
        {
                eDebug("channel not found!");
-               return -ENOENT;
+               return errChannelNotInList;
        }
 
        /* allocate a frontend. */
        
        ePtr<eDVBAllocatedFrontend> fe;
-       
-       if (allocateFrontend(fe, feparm))
-               return errNoFrontend;
+
+       int err = allocateFrontend(fe, feparm);
+       if (err)
+               return err;
 
        RESULT res;
        ePtr<eDVBChannel> ch;
@@ -517,9 +537,10 @@ RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, in
                m_releaseCachedChannelTimer.stop();
        }
 
-       if (allocateFrontendByIndex(fe, slot_index))
-               return errNoFrontend;
-       
+       int err = allocateFrontendByIndex(fe, slot_index);
+       if (err)
+               return err;
+
        eDVBChannel *ch;
        ch = new eDVBChannel(this, fe);
 
@@ -592,14 +613,41 @@ int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &fepar
        return bestval;
 }
 
+int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
+{
+       if (channellist)
+       {
+               ePtr<iDVBFrontendParameters> feparm;
+               if (!channellist->getChannelFrontendData(chid, feparm))
+               {
+                       int system;
+                       if (!feparm->getSystem(system))
+                       {
+                               switch(system)
+                               {
+                                       case iDVBFrontend::feSatellite:
+                                               return 50000;
+                                       case iDVBFrontend::feCable:
+                                               return 40000;
+                                       case iDVBFrontend::feTerrestrial:
+                                               return 30000;
+                                       default:
+                                               break;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore)
 {
-       int ret=30000;
+       int ret=0;
        if (m_cached_channel)
        {
                eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
                if(channelid==cache_chan->getChannelID())
-                       return ret;
+                       return tuner_type_channel_default(m_list, channelid);
        }
 
                /* first, check if a channel is already existing. */
@@ -610,7 +658,7 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
                if (i->m_channel_id == channelid)
                {
 //                     eDebug("found shared channel..");
-                       return ret;
+                       return tuner_type_channel_default(m_list, channelid);
                }
        }
 
@@ -680,14 +728,12 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
        if (!m_list)
        {
                eDebug("no channel list set!");
-               ret = 0;
                goto error;
        }
 
        if (m_list->getChannelFrontendData(channelid, feparm))
        {
                eDebug("channel not found!");
-               ret = 0;
                goto error;
        }
 
@@ -920,6 +966,7 @@ void eDVBChannel::cueSheetEvent(int event)
                                m_skipmode_n = m_skipmode_m = 0;
                        }
                }
+               ASSERT(m_pvr_thread);
                m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
                eDebug("flush pvr");
                flushPVR(m_cue->m_decoding_demux);
@@ -1057,7 +1104,7 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                        pts_t nextap;
                        if (m_tstools.getNextAccessPoint(nextap, now, pts))
                        {
-                               pts = now;
+                               pts = now - 90000; /* approx. 1s */
                                eDebug("AP relative seeking failed!");
                        } else
                        {
@@ -1102,7 +1149,7 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                        {
                                        /* in normal playback, just start at the next zone. */
                                start = i->first;
-                               
+
                                        /* size is not 64bit! */
                                if ((i->second - i->first) > max)
                                        size = max;
@@ -1123,8 +1170,11 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                                --i;
                                eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
                                size_t len;
-                               
-                               if ((i->second - i->first) > max)
+
+                               aligned_start = align(i->first, blocksize);
+                               aligned_end = align(i->second, blocksize);
+
+                               if ((aligned_end - aligned_start) > max)
                                        len = max;
                                else
                                        len = aligned_end - aligned_start;
@@ -1132,19 +1182,19 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                                start = aligned_end - len;
                                eDebug("skipping to %llx, %d", start, len);
                        }
-                       
+
                        eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
                        return;
                }
        }
-       
+
        if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
        {
                eDebug("reached SOF");
                m_skipmode_m = 0;
                m_pvr_thread->sendEvent(eFilePushThread::evtUser);
        }
-       
+
        start = current_offset;
        size = max;