reset frontend type on tuner type change also on simulated tuner
[enigma2.git] / lib / dvb / dvb.cpp
index f0186de70b24a84c529b8aaa6e86ad63f5f3d99a..0b1bdc2c2a5b2d3c21be82fc4a56c2345b568731 100644 (file)
@@ -82,8 +82,36 @@ eDVBResourceManager::eDVBResourceManager()
                num_adapter++;
        }
 
-       eDebug("found %d adapter, %d frontends(%d sim) and %d demux",
-               m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size());
+       int fd = open("/proc/stb/info/model", O_RDONLY);
+       char tmp[255];
+       int rd = fd >= 0 ? read(fd, tmp, 255) : 0;
+       if (fd >= 0)
+               close(fd);
+
+       if (!strncmp(tmp, "dm7025\n", rd))
+               m_boxtype = DM7025;
+       else if (!strncmp(tmp, "dm8000\n", rd))
+               m_boxtype = DM8000;
+       else if (!strncmp(tmp, "dm800\n", rd))
+               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)
+                       m_boxtype = DM800;
+               else if (m_demux.size() < 5)
+                       m_boxtype = DM7025;
+               else
+                       m_boxtype = DM8000;
+       }
+
+       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);
 
@@ -117,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;
        }
@@ -294,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;
 }
@@ -414,7 +450,9 @@ alloc_fe_by_id_not_possible:
        return err;
 }
 
-RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int cap)
+#define capHoldDecodeReference 64
+
+RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int &cap)
 {
                /* find first unused demux which is on same adapter as frontend (or any, if PVR)
                   never use the first one unless we need a decoding demux. */
@@ -429,7 +467,36 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBA
 
        ePtr<eDVBRegisteredDemux> unused;
 
-       if (m_demux.size() < 5)
+       if (m_boxtype == DM800) // dm800
+       {
+               cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
+               for (; i != m_demux.end(); ++i, ++n)
+               {
+                       if (!i->m_inuse)
+                       {
+                               if (!unused)
+                                       unused = i;
+                       }
+                       else
+                       {
+                               if (fe)
+                               {
+                                       if (i->m_adapter == fe->m_adapter && 
+                                           i->m_demux->getSource() == fe->m_frontend->getDVBID())
+                                       {
+                                               demux = new eDVBAllocatedDemux(i);
+                                               return 0;
+                                       }
+                               }
+                               else if (i->m_demux->getSource() == -1) // PVR
+                               {
+                                       demux = new eDVBAllocatedDemux(i);
+                                       return 0;
+                               }
+                       }
+               }
+       }
+       else if (m_boxtype == DM7025) // ATI
        {
                /* FIXME: hardware demux policy */
                if (!(cap & iDVBChannel::capDecode))
@@ -456,8 +523,9 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBA
                        }
                }
        }
-       else // we asume dm8000
+       else if (m_boxtype == DM8000 || m_boxtype == DM500HD || m_boxtype == DM800SE || m_boxtype == DM7020HD)
        {
+               cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
                for (; i != m_demux.end(); ++i, ++n)
                {
                        if (fe)
@@ -1068,6 +1136,7 @@ eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *fronte
        m_frontend = frontend;
 
        m_pvr_thread = 0;
+       m_pvr_fd_dst = -1;
 
        m_skipmode_n = m_skipmode_m = m_skipmode_frames = 0;
 
@@ -1267,16 +1336,6 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                return;
        }
 
-       m_cue->m_lock.RdLock();
-       if (!m_cue->m_decoding_demux)
-       {
-               start = current_offset;
-               size = max;
-               eDebug("getNextSourceSpan, no decoding demux. forcing normal play");
-               m_cue->m_lock.Unlock();
-               return;
-       }
-
        if (m_skipmode_n)
        {
                eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames);
@@ -1284,7 +1343,6 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
        }
 
        eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
-       
        int frame_skip_success = 0;
 
        if (m_skipmode_m)
@@ -1329,6 +1387,8 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                }
        }
 
