=== libs/libmythtv/tv_rec.cpp
==================================================================
--- libs/libmythtv/tv_rec.cpp	(revision 228)
+++ libs/libmythtv/tv_rec.cpp	(revision 230)
@@ -770,11 +770,9 @@
     eitScanStartTime = QDateTime::currentDateTime();    
     if ((internalState == kState_None) && (genOpt.cardtype == "DVB"))
     {
-        // Add some randomness to avoid all cards starting
-        // EIT scanning at nearly the same time.
+        // start the eit scanning only if the encoder is idle_start sec idle
         uint idle_start = gContext->GetNumSetting("EITCrawIdleStart", 60);
-        uint timeout = idle_start + (random() % 59);
-        eitScanStartTime = eitScanStartTime.addSecs(timeout);
+        eitScanStartTime = eitScanStartTime.addSecs(idle_start);
     }
     else
         eitScanStartTime = eitScanStartTime.addYears(1);
@@ -1246,11 +1244,9 @@
     SetFlags(kFlagRunMainLoop);
     ClearFlags(kFlagExitPlayer | kFlagFinishRecording);
 
-    // Add some randomness to avoid all cards starting
-    // EIT scanning at nearly the same time.
+    // start the eit scanning only if the encoder is idle_start sec idle
     uint idle_start = gContext->GetNumSetting("EITCrawIdleStart", 60);
-    uint timeout = idle_start + (random() % 59);
-    eitScanStartTime = QDateTime::currentDateTime().addSecs(timeout);
+    eitScanStartTime = QDateTime::currentDateTime().addSecs(idle_start);
 
     while (HasFlags(kFlagRunMainLoop))
     {
@@ -3151,6 +3147,30 @@
     VERBOSE(VB_RECORD, LOC + "SetChannel()" + " -- end");
 }
 
