[browser] add exception handling.
[vuplus_dvbapp] / lib / dvb / dvb.cpp
index 836851c..ce09603 100644 (file)
@@ -96,6 +96,10 @@ eDVBResourceManager::eDVBResourceManager()
                m_boxtype = DM800;
        else if (!strncmp(tmp, "dm500hd\n", rd))
                m_boxtype = DM500HD;
+       else if (!strncmp(tmp, "dm800se\n", rd))
+               m_boxtype = DM800SE;
+       else if (!strncmp(tmp, "dm7020hd\n", rd))
+               m_boxtype = DM7020HD;
        else {
                eDebug("boxtype detection via /proc/stb/info not possible... use fallback via demux count!\n");
                if (m_demux.size() == 3)
@@ -106,7 +110,7 @@ eDVBResourceManager::eDVBResourceManager()
                        m_boxtype = DM8000;
        }
 
-       eDebug("found %d adapter, %d frontends(%d sim) and %d demux, boxtype %d",
+       eDebug("found %zd adapter, %zd frontends(%zd sim) and %zd demux, boxtype %d",
                m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size(), m_boxtype);
 
        eDVBCAService::registerChannelCallback(this);
@@ -141,19 +145,20 @@ eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
 #endif
                if (stat(filename, &s))
                        break;
-               ePtr<eDVBFrontend> fe;
+               eDVBFrontend *fe;
 
                {
                        int ok = 0;
-                       fe = new eDVBFrontend(m_nr, num_fe, ok);
+                       fe = new eDVBFrontend(m_nr, num_fe, ok, true);
                        if (ok)
-                               m_frontend.push_back(fe);
+                               m_simulate_frontend.push_back(ePtr<eDVBFrontend>(fe));
                }
+
                {
                        int ok = 0;
-                       fe = new eDVBFrontend(m_nr, num_fe, ok, true);
+                       fe = new eDVBFrontend(m_nr, num_fe, ok, false, fe);
                        if (ok)
-                               m_simulate_frontend.push_back(fe);
+                               m_frontend.push_back(ePtr<eDVBFrontend>(fe));
                }
                ++num_fe;
        }
@@ -318,27 +323,34 @@ PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
                PyErr_SetString(PyExc_StandardError, "eDVBResourceManager::setFrontendSlotInformations argument should be a python list");
                return NULL;
        }
-       if ((unsigned int)PyList_Size(list) != m_frontend.size())
+       unsigned int assigned=0;
+       for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
        {
+               int pos=0;
+               while (pos < PyList_Size(list)) {
+                       ePyObject obj = PyList_GET_ITEM(list, pos++);
+                       if (!i->m_frontend->setSlotInfo(obj))
+                               continue;
+                       ++assigned;
+                       break;
+               }
+       }
+       if (assigned != m_frontend.size()) {
                char blasel[256];
-               sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations list size incorrect %d frontends avail, but %d entries in slotlist",
-                       m_frontend.size(), PyList_Size(list));
+               sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations .. assigned %zd socket informations, but %d registered frontends!",
+                       m_frontend.size(), assigned);
                PyErr_SetString(PyExc_StandardError, blasel);
                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++);
-               if (!i->m_frontend->setSlotInfo(obj))
-                       return NULL;
-       }
-       pos=0;
        for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_simulate_frontend.begin()); i != m_simulate_frontend.end(); ++i)
        {
-               ePyObject obj = PyList_GET_ITEM(list, pos++);
-               if (!i->m_frontend->setSlotInfo(obj))
-                       return NULL;
+               int pos=0;
+               while (pos < PyList_Size(list)) {
+                       ePyObject obj = PyList_GET_ITEM(list, pos++);
+                       if (!i->m_frontend->setSlotInfo(obj))
+                               continue;
+                       break;
+               }
        }
        Py_RETURN_NONE;
 }
@@ -455,7 +467,7 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBA
 
        ePtr<eDVBRegisteredDemux> unused;
 
-       if (m_boxtype == DM800 || m_boxtype == DM500HD) // dm800 / 500hd
+       if (m_boxtype == DM800) // dm800
        {
                cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
                for (; i != m_demux.end(); ++i, ++n)
@@ -511,32 +523,48 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBA
                        }
                }
        }