+       m_cue->m_lock.RdLock();
+
        while (!m_cue->m_seek_requests.empty())
        {
                std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
@@ -1353,6 +1413,13 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                                eDebug("decoder getPTS failed, can't seek relative");
                                continue;
                        }
+                       if (!m_cue->m_decoding_demux)
+                       {
+                               eDebug("getNextSourceSpan, no decoding demux. couldn't seek to %llx... ignore request!", pts);
+                               start = current_offset;
+                               size = max;
+                               continue;
+                       }
                        if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
                        {
                                eDebug("seekTo: getCurrentPosition failed!");
@@ -1405,12 +1472,7 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off
                        continue;
                }
                
-               size_t iframe_len;
-                       /* try to align to iframe */
-               int direction = pts < 0 ? -1 : 1;
-               m_tstools.findFrame(offset, iframe_len, direction);
-
-               eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx (skipped additional %d frames due to iframe re-align)", relative, pts, offset, direction);
+               eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
                current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
        }
 
@@ -1429,7 +1491,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)
@@ -1470,10 +1532,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;
                }
        }
@@ -1489,7 +1551,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;
@@ -1607,6 +1669,18 @@ void eDVBChannel::SDTready(int result)
        m_SDT = 0;
 }
 
+int eDVBChannel::reserveDemux()
+{
+       ePtr<iDVBDemux> dmx;
+       if (!getDemux(dmx, 0))
+       {
+               uint8_t id;
+               if (!dmx->getCADemuxID(id))
+                       return id;
+       }
+       return -1;
+}
+
 RESULT eDVBChannel::requestTsidOnid(ePyObject callback)
 {
        if (PyCallable_Check(callback))
@@ -1641,17 +1715,24 @@ RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
 
                if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
                        return -1;
-       }
 
-       demux = *our_demux;
+               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',
                   the refcount is lost. thus, decoding demuxes are never allocated.
 
                   this poses a big problem for PiP. */
-       if (cap & capDecode)
-               our_demux = 0;
+
+               if (cap & capHoldDecodeReference) // this is set in eDVBResourceManager::allocateDemux for Dm500HD/DM800 and DM8000
+                       ;
+               else if (cap & capDecode)
+                       our_demux = 0;
+       }
+       else
+               demux = *our_demux;
+
        return 0;
 }
 
@@ -1673,6 +1754,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)
@@ -1682,21 +1777,44 @@ 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! */
 
+       if (m_pvr_fd_dst < 0)
+       {
                /* (this codepath needs to be improved anyway.) */
 #if HAVE_DVB_API_VERSION < 3
-       m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
+               m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
+               if (m_pvr_fd_dst < 0)
+               {
+                       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
-       m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
+               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
-       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.
-               return -ENODEV;
        }
 
        m_pvr_thread = new eDVBChannelFilePush();
@@ -1704,13 +1822,9 @@ RESULT eDVBChannel::playFile(const char *file)
        m_pvr_thread->setStreamMode(1);
        m_pvr_thread->setScatterGather(this);
 
-       if (m_pvr_thread->start(file, m_pvr_fd_dst))
-       {
-               delete m_pvr_thread;
-               m_pvr_thread = 0;
-               eDebug("can't open PVR file %s (%m)", file);
-               return -ENOENT;
-       }
+       m_event(this, evtPreStart);
+
+       m_pvr_thread->start(source, m_pvr_fd_dst);
        CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
 
        m_state = state_ok;
@@ -1719,15 +1833,23 @@ RESULT eDVBChannel::playFile(const char *file)
        return 0;
 }
 
-void eDVBChannel::stopFile()
+void eDVBChannel::stopSource()
 {
        if (m_pvr_thread)
        {
                m_pvr_thread->stop();
-               ::close(m_pvr_fd_dst);
                delete m_pvr_thread;
                m_pvr_thread = 0;
        }
+       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)
@@ -1828,7 +1950,7 @@ void eCueSheet::clear()
 
 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
 {
-       assert(begin < end);
+       ASSERT(begin < end);
        m_lock.WrLock();
        m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
        m_lock.Unlock();