Ticket #1728: 20060425_eit_refactoring.patch

File 20060425_eit_refactoring.patch, 31.7 KB (added by Janne <janne-mythtv@…>, 18 years ago)

all in one patch of my changes to eit scanning

  • libs/libmythtv/eitcache.h

    === libs/libmythtv/eitcache.h
    ==================================================================
     
    1 /*
     1/* -*- Mode: c++ -*-
    22 * Copyright 2006 (C) Stuart Auchterlonie <stuarta at squashedfrog.net>
    33 * License: GPL v2
    44 */
     
    1010
    1111// Qt headers
    1212#include <qmap.h>
     13#include <qmutex.h>
    1314#include <qstring.h>
    1415
    1516typedef QMap<uint64_t, uint64_t> key_map_t;
     
    2021    EITCache();
    2122   ~EITCache() {};
    2223
    23     bool IsNewEIT(const uint tsid,       const uint eventid,
    24                   const uint serviceid,  const uint tableid,
    25                   const uint version,
    26                   const unsigned char * const eitdata,
    27                   const uint eitlength);
     24    bool IsNewEIT(const uint onid, const uint tsid,
     25                  const uint serviceid, const uint eventid,
     26                  const uint tableid, const uint version,
     27                  const uint endtime);
    2828
     29    uint PruneOldEntries(uint timestamp);
     30
    2931    void ResetStatistics(void);
    30     QString GetStatistics(void) const;
     32    QString GetStatistics(void);
    3133
    3234  private:
    3335    // event key cache
    3436    key_map_t   eventMap;
    3537
     38    QMutex      eventMapLock;
     39
     40    uint        lastPruneTime;
     41
    3642    // statistics
    3743    uint        accessCnt;
    3844    uint        hitCnt;
    3945    uint        tblChgCnt;
    4046    uint        verChgCnt;
     47    uint        pruneCnt;
     48    uint        prunedHitCnt;
    4149
    4250    static const uint kVersionMax;
    4351};
  • libs/libmythtv/eithelper.cpp

    === libs/libmythtv/eithelper.cpp
    ==================================================================
     
    2626#define LOC QString("EITHelper: ")
    2727#define LOC_ERR QString("EITHelper, Error: ")
    2828
    29 EITHelper::EITHelper() :
    30     eitfixup(new EITFixUp()), eitcache(new EITCache()),
     29EITHelper::EITHelper(EITCache *cache) :
     30    eitfixup(new EITFixUp()), eitcache(cache),
    3131    gps_offset(-1 * GPS_LEAP_SECONDS),          utc_offset(0),
    3232    sourceid(0)
    3333{
     
    209209
    210210    for (uint i = 0; i < eit->EventCount(); i++)
    211211    {
     212        QDateTime starttime = MythUTCToLocal(eit->StartTimeUTC(i));
    212213        // Skip event if we have already processed it before...
    213         if (!eitcache->IsNewEIT(
    214                 eit->TSID(),      eit->EventID(i),
    215                 eit->ServiceID(), eit->TableID(),
    216                 eit->Version(),
    217                 eit->Descriptors(i), eit->DescriptorsLength(i)))
     214        if (!eitcache->IsNewEIT(eit->OriginalNetworkID(), eit->TSID(),
     215                                eit->ServiceID(), eit->EventID(i),
     216                                eit->TableID(), eit->Version(),
     217                                starttime.toTime_t()+eit->DurationInSeconds(i)))
    218218        {
    219219            continue;
    220220        }
     
    320320        if (!chanid)
    321321            continue;
    322322
    323         QDateTime starttime = MythUTCToLocal(eit->StartTimeUTC(i));
    324323        EITFixUp::TimeFix(starttime);
    325324        QDateTime endtime   = starttime.addSecs(eit->DurationInSeconds(i));
    326325
  • libs/libmythtv/eitcache.cpp

    === libs/libmythtv/eitcache.cpp
    ==================================================================
     
    11// -*- Mode: c++ -*-
    22/*
    33 * Copyright 2006 (C) Stuart Auchterlonie <stuarta at squashedfrog.net>
     4 * Copyright 2006 (C) Janne Grunau <janne-mythtv at grunau.be>
    45 * License: GPL v2
    56 */
    67
     8
     9#include <iostream>
     10using namespace std;
     11
     12#include <qdatetime.h>
     13
    714#include "eitcache.h"
    8 #include <stdio.h>
     15#include "mythcontext.h"
    916
     17#define LOC "EITCache: "
     18
    1019// Highest version number. version is 5bits
    1120const uint EITCache::kVersionMax = 31;
    1221
    1322EITCache::EITCache()
    14     : accessCnt(0), hitCnt(0), tblChgCnt(0), verChgCnt(0)
     23    : accessCnt(0), hitCnt(0), tblChgCnt(0), verChgCnt(0),
     24      pruneCnt(0), prunedHitCnt(0)
    1525{
     26    // six hours ago
     27    lastPruneTime = QDateTime::currentDateTime().addSecs(-21600).toTime_t();
    1628}
    1729
    1830void EITCache::ResetStatistics(void)
     
    2133    hitCnt    = 0;
    2234    tblChgCnt = 0;
    2335    verChgCnt = 0;
     36    pruneCnt  = 0;
     37    prunedHitCnt = 0;
    2438}
    2539
    26 QString EITCache::GetStatistics(void) const
     40QString EITCache::GetStatistics(void)
    2741{
     42    QMutexLocker locker(&eventMapLock);
    2843    return QString(
    2944        "EITCache::statistics: Accesses: %1, Hits: %2, "
    30         "Table Upgrades %3, New Versions: %4")
    31         .arg(accessCnt).arg(hitCnt).arg(tblChgCnt).arg(verChgCnt);
     45        "Table Upgrades %3, New Versions: %4, Entries: %5 "
     46        "Pruned entries: %6, pruned Hits: %7.")
     47        .arg(accessCnt).arg(hitCnt).arg(tblChgCnt).arg(verChgCnt)
     48        .arg(eventMap.size()).arg(pruneCnt).arg(prunedHitCnt);
    3249}
    3350
    34 static uint64_t construct_key(uint tsid, uint eventid, uint serviceid)
     51static uint64_t construct_key(uint onid, uint tsid, uint serviceid, uint eventid)
    3552{
    36     return (((uint64_t) tsid      << 48) | ((uint64_t) eventid   << 32) |
    37             ((uint64_t) serviceid << 16));
     53    return (((uint64_t) onid      << 48) | ((uint64_t) tsid    << 32) |
     54            ((uint64_t) serviceid << 16) | ((uint64_t) eventid      ));
    3855}
    3956
    40 static uint64_t construct_sig(uint tableid, uint version, uint chksum)
     57static uint64_t construct_sig(uint tableid, uint version, uint endtime)
    4158{
    4259    return (((uint64_t) tableid   << 40) | ((uint64_t) version   << 32) |
    43             ((uint64_t) chksum));
     60            ((uint64_t) endtime));
    4461}
    4562
    4663static uint extract_table_id(uint64_t sig)
     
    5370    return (sig >> 32) & 0x1f;
    5471}
    5572
    56 bool EITCache::IsNewEIT(const uint tsid,      const uint eventid,
    57                         const uint serviceid, const uint tableid,
    58                         const uint version,
    59                         const unsigned char * const /*eitdata*/,
    60                         const uint /*eitlength*/)
     73static uint extract_endtime(uint64_t sig)
    6174{
     75    return sig & 0xffffffff;
     76}
     77
     78bool EITCache::IsNewEIT(const uint onid, const uint tsid,
     79                        const uint serviceid, const uint eventid,
     80                        const uint tableid, const uint version,
     81                        const uint endtime)
     82{
    6283    accessCnt++;
    6384
    64     uint64_t key = construct_key(tsid, eventid, serviceid);
     85    // don't readd pruned entries
     86    if (endtime < lastPruneTime)
     87    {
     88        prunedHitCnt++;
     89        return false;
     90    }
     91
     92    uint64_t key = construct_key(onid, tsid, serviceid, eventid);
     93
     94    QMutexLocker locker(&eventMapLock);
    6595    key_map_t::const_iterator it = eventMap.find(key);
    6696
    6797    if (it != eventMap.end())
     
    87117        }
    88118    }
    89119
    90     eventMap[key] = construct_sig(tableid, version, 0 /*chksum*/);
     120    eventMap[key] = construct_sig(tableid, version, endtime);
    91121
    92122    return true;
    93123}
    94124
     125uint EITCache::PruneOldEntries(uint timestamp)
     126{
     127    QDateTime extime = QDateTime();
     128    extime.setTime_t(timestamp);
     129    VERBOSE(VB_EIT, LOC + QString("Pruning all entries that ended before %1,")
     130            .arg(extime.toString()));
     131
     132    QMutexLocker locker(&eventMapLock);
     133    uint size = eventMap.size();
     134
     135    key_map_t::iterator it = eventMap.begin();
     136    while (it != eventMap.end())
     137    {
     138        if (extract_endtime(*it) < timestamp)
     139        {
     140            key_map_t::iterator tmp = it;
     141            ++tmp;
     142            eventMap.erase(it);
     143            it = tmp;
     144        }
     145        else
     146            ++it;
     147    }
     148
     149    lastPruneTime = timestamp;
     150    size -= eventMap.size();
     151    prunedHitCnt += size;
     152    return size;
     153}
     154
    95155/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/eithelper.h

    === libs/libmythtv/eithelper.h
    ==================================================================
     
    5151class EITHelper
    5252{
    5353  public:
    54     EITHelper();
     54    EITHelper(EITCache *cache);
    5555    virtual ~EITHelper();
    5656
    5757    uint GetListSize(void) const;
  • libs/libmythtv/eitscanner.h

    === libs/libmythtv/eitscanner.h
    ==================================================================
     
    1717class EITHelper;
    1818class dvb_channel_t;
    1919class ProgramMapTable;
     20class EITCache;
    2021
    2122class EITSource
    2223{
     
    2829class EITScanner
    2930{
    3031  public:
    31     EITScanner();
     32    EITScanner(EITCache *cache);
    3233    ~EITScanner() { TeardownAll(); }
    3334
    3435    void StartPassiveScan(ChannelBase*, EITSource*, bool ignore_source);
    3536    void StopPassiveScan(void);
    3637
     38#if 0
    3739    void StartActiveScan(TVRec*, uint max_seconds_per_source,
    3840                         bool ignore_source);
    3941
    4042    void StopActiveScan(void);       
     43#endif
    4144
    4245  private:
    4346    void TeardownAll(void);
     
    5659
    5760    TVRec           *rec;
    5861    bool             activeScan;
     62#if 0
    5963    QDateTime        activeScanNextTrig;
    6064    uint             activeScanTrigTime;
    6165    QStringList      activeScanChannels;
    6266    QStringList::iterator activeScanNextChan;
     67#endif
    6368
    6469    bool             ignore_source;
    6570
  • libs/libmythtv/tv_rec.cpp

    === libs/libmythtv/tv_rec.cpp
    ==================================================================
     
    117117       // Various components TVRec coordinates
    118118    : recorder(NULL), channel(NULL), signalMonitor(NULL),
    119119      scanner(NULL), dvbsiparser(NULL), dummyRecorder(NULL),
     120      eitcache(NULL),
    120121      // Configuration variables from database
    121122      transcodeFirst(false), earlyCommFlag(false), runJobOnHostOnly(false),
    122123      audioSampleRateDB(0), overRecordSecNrml(0), overRecordSecCat(0),
     
    151152    bool init_run = false;
    152153    if (genOpt.cardtype == "DVB")
    153154    {
    154         if (!scanner)
    155             scanner = new EITScanner();
     155        if (!scanner && eitcache)
     156            scanner = new EITScanner(eitcache);
    156157
    157158#ifdef USING_DVB
    158159        channel = new DVBChannel(genOpt.videodev.toInt(), this);
     
    726727    // to avoid race condition with it's tuning requests.
    727728    if (HasFlags(kFlagEITScannerRunning))
    728729    {
    729         scanner->StopActiveScan();
     730        scanner->StopPassiveScan();
    730731        ClearFlags(kFlagEITScannerRunning);
    731732    }
    732733
     
    770771    eitScanStartTime = QDateTime::currentDateTime();   
    771772    if ((internalState == kState_None) && (genOpt.cardtype == "DVB"))
    772773    {
    773         // Add some randomness to avoid all cards starting
    774         // EIT scanning at nearly the same time.
     774        // start the eit scanning only if the encoder is idle_start sec idle
    775775        uint idle_start = gContext->GetNumSetting("EITCrawIdleStart", 60);
    776         uint timeout = idle_start + (random() % 59);
    777         eitScanStartTime = eitScanStartTime.addSecs(timeout);
     776        eitScanStartTime = eitScanStartTime.addSecs(idle_start);
    778777    }
    779778    else
    780779        eitScanStartTime = eitScanStartTime.addYears(1);
     
    906905#ifdef USING_HDHOMERUN
    907906        HDHRChannel  *hdhr_channel  = GetHDHRChannel();
    908907        HDHRRecorder *hdhr_recorder = GetHDHRRecorder();
    909         if (hdhr_channel && hdhr_recorder && !scanner)
     908        if (hdhr_channel && hdhr_recorder && !scanner && eitcache)
    910909        {
    911910            uint ignore = gContext->GetNumSetting("EITIgnoresSource", 0);
    912             scanner = new EITScanner();
     911            scanner = new EITScanner(eitcache);
    913912            scanner->StartPassiveScan(hdhr_channel, hdhr_recorder, ignore);
    914913        }
    915914#endif // USING_HDHOMERUN
     
    12461245    SetFlags(kFlagRunMainLoop);
    12471246    ClearFlags(kFlagExitPlayer | kFlagFinishRecording);
    12481247
    1249     // Add some randomness to avoid all cards starting
    1250     // EIT scanning at nearly the same time.
     1248    // start the eit scanning only if the encoder is idle_start sec idle
    12511249    uint idle_start = gContext->GetNumSetting("EITCrawIdleStart", 60);
    1252     uint timeout = idle_start + (random() % 59);
    1253     eitScanStartTime = QDateTime::currentDateTime().addSecs(timeout);
     1250    eitScanStartTime = QDateTime::currentDateTime().addSecs(idle_start);
    12541251
    12551252    while (HasFlags(kFlagRunMainLoop))
    12561253    {
     
    13801377                        "for all sources on this card.");
    13811378                eitScanStartTime = eitScanStartTime.addYears(1);
    13821379            }
     1380/*
    13831381            else
    13841382            {
    13851383                uint ttMin = gContext->GetNumSetting("EITTransportTimeout", 5);
     
    13881386                SetFlags(kFlagEITScannerRunning);
    13891387                eitScanStartTime = QDateTime::currentDateTime().addYears(1);
    13901388            }
     1389*/
    13911390        }
    13921391
    13931392        // We should be no more than a few thousand milliseconds,
     
    31493148    VERBOSE(VB_RECORD, LOC + "SetChannel()" + " -- end");
    31503149}
    31513150
     3151/** \fn TVRec::StartEITScan(QString)
     3152 *  \brief Starts EIT scanning on the named channel and the current tuner.
     3153 *
     3154 *  \param name channum of channel to scan on
     3155 */
     3156bool TVRec::StartEITScan(QString name)
     3157{
     3158    // initialize eit scanner if needed
     3159    if (!scanner && eitcache)
     3160        scanner = new EITScanner(eitcache);
     3161
     3162    // Is this enough to guard against channel changes while recording?
     3163    if (QDateTime::currentDateTime() > eitScanStartTime)
     3164    {
     3165        SetChannel(name, kFlagEITScan);
     3166        //TODO: check for successful tuning
     3167        return true;
     3168    }
     3169    VERBOSE(VB_EIT, LOC + QString("Now: %1 - start scan only after: %2")
     3170            .arg(QDateTime::currentDateTime().toString())
     3171            .arg(eitScanStartTime.toString()));
     3172
     3173    return false;
     3174}
     3175
    31523176/** \fn TVRec::GetNextProgram(int,QString&,QString&,QString&,QString&,QString&,QString&,QString&,QString&,QString&,QString&,QString&,QString&)
    31533177 *  \brief Returns information about the program that would be seen if we changed
    31543178 *         the channel using ChangeChannel(int) with "direction".
     
    35403564
    35413565    if (!(request.flags & kFlagEITScan) && HasFlags(kFlagEITScannerRunning))
    35423566    {
    3543         scanner->StopActiveScan();
     3567        scanner->StopPassiveScan();
    35443568        ClearFlags(kFlagEITScannerRunning);
    35453569    }
    35463570
  • libs/libmythtv/eitscanner.cpp

    === libs/libmythtv/eitscanner.cpp
    ==================================================================
     
    2525QDateTime  EITScanner::resched_next_time      = QDateTime::currentDateTime();
    2626const uint EITScanner::kMinRescheduleInterval = 150;
    2727
    28 EITScanner::EITScanner()
    29     : channel(NULL), eitSource(NULL), eitHelper(new EITHelper()),
     28EITScanner::EITScanner(EITCache *cache)
     29    : channel(NULL), eitSource(NULL), eitHelper(new EITHelper(cache)),
    3030      exitThread(false), rec(NULL), activeScan(false)
    3131{
    3232    QStringList langPref = iso639_get_language_list();
     
    4141
    4242void EITScanner::TeardownAll(void)
    4343{
    44     StopActiveScan();
     44    StopPassiveScan();
    4545    if (!exitThread)
    4646    {
    4747        exitThread = true;
     
    114114            RescheduleRecordings();
    115115        }
    116116
     117#if 0
    117118        if (activeScan && (QDateTime::currentDateTime() > activeScanNextTrig))
    118119        {
    119120            // if there have been any new events, tell scheduler to run.
     
    140141                .addSecs(activeScanTrigTime);
    141142            activeScanNextChan++;
    142143        }
     144#endif
    143145
    144146        exitThreadCond.wait(200); // sleep up to 200 ms.
    145147    }
     
    209211    eitHelper->SetSourceID(0);
    210212}
    211213
     214#if 0
    212215void EITScanner::StartActiveScan(TVRec *_rec, uint max_seconds_per_source,
    213216                                 bool _ignore_source)
    214217{
     
    272275    rec = NULL;
    273276    StopPassiveScan();
    274277}
     278#endif
  • libs/libmythtv/tv_rec.h

    === libs/libmythtv/tv_rec.h
    ==================================================================
     
    2020class QSocket;
    2121class NuppelVideoRecorder;
    2222class RingBuffer;
     23class EITCache;
    2324class EITScanner;
    2425class DVBSIParser;
    2526class DummyDTVRecorder;
     
    221222        { SetChannel(QString("NextChannel %1").arg((int)dir)); }
    222223    void SetChannel(QString name, uint requestType = kFlagDetect);
    223224
     225    bool StartEITScan(QString name);
     226
    224227    int SetSignalMonitoringRate(int msec, int notifyFrontend = 1);
    225228    int ChangeColour(bool direction);
    226229    int ChangeContrast(bool direction);
     
    254257    void DVBGotPMT(void)
    255258        { QMutexLocker lock(&stateChangeLock); triggerEventLoop.wakeAll(); }
    256259
     260    void SetEITCache(EITCache *cache) { eitcache = cache; }
     261
    257262  public slots:
    258263    void SignalMonitorAllGood() { triggerEventLoop.wakeAll(); }
    259264    void deleteLater(void);
     
    340345    RecorderBase     *recorder;
    341346    ChannelBase      *channel;
    342347    SignalMonitor    *signalMonitor;
     348    EITCache         *eitcache;
    343349    EITScanner       *scanner;
    344350    DVBSIParser      *dvbsiparser;
    345351    DummyDTVRecorder *dummyRecorder;
  • libs/libmyth/mythcontext.h

    === libs/libmyth/mythcontext.h
    ==================================================================
     
    229229 *   You must also update this value in
    230230 *   mythplugins/mythweb/includes/mythbackend.php
    231231 */
    232 #define MYTH_PROTO_VERSION "29"
     232#define MYTH_PROTO_VERSION "30"
    233233
    234234/** \class MythContext
    235235 *  \brief This class contains the runtime context for MythTV.
  • programs/mythbackend/encoderlink.h

    === programs/mythbackend/encoderlink.h
    ==================================================================
     
    8282    void ToggleChannelFavorite(void);
    8383    void ChangeChannel(int channeldirection);
    8484    void SetChannel(const QString &name);
     85    bool StartEITScan(const QString chanid);
    8586    int ChangeContrast(bool direction);
    8687    int ChangeBrightness(bool direction);
    8788    int ChangeColour(bool direction);
  • programs/mythbackend/playbacksock.cpp

    === programs/mythbackend/playbacksock.cpp
    ==================================================================
     
    285285    int ret = strlist[0].toInt();
    286286    return ret;
    287287}
     288
     289bool PlaybackSock::StartEITScan(int capturecardnum, QString chanid)
     290{
     291    QStringList strlist = QString("QUERY_REMOTEENCODER %1").arg(capturecardnum);
     292    strlist << "START_EIT_SCAN";
     293    strlist << chanid;
     294
     295    SendReceiveStringList(strlist);
     296
     297    bool ret = strlist[0].toInt();
     298    return ret;
     299}
     300
  • programs/mythbackend/mythbackend.pro

    === programs/mythbackend/mythbackend.pro
    ==================================================================
     
    1313
    1414# Input
    1515HEADERS += autoexpire.h encoderlink.h filetransfer.h httpstatus.h mainserver.h
    16 HEADERS += playbacksock.h scheduler.h server.h housekeeper.h
     16HEADERS += playbacksock.h scheduler.h server.h housekeeper.h eitactivescanner.h
    1717
    1818SOURCES += autoexpire.cpp encoderlink.cpp filetransfer.cpp httpstatus.cpp
    1919SOURCES += main.cpp mainserver.cpp playbacksock.cpp scheduler.cpp server.cpp
    20 SOURCES += housekeeper.cpp
     20SOURCES += housekeeper.cpp eitactivescanner.cpp
    2121
    2222using_oss:DEFINES += USING_OSS
    2323
  • programs/mythbackend/mainserver.cpp

    === programs/mythbackend/mainserver.cpp
    ==================================================================
     
    27672767        info->ToStringList(retlist);
    27682768        delete info;
    27692769    }
     2770    else if (command == "START_EIT_SCAN")
     2771    {
     2772        retlist << QString::number((int)enc->StartEITScan(slist[2]));
     2773    }
    27702774
    27712775    SendResponse(pbssock, retlist);
    27722776}
  • programs/mythbackend/playbacksock.h

    === programs/mythbackend/playbacksock.h
    ==================================================================
     
    6060                                 const ProgramInfo *pginfo);
    6161    void RecordPending(int capturecardnum, const ProgramInfo *pginfo, int secsleft);
    6262    int SetSignalMonitoringRate(int capturecardnum, int rate, int notifyFrontend);
     63    bool StartEITScan(int capturecardnum, QString chanid);
    6364
    6465  private:
    6566    bool SendReceiveStringList(QStringList &strlist);
  • programs/mythbackend/main.cpp

    === programs/mythbackend/main.cpp
    ==================================================================
     
    2626#include "encoderlink.h"
    2727#include "remoteutil.h"
    2828#include "housekeeper.h"
     29#include "eitactivescanner.h"
    2930
    3031#include "libmyth/mythcontext.h"
    3132#include "libmyth/mythdbcon.h"
     
    4243QString lockfile_location;
    4344HouseKeeper *housekeeping = NULL;
    4445QString logfile = "";
     46EITActiveScanner *eitscanner = NULL;
    4547
    4648bool setupTVs(bool ismaster, bool &error)
    4749{
     
    595597    else
    596598        jobqueue = new JobQueue(ismaster);
    597599
     600    eitscanner = new EITActiveScanner(ismaster, &tvList);
    598601    VERBOSE(VB_IMPORTANT, QString("%1 version: %2 www.mythtv.org")
    599602                            .arg(binname).arg(MYTH_BINARY_VERSION));
    600603
  • programs/mythbackend/eitactivescanner.cpp

    === programs/mythbackend/eitactivescanner.cpp
    ==================================================================
     
     1// -*- Mode: c++ -*-
     2
     3#include "eitactivescanner.h"
     4
     5#include "libmythtv/tv_rec.h"
     6
     7
     8/*****************************************************************************
     9 *
     10 * Active EIT scanner: controls the TVRecs on the master backend
     11                       and holds a persistant event cache on each backend
     12*/
     13
     14EITActiveScanner::EITActiveScanner(bool _ismaster, QMap<int, EncoderLink *> *tvList)
     15    : exitThread(false), eitCache(new EITCache()),
     16      cardList(tvList), ismaster(_ismaster)
     17{
     18    pthread_create(&eventThread, NULL, SpawnEventLoop, this);
     19}
     20/*
     21void EITActiveScanner::TeardownAll(void)
     22{
     23    StopActiveScan();
     24    if (!exitThread)
     25    {
     26        exitThread = true;
     27        exitThreadCond.wakeAll();
     28        pthread_join(eventThread, NULL);
     29    }
     30}*/
     31
     32/** \fn EITActiveScanner::SpawnEventLoop(void*)
     33 *  \brief Thunk that allows scanner_thread pthread to
     34 *         call EITActiveScanner::RunEventLoop().
     35 */
     36void *EITActiveScanner::SpawnEventLoop(void *param)
     37{
     38    EITActiveScanner *scanner = (EITActiveScanner*) param;
     39    scanner->RunEventLoop();
     40    return NULL;
     41}
     42
     43/** \fn EITActiveScanner::RunEventLoop()
     44 *  \brief This runs the event loop for EITActiveScanner until 'exitThread' is true.
     45 */
     46void EITActiveScanner::RunEventLoop(void)
     47{
     48    exitThread = false;
     49
     50    QMap<int, EncoderLink *>::iterator it = cardList->begin();
     51    for (; it != cardList->end(); ++it)
     52    {
     53        TVRec *rec = it.data()->GetTVRec();
     54        if (rec)
     55        {
     56            rec->SetEITCache(eitCache);
     57        }
     58    }
     59    if (ismaster)
     60        StartActiveScan();
     61
     62    while (!exitThread)
     63    {
     64        QDateTime now = QDateTime::currentDateTime();
     65
     66        if (ismaster && (now > nextTriggerTime) && !cardList->isEmpty())
     67        {
     68            VERBOSE(VB_EIT, eitCache->GetStatistics());
     69            if (nextCard == cardsSources.end())
     70            {
     71                nextCard = cardsSources.begin();
     72            }
     73
     74            // find source with the highest priority
     75            vector<uint>::iterator source = sources.begin();
     76            while (source != sources.end())
     77            {
     78                if ((*nextCard).end() != find((*nextCard).begin(),
     79                                            (*nextCard).end(), *source))
     80                    break;
     81                ++source;
     82            }
     83            if (source == sources.end())
     84            {
     85                VERBOSE(VB_EIT, QString("Couldn't find source for card %1.")
     86                        .arg(nextCard.key()));
     87                continue;
     88            }
     89            uint sid = *source;
     90            int cardid = nextCard.key();
     91
     92
     93            if (!(*(nextChan[sid])).isEmpty() &&
     94                (*cardList)[cardid]->StartEITScan(*(nextChan[sid])))
     95            {
     96                VERBOSE(VB_GENERAL, QString("DVB(%1): Now looking for EIT "
     97                                            "data on multiplex of channel %2 "
     98                                            "of source %3")
     99                        .arg(cardid).arg(*(nextChan[sid])).arg(sid));
     100                /* advace to the next channel and test for valid iterator.
     101                   needed to simplify selection of the source
     102                   with the highest priority. */
     103                nextChan[sid]++;
     104                if (nextChan[sid] == channels[sid].end())
     105                {
     106                    nextChan[sid] = channels[sid].begin();
     107                    sources.erase(source);
     108                    sources.push_back(sid);
     109                    //cerr << "Moved source " << sid << " to the back of the queue." << endl;
     110                }
     111            }
     112            else
     113            {
     114                VERBOSE(VB_GENERAL, QString("Skipping card %1 in scan for EIT "
     115                                            "data on multiplex of channel %2 "
     116                                            "of source %3")
     117                        .arg(cardid).arg(*(nextChan[sid])).arg(sid));
     118            }
     119
     120            nextTriggerTime = QDateTime::currentDateTime().addSecs(triggerTime);
     121
     122            nextCard++;
     123        }
     124
     125        // prune cache entries that ended more than kPruneCacheTimeOffset ago
     126        if (now > nextPruneCacheTime)
     127        {
     128            uint prunedEntries = eitCache->PruneOldEntries(now
     129                                 .addSecs(-kPruneCacheTimeOffset).toTime_t());
     130            nextPruneCacheTime =  QDateTime::currentDateTime()
     131                .addSecs(kPruneCacheTimeOffset);
     132
     133            VERBOSE(VB_EIT, eitCache->GetStatistics());
     134            VERBOSE(VB_EIT, QString("Pruned %1 entries from the eit cache")
     135                        .arg(prunedEntries));
     136        }
     137           
     138        exitThreadCond.wait(1000); // sleep up to 1 second.
     139    }
     140}
     141
     142void EITActiveScanner::StartActiveScan()
     143{
     144    if (!sources.size())
     145    {
     146        // get all source ids with useeit == 1
     147        MSqlQuery query(MSqlQuery::InitCon());
     148        query.prepare(
     149            "SELECT DISTINCT channel.sourceid "
     150            "FROM channel, videosource "
     151            "WHERE videosource.sourceid = channel.sourceid AND "
     152            "      channel.mplexid        IS NOT NULL      AND "
     153            "      useonairguide        = 1                AND "
     154            "      useeit               = 1 "
     155            "GROUP BY mplexid "
     156            "ORDER BY channel.sourceid, atscsrcid, mplexid");
     157       
     158        if (!query.exec() || !query.isActive())
     159        {
     160            MythContext::DBError("EITActiveScanner::StartActiveScan", query);
     161            return;
     162        }
     163       
     164        while (query.next())
     165            sources.push_back(query.value(0).toUInt());
     166
     167        // getting mapping from cardid to sourceid with useeit == 1
     168        query.prepare(
     169            "SELECT cardid, videosource.sourceid "
     170            "FROM videosource,cardinput "
     171            "WHERE videosource.sourceid = cardinput.sourceid AND "
     172            "      useeit               = 1 "
     173            "ORDER BY cardid");
     174       
     175        if (!query.exec() || !query.isActive())
     176        {
     177            MythContext::DBError("EITActiveScanner::StartActiveScan", query);
     178            return;
     179        }
     180       
     181        while (query.next())
     182            cardsSources[query.value(0).toInt()]
     183                .push_back(query.value(1).toUInt());
     184
     185
     186        // get one channel with sourceid per mplexid
     187        query.prepare(
     188            "SELECT channel.sourceid, min(channum) "
     189            "FROM channel, videosource "
     190            "WHERE videosource.sourceid = channel.sourceid AND "
     191            "      channel.mplexid        IS NOT NULL      AND "
     192            "      useonairguide        = 1                AND "
     193            "      useeit               = 1                AND "
     194            "      channum             != '' "
     195            "GROUP BY mplexid "
     196            "ORDER BY channel.sourceid, atscsrcid, mplexid");
     197
     198        if (!query.exec() || !query.isActive())
     199        {
     200            MythContext::DBError("EITScanner::StartActiveScan", query);
     201            return;
     202        }
     203
     204        while (query.next())
     205        {
     206            VERBOSE(VB_EIT,QString("Adding channel %1 for source %2 "
     207                                   "to scan list")
     208                    .arg(query.value(0).toString())
     209                    .arg(query.value(1).toUInt()));
     210            channels[query.value(0).toUInt()]
     211                .push_back(query.value(1).toString());
     212        }
     213    }
     214    int number = 0;
     215    for (vector<uint>::iterator it = sources.begin(); it != sources.end(); ++it)
     216    {
     217        nextChan[*it] = channels[*it].begin();
     218        number += channels[*it].size();
     219    }
     220
     221    VERBOSE(VB_EIT,
     222            QString("StartActiveScan called with %1 multiplexes on %2 sources")
     223            .arg(number).arg(sources.size()));
     224
     225    if (sources.size())
     226    {
     227        uint scantime = gContext->GetNumSetting("EITTransportTimeout", 5) * 60;
     228        uint idle_start = gContext->GetNumSetting("EITCrawIdleStart", 60);
     229
     230        nextTriggerTime    = QDateTime::currentDateTime().addSecs(idle_start+5);
     231        triggerTime        = scantime / cardList->size();
     232        nextCard           = cardsSources.begin();
     233        nextPruneCacheTime = QDateTime::currentDateTime()
     234            .addSecs(kPruneCacheTimeOffset);
     235    }
     236}
  • programs/mythbackend/eitactivescanner.h

    Property changes on: programs/mythbackend/eitactivescanner.cpp
    ___________________________________________________________________
    Name: svn:mime-type
     +text/cpp
    
    === programs/mythbackend/eitactivescanner.h
    ==================================================================
     
     1// -*- Mode: c++ -*-
     2#ifndef EITACTIVESCANNER_H
     3#define EITACTIVESCANNER_H
     4
     5// C includes
     6#include <pthread.h>
     7
     8// Qt includes
     9#include <qobject.h>
     10#include <qdatetime.h>
     11#include <qstringlist.h>
     12#include <qwaitcondition.h>
     13
     14// myth includes
     15#include "encoderlink.h"
     16
     17#include "libmythtv/eitcache.h"
     18
     19
     20
     21class EITActiveScanner
     22{
     23  public:
     24    EITActiveScanner(bool _ismaster, QMap<int, EncoderLink *> *tvList);
     25    ~EITActiveScanner() {}
     26
     27  private:
     28    void StartActiveScan(void);
     29    void RunEventLoop(void);
     30    static void *SpawnEventLoop(void*);
     31
     32    QMutex           lock;
     33
     34    pthread_t        eventThread;
     35    bool             exitThread;
     36    QWaitCondition   exitThreadCond;
     37
     38    EITCache         *eitCache;
     39
     40    QDateTime        nextTriggerTime;
     41    uint             triggerTime;
     42
     43    vector<uint>                        sources;
     44    QMap<uint, QStringList>             channels;
     45    QMap<uint, QStringList::iterator>   nextChan;
     46
     47    QMap<int, EncoderLink *>            *cardList;
     48
     49    QMap<int, vector<uint> >            cardsSources;
     50    QMap<int, vector<uint> >::iterator  nextCard;
     51
     52    bool                ismaster;
     53
     54    QDateTime           nextPruneCacheTime;
     55
     56    static const int    kPruneCacheTimeOffset = 21600; // six hours
     57};
     58
     59#endif //EITACTIVESCANNER_H
  • programs/mythbackend/encoderlink.cpp

    Property changes on: programs/mythbackend/eitactivescanner.h
    ___________________________________________________________________
    Name: svn:mime-type
     +text/cpp
    
    === programs/mythbackend/encoderlink.cpp
    ==================================================================
     
    199199    return retval;
    200200}
    201201
     202/** \fn EncoderLink::StartEITScan(const QString)
     203 *  \brief Tells TVRec to scan for EIT on channel chanid.
     204 *  \param chanid      Channel to scan
     205 */
     206bool EncoderLink::StartEITScan(const QString chanid)
     207{
     208    if (local)
     209        return tv->StartEITScan(chanid);
     210    else if (sock)
     211    {
     212        return sock->StartEITScan(m_capturecardnum, chanid);
     213    }
     214}
     215
     216
    202217/** \fn EncoderLink::RecordPending(const ProgramInfo*, int)
    203218 *  \brief Tells TVRec there is a pending recording "rec" in "secsleft" seconds.
    204219 *  \param rec      Recording to make.