-       else if (m_boxtype == DM8000)
+       else if (m_boxtype == DM8000 || m_boxtype == DM500HD || m_boxtype == DM800SE || m_boxtype == DM7020HD)
        {
+               iDVBAdapter *adapter = fe ? fe->m_adapter : m_adapter.begin(); /* look for a demux on the same adapter as the frontend, or the first adapter for dvr playback */
+               int source = fe ? fe->m_frontend->getDVBID() : -1;
                cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
-               for (; i != m_demux.end(); ++i, ++n)
+               if (!fe)
                {
-                       if (fe)
+                       /*
+                        * For pvr playback, start with the last demux.
+                        * On some hardware, we have less ca devices than demuxes,
+                        * so we should try to leave the first demuxes for live tv,
+                        * and start with the last for pvr playback
+                        */
+                       i = m_demux.end();
+                       --i;
+               }
+               while (i != m_demux.end())
+               {
+                       if (i->m_adapter == adapter)
                        {
                                if (!i->m_inuse)
                                {
-                                       if (!unused)
-                                               unused = i;
+                                       /* mark the first unused demux, we'll use that when we do not find a better match */
+                                       if (!unused) unused = i;
                                }
-                               else if (i->m_adapter == fe->m_adapter &&
-                                   i->m_demux->getSource() == fe->m_frontend->getDVBID())
+                               else
                                {
-                                       demux = new eDVBAllocatedDemux(i);
-                                       return 0;
+                                       /* demux is in use, see if we can share it */
+                                       if (source >= 0 && i->m_demux->getSource() == source)
+                                       {
+                                               demux = new eDVBAllocatedDemux(i);
+                                               return 0;
+                                       }
                                }
                        }
-                       else if (n == 4) // always use demux4 for PVR (demux 4 can not descramble...)
+                       if (fe)
                        {
-                               if (i->m_inuse) {
-                                       demux = new eDVBAllocatedDemux(i);
-                                       return 0;
-                               }
-                               unused = i;
+                               ++i;
+                       }
+                       else
+                       {
+                               --i;
                        }
                }
        }
@@ -707,8 +735,7 @@ RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, in
        return 0;
 }
 
-
-RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
+RESULT eDVBResourceManager::allocatePVRChannel(const eDVBChannelID &channelid, eUsePtr<iDVBPVRChannel> &channel)
 {
        ePtr<eDVBAllocatedDemux> demux;
 
@@ -719,7 +746,18 @@ RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
                m_releaseCachedChannelTimer->stop();
        }
 
-       channel = new eDVBChannel(this, 0);
+       ePtr<eDVBChannel> ch = new eDVBChannel(this, 0);
+       if (channelid)
+       {
+               /*
+                * user provided a channelid, with the clear intention for
+                * this channel to be registered at the resource manager.
+                * (allowing e.g. epgcache to be started)
+                */
+               ePtr<iDVBFrontendParameters> feparm;
+               ch->setChannel(channelid, feparm);
+       }
+       channel = ch;
        return 0;
 }
 
@@ -1175,8 +1213,22 @@ void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
                }
        } else if (state == iDVBFrontend::stateFailed)
        {
+#ifdef BUILD_VUPLUS /* ikseong  */
+               if (m_current_frontend_parameters)
+               {
+                       eDebug("OURSTATE: lost lock, trying to retune");
+                       ourstate = state_tuning;
+                       m_frontend->get().tune(*m_current_frontend_parameters);
+               } 
+               else
+               {
+                       eDebug("OURSTATE: failed");
+                       ourstate = state_failed;
+               }
+#else
                eDebug("OURSTATE: failed");
                ourstate = state_failed;
+#endif         
        } else
                eFatal("state unknown");
 
@@ -1479,7 +1531,7 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                                size = max;
                        else
                                size = aligned_end - current_offset;
-                       eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
+                       eDebug("HIT, %lld < %lld < %lld, size: %zd", i->first, current_offset, i->second, size);
                        return;
                }
                if (current_offset < aligned_start)
@@ -1520,10 +1572,10 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                                        len = aligned_end - aligned_start;
 
                                start = aligned_end - len;
-                               eDebug("skipping to %llx, %d", start, len);
+                               eDebug("skipping to %llx, %zd", start, len);
                        }
 
-                       eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
+                       eDebug("result: %llx, %zx (%llx %llx)", start, size, aligned_start, aligned_end);
                        return;
                }
        }
