Ticket #9737: tv_rec.cpp

File tv_rec.cpp, 139.2 KB (added by luigi.zanderighi@…, 14 years ago)

Patched tv_rec.cpp

Line 
1// C headers
2#include <cstdio>
3#include <cstdlib>
4#include <cstring>
5#include <unistd.h>
6#include <sched.h> // for sched_yield
7
8// C++ headers
9#include <iostream>
10using namespace std;
11
12// MythTV headers
13
14#include "compat.h"
15#include "previewgeneratorqueue.h"
16#include "mythconfig.h"
17#include "tv_rec.h"
18#include "osd.h"
19#include "mythcorecontext.h"
20#include "dialogbox.h"
21#include "recordingprofile.h"
22#include "util.h"
23#include "programinfo.h"
24#include "dtvsignalmonitor.h"
25#include "mythdb.h"
26#include "jobqueue.h"
27#include "recordingrule.h"
28#include "eitscanner.h"
29#include "ringbuffer.h"
30#include "storagegroup.h"
31#include "remoteutil.h"
32#include "tvremoteutil.h"
33#include "mythsystemevent.h"
34
35#include "atscstreamdata.h"
36#include "dvbstreamdata.h"
37#include "atsctables.h"
38
39#include "livetvchain.h"
40
41#include "channelutil.h"
42#include "channelbase.h"
43#include "dummychannel.h"
44#include "dtvchannel.h"
45#include "dvbchannel.h"
46#include "hdhrchannel.h"
47#include "iptvchannel.h"
48#include "firewirechannel.h"
49
50#include "recorderbase.h"
51#include "NuppelVideoRecorder.h"
52#include "mpegrecorder.h"
53#include "dvbrecorder.h"
54#include "hdhrrecorder.h"
55#include "iptvrecorder.h"
56#include "firewirerecorder.h"
57#include "importrecorder.h"
58
59#include "channelgroup.h"
60
61#ifdef USING_V4L
62#include "v4lchannel.h"
63#endif
64
65#define DEBUG_CHANNEL_PREFIX 0 /**< set to 1 to channel prefixing */
66
67#define LOC QString("TVRec(%1): ").arg(cardid)
68#define LOC_ERR QString("TVRec(%1) Error: ").arg(cardid)
69
70/// How many milliseconds the signal monitor should wait between checks
71const uint TVRec::kSignalMonitoringRate = 50; /* msec */
72
73QMutex            TVRec::cardsLock;
74QMap<uint,TVRec*> TVRec::cards;
75
76static bool is_dishnet_eit(uint cardid);
77static QString load_profile(QString,void*,RecordingInfo*,RecordingProfile&);
78static int init_jobs(const RecordingInfo *rec, RecordingProfile &profile,
79                     bool on_host, bool transcode_bfr_comm, bool on_line_comm);
80
81/** \class TVRec
82 *  \brief This is the coordinating class of the \ref recorder_subsystem.
83 *
84 *  TVRec is used by EncoderLink, which in turn is used by RemoteEncoder
85 *  which allows the TV class on the frontend to communicate with TVRec
86 *  and is used by MainServer to implement portions of the
87 *  \ref myth_network_protocol on the backend.
88 *
89 *  TVRec contains an instance of RecorderBase, which actually handles the
90 *  recording of a program. It also contains an instance of RingBuffer, which
91 *  in this case is used to either stream an existing recording to the
92 *  frontend, or to save a stream from the RecorderBase to disk. Finally,
93 *  if there is a tuner on the hardware RecorderBase is implementing then
94 *  TVRec contains a channel instance for that hardware, and possibly a
95 *  SignalMonitor instance which monitors the signal quality on a tuners
96 *  current input.
97 */
98
99/** \fn TVRec::TVRec(int)
100 *  \brief Performs instance initialiation not requiring access to database.
101 *
102 *  \sa Init()
103 *  \param capturecardnum Capture card number
104 */
105TVRec::TVRec(int capturecardnum)
106       // Various components TVRec coordinates
107    : recorder(NULL), channel(NULL), signalMonitor(NULL),
108      scanner(NULL),
109      // Configuration variables from database
110      transcodeFirst(false),
111      earlyCommFlag(false),         runJobOnHostOnly(false),
112      eitCrawlIdleStart(60),        eitTransportTimeout(5*60),
113      audioSampleRateDB(0),
114      overRecordSecNrml(0),         overRecordSecCat(0),
115      overRecordCategory(""),
116      // Configuration variables from setup rutines
117      cardid(capturecardnum), ispip(false),
118      // State variables
119      stateChangeLock(QMutex::Recursive),
120      pendingRecLock(QMutex::Recursive),
121      internalState(kState_None), desiredNextState(kState_None),
122      changeState(false), pauseNotify(true),
123      stateFlags(0), lastTuningRequest(0),
124      triggerEventLoopLock(QMutex::NonRecursive),
125      triggerEventLoopSignal(false),
126      triggerEventSleepLock(QMutex::NonRecursive),
127      triggerEventSleepSignal(false),
128      m_switchingBuffer(false),
129      m_recStatus(rsUnknown),
130      // Current recording info
131      curRecording(NULL), autoRunJobs(JOB_NONE),
132      overrecordseconds(0),
133      // Pseudo LiveTV recording
134      pseudoLiveTVRecording(NULL),
135      nextLiveTVDir(""),            nextLiveTVDirLock(),
136      // tvchain
137      tvchain(NULL),
138      // RingBuffer info
139      ringBuffer(NULL), rbFileExt("mpg")
140{
141    QMutexLocker locker(&cardsLock);
142    cards[cardid] = this;
143}
144
145bool TVRec::CreateChannel(const QString &startchannel)
146{
147    rbFileExt = "mpg";
148    bool init_run = false;
149
150    if (genOpt.cardtype == "DVB")
151    {
152#ifdef USING_DVB
153        channel = new DVBChannel(genOpt.videodev, this);
154        if (!channel->Open())
155            return false;
156        GetDVBChannel()->SetSlowTuning(dvbOpt.dvb_tuning_delay);
157        InitChannel(genOpt.defaultinput, startchannel);
158        CloseChannel(); // Close the channel if in dvb_on_demand mode
159        init_run = true;
160#endif
161    }
162    else if (genOpt.cardtype == "FIREWIRE")
163    {
164#ifdef USING_FIREWIRE
165        channel = new FirewireChannel(this, genOpt.videodev, fwOpt);
166        if (!channel->Open())
167            return false;
168        InitChannel(genOpt.defaultinput, startchannel);
169        init_run = true;
170#endif
171    }
172    else if (genOpt.cardtype == "HDHOMERUN")
173    {
174#ifdef USING_HDHOMERUN
175        channel = new HDHRChannel(this, genOpt.videodev);
176        if (!channel->Open())
177            return false;
178        InitChannel(genOpt.defaultinput, startchannel);
179        GetDTVChannel()->EnterPowerSavingMode();
180        init_run = true;
181#endif
182    }
183    else if ((genOpt.cardtype == "IMPORT") ||
184             (genOpt.cardtype == "DEMO") ||
185             (genOpt.cardtype == "MPEG" &&
186              genOpt.videodev.toLower().left(5) == "file:"))
187    {
188        channel = new DummyChannel(this);
189        if (!channel->Open())
190            return false;
191        InitChannel(genOpt.defaultinput, startchannel);
192        init_run = true;
193    }
194    else if (genOpt.cardtype == "FREEBOX")
195    {
196#ifdef USING_IPTV
197        channel = new IPTVChannel(this, genOpt.videodev);
198        if (!channel->Open())
199            return false;
200        InitChannel(genOpt.defaultinput, startchannel);
201        init_run = true;
202#endif
203    }
204    else // "V4L" or "MPEG", ie, analog TV
205    {
206#ifdef USING_V4L
207        channel = new V4LChannel(this, genOpt.videodev);
208        if (!channel->Open())
209            return false;
210        InitChannel(genOpt.defaultinput, startchannel);
211        CloseChannel();
212        init_run = true;
213#endif
214        if ((genOpt.cardtype != "MPEG") && (genOpt.cardtype != "HDPVR"))
215            rbFileExt = "nuv";
216    }
217
218    if (!init_run)
219    {
220        QString msg = QString(
221            "%1 card configured on video device %2, \n"
222            "but MythTV was not compiled with %3 support. \n"
223            "\n"
224            "Recompile MythTV with %4 support or remove the card \n"
225            "from the configuration and restart MythTV.")
226            .arg(genOpt.cardtype).arg(genOpt.videodev)
227            .arg(genOpt.cardtype).arg(genOpt.cardtype);
228        VERBOSE(VB_IMPORTANT, LOC_ERR + "\n" + msg + "\n");
229        SetFlags(kFlagErrored);
230        return false;
231    }
232    return true;
233}
234
235/** \fn TVRec::Init(void)
236 *  \brief Performs instance initialization, returns true on success.
237 *
238 *  \return Returns true on success, false on failure.
239 */
240bool TVRec::Init(void)
241{
242    QMutexLocker lock(&stateChangeLock);
243
244    if (!GetDevices(cardid, genOpt, dvbOpt, fwOpt))
245        return false;
246
247    pendingRecLock.lock();
248    m_recStatus = rsUnknown;
249    pendingRecLock.unlock();
250
251    // configure the Channel instance
252    QString startchannel = GetStartChannel(cardid, genOpt.defaultinput);
253    if (!CreateChannel(startchannel))
254        return false;
255
256    transcodeFirst    =
257        gCoreContext->GetNumSetting("AutoTranscodeBeforeAutoCommflag", 0);
258    earlyCommFlag     = gCoreContext->GetNumSetting("AutoCommflagWhileRecording", 0);
259    runJobOnHostOnly  = gCoreContext->GetNumSetting("JobsRunOnRecordHost", 0);
260    eitTransportTimeout=gCoreContext->GetNumSetting("EITTransportTimeout", 5) * 60;
261    eitCrawlIdleStart = gCoreContext->GetNumSetting("EITCrawIdleStart", 60);
262    audioSampleRateDB = gCoreContext->GetNumSetting("AudioSampleRate");
263    overRecordSecNrml = gCoreContext->GetNumSetting("RecordOverTime");
264    overRecordSecCat  = gCoreContext->GetNumSetting("CategoryOverTime") * 60;
265    overRecordCategory= gCoreContext->GetSetting("OverTimeCategory");
266
267    EventThread.SetParent(this);
268    EventThread.start();
269
270    WaitForEventThreadSleep();
271
272    return true;
273}
274
275/** \fn TVRec::~TVRec()
276 *  \brief Stops the event and scanning threads and deletes any ChannelBase,
277 *         RingBuffer, and RecorderBase instances.
278 */
279TVRec::~TVRec()
280{
281    QMutexLocker locker(&cardsLock);
282    cards.remove(cardid);
283    TeardownAll();
284}
285
286void TVRec::TeardownAll(void)
287{
288    if (HasFlags(kFlagRunMainLoop))
289    {
290        ClearFlags(kFlagRunMainLoop);
291        EventThread.wait();
292    }
293
294    TeardownSignalMonitor();
295
296    if (scanner)
297    {
298        delete scanner;
299        scanner = NULL;
300    }
301
302    if (channel)
303    {
304        delete channel;
305        channel = NULL;
306    }
307
308    TeardownRecorder(true);
309
310    SetRingBuffer(NULL);
311}
312
313void TVRec::WakeEventLoop(void)
314{
315    QMutexLocker locker(&triggerEventLoopLock);
316    triggerEventLoopSignal = true;
317    triggerEventLoopWait.wakeAll();
318}
319
320/** \fn TVRec::GetState() const
321 *  \brief Returns the TVState of the recorder.
322 *
323 *   If there is a pending state change kState_ChangingState is returned.
324 *  \sa EncoderLink::GetState(), \ref recorder_subsystem
325 */
326TVState TVRec::GetState(void) const
327{
328    if (changeState)
329        return kState_ChangingState;
330    return internalState;
331}
332
333/** \fn TVRec::GetRecording(void)
334 *  \brief Allocates and returns a ProgramInfo for the current recording.
335 *
336 *  Note: The user of this function must free the %ProgramInfo this returns.
337 *  \return %ProgramInfo for the current recording, if it exists, blank
338 *          %ProgramInfo otherwise.
339 */
340ProgramInfo *TVRec::GetRecording(void)
341{
342    QMutexLocker lock(&stateChangeLock);
343
344    ProgramInfo *tmppginfo = NULL;
345
346    if (curRecording && !changeState)
347    {
348        tmppginfo = new ProgramInfo(*curRecording);
349        tmppginfo->SetRecordingStatus(rsRecording);
350    }
351    else
352        tmppginfo = new ProgramInfo();
353    tmppginfo->SetCardID(cardid);
354
355    return tmppginfo;
356}
357
358/** \fn TVRec::RecordPending(const ProgramInfo*, int, bool)
359 *  \brief Tells TVRec "rcinfo" is the next pending recording.
360 *
361 *   When there is a pending recording and the frontend is in "Live TV"
362 *   mode the TVRec event loop will send a "ASK_RECORDING" message to
363 *   it. Depending on what that query returns, the recording will be
364 *   started or not started.
365 *
366 *  \sa TV::AskAllowRecording(const QStringList&, int, bool)
367 *  \param rcinfo   ProgramInfo on pending program.
368 *  \param secsleft Seconds left until pending recording begins.
369 *                  Set to -1 to revoke the current pending recording.
370 *  \param hasLater If true, a later non-conflicting showing is available.
371 */
372void TVRec::RecordPending(const ProgramInfo *rcinfo, int secsleft,
373                          bool hasLater)
374{
375    QMutexLocker statelock(&stateChangeLock);
376    QMutexLocker pendlock(&pendingRecLock);
377
378    if (secsleft < 0)
379    {
380        VERBOSE(VB_RECORD, LOC + "Pending recording revoked on " +
381                QString("inputid %1").arg(rcinfo->GetInputID()));
382
383        PendingMap::iterator it = pendingRecordings.find(rcinfo->GetCardID());
384        if (it != pendingRecordings.end())
385        {
386            (*it).ask = false;
387            (*it).doNotAsk = (*it).canceled = true;
388        }
389        return;
390    }
391
392    VERBOSE(VB_RECORD, LOC +
393            QString("RecordPending on inputid %1").arg(rcinfo->GetInputID()));
394
395    PendingInfo pending;
396    pending.info            = new ProgramInfo(*rcinfo);
397    pending.recordingStart  = QDateTime::currentDateTime().addSecs(secsleft);
398    pending.hasLaterShowing = hasLater;
399    pending.ask             = true;
400    pending.doNotAsk        = false;
401
402    pendingRecordings[rcinfo->GetCardID()] = pending;
403
404    // If this isn't a recording for this instance to make, we are done
405    if (rcinfo->GetCardID() != cardid)
406        return;
407
408    // We also need to check our input groups
409    vector<uint> cardids = CardUtil::GetConflictingCards(
410        rcinfo->GetInputID(), cardid);
411
412    pendingRecordings[rcinfo->GetCardID()].possibleConflicts = cardids;
413
414    pendlock.unlock();
415    statelock.unlock();
416    for (uint i = 0; i < cardids.size(); i++)
417        RemoteRecordPending(cardids[i], rcinfo, secsleft, hasLater);
418    statelock.relock();
419    pendlock.relock();
420}
421
422/** \fn TVRec::SetPseudoLiveTVRecording(ProgramInfo*)
423 *  \brief Sets the pseudo LiveTV ProgramInfo
424 */
425void TVRec::SetPseudoLiveTVRecording(ProgramInfo *pi)
426{
427    ProgramInfo *old_rec = pseudoLiveTVRecording;
428    pseudoLiveTVRecording = pi;
429    if (old_rec)
430        delete old_rec;
431}
432
433/** \fn TVRec::GetRecordEndTime(const ProgramInfo*) const
434 *  \brief Returns recording end time with proper post-roll
435 */
436QDateTime TVRec::GetRecordEndTime(const ProgramInfo *pi) const
437{
438    bool spcat = (!overRecordCategory.isEmpty() &&
439                  pi->GetCategory() == overRecordCategory);
440    int secs = (spcat) ? overRecordSecCat : overRecordSecNrml;
441    return pi->GetRecordingEndTime().addSecs(secs);
442}
443
444/** \fn TVRec::CancelNextRecording(bool)
445 *  \brief Tells TVRec to cancel the upcoming recording.
446 *  \sa RecordPending(const ProgramInfo*, int, bool),
447 *      TV::AskAllowRecording(const QStringList&, int, bool)
448 */
449void TVRec::CancelNextRecording(bool cancel)
450{
451    QMutexLocker pendlock(&pendingRecLock);
452    VERBOSE(VB_RECORD, LOC + "CancelNextRecording("<<cancel<<") -- begin");
453
454    PendingMap::iterator it = pendingRecordings.find(cardid);
455    if (it == pendingRecordings.end())
456    {
457        VERBOSE(VB_RECORD, LOC + "CancelNextRecording("<<cancel<<") -- "
458                "error, unknown recording");
459        return;
460    }
461
462    if (cancel)
463    {
464        vector<uint> &cardids = (*it).possibleConflicts;
465        for (uint i = 0; i < cardids.size(); i++)
466        {
467            VERBOSE(VB_RECORD, LOC +
468                    "CancelNextRecording -- cardid "<<cardids[i]);
469
470            pendlock.unlock();
471            RemoteRecordPending(cardids[i], (*it).info, -1, false);
472            pendlock.relock();
473        }
474
475        VERBOSE(VB_RECORD, LOC + "CancelNextRecording -- cardid "<<cardid);
476
477        RecordPending((*it).info, -1, false);
478    }
479    else
480    {
481        (*it).canceled = false;
482    }
483
484    VERBOSE(VB_RECORD, LOC + "CancelNextRecording("<<cancel<<") -- end");
485}
486
487/** \fn TVRec::StartRecording(const ProgramInfo*)
488 *  \brief Tells TVRec to Start recording the program "rcinfo"
489 *         as soon as possible.
490 *
491 *  \return +1 if the recording started successfully,
492 *          -1 if TVRec is busy doing something else, 0 otherwise.
493 *  \sa EncoderLink::StartRecording(const ProgramInfo*)
494 *      RecordPending(const ProgramInfo*, int, bool), StopRecording()
495 */
496RecStatusType TVRec::StartRecording(const ProgramInfo *rcinfo)
497{
498    VERBOSE(VB_RECORD, LOC + QString("StartRecording(%1)")
499            .arg(rcinfo->toString(ProgramInfo::kTitleSubtitle)));
500
501    QMutexLocker lock(&stateChangeLock);
502    QString msg("");
503
504    pendingRecLock.lock();
505    m_recStatus = rsAborted;
506    pendingRecLock.unlock();
507
508    // Flush out any pending state changes
509    WaitForEventThreadSleep();
510
511    // We need to do this check early so we don't cancel an overrecord
512    // that we're trying to extend.
513    if (internalState != kState_WatchingLiveTV &&
514        curRecording && curRecording->IsSameProgramWeakCheck(*rcinfo))
515    {
516        int post_roll_seconds  = curRecording->GetRecordingEndTime()
517            .secsTo(recordEndTime);
518
519        curRecording->SetRecordingRuleType(rcinfo->GetRecordingRuleType());
520        curRecording->SetRecordingRuleID(rcinfo->GetRecordingRuleID());
521        curRecording->SetRecordingEndTime(rcinfo->GetRecordingEndTime());
522        curRecording->UpdateRecordingEnd();
523
524        recordEndTime = curRecording->GetRecordingEndTime()
525            .addSecs(post_roll_seconds);
526
527        msg = QString("updating recording: %1 %2 %3 %4")
528            .arg(curRecording->GetTitle()).arg(curRecording->GetChanID())
529            .arg(curRecording->GetRecordingStartTime(ISODate))
530            .arg(curRecording->GetRecordingEndTime(ISODate));
531        VERBOSE(VB_RECORD, LOC + msg);
532
533        ClearFlags(kFlagCancelNextRecording);
534
535        pendingRecLock.lock();
536        m_recStatus = rsRecording;
537        pendingRecLock.unlock();
538        return rsRecording;
539    }
540
541    bool cancelNext = false;
542    PendingInfo pendinfo;
543    PendingMap::iterator it;
544    bool has_pending;
545
546    pendingRecLock.lock();
547    if ((it = pendingRecordings.find(cardid)) != pendingRecordings.end())
548    {
549        (*it).ask = (*it).doNotAsk = false;
550        cancelNext = (*it).canceled;
551    }
552    pendingRecLock.unlock();
553
554    // Flush out events...
555    WaitForEventThreadSleep();
556
557    // Rescan pending recordings since the event loop may have deleted
558    // a stale entry.  If this happens the info pointer will not be valid
559    // since the HandlePendingRecordings loop will have deleted it.
560    pendingRecLock.lock();
561    it = pendingRecordings.find(cardid);
562    has_pending = (it != pendingRecordings.end());
563    if (has_pending)
564        pendinfo = *it;
565    pendingRecLock.unlock();
566
567    // If the needed input is in a shared input group, and we are
568    // not canceling the recording anyway, check other recorders
569    if (!cancelNext && has_pending && pendinfo.possibleConflicts.size())
570    {
571        VERBOSE(VB_RECORD, LOC + "Checking input group recorders - begin");
572        vector<uint> &cardids = pendinfo.possibleConflicts;
573
574        uint mplexid = 0, sourceid = 0;
575        vector<uint> cardids2;
576        vector<TVState> states;
577
578        // Stop remote recordings if needed
579        for (uint i = 0; i < cardids.size(); i++)
580        {
581            TunedInputInfo busy_input;
582            bool is_busy = RemoteIsBusy(cardids[i], busy_input);
583
584            // if the other recorder is busy, but the input is
585            // not in a shared input group, then as far as we're
586            // concerned here it isn't busy.
587            if (is_busy)
588            {
589                is_busy = (bool) igrp.GetSharedInputGroup(
590                    busy_input.inputid, rcinfo->GetInputID());
591            }
592
593            if (is_busy && !sourceid)
594            {
595                mplexid  = pendinfo.info->QueryMplexID();
596                sourceid = pendinfo.info->GetSourceID();
597            }
598
599            if (is_busy &&
600                ((sourceid != busy_input.sourceid) ||
601                 (mplexid  != busy_input.mplexid)))
602            {
603                states.push_back((TVState) RemoteGetState(cardids[i]));
604                cardids2.push_back(cardids[i]);
605            }
606        }
607
608        bool ok = true;
609        for (uint i = 0; (i < cardids2.size()) && ok; i++)
610        {
611            VERBOSE(VB_RECORD, LOC +
612                    QString("Attempting to stop card %1 in state %2")
613                    .arg(cardids2[i]).arg(StateToString(states[i])));
614
615            bool success = RemoteStopRecording(cardids2[i]);
616            if (success)
617            {
618                uint state = RemoteGetState(cardids2[i]);
619                VERBOSE(VB_IMPORTANT, LOC + QString("a %1: %2")
620                        .arg(cardids2[i]).arg(StateToString((TVState)state)));
621                success = (kState_None == state);
622            }
623
624            // If we managed to stop LiveTV recording, restart playback..
625            if (success && states[i] == kState_WatchingLiveTV)
626            {
627                QString message = QString("QUIT_LIVETV %1").arg(cardids2[i]);
628                MythEvent me(message);
629                gCoreContext->dispatch(me);
630            }
631
632            VERBOSE(VB_RECORD, LOC + QString(
633                        "Stopping recording on %1, %2")
634                    .arg(cardids2[i])
635                    .arg(success ? "succeeded" : "failed"));
636
637            ok &= success;
638        }
639
640        // If we failed to stop the remote recordings, don't record
641        if (!ok)
642        {
643            CancelNextRecording(true);
644            cancelNext = true;
645        }
646
647        cardids.clear();
648
649        VERBOSE(VB_RECORD, LOC + "Checking input group recorders - done");
650    }
651
652    // If in post-roll, end recording
653    if (!cancelNext && (GetState() == kState_RecordingOnly))
654    {
655        stateChangeLock.unlock();
656        StopRecording();
657        stateChangeLock.lock();
658    }
659
660    if (!cancelNext && (GetState() == kState_None))
661    {
662        if (tvchain)
663        {
664            QString message = QString("LIVETV_EXITED");
665            MythEvent me(message, tvchain->GetID());
666            gCoreContext->dispatch(me);
667            tvchain = NULL;
668        }
669
670        recordEndTime = GetRecordEndTime(rcinfo);
671
672        // Tell event loop to begin recording.
673        curRecording = new RecordingInfo(*rcinfo);
674        curRecording->MarkAsInUse(true, kRecorderInUseID);
675        StartedRecording(curRecording);
676
677        // Make sure scheduler is allowed to end this recording
678        ClearFlags(kFlagCancelNextRecording);
679
680        pendingRecLock.lock();
681        m_recStatus = rsTuning;
682        pendingRecLock.unlock();
683        ChangeState(kState_RecordingOnly);
684    }
685    else if (!cancelNext && (GetState() == kState_WatchingLiveTV))
686    {
687        SetPseudoLiveTVRecording(new ProgramInfo(*rcinfo));
688        recordEndTime = GetRecordEndTime(rcinfo);
689        pendingRecLock.lock();
690        m_recStatus = rsRecording;
691        pendingRecLock.unlock();
692
693        // We want the frontend to change channel for recording
694        // and disable the UI for channel change, PiP, etc.
695
696        QString message = QString("LIVETV_WATCH %1 1").arg(cardid);
697        QStringList prog;
698        rcinfo->ToStringList(prog);
699        MythEvent me(message, prog);
700        gCoreContext->dispatch(me);
701    }
702    else
703    {
704        msg = QString("Wanted to record: %1 %2 %3 %4\n\t\t\t")
705            .arg(rcinfo->GetTitle()).arg(rcinfo->GetChanID())
706            .arg(rcinfo->GetRecordingStartTime(ISODate))
707            .arg(rcinfo->GetRecordingEndTime(ISODate));
708
709        if (cancelNext)
710        {
711            msg += "But a user has canceled this recording";
712            pendingRecLock.lock();
713            m_recStatus = rsCancelled;
714            pendingRecLock.unlock();
715        }
716        else
717        {
718            msg += QString("But the current state is: %1")
719                .arg(StateToString(internalState));
720            pendingRecLock.lock();
721            m_recStatus = rsTunerBusy;
722            pendingRecLock.unlock();
723        }
724
725        if (curRecording && internalState == kState_RecordingOnly)
726            msg += QString("\n\t\t\tCurrently recording: %1 %2 %3 %4")
727                .arg(curRecording->GetTitle()).arg(curRecording->GetChanID())
728                .arg(curRecording->GetRecordingStartTime(ISODate))
729                .arg(curRecording->GetRecordingEndTime(ISODate));
730
731        VERBOSE(VB_IMPORTANT, LOC + msg);
732    }
733
734    for (int i = 0; i < pendingRecordings.size(); i++)
735        delete pendingRecordings[i].info;
736    pendingRecordings.clear();
737
738    WaitForEventThreadSleep();
739
740    RecStatusType  status;
741
742    pendingRecLock.lock();
743    if ((curRecording) && (curRecording->GetRecordingStatus() == rsFailed) &&
744        (m_recStatus == rsRecording || m_recStatus == rsTuning))
745        m_recStatus = rsFailed;
746    status = m_recStatus;
747    pendingRecLock.unlock();
748
749    return status;
750}
751
752RecStatusType TVRec::GetRecordingStatus(void) const
753{
754    QMutexLocker pendlock(&pendingRecLock);
755    return m_recStatus;
756}
757
758
759/** \fn TVRec::StopRecording(bool killFile)
760 *  \brief Changes from a recording state to kState_None.
761 *  \sa StartRecording(const ProgramInfo *rec), FinishRecording()
762 */
763void TVRec::StopRecording(bool killFile)
764{
765    if (StateIsRecording(GetState()))
766    {
767        QMutexLocker lock(&stateChangeLock);
768        if (killFile)
769            SetFlags(kFlagKillRec);
770        ChangeState(RemoveRecording(GetState()));
771        // wait for state change to take effect
772        WaitForEventThreadSleep();
773        ClearFlags(kFlagCancelNextRecording|kFlagKillRec);
774
775        pendingRecLock.lock();
776        m_recStatus = rsUnknown;
777        pendingRecLock.unlock();
778    }
779}
780
781/** \fn TVRec::StateIsRecording(TVState)
782 *  \brief Returns true if "state" is kState_RecordingOnly,
783 *         or kState_WatchingLiveTV.
784 *  \param state TVState to check.
785 */
786bool TVRec::StateIsRecording(TVState state)
787{
788    return (state == kState_RecordingOnly ||
789            state == kState_WatchingLiveTV);
790}
791
792/** \fn TVRec::StateIsPlaying(TVState)
793 *  \brief Returns true if we are in any state associated with a player.
794 *  \param state TVState to check.
795 */
796bool TVRec::StateIsPlaying(TVState state)
797{
798    return (state == kState_WatchingPreRecorded);
799}
800
801/** \fn TVRec::RemoveRecording(TVState)
802 *  \brief If "state" is kState_RecordingOnly or kState_WatchingLiveTV,
803 *         returns a kState_None, otherwise returns kState_Error.
804 *  \param state TVState to check.
805 */
806TVState TVRec::RemoveRecording(TVState state)
807{
808    if (StateIsRecording(state))
809        return kState_None;
810
811    VERBOSE(VB_IMPORTANT, LOC_ERR +
812            QString("Unknown state in RemoveRecording: %1")
813            .arg(StateToString(state)));
814    return kState_Error;
815}
816
817/** \fn TVRec::RemovePlaying(TVState)
818 *  \brief Returns TVState that would remove the playing, but potentially
819 *         keep recording if we are watching an in progress recording.
820 *  \param state TVState to check.
821 */
822TVState TVRec::RemovePlaying(TVState state)
823{
824    if (StateIsPlaying(state))
825    {
826        if (state == kState_WatchingPreRecorded)
827            return kState_None;
828        return kState_RecordingOnly;
829    }
830
831    QString msg = "Unknown state in RemovePlaying: %1";
832    VERBOSE(VB_IMPORTANT, LOC_ERR + msg.arg(StateToString(state)));
833
834    return kState_Error;
835}
836
837/** \fn TVRec::StartedRecording(RecordingInfo *curRec)
838 *  \brief Inserts a "curRec" into the database
839 *  \param curRec Recording to add to database.
840 *  \sa ProgramInfo::StartedRecording(const QString&)
841 */
842void TVRec::StartedRecording(RecordingInfo *curRec)
843{
844    if (!curRec)
845        return;
846
847    curRec->StartedRecording(rbFileExt);
848    VERBOSE(VB_RECORD, LOC + "StartedRecording("<<curRec<<") fn("
849            <<curRec->GetPathname()<<")");
850
851    if (curRec->IsCommercialFree())
852        curRec->SaveCommFlagged(COMM_FLAG_COMMFREE);
853
854    SendMythSystemRecEvent("REC_STARTED", curRec);
855}
856
857/** \fn TVRec::FinishedRecording(RecordingInfo *curRec)
858 *  \brief If not a premature stop, adds program to history of recorded
859 *         programs. If the recording type is kFindOneRecord this find
860 *         is removed.
861 *  \sa ProgramInfo::FinishedRecording(bool prematurestop)
862 *  \param curRec ProgramInfo or recording to mark as done
863 */
864void TVRec::FinishedRecording(RecordingInfo *curRec)
865{
866    if (!curRec)
867        return;
868
869    const QString recgrp = curRec->QueryRecordingGroup();
870    curRec->SetRecordingGroup(recgrp);
871
872    VERBOSE(VB_RECORD, LOC + QString("FinishedRecording(%1) in recgroup: %2")
873            .arg(curRec->GetTitle()).arg(recgrp));
874
875    if (curRec->GetRecordingStatus() == rsRecording)
876        curRec->SetRecordingStatus(rsRecorded);
877    else if (curRec->GetRecordingStatus() != rsRecorded)
878        curRec->SetRecordingStatus(rsFailed);
879    curRec->SetRecordingEndTime(mythCurrentDateTime());
880
881    if (tvchain)
882        tvchain->FinishedRecording(curRec);
883
884    // Make sure really short recordings have positive run time.
885    if (curRec->GetRecordingEndTime() <= curRec->GetRecordingStartTime())
886    {
887        curRec->SetRecordingEndTime(
888            curRec->GetRecordingStartTime().addSecs(60));
889    }
890
891    // Round up recording end time (probably should be done in the UI only)
892    QDateTime recendts = curRec->GetRecordingEndTime();
893    recendts.setTime(QTime(recendts.addSecs(30).time().hour(),
894                           recendts.addSecs(30).time().minute()));
895    curRec->SetRecordingEndTime(recendts);
896
897    if (recgrp != "LiveTV")
898    {
899        MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
900                     .arg(curRec->GetCardID())
901                     .arg(curRec->GetChanID())
902                     .arg(curRec->GetScheduledStartTime(ISODate))
903                     .arg(curRec->GetRecordingStatus())
904                     .arg(curRec->GetRecordingEndTime(ISODate)));
905        gCoreContext->dispatch(me);
906    }
907
908    curRec->FinishedRecording(curRec->GetRecordingStatus() != rsRecorded);
909}
910
911#define TRANSITION(ASTATE,BSTATE) \
912   ((internalState == ASTATE) && (desiredNextState == BSTATE))
913#define SET_NEXT() do { nextState = desiredNextState; changed = true; } while(0)
914#define SET_LAST() do { nextState = internalState; changed = true; } while(0)
915
916/** \fn TVRec::HandleStateChange(void)
917 *  \brief Changes the internalState to the desiredNextState if possible.
918 *
919 *   Note: There must exist a state transition from any state we can enter
920 *   to the kState_None state, as this is used to shutdown TV in RunTV.
921 *
922 */
923void TVRec::HandleStateChange(void)
924{
925    TVState nextState = internalState;
926
927    bool changed = false;
928
929    QString transMsg = QString(" %1 to %2")
930        .arg(StateToString(nextState))
931        .arg(StateToString(desiredNextState));
932
933    if (desiredNextState == internalState)
934    {
935        VERBOSE(VB_IMPORTANT, LOC_ERR + "HandleStateChange(): "
936                "Null transition" + transMsg);
937        changeState = false;
938        return;
939    }
940
941    // Make sure EIT scan is stopped before any tuning,
942    // to avoid race condition with it's tuning requests.
943    if (HasFlags(kFlagEITScannerRunning))
944    {
945        scanner->StopActiveScan();
946        ClearFlags(kFlagEITScannerRunning);
947    }
948
949    // Handle different state transitions
950    if (TRANSITION(kState_None, kState_WatchingLiveTV))
951    {
952        tuningRequests.enqueue(TuningRequest(kFlagLiveTV));
953        SET_NEXT();
954    }
955    else if (TRANSITION(kState_WatchingLiveTV, kState_None))
956    {
957        tuningRequests.enqueue(TuningRequest(kFlagKillRec|kFlagKillRingBuffer));
958        SET_NEXT();
959    }
960    else if (TRANSITION(kState_WatchingLiveTV, kState_RecordingOnly))
961    {
962        SetPseudoLiveTVRecording(NULL);
963
964        SET_NEXT();
965    }
966    else if (TRANSITION(kState_None, kState_RecordingOnly))
967    {
968        SetPseudoLiveTVRecording(NULL);
969        tuningRequests.enqueue(TuningRequest(kFlagRecording, curRecording));
970        SET_NEXT();
971    }
972    else if (TRANSITION(kState_RecordingOnly, kState_None))
973    {
974        tuningRequests.enqueue(
975            TuningRequest(kFlagCloseRec|kFlagKillRingBuffer|
976                          (GetFlags()&kFlagKillRec)));
977        SET_NEXT();
978    }
979
980    QString msg = (changed) ? "Changing from" : "Unknown state transition:";
981    VERBOSE(VB_IMPORTANT, LOC + msg + transMsg);
982
983    // update internal state variable
984    internalState = nextState;
985    changeState = false;
986
987    eitScanStartTime = QDateTime::currentDateTime();
988    if ((internalState == kState_None) &&
989        scanner)
990        eitScanStartTime = eitScanStartTime.addSecs(eitCrawlIdleStart);
991    else
992        eitScanStartTime = eitScanStartTime.addYears(1);
993}
994#undef TRANSITION
995#undef SET_NEXT
996#undef SET_LAST
997
998/** \fn TVRec::ChangeState(TVState)
999 *  \brief Puts a state change on the nextState queue.
1000 */
1001void TVRec::ChangeState(TVState nextState)
1002{
1003    QMutexLocker lock(&stateChangeLock);
1004    desiredNextState = nextState;
1005    changeState = true;
1006    WakeEventLoop();
1007}
1008
1009/** \fn TVRec::SetupRecorder(RecordingProfile&)
1010 *  \brief Allocates and initializes the RecorderBase instance.
1011 *
1012 *  Based on the card type, one of the possible recorders are started.
1013 *  If the card type is "MPEG" or "HDPVR" a MpegRecorder is started,
1014 *  if the card type is "HDHOMERUN" a HDHRRecorder is started,
1015 *  if the card type is "FIREWIRE" a FirewireRecorder is started,
1016 *  if the card type is "DVB" a DVBRecorder is started,
1017 *  otherwise a NuppelVideoRecorder is started.
1018 *
1019 *  If there is any this will return false.
1020 * \sa IsErrored()
1021 */
1022bool TVRec::SetupRecorder(RecordingProfile &profile)
1023{
1024    recorder = NULL;
1025    if (genOpt.cardtype == "MPEG")
1026    {
1027#ifdef USING_IVTV
1028        recorder = new MpegRecorder(this);
1029#endif // USING_IVTV
1030    }
1031    else if (genOpt.cardtype == "HDPVR")
1032    {
1033#ifdef USING_HDPVR
1034        recorder = new MpegRecorder(this);
1035#endif // USING_HDPVR
1036    }
1037    else if (genOpt.cardtype == "FIREWIRE")
1038    {
1039#ifdef USING_FIREWIRE
1040        recorder = new FirewireRecorder(this, GetFirewireChannel());
1041#endif // USING_FIREWIRE
1042    }
1043    else if (genOpt.cardtype == "HDHOMERUN")
1044    {
1045#ifdef USING_HDHOMERUN
1046        recorder = new HDHRRecorder(this, GetHDHRChannel());
1047        ringBuffer->SetWriteBufferSize(4*1024*1024);
1048        recorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart);
1049#endif // USING_HDHOMERUN
1050    }
1051    else if (genOpt.cardtype == "DVB")
1052    {
1053#ifdef USING_DVB
1054        recorder = new DVBRecorder(this, GetDVBChannel());
1055        ringBuffer->SetWriteBufferSize(4*1024*1024);
1056        recorder->SetOption("wait_for_seqstart", genOpt.wait_for_seqstart);
1057        recorder->SetOption("dvb_on_demand",     dvbOpt.dvb_on_demand);
1058#endif // USING_DVB
1059    }
1060    else if (genOpt.cardtype == "FREEBOX")
1061    {
1062#ifdef USING_IPTV
1063        IPTVChannel *chan = dynamic_cast<IPTVChannel*>(channel);
1064        recorder = new IPTVRecorder(this, chan);
1065        ringBuffer->SetWriteBufferSize(4*1024*1024);
1066        recorder->SetOption("mrl", genOpt.videodev);
1067#endif // USING_IPTV
1068    }
1069    else if (genOpt.cardtype == "IMPORT")
1070    {
1071        recorder = new ImportRecorder(this);
1072    }
1073    else if (genOpt.cardtype == "DEMO")
1074    {
1075#ifdef USING_IVTV
1076        recorder = new MpegRecorder(this);
1077#else
1078        recorder = new ImportRecorder(this);
1079#endif
1080    }
1081    else
1082    {
1083#ifdef USING_V4L
1084        // V4L/MJPEG/GO7007 from here on
1085        recorder = new NuppelVideoRecorder(this, channel);
1086        recorder->SetOption("skipbtaudio", genOpt.skip_btaudio);
1087#endif // USING_V4L
1088    }
1089
1090    if (recorder)
1091    {
1092        recorder->SetOptionsFromProfile(
1093            &profile, genOpt.videodev, genOpt.audiodev, genOpt.vbidev);
1094        // Override the samplerate defined in the profile if this card
1095        // was configured with a fixed rate.
1096        if (genOpt.audiosamplerate)
1097            recorder->SetOption("samplerate", genOpt.audiosamplerate);
1098        recorder->SetRingBuffer(ringBuffer);
1099        recorder->Initialize();
1100
1101        if (recorder->IsErrored())
1102        {
1103            VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to initialize recorder!");
1104            delete recorder;
1105            recorder = NULL;
1106            return false;
1107        }
1108
1109        return true;
1110    }
1111
1112    QString msg = "Need %1 recorder, but compiled without %2 support!";
1113    msg = msg.arg(genOpt.cardtype).arg(genOpt.cardtype);
1114    VERBOSE(VB_IMPORTANT, LOC_ERR + msg);
1115
1116    return false;
1117}
1118
1119/** \fn TVRec::TeardownRecorder(bool)
1120 *  \brief Tears down the recorder.
1121 *
1122 *   If a "recorder" exists, RecorderBase::StopRecording() is called.
1123 *   We then wait for "recorder_thread" to exit, and finally we delete
1124 *   "recorder".
1125 *
1126 *   If a RingBuffer instance exists, RingBuffer::StopReads() is called,
1127 *   and then we delete the RingBuffer instance.
1128 *
1129 *   If killfile is true, the recording is deleted.
1130 *
1131 *   Finally, if there was a recording and it was not deleted,
1132 *   schedule any post-processing jobs.
1133 *
1134 *  \param killFile if true the recorded file is deleted.
1135 */
1136void TVRec::TeardownRecorder(bool killFile)
1137{
1138    pauseNotify = false;
1139    ispip = false;
1140
1141    if (recorder && HasFlags(kFlagRecorderRunning))
1142    {
1143        // Get the width and set the videoprops
1144        uint avg_height = curRecording->QueryAverageHeight();
1145        curRecording->SaveResolutionProperty(
1146            (avg_height > 1000) ? VID_1080 :
1147            ((avg_height > 700) ? VID_720 : VID_UNKNOWN));
1148
1149        int secsSince = curRecording->GetRecordingStartTime()
1150            .secsTo(QDateTime::currentDateTime());
1151        QString message = QString("DONE_RECORDING %1 %2 %3")
1152            .arg(cardid).arg(secsSince).arg(GetFramesWritten());
1153        MythEvent me(message);
1154        gCoreContext->dispatch(me);
1155
1156        recorder->StopRecording();
1157        RecorderThread.wait();
1158    }
1159    ClearFlags(kFlagRecorderRunning);
1160
1161    if (recorder)
1162    {
1163        if (GetV4LChannel())
1164            channel->SetFd(-1);
1165
1166        delete recorder;
1167        recorder = NULL;
1168    }
1169
1170    if (ringBuffer)
1171        ringBuffer->StopReads();
1172
1173    if (curRecording)
1174    {
1175        if (!killFile)
1176        {
1177            if (curRecording->IsLocal())
1178                PreviewGeneratorQueue::GetPreviewImage(*curRecording, "");
1179
1180            if (!tvchain)
1181            {
1182                int secsSince = curRecording->GetRecordingStartTime()
1183                    .secsTo(QDateTime::currentDateTime());
1184                if (secsSince < 120)
1185                {
1186                    JobQueue::RemoveJobsFromMask(JOB_COMMFLAG, autoRunJobs);
1187                    JobQueue::RemoveJobsFromMask(JOB_TRANSCODE, autoRunJobs);
1188                }
1189
1190                if (autoRunJobs)
1191                    JobQueue::QueueRecordingJobs(*curRecording, autoRunJobs);
1192            }
1193        }
1194
1195        FinishedRecording(curRecording);
1196
1197        SendMythSystemRecEvent("REC_FINISHED", curRecording);
1198
1199        curRecording->MarkAsInUse(false, kRecorderInUseID);
1200        delete curRecording;
1201        curRecording = NULL;
1202    }
1203
1204    pauseNotify = true;
1205
1206    if (GetDTVChannel())
1207        GetDTVChannel()->EnterPowerSavingMode();
1208}
1209
1210DVBRecorder *TVRec::GetDVBRecorder(void)
1211{
1212#ifdef USING_DVB
1213    return dynamic_cast<DVBRecorder*>(recorder);
1214#else // if !USING_DVB
1215    return NULL;
1216#endif // !USING_DVB
1217}
1218
1219HDHRRecorder *TVRec::GetHDHRRecorder(void)
1220{
1221#ifdef USING_HDHOMERUN
1222    return dynamic_cast<HDHRRecorder*>(recorder);
1223#else // if !USING_HDHOMERUN
1224    return NULL;
1225#endif // !USING_HDHOMERUN
1226}
1227
1228DTVRecorder *TVRec::GetDTVRecorder(void)
1229{
1230    return dynamic_cast<DTVRecorder*>(recorder);
1231}
1232
1233/** \fn TVRec::InitChannel(const QString&, const QString&)
1234 *  \brief Performs ChannelBase instance init from database and
1235 *         tuner hardware (requires that channel be open).
1236 */
1237void TVRec::InitChannel(const QString &inputname, const QString &startchannel)
1238{
1239    if (!channel)
1240        return;
1241
1242    QString input   = inputname;
1243    QString channum = startchannel;
1244
1245    channel->Init(input, channum, true);
1246}
1247
1248void TVRec::CloseChannel(void)
1249{
1250    if (!channel)
1251        return;
1252
1253    if (GetDVBChannel() && !dvbOpt.dvb_on_demand)
1254        return;
1255
1256    channel->Close();
1257}
1258
1259DTVChannel *TVRec::GetDTVChannel(void)
1260{
1261    return dynamic_cast<DTVChannel*>(channel);
1262}
1263
1264HDHRChannel *TVRec::GetHDHRChannel(void)
1265{
1266#ifdef USING_HDHOMERUN
1267    return dynamic_cast<HDHRChannel*>(channel);
1268#else
1269    return NULL;
1270#endif // USING_HDHOMERUN
1271}
1272
1273DVBChannel *TVRec::GetDVBChannel(void)
1274{
1275#ifdef USING_DVB
1276    return dynamic_cast<DVBChannel*>(channel);
1277#else
1278    return NULL;
1279#endif // USING_DVB
1280}
1281
1282FirewireChannel *TVRec::GetFirewireChannel(void)
1283{
1284#ifdef USING_FIREWIRE
1285    return dynamic_cast<FirewireChannel*>(channel);
1286#else
1287    return NULL;
1288#endif // USING_FIREWIRE
1289}
1290
1291V4LChannel *TVRec::GetV4LChannel(void)
1292{
1293#ifdef USING_V4L
1294    return dynamic_cast<V4LChannel*>(channel);
1295#else
1296    return NULL;
1297#endif // USING_V4L
1298}
1299
1300/** \fn TVReEventThread::run(void)
1301 *  \brief Thunk that allows event thread to call RunTV().
1302 */
1303void TVRecEventThread::run(void)
1304{
1305    if (!m_parent)
1306        return;
1307
1308    m_parent->RunTV();
1309}
1310
1311/** \fn TVReRecordThread::run(void)
1312 *  \brief Thunk that allows recorder thread to
1313 *         call RecorderBase::StartRecording().
1314 */
1315void TVRecRecordThread::run(void)
1316{
1317    if (!m_parent || !m_parent->recorder)
1318        return;
1319
1320    m_parent->recorder->StartRecording();
1321}
1322
1323static bool get_use_eit(uint cardid)
1324{
1325    MSqlQuery query(MSqlQuery::InitCon());
1326    query.prepare(
1327        "SELECT SUM(useeit) "
1328        "FROM videosource, cardinput "
1329        "WHERE videosource.sourceid = cardinput.sourceid AND"
1330        "      cardinput.cardid     = :CARDID");
1331    query.bindValue(":CARDID", cardid);
1332
1333    if (!query.exec() || !query.isActive())
1334    {
1335        MythDB::DBError("get_use_eit", query);
1336        return false;
1337    }
1338    else if (query.next())
1339        return query.value(0).toBool();
1340    return false;
1341}
1342
1343static bool is_dishnet_eit(uint cardid)
1344{
1345    MSqlQuery query(MSqlQuery::InitCon());
1346    query.prepare(
1347        "SELECT SUM(dishnet_eit) "
1348        "FROM videosource, cardinput "
1349        "WHERE videosource.sourceid = cardinput.sourceid AND"
1350        "      cardinput.cardid     = :CARDID");
1351    query.bindValue(":CARDID", cardid);
1352
1353    if (!query.exec() || !query.isActive())
1354    {
1355        MythDB::DBError("is_dishnet_eit", query);
1356        return false;
1357    }
1358    else if (query.next())
1359        return query.value(0).toBool();
1360    return false;
1361}
1362
1363static int no_capturecards(uint cardid)
1364{
1365    MSqlQuery query(MSqlQuery::InitCon());
1366
1367    QString str =
1368        "SELECT COUNT(cardid) "
1369        "FROM capturecard ";
1370
1371    if (cardid)
1372        str += "WHERE cardid < :CARDID";
1373
1374    query.prepare(str);
1375
1376    if (cardid)
1377        query.bindValue(":CARDID", cardid);
1378
1379    if (!query.exec() || !query.isActive())
1380    {
1381        MythDB::DBError("no_capturecards", query);
1382        return -1;
1383    }
1384    else if (query.next())
1385        return query.value(0).toInt();
1386    return -1;
1387}
1388
1389/** \fn TVRec::RunTV(void)
1390 *  \brief Event handling method, contains event loop.
1391 */
1392void TVRec::RunTV(void)
1393{
1394    QMutexLocker lock(&stateChangeLock);
1395    SetFlags(kFlagRunMainLoop);
1396    ClearFlags(kFlagExitPlayer | kFlagFinishRecording);
1397
1398    eitScanStartTime = QDateTime::currentDateTime();
1399    // check whether we should use the EITScanner in this TVRec instance
1400    if (CardUtil::IsEITCapable(genOpt.cardtype) &&
1401        (!GetDVBChannel() || GetDVBChannel()->IsMaster()))
1402    {
1403        scanner = new EITScanner(cardid);
1404        uint timeout = eitCrawlIdleStart;
1405        // get the number of capture cards and the position of the current card
1406        // to distribute the the scan start evenly over eitTransportTimeout
1407        int card_pos = no_capturecards(cardid);
1408        int no_cards = no_capturecards(0);
1409        if (no_cards > 0 && card_pos >= 0)
1410            timeout += eitTransportTimeout * card_pos / no_cards;
1411        else
1412            timeout += random() % eitTransportTimeout;
1413
1414        eitScanStartTime = eitScanStartTime.addSecs(timeout);
1415    }
1416    else
1417        eitScanStartTime = eitScanStartTime.addYears(1);
1418
1419    while (HasFlags(kFlagRunMainLoop))
1420    {
1421        // If there is a state change queued up, do it...
1422        if (changeState)
1423        {
1424            HandleStateChange();
1425            ClearFlags(kFlagFrontendReady | kFlagCancelNextRecording);
1426        }
1427
1428        // Quick exit on fatal errors.
1429        if (IsErrored())
1430        {
1431            VERBOSE(VB_IMPORTANT, LOC_ERR +
1432                    "RunTV encountered fatal error, exiting event thread.");
1433            ClearFlags(kFlagRunMainLoop);
1434            return;
1435        }
1436
1437        // Handle any tuning events..
1438        HandleTuning();
1439
1440        // Tell frontends about pending recordings
1441        HandlePendingRecordings();
1442
1443        // If we are recording a program, check if the recording is
1444        // over or someone has asked us to finish the recording.
1445        if (GetState() == kState_RecordingOnly &&
1446            (QDateTime::currentDateTime() > recordEndTime ||
1447             HasFlags(kFlagFinishRecording)))
1448        {
1449            ChangeState(kState_None);
1450            ClearFlags(kFlagFinishRecording);
1451        }
1452
1453        if (curRecording)
1454        {
1455            curRecording->UpdateInUseMark();
1456
1457            if (recorder)
1458            {
1459                recorder->SavePositionMap();
1460
1461                // Check for recorder errors
1462                if (recorder->IsErrored())
1463                {
1464                    curRecording->SetRecordingStatus(rsFailed);
1465
1466                    if (GetState() == kState_WatchingLiveTV)
1467                    {
1468                        QString message = QString("QUIT_LIVETV %1").arg(cardid);
1469                        MythEvent me(message);
1470                        gCoreContext->dispatch(me);
1471                    }
1472                    else
1473                        ChangeState(kState_None);
1474                }
1475            }
1476        }
1477
1478        // Check for the end of the current program..
1479        if (GetState() == kState_WatchingLiveTV)
1480        {
1481            QDateTime now   = QDateTime::currentDateTime();
1482            bool has_finish = HasFlags(kFlagFinishRecording);
1483            bool has_rec    = pseudoLiveTVRecording;
1484            bool enable_ui  = true;
1485
1486            pendingRecLock.lock();
1487            bool rec_soon   =
1488                pendingRecordings.find(cardid) != pendingRecordings.end();
1489            pendingRecLock.unlock();
1490
1491            if (has_rec && (has_finish || (now > recordEndTime)))
1492            {
1493                if (pseudoLiveTVRecording && curRecording)
1494                {
1495                    int secsSince = curRecording->GetRecordingStartTime()
1496                        .secsTo(QDateTime::currentDateTime());
1497                    if (secsSince < 120)
1498                    {
1499                        JobQueue::RemoveJobsFromMask(JOB_COMMFLAG,
1500                            autoRunJobs);
1501                        JobQueue::RemoveJobsFromMask(JOB_TRANSCODE,
1502                            autoRunJobs);
1503                    }
1504
1505                    if (autoRunJobs)
1506                    {
1507                        JobQueue::QueueRecordingJobs(
1508                            *curRecording, autoRunJobs);
1509                    }
1510                }
1511
1512                SetPseudoLiveTVRecording(NULL);
1513            }
1514            else if (!has_rec && !rec_soon && curRecording &&
1515                     (now >= curRecording->GetScheduledEndTime()))
1516            {
1517                if (!m_switchingBuffer)
1518                {
1519                    m_switchingBuffer = true;
1520
1521                    SwitchLiveTVRingBuffer(channel->GetCurrentName(),
1522                                           false, true);
1523
1524                    QDateTime starttime; starttime.setTime_t(0);
1525                    if (curRecording)
1526                        starttime = curRecording->GetRecordingStartTime();
1527
1528                    VERBOSE(VB_RECORD, LOC
1529                            <<"!has_rec("<<!has_rec<<") "
1530                            <<"!rec_soon("<<!rec_soon<<") "
1531                            <<"curRec("<<curRecording<<") "
1532                            <<"starttm("
1533                            <<starttime.toString(Qt::ISODate)<<")");
1534                }
1535                else
1536                {
1537                    VERBOSE(VB_RECORD, "Waiting for ringbuffer switch");
1538                }
1539            }
1540            else
1541                enable_ui = false;
1542
1543            if (enable_ui)
1544            {
1545                VERBOSE(VB_RECORD, LOC + "Enabling Full LiveTV UI.");
1546                QString message = QString("LIVETV_WATCH %1 0").arg(cardid);
1547                MythEvent me(message);
1548                gCoreContext->dispatch(me);
1549            }
1550        }
1551
1552        // Check for ExitPlayer flag, and if set change to a non-watching
1553        // state (either kState_RecordingOnly or kState_None).
1554        if (HasFlags(kFlagExitPlayer))
1555        {
1556            if (internalState == kState_WatchingLiveTV)
1557                ChangeState(kState_None);
1558            else if (StateIsPlaying(internalState))
1559                ChangeState(RemovePlaying(internalState));
1560            ClearFlags(kFlagExitPlayer);
1561        }
1562
1563        if (channel && scanner &&
1564            QDateTime::currentDateTime() > eitScanStartTime)
1565        {
1566            if (!dvbOpt.dvb_eitscan)
1567            {
1568                VERBOSE(VB_EIT, LOC + "EIT scanning disabled for this card.");
1569                eitScanStartTime = eitScanStartTime.addYears(1);
1570            }
1571            else if (!get_use_eit(GetCaptureCardNum()))
1572            {
1573                VERBOSE(VB_EIT, LOC + "EIT scanning disabled "
1574                        "for all sources on this card.");
1575                eitScanStartTime = eitScanStartTime.addYears(1);
1576            }
1577            else
1578            {
1579                scanner->StartActiveScan(this, eitTransportTimeout);
1580                SetFlags(kFlagEITScannerRunning);
1581                eitScanStartTime = QDateTime::currentDateTime().addYears(1);
1582            }
1583        }
1584
1585        // We should be no more than a few thousand milliseconds,
1586        // as the end recording code does not have a trigger...
1587        // NOTE: If you change anything here, make sure that
1588        // WaitforEventThreadSleep() will still work...
1589        if (tuningRequests.empty() && !changeState)
1590        {
1591            lock.unlock(); // stateChangeLock
1592
1593            {
1594                QMutexLocker locker(&triggerEventSleepLock);
1595                triggerEventSleepSignal = true;
1596                triggerEventSleepWait.wakeAll();
1597            }
1598
1599            sched_yield();
1600
1601            {
1602                QMutexLocker locker(&triggerEventLoopLock);
1603                // We check triggerEventLoopSignal because it is possible
1604                // that WakeEventLoop() was called since we
1605                // unlocked the stateChangeLock
1606                if (!triggerEventLoopSignal)
1607                {
1608                    triggerEventLoopWait.wait(
1609                        &triggerEventLoopLock, 1000 /* ms */);
1610                }
1611                triggerEventLoopSignal = false;
1612            }
1613
1614            lock.relock(); // stateChangeLock
1615        }
1616    }
1617
1618    if (GetState() != kState_None)
1619    {
1620        ChangeState(kState_None);
1621        HandleStateChange();
1622    }
1623}
1624
1625/** \fn TVRec::WaitForEventThreadSleep(bool wake, ulong time)
1626 *
1627 *  You MUST HAVE the stateChange-lock locked when you call this method!
1628 */
1629
1630bool TVRec::WaitForEventThreadSleep(bool wake, ulong time)
1631{
1632    bool ok = false;
1633    MythTimer t;
1634    t.start();
1635
1636    while (!ok && ((unsigned long) t.elapsed()) < time)
1637    {
1638        if (wake)
1639            WakeEventLoop();
1640
1641        stateChangeLock.unlock();
1642
1643        sched_yield();
1644
1645        {
1646            QMutexLocker locker(&triggerEventSleepLock);
1647            if (!triggerEventSleepSignal)
1648                triggerEventSleepWait.wait(&triggerEventSleepLock);
1649            triggerEventSleepSignal = false;
1650        }
1651
1652        stateChangeLock.lock();
1653
1654        // verify that we were triggered.
1655        ok = (tuningRequests.empty() && !changeState);
1656    }
1657    return ok;
1658}
1659
1660void TVRec::HandlePendingRecordings(void)
1661{
1662    QMutexLocker pendlock(&pendingRecLock);
1663
1664    if (pendingRecordings.empty())
1665        return;
1666
1667    // If we have a pending recording and AskAllowRecording
1668    // or DoNotAskAllowRecording is set and the frontend is
1669    // ready send an ASK_RECORDING query to frontend.
1670
1671    PendingMap::iterator it, next;
1672
1673    for (it = pendingRecordings.begin(); it != pendingRecordings.end();)
1674    {
1675        next = it; ++next;
1676        if (QDateTime::currentDateTime() > (*it).recordingStart.addSecs(30))
1677        {
1678            VERBOSE(VB_RECORD, LOC + "Deleting stale pending recording " +
1679                    QString("%1 '%2'")
1680                    .arg((*it).info->GetCardID())
1681                    .arg((*it).info->GetTitle()));
1682
1683            delete (*it).info;
1684            pendingRecordings.erase(it);
1685        }
1686        it = next;
1687    }
1688
1689    bool has_rec = false;
1690    it = pendingRecordings.begin();
1691    if ((1 == pendingRecordings.size()) &&
1692        (*it).ask &&
1693        ((*it).info->GetCardID() == cardid) &&
1694        (GetState() == kState_WatchingLiveTV))
1695    {
1696        CheckForRecGroupChange();
1697        has_rec = pseudoLiveTVRecording &&
1698            (pseudoLiveTVRecording->GetRecordingEndTime() >
1699             (*it).recordingStart);
1700    }
1701
1702    for (it = pendingRecordings.begin(); it != pendingRecordings.end(); ++it)
1703    {
1704        if (!(*it).ask && !(*it).doNotAsk)
1705            continue;
1706
1707        int timeuntil = ((*it).doNotAsk) ?
1708            -1: QDateTime::currentDateTime().secsTo((*it).recordingStart);
1709
1710        if (has_rec)
1711            (*it).canceled = true;
1712
1713        QString query = QString("ASK_RECORDING %1 %2 %3 %4")
1714            .arg(cardid)
1715            .arg(timeuntil)
1716            .arg(has_rec ? 1 : 0)
1717            .arg((*it).hasLaterShowing ? 1 : 0);
1718
1719        VERBOSE(VB_IMPORTANT, LOC + query);
1720
1721        QStringList msg;
1722        (*it).info->ToStringList(msg);
1723        MythEvent me(query, msg);
1724        gCoreContext->dispatch(me);
1725
1726        (*it).ask = (*it).doNotAsk = false;
1727    }
1728}
1729
1730bool TVRec::GetDevices(uint cardid,
1731                       GeneralDBOptions   &gen_opts,
1732                       DVBDBOptions       &dvb_opts,
1733                       FireWireDBOptions  &firewire_opts)
1734{
1735    int testnum = 0;
1736    QString test;
1737
1738    MSqlQuery query(MSqlQuery::InitCon());
1739    query.prepare(
1740        "SELECT videodevice,      vbidevice,           audiodevice,     "
1741        "       audioratelimit,   defaultinput,        cardtype,        "
1742        "       skipbtaudio,      signal_timeout,      channel_timeout, "
1743        "       dvb_wait_for_seqstart, "
1744        ""
1745        "       dvb_on_demand,    dvb_tuning_delay,    dvb_eitscan,"
1746        ""
1747        "       firewire_speed,   firewire_model,      firewire_connection "
1748        ""
1749        "FROM capturecard "
1750        "WHERE cardid = :CARDID");
1751    query.bindValue(":CARDID", cardid);
1752
1753    if (!query.exec() || !query.isActive())
1754    {
1755        MythDB::DBError("getdevices", query);
1756        return false;
1757    }
1758
1759    if (!query.next())
1760        return false;
1761
1762    // General options
1763    test = query.value(0).toString();
1764    if (test != QString::null)
1765        gen_opts.videodev = test;
1766
1767    test = query.value(1).toString();
1768    if (test != QString::null)
1769        gen_opts.vbidev = test;
1770
1771    test = query.value(2).toString();
1772    if (test != QString::null)
1773        gen_opts.audiodev = test;
1774
1775    gen_opts.audiosamplerate = max(testnum, query.value(3).toInt());
1776
1777    test = query.value(4).toString();
1778    if (test != QString::null)
1779        gen_opts.defaultinput = test;
1780
1781    test = query.value(5).toString();
1782    if (test != QString::null)
1783        gen_opts.cardtype = test;
1784
1785    gen_opts.skip_btaudio = query.value(6).toUInt();
1786
1787    gen_opts.signal_timeout  = (uint) max(query.value(7).toInt(), 0);
1788    gen_opts.channel_timeout = (uint) max(query.value(8).toInt(), 0);
1789
1790    // We should have at least 100 ms to acquire tables...
1791    int table_timeout = ((int)gen_opts.channel_timeout -
1792                         (int)gen_opts.signal_timeout);
1793    if (table_timeout < 100)
1794        gen_opts.channel_timeout = gen_opts.signal_timeout + 2500;
1795
1796    gen_opts.wait_for_seqstart = query.value(9).toUInt();
1797
1798    // DVB options
1799    uint dvboff = 10;
1800    dvb_opts.dvb_on_demand    = query.value(dvboff + 0).toUInt();
1801    dvb_opts.dvb_tuning_delay = query.value(dvboff + 1).toUInt();
1802    dvb_opts.dvb_eitscan      = query.value(dvboff + 2).toUInt();
1803
1804    // Firewire options
1805    uint fireoff = dvboff + 3;
1806    firewire_opts.speed       = query.value(fireoff + 0).toUInt();
1807
1808    test = query.value(fireoff + 1).toString();
1809    if (test != QString::null)
1810        firewire_opts.model = test;
1811
1812    firewire_opts.connection  = query.value(fireoff + 2).toUInt();
1813
1814    return true;
1815}
1816
1817QString TVRec::GetStartChannel(uint cardid, const QString &defaultinput)
1818{
1819    QString startchan = QString::null;
1820
1821    // Get last tuned channel from database, to use as starting channel
1822    MSqlQuery query(MSqlQuery::InitCon());
1823    query.prepare(
1824        "SELECT startchan "
1825        "FROM cardinput "
1826        "WHERE cardinput.cardid   = :CARDID    AND "
1827        "      inputname          = :INPUTNAME");
1828    query.bindValue(":CARDID",    cardid);
1829    query.bindValue(":INPUTNAME", defaultinput);
1830
1831    if (!query.exec() || !query.isActive())
1832    {
1833        MythDB::DBError("getstartchan", query);
1834    }
1835    else if (query.next())
1836    {
1837        startchan = query.value(0).toString();
1838        if (!startchan.isEmpty())
1839        {
1840            VERBOSE(VB_CHANNEL, LOC + QString("Start channel: %1.")
1841                    .arg(startchan));
1842            return startchan;
1843        }
1844    }
1845
1846    // If we failed to get the last tuned channel,
1847    // get a valid channel on our current input.
1848    query.prepare(
1849        "SELECT channum "
1850        "FROM capturecard, cardinput, channel "
1851        "WHERE capturecard.cardid = cardinput.cardid   AND "
1852        "      channel.sourceid   = cardinput.sourceid AND "
1853        "      capturecard.cardid = :CARDID AND "
1854        "      inputname          = :INPUTNAME");
1855    query.bindValue(":CARDID",    cardid);
1856    query.bindValue(":INPUTNAME", defaultinput);
1857
1858    if (!query.exec() || !query.isActive())
1859    {
1860        MythDB::DBError("getstartchan2", query);
1861    }
1862    while (query.next())
1863    {
1864        startchan = query.value(0).toString();
1865        if (!startchan.isEmpty())
1866        {
1867            VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Start channel from DB is "
1868                    "empty, setting to '%1' instead.").arg(startchan));
1869            return startchan;
1870        }
1871    }
1872
1873    // If we failed to get a channel on our current input,
1874    // widen search to any input.
1875    query.prepare(
1876        "SELECT channum, inputname "
1877        "FROM capturecard, cardinput, channel "
1878        "WHERE capturecard.cardid = cardinput.cardid   AND "
1879        "      channel.sourceid   = cardinput.sourceid AND "
1880        "      capturecard.cardid = :CARDID");
1881    query.bindValue(":CARDID", cardid);
1882
1883    if (!query.exec() || !query.isActive())
1884    {
1885        MythDB::DBError("getstartchan3", query);
1886    }
1887    while (query.next())
1888    {
1889        startchan = query.value(0).toString();
1890        if (!startchan.isEmpty())
1891        {
1892            VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Start channel invalid, "
1893                    "setting to '%1' on input %2 instead.").arg(startchan)
1894                    .arg(query.value(1).toString()));
1895            return startchan;
1896        }
1897    }
1898
1899    // If there are no valid channels, just use a random channel
1900    startchan = "3";
1901    VERBOSE(VB_IMPORTANT, LOC_ERR + QString("Problem finding starting channel, "
1902            "setting to default of '%1'.").arg(startchan));
1903    return startchan;
1904}
1905
1906static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
1907{
1908    if (!dtvMon->GetATSCStreamData())
1909        return;
1910
1911    const MasterGuideTable *mgt = dtvMon->GetATSCStreamData()->GetCachedMGT();
1912    if (!mgt)
1913        return;
1914
1915    for (uint i = 0; i < mgt->TableCount(); ++i)
1916    {
1917        pid_cache_item_t item(mgt->TablePID(i), mgt->TableType(i));
1918        pid_cache.push_back(item);
1919    }
1920    dtvMon->GetATSCStreamData()->ReturnCachedTable(mgt);
1921}
1922
1923static bool ApplyCachedPids(DTVSignalMonitor *dtvMon, const DTVChannel* channel)
1924{
1925    pid_cache_t pid_cache;
1926    channel->GetCachedPids(pid_cache);
1927    pid_cache_t::const_iterator it = pid_cache.begin();
1928    bool vctpid_cached = false;
1929    for (; it != pid_cache.end(); ++it)
1930    {
1931        if ((it->second == TableID::TVCT) ||
1932            (it->second == TableID::CVCT))
1933        {
1934            vctpid_cached = true;
1935            dtvMon->GetATSCStreamData()->AddListeningPID(it->first);
1936        }
1937    }
1938    return vctpid_cached;
1939}
1940
1941/** \fn bool TVRec::SetupDTVSignalMonitor(void)
1942 *  \brief Tells DTVSignalMonitor what channel to look for.
1943 *
1944 *   If the major and minor channels are set we tell the signal
1945 *   monitor to look for those in the VCT.
1946 *
1947 *   Otherwise, we tell the signal monitor to look for the MPEG
1948 *   program number in the PAT.
1949 *
1950 *   This method also grabs the ATSCStreamData() from the recorder
1951 *   if possible, or creates one if needed.
1952 */
1953bool TVRec::SetupDTVSignalMonitor(bool EITscan)
1954{
1955    VERBOSE(VB_RECORD, LOC + "Setting up table monitoring.");
1956
1957    DTVSignalMonitor *sm = GetDTVSignalMonitor();
1958    DTVChannel *dtvchan = GetDTVChannel();
1959    if (!sm || !dtvchan)
1960    {
1961        VERBOSE(VB_IMPORTANT, LOC_ERR + "Setting up table monitoring.");
1962        return false;
1963    }
1964
1965    MPEGStreamData *sd = NULL;
1966    if (GetDTVRecorder())
1967    {
1968        sd = GetDTVRecorder()->GetStreamData();
1969        sd->SetCaching(true);
1970    }
1971
1972    QString recording_type = "all";
1973    RecordingInfo *rec = lastTuningRequest.program;
1974    RecordingProfile profile;
1975    load_profile(genOpt.cardtype, tvchain, rec, profile);
1976    const Setting *setting = profile.byName("recordingtype");
1977    if (setting)
1978        recording_type = setting->getValue();
1979
1980    const QString tuningmode = dtvchan->GetTuningMode();
1981
1982    // Check if this is an ATSC Channel
1983    int major = dtvchan->GetMajorChannel();
1984    int minor = dtvchan->GetMinorChannel();
1985    if ((minor > 0) && (tuningmode == "atsc"))
1986    {
1987        QString msg = QString("ATSC channel: %1_%2").arg(major).arg(minor);
1988        VERBOSE(VB_RECORD, LOC + msg);
1989
1990        ATSCStreamData *asd = dynamic_cast<ATSCStreamData*>(sd);
1991        if (!asd)
1992        {
1993            sd = asd = new ATSCStreamData(major, minor);
1994            sd->SetCaching(true);
1995            if (GetDTVRecorder())
1996                GetDTVRecorder()->SetStreamData(asd);
1997        }
1998
1999        asd->Reset();
2000        sm->SetStreamData(sd);
2001        sm->SetChannel(major, minor);
2002        sd->SetRecordingType(recording_type);
2003
2004        // Try to get pid of VCT from cache and
2005        // require MGT if we don't have VCT pid.
2006        if (!ApplyCachedPids(sm, dtvchan))
2007            sm->AddFlags(SignalMonitor::kDTVSigMon_WaitForMGT);
2008
2009        VERBOSE(VB_RECORD, LOC + "Successfully set up ATSC table monitoring.");
2010        return true;
2011    }
2012
2013    // Check if this is an DVB channel
2014    int progNum = dtvchan->GetProgramNumber();
2015#ifdef USING_DVB
2016    if ((progNum >= 0) && (tuningmode == "dvb"))
2017    {
2018        int netid   = dtvchan->GetOriginalNetworkID();
2019        int tsid    = dtvchan->GetTransportID();
2020
2021        DVBStreamData *dsd = dynamic_cast<DVBStreamData*>(sd);
2022        if (!dsd)
2023        {
2024            sd = dsd = new DVBStreamData(netid, tsid, progNum);
2025            sd->SetCaching(true);
2026            if (GetDTVRecorder())
2027                GetDTVRecorder()->SetStreamData(dsd);
2028        }
2029
2030        VERBOSE(VB_RECORD, LOC +
2031                QString("DVB service_id %1 on net_id %2 tsid %3")
2032                .arg(progNum).arg(netid).arg(tsid));
2033
2034        // Some DVB devices munge the PMT and/or PAT so the CRC check fails.
2035        // We need to tell the stream data class to not check the CRC on
2036        // these devices.
2037        if (GetDVBChannel())
2038            sd->SetIgnoreCRC(GetDVBChannel()->HasCRCBug());
2039
2040        dsd->Reset();
2041        sm->SetStreamData(sd);
2042        sm->SetDVBService(netid, tsid, progNum);
2043        sd->SetRecordingType(recording_type);
2044
2045        sm->AddFlags(SignalMonitor::kDTVSigMon_WaitForPMT |
2046                     SignalMonitor::kDTVSigMon_WaitForSDT |
2047                     SignalMonitor::kDVBSigMon_WaitForPos);
2048        sm->SetRotorTarget(1.0f);
2049
2050        VERBOSE(VB_RECORD, LOC + "Successfully set up DVB table monitoring.");
2051        return true;
2052    }
2053#endif // USING_DVB
2054
2055    // Check if this is an MPEG channel
2056    if (progNum >= 0)
2057    {
2058        if (!sd)
2059        {
2060            sd = new MPEGStreamData(progNum, true);
2061            sd->SetCaching(true);
2062            if (GetDTVRecorder())
2063                GetDTVRecorder()->SetStreamData(sd);
2064        }
2065
2066        QString msg = QString("MPEG program number: %1").arg(progNum);
2067        VERBOSE(VB_RECORD, LOC + msg);
2068
2069#ifdef USING_DVB
2070        // Some DVB devices munge the PMT and/or PAT so the CRC check fails.
2071        // We need to tell the stream data class to not check the CRC on
2072        // these devices.
2073        if (GetDVBChannel())
2074            sd->SetIgnoreCRC(GetDVBChannel()->HasCRCBug());
2075#endif // USING_DVB
2076
2077        sd->Reset();
2078        sm->SetStreamData(sd);
2079        sm->SetProgramNumber(progNum);
2080        sd->SetRecordingType(recording_type);
2081
2082        sm->AddFlags(SignalMonitor::kDTVSigMon_WaitForPAT |
2083                     SignalMonitor::kDTVSigMon_WaitForPMT |
2084                     SignalMonitor::kDVBSigMon_WaitForPos);
2085        sm->SetRotorTarget(1.0f);
2086
2087        if (EITscan)
2088        {
2089            sm->GetStreamData()->SetVideoStreamsRequired(0);
2090            sm->IgnoreEncrypted(true);
2091        }
2092
2093        VERBOSE(VB_RECORD, LOC + "Successfully set up MPEG table monitoring.");
2094        return true;
2095    }
2096
2097    QString msg = "No valid DTV info, ATSC maj(%1) min(%2), MPEG pn(%3)";
2098    VERBOSE(VB_IMPORTANT, LOC_ERR + msg.arg(major).arg(minor).arg(progNum));
2099    return false;
2100}
2101
2102/** \fn TVRec::SetupSignalMonitor(bool,bool)
2103 *  \brief This creates a SignalMonitor instance and
2104 *         begins signal monitoring.
2105 *
2106 *   If the channel exists a SignalMonitor instance is created and
2107 *   SignalMonitor::Start() is called to start the signal monitoring thread.
2108 *
2109 *  \param tablemon If set we enable table monitoring
2110 *  \param notify   If set we notify the frontend of the signal values
2111 *  \return true on success, false on failure
2112 */
2113bool TVRec::SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
2114{
2115    VERBOSE(VB_RECORD, LOC + "SetupSignalMonitor("
2116            <<tablemon<<", "<<notify<<")");
2117
2118    // if it already exists, there no need to initialize it
2119    if (signalMonitor)
2120        return true;
2121
2122    // if there is no channel object we can't monitor it
2123    if (!channel)
2124        return false;
2125
2126    // nothing to monitor here either (DummyChannel)
2127    if (genOpt.cardtype == "IMPORT" || genOpt.cardtype == "DEMO")
2128        return true;
2129
2130    // make sure statics are initialized
2131    SignalMonitorValue::Init();
2132
2133    if (channel->Open())
2134        signalMonitor = SignalMonitor::Init(genOpt.cardtype, cardid,
2135                                            channel);
2136
2137    if (signalMonitor)
2138    {
2139        VERBOSE(VB_RECORD, LOC + "Signal monitor successfully created");
2140
2141        signalMonitor->SetMonitoring(this, EITscan,
2142                                     GetDTVSignalMonitor() && tablemon);
2143        signalMonitor->AddListener(this);
2144        signalMonitor->SetUpdateRate(kSignalMonitoringRate);
2145        signalMonitor->SetNotifyFrontend(notify);
2146
2147        // Start the monitoring thread
2148        signalMonitor->Start(true);
2149    }
2150
2151    return true;
2152}
2153
2154/** \fn TVRec::TeardownSignalMonitor()
2155 *  \brief If a SignalMonitor instance exists, the monitoring thread is
2156 *         stopped and the instance is deleted.
2157 */
2158void TVRec::TeardownSignalMonitor()
2159{
2160    if (!signalMonitor)
2161        return;
2162
2163    VERBOSE(VB_RECORD, LOC + "TeardownSignalMonitor() -- begin");
2164
2165    // If this is a DTV signal monitor, save any pids we know about.
2166    DTVSignalMonitor *dtvMon  = GetDTVSignalMonitor();
2167    DTVChannel       *dtvChan = GetDTVChannel();
2168    if (dtvMon && dtvChan)
2169    {
2170        pid_cache_t pid_cache;
2171        GetPidsToCache(dtvMon, pid_cache);
2172        if (pid_cache.size())
2173            dtvChan->SaveCachedPids(pid_cache);
2174    }
2175
2176    if (signalMonitor)
2177    {
2178        delete signalMonitor;
2179        signalMonitor = NULL;
2180    }
2181
2182    VERBOSE(VB_RECORD, LOC + "TeardownSignalMonitor() -- end");
2183}
2184
2185/** \fn TVRec::SetSignalMonitoringRate(int,int)
2186 *  \brief Sets the signal monitoring rate.
2187 *
2188 *  \sa EncoderLink::SetSignalMonitoringRate(int,int),
2189 *      RemoteEncoder::SetSignalMonitoringRate(int,int)
2190 *  \param rate           The update rate to use in milliseconds,
2191 *                        use 0 to disable signal monitoring.
2192 *  \param notifyFrontend If 1, SIGNAL messages will be sent to
2193 *                        the frontend using this recorder.
2194 *  \return 1 if it signal monitoring is turned on, 0 otherwise.
2195 */
2196int TVRec::SetSignalMonitoringRate(int rate, int notifyFrontend)
2197{
2198    QString msg = "SetSignalMonitoringRate(%1, %2)";
2199    VERBOSE(VB_RECORD, LOC + msg.arg(rate).arg(notifyFrontend) + "-- start");
2200
2201    QMutexLocker lock(&stateChangeLock);
2202
2203    if (!SignalMonitor::IsSupported(genOpt.cardtype))
2204    {
2205        VERBOSE(VB_IMPORTANT, LOC + "Signal Monitoring is not"
2206                "supported by your hardware.");
2207        return 0;
2208    }
2209
2210    if (GetState() != kState_WatchingLiveTV)
2211    {
2212        VERBOSE(VB_IMPORTANT, LOC + "Signal can only "
2213                "be monitored in LiveTV Mode.");
2214        return 0;
2215    }
2216
2217    ClearFlags(kFlagRingBufferReady);
2218
2219    TuningRequest req = (rate > 0) ?
2220        TuningRequest(kFlagAntennaAdjust, channel->GetCurrentName()) :
2221        TuningRequest(kFlagLiveTV);
2222
2223    tuningRequests.enqueue(req);
2224
2225    // Wait for RingBuffer reset
2226    while (!HasFlags(kFlagRingBufferReady))
2227        WaitForEventThreadSleep();
2228    VERBOSE(VB_RECORD, LOC + msg.arg(rate).arg(notifyFrontend) + " -- end");
2229    return 1;
2230}
2231
2232DTVSignalMonitor *TVRec::GetDTVSignalMonitor(void)
2233{
2234    return dynamic_cast<DTVSignalMonitor*>(signalMonitor);
2235}
2236
2237/** \fn TVRec::ShouldSwitchToAnotherCard(QString)
2238 *  \brief Checks if named channel exists on current tuner, or
2239 *         another tuner.
2240 *
2241 *  \param chanid channel to verify against tuners.
2242 *  \return true if the channel on another tuner and not current tuner,
2243 *          false otherwise.
2244 *  \sa EncoderLink::ShouldSwitchToAnotherCard(const QString&),
2245 *      RemoteEncoder::ShouldSwitchToAnotherCard(QString),
2246 *      CheckChannel(QString)
2247 */
2248bool TVRec::ShouldSwitchToAnotherCard(QString chanid)
2249{
2250    QString msg("");
2251    MSqlQuery query(MSqlQuery::InitCon());
2252
2253    if (!query.isConnected())
2254        return false;
2255
2256    query.prepare("SELECT channel.channum, channel.callsign "
2257                  "FROM channel "
2258                  "WHERE channel.chanid = :CHANID");
2259    query.bindValue(":CHANID", chanid);
2260    if (!query.exec() || !query.isActive() || query.size() == 0)
2261    {
2262        MythDB::DBError("ShouldSwitchToAnotherCard", query);
2263        return false;
2264    }
2265
2266    query.next();
2267    QString channelname = query.value(0).toString();
2268    QString callsign = query.value(1).toString();
2269
2270    query.prepare(
2271        "SELECT channel.channum "
2272        "FROM channel,cardinput "
2273        "WHERE ( channel.chanid = :CHANID OR             "
2274        "        ( channel.channum  = :CHANNUM AND       "
2275        "          channel.callsign = :CALLSIGN    )     "
2276        "      )                                     AND "
2277        "      channel.sourceid = cardinput.sourceid AND "
2278        "      cardinput.cardid = :CARDID");
2279    query.bindValue(":CHANID", chanid);
2280    query.bindValue(":CHANNUM", channelname);
2281    query.bindValue(":CALLSIGN", callsign);
2282    query.bindValue(":CARDID", cardid);
2283
2284    if (!query.exec() || !query.isActive())
2285    {
2286        MythDB::DBError("ShouldSwitchToAnotherCard", query);
2287    }
2288    else if (query.size() > 0)
2289    {
2290        msg = "Found channel (%1) on current card(%2).";
2291        VERBOSE(VB_RECORD, LOC + msg.arg(channelname).arg(cardid));
2292        return false;
2293    }
2294
2295    // We didn't find it on the current card, so now we check other cards.
2296    query.prepare(
2297        "SELECT channel.channum, cardinput.cardid "
2298        "FROM channel,cardinput "
2299        "WHERE ( channel.chanid = :CHANID OR              "
2300        "        ( channel.channum  = :CHANNUM AND        "
2301        "          channel.callsign = :CALLSIGN    )      "
2302        "      )                                      AND "
2303        "      channel.sourceid  = cardinput.sourceid AND "
2304        "      cardinput.cardid != :CARDID");
2305    query.bindValue(":CHANID", chanid);
2306    query.bindValue(":CHANNUM", channelname);
2307    query.bindValue(":CALLSIGN", callsign);
2308    query.bindValue(":CARDID", cardid);
2309
2310    if (!query.exec() || !query.isActive())
2311    {
2312        MythDB::DBError("ShouldSwitchToAnotherCard", query);
2313    }
2314    else if (query.next())
2315    {
2316        msg = QString("Found channel (%1) on different card(%2).")
2317            .arg(query.value(0).toString()).arg(query.value(1).toString());
2318        VERBOSE(VB_RECORD, LOC + msg);
2319        return true;
2320    }
2321
2322    msg = QString("Did not find channel(%1) on any card.").arg(channelname);
2323    VERBOSE(VB_RECORD, LOC + msg);
2324    return false;
2325}
2326
2327/** \fn TVRec::CheckChannel(QString) const
2328 *  \brief Checks if named channel exists on current tuner.
2329 *
2330 *  \param name channel to verify against current tuner.
2331 *  \return true if it succeeds, false otherwise.
2332 *  \sa EncoderLink::CheckChannel(const QString&),
2333 *      RemoteEncoder::CheckChannel(QString),
2334 *      CheckChannel(ChannelBase*,const QString&,QString&),
2335 *      ShouldSwitchToAnotherCard(QString)
2336 */
2337bool TVRec::CheckChannel(QString name) const
2338{
2339    if (!channel)
2340        return false;
2341
2342    QString dummyID;
2343    return channel->CheckChannel(name, dummyID);
2344}
2345
2346/** \fn QString add_spacer(const QString&, const QString&)
2347 *  \brief Adds the spacer before the last character in chan.
2348 */
2349static QString add_spacer(const QString &channel, const QString &spacer)
2350{
2351    QString chan = channel;
2352    chan.detach();
2353    if ((chan.length() >= 2) && !spacer.isEmpty())
2354        return chan.left(chan.length()-1) + spacer + chan.right(1);
2355    return chan;
2356}
2357
2358/** \fn TVRec::CheckChannelPrefix(const QString&,uint&,bool&,QString&)
2359 *  \brief Checks a prefix against the channels in the DB.
2360 *
2361 *   If the prefix matches a channel on any recorder this function returns
2362 *   true, otherwise it returns false.
2363 *
2364 *   If the prefix matches any channel entirely (i.e. prefix == channum),
2365 *   then the cardid of the recorder it matches is returned in
2366 *   'is_complete_valid_channel_on_rec'; if it matches multiple recorders,
2367 *   and one of them is this recorder, this recorder is returned in
2368 *   'is_complete_valid_channel_on_rec'; if it isn't complete for any channel
2369 *    on any recorder 'is_complete_valid_channel_on_rec' is set to zero.
2370 *
2371 *   If adding another character could reduce the number of channels the
2372 *   prefix matches 'is_extra_char_useful' is set to true, otherwise it
2373 *   is set to false.
2374 *
2375 *   Finally, if in order for the prefix to match a channel, a spacer needs
2376 *   to be added, the first matching spacer is returned in needed_spacer.
2377 *   If there is more than one spacer that might be employed and one of them
2378 *   is used for the current recorder, and others are used for other
2379 *   recorders, then the one for the current recorder is returned. The
2380 *   spacer must be inserted before the last character of the prefix for
2381 *   anything else returned from the function to be valid.
2382 *
2383 *  \return true if this is a valid prefix for a channel, false otherwise
2384 */
2385bool TVRec::CheckChannelPrefix(const QString &prefix,
2386                               uint          &is_complete_valid_channel_on_rec,
2387                               bool          &is_extra_char_useful,
2388                               QString       &needed_spacer)
2389{
2390#if DEBUG_CHANNEL_PREFIX
2391    VERBOSE(VB_IMPORTANT, QString("CheckChannelPrefix(%1)").arg(prefix));
2392#endif
2393
2394    static const uint kSpacerListSize = 5;
2395    static const char* spacers[kSpacerListSize] = { "", "_", "-", "#", "." };
2396
2397    MSqlQuery query(MSqlQuery::InitCon());
2398    QString basequery = QString(
2399        "SELECT channel.chanid, channel.channum, cardinput.cardid "
2400        "FROM channel, capturecard, cardinput "
2401        "WHERE channel.channum LIKE '%1%'            AND "
2402        "      channel.sourceid = cardinput.sourceid AND "
2403        "      cardinput.cardid = capturecard.cardid");
2404
2405    QString cardquery[2] =
2406    {
2407        QString(" AND capturecard.cardid  = '%1'").arg(cardid),
2408        QString(" AND capturecard.cardid != '%1'").arg(cardid),
2409    };
2410
2411    vector<uint>    fchanid;
2412    vector<QString> fchannum;
2413    vector<uint>    fcardid;
2414    vector<QString> fspacer;
2415
2416    for (uint i = 0; i < 2; i++)
2417    {
2418        for (uint j = 0; j < kSpacerListSize; j++)
2419        {
2420            QString qprefix = add_spacer(
2421                prefix, (QString(spacers[j]) == "_") ? "\\_" : spacers[j]);
2422            query.prepare(basequery.arg(qprefix) + cardquery[i]);
2423
2424            if (!query.exec() || !query.isActive())
2425            {
2426                MythDB::DBError("checkchannel -- locate channum", query);
2427            }
2428            else if (query.size())
2429            {
2430                while (query.next())
2431                {
2432                    fchanid.push_back(query.value(0).toUInt());
2433                    fchannum.push_back(query.value(1).toString());
2434                    fcardid.push_back(query.value(2).toUInt());
2435                    fspacer.push_back(spacers[j]);
2436#if DEBUG_CHANNEL_PREFIX
2437                    VERBOSE(VB_IMPORTANT, QString("(%1,%2) Adding %3 rec %4")
2438                            .arg(i).arg(j).arg(query.value(1).toString(),6)
2439                            .arg(query.value(2).toUInt()));
2440#endif
2441                }
2442            }
2443
2444            if (prefix.length() < 2)
2445                break;
2446        }
2447    }
2448
2449    // Now process the lists for the info we need...
2450    is_extra_char_useful = false;
2451    is_complete_valid_channel_on_rec = 0;
2452    needed_spacer = "";
2453
2454    if (fchanid.size() == 0)
2455        return false;
2456
2457    if (fchanid.size() == 1) // Unique channel...
2458    {
2459        needed_spacer = fspacer[0];
2460        bool nc       = (fchannum[0] != add_spacer(prefix, fspacer[0]));
2461
2462        is_complete_valid_channel_on_rec = (nc) ? 0 : fcardid[0];
2463        is_extra_char_useful             = nc;
2464        return true;
2465    }
2466
2467    // If we get this far there is more than one channel
2468    // sharing the prefix we were given.
2469
2470    // Is an extra characher useful for disambiguation?
2471    is_extra_char_useful = false;
2472    for (uint i = 0; (i < fchannum.size()) && !is_extra_char_useful; i++)
2473    {
2474        is_extra_char_useful = (fchannum[i] != add_spacer(prefix, fspacer[i]));
2475#if DEBUG_CHANNEL_PREFIX
2476        VERBOSE(VB_IMPORTANT, "is_extra_char_useful("
2477                <<fchannum[i]<<"!="<<add_spacer(prefix, fspacer[i])
2478                <<"): "<<is_extra_char_useful);
2479#endif
2480    }
2481
2482    // Are any of the channels complete w/o spacer?
2483    // If so set is_complete_valid_channel_on_rec,
2484    // with a preference for our cardid.
2485    for (uint i = 0; i < fchannum.size(); i++)
2486    {
2487        if (fchannum[i] == prefix)
2488        {
2489            is_complete_valid_channel_on_rec = fcardid[i];
2490            if (fcardid[i] == (uint)cardid)
2491                break;
2492        }
2493    }
2494
2495    if (is_complete_valid_channel_on_rec)
2496        return true;
2497
2498    // Add a spacer, if one is needed to select a valid channel.
2499    bool spacer_needed = true;
2500    for (uint i = 0; (i < fspacer.size() && spacer_needed); i++)
2501        spacer_needed = !fspacer[i].isEmpty();
2502    if (spacer_needed)
2503        needed_spacer = fspacer[0];
2504
2505    // If it isn't useful to wait for more characters,
2506    // then try to commit to any true match immediately.
2507    for (uint i = 0; i < ((is_extra_char_useful) ? 0 : fchanid.size()); i++)
2508    {
2509        if (fchannum[i] == add_spacer(prefix, fspacer[i]))
2510        {
2511            needed_spacer = fspacer[i];
2512            is_complete_valid_channel_on_rec = fcardid[i];
2513            return true;
2514        }
2515    }
2516
2517    return true;
2518}
2519
2520bool TVRec::SetVideoFiltersForChannel(uint  sourceid,
2521                                      const QString &channum)
2522{
2523    if (!recorder)
2524        return false;
2525
2526    QString videoFilters = ChannelUtil::GetVideoFilters(sourceid, channum);
2527    if (!videoFilters.isEmpty())
2528    {
2529        recorder->SetVideoFilters(videoFilters);
2530        return true;
2531    }
2532
2533    return false;
2534}
2535
2536/** \fn TVRec::IsReallyRecording()
2537 *  \brief Returns true if frontend can consider the recorder started.
2538 *  \sa IsRecording()
2539 */
2540bool TVRec::IsReallyRecording(void)
2541{
2542    return ((recorder && recorder->IsRecording()) ||
2543            HasFlags(kFlagDummyRecorderRunning));
2544}
2545
2546/** \fn TVRec::IsBusy(TunedInputInfo*,int) const
2547 *  \brief Returns true if the recorder is busy, or will be within
2548 *         the next time_buffer seconds.
2549 *  \sa EncoderLink::IsBusy(TunedInputInfo*, int time_buffer)
2550 */
2551bool TVRec::IsBusy(TunedInputInfo *busy_input, int time_buffer) const
2552{
2553    TunedInputInfo dummy;
2554    if (!busy_input)
2555        busy_input = &dummy;
2556
2557    busy_input->Clear();
2558
2559    if (!channel)
2560        return false;
2561
2562    QStringList list = channel->GetConnectedInputs();
2563    if (list.empty())
2564        return false;
2565
2566    uint chanid = 0;
2567
2568    if (GetState() != kState_None)
2569    {
2570        busy_input->inputid = channel->GetCurrentInputNum();
2571        chanid              = channel->GetChanID();
2572    }
2573
2574    PendingInfo pendinfo;
2575    bool        has_pending;
2576    {
2577        pendingRecLock.lock();
2578        PendingMap::const_iterator it = pendingRecordings.find(cardid);
2579        has_pending = (it != pendingRecordings.end());
2580        if (has_pending)
2581            pendinfo = *it;
2582        pendingRecLock.unlock();
2583    }
2584
2585    if (!busy_input->inputid && has_pending)
2586    {
2587        int timeLeft = QDateTime::currentDateTime()
2588            .secsTo(pendinfo.recordingStart);
2589
2590        if (timeLeft <= time_buffer)
2591        {
2592            QString channum = QString::null, input = QString::null;
2593            if (pendinfo.info->QueryTuningInfo(channum, input))
2594            {
2595                busy_input->inputid = channel->GetInputByName(input);
2596                chanid = pendinfo.info->GetChanID();
2597            }
2598        }
2599    }
2600
2601    if (busy_input->inputid)
2602    {
2603        CardUtil::GetInputInfo(*busy_input);
2604        busy_input->chanid  = chanid;
2605        busy_input->mplexid = ChannelUtil::GetMplexID(busy_input->chanid);
2606        busy_input->mplexid =
2607            (32767 == busy_input->mplexid) ? 0 : busy_input->mplexid;
2608    }
2609
2610    return busy_input->inputid;
2611}
2612
2613
2614/** \fn TVRec::GetFramerate()
2615 *  \brief Returns recordering frame rate from the recorder.
2616 *  \sa RemoteEncoder::GetFrameRate(), EncoderLink::GetFramerate(void),
2617 *      RecorderBase::GetFrameRate()
2618 *  \return Frames per second if query succeeds -1 otherwise.
2619 */
2620float TVRec::GetFramerate(void)
2621{
2622    QMutexLocker lock(&stateChangeLock);
2623
2624    if (recorder)
2625        return recorder->GetFrameRate();
2626    return -1.0f;
2627}
2628
2629/** \fn TVRec::GetFramesWritten()
2630 *  \brief Returns number of frames written to disk by recorder.
2631 *
2632 *  \sa EncoderLink::GetFramesWritten(), RemoteEncoder::GetFramesWritten()
2633 *  \return Number of frames if query succeeds, -1 otherwise.
2634 */
2635long long TVRec::GetFramesWritten(void)
2636{
2637    QMutexLocker lock(&stateChangeLock);
2638
2639    if (recorder)
2640        return recorder->GetFramesWritten();
2641    return -1;
2642}
2643
2644/** \fn TVRec::GetFilePosition()
2645 *  \brief Returns total number of bytes written by RingBuffer.
2646 *
2647 *  \sa EncoderLink::GetFilePosition(), RemoteEncoder::GetFilePosition()
2648 *  \return Bytes written if query succeeds, -1 otherwise.
2649 */
2650long long TVRec::GetFilePosition(void)
2651{
2652    QMutexLocker lock(&stateChangeLock);
2653
2654    if (ringBuffer)
2655        return ringBuffer->GetWritePosition();
2656    return -1;
2657}
2658
2659/** \brief Returns byte position in RingBuffer
2660 *         of a keyframe according to recorder.
2661 *
2662 *  \sa EncoderLink::GetKeyframePosition(uint64_t),
2663 *      RemoteEncoder::GetKeyframePosition(uint64_t)
2664 *  \return Byte position of keyframe if query succeeds, -1 otherwise.
2665 */
2666int64_t TVRec::GetKeyframePosition(uint64_t desired) const
2667{
2668    QMutexLocker lock(&stateChangeLock);
2669
2670    if (recorder)
2671        return recorder->GetKeyframePosition(desired);
2672    return -1;
2673}
2674
2675/**
2676 *  \brief Returns byte position in RingBuffer of a keyframes
2677 *         according to recorder.
2678 *
2679 *  \sa EncoderLink::GetKeyframePositions(int64_t, int64_t, frm_pos_map_t&),
2680 *      RemoteEncoder::GetKeyframePositions(int64_t, int64_t, frm_pos_map_t&)
2681 *  \return Byte position of keyframe if query succeeds, -1 otherwise.
2682 */
2683bool TVRec::GetKeyframePositions(
2684    int64_t start, int64_t end, frm_pos_map_t &map) const
2685{
2686    QMutexLocker lock(&stateChangeLock);
2687
2688    if (recorder)
2689        return recorder->GetKeyframePositions(start, end, map);
2690
2691    return false;
2692}
2693
2694/** \fn TVRec::GetMaxBitrate(void) const
2695 *  \brief Returns the maximum bits per second this recorder can produce.
2696 *
2697 *  \sa EncoderLink::GetMaxBitrate(void), RemoteEncoder::GetMaxBitrate(void)
2698 */
2699long long TVRec::GetMaxBitrate(void) const
2700{
2701    long long bitrate;
2702    if (genOpt.cardtype == "MPEG")
2703        bitrate = 10080000LL; // use DVD max bit rate
2704    if (genOpt.cardtype == "HDPVR")
2705        bitrate = 20200000LL; // Peek bit rate for HD-PVR
2706    else if (!CardUtil::IsEncoder(genOpt.cardtype))
2707        bitrate = 22200000LL; // 1080i
2708    else // frame grabber
2709        bitrate = 10080000LL; // use DVD max bit rate, probably too big
2710
2711    return bitrate;
2712}
2713
2714/** \fn TVRec::SpawnLiveTV(LiveTVChain*,bool,QString)
2715 *  \brief Tells TVRec to spawn a "Live TV" recorder.
2716 *  \sa EncoderLink::SpawnLiveTV(LiveTVChain*,bool,QString),
2717 *      RemoteEncoder::SpawnLiveTV(QString,bool,QSting)
2718 */
2719void TVRec::SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
2720{
2721    QMutexLocker lock(&stateChangeLock);
2722
2723    tvchain = newchain;
2724    tvchain->ReloadAll();
2725
2726    QString hostprefix = QString("myth://%1:%2/")
2727                                .arg(gCoreContext->GetSetting("BackendServerIP"))
2728                                .arg(gCoreContext->GetSetting("BackendServerPort"));
2729
2730    tvchain->SetHostPrefix(hostprefix);
2731    tvchain->SetCardType(genOpt.cardtype);
2732
2733    ispip = pip;
2734    LiveTVStartChannel = startchan;
2735
2736    // Change to WatchingLiveTV
2737    ChangeState(kState_WatchingLiveTV);
2738    // Wait for state change to take effect
2739    WaitForEventThreadSleep();
2740
2741    // Make sure StartRecording can't steal our tuner
2742    SetFlags(kFlagCancelNextRecording);
2743}
2744
2745/** \fn TVRec::GetChainID()
2746 *  \brief Get the chainid of the livetv instance
2747 */
2748QString TVRec::GetChainID(void)
2749{
2750    if (tvchain)
2751        return tvchain->GetID();
2752    return "";
2753}
2754
2755/** \fn TVRec::CheckForRecGroupChange(void)
2756 *  \brief Check if frontend changed the recording group.
2757 *
2758 *   This is needed because the frontend may toggle whether something
2759 *   should be kept as a recording in the frontend, but this class may
2760 *   not find out about it in time unless we check the DB when this
2761 *   information is important.
2762 */
2763void TVRec::CheckForRecGroupChange(void)
2764{
2765    QMutexLocker lock(&stateChangeLock);
2766
2767    if (internalState == kState_None)
2768        return; // already stopped
2769
2770    if (!curRecording)
2771        return;
2772
2773    const QString recgrp = curRecording->QueryRecordingGroup();
2774    curRecording->SetRecordingGroup(recgrp);
2775
2776    if (recgrp != "LiveTV" && !pseudoLiveTVRecording)
2777    {
2778        // User wants this recording to continue
2779        SetPseudoLiveTVRecording(new ProgramInfo(*curRecording));
2780    }
2781    else if (recgrp == "LiveTV" && pseudoLiveTVRecording)
2782    {
2783        // User wants to abandon scheduled recording
2784        SetPseudoLiveTVRecording(NULL);
2785    }
2786}
2787
2788static uint get_input_id(uint cardid, const QString &inputname)
2789{
2790    MSqlQuery query(MSqlQuery::InitCon());
2791
2792    query.prepare(
2793        "SELECT cardinputid "
2794        "FROM cardinput "
2795        "WHERE cardid    = :CARDID AND "
2796        "      inputname = :INNAME");
2797
2798    query.bindValue(":CARDID", cardid);
2799    query.bindValue(":INNAME", inputname);
2800
2801    if (!query.exec() || !query.isActive())
2802        MythDB::DBError("get_input_id", query);
2803    else if (query.next())
2804        return query.value(0).toUInt();
2805
2806    return 0;
2807}
2808
2809/** \fn TVRec::NotifySchedulerOfRecording(RecordingInfo*)
2810 *  \brief Tell scheduler about the recording.
2811 *
2812 *   This is needed if the frontend has marked the LiveTV
2813 *   buffer for recording after we exit LiveTV. In this case
2814 *   the scheduler needs to know about the recording so it
2815 *   can properly take overrecord into account, and to properly
2816 *   reschedule other recordings around to avoid this recording.
2817 */
2818void TVRec::NotifySchedulerOfRecording(RecordingInfo *rec)
2819{
2820    if (!channel)
2821        return;
2822
2823    // Notify scheduler of the recording.
2824    // + set up recording so it can be resumed
2825    rec->SetCardID(cardid);
2826    rec->SetInputID(get_input_id(cardid, channel->GetCurrentInput()));
2827    rec->SetRecordingRuleType(rec->GetRecordingRule()->m_type);
2828
2829    if (rec->GetRecordingRuleType() == kNotRecording)
2830    {
2831        rec->SetRecordingRuleType(kSingleRecord);
2832        rec->GetRecordingRule()->m_type = kSingleRecord;
2833    }
2834
2835    // + remove DefaultEndOffset which would mismatch the live session
2836    rec->GetRecordingRule()->m_endOffset = 0;
2837
2838    // + save rsInactive recstatus to so that a reschedule call
2839    //   doesn't start recording this on another card before we
2840    //   send the SCHEDULER_ADD_RECORDING message to the scheduler.
2841    rec->SetRecordingStatus(rsInactive);
2842    rec->AddHistory(false);
2843
2844    // + save RecordingRule so that we get a recordid
2845    //   (don't allow signalChange(), avoiding unneeded reschedule)
2846    rec->GetRecordingRule()->Save(false);
2847
2848    // + save recordid to recorded entry
2849    rec->ApplyRecordRecID();
2850
2851    // + set proper recstatus (saved later)
2852    rec->SetRecordingStatus(rsRecording);
2853
2854    // + pass proginfo to scheduler and reschedule
2855    QStringList prog;
2856    rec->ToStringList(prog);
2857    MythEvent me("SCHEDULER_ADD_RECORDING", prog);
2858    gCoreContext->dispatch(me);
2859
2860    // Allow scheduler to end this recording before post-roll,
2861    // if it has another recording for this recorder.
2862    ClearFlags(kFlagCancelNextRecording);
2863}
2864
2865/** \fn TVRec::SetLiveRecording(int)
2866 *  \brief Tells the Scheduler about changes to the recording status
2867 *         of the LiveTV recording.
2868 *
2869 *   NOTE: Currently the 'recording' parameter is ignored and decisions
2870 *         are based on the recording group alone.
2871 *
2872 *  \param recording Set to 1 to mark as rsRecording, set to 0 to mark as
2873 *         rsCancelled, and set to -1 to base the decision of the recording
2874 *         group.
2875 */
2876void TVRec::SetLiveRecording(int recording)
2877{
2878    VERBOSE(VB_IMPORTANT, LOC + "SetLiveRecording("<<recording<<")");
2879    QMutexLocker locker(&stateChangeLock);
2880
2881    (void) recording;
2882
2883    RecStatusType recstat = rsCancelled;
2884    bool was_rec = pseudoLiveTVRecording;
2885    CheckForRecGroupChange();
2886    if (was_rec && !pseudoLiveTVRecording)
2887    {
2888        VERBOSE(VB_IMPORTANT, LOC + "SetLiveRecording() -- cancel");
2889        // cancel -- 'recording' should be 0 or -1
2890        SetFlags(kFlagCancelNextRecording);
2891        curRecording->SetRecordingGroup("LiveTV");
2892        autoRunJobs = JOB_NONE;
2893    }
2894    else if (!was_rec && pseudoLiveTVRecording)
2895    {
2896        VERBOSE(VB_IMPORTANT, LOC + "SetLiveRecording() -- record");
2897        // record -- 'recording' should be 1 or -1
2898
2899        // If the last recording was flagged for keeping
2900        // in the frontend, then add the recording rule
2901        // so that transcode, commfrag, etc can be run.
2902        recordEndTime = GetRecordEndTime(pseudoLiveTVRecording);
2903        NotifySchedulerOfRecording(curRecording);
2904        recstat = curRecording->GetRecordingStatus();
2905        curRecording->SetRecordingGroup("Default");
2906
2907        RecordingProfile profile;
2908        load_profile(genOpt.cardtype, NULL, curRecording, profile);
2909        autoRunJobs = init_jobs(curRecording, profile, runJobOnHostOnly,
2910                                transcodeFirst, earlyCommFlag);
2911    }
2912
2913    MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
2914                 .arg(curRecording->GetCardID())
2915                 .arg(curRecording->GetChanID())
2916                 .arg(curRecording->GetScheduledStartTime(ISODate))
2917                 .arg(recstat)
2918                 .arg(curRecording->GetRecordingEndTime(ISODate)));
2919
2920    gCoreContext->dispatch(me);
2921}
2922
2923/** \fn TVRec::StopLiveTV(void)
2924 *  \brief Tells TVRec to stop a "Live TV" recorder.
2925 *  \sa EncoderLink::StopLiveTV(), RemoteEncoder::StopLiveTV()
2926 */
2927void TVRec::StopLiveTV(void)
2928{
2929    QMutexLocker lock(&stateChangeLock);
2930    VERBOSE(VB_RECORD, LOC + "StopLiveTV(void) curRec: "<<curRecording
2931            <<" pseudoRec: "<<pseudoLiveTVRecording);
2932
2933    if (internalState != kState_WatchingLiveTV)
2934        return;
2935
2936    bool hadPseudoLiveTVRec = pseudoLiveTVRecording;
2937    CheckForRecGroupChange();
2938
2939    if (!hadPseudoLiveTVRec && pseudoLiveTVRecording)
2940        NotifySchedulerOfRecording(curRecording);
2941
2942    // Figure out next state and if needed recording end time.
2943    TVState next_state = kState_None;
2944    if (pseudoLiveTVRecording)
2945    {
2946        recordEndTime = GetRecordEndTime(pseudoLiveTVRecording);
2947        next_state = kState_RecordingOnly;
2948    }
2949
2950    // Change to the appropriate state
2951    ChangeState(next_state);
2952
2953    // Wait for state change to take effect...
2954    WaitForEventThreadSleep();
2955
2956    // We are done with the tvchain...
2957    tvchain = NULL;
2958}
2959
2960/** \fn TVRec::PauseRecorder(void)
2961 *  \brief Tells "recorder" to pause, used for channel and input changes.
2962 *
2963 *   When the RecorderBase instance has paused it calls RecorderPaused(void)
2964 *
2965 *  \sa EncoderLink::PauseRecorder(void), RemoteEncoder::PauseRecorder(void),
2966 *      RecorderBase::Pause(void)
2967 */
2968void TVRec::PauseRecorder(void)
2969{
2970    QMutexLocker lock(&stateChangeLock);
2971
2972    if (!recorder)
2973    {
2974        VERBOSE(VB_IMPORTANT, LOC + "PauseRecorder() "
2975                "called with no recorder");
2976        return;
2977    }
2978
2979    recorder->Pause();
2980}
2981
2982/** \fn TVRec::RecorderPaused(void)
2983 *  \brief This is a callback, called by the "recorder" instance when
2984 *         it has actually paused.
2985 *  \sa PauseRecorder(void)
2986 */
2987void TVRec::RecorderPaused(void)
2988{
2989    if (pauseNotify)
2990        WakeEventLoop();
2991}
2992
2993/**
2994 *  \brief Toggles whether the current channel should be on our favorites list.
2995 */
2996void TVRec::ToggleChannelFavorite(QString changroupname)
2997{
2998    QMutexLocker lock(&stateChangeLock);
2999
3000    if (!channel)
3001        return;
3002
3003    // Get current channel id...
3004    uint    sourceid = channel->GetCurrentSourceID();
3005    QString channum  = channel->GetCurrentName();
3006    uint chanid = ChannelUtil::GetChanID(sourceid, channum);
3007
3008    if (!chanid)
3009    {
3010        VERBOSE(VB_IMPORTANT, LOC_ERR + QString(
3011                "Channel: \'%1\' was not found in the database.\n"
3012                "\t\t\tMost likely, your DefaultTVChannel setting is wrong.\n"
3013                "\t\t\tCould not toggle favorite.").arg(channum));
3014        return;
3015    }
3016
3017    int  changrpid;
3018    bool result;
3019
3020    changrpid = ChannelGroup::GetChannelGroupId(changroupname);
3021
3022    if (changrpid <1)
3023    {
3024          VERBOSE(VB_RECORD, LOC + QString("ToggleChannelFavorite: Invalid "
3025                   "channel group name %1, ").arg(changroupname));
3026    }
3027    else
3028    {
3029        result = ChannelGroup::ToggleChannel(chanid, changrpid, true);
3030
3031        if (!result)
3032           VERBOSE(VB_RECORD, LOC + "Unable to toggle channel favorite.");
3033        else
3034           VERBOSE(VB_RECORD, LOC + QString("Toggled channel favorite."
3035                   "channum %1, chan group %2").arg(channum).arg(changroupname));
3036    }
3037}
3038
3039/** \fn TVRec::ChangePictureAttribute(PictureAdjustType,PictureAttribute,bool)
3040 *  \brief Returns current value [0,100] if it succeeds, -1 otherwise.
3041 *
3042 *  Note: In practice this only works with frame grabbing recorders.
3043 */
3044int TVRec::GetPictureAttribute(PictureAttribute attr)
3045{
3046    QMutexLocker lock(&stateChangeLock);
3047    if (!channel)
3048        return -1;
3049
3050    int ret = channel->GetPictureAttribute(attr);
3051
3052    return (ret < 0) ? -1 : ret / 655;
3053}
3054
3055/** \fn TVRec::ChangePictureAttribute(PictureAdjustType,PictureAttribute,bool)
3056 *  \brief Changes brightness/contrast/colour/hue of a recording.
3057 *
3058 *  Note: In practice this only works with frame grabbing recorders.
3059 *
3060 *  \return current value [0,100] if it succeeds, -1 otherwise.
3061 */
3062int TVRec::ChangePictureAttribute(PictureAdjustType type,
3063                                  PictureAttribute  attr,
3064                                  bool              direction)
3065{
3066    QMutexLocker lock(&stateChangeLock);
3067    if (!channel)
3068        return -1;
3069
3070    int ret = channel->ChangePictureAttribute(type, attr, direction);
3071
3072    return (ret < 0) ? -1 : ret / 655;
3073}
3074
3075/** \fn TVRec::GetFreeInputs(const vector<uint>&) const
3076 *  \brief Returns the recorder's available inputs.
3077 *
3078 *   This filters out the connected inputs that belong to an input
3079 *   group which is busy. Recorders in the excluded cardids will
3080 *   not be considered busy for the sake of determining free inputs.
3081 *
3082 */
3083vector<InputInfo> TVRec::GetFreeInputs(
3084    const vector<uint> &excluded_cardids) const
3085{
3086    vector<InputInfo> list;
3087    if (channel)
3088        list = channel->GetFreeInputs(excluded_cardids);
3089    return list;
3090}
3091
3092/** \fn TVRec::GetInput(void) const
3093 *  \brief Returns current input.
3094 */
3095QString TVRec::GetInput(void) const
3096{
3097    if (channel)
3098        return channel->GetCurrentInput();
3099    return QString::null;
3100}
3101
3102/** \fn TVRec::SetInput(QString, uint)
3103 *  \brief Changes to the specified input.
3104 *
3105 *   You must call PauseRecorder(void) before calling this.
3106 *
3107 *  \param input Input to switch to, or "SwitchToNextInput".
3108 *  \return input we have switched to
3109 */
3110QString TVRec::SetInput(QString input, uint requestType)
3111{
3112    QMutexLocker lock(&stateChangeLock);
3113    QString origIn = input;
3114    VERBOSE(VB_RECORD, LOC + "SetInput("<<input<<") -- begin");
3115
3116    if (!channel)
3117    {
3118        VERBOSE(VB_RECORD, LOC + "SetInput() -- end  no channel class");
3119        return QString::null;
3120    }
3121
3122    input = (input == "SwitchToNextInput") ? channel->GetNextInput() : input;
3123
3124    if (input == channel->GetCurrentInput())
3125    {
3126        VERBOSE(VB_RECORD, LOC + "SetInput("<<origIn<<":"<<input
3127                <<") -- end  nothing to do");
3128        return input;
3129    }
3130
3131    QString name = channel->GetNextInputStartChan();
3132
3133    // Detect tuning request type if needed
3134    if (requestType & kFlagDetect)
3135    {
3136        WaitForEventThreadSleep();
3137        requestType = lastTuningRequest.flags & (kFlagRec | kFlagNoRec);
3138    }
3139
3140    // Clear the RingBuffer reset flag, in case we wait for a reset below
3141    ClearFlags(kFlagRingBufferReady);
3142
3143    // Actually add the tuning request to the queue, and
3144    // then wait for it to start tuning
3145    tuningRequests.enqueue(TuningRequest(requestType, name, input));
3146    WaitForEventThreadSleep();
3147
3148    // If we are using a recorder, wait for a RingBuffer reset
3149    if (requestType & kFlagRec)
3150    {
3151        while (!HasFlags(kFlagRingBufferReady))
3152            WaitForEventThreadSleep();
3153    }
3154    VERBOSE(VB_RECORD, LOC + "SetInput("<<origIn<<":"<<input<<") -- end");
3155
3156    return GetInput();
3157}
3158
3159/** \fn TVRec::SetChannel(QString,uint)
3160 *  \brief Changes to a named channel on the current tuner.
3161 *
3162 *   You must call PauseRecorder() before calling this.
3163 *
3164 *  \param name channum of channel to change to
3165 *  \param requestType tells us what kind of request to actually send to
3166 *                     the tuning thread, kFlagDetect is usually sufficient
3167 */
3168void TVRec::SetChannel(QString name, uint requestType)
3169{
3170    QMutexLocker lock(&stateChangeLock);
3171    VERBOSE(VB_CHANNEL, LOC + QString("SetChannel(%1) -- begin").arg(name));
3172
3173    // Detect tuning request type if needed
3174    if (requestType & kFlagDetect)
3175    {
3176        WaitForEventThreadSleep();
3177        requestType = lastTuningRequest.flags & (kFlagRec | kFlagNoRec);
3178    }
3179
3180    // Clear the RingBuffer reset flag, in case we wait for a reset below
3181    ClearFlags(kFlagRingBufferReady);
3182
3183    // Actually add the tuning request to the queue, and
3184    // then wait for it to start tuning
3185    tuningRequests.enqueue(TuningRequest(requestType, name));
3186    WaitForEventThreadSleep();
3187
3188    // If we are using a recorder, wait for a RingBuffer reset
3189    if (requestType & kFlagRec)
3190    {
3191        while (!HasFlags(kFlagRingBufferReady))
3192            WaitForEventThreadSleep();
3193    }
3194    VERBOSE(VB_CHANNEL, LOC + QString("SetChannel(%1) -- end").arg(name));
3195}
3196
3197void TVRec::GetNextProgram(BrowseDirection direction,
3198                           QString &title,       QString &subtitle,
3199                           QString &desc,        QString &category,
3200                           QString &starttime,   QString &endtime,
3201                           QString &callsign,    QString &iconpath,
3202                           QString &channum,     uint    &sourceChanid,
3203                           QString &seriesid,    QString &programid)
3204{
3205    QString compare     = "<=";
3206    QString sortorder   = "desc";
3207    uint    chanid      = 0;
3208
3209    if (sourceChanid)
3210    {
3211        chanid = sourceChanid;
3212
3213        if (BROWSE_UP == direction)
3214            chanid = channel->GetNextChannel(chanid, CHANNEL_DIRECTION_UP);
3215        else if (BROWSE_DOWN == direction)
3216            chanid = channel->GetNextChannel(chanid, CHANNEL_DIRECTION_DOWN);
3217        else if (BROWSE_FAVORITE == direction)
3218            chanid = channel->GetNextChannel(
3219                chanid, CHANNEL_DIRECTION_FAVORITE);
3220
3221        else if (BROWSE_LEFT == direction)
3222        {
3223            compare = "<";
3224        }
3225        else if (BROWSE_RIGHT == direction)
3226        {
3227            compare = ">";
3228            sortorder = "asc";
3229        }
3230    }
3231
3232    if (!chanid)
3233    {
3234        if (BROWSE_SAME == direction)
3235            chanid = channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3236        else if (BROWSE_UP == direction)
3237            chanid = channel->GetNextChannel(channum, CHANNEL_DIRECTION_UP);
3238        else if (BROWSE_DOWN == direction)
3239            chanid = channel->GetNextChannel(channum, CHANNEL_DIRECTION_DOWN);
3240        else if (BROWSE_FAVORITE == direction)
3241            chanid = channel->GetNextChannel(channum,
3242                                             CHANNEL_DIRECTION_FAVORITE);
3243        else if (BROWSE_LEFT == direction)
3244        {
3245            chanid = channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3246            compare = "<";
3247        }
3248        else if (BROWSE_RIGHT == direction)
3249        {
3250            chanid = channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3251            compare = ">";
3252            sortorder = "asc";
3253        }
3254    }
3255
3256    QString querystr = QString(
3257        "SELECT title,     subtitle, description, category, "
3258        "       starttime, endtime,  callsign,    icon,     "
3259        "       channum,   seriesid, programid "
3260        "FROM program, channel "
3261        "WHERE program.chanid = channel.chanid AND "
3262        "      channel.chanid = :CHANID        AND "
3263        "      starttime %1 :STARTTIME "
3264        "ORDER BY starttime %2 "
3265        "LIMIT 1").arg(compare).arg(sortorder);
3266
3267    MSqlQuery query(MSqlQuery::InitCon());
3268    query.prepare(querystr);
3269    query.bindValue(":CHANID",    chanid);
3270    query.bindValue(":STARTTIME", starttime);
3271
3272    // Clear everything now in case either query fails.
3273    title     = subtitle  = desc      = category  = "";
3274    starttime = endtime   = callsign  = iconpath  = "";
3275    channum   = seriesid  = programid = "";
3276    sourceChanid = 0;
3277
3278    // Try to get the program info
3279    if (!query.exec() && !query.isActive())
3280    {
3281        MythDB::DBError("GetNextProgram -- get program info", query);
3282    }
3283    else if (query.next())
3284    {
3285        title     = query.value(0).toString();
3286        subtitle  = query.value(1).toString();
3287        desc      = query.value(2).toString();
3288        category  = query.value(3).toString();
3289        starttime = query.value(4).toString();
3290        endtime   = query.value(5).toString();
3291        callsign  = query.value(6).toString();
3292        iconpath  = query.value(7).toString();
3293        channum   = query.value(8).toString();
3294        seriesid  = query.value(9).toString();
3295        programid = query.value(10).toString();
3296        sourceChanid = chanid;
3297        return;
3298    }
3299
3300    // Couldn't get program info, so get the channel info instead
3301    query.prepare(
3302        "SELECT channum, callsign, icon "
3303        "FROM channel "
3304        "WHERE chanid = :CHANID");
3305    query.bindValue(":CHANID", chanid);
3306
3307    if (!query.exec() || !query.isActive())
3308    {
3309        MythDB::DBError("GetNextProgram -- get channel info", query);
3310    }
3311    else if (query.next())
3312    {
3313        sourceChanid = chanid;
3314        channum  = query.value(0).toString();
3315        callsign = query.value(1).toString();
3316        iconpath = query.value(2).toString();
3317    }
3318}
3319
3320bool TVRec::GetChannelInfo(uint &chanid, uint &sourceid,
3321                           QString &callsign, QString &channum,
3322                           QString &channame, QString &xmltvid) const
3323{
3324    callsign = "";
3325    channum  = "";
3326    channame = "";
3327    xmltvid  = "";
3328
3329    if ((!chanid || !sourceid) && !channel)
3330        return false;
3331
3332    if (!chanid)
3333        chanid = (uint) max(channel->GetChanID(), 0);
3334
3335    if (!sourceid)
3336        sourceid = channel->GetCurrentSourceID();
3337
3338    MSqlQuery query(MSqlQuery::InitCon());
3339    query.prepare(
3340        "SELECT callsign, channum, name, xmltvid "
3341        "FROM channel "
3342        "WHERE chanid = :CHANID");
3343    query.bindValue(":CHANID", chanid);
3344    if (!query.exec() || !query.isActive())
3345    {
3346        MythDB::DBError("GetChannelInfo", query);
3347        return false;
3348    }
3349
3350    if (!query.next())
3351        return false;
3352
3353    callsign = query.value(0).toString();
3354    channum  = query.value(1).toString();
3355    channame = query.value(2).toString();
3356    xmltvid  = query.value(3).toString();
3357
3358    return true;
3359}
3360
3361bool TVRec::SetChannelInfo(uint chanid, uint sourceid,
3362                           QString oldchannum,
3363                           QString callsign, QString channum,
3364                           QString channame, QString xmltvid)
3365{
3366    if (!chanid || !sourceid || channum.isEmpty())
3367        return false;
3368//LZ: 'swap' channels not only update
3369    MSqlQuery swapquery(MSqlQuery::InitCon());
3370    query.prepare(
3371        "UPDATE channel "
3372        "SET channum  = :OLDCHANNUM,  "
3373        "WHERE channum   = :CHANNUM AND "
3374        "      sourceid = :SOURCEID");
3375    swapquery.bindValue(":CHANNUM",  channum);
3376    swapquery.bindValue(":SOURCEID", channame);
3377    swapquery.bindValue(":OLDCHANNUM",  xmltvid);
3378   
3379
3380    MSqlQuery query(MSqlQuery::InitCon());
3381    query.prepare(
3382        "UPDATE channel "
3383        "SET callsign = :CALLSIGN, "
3384        "    channum  = :CHANNUM,  "
3385        "    name     = :CHANNAME, "
3386        "    xmltvid  = :XMLTVID   "
3387        "WHERE chanid   = :CHANID AND "
3388        "      sourceid = :SOURCEID");
3389    query.bindValue(":CALLSIGN", callsign);
3390    query.bindValue(":CHANNUM",  channum);
3391    query.bindValue(":CHANNAME", channame);
3392    query.bindValue(":XMLTVID",  xmltvid);
3393    query.bindValue(":CHANID",   chanid);
3394    query.bindValue(":SOURCEID", sourceid);
3395
3396    if (!query.exec() || !swapquery.exec())
3397    {
3398        MythDB::DBError("SetChannelInfo", query);
3399        return false;
3400    }
3401
3402    if (channel)
3403        channel->Renumber(sourceid, oldchannum, channum);
3404
3405    return true;
3406}
3407
3408/** \fn TVRec::SetRingBuffer(RingBuffer*)
3409 *  \brief Sets "ringBuffer", deleting any existing RingBuffer.
3410 */
3411void TVRec::SetRingBuffer(RingBuffer *rb)
3412{
3413    QMutexLocker lock(&stateChangeLock);
3414
3415    RingBuffer *rb_old = ringBuffer;
3416    ringBuffer = rb;
3417
3418    if (rb_old && (rb_old != rb))
3419    {
3420        if (HasFlags(kFlagDummyRecorderRunning))
3421            ClearFlags(kFlagDummyRecorderRunning);
3422        delete rb_old;
3423    }
3424
3425    m_switchingBuffer = false;
3426}
3427
3428void TVRec::RingBufferChanged(RingBuffer *rb, ProgramInfo *pginfo)
3429{
3430    VERBOSE(VB_IMPORTANT, LOC + "RingBufferChanged()");
3431
3432    if (pginfo)
3433    {
3434        if (curRecording)
3435        {
3436            FinishedRecording(curRecording);
3437            curRecording->MarkAsInUse(false, kRecorderInUseID);
3438            delete curRecording;
3439        }
3440        curRecording = new RecordingInfo(*pginfo);
3441        curRecording->MarkAsInUse(true, kRecorderInUseID);
3442    }
3443
3444    SetRingBuffer(rb);
3445}
3446
3447QString TVRec::TuningGetChanNum(const TuningRequest &request,
3448                                QString &input) const
3449{
3450    QString channum = QString::null;
3451
3452    if (request.program)
3453    {
3454        request.program->QueryTuningInfo(channum, input);
3455        return channum;
3456    }
3457
3458    channum = request.channel;
3459    input   = request.input;
3460
3461    // If this is Live TV startup, we need a channel...
3462    if (channum.isEmpty() && (request.flags & kFlagLiveTV))
3463    {
3464        if (!LiveTVStartChannel.isEmpty())
3465            channum = LiveTVStartChannel;
3466        else
3467        {
3468            input   = genOpt.defaultinput;
3469            channum = GetStartChannel(cardid, input);
3470        }
3471    }
3472    if (request.flags & kFlagLiveTV)
3473        channel->Init(input, channum, false);
3474
3475    if (channel && !channum.isEmpty() && (channum.indexOf("NextChannel") >= 0))
3476    {
3477        int dir     = channum.right(channum.length() - 12).toInt();
3478        uint chanid = channel->GetNextChannel(0, dir);
3479        channum     = ChannelUtil::GetChanNum(chanid);
3480    }
3481
3482    return channum;
3483}
3484
3485bool TVRec::TuningOnSameMultiplex(TuningRequest &request)
3486{
3487    if ((request.flags & kFlagAntennaAdjust) || request.input.isEmpty() ||
3488        !GetDTVRecorder() || signalMonitor || !channel || !channel->IsOpen())
3489    {
3490        return false;
3491    }
3492
3493    uint    sourceid   = channel->GetCurrentSourceID();
3494    QString oldchannum = channel->GetCurrentName();
3495    QString newchannum = request.channel;
3496
3497    if (ChannelUtil::IsOnSameMultiplex(sourceid, newchannum, oldchannum))
3498    {
3499        MPEGStreamData *mpeg = GetDTVRecorder()->GetStreamData();
3500        ATSCStreamData *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3501
3502        if (atsc)
3503        {
3504            uint major, minor = 0;
3505            ChannelUtil::GetATSCChannel(sourceid, newchannum, major, minor);
3506
3507            if (minor && atsc->HasChannel(major, minor))
3508            {
3509                request.majorChan = major;
3510                request.minorChan = minor;
3511                return true;
3512            }
3513        }
3514
3515        if (mpeg)
3516        {
3517            uint progNum = ChannelUtil::GetProgramNumber(sourceid, newchannum);
3518            if (mpeg->HasProgram(progNum))
3519            {
3520                request.progNum = progNum;
3521                return true;
3522            }
3523        }
3524    }
3525
3526    return false;
3527}
3528
3529/** \fn TVRec::HandleTuning(void)
3530 *  \brief Handles all tuning events.
3531 *
3532 *   This method pops tuning events off the tuningState queue
3533 *   and does what needs to be done, mostly by calling one of
3534 *   the Tuning... methods.
3535 */
3536void TVRec::HandleTuning(void)
3537{
3538    if (tuningRequests.size())
3539    {
3540        TuningRequest request = tuningRequests.front();
3541        VERBOSE(VB_RECORD, LOC + "HandleTuning Request: "<<request.toString());
3542
3543        QString input;
3544        request.channel = TuningGetChanNum(request, input);
3545        request.input   = input;
3546
3547        if (TuningOnSameMultiplex(request))
3548            VERBOSE(VB_PLAYBACK, LOC + "On same multiplex");
3549
3550        TuningShutdowns(request);
3551
3552        // The dequeue isn't safe to do until now because we
3553        // release the stateChangeLock to teardown a recorder
3554        tuningRequests.dequeue();
3555
3556        // Now we start new stuff
3557        if (request.flags & (kFlagRecording|kFlagLiveTV|
3558                             kFlagEITScan|kFlagAntennaAdjust))
3559        {
3560            if (!recorder)
3561            {
3562                VERBOSE(VB_RECORD, LOC +
3563                        "No recorder yet, calling TuningFrequency");
3564                TuningFrequency(request);
3565            }
3566            else
3567            {
3568                VERBOSE(VB_RECORD, LOC + "Waiting for recorder pause..");
3569                SetFlags(kFlagWaitingForRecPause);
3570            }
3571        }
3572        lastTuningRequest = request;
3573    }
3574
3575    if (HasFlags(kFlagWaitingForRecPause))
3576    {
3577        if (!recorder->IsPaused())
3578            return;
3579
3580        ClearFlags(kFlagWaitingForRecPause);
3581        VERBOSE(VB_RECORD, LOC + "Recorder paused, calling TuningFrequency");
3582        TuningFrequency(lastTuningRequest);
3583    }
3584
3585    MPEGStreamData *streamData = NULL;
3586    if (HasFlags(kFlagWaitingForSignal) && !(streamData = TuningSignalCheck()))
3587        return;
3588
3589    if (HasFlags(kFlagNeedToStartRecorder))
3590    {
3591        if (recorder)
3592            TuningRestartRecorder();
3593        else
3594            TuningNewRecorder(streamData);
3595
3596        // If we got this far it is safe to set a new starting channel...
3597        if (channel)
3598            channel->StoreInputChannels();
3599    }
3600}
3601
3602/** \fn TVRec::TuningCheckForHWChange(const TuningRequest&,QString&,QString&)
3603 *  \brief Returns cardid for device info row in capturecard if it changes.
3604 */
3605uint TVRec::TuningCheckForHWChange(const TuningRequest &request,
3606                                   QString &channum,
3607                                   QString &inputname)
3608{
3609    if (!channel)
3610        return 0;
3611
3612    uint curCardID = 0, newCardID = 0;
3613    channum   = request.channel;
3614    inputname = request.input;
3615
3616    if (request.program)
3617        request.program->QueryTuningInfo(channum, inputname);
3618
3619    if (!channum.isEmpty() && inputname.isEmpty())
3620        channel->CheckChannel(channum, inputname);
3621
3622    if (!inputname.isEmpty())
3623    {
3624        int current_input = channel->GetCurrentInputNum();
3625        int new_input     = channel->GetInputByName(inputname);
3626        curCardID = channel->GetInputCardID(current_input);
3627        newCardID = channel->GetInputCardID(new_input);
3628        VERBOSE(VB_IMPORTANT, LOC<<"HW Tuner: "<<curCardID<<"->"<<newCardID);
3629    }
3630
3631    if (curCardID != newCardID)
3632    {
3633        if (channum.isEmpty())
3634            channum = GetStartChannel(newCardID, inputname);
3635        return newCardID;
3636    }
3637
3638    return 0;
3639}
3640
3641/** \fn TVRec::TuningShutdowns(const TuningRequest&)
3642 *  \brief This shuts down anything that needs to be shut down
3643 *         before handling the passed in tuning request.
3644 */
3645void TVRec::TuningShutdowns(const TuningRequest &request)
3646{
3647    QString channum, inputname;
3648    uint newCardID = TuningCheckForHWChange(request, channum, inputname);
3649
3650    if (!(request.flags & kFlagEITScan) && HasFlags(kFlagEITScannerRunning))
3651    {
3652        scanner->StopActiveScan();
3653        ClearFlags(kFlagEITScannerRunning);
3654    }
3655
3656    if (scanner && !request.IsOnSameMultiplex())
3657        scanner->StopPassiveScan();
3658
3659    if (HasFlags(kFlagSignalMonitorRunning))
3660    {
3661        MPEGStreamData *sd = NULL;
3662        if (GetDTVSignalMonitor())
3663            sd = GetDTVSignalMonitor()->GetStreamData();
3664        TeardownSignalMonitor();
3665        ClearFlags(kFlagSignalMonitorRunning);
3666
3667        // Delete StreamData if it is not in use by the recorder.
3668        MPEGStreamData *rec_sd = NULL;
3669        if (GetDTVRecorder())
3670            rec_sd = GetDTVRecorder()->GetStreamData();
3671        if (sd && (sd != rec_sd))
3672            delete sd;
3673    }
3674    if (HasFlags(kFlagWaitingForSignal))
3675        ClearFlags(kFlagWaitingForSignal);
3676
3677    // At this point any waits are canceled.
3678
3679    if (newCardID || (request.flags & kFlagNoRec))
3680    {
3681        if (HasFlags(kFlagDummyRecorderRunning))
3682        {
3683            ClearFlags(kFlagDummyRecorderRunning);
3684            FinishedRecording(curRecording);
3685            curRecording->MarkAsInUse(false, kRecorderInUseID);
3686        }
3687
3688        if (request.flags & kFlagCloseRec)
3689            FinishedRecording(lastTuningRequest.program);
3690
3691        if (HasFlags(kFlagRecorderRunning) ||
3692            (curRecording && curRecording->GetRecordingStatus() == rsFailed))
3693        {
3694            stateChangeLock.unlock();
3695            TeardownRecorder(request.flags & kFlagKillRec);
3696            stateChangeLock.lock();
3697            ClearFlags(kFlagRecorderRunning);
3698        }
3699        // At this point the recorders are shut down
3700
3701        CloseChannel();
3702        // At this point the channel is shut down
3703    }
3704
3705    // handle HW change for digital/analog cards
3706    if (newCardID)
3707    {
3708        VERBOSE(VB_IMPORTANT, "Recreating channel...");
3709        channel->Close();
3710        delete channel;
3711        channel = NULL;
3712
3713        GetDevices(newCardID, genOpt, dvbOpt, fwOpt);
3714        genOpt.defaultinput = inputname;
3715        CreateChannel(channum);
3716        if (!(request.flags & kFlagNoRec))
3717            channel->Open();
3718    }
3719
3720    if (ringBuffer && (request.flags & kFlagKillRingBuffer))
3721    {
3722        VERBOSE(VB_RECORD, LOC + "Tearing down RingBuffer");
3723        SetRingBuffer(NULL);
3724        // At this point the ringbuffer is shut down
3725    }
3726
3727    // Clear pending actions from last request
3728    ClearFlags(kFlagPendingActions);
3729}
3730
3731/** \fn TVRec::TuningFrequency(const TuningRequest&)
3732 *  \brief Performs initial tuning required for any tuning event.
3733 *
3734 *   This figures out the channel name, and possibly the
3735 *   input name we need to pass to "channel" and then calls
3736 *   channel appropriately.
3737 *
3738 *   Then it adds any filters and sets any video capture attributes
3739 *   that need to be set.
3740 *
3741 *   The signal monitoring is started if possible. If it is started
3742 *   the kFlagWaitForSignal flag is set.
3743 *
3744 *   The kFlagNeedToStartRecorder flag is ald set if this isn't
3745 *   an EIT scan so that the recorder is started or restarted a
3746 *   appropriate.
3747 */
3748void TVRec::TuningFrequency(const TuningRequest &request)
3749{
3750    if (!channel)
3751    {
3752        VERBOSE(VB_IMPORTANT, LOC_ERR +
3753                "TuningFrequency called without a valid channel object");
3754        return;
3755    }
3756
3757    DTVChannel *dtvchan = GetDTVChannel();
3758    bool livetv = request.flags & kFlagLiveTV;
3759    bool antadj = request.flags & kFlagAntennaAdjust;
3760    bool has_dummy = false;
3761    bool ok = true;
3762
3763    if (dtvchan)
3764    {
3765        MPEGStreamData *mpeg = NULL;
3766
3767        if (GetDTVRecorder())
3768            mpeg = GetDTVRecorder()->GetStreamData();
3769
3770        const QString tuningmode = (HasFlags(kFlagEITScannerRunning)) ?
3771                                   dtvchan->GetSIStandard() :
3772                                   dtvchan->GetSuggestedTuningMode
3773                                   (kState_WatchingLiveTV == internalState);
3774
3775        dtvchan->SetTuningMode(tuningmode);
3776
3777        if (request.minorChan && (tuningmode == "atsc"))
3778        {
3779            channel->SelectChannel(request.channel, false);
3780            ATSCStreamData *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3781            if (atsc)
3782                atsc->SetDesiredChannel(request.majorChan, request.minorChan);
3783        }
3784        else if (request.progNum >= 0)
3785        {
3786            channel->SelectChannel(request.channel, false);
3787            if (mpeg)
3788                mpeg->SetDesiredProgram(request.progNum);
3789        }
3790    }
3791
3792    if (request.IsOnSameMultiplex())
3793    {
3794        QStringList slist;
3795        slist<<"message"<<QObject::tr("On known multiplex...");
3796        MythEvent me(QString("SIGNAL %1").arg(cardid), slist);
3797        gCoreContext->dispatch(me);
3798
3799        SetFlags(kFlagNeedToStartRecorder);
3800        return;
3801    }
3802
3803    QString input   = request.input;
3804    QString channum = request.channel;
3805
3806    channel->Open();
3807
3808    if (livetv || antadj)
3809    {
3810        // We need there to be a ringbuffer for these modes
3811        ProgramInfo *tmp = pseudoLiveTVRecording;
3812        pseudoLiveTVRecording = NULL;
3813
3814        tvchain->SetCardType("DUMMY");
3815
3816        if (!ringBuffer)
3817            ok = CreateLiveTVRingBuffer(channum);
3818        else
3819            ok = SwitchLiveTVRingBuffer(channum, true, false);
3820        pseudoLiveTVRecording = tmp;
3821
3822        tvchain->SetCardType(genOpt.cardtype);
3823
3824        if (!ok)
3825        {
3826            VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create RingBuffer 1");
3827            return;
3828        }
3829
3830        has_dummy = true;
3831    }
3832
3833    if (!channum.isEmpty())
3834    {
3835        if (!input.isEmpty())
3836            channel->SelectInput(input, channum, true);
3837        else
3838            channel->SelectChannel(channum, true);
3839    }
3840
3841    // Start signal (or channel change) monitoring
3842    VERBOSE(VB_RECORD, LOC + "Starting Signal Monitor");
3843    bool error = false;
3844    if (!SetupSignalMonitor(!antadj, request.flags & kFlagEITScan,
3845                            livetv | antadj))
3846    {
3847        VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to setup signal monitor");
3848        if (signalMonitor)
3849        {
3850            delete signalMonitor;
3851            signalMonitor = NULL;
3852        }
3853
3854        // pretend the signal monitor is running to prevent segfault
3855        SetFlags(kFlagSignalMonitorRunning);
3856        ClearFlags(kFlagWaitingForSignal);
3857        error = true;
3858    }
3859    else if (signalMonitor)
3860    {
3861        SetFlags(kFlagSignalMonitorRunning);
3862        ClearFlags(kFlagWaitingForSignal);
3863        if (!antadj)
3864            SetFlags(kFlagWaitingForSignal);
3865    }
3866
3867    if (has_dummy && ringBuffer)
3868    {
3869        // Make sure recorder doesn't point to bogus ringbuffer before
3870        // it is potentially restarted without a new ringbuffer, if
3871        // the next channel won't tune and the user exits LiveTV.
3872        if (recorder)
3873            recorder->SetRingBuffer(NULL);
3874
3875        SetFlags(kFlagDummyRecorderRunning);
3876        VERBOSE(VB_RECORD, "DummyDTVRecorder -- started");
3877        SetFlags(kFlagRingBufferReady);
3878    }
3879
3880    // if we had problems starting the signal monitor,
3881    // we don't want to start the recorder...
3882    if (error)
3883        return;
3884
3885    // Request a recorder, if the command is a recording command
3886    ClearFlags(kFlagNeedToStartRecorder);
3887    if (request.flags & kFlagRec && !antadj)
3888        SetFlags(kFlagNeedToStartRecorder);
3889}
3890
3891/** \fn TVRec::TuningSignalCheck(void)
3892 *  \brief This checks if we have a channel lock.
3893 *
3894 *   If we have a channel lock this shuts down the signal monitoring.
3895 *
3896 *  \return MPEGStreamData pointer if we have a complete lock, NULL otherwise
3897 */
3898MPEGStreamData *TVRec::TuningSignalCheck(void)
3899{
3900    if (signalMonitor->IsAllGood())
3901    {
3902        VERBOSE(VB_RECORD, LOC + "Got good signal");
3903
3904        pendingRecLock.lock();
3905        m_recStatus = rsRecording;
3906        pendingRecLock.unlock();
3907        if (curRecording)
3908            curRecording->SetRecordingStatus(rsRecording);
3909    }
3910    else if (signalMonitor->IsErrored())
3911    {
3912        VERBOSE(VB_RECORD, LOC_ERR + "SignalMonitor failed");
3913        ClearFlags(kFlagNeedToStartRecorder);
3914
3915        pendingRecLock.lock();
3916        m_recStatus = rsFailed;
3917        pendingRecLock.unlock();
3918        if (curRecording)
3919            curRecording->SetRecordingStatus(rsFailed);
3920
3921        if (HasFlags(kFlagEITScannerRunning))
3922        {
3923            scanner->StopActiveScan();
3924            ClearFlags(kFlagEITScannerRunning);
3925        }
3926    }
3927    else
3928        return NULL;
3929
3930    if (curRecording)
3931    {
3932        MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
3933                     .arg(curRecording->GetCardID())
3934                     .arg(curRecording->GetChanID())
3935                     .arg(curRecording->GetScheduledStartTime(ISODate))
3936                     .arg(curRecording->GetRecordingStatus())
3937                     .arg(curRecording->GetRecordingEndTime(ISODate)));
3938        gCoreContext->dispatch(me);
3939    }
3940
3941    // grab useful data from DTV signal monitor before we kill it...
3942    MPEGStreamData *streamData = NULL;
3943    if (GetDTVSignalMonitor())
3944        streamData = GetDTVSignalMonitor()->GetStreamData();
3945
3946    if (!HasFlags(kFlagEITScannerRunning))
3947    {
3948        // shut down signal monitoring
3949        TeardownSignalMonitor();
3950        ClearFlags(kFlagSignalMonitorRunning);
3951    }
3952    ClearFlags(kFlagWaitingForSignal);
3953
3954    if (streamData)
3955    {
3956        DVBStreamData *dsd = dynamic_cast<DVBStreamData*>(streamData);
3957        if (dsd)
3958            dsd->SetDishNetEIT(is_dishnet_eit(cardid));
3959        if (!get_use_eit(GetCaptureCardNum()))
3960        {
3961            VERBOSE(VB_EIT, LOC + "EIT scanning disabled "
3962                    "for all sources on this card.");
3963        }
3964        else if (scanner)
3965            scanner->StartPassiveScan(channel, streamData);
3966    }
3967
3968    return streamData;
3969}
3970
3971static int init_jobs(const RecordingInfo *rec, RecordingProfile &profile,
3972                      bool on_host, bool transcode_bfr_comm, bool on_line_comm)
3973{
3974    if (!rec)
3975        return 0; // no jobs for Live TV recordings..
3976
3977    int jobs = 0; // start with no jobs
3978
3979    // grab standard jobs flags from program info
3980    JobQueue::AddJobsToMask(rec->GetAutoRunJobs(), jobs);
3981
3982    // disable commercial flagging on PBS, BBC, etc.
3983    if (rec->IsCommercialFree())
3984        JobQueue::RemoveJobsFromMask(JOB_COMMFLAG, jobs);
3985
3986    // disable transcoding if the profile does not allow auto transcoding
3987    const Setting *autoTrans = profile.byName("autotranscode");
3988    if ((!autoTrans) || (autoTrans->getValue().toInt() == 0))
3989        JobQueue::RemoveJobsFromMask(JOB_TRANSCODE, jobs);
3990
3991    // is commercial flagging enabled, and is on-line comm flagging enabled?
3992    bool rt = JobQueue::JobIsInMask(JOB_COMMFLAG, jobs) && on_line_comm;
3993    // also, we either need transcoding to be disabled or
3994    // we need to be allowed to commercial flag before transcoding?
3995    rt &= JobQueue::JobIsNotInMask(JOB_TRANSCODE, jobs) ||
3996        !transcode_bfr_comm;
3997    if (rt)
3998    {
3999        // queue up real-time (i.e. on-line) commercial flagging.
4000        QString host = (on_host) ? gCoreContext->GetHostName() : "";
4001        JobQueue::QueueJob(JOB_COMMFLAG,
4002                           rec->GetChanID(),
4003                           rec->GetRecordingStartTime(), "", "",
4004                           host, JOB_LIVE_REC);
4005
4006        // don't do regular comm flagging, we won't need it.
4007        JobQueue::RemoveJobsFromMask(JOB_COMMFLAG, jobs);
4008    }
4009
4010    return jobs;
4011}
4012
4013static QString load_profile(QString cardtype, void *tvchain,
4014                            RecordingInfo *rec, RecordingProfile &profile)
4015{
4016    // Determine the correct recording profile.
4017    // In LiveTV mode use "Live TV" profile, otherwise use the
4018    // recording's specified profile. If the desired profile can't
4019    // be found, fall back to the "Default" profile for card type.
4020    QString profileName = "Live TV";
4021    if (!tvchain && rec)
4022        profileName = rec->GetRecordingRule()->m_recProfile;
4023
4024    if (!profile.loadByType(profileName, cardtype))
4025    {
4026        profileName = "Default";
4027        profile.loadByType(profileName, cardtype);
4028    }
4029
4030    VERBOSE(VB_RECORD, QString("Using profile '%1' to record")
4031            .arg(profileName));
4032
4033    return profileName;
4034}
4035
4036/** \fn TVRec::TuningNewRecorder(MPEGStreamData*)
4037 *  \brief Creates a recorder instance.
4038 */
4039void TVRec::TuningNewRecorder(MPEGStreamData *streamData)
4040{
4041    VERBOSE(VB_RECORD, LOC + "Starting Recorder");
4042
4043    bool had_dummyrec = false;
4044    if (HasFlags(kFlagDummyRecorderRunning))
4045    {
4046        ClearFlags(kFlagDummyRecorderRunning);
4047        FinishedRecording(curRecording);
4048        curRecording->MarkAsInUse(false, kRecorderInUseID);
4049        had_dummyrec = true;
4050    }
4051
4052    RecordingInfo *rec = lastTuningRequest.program;
4053
4054    RecordingProfile profile;
4055    QString profileName = load_profile(genOpt.cardtype, tvchain, rec, profile);
4056
4057    if (tvchain)
4058    {
4059        bool ok;
4060        if (!ringBuffer)
4061        {
4062            ok = CreateLiveTVRingBuffer(channel->GetCurrentName());
4063            SetFlags(kFlagRingBufferReady);
4064        }
4065        else
4066            ok = SwitchLiveTVRingBuffer(channel->GetCurrentName(),
4067                                        true, !had_dummyrec && recorder);
4068        if (!ok)
4069        {
4070            VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create RingBuffer 2");
4071            goto err_ret;
4072        }
4073        rec = curRecording;  // new'd in Create/SwitchLiveTVRingBuffer()
4074    }
4075
4076    if (lastTuningRequest.flags & kFlagRecording)
4077    {
4078        bool write = genOpt.cardtype != "IMPORT";
4079        VERBOSE(VB_IMPORTANT, LOC + QString("rec->GetPathname(): '%1'")
4080                .arg(rec->GetPathname()));
4081        SetRingBuffer(RingBuffer::Create(rec->GetPathname(), write));
4082        if (!ringBuffer->IsOpen() && write)
4083        {
4084            VERBOSE(VB_IMPORTANT, LOC_ERR +
4085                    QString("RingBuffer '%1' not open...")
4086                    .arg(rec->GetPathname()));
4087            SetRingBuffer(NULL);
4088            ClearFlags(kFlagPendingActions);
4089            goto err_ret;
4090        }
4091    }
4092
4093    if (!ringBuffer)
4094    {
4095        VERBOSE(VB_IMPORTANT, LOC_ERR + QString(
4096                    "Failed to start recorder!  ringBuffer is NULL\n"
4097                    "\t\t\t\t  Tuning request was %1\n")
4098                .arg(lastTuningRequest.toString()));
4099
4100        if (HasFlags(kFlagLiveTV))
4101        {
4102            QString message = QString("QUIT_LIVETV %1").arg(cardid);
4103            MythEvent me(message);
4104            gCoreContext->dispatch(me);
4105        }
4106        goto err_ret;
4107    }
4108
4109    if (channel && genOpt.cardtype == "MJPEG")
4110        channel->Close(); // Needed because of NVR::MJPEGInit()
4111
4112    if (!SetupRecorder(profile))
4113    {
4114        VERBOSE(VB_IMPORTANT, LOC_ERR + QString(
4115                    "Failed to start recorder!\n"
4116                    "\t\t\t\t  Tuning request was %1\n")
4117                .arg(lastTuningRequest.toString()));
4118
4119        if (HasFlags(kFlagLiveTV))
4120        {
4121            QString message = QString("QUIT_LIVETV %1").arg(cardid);
4122            MythEvent me(message);
4123            gCoreContext->dispatch(me);
4124        }
4125        TeardownRecorder(true);
4126        goto err_ret;
4127    }
4128
4129    if (GetDTVRecorder() && streamData)
4130    {
4131        const Setting *setting = profile.byName("recordingtype");
4132        if (setting)
4133            streamData->SetRecordingType(setting->getValue());
4134        GetDTVRecorder()->SetStreamData(streamData);
4135    }
4136
4137    if (channel && genOpt.cardtype == "MJPEG")
4138        channel->Open(); // Needed because of NVR::MJPEGInit()
4139
4140    if (rec)
4141        recorder->SetRecording(rec);
4142
4143    // Setup for framebuffer capture devices..
4144    if (channel)
4145    {
4146        SetVideoFiltersForChannel(channel->GetCurrentSourceID(),
4147                                  channel->GetCurrentName());
4148    }
4149
4150#ifdef USING_V4L
4151    if (GetV4LChannel())
4152    {
4153        channel->InitPictureAttributes();
4154        CloseChannel();
4155    }
4156#endif
4157
4158    RecorderThread.SetParent(this);
4159    RecorderThread.start();
4160
4161    // Wait for recorder to start.
4162    stateChangeLock.unlock();
4163    while (!recorder->IsRecording() && !recorder->IsErrored())
4164        usleep(5 * 1000);
4165    stateChangeLock.lock();
4166
4167    if (GetV4LChannel())
4168        channel->SetFd(recorder->GetVideoFd());
4169
4170    SetFlags(kFlagRecorderRunning | kFlagRingBufferReady);
4171
4172    if (!tvchain)
4173        autoRunJobs = init_jobs(rec, profile, runJobOnHostOnly,
4174                                transcodeFirst, earlyCommFlag);
4175
4176    ClearFlags(kFlagNeedToStartRecorder);
4177    return;
4178
4179  err_ret:
4180    ChangeState(kState_None);
4181    if (tvchain)
4182        delete rec;
4183}
4184
4185/** \fn TVRec::TuningRestartRecorder(void)
4186 *  \brief Restarts a stopped recorder or unpauses a paused recorder.
4187 */
4188void TVRec::TuningRestartRecorder(void)
4189{
4190    VERBOSE(VB_RECORD, LOC + "Restarting Recorder");
4191
4192    bool had_dummyrec = false;
4193    if (HasFlags(kFlagDummyRecorderRunning))
4194    {
4195        ClearFlags(kFlagDummyRecorderRunning);
4196        had_dummyrec = true;
4197    }
4198
4199    if (curRecording)
4200    {
4201        FinishedRecording(curRecording);
4202        curRecording->MarkAsInUse(false, kRecorderInUseID);
4203
4204        if (pseudoLiveTVRecording)
4205        {
4206            int secsSince = curRecording->GetRecordingStartTime()
4207                .secsTo(QDateTime::currentDateTime());
4208            if (secsSince < 120)
4209            {
4210                JobQueue::RemoveJobsFromMask(JOB_COMMFLAG, autoRunJobs);
4211                JobQueue::RemoveJobsFromMask(JOB_TRANSCODE, autoRunJobs);
4212            }
4213
4214            if (autoRunJobs)
4215                JobQueue::QueueRecordingJobs(*curRecording, autoRunJobs);
4216        }
4217    }
4218
4219    SwitchLiveTVRingBuffer(channel->GetCurrentName(), true, !had_dummyrec);
4220
4221    if (had_dummyrec)
4222    {
4223        recorder->SetRingBuffer(ringBuffer);
4224        ProgramInfo *progInfo = tvchain->GetProgramAt(-1);
4225        recorder->SetRecording(progInfo);
4226        delete progInfo;
4227    }
4228    recorder->Reset();
4229
4230    // Set file descriptor of channel from recorder for V4L
4231    channel->SetFd(recorder->GetVideoFd());
4232
4233    // Some recorders unpause on Reset, others do not...
4234    recorder->Unpause();
4235
4236    if (pseudoLiveTVRecording)
4237    {
4238        ProgramInfo *rcinfo1 = pseudoLiveTVRecording;
4239        QString msg1 = QString("Recording: %1 %2 %3 %4")
4240            .arg(rcinfo1->GetTitle()).arg(rcinfo1->GetChanID())
4241            .arg(rcinfo1->GetRecordingStartTime(ISODate))
4242            .arg(rcinfo1->GetRecordingEndTime(ISODate));
4243        ProgramInfo *rcinfo2 = tvchain->GetProgramAt(-1);
4244        QString msg2 = QString("Recording: %1 %2 %3 %4")
4245            .arg(rcinfo2->GetTitle()).arg(rcinfo2->GetChanID())
4246            .arg(rcinfo2->GetRecordingStartTime(ISODate))
4247            .arg(rcinfo2->GetRecordingEndTime(ISODate));
4248        delete rcinfo2;
4249        VERBOSE(VB_RECORD, LOC + "Pseudo LiveTV recording starting." +
4250                "\n\t\t\t" + msg1 + "\n\t\t\t" + msg2);
4251
4252        curRecording->SaveAutoExpire(
4253            curRecording->GetRecordingRule()->GetAutoExpire());
4254
4255        curRecording->ApplyRecordRecGroupChange(
4256            curRecording->GetRecordingRule()->m_recGroup);
4257
4258        RecordingProfile profile;
4259        QString profileName = load_profile(genOpt.cardtype, NULL,
4260                                           curRecording, profile);
4261        autoRunJobs = init_jobs(curRecording, profile, runJobOnHostOnly,
4262                                transcodeFirst, earlyCommFlag);
4263    }
4264
4265    ClearFlags(kFlagNeedToStartRecorder);
4266}
4267
4268void TVRec::SetFlags(uint f)
4269{
4270    QMutexLocker lock(&stateChangeLock);
4271    stateFlags |= f;
4272    VERBOSE(VB_RECORD, LOC + QString("SetFlags(%1) -> %2")
4273            .arg(FlagToString(f)).arg(FlagToString(stateFlags)));
4274    WakeEventLoop();
4275}
4276
4277void TVRec::ClearFlags(uint f)
4278{
4279    QMutexLocker lock(&stateChangeLock);
4280    stateFlags &= ~f;
4281    VERBOSE(VB_RECORD, LOC + QString("ClearFlags(%1) -> %2")
4282            .arg(FlagToString(f)).arg(FlagToString(stateFlags)));
4283    WakeEventLoop();
4284}
4285
4286QString TVRec::FlagToString(uint f)
4287{
4288    QString msg("");
4289
4290    // General flags
4291    if (kFlagFrontendReady & f)
4292        msg += "FrontendReady,";
4293    if (kFlagRunMainLoop & f)
4294        msg += "RunMainLoop,";
4295    if (kFlagExitPlayer & f)
4296        msg += "ExitPlayer,";
4297    if (kFlagFinishRecording & f)
4298        msg += "FinishRecording,";
4299    if (kFlagErrored & f)
4300        msg += "Errored,";
4301    if (kFlagCancelNextRecording & f)
4302        msg += "CancelNextRecording,";
4303
4304    // Tuning flags
4305    if ((kFlagRec & f) == kFlagRec)
4306        msg += "REC,";
4307    else
4308    {
4309        if (kFlagLiveTV & f)
4310            msg += "LiveTV,";
4311        if (kFlagRecording & f)
4312            msg += "Recording,";
4313    }
4314    if ((kFlagNoRec & f) == kFlagNoRec)
4315        msg += "NOREC,";
4316    else
4317    {
4318        if (kFlagEITScan & f)
4319            msg += "EITScan,";
4320        if (kFlagCloseRec & f)
4321            msg += "CloseRec,";
4322        if (kFlagKillRec & f)
4323            msg += "KillRec,";
4324        if (kFlagAntennaAdjust & f)
4325            msg += "AntennaAdjust,";
4326    }
4327    if ((kFlagPendingActions & f) == kFlagPendingActions)
4328        msg += "PENDINGACTIONS,";
4329    else
4330    {
4331        if (kFlagWaitingForRecPause & f)
4332            msg += "WaitingForRecPause,";
4333        if (kFlagWaitingForSignal & f)
4334            msg += "WaitingForSignal,";
4335        if (kFlagNeedToStartRecorder & f)
4336            msg += "NeedToStartRecorder,";
4337        if (kFlagKillRingBuffer & f)
4338            msg += "KillRingBuffer,";
4339    }
4340    if ((kFlagAnyRunning & f) == kFlagAnyRunning)
4341        msg += "ANYRUNNING,";
4342    else
4343    {
4344        if (kFlagSignalMonitorRunning & f)
4345            msg += "SignalMonitorRunning,";
4346        if (kFlagEITScannerRunning & f)
4347            msg += "EITScannerRunning,";
4348        if ((kFlagAnyRecRunning & f) == kFlagAnyRecRunning)
4349            msg += "ANYRECRUNNING,";
4350        else
4351        {
4352            if (kFlagDummyRecorderRunning & f)
4353                msg += "DummyRecorderRunning,";
4354            if (kFlagRecorderRunning & f)
4355                msg += "RecorderRunning,";
4356        }
4357    }
4358    if (kFlagRingBufferReady & f)
4359        msg += "RingBufferReady,";
4360
4361    if (msg.isEmpty())
4362        msg = QString("0x%1").arg(f,0,16);
4363
4364    return msg;
4365}
4366
4367bool TVRec::WaitForNextLiveTVDir(void)
4368{
4369    QMutexLocker lock(&nextLiveTVDirLock);
4370
4371    bool found = !nextLiveTVDir.isEmpty();
4372    if (!found && triggerLiveTVDir.wait(&nextLiveTVDirLock, 500))
4373    {
4374        found = !nextLiveTVDir.isEmpty();
4375    }
4376
4377    return found;
4378}
4379
4380void TVRec::SetNextLiveTVDir(QString dir)
4381{
4382    QMutexLocker lock(&nextLiveTVDirLock);
4383
4384    nextLiveTVDir = dir;
4385    triggerLiveTVDir.wakeAll();
4386}
4387
4388bool TVRec::GetProgramRingBufferForLiveTV(RecordingInfo **pginfo,
4389                                          RingBuffer **rb,
4390                                          const QString & channum,
4391                                          int inputID)
4392{
4393    VERBOSE(VB_RECORD, LOC + "GetProgramRingBufferForLiveTV()");
4394    if (!channel || !tvchain || !pginfo || !rb)
4395        return false;
4396
4397    nextLiveTVDirLock.lock();
4398    nextLiveTVDir.clear();
4399    nextLiveTVDirLock.unlock();
4400
4401    // Dispatch this early, the response can take a while.
4402    MythEvent me(QString("QUERY_NEXT_LIVETV_DIR %1").arg(cardid));
4403    gCoreContext->dispatch(me);
4404
4405    uint    sourceid = channel->GetSourceID(inputID);
4406    int     chanid   = ChannelUtil::GetChanID(sourceid, channum);
4407
4408    if (chanid < 0)
4409    {
4410        // Test setups might have zero channels
4411        if (genOpt.cardtype == "IMPORT" || genOpt.cardtype == "DEMO")
4412            chanid = 9999;
4413        else
4414        {
4415            VERBOSE(VB_IMPORTANT, (LOC_ERR +
4416                "Channel: \'%1\' was not found in the database.\n"
4417                "\t\t\tMost likely, your DefaultTVChannel setting is wrong.\n"
4418                "\t\t\tCould not start livetv.").arg(channum));
4419            return false;
4420        }
4421    }
4422
4423    int hoursMax = gCoreContext->GetNumSetting("MaxHoursPerLiveTVRecording", 8);
4424    if (hoursMax <= 0)
4425        hoursMax = 8;
4426
4427    RecordingInfo *prog = NULL;
4428    if (pseudoLiveTVRecording)
4429        prog = new RecordingInfo(*pseudoLiveTVRecording);
4430    else
4431    {
4432        prog = new RecordingInfo(
4433            chanid, mythCurrentDateTime(), true, hoursMax);
4434    }
4435
4436    prog->SetCardID(cardid);
4437
4438    if (prog->GetRecordingStartTime() == prog->GetRecordingEndTime())
4439    {
4440        VERBOSE(VB_IMPORTANT, LOC_ERR + "GetProgramRingBufferForLiveTV()"
4441                "\n\t\t\tProgramInfo is invalid."
4442                "\n" + prog->toString());
4443        prog->SetScheduledEndTime(prog->GetRecordingStartTime().addSecs(3600));
4444        prog->SetRecordingEndTime(prog->GetScheduledEndTime());
4445
4446        prog->SetChanID(chanid);
4447    }
4448
4449    if (!pseudoLiveTVRecording)
4450        prog->SetRecordingStartTime(mythCurrentDateTime());
4451
4452    prog->SetStorageGroup("LiveTV");
4453
4454    if (WaitForNextLiveTVDir())
4455    {
4456        QMutexLocker lock(&nextLiveTVDirLock);
4457        prog->SetPathname(nextLiveTVDir);
4458    }
4459    else
4460    {
4461        StorageGroup sgroup("LiveTV", gCoreContext->GetHostName());
4462        prog->SetPathname(sgroup.FindNextDirMostFree());
4463    }
4464
4465    StartedRecording(prog);
4466
4467    *rb = RingBuffer::Create(prog->GetPathname(), true);
4468    if (!(*rb)->IsOpen())
4469    {
4470        VERBOSE(VB_IMPORTANT, LOC_ERR +
4471                QString("RingBuffer '%1' not open...")
4472                .arg(prog->GetPathname()));
4473
4474        delete *rb;
4475        delete prog;
4476
4477        return false;
4478    }
4479
4480    *pginfo = prog;
4481    return true;
4482}
4483
4484bool TVRec::CreateLiveTVRingBuffer(const QString & channum)
4485{
4486    VERBOSE(VB_RECORD, LOC + QString("CreateLiveTVRingBuffer(%1)")
4487            .arg(channum));
4488
4489    RecordingInfo *pginfo = NULL;
4490    RingBuffer    *rb = NULL;
4491    QString        inputName;
4492    int            inputID = -1;
4493
4494    if (!channel->CheckChannel(channum, inputName))
4495    {
4496        ChangeState(kState_None);
4497        return false;
4498    }
4499
4500    inputID = inputName.isEmpty() ?
4501      channel->GetCurrentInputNum() : channel->GetInputByName(inputName);
4502
4503    if (!GetProgramRingBufferForLiveTV(&pginfo, &rb, channum, inputID))
4504    {
4505        ClearFlags(kFlagPendingActions);
4506        ChangeState(kState_None);
4507        VERBOSE(VB_IMPORTANT, LOC_ERR +
4508                QString("CreateLiveTVRingBuffer(%1) failed").arg(channum));
4509        return false;
4510    }
4511
4512    SetRingBuffer(rb);
4513
4514    pginfo->SaveAutoExpire(kLiveTVAutoExpire);
4515    pginfo->ApplyRecordRecGroupChange("LiveTV");
4516
4517    bool discont = (tvchain->TotalSize() > 0);
4518    tvchain->AppendNewProgram(pginfo, channel->GetCurrentName(),
4519                              channel->GetCurrentInput(), discont);
4520
4521    if (curRecording)
4522    {
4523        curRecording->MarkAsInUse(false, kRecorderInUseID);
4524        delete curRecording;
4525    }
4526
4527    curRecording = pginfo;
4528    curRecording->MarkAsInUse(true, kRecorderInUseID);
4529
4530    return true;
4531}
4532
4533bool TVRec::SwitchLiveTVRingBuffer(const QString & channum,
4534                                   bool discont, bool set_rec)
4535{
4536    VERBOSE(VB_RECORD, LOC + "SwitchLiveTVRingBuffer(discont "
4537            <<discont<<", set_rec "<<set_rec<<")");
4538
4539    RecordingInfo *pginfo = NULL;
4540    RingBuffer    *rb = NULL;
4541    QString        inputName;
4542    int            inputID = -1;
4543
4544    if (!channel->CheckChannel(channum, inputName))
4545    {
4546        ChangeState(kState_None);
4547        return false;
4548    }
4549
4550    inputID = inputName.isEmpty() ?
4551      channel->GetCurrentInputNum() : channel->GetInputByName(inputName);
4552
4553    if (!GetProgramRingBufferForLiveTV(&pginfo, &rb, channum, inputID))
4554    {
4555        ChangeState(kState_None);
4556        return false;
4557    }
4558
4559    ProgramInfo *pi = tvchain->GetProgramAt(-1);
4560    if (pi)
4561    {
4562        RecordingInfo *oldinfo = new RecordingInfo(*pi);
4563        delete pi;
4564        FinishedRecording(oldinfo);
4565        if (tvchain->GetCardType(-1) != "DUMMY")
4566        {
4567            if (!oldinfo->IsLocal())
4568                oldinfo->SetPathname(oldinfo->GetPlaybackURL(false,true));
4569            if (oldinfo->IsLocal())
4570                PreviewGeneratorQueue::GetPreviewImage(*oldinfo, "");
4571        }
4572        delete oldinfo;
4573    }
4574
4575    pginfo->MarkAsInUse(true, kRecorderInUseID);
4576    pginfo->SaveAutoExpire(kLiveTVAutoExpire);
4577    pginfo->ApplyRecordRecGroupChange("LiveTV");
4578    tvchain->AppendNewProgram(pginfo, channel->GetCurrentName(),
4579                              channel->GetCurrentInput(), discont);
4580
4581    if (set_rec && recorder)
4582    {
4583        recorder->SetNextRecording(pginfo, rb);
4584        if (discont)
4585            recorder->CheckForRingBufferSwitch();
4586        delete pginfo;
4587        SetFlags(kFlagRingBufferReady);
4588    }
4589    else if (!set_rec)
4590    {
4591        if (curRecording)
4592        {
4593            curRecording->MarkAsInUse(false, kRecorderInUseID);
4594            delete curRecording;
4595        }
4596        curRecording = pginfo;
4597        SetRingBuffer(rb);
4598    }
4599
4600    return true;
4601}
4602
4603TVRec* TVRec::GetTVRec(uint cardid)
4604{
4605    QMutexLocker locker(&cardsLock);
4606    QMap<uint,TVRec*>::const_iterator it = cards.find(cardid);
4607    if (it == cards.end())
4608        return NULL;
4609    return *it;
4610}
4611
4612QString TuningRequest::toString(void) const
4613{
4614    return QString("Program(%1) channel(%2) input(%3) flags(%4)")
4615        .arg((program != 0) ? "yes" : "no").arg(channel).arg(input)
4616        .arg(TVRec::FlagToString(flags));
4617}
4618
4619/* vim: set expandtab tabstop=4 shiftwidth=4: */
4620