Ticket #6719: channel-thread-trunk-24509.patch

File channel-thread-trunk-24509.patch, 55.4 KB (added by jpoet, 11 years ago)

This version tightens up a critical section, a little bit.

  • libs/libmythtv/analogsignalmonitor.cpp

    old new void AnalogSignalMonitor::UpdateValues(v 
    3030
    3131    int videofd = channel->GetFd();
    3232    if (videofd < 0)
    3333        return;
    3434
     35    if (!IsChannelTuned())
     36        return;
     37
    3538    bool isLocked = false;
    3639    if (usingv4l2)
    3740    {
    3841        struct v4l2_tuner tuner;
    3942        bzero(&tuner, sizeof(tuner));
  • libs/libmythtv/channelbase.cpp

    old new using namespace std; 
    3333
    3434#define LOC QString("ChannelBase(%1): ").arg(GetCardID())
    3535#define LOC_WARN QString("ChannelBase(%1) Warning: ").arg(GetCardID())
    3636#define LOC_ERR QString("ChannelBase(%1) Error: ").arg(GetCardID())
    3737
     38/*
     39 * Run the channel change thread, and report the status when done
     40 */
     41void ChannelThread::run(void)
     42{
     43    bool result = tuner->SetChannelByString(channel);
     44    tuner->setStatus(result ?
     45                     ChannelBase::changeSuccess : ChannelBase::changeFailed);
     46}
     47
    3848ChannelBase::ChannelBase(TVRec *parent)
    3949    :
    4050    m_pParent(parent), m_curchannelname(""),
    41     m_currentInputID(-1), m_commfree(false), m_cardid(0)
     51    m_currentInputID(-1), m_commfree(false), m_cardid(0),
     52    m_abort_change(false)
    4253{
     54    m_tuneStatus = changeUnknown;
     55    m_tuneThread.tuner = this;
    4356}
    4457
    4558ChannelBase::~ChannelBase(void)
    4659{
    4760    ClearInputMap();
     61    TeardownAll();
     62}
     63
     64void ChannelBase::TeardownAll(void)
     65{
     66    if (m_tuneThread.isRunning())
     67    {
     68        m_thread_lock.lock();
     69        m_abort_change = true;
     70        m_tuneCond.wakeAll();
     71        m_thread_lock.unlock();
     72        m_tuneThread.wait();
     73    }
     74}
     75
     76void ChannelBase::SelectChannel(const QString & chan)
     77{
     78    VERBOSE(VB_CHANNEL, LOC + "SelectChannel " + chan);
     79    TeardownAll();
     80
     81    m_thread_lock.lock();
     82    m_abort_change = false;
     83    m_tuneStatus = changePending;
     84    m_thread_lock.unlock();
     85
     86    m_curchannelname = m_tuneThread.channel = chan;
     87    m_tuneThread.start();
     88}
     89
     90/*
     91 * Returns true of the channel change thread should abort
     92 */
     93bool ChannelBase::Aborted(void)
     94{
     95    bool       result;
     96
     97    m_thread_lock.lock();
     98    result = m_abort_change;
     99    m_thread_lock.unlock();
     100
     101    return result;
     102}
     103
     104ChannelBase::Status ChannelBase::GetStatus(void)
     105{
     106    Status status;
     107
     108    m_thread_lock.lock();
     109    status = m_tuneStatus;
     110    m_thread_lock.unlock();
     111
     112    return status;
     113}
     114
     115ChannelBase::Status ChannelBase::Wait(void)
     116{
     117    m_tuneThread.wait();
     118    return m_tuneStatus;
     119}
     120
     121void ChannelBase::setStatus(ChannelBase::Status status)
     122{
     123    m_thread_lock.lock();
     124    m_tuneStatus = status;
     125    m_thread_lock.unlock();
    48126}
    49127
    50128bool ChannelBase::Init(QString &inputname, QString &startchannel, bool setchan)
    51129{
    52130    bool ok;
    53131
     132    VERBOSE(VB_CHANNEL, LOC + QString("Init(%1, %2, %3)")
     133            .arg(inputname).arg(startchannel).arg(setchan));
     134
    54135    if (!setchan)
    55136        ok = inputname.isEmpty() ? false : IsTunable(inputname, startchannel);
    56137    else if (inputname.isEmpty())
    57         ok = SetChannelByString(startchannel);
     138    {
     139        SelectChannel(startchannel);
     140        ok = Wait();
     141    }
    58142    else
    59143        ok = SwitchToInput(inputname, startchannel);
    60144
    61145    if (ok)
    62146        return true;
    bool ChannelBase::Init(QString &inputnam 
    123207                find(channels.begin(), channels.end(), chanid);
    124208
    125209            if (chanid && cit != channels.end())
    126210            {
    127211                if (!setchan)
    128                 {
    129212                    ok = IsTunable(*it, (mplexid_restriction) ?
    130213                                   (*cit).channum : startchannel);
    131                 }
    132214                else
    133215                    ok = SwitchToInput(*it, (*cit).channum);
    134216
    135217                if (ok)
    136218                {
    int ChannelBase::GetInputByName(const QS 
    328410            return (int)it.key();
    329411    }
    330412    return -1;
    331413}
    332414
     415#if 0 // Not used?
    333416bool ChannelBase::SwitchToInput(const QString &inputname)
    334417{
    335418    int input = GetInputByName(inputname);
    336419
    337420    if (input >= 0)
    bool ChannelBase::SwitchToInput(const QS 
    339422    else
    340423        VERBOSE(VB_IMPORTANT, QString("ChannelBase: Could not find input: "
    341424                                      "%1 on card\n").arg(inputname));
    342425    return false;
    343426}
     427#endif
     428
     429bool ChannelBase::SelectInput(const QString &inputname, const QString &chan)
     430{
     431    int input = GetInputByName(inputname);
     432
     433    VERBOSE(VB_CHANNEL, LOC + QString("SelectInput(%1, %2) %3")
     434            .arg(inputname).arg(chan).arg(input));
     435
     436    if (input >= 0)
     437    {
     438        if (!SwitchToInput(input, false))
     439            return false;
     440        SelectChannel(chan);
     441    }
     442    else
     443    {
     444        VERBOSE(VB_IMPORTANT,
     445                QString("ChannelBase: Could not find input: %1 on card when "
     446                        "setting channel %2\n").arg(inputname).arg(chan));
     447        return false;
     448    }
     449
     450    return true;
     451}
    344452
    345453bool ChannelBase::SwitchToInput(const QString &inputname, const QString &chan)
    346454{
    347455    int input = GetInputByName(inputname);
    348456
    349     bool ok = false;
     457    VERBOSE(VB_CHANNEL, LOC + QString("SwitchToInput(%1, %2), %3")
     458            .arg(inputname).arg(chan).arg(input));
     459
    350460    if (input >= 0)
    351461    {
    352         ok = SwitchToInput(input, false);
    353         if (ok)
    354             ok = SetChannelByString(chan);
     462        if (!SwitchToInput(input, false))
     463            return false;
     464        return SetChannelByString(chan);
    355465    }
    356466    else
    357467    {
    358468        VERBOSE(VB_IMPORTANT,
    359469                QString("ChannelBase: Could not find input: %1 on card when "
    360470                        "setting channel %2\n").arg(inputname).arg(chan));
     471        return false;
    361472    }
    362     return ok;
     473
     474    return true;
    363475}
    364476
    365477bool ChannelBase::SwitchToInput(int newInputNum, bool setstarting)
    366478{
     479    VERBOSE(VB_CHANNEL, LOC + QString("SwitchToInput(%1, %2)")
     480            .arg(newInputNum).arg(setstarting));
     481
    367482    InputMap::const_iterator it = m_inputs.find(newInputNum);
    368483    if (it == m_inputs.end() || (*it)->startChanNum.isEmpty())
    369484        return false;
    370485
    371486    uint mplexid_restriction;
    bool ChannelBase::SwitchToInput(int newI 
    373488        return false;
    374489
    375490    // input switching code would go here
    376491
    377492    if (setstarting)
    378         return SetChannelByString((*it)->startChanNum);
     493        SelectChannel((*it)->startChanNum);
    379494
    380495    return true;
    381496}
    382497
    383498static bool is_input_group_busy(
    static bool is_input_busy( 
    484599            busygrp, busyrec, busyin, mplexid_restriction);
    485600    }
    486601    return is_busy;
    487602}
    488603
    489 bool ChannelBase::IsInputAvailable(
    490     int inputid, uint &mplexid_restriction) const
     604bool ChannelBase::IsInputAvailable(int inputid, uint &mplexid_restriction) const
    491605{
    492606    if (inputid < 0)
    493607        return false;
    494608
    495609    // Check each input to make sure it doesn't belong to an
    bool ChannelBase::ChangeExternalChannel( 
    650764        VERBOSE(VB_IMPORTANT, msg);
    651765        _exit(CHANNEL__EXIT__EXECL_ERROR); // this exit is ok
    652766    }
    653767    else
    654768    {   // child contains the pid of the new process
    655         int status = 0, pid = 0;
     769        QMutex      lock;
     770        int         status = 0, pid = 0;
     771
    656772        VERBOSE(VB_CHANNEL, "Waiting for External Tuning program to exit");
    657773
    658774        bool timed_out = false;
    659775        uint timeout = 30; // how long to wait in seconds
    660776        time_t start_time = time(0);
    661         while (-1 != pid && !timed_out)
     777        while (-1 != pid && !timed_out && !Aborted())
    662778        {
    663             sleep(1);
     779            lock.lock();
     780            m_tuneCond.wait(&lock, 500);  // sleep up to 0.5 seconds
    664781            pid = waitpid(child, &status, WUNTRACED|WNOHANG);
    665782            VERBOSE(VB_IMPORTANT, QString("ret_pid(%1) child(%2) status(0x%3)")
    666783                    .arg(pid).arg(child).arg(status,0,16));
    667784            if (pid==child)
     785            {
     786                lock.unlock();
    668787                break;
     788            }
    669789            else if (time(0) > (time_t)(start_time + timeout))
    670790                timed_out = true;
     791            lock.unlock();
    671792        }
    672         if (timed_out)
     793
     794        if (timed_out || Aborted())
    673795        {
    674             VERBOSE(VB_IMPORTANT, "External Tuning program timed out, killing");
     796            if (Aborted())
     797                VERBOSE(VB_IMPORTANT, "Aborting External Tuning program");
     798            else
     799                VERBOSE(VB_IMPORTANT, "External Tuning program timed out, "
     800                        "killing");
    675801            kill(child, SIGTERM);
    676802            usleep(500);
    677803            kill(child, SIGKILL);
    678804            return false;
    679805        }
  • libs/libmythtv/channelbase.h

    old new  
    33#ifndef CHANNELBASE_H
    44#define CHANNELBASE_H
    55
    66// Qt headers
    77#include <QStringList>
     8#include <qwaitcondition.h>
     9#include <qmutex.h>
     10#include <qthread.h>
    811
    912// MythTV headers
    1013#include "channelutil.h"
    1114#include "inputinfo.h"
    1215#include "tv.h"
    1316
    1417class TVRec;
     18class ChannelBase;
     19
     20/*
     21 * Thread to run tunning process in
     22 */
     23class ChannelThread : public QThread
     24{
     25  public:
     26    virtual void run(void);
     27
     28    QString      channel;
     29    ChannelBase *tuner;
     30};
    1531
    1632/** \class ChannelBase
    1733 *  \brief Abstract class providing a generic interface to tuning hardware.
    1834 *
    1935 *   This class abstracts channel implementations for analog TV, ATSC, DVB, etc.
    class TVRec; 
    2137 *   It is responsible for tuning, i.e. switching channels.
    2238 */
    2339
    2440class ChannelBase
    2541{
    26  public:
     42    friend class ChannelThread;
     43
     44  public:
     45    enum Status { changeUnknown = 'U', changePending = 'P',
     46                  changeFailed = 'F', changeSuccess = 'S' };
     47
    2748    ChannelBase(TVRec *parent);
    28     virtual ~ChannelBase();
     49    virtual ~ChannelBase(void);
    2950
    3051    virtual bool Init(QString &inputname, QString &startchannel, bool setchan);
    3152    virtual bool IsTunable(const QString &input, const QString &channum) const;
    3253
     54    virtual void SelectChannel(const QString & chan);
     55
     56    Status GetStatus(void);
     57    Status Wait(void);
     58
    3359    // Methods that must be implemented.
    3460    /// \brief Opens the channel changing hardware for use.
    3561    virtual bool Open(void) = 0;
    3662    /// \brief Closes the channel changing hardware to use.
    3763    virtual void Close(void) = 0;
    38     virtual bool SetChannelByString(const QString &chan) = 0;
    3964    /// \brief Reports whether channel is already open
    4065    virtual bool IsOpen(void) const = 0;
    4166
    4267    // Methods that one might want to specialize
    4368    /// \brief Sets file descriptor.
    class ChannelBase 
    80105    // Sets
    81106    virtual void Renumber(uint srcid, const QString &oldChanNum,
    82107                          const QString &newChanNum);
    83108
    84109    // Input toggling convenience methods
    85     virtual bool SwitchToInput(const QString &input);
    86     virtual bool SwitchToInput(const QString &input, const QString &chan);
     110//    virtual bool SwitchToInput(const QString &input); // not used?
     111    virtual bool SelectInput(const QString &input, const QString &chan);
    87112
    88113    virtual bool InitializeInputs(void);
    89114
    90115    // Misc. Commands
    91116    virtual bool Retune(void) { return false; }
    class ChannelBase 
    106131    // \brief Set cardid for scanning
    107132    void SetCardID(uint _cardid) { m_cardid = _cardid; }
    108133
    109134    virtual int GetCardID(void) const;
    110135  protected:
     136    virtual bool SetChannelByString(const QString &chan) = 0;
     137
    111138    /// \brief Switches to another input on hardware,
    112139    ///        and sets the channel is setstarting is true.
     140    virtual bool SwitchToInput(const QString &input, const QString &chan);
    113141    virtual bool SwitchToInput(int inputNum, bool setstarting);
    114142    virtual bool IsInputAvailable(
    115143        int inputNum, uint &mplexid_restriction) const;
    116144
    117145    virtual bool ChangeExternalChannel(const QString &newchan);
    118146    static void StoreInputChannels(const InputMap&);
    119147    static void StoreDefaultInput(uint cardid, const QString &input);
    120148    void ClearInputMap(void);
    121149
     150    bool Aborted();
     151    void setStatus(Status status);
     152    void TeardownAll(void);
     153
    122154    TVRec   *m_pParent;
    123155    QString  m_curchannelname;
    124156    int      m_currentInputID;
    125157    bool     m_commfree;
    126158    uint     m_cardid;
    127159    InputMap m_inputs;
    128160    DBChanList m_allchannels; ///< channels across all inputs
     161
     162    QWaitCondition  m_tuneCond;
     163
     164  private:
     165    mutable  ChannelThread   m_tuneThread;
     166    Status   m_tuneStatus;
     167    QMutex   m_thread_lock;
     168    bool     m_abort_change;
    129169};
    130170
    131171#endif
    132172
  • new file libs/libmythtv/channelchangemonitor.cpp

    - +  
     1// -*- Mode: c++ -*-
     2
     3#include <cerrno>
     4#include <unistd.h>
     5#include <sys/ioctl.h>
     6
     7#include "videodev_myth.h"
     8#include "mythcontext.h"
     9#include "channelchangemonitor.h"
     10#include "v4lchannel.h"
     11
     12#define LOC QString("ChannelChangeM: ").arg(channel->GetDevice())
     13#define LOC_ERR QString("ChannelChangeM, Error: ").arg(channel->GetDevice())
     14
     15ChannelChangeMonitor::ChannelChangeMonitor(
     16    int db_cardnum, V4LChannel *_channel, uint64_t _flags) :
     17    SignalMonitor(db_cardnum, _channel, _flags)
     18{
     19}
     20
     21void ChannelChangeMonitor::UpdateValues(void)
     22{
     23    if (!running || exit)
     24        return;
     25
     26    if (!IsChannelTuned())
     27        return;
     28
     29    {
     30        QMutexLocker locker(&statusLock);
     31        signalLock.SetValue(true);
     32        signalStrength.SetValue(100);
     33    }
     34
     35    EmitStatus();
     36    SendMessageAllGood();
     37}
     38
  • new file libs/libmythtv/channelchangemonitor.h

    - +  
     1// -*- Mode: c++ -*-
     2// Copyright (c) 2005, Daniel Thor Kristjansson
     3
     4#ifndef _CHANNEL_CHANGE_MONITOR_H_
     5#define _CHANNEL_CHANGE_MONITOR_H_
     6
     7// MythTV headers
     8#include "signalmonitor.h"
     9
     10class V4LChannel;
     11
     12class ChannelChangeMonitor : public SignalMonitor
     13{
     14  public:
     15    ChannelChangeMonitor(
     16        int db_cardnum, V4LChannel *_channel,
     17        uint64_t _flags = kSigMon_WaitForSig);
     18
     19    virtual void UpdateValues(void);
     20};
     21
     22#endif // _CHANNEL_CHANGE_MONITOR_H_
  • libs/libmythtv/channelscan/channelscan_sm.cpp

    old new void ChannelScanSM::ScanTransport(const  
    16251625        GetDTVSignalMonitor()->GetScanStreamData()->Reset();
    16261626        GetDTVSignalMonitor()->SetChannel(-1,-1);
    16271627    }
    16281628
    16291629    // Start signal monitor for this channel
    1630     signalMonitor->Start();
     1630    signalMonitor->Start(false);
    16311631
    16321632    timer.start();
    16331633    waitingForTables = (item.tuning.sistandard != "analog");
    16341634}
    16351635
  • libs/libmythtv/channelscan/channelscan_sm.h

    old new class AnalogSignalHandler : public Signa 
    7171    AnalogSignalHandler(ChannelScanSM *_siscan) : siscan(_siscan) { }
    7272
    7373  public slots:
    7474    virtual inline void AllGood(void);
    7575    virtual void StatusSignalLock(const SignalMonitorValue&) { }
     76    virtual void StatusChannelTuned(const SignalMonitorValue&) { }
    7677    virtual void StatusSignalStrength(const SignalMonitorValue&) { }
    7778
    7879  private:
    7980    ChannelScanSM *siscan;
    8081};
  • libs/libmythtv/channelscan/scanmonitor.cpp

    old new QEvent::Type ScannerEvent::SetStatusSign 
    5353    (QEvent::Type) QEvent::registerEventType();
    5454QEvent::Type ScannerEvent::SetStatusSignalStrength =
    5555    (QEvent::Type) QEvent::registerEventType();
    5656QEvent::Type ScannerEvent::SetStatusSignalLock =
    5757    (QEvent::Type) QEvent::registerEventType();
     58QEvent::Type ScannerEvent::SetStatusChannelTuned =
     59    (QEvent::Type) QEvent::registerEventType();
    5860
    5961/// Percentage to set to after the transports have been scanned
    6062#define TRANSPORT_PCT 6
    6163/// Percentage to set to after the first tune
    6264#define TUNED_PCT     3
    void ScanMonitor::StatusRotorPosition(co 
    131133void ScanMonitor::StatusSignalLock(const SignalMonitorValue &val)
    132134{
    133135    post_event(this, ScannerEvent::SetStatusSignalLock, val.GetValue());
    134136}
    135137
     138void ScanMonitor::StatusChannelTuned(const SignalMonitorValue &val)
     139{
     140    post_event(this, ScannerEvent::SetStatusChannelTuned, val.GetValue());
     141}
     142
    136143void ScanMonitor::StatusSignalToNoise(const SignalMonitorValue &val)
    137144{
    138145    post_event(this, ScannerEvent::SetStatusSignalToNoise,
    139146               val.GetNormalizedValue(0, 65535));
    140147}
  • libs/libmythtv/channelscan/scanmonitor.h

    old new class ScanMonitor : 
    6363    void ScanComplete(void);
    6464
    6565    // SignalMonitorListener
    6666    virtual void AllGood(void) { }
    6767    virtual void StatusSignalLock(const SignalMonitorValue&);
     68    virtual void StatusChannelTuned(const SignalMonitorValue&);
    6869    virtual void StatusSignalStrength(const SignalMonitorValue&);
    6970
    7071    // DVBSignalMonitorListener
    7172    virtual void StatusSignalToNoise(const SignalMonitorValue&);
    7273    virtual void StatusBitErrorRate(const SignalMonitorValue&) { }
    class ScannerEvent : public QEvent 
    108109    static Type SetPercentComplete;
    109110    static Type SetStatusRotorPosition;
    110111    static Type SetStatusSignalToNoise;
    111112    static Type SetStatusSignalStrength;
    112113    static Type SetStatusSignalLock;
     114    static Type SetStatusChannelTuned;
    113115
    114116  private:
    115117    ~ScannerEvent() { }
    116118
    117119  private:
  • libs/libmythtv/dtvsignalmonitor.cpp

    old new  
    2323DTVSignalMonitor::DTVSignalMonitor(int db_cardnum,
    2424                                   DTVChannel *_channel,
    2525                                   uint64_t wait_for_mask)
    2626    : SignalMonitor(db_cardnum, _channel, wait_for_mask),
    2727      stream_data(NULL),
     28      channelTuned(QObject::tr("Channel Tuned"), "tuned", 3, true, 0, 3, 0),
    2829      seenPAT(QObject::tr("Seen")+" PAT", "seen_pat", 1, true, 0, 1, 0),
    2930      seenPMT(QObject::tr("Seen")+" PMT", "seen_pmt", 1, true, 0, 1, 0),
    3031      seenMGT(QObject::tr("Seen")+" MGT", "seen_mgt", 1, true, 0, 1, 0),
    3132      seenVCT(QObject::tr("Seen")+" VCT", "seen_vct", 1, true, 0, 1, 0),
    3233      seenNIT(QObject::tr("Seen")+" NIT", "seen_nit", 1, true, 0, 1, 0),
    DTVChannel *DTVSignalMonitor::GetDTVChan 
    6162
    6263QStringList DTVSignalMonitor::GetStatusList(bool kick)
    6364{
    6465    QStringList list = SignalMonitor::GetStatusList(kick);
    6566    QMutexLocker locker(&statusLock);
     67
     68    // tuned?
     69    if (flags & kSigMon_Tuned)
     70    {
     71        list<<channelTuned.GetName()<<channelTuned.GetStatus();
     72    }
     73
    6674    // mpeg tables
    6775    if (flags & kDTVSigMon_WaitForPAT)
    6876    {
    6977        list<<seenPAT.GetName()<<seenPAT.GetStatus();
    7078        list<<matchingPAT.GetName()<<matchingPAT.GetStatus();
    void DTVSignalMonitor::RemoveFlags(uint6 
    136144}
    137145
    138146void DTVSignalMonitor::UpdateMonitorValues(void)
    139147{
    140148    QMutexLocker locker(&statusLock);
     149    channelTuned.SetValue((flags & kSigMon_Tuned)      ? 3 : 1);
    141150    seenPAT.SetValue(    (flags & kDTVSigMon_PATSeen)  ? 1 : 0);
    142151    seenPMT.SetValue(    (flags & kDTVSigMon_PMTSeen)  ? 1 : 0);
    143152    seenMGT.SetValue(    (flags & kDTVSigMon_MGTSeen)  ? 1 : 0);
    144153    seenVCT.SetValue(    (flags & kDTVSigMon_VCTSeen)  ? 1 : 0);
    145154    seenNIT.SetValue(    (flags & kDTVSigMon_NITSeen)  ? 1 : 0);
  • libs/libmythtv/dtvsignalmonitor.h

    old new class DTVSignalMonitor : public SignalMo 
    109109    void UpdateListeningForEIT(void);
    110110
    111111  protected:
    112112    MPEGStreamData    *stream_data;
    113113    vector<uint>       eit_pids;
     114    SignalMonitorValue channelTuned;
    114115    SignalMonitorValue seenPAT;
    115116    SignalMonitorValue seenPMT;
    116117    SignalMonitorValue seenMGT;
    117118    SignalMonitorValue seenVCT;
    118119    SignalMonitorValue seenNIT;
  • libs/libmythtv/dvbsignalmonitor.cpp

    old new void DVBSignalMonitor::UpdateValues(void 
    230230
    231231        update_done = true;
    232232        return;
    233233    }
    234234
     235    if (!IsChannelTuned())
     236        return;
     237
    235238    AddFlags(kSigMon_WaitForSig);
    236239
    237240    DVBChannel *dvbchannel = GetDVBChannel();
    238241    if (!dvbchannel)
    239242        return;
  • libs/libmythtv/firewiresignalmonitor.cpp

    old new void FirewireSignalMonitor::AddData(cons 
    188188void FirewireSignalMonitor::UpdateValues(void)
    189189{
    190190    if (!running || exit)
    191191        return;
    192192
     193    if (!IsChannelTuned())
     194        return;
     195
    193196    if (dtvMonitorRunning)
    194197    {
    195198        EmitStatus();
    196199        if (IsAllGood())
    197200            SendMessageAllGood();
  • libs/libmythtv/hdhrchannel.cpp

    old new bool HDHRChannel::SetChannelByString(con 
    141141
    142142    uint mplexid_restriction;
    143143    if (!IsInputAvailable(m_currentInputID, mplexid_restriction))
    144144        return false;
    145145
     146    if (Aborted())
     147        return false;
     148
    146149    // Fetch tuning data from the database.
    147150    QString tvformat, modulation, freqtable, freqid, si_std;
    148151    int finetune;
    149152    uint64_t frequency;
    150153    int mpeg_prog_num;
  • libs/libmythtv/hdhrsignalmonitor.cpp

    old new void HDHRSignalMonitor::UpdateValues(voi 
    103103
    104104        update_done = true;
    105105        return;
    106106    }
    107107
     108    if (!IsChannelTuned())
     109        return;
     110
    108111    struct hdhomerun_tuner_status_t status;
    109112    streamHandler->GetTunerStatus(&status);
    110113
    111114    uint sig = status.signal_strength;
    112115    uint snq = status.signal_to_noise_quality;
  • libs/libmythtv/iptvsignalmonitor.cpp

    old new void IPTVSignalMonitor::AddData( 
    117117void IPTVSignalMonitor::UpdateValues(void)
    118118{
    119119    if (!running || exit)
    120120        return;
    121121
     122    if (!IsChannelTuned())
     123        return;
     124
    122125    if (dtvMonitorRunning)
    123126    {
    124127        EmitStatus();
    125128        if (IsAllGood())
    126129            SendMessageAllGood();
  • libs/libmythtv/libmythtv.pro

    old new using_backend { 
    445445        SOURCES += audioinputoss.cpp
    446446        DEFINES += USING_OSS
    447447        LIBS += $$OSS_LIBS
    448448    }
    449449
     450    HEADERS += channelchangemonitor.h
     451    SOURCES += channelchangemonitor.cpp
     452
    450453    # Support for Video4Linux devices
    451454    using_v4l {
    452455        HEADERS += v4lchannel.h                analogsignalmonitor.h
    453456        SOURCES += v4lchannel.cpp              analogsignalmonitor.cpp
    454457
  • libs/libmythtv/signalmonitor.cpp

    old new  
    66#include <signal.h>
    77#include <unistd.h>
    88
    99// MythTV headers
    1010#include "mythcontext.h"
     11#include "tv_rec.h"
    1112#include "signalmonitor.h"
    1213#include "compat.h"
    1314#include "mythverbose.h"
    1415
    1516extern "C" {
    extern "C" { 
    4041#ifdef USING_FIREWIRE
    4142#   include "firewiresignalmonitor.h"
    4243#   include "firewirechannel.h"
    4344#endif
    4445
     46#include "channelchangemonitor.h"
     47
    4548#undef DBG_SM
    4649#define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \
    4750    "SM("<<channel->GetDevice()<<")::"<<FUNC<<": "<<MSG);
    4851
    4952/** \class SignalMonitor
    SignalMonitor *SignalMonitor::Init(QStri 
    9194            signalMonitor = new DVBSignalMonitor(db_cardnum, dvbc);
    9295    }
    9396#endif
    9497
    9598#ifdef USING_V4L
     99#if 0 // Just use ChannelChangeMonitor for these types
    96100    if ((cardtype.toUpper() == "V4L") ||
    97         (cardtype.toUpper() == "MPEG") ||
    98         (cardtype.toUpper() == "HDPVR"))
     101        (cardtype.toUpper() == "MPEG"))
    99102    {
    100103        V4LChannel *chan = dynamic_cast<V4LChannel*>(channel);
    101104        if (chan)
    102105            signalMonitor = new AnalogSignalMonitor(db_cardnum, chan);
    103106    }
    104107#endif
     108#endif
    105109
    106110#ifdef USING_HDHOMERUN
    107111    if (cardtype.toUpper() == "HDHOMERUN")
    108112    {
    109113        HDHRChannel *hdhrc = dynamic_cast<HDHRChannel*>(channel);
    SignalMonitor *SignalMonitor::Init(QStri 
    130134    }
    131135#endif
    132136
    133137    if (!signalMonitor)
    134138    {
     139        V4LChannel *chan = dynamic_cast<V4LChannel*>(channel);
     140        if (chan)
     141            signalMonitor = new ChannelChangeMonitor(db_cardnum, chan);
     142    }
     143
     144    if (!signalMonitor)
     145    {
    135146        VERBOSE(VB_IMPORTANT,
    136147                QString("Failed to create signal monitor in Init(%1, %2, 0x%3)")
    137148                .arg(cardtype).arg(db_cardnum).arg((long)channel,0,16));
    138149    }
    139150
    SignalMonitor::SignalMonitor(int _captur 
    158169    : channel(_channel),
    159170      capturecardnum(_capturecardnum), flags(wait_for_mask),
    160171      update_rate(25),                 minimum_update_rate(5),
    161172      running(false),                  exit(false),
    162173      update_done(false),              notify_frontend(true),
    163       error(""),
     174      is_tuned(false),                 tablemon(false),
     175      eit_scan(false),                 error(""),
    164176      signalLock    (QObject::tr("Signal Lock"),  "slock",
    165177                     1, true, 0,   1, 0),
    166178      signalStrength(QObject::tr("Signal Power"), "signal",
    167179                     0, true, 0, 100, 0),
     180      channelTuned("Channel Tuned", "tuned", 3, true, 0, 3, 0),
    168181      statusLock(QMutex::Recursive)
    169182{
    170183}
    171184
    172185/** \fn SignalMonitor::~SignalMonitor()
    bool SignalMonitor::HasAnyFlag(uint64_t  
    200213}
    201214
    202215/** \fn SignalMonitor::Start()
    203216 *  \brief Start signal monitoring thread.
    204217 */
    205 void SignalMonitor::Start()
     218void SignalMonitor::Start(bool waitfor_tune)
    206219{
    207220    DBG_SM("Start", "begin");
    208221    {
    209222        QMutexLocker locker(&startStopLock);
     223
     224        // When used for scanning, don't wait for the tuning thread
     225        is_tuned = !waitfor_tune;
     226
    210227        if (!running)
    211228        {
    212229            int rval = pthread_create(
    213230                &monitor_thread, NULL, SpawnMonitorLoop, this);
    214231
    QStringList SignalMonitor::GetStatusList 
    277294    else if (!running)
    278295        UpdateValues();
    279296
    280297    QStringList list;
    281298    statusLock.lock();
     299    list<<channelTuned.GetName()<<channelTuned.GetStatus();
    282300    list<<signalLock.GetName()<<signalLock.GetStatus();
    283301    if (HasFlags(kSigMon_WaitForSig))
    284302        list<<signalStrength.GetName()<<signalStrength.GetStatus();
    285303    statusLock.unlock();
    286304
    void SignalMonitor::MonitorLoop() 
    304322        if (notify_frontend && capturecardnum>=0)
    305323        {
    306324            QStringList slist = GetStatusList(false);
    307325            MythEvent me(QString("SIGNAL %1").arg(capturecardnum), slist);
    308326            gContext->dispatch(me);
    309             //cerr<<"sent SIGNAL"<<endl;
    310327        }
    311328
    312329        usleep(update_rate * 1000);
    313330    }
    314331
    void SignalMonitor::SendMessage( 
    439456            listener->AllGood();
    440457            break;
    441458        case kStatusSignalStrength:
    442459            listener->StatusSignalStrength(val);
    443460            break;
     461        case kStatusChannelTuned:
     462            listener->StatusChannelTuned(val);
     463            break;
    444464        case kStatusSignalToNoise:
    445465            if (dvblistener)
    446466                dvblistener->StatusSignalToNoise(val);
    447467            break;
    448468        case kStatusBitErrorRate:
    void SignalMonitor::SendMessage( 
    459479            break;
    460480        }
    461481    }
    462482}
    463483
     484bool SignalMonitor::IsChannelTuned(void)
     485{
     486    if (is_tuned)
     487        return true;
     488
     489    ChannelBase::Status status = channel->GetStatus();
     490    QMutexLocker locker(&statusLock);
     491
     492    switch (status) {
     493      case ChannelBase::changePending:
     494        channelTuned.SetValue(1);
     495        break;
     496      case ChannelBase::changeFailed:
     497        channelTuned.SetValue(2);
     498        break;
     499      case ChannelBase::changeSuccess:
     500        channelTuned.SetValue(3);
     501        break;
     502    }
     503
     504    EmitStatus();
     505
     506    if (status == ChannelBase::changeSuccess)
     507    {
     508        if (tablemon)
     509            pParent->SetupDTVSignalMonitor(eit_scan);
     510
     511        is_tuned = true;
     512        return true;
     513    }
     514
     515    return false;
     516}
     517
    464518void SignalMonitor::SendMessageAllGood(void)
    465519{
    466520    QMutexLocker locker(&listenerLock);
    467521    for (uint i = 0; i < listeners.size(); i++)
    468522        listeners[i]->AllGood();
    469523}
    470524
    471525void SignalMonitor::EmitStatus(void)
    472526{
     527    SendMessage(kStatusChannelTuned, channelTuned);
    473528    SendMessage(kStatusSignalLock, signalLock);
    474529    if (HasFlags(kSigMon_WaitForSig))
    475530        SendMessage(kStatusSignalStrength,    signalStrength);
    476531}
  • libs/libmythtv/signalmonitor.h

    old new using namespace std; 
    2424#define DBG_SM(FUNC, MSG) VERBOSE(VB_CHANNEL, \
    2525    "SM("<<channel->GetDevice()<<")::"<<FUNC<<": "<<MSG);
    2626
    2727inline QString sm_flags_to_string(uint64_t);
    2828
     29class TVRec;
     30
    2931class SignalMonitor
    3032{
    3133  public:
    3234    /// Returns true iff the card type supports signal monitoring.
    3335    static inline bool IsRequired(const QString &cardtype);
    class SignalMonitor 
    3739    virtual ~SignalMonitor();
    3840
    3941    // // // // // // // // // // // // // // // // // // // // // // // //
    4042    // Control  // // // // // // // // // // // // // // // // // // // //
    4143
    42     virtual void Start();
     44    virtual void Start(bool waitfor_tune);
    4345    virtual void Stop();
    4446    virtual void Kick();
    4547    virtual bool WaitForLock(int timeout = -1);
    4648
    4749    // // // // // // // // // // // // // // // // // // // // // // // //
    class SignalMonitor 
    8183     *  \param notify if true SIGNAL MythEvents are sent to the frontend,
    8284     *         otherwise they are not.
    8385     */
    8486    void SetNotifyFrontend(bool notify) { notify_frontend = notify; }
    8587
     88    /** \brief Indicate if table monitoring is needed
     89     *  \param monitor if true parent->SetupDTVSignalMonitor is called
     90     *         after the channel is tuned.
     91     */
     92    void SetMonitoring(TVRec * parent, bool EITscan, bool monitor)
     93        { pParent = parent; eit_scan = EITscan, tablemon = monitor; }
     94
    8695    /** \brief Sets the number of milliseconds between signal monitoring
    8796     *         attempts in the signal monitoring thread.
    8897     *
    8998     *   Defaults to 25 milliseconds.
    9099     *  \param msec Milliseconds between signal monitoring events.
    class SignalMonitor 
    106115                  uint64_t wait_for_mask);
    107116
    108117    static void* SpawnMonitorLoop(void*);
    109118    virtual void MonitorLoop();
    110119
     120    bool IsChannelTuned(void);
     121
    111122    /// \brief This should be overridden to actually do signal monitoring.
    112123    virtual void UpdateValues() { ; }
    113124
    114125  public:
    115126    /// We've seen a PAT,
    class SignalMonitor 
    137148    /// We've seen the FireWire STB power state
    138149    static const uint64_t kFWSigMon_PowerSeen   = 0x0000000100ULL;
    139150    /// We've seen something indicating whether the data stream is encrypted
    140151    static const uint64_t kDTVSigMon_CryptSeen  = 0x0000000200ULL;
    141152
     153    static const uint64_t kSigMon_Tuned         = 0x0000000400ULL;
     154
    142155    /// We've seen a PAT matching our requirements
    143156    static const uint64_t kDTVSigMon_PATMatch   = 0x0000001000ULL;
    144157    /// We've seen a PMT matching our requirements
    145158    static const uint64_t kDTVSigMon_PMTMatch   = 0x0000002000ULL;
    146159    /// We've seen an MGT matching our requirements
    class SignalMonitor 
    182195    static const uint64_t kDVBSigMon_WaitForPos = 0x8000000000ULL;
    183196
    184197  protected:
    185198    pthread_t    monitor_thread;
    186199    ChannelBase *channel;
     200    TVRec       *pParent;
    187201    int          capturecardnum;
    188202    uint64_t     flags;
    189203    int          update_rate;
    190204    uint         minimum_update_rate;
    191205    bool         running;
    192206    bool         exit;
    193207    bool         update_done;
    194208    bool         notify_frontend;
     209    bool         is_tuned;
     210    bool         tablemon;
     211    bool         eit_scan;
    195212    QString      error;
    196213
    197214    SignalMonitorValue signalLock;
    198215    SignalMonitorValue signalStrength;
     216    SignalMonitorValue channelTuned;
    199217
    200218    vector<SignalMonitorListener*> listeners;
    201219
    202220    QMutex             startStopLock;
    203221    mutable QMutex     statusLock;
  • libs/libmythtv/signalmonitorlistener.h

    old new  
    77#include "mythexp.h"
    88#include "signalmonitorvalue.h"
    99
    1010typedef enum {
    1111    kAllGood,
     12    kStatusChannelTuned,
    1213    kStatusSignalLock,
    1314    kStatusSignalStrength,
    1415    kStatusSignalToNoise,
    1516    kStatusBitErrorRate,
    1617    kStatusUncorrectedBlocks,
    class MPUBLIC SignalMonitorListener 
    2829     *   Note: Signals are only sent once the monitoring thread
    2930     *         has been started.
    3031     */
    3132    virtual void AllGood(void) = 0;
    3233
     34    /** \brief Signal to be sent with change change status.
     35     *
     36     *   Note: Signals are only sent once the monitoring thread
     37     *         has been started.
     38     */
     39    virtual void StatusChannelTuned(const SignalMonitorValue&) = 0;
     40
    3341    /** \brief Signal to be sent as true when it is safe to begin
    3442     *   or continue recording, and false if it may not be safe.
    3543     *
    3644     *   Note: Signals are only sent once the monitoring thread
    3745     *         has been started.
  • libs/libmythtv/tv_play.cpp

    old new void TV::UpdateOSDSignal(const PlayerCon 
    74477447
    74487448    uint  sig  = 0;
    74497449    float snr  = 0.0f;
    74507450    uint  ber  = 0xffffffff;
    74517451    int   pos  = -1;
     7452    int   tuned = -1;
    74527453    QString pat(""), pmt(""), mgt(""), vct(""), nit(""), sdt(""), crypt("");
    74537454    QString err = QString::null, msg = QString::null;
    74547455    for (it = slist.begin(); it != slist.end(); ++it)
    74557456    {
    74567457        if ("error" == it->GetShortName())
    void TV::UpdateOSDSignal(const PlayerCon 
    74737474            snr = it->GetValue();
    74747475        else if ("ber" == it->GetShortName())
    74757476            ber = it->GetValue();
    74767477        else if ("pos" == it->GetShortName())
    74777478            pos = it->GetValue();
     7479        else if ("tuned" == it->GetShortName())
     7480            tuned = it->GetValue();
    74787481        else if ("seen_pat" == it->GetShortName())
    74797482            pat = it->IsGood() ? "a" : "_";
    74807483        else if ("matching_pat" == it->GetShortName())
    74817484            pat = it->IsGood() ? "A" : pat;
    74827485        else if ("seen_pmt" == it->GetShortName())
    void TV::UpdateOSDSignal(const PlayerCon 
    75067509    }
    75077510    if (sig)
    75087511        infoMap["signal"] = QString::number(sig); // use normalized value
    75097512
    75107513    bool    allGood = SignalMonitorValue::AllGood(slist);
     7514    char    tuneCode;
    75117515    QString slock   = ("1" == infoMap["slock"]) ? "L" : "l";
    75127516    QString lockMsg = (slock=="L") ? tr("Partial Lock") : tr("No Lock");
    75137517    QString sigMsg  = allGood ? tr("Lock") : lockMsg;
    75147518
    75157519    QString sigDesc = tr("Signal %1\%").arg(sig,2);
    void TV::UpdateOSDSignal(const PlayerCon 
    75187522    if (ber != 0xffffffff)
    75197523        sigDesc += " | " + tr("BE %1", "Bit Errors").arg(ber, 2);
    75207524    if ((pos >= 0) && (pos < 100))
    75217525        sigDesc += " | " + tr("Rotor %1\%").arg(pos,2);
    75227526
    7523     sigDesc = sigDesc + QString(" | (%1%2%3%4%5%6%7%8) %9")
    7524         .arg(slock).arg(pat).arg(pmt).arg(mgt).arg(vct)
    7525         .arg(nit).arg(sdt).arg(crypt).arg(sigMsg);
     7527    if (tuned == 1)
     7528        tuneCode = 't';
     7529    else if (tuned == 2)
     7530        tuneCode = 'F';
     7531    else if (tuned == 3)
     7532        tuneCode = 'T';
     7533    else
     7534        tuneCode = '_';
     7535
     7536    sigDesc = sigDesc + QString(" | (%1%2%3%4%5%6%7%8%9) %10")
     7537              .arg(tuneCode).arg(slock).arg(pat).arg(pmt).arg(mgt).arg(vct)
     7538              .arg(nit).arg(sdt).arg(crypt).arg(sigMsg);
    75267539
    75277540    if (!err.isEmpty())
    75287541        sigDesc = err;
    75297542    else if (!msg.isEmpty())
    75307543        sigDesc = msg;
  • libs/libmythtv/tv_rec.cpp

    old new ProgramInfo *TVRec::GetRecording(void) 
    365365 *  \param hasLater If true, a later non-conflicting showing is available.
    366366 */
    367367void TVRec::RecordPending(const ProgramInfo *rcinfo, int secsleft,
    368368                          bool hasLater)
    369369{
    370     QMutexLocker lock(&stateChangeLock);
     370    QMutexLocker statelock(&stateChangeLock);
     371    QMutexLocker pendlock(&pendingRecLock);
    371372
    372373    if (secsleft < 0)
    373374    {
    374375        VERBOSE(VB_RECORD, LOC + "Pending recording revoked on " +
    375376                QString("inputid %1").arg(rcinfo->inputid));
    void TVRec::RecordPending(const ProgramI 
    403404    vector<uint> cardids = CardUtil::GetConflictingCards(
    404405        rcinfo->inputid, cardid);
    405406
    406407    pendingRecordings[rcinfo->cardid].possibleConflicts = cardids;
    407408
    408     stateChangeLock.unlock();
     409    statelock.unlock();
    409410    for (uint i = 0; i < cardids.size(); i++)
    410411        RemoteRecordPending(cardids[i], rcinfo, secsleft, hasLater);
    411     stateChangeLock.lock();
     412    statelock.relock();
    412413}
    413414
    414415/** \fn TVRec::SetPseudoLiveTVRecording(ProgramInfo*)
    415416 *  \brief Sets the pseudo LiveTV ProgramInfo
    416417 */
    QDateTime TVRec::GetRecordEndTime(const  
    438439 *  \sa RecordPending(const ProgramInfo*, int, bool),
    439440 *      TV::AskAllowRecording(const QStringList&, int, bool)
    440441 */
    441442void TVRec::CancelNextRecording(bool cancel)
    442443{
     444    QMutexLocker pendlock(&pendingRecLock);
    443445    VERBOSE(VB_RECORD, LOC + "CancelNextRecording("<<cancel<<") -- begin");
    444446
    445447    PendingMap::iterator it = pendingRecordings.find(cardid);
    446448    if (it == pendingRecordings.end())
    447449    {
    RecStatusType TVRec::StartRecording(cons 
    520522
    521523        retval = rsRecording;
    522524        return retval;
    523525    }
    524526
    525     PendingMap::iterator it = pendingRecordings.find(cardid);
    526527    bool cancelNext = false;
    527     if (it != pendingRecordings.end())
     528    PendingInfo pendinfo;
     529    PendingMap::iterator it;
     530    bool has_pending;
     531
     532    pendingRecLock.lock();
     533    if ((it = pendingRecordings.find(cardid)) != pendingRecordings.end())
    528534    {
    529535        (*it).ask = (*it).doNotAsk = false;
    530536        cancelNext = (*it).canceled;
    531537    }
     538    pendingRecLock.unlock();
    532539
    533540    // Flush out events...
    534541    WaitForEventThreadSleep();
    535542
    536543    // Rescan pending recordings since the event loop may have deleted
    537544    // a stale entry.  If this happens the info pointer will not be valid
    538545    // since the HandlePendingRecordings loop will have deleted it.
     546    pendingRecLock.lock();
    539547    it = pendingRecordings.find(cardid);
     548    has_pending = (it != pendingRecordings.end());
     549    if (has_pending)
     550        pendinfo = *it;
     551    pendingRecLock.unlock();
    540552
    541553    // If the needed input is in a shared input group, and we are
    542554    // not canceling the recording anyway, check other recorders
    543     if (!cancelNext &&
    544         (it != pendingRecordings.end()) && (*it).possibleConflicts.size())
     555    if (!cancelNext && has_pending && pendinfo.possibleConflicts.size())
    545556    {
    546557        VERBOSE(VB_RECORD, LOC + "Checking input group recorders - begin");
    547         vector<uint> &cardids = (*it).possibleConflicts;
     558        vector<uint> &cardids = pendinfo.possibleConflicts;
    548559
    549560        uint mplexid = 0, sourceid = 0;
    550561        vector<uint> cardids2;
    551562        vector<TVState> states;
    552563
    RecStatusType TVRec::StartRecording(cons 
    565576                    busy_input.inputid, rcinfo->inputid);
    566577            }
    567578
    568579            if (is_busy && !sourceid)
    569580            {
    570                 mplexid  = (*it).info->GetMplexID();
    571                 sourceid = (*it).info->sourceid;
     581                mplexid  = pendinfo.info->GetMplexID();
     582                sourceid = pendinfo.info->sourceid;
    572583            }
    573584
    574585            if (is_busy &&
    575586                ((sourceid != busy_input.sourceid) ||
    576587                 (mplexid  != busy_input.mplexid)))
    void TVRec::HandleStateChange(void) 
    953964 *  \brief Puts a state change on the nextState queue.
    954965 */
    955966void TVRec::ChangeState(TVState nextState)
    956967{
    957968    QMutexLocker lock(&stateChangeLock);
    958 
    959969    desiredNextState = nextState;
    960970    changeState = true;
    961971    WakeEventLoop();
    962972}
    963973
    void TVRec::RunTV(void) 
    14261436        if (GetState() == kState_WatchingLiveTV)
    14271437        {
    14281438            QDateTime now   = QDateTime::currentDateTime();
    14291439            bool has_finish = HasFlags(kFlagFinishRecording);
    14301440            bool has_rec    = pseudoLiveTVRecording;
     1441            bool enable_ui  = true;
     1442
     1443            pendingRecLock.lock();
    14311444            bool rec_soon   =
    14321445                pendingRecordings.find(cardid) != pendingRecordings.end();
    1433             bool enable_ui  = true;
     1446            pendingRecLock.unlock();
    14341447
    14351448            if (has_rec && (has_finish || (now > recordEndTime)))
    14361449            {
    14371450                if (pseudoLiveTVRecording && curRecording)
    14381451                {
    bool TVRec::WaitForEventThreadSleep(bool 
    15991612    return ok;
    16001613}
    16011614
    16021615void TVRec::HandlePendingRecordings(void)
    16031616{
     1617    QMutexLocker pendlock(&pendingRecLock);
     1618
    16041619    if (pendingRecordings.empty())
    16051620        return;
    16061621
    16071622    // If we have a pending recording and AskAllowRecording
    16081623    // or DoNotAskAllowRecording is set and the frontend is
    bool ApplyCachedPids(DTVSignalMonitor *d 
    18871902 *   program number in the PAT.
    18881903 *
    18891904 *   This method also grabs the ATSCStreamData() from the recorder
    18901905 *   if possible, or creates one if needed.
    18911906 */
    1892 bool TVRec::SetupDTVSignalMonitor(void)
     1907bool TVRec::SetupDTVSignalMonitor(bool EITscan)
    18931908{
    18941909    VERBOSE(VB_RECORD, LOC + "Setting up table monitoring.");
    18951910
    18961911    DTVSignalMonitor *sm = GetDTVSignalMonitor();
    18971912    DTVChannel *dtvchan = GetDTVChannel();
    bool TVRec::SetupDTVSignalMonitor(void) 
    20212036        sm->AddFlags(SignalMonitor::kDTVSigMon_WaitForPAT |
    20222037                     SignalMonitor::kDTVSigMon_WaitForPMT |
    20232038                     SignalMonitor::kDVBSigMon_WaitForPos);
    20242039        sm->SetRotorTarget(1.0f);
    20252040
     2041        if (EITscan)
     2042        {
     2043            sm->GetStreamData()->SetVideoStreamsRequired(0);
     2044            sm->IgnoreEncrypted(true);
     2045        }
     2046
    20262047        VERBOSE(VB_RECORD, LOC + "Successfully set up MPEG table monitoring.");
    20272048        return true;
    20282049    }
    20292050
    20302051    QString msg = "No valid DTV info, ATSC maj(%1) min(%2), MPEG pn(%3)";
    bool TVRec::SetupDTVSignalMonitor(void) 
    20422063 *
    20432064 *  \param tablemon If set we enable table monitoring
    20442065 *  \param notify   If set we notify the frontend of the signal values
    20452066 *  \return true on success, false on failure
    20462067 */
    2047 bool TVRec::SetupSignalMonitor(bool tablemon, bool notify)
     2068bool TVRec::SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
    20482069{
    20492070    VERBOSE(VB_RECORD, LOC + "SetupSignalMonitor("
    20502071            <<tablemon<<", "<<notify<<")");
    20512072
    20522073    // if it already exists, there no need to initialize it
    bool TVRec::SetupSignalMonitor(bool tabl 
    20582079        return false;
    20592080
    20602081    // make sure statics are initialized
    20612082    SignalMonitorValue::Init();
    20622083
    2063     if (SignalMonitor::IsSupported(genOpt.cardtype) && channel->Open())
    2064         signalMonitor = SignalMonitor::Init(genOpt.cardtype, cardid, channel);
     2084    if (channel->Open())
     2085        signalMonitor = SignalMonitor::Init(genOpt.cardtype, cardid,
     2086                                            channel);
    20652087
    20662088    if (signalMonitor)
    20672089    {
    20682090        VERBOSE(VB_RECORD, LOC + "Signal monitor successfully created");
    2069         // If this is a monitor for Digital TV, initialize table monitors
    2070         if (GetDTVSignalMonitor() && tablemon && !SetupDTVSignalMonitor())
    2071         {
    2072             VERBOSE(VB_IMPORTANT, LOC_ERR +
    2073                     "Failed to setup digital signal monitoring");
    2074 
    2075             return false;
    2076         }
    20772091
     2092        signalMonitor->SetMonitoring(this, EITscan,
     2093                                     GetDTVSignalMonitor() && tablemon);
    20782094        signalMonitor->AddListener(this);
    20792095        signalMonitor->SetUpdateRate(kSignalMonitoringRate);
    20802096        signalMonitor->SetNotifyFrontend(notify);
    20812097
    20822098        // Start the monitoring thread
    2083         signalMonitor->Start();
     2099        signalMonitor->Start(true);
    20842100    }
    20852101
    20862102    return true;
    20872103}
    20882104
    bool TVRec::IsReallyRecording(void) 
    24832499 *         the next time_buffer seconds.
    24842500 *  \sa EncoderLink::IsBusy(TunedInputInfo*, int time_buffer)
    24852501 */
    24862502bool TVRec::IsBusy(TunedInputInfo *busy_input, int time_buffer) const
    24872503{
    2488     QMutexLocker lock(&stateChangeLock);
    2489 
    24902504    TunedInputInfo dummy;
    24912505    if (!busy_input)
    24922506        busy_input = &dummy;
    24932507
    24942508    busy_input->Clear();
    bool TVRec::IsBusy(TunedInputInfo *busy_ 
    25062520    {
    25072521        busy_input->inputid = channel->GetCurrentInputNum();
    25082522        chanid              = channel->GetChanID();
    25092523    }
    25102524
    2511     PendingMap::const_iterator it = pendingRecordings.find(cardid);
    2512     if (!busy_input->inputid && (it != pendingRecordings.end()))
     2525    PendingInfo pendinfo;
     2526    bool        has_pending;
     2527    {
     2528        pendingRecLock.lock();
     2529        PendingMap::const_iterator it = pendingRecordings.find(cardid);
     2530        has_pending = (it != pendingRecordings.end());
     2531        if (has_pending)
     2532            pendinfo = *it;
     2533        pendingRecLock.unlock();
     2534    }
     2535
     2536    if (!busy_input->inputid && has_pending)
    25132537    {
    25142538        int timeLeft = QDateTime::currentDateTime()
    2515             .secsTo((*it).recordingStart);
     2539            .secsTo(pendinfo.recordingStart);
    25162540
    25172541        if (timeLeft <= time_buffer)
    25182542        {
    25192543            QString channum = QString::null, input = QString::null;
    2520             if ((*it).info->GetChannel(channum, input))
     2544            if (pendinfo.info->GetChannel(channum, input))
    25212545            {
    25222546                busy_input->inputid = channel->GetInputByName(input);
    2523                 chanid = (*it).info->chanid.toUInt();
     2547                chanid = pendinfo.info->chanid.toUInt();
    25242548            }
    25252549        }
    25262550    }
    25272551
    25282552    if (busy_input->inputid)
    void TVRec::TuningShutdowns(const Tuning 
    36763700 *   appropriate.
    36773701 */
    36783702void TVRec::TuningFrequency(const TuningRequest &request)
    36793703{
    36803704    DTVChannel *dtvchan = GetDTVChannel();
     3705
     3706    bool livetv = request.flags & kFlagLiveTV;
     3707    bool antadj = request.flags & kFlagAntennaAdjust;
     3708    bool has_dummy = false;
     3709
    36813710    if (dtvchan)
    36823711    {
    36833712        MPEGStreamData *mpeg = NULL;
    36843713
    36853714        if (GetDTVRecorder())
    void TVRec::TuningFrequency(const Tuning 
    36923721
    36933722        dtvchan->SetTuningMode(tuningmode);
    36943723
    36953724        if (request.minorChan && (tuningmode == "atsc"))
    36963725        {
    3697             channel->SetChannelByString(request.channel);
    3698 
     3726            channel->SelectChannel(request.channel);
    36993727            ATSCStreamData *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
    37003728            if (atsc)
    37013729                atsc->SetDesiredChannel(request.majorChan, request.minorChan);
    37023730        }
    37033731        else if (request.progNum >= 0)
    37043732        {
    3705             channel->SetChannelByString(request.channel);
    3706 
     3733            channel->SelectChannel(request.channel);
    37073734            if (mpeg)
    37083735                mpeg->SetDesiredProgram(request.progNum);
    37093736        }
    37103737    }
    37113738
    void TVRec::TuningFrequency(const Tuning 
    37303757        ok = true;
    37313758
    37323759    if (channel && !channum.isEmpty())
    37333760    {
    37343761        if (!input.isEmpty())
    3735             ok = channel->SwitchToInput(input, channum);
     3762            channel->SelectInput(input, channum);
    37363763        else
    3737             ok = channel->SetChannelByString(channum);
     3764            channel->SelectChannel(channum);
     3765
     3766        ok = true;
    37383767    }
    37393768
    37403769    if (!ok)
    37413770    {
    37423771        if (!(request.flags & kFlagLiveTV) || !(request.flags & kFlagEITScan))
    void TVRec::TuningFrequency(const Tuning 
    37593788            VERBOSE(VB_IMPORTANT, LOC_ERR +
    37603789                    QString("Failed to set channel to %1.").arg(channum));
    37613790        }
    37623791    }
    37633792
    3764     bool livetv = request.flags & kFlagLiveTV;
    3765     bool antadj = request.flags & kFlagAntennaAdjust;
    3766     bool use_sm = SignalMonitor::IsRequired(genOpt.cardtype);
    3767     bool use_dr = use_sm && (livetv || antadj);
    3768     bool has_dummy = false;
    3769 
    3770     if (use_dr)
     3793    if (livetv || antadj)
    37713794    {
    37723795        // We need there to be a ringbuffer for these modes
    37733796        bool ok;
    37743797        ProgramInfo *tmp = pseudoLiveTVRecording;
    37753798        pseudoLiveTVRecording = NULL;
    void TVRec::TuningFrequency(const Tuning 
    37913814        }
    37923815
    37933816        has_dummy = true;
    37943817    }
    37953818
    3796     // Start signal monitoring for devices capable of monitoring
    3797     if (use_sm)
     3819    // Start signal (or channel change) monitoring
     3820    VERBOSE(VB_RECORD, LOC + "Starting Signal Monitor");
     3821    bool error = false;
     3822    if (!SetupSignalMonitor(!antadj, request.flags & kFlagEITScan,
     3823                            livetv | antadj))
    37983824    {
    3799         VERBOSE(VB_RECORD, LOC + "Starting Signal Monitor");
    3800         bool error = false;
    3801         if (!SetupSignalMonitor(!antadj, livetv | antadj))
    3802         {
    3803             VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to setup signal monitor");
    3804             if (signalMonitor)
    3805             {
    3806                 delete signalMonitor;
    3807                 signalMonitor = NULL;
    3808             }
    3809 
    3810             // pretend the signal monitor is running to prevent segfault
    3811             SetFlags(kFlagSignalMonitorRunning);
    3812             ClearFlags(kFlagWaitingForSignal);
    3813             error = true;
    3814         }
    3815 
     3825        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to setup signal monitor");
    38163826        if (signalMonitor)
    38173827        {
    3818             if (request.flags & kFlagEITScan)
    3819             {
    3820                 GetDTVSignalMonitor()->GetStreamData()->
    3821                     SetVideoStreamsRequired(0);
    3822                 GetDTVSignalMonitor()->IgnoreEncrypted(true);
    3823             }
    3824 
    3825             SetFlags(kFlagSignalMonitorRunning);
    3826             ClearFlags(kFlagWaitingForSignal);
    3827             if (!antadj)
    3828                 SetFlags(kFlagWaitingForSignal);
     3828            delete signalMonitor;
     3829            signalMonitor = NULL;
    38293830        }
    38303831
    3831         if (has_dummy && ringBuffer)
    3832         {
    3833             // Make sure recorder doesn't point to bogus ringbuffer before
    3834             // it is potentially restarted without a new ringbuffer, if
    3835             // the next channel won't tune and the user exits LiveTV.
    3836             if (recorder)
    3837                 recorder->SetRingBuffer(NULL);
     3832        // pretend the signal monitor is running to prevent segfault
     3833        SetFlags(kFlagSignalMonitorRunning);
     3834        ClearFlags(kFlagWaitingForSignal);
     3835        error = true;
     3836    }
    38383837
    3839             SetFlags(kFlagDummyRecorderRunning);
    3840             VERBOSE(VB_RECORD, "DummyDTVRecorder -- started");
    3841             SetFlags(kFlagRingBufferReady);
    3842         }
     3838    if (signalMonitor)
     3839    {
     3840        SetFlags(kFlagSignalMonitorRunning);
     3841        ClearFlags(kFlagWaitingForSignal);
     3842        if (!antadj)
     3843            SetFlags(kFlagWaitingForSignal);
     3844    }
    38433845
    3844         // if we had problems starting the signal monitor,
    3845         // we don't want to start the recorder...
    3846         if (error)
    3847             return;
     3846    if (has_dummy && ringBuffer)
     3847    {
     3848        // Make sure recorder doesn't point to bogus ringbuffer before
     3849        // it is potentially restarted without a new ringbuffer, if
     3850        // the next channel won't tune and the user exits LiveTV.
     3851        if (recorder)
     3852            recorder->SetRingBuffer(NULL);
     3853
     3854        SetFlags(kFlagDummyRecorderRunning);
     3855        VERBOSE(VB_RECORD, "DummyDTVRecorder -- started");
     3856        SetFlags(kFlagRingBufferReady);
    38483857    }
    38493858
     3859    // if we had problems starting the signal monitor,
     3860    // we don't want to start the recorder...
     3861    if (error)
     3862        return;
     3863
    38503864    // Request a recorder, if the command is a recording command
    38513865    ClearFlags(kFlagNeedToStartRecorder);
    38523866    if (request.flags & kFlagRec && !antadj)
    38533867        SetFlags(kFlagNeedToStartRecorder);
    38543868}
  • libs/libmythtv/tv_rec.h

    old new class PendingInfo 
    148148typedef QMap<uint,PendingInfo> PendingMap;
    149149
    150150class MPUBLIC TVRec : public SignalMonitorListener
    151151{
    152152    friend class TuningRequest;
     153    friend class SignalMonitor;
    153154
    154155  public:
    155156    TVRec(int capturecardnum);
    156157   ~TVRec(void);
    157158
    class MPUBLIC TVRec : public SignalMonit 
    242243    uint GetFlags(void) const { return stateFlags; }
    243244
    244245    static TVRec *GetTVRec(uint cardid);
    245246
    246247    virtual void AllGood(void) { WakeEventLoop(); }
     248    virtual void StatusChannelTuned(const SignalMonitorValue&) { }
    247249    virtual void StatusSignalLock(const SignalMonitorValue&) { }
    248250    virtual void StatusSignalStrength(const SignalMonitorValue&) { }
    249251
    250252  protected:
    251253    void RunTV(void);
    252254    bool WaitForEventThreadSleep(bool wake = true, ulong time = ULONG_MAX);
    253255    static void *EventThread(void *param);
    254256    static void *RecorderThread(void *param);
     257    bool SetupDTVSignalMonitor(bool EITscan);
    255258
    256259  private:
    257260    void SetRingBuffer(RingBuffer *);
    258261    void SetPseudoLiveTVRecording(ProgramInfo*);
    259262    void TeardownAll(void);
    class MPUBLIC TVRec : public SignalMonit 
    279282    HDHRChannel  *GetHDHRChannel(void);
    280283    DVBChannel   *GetDVBChannel(void);
    281284    FirewireChannel *GetFirewireChannel(void);
    282285    V4LChannel   *GetV4LChannel(void);
    283286
    284     bool SetupSignalMonitor(bool enable_table_monitoring, bool notify);
    285     bool SetupDTVSignalMonitor(void);
     287    bool SetupSignalMonitor(bool enable_table_monitoring,
     288                            bool EITscan, bool notify);
    286289    void TeardownSignalMonitor(void);
    287290    DTVSignalMonitor *GetDTVSignalMonitor(void);
    288291
    289292    bool HasFlags(uint f) const { return (stateFlags & f) == f; }
    290293    void SetFlags(uint f);
    class MPUBLIC TVRec : public SignalMonit 
    358361    DVBDBOptions       dvbOpt;
    359362    FireWireDBOptions  fwOpt;
    360363
    361364    // State variables
    362365    mutable QMutex stateChangeLock;
     366    mutable QMutex pendingRecLock;
    363367    TVState        internalState;
    364368    TVState        desiredNextState;
    365369    bool           changeState;
    366370    bool           pauseNotify;
    367371    uint           stateFlags;
  • libs/libmythtv/v4lchannel.h

    old new class V4LChannel : public DTVChannel 
    4747    int  GetFd(void)        const { return videofd; }
    4848    QString GetDevice(void) const { return device; }
    4949    QString GetSIStandard(void) const { return "atsc"; }
    5050
    5151    // Commands
    52     bool SwitchToInput(int newcapchannel, bool setstarting);
    5352    bool Retune(void);
    5453
    5554    // Picture attributes.
    5655    bool InitPictureAttributes(void);
    5756    int  GetPictureAttribute(PictureAttribute) const;
    class V4LChannel : public DTVChannel 
    6766
    6867    // Analog scanning stuff
    6968    bool Tune(uint frequency, QString inputname,
    7069              QString modulation, QString si_std);
    7170
     71  protected:
     72    bool SwitchToInput(int newcapchannel, bool setstarting);
     73
    7274  private:
    7375    // Helper Sets
    7476    void SetFreqTable(const int index);
    7577    int  SetFreqTable(const QString &name);
    7678    bool SetInputAndFormat(int newcapchannel, QString newFmt);