@@ -1539,7 +1591,7 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
        {
                start = current_offset;
                size = max;
-               eDebug("NO CUESHEET. (%08llx, %d)", start, size);
+               eDebug("NO CUESHEET. (%08llx, %zd)", start, size);
        } else
        {
                start = current_offset;
@@ -1579,14 +1631,15 @@ RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontend
        if (!channelid)
                return 0;
 
+       m_channel_id = channelid;
+       m_mgr->addChannel(channelid, this);
+
        if (!m_frontend)
        {
-               eDebug("no frontend to tune!");
-               return -ENODEV;
+               /* no frontend, no need to tune (must be a streamed service) */
+               return 0;
        }
 
-       m_channel_id = channelid;
-       m_mgr->addChannel(channelid, this);
        m_state = state_tuning;
                        /* if tuning fails, shutdown the channel immediately. */
        int res;
@@ -1697,6 +1750,12 @@ RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
 {
        ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
 
+       if (m_frontend == NULL)
+       {
+               /* in dvr mode, we have to stick to a single demux (the one connected to our dvr device) */
+               our_demux = m_decoder_demux ? m_decoder_demux : m_demux;
+       }
+
        if (!our_demux)
        {
                demux = 0;
@@ -1743,6 +1802,20 @@ RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> &p
 
 RESULT eDVBChannel::playFile(const char *file)
 {
+       eRawFile *f = new eRawFile();
+       ePtr<iTsSource> source = f;
+
+       if (f->open(file) < 0)
+       {
+               eDebug("can't open PVR file %s (%m)", file);
+               return -ENOENT;
+       }
+
+       return playSource(source, file);
+}
+
+RESULT eDVBChannel::playSource(ePtr<iTsSource> &source, const char *streaminfo_file)
+{
        ASSERT(!m_frontend);
        if (m_pvr_thread)
        {
@@ -1751,7 +1824,13 @@ RESULT eDVBChannel::playFile(const char *file)
                m_pvr_thread = 0;
        }
 
-       m_tstools.openFile(file);
+       if (!source->valid())
+       {
+               eDebug("PVR source is not valid!");
+               return -ENOENT;
+       }
+
+       m_tstools.setSource(source, streaminfo_file);
 
                /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
                   THEN DO A REAL FIX HERE! */
@@ -1761,32 +1840,39 @@ RESULT eDVBChannel::playFile(const char *file)
                /* (this codepath needs to be improved anyway.) */
 #if HAVE_DVB_API_VERSION < 3
                m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
-#else
-               m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
-#endif
                if (m_pvr_fd_dst < 0)
                {
-                       eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
+                       eDebug("can't open /dev/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
+                       return -ENODEV;
+               }
+#else
+               ePtr<eDVBAllocatedDemux> &demux = m_demux ? m_demux : m_decoder_demux;
+               if (demux)
+               {
+                       m_pvr_fd_dst = demux->get().openDVR(O_WRONLY);
+                       if (m_pvr_fd_dst < 0)
+                       {
+                               eDebug("can't open /dev/dvb/adapterX/dvrX - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
+                               return -ENODEV;
+                       }
+               }
+               else
+               {
+                       eDebug("no demux allocated yet.. so its not possible to open the dvr device!!");
                        return -ENODEV;
                }
+#endif
        }
 
        m_pvr_thread = new eDVBChannelFilePush();
        m_pvr_thread->enablePVRCommit(1);
-       m_pvr_thread->setStreamMode(1);
+       /* If the source specifies a length, it's a file. If not, it's a stream */
+       m_pvr_thread->setStreamMode(source->length() <= 0);
        m_pvr_thread->setScatterGather(this);
 
        m_event(this, evtPreStart);
 
-       if (m_pvr_thread->start(file, m_pvr_fd_dst))
-       {
-               delete m_pvr_thread;
-               m_pvr_thread = 0;
-               ::close(m_pvr_fd_dst);
-               m_pvr_fd_dst = -1;
-               eDebug("can't open PVR file %s (%m)", file);
-               return -ENOENT;
-       }
+       m_pvr_thread->start(source, m_pvr_fd_dst);
        CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
 
        m_state = state_ok;
@@ -1795,7 +1881,7 @@ RESULT eDVBChannel::playFile(const char *file)
        return 0;
 }
 
-void eDVBChannel::stopFile()
+void eDVBChannel::stopSource()
 {
        if (m_pvr_thread)
        {
@@ -1805,6 +1891,13 @@ void eDVBChannel::stopFile()
        }
        if (m_pvr_fd_dst >= 0)
                ::close(m_pvr_fd_dst);
+       ePtr<iTsSource> d;
+       m_tstools.setSource(d);
+}
+
+void eDVBChannel::stopFile()
+{
+       stopSource();
 }
 
 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)