+/** \fn TVRec::StartEITScan(QString)
+ *  \brief Starts EIT scanning on the named channel and the current tuner.
+ *
+ *  \param name channum of channel to scan on
+ */
+bool TVRec::StartEITScan(QString name)
+{
+    // initialize eit scanner if needed
+    if (!scanner && eitcache)
+        scanner = new EITScanner(eitcache);
+
+    if (QDateTime::currentDateTime() > eitScanStartTime)
+    {
+        SetChannel(name, kFlagEITScan);
+        uint ignore = gContext->GetNumSetting("EITIgnoresSource", 0);
+        return true;
+    }
+    VERBOSE(VB_EIT, LOC + QString("Now: %1 - start scan only after: %2")
+            .arg(QDateTime::currentDateTime().toString())
+            .arg(eitScanStartTime.toString()));
+
+    return false;
+}
+
 /** \fn TVRec::GetNextProgram(int,QString&,QString&,QString&,QString&,QString&,QString&,QString&,QString&,QString&,QString&,QString&,QString&)
  *  \brief Returns information about the program that would be seen if we changed
  *         the channel using ChangeChannel(int) with "direction".
=== libs/libmythtv/tv_rec.h
==================================================================
--- libs/libmythtv/tv_rec.h	(revision 228)
+++ libs/libmythtv/tv_rec.h	(revision 230)
@@ -221,6 +221,8 @@
         { SetChannel(QString("NextChannel %1").arg((int)dir)); }
     void SetChannel(QString name, uint requestType = kFlagDetect);
 
+    bool StartEITScan(QString name);
+
     int SetSignalMonitoringRate(int msec, int notifyFrontend = 1);
     int ChangeColour(bool direction);
     int ChangeContrast(bool direction);
=== programs/mythbackend/encoderlink.h
==================================================================
--- programs/mythbackend/encoderlink.h	(revision 228)
+++ programs/mythbackend/encoderlink.h	(revision 230)
@@ -82,6 +82,7 @@
     void ToggleChannelFavorite(void);
     void ChangeChannel(int channeldirection);
     void SetChannel(const QString &name);
+    bool StartEITScan(const QString chanid);
     int ChangeContrast(bool direction);
     int ChangeBrightness(bool direction);
     int ChangeColour(bool direction);
=== programs/mythbackend/mythbackend.pro
==================================================================
--- programs/mythbackend/mythbackend.pro	(revision 228)
+++ programs/mythbackend/mythbackend.pro	(revision 230)
@@ -13,11 +13,11 @@
 
 # Input
 HEADERS += autoexpire.h encoderlink.h filetransfer.h httpstatus.h mainserver.h
-HEADERS += playbacksock.h scheduler.h server.h housekeeper.h
+HEADERS += playbacksock.h scheduler.h server.h housekeeper.h eitactivescanner.h
 
 SOURCES += autoexpire.cpp encoderlink.cpp filetransfer.cpp httpstatus.cpp
 SOURCES += main.cpp mainserver.cpp playbacksock.cpp scheduler.cpp server.cpp
-SOURCES += housekeeper.cpp
+SOURCES += housekeeper.cpp eitactivescanner.cpp
 
 using_oss:DEFINES += USING_OSS
 
=== programs/mythbackend/main.cpp
==================================================================
--- programs/mythbackend/main.cpp	(revision 228)
+++ programs/mythbackend/main.cpp	(revision 230)
@@ -26,6 +26,7 @@
 #include "encoderlink.h"
 #include "remoteutil.h"
 #include "housekeeper.h"
+#include "eitactivescanner.h"
 
 #include "libmyth/mythcontext.h"
 #include "libmyth/mythdbcon.h"
@@ -42,6 +43,7 @@
 QString lockfile_location;
 HouseKeeper *housekeeping = NULL;
 QString logfile = "";
+EITActiveScanner *eitscanner = NULL;
 
 bool setupTVs(bool ismaster, bool &error)
 {
@@ -595,6 +597,7 @@
     else
         jobqueue = new JobQueue(ismaster);
 
+    eitscanner = new EITActiveScanner(ismaster, &tvList);
     VERBOSE(VB_IMPORTANT, QString("%1 version: %2 www.mythtv.org")
                             .arg(binname).arg(MYTH_BINARY_VERSION));
 
=== programs/mythbackend/eitactivescanner.cpp
==================================================================
--- programs/mythbackend/eitactivescanner.cpp	(revision 228)
+++ programs/mythbackend/eitactivescanner.cpp	(revision 230)
@@ -0,0 +1,194 @@
+// -*- Mode: c++ -*-
+
+#include "eitactivescanner.h"
+
+#include "libmythtv/tv_rec.h"
+
+
+/*****************************************************************************
+ *
+ * Active EIT scanner: controls the TVRecs on the master backend
+                       and holds a persistant event cache on each backend
+*/
+
+EITActiveScanner::EITActiveScanner(bool _ismaster, QMap<int, EncoderLink *> *tvList)
+    : exitThread(false), eitCache(new EITCache()),
+      cardList(tvList), ismaster(_ismaster)
+{
+    pthread_create(&eventThread, NULL, SpawnEventLoop, this);
+}
+/*
+void EITActiveScanner::TeardownAll(void)
+{
+    StopActiveScan();
+    if (!exitThread)
+    {
+        exitThread = true;
+        exitThreadCond.wakeAll();
+        pthread_join(eventThread, NULL);
+    }
+}*/
+
+/** \fn EITActiveScanner::SpawnEventLoop(void*)
+ *  \brief Thunk that allows scanner_thread pthread to
+ *         call EITActiveScanner::RunEventLoop().
+ */
+void *EITActiveScanner::SpawnEventLoop(void *param)
+{
+    EITActiveScanner *scanner = (EITActiveScanner*) param;
+    scanner->RunEventLoop();
+    return NULL;
+}
+
+/** \fn EITActiveScanner::RunEventLoop()
+ *  \brief This runs the event loop for EITActiveScanner until 'exitThread' is true.
+ */
+void EITActiveScanner::RunEventLoop(void)
+{
+    exitThread = false;
+
+//     QMap<int, EncoderLink *>::iterator it = cardList->begin();
+//     for (; it != cardList->end(); ++it)
+//     {
+//         TVRec *rec = it.data()->GetTVRec();
+//         if (rec)
+//         {
+//             rec->SetEITCache(eitCache);
+//         }
+//     }
+//    if (ismaster)
+        StartActiveScan();
+
+
+
+    while (!exitThread)
+    {
+        if (ismaster && (QDateTime::currentDateTime() > activeScanNextTrig)
+            && !cardList->isEmpty())
+        {
+//             cerr << eitCache->GetStatistics() << endl;
+            if (activeScanNextCard == cardIDToSourceID.end())
+            {
+                activeScanNextCard = cardIDToSourceID.begin();
+            }
+
+            uint source = *activeScanNextCard;
+
+            int curCardID = activeScanNextCard.key();
+            if (activeScanNextChan[source] == activeScanChannels[source].end())
+                activeScanNextChan[source] = activeScanChannels[source].begin();
+
+            if (!(*(activeScanNextChan[source])).isEmpty() &&
+                (*cardList)[curCardID]->StartEITScan(*(activeScanNextChan[source])))
+            {
+                VERBOSE(VB_GENERAL, QString("(%1)Now looking for EIT data on "
+                                            "multiplex of channel %2 of source %3")
+                        .arg(curCardID).arg(*(activeScanNextChan[source])).arg(source));
+                activeScanNextChan[source]++;
+            }
+            else
+            {
+                VERBOSE(VB_GENERAL, QString("Skipping card %1 in scan for EIT data on "
+                                            "multiplex of channel %2 of source %3")
+                        .arg(curCardID).arg(*(activeScanNextChan[source])).arg(source));
+            }
+
+            activeScanNextTrig = QDateTime::currentDateTime()
+                .addSecs(activeScanTrigTime);
+
+            activeScanNextCard++;
+        }
+        // TODO: prune old eit cache entries every now and then
+            
+        exitThreadCond.wait(200); // sleep up to 200 ms.
+    }
+}
+
+void EITActiveScanner::StartActiveScan()
+{
+    if (!activeScanSources.size())
+    {
+        // get all source ids with useeit == 1
+        MSqlQuery query(MSqlQuery::InitCon());
+        query.prepare(
+            "SELECT DISTINCT channel.sourceid "
+            "FROM channel, videosource "
+            "WHERE videosource.sourceid = channel.sourceid AND "
+            "      channel.mplexid        IS NOT NULL      AND "
+            "      useonairguide        = 1                AND "
+            "      useeit               = 1 "
+            "GROUP BY mplexid "
+            "ORDER BY channel.sourceid, atscsrcid, mplexid");
+        
+        if (!query.exec() || !query.isActive())
+        {
+            MythContext::DBError("EITActiveScanner::StartActiveScan", query);
+            return;
+        }
+        
+        while (query.next())
+            activeScanSources.push_back(query.value(0).toUInt());
+
+        // getting mapping from cardid to sourceid with useeit == 1
+        query.prepare(
+            "SELECT cardid, videosource.sourceid "
+            "FROM videosource,cardinput "
+            "WHERE videosource.sourceid = cardinput.sourceid AND "
+            "      useeit               = 1 "
+            "ORDER BY cardid");
+        
+        if (!query.exec() || !query.isActive())
+        {
+            MythContext::DBError("EITActiveScanner::StartActiveScan", query);
+            return;
+        }
+        
+        while (query.next())
+            cardIDToSourceID[query.value(0).toInt()] = query.value(1).toUInt();
+
+
+        // get one channel with sourceid per mplexid
+        query.prepare(
+            "SELECT channel.sourceid, min(channum) "
+            "FROM channel, videosource "
+            "WHERE videosource.sourceid = channel.sourceid AND "
+            "      channel.mplexid        IS NOT NULL      AND "
+            "      useonairguide        = 1                AND "
+            "      useeit               = 1                AND "
+            "      channum             != '' "
+            "GROUP BY mplexid "
+            "ORDER BY channel.sourceid, atscsrcid, mplexid");
+
+        if (!query.exec() || !query.isActive())
+        {
+            MythContext::DBError("EITScanner::StartActiveScan", query);
+            return;
+        }
+
+        while (query.next())
+        {
+            VERBOSE(VB_EIT,QString("Adding channel %1 for source %2 to scan list")
+            .arg(query.value(0).toString()).arg(query.value(1).toUInt()));
+            activeScanChannels[query.value(0).toUInt()].push_back(query.value(1).toString());
+        }
+    }
+    int number = 0;
+    for (vector<uint>::iterator it = activeScanSources.begin(); it != activeScanSources.end(); ++it)
+    {
+        activeScanNextChan[*it] = activeScanChannels[*it].begin();
+        number += activeScanChannels[*it].size();
+    }
+
+    VERBOSE(VB_EIT,
+            QString("StartActiveScan called with %1 multiplexes on %2 sources")
+            .arg(number).arg(activeScanSources.size()));
+
+    if (activeScanSources.size())
+    {
+        uint max_seconds_per_source = gContext->GetNumSetting("EITTransportTimeout", 5) * 60;
+
+        activeScanNextTrig = QDateTime::currentDateTime();
+        activeScanTrigTime = max_seconds_per_source / cardList->size();
+        activeScanNextCard = cardIDToSourceID.begin();
+    }
+}

Property changes on: programs/mythbackend/eitactivescanner.cpp
___________________________________________________________________
Name: svn:mime-type
 +text/cpp

=== programs/mythbackend/eitactivescanner.h
==================================================================
--- programs/mythbackend/eitactivescanner.h	(revision 228)
+++ programs/mythbackend/eitactivescanner.h	(revision 230)
@@ -0,0 +1,54 @@
+// -*- Mode: c++ -*-
+#ifndef EITACTIVESCANNER_H
+#define EITACTIVESCANNER_H
+
+// C includes
+#include <pthread.h>
+
+// Qt includes
+#include <qobject.h>
+#include <qdatetime.h>
+#include <qstringlist.h>
+#include <qwaitcondition.h>
+
+// myth includes
+#include "encoderlink.h"
+
+#include "libmythtv/eitcache.h"
+
+
+
+class EITActiveScanner
+{
+  public:
+    EITActiveScanner(bool _ismaster, QMap<int, EncoderLink *> *tvList);
+    ~EITActiveScanner() {}
+
+  private:
+    void StartActiveScan(void);
+    void RunEventLoop(void);
+    static void *SpawnEventLoop(void*);
+
+    QMutex           lock;
+
+    pthread_t        eventThread;
+    bool             exitThread;
+    QWaitCondition   exitThreadCond;
+
+    EITCache         *eitCache;
+
+    QDateTime        activeScanNextTrig;
+    uint             activeScanTrigTime;
+
+    vector<uint>                      activeScanSources;
+    QMap<uint, QStringList>           activeScanChannels;
+    QMap<uint, QStringList::iterator> activeScanNextChan;
+
+    QMap<int, EncoderLink *>   *cardList;
+    QMap<int, uint>            cardIDToSourceID;
+    QMap<int, uint>::iterator  activeScanNextCard;
+
+    bool             ismaster;
+};
+
+#endif //EITACTIVESCANNER_H

Property changes on: programs/mythbackend/eitactivescanner.h
___________________________________________________________________
Name: svn:mime-type
 +text/cpp

=== programs/mythbackend/encoderlink.cpp
==================================================================
--- programs/mythbackend/encoderlink.cpp	(revision 228)
+++ programs/mythbackend/encoderlink.cpp	(revision 230)
@@ -199,6 +199,23 @@
     return retval;
 }
 
+/** \fn EncoderLink::StartEITScan(const QString)
+ *  \brief Tells TVRec to scan for EIT on channel chanid.
+ *  \param chanid      Channel to scan
+ */
+bool EncoderLink::StartEITScan(const QString chanid)
+{
+    if (local)
+        return tv->StartEITScan(chanid);
+    else if (sock)
+    {
+        VERBOSE(VB_IMPORTANT, "StartEITScan is currently only supported locally");
+        return false;
+        /*return sock->StartEITScan(m_capturecardnum, chanid);*/
+    }
+}
+
+
 /** \fn EncoderLink::RecordPending(const ProgramInfo*, int)
  *  \brief Tells TVRec there is a pending recording "rec" in "secsleft" seconds.
  *  \param rec      Recording to make.
