Ticket #866: 866-v1.patch

File 866-v1.patch, 36.6 KB (added by danielk, 14 years ago)

Fixes several LiveTV+Recording bugs

  • libs/libmythtv/osd.h

     
    7777    void SetSettingsText(const QString &text, int length);
    7878
    7979    void NewDialogBox(const QString &name, const QString &message,
    80                       QStringList &options, int length);
     80                      QStringList &options, int length, int sel = 0);
    8181    void DialogUp(const QString &name);
    8282    void DialogDown(const QString &name);
    8383    bool DialogShowing(const QString &name);
  • libs/libmythtv/tv_play.cpp

     
    246246      // Program Info for currently playing video
    247247      recorderPlaybackInfo(NULL),
    248248      playbackinfo(NULL), inputFilename(""), playbackLen(0),
     249      lastProgram(NULL), jumpToProgram(false),
    249250      // Video Players
    250251      nvp(NULL), pipnvp(NULL), activenvp(NULL),
    251252      // Remote Encoders
     
    262263      // Window info (GUI is optional, transcoding, preview img, etc)
    263264      myWindow(NULL), embedWinID(0), embedBounds(0,0,0,0)
    264265{
     266    for (uint i = 0; i < 2; i++)
     267    {
     268        pseudoLiveTVRec[i]   = NULL;
     269        pseudoLiveTVState[i] = kPseudoNormalLiveTV;
     270    }
     271
    265272    lastLcdUpdate = QDateTime::currentDateTime();
    266273    lastLcdUpdate.addYears(-1); // make last LCD update last year..
    267274    lastSignalMsgTime.start();
     
    335342            float wmult, hmult;
    336343            gContext->GetScreenSettings(xbase, width, wmult,
    337344                                        ybase, height, hmult);
    338             if (abs(saved_gui_bounds.x()-xbase < 3) &&
    339                 abs(saved_gui_bounds.y()-ybase < 3))
     345            if ((abs(saved_gui_bounds.x()-xbase) < 3) &&
     346                (abs(saved_gui_bounds.y()-ybase) < 3))
    340347            {
    341                 saved_gui_bounds.setX(xbase);
    342                 saved_gui_bounds.setY(ybase);
     348                saved_gui_bounds = QRect(QPoint(xbase, ybase),
     349                                         mainWindow->size());
    343350            }
    344351        }
    345352
     
    574581    activerecorder->FinishRecording();
    575582}
    576583
    577 void TV::AskAllowRecording(const QStringList &messages, int timeuntil)
     584void TV::AskAllowRecording(const QStringList &messages, int timeuntil,
     585                           bool hasrec)
    578586{
    579587    if (!StateIsLiveTV(GetState()))
    580588       return;
     
    605613    options += tr("Record and watch while it records");
    606614    options += tr("Let it record and go back to the Main Menu");
    607615    options += tr("Don't let it record, I want to watch TV");
     616    int sel = (hasrec) ? 2 : 0;
    608617
    609618    dialogname = "allowrecordingbox";
    610     GetOSD()->NewDialogBox(dialogname, message, options, timeuntil);
     619    GetOSD()->NewDialogBox(dialogname, message, options, timeuntil, sel);
    611620}
    612621
    613622void TV::setLastProgram(ProgramInfo *rcinfo)
     
    14891498            exitPlayer = false;
    14901499        }
    14911500
     1501        for (uint i = InStateChange() ? 2 : 0; i < 2; i++)
     1502        {
     1503            if (kPseudoChangeChannel != pseudoLiveTVState[i])
     1504                continue;
     1505
     1506            VERBOSE(VB_PLAYBACK, "REC_PROGRAM -- channel change "<<i);
     1507            if (activerecorder != recorder)
     1508                ToggleActiveWindow();
     1509
     1510            uint    chanid  = pseudoLiveTVRec[i]->chanid.toUInt();
     1511            QString channum = pseudoLiveTVRec[i]->chanstr;
     1512            str_vec_t tmp = prevChan;
     1513            prevChan.clear();
     1514            if (i && activenvp == nvp)
     1515                ToggleActiveWindow();
     1516            ChangeChannel(chanid, channum);
     1517            prevChan = tmp;
     1518            pseudoLiveTVState[i] = kPseudoRecording;
     1519
     1520            if (i && pipnvp)
     1521                TogglePIPView();
     1522        }
     1523
    14921524        if ((doing_ff_rew || speed_index) &&
    14931525            activenvp && activenvp->AtNormalSpeed())
    14941526        {
     
    18481880                else if (dialogname == "allowrecordingbox")
    18491881                {
    18501882                    int result = GetOSD()->GetDialogResponse(dialogname);
    1851    
    1852                     if (result == 2)
     1883
     1884                    if (result == 1)
     1885                        recorder->CancelNextRecording(false);
     1886                    else if (result == 2)
    18531887                        StopLiveTV();
    18541888                    else if (result == 3)
    1855                         recorder->CancelNextRecording();
     1889                        recorder->CancelNextRecording(true);
    18561890                }
    18571891                else if (dialogname == "channel_timed_out")
    18581892                {
     
    22122246            }
    22132247            else if (StateIsLiveTV(GetState()))
    22142248            {
    2215                 ChangeState(kState_None);
    22162249                exitPlayer = true;
    22172250                wantsToQuit = true;
    22182251            }
     
    22922325        }
    22932326    }
    22942327
    2295     if (StateIsLiveTV(GetState()))
     2328    if (StateIsLiveTV(GetState()) || StateIsPlaying(internalState))
    22962329    {
    22972330        for (unsigned int i = 0; i < actions.size() && !handled; i++)
    22982331        {
     
    23062339                else
    23072340                    ToggleOSD(true);
    23082341            }
    2309             else if (action == "CHANNELUP")
    2310             {
    2311                 if (persistentbrowsemode)
    2312                     BrowseDispInfo(BROWSE_UP);
    2313                 else
    2314                     ChangeChannel(CHANNEL_DIRECTION_UP);
    2315             }
    2316             else if (action == "CHANNELDOWN")
    2317             {
    2318                 if (persistentbrowsemode)
    2319                     BrowseDispInfo(BROWSE_DOWN);
    2320                 else
    2321                     ChangeChannel(CHANNEL_DIRECTION_DOWN);
    2322             }
    2323             else if (action == "TOGGLERECORD")
     2342            else if (action == "TOGGLESLEEP")
     2343                ToggleSleepTimer();
     2344            else
     2345                handled = false;
     2346        }
     2347    }
     2348
     2349    uint aindx = (activenvp == nvp) ? 0 : 1;
     2350    if (StateIsLiveTV(GetState()))
     2351    {
     2352        for (unsigned int i = 0; i < actions.size() && !handled; i++)
     2353        {
     2354            QString action = actions[i];
     2355            handled = true;
     2356
     2357            if (action == "TOGGLERECORD")
    23242358                ToggleRecord();
    2325             else if (action == "NEXTFAV")
    2326                 ChangeChannel(CHANNEL_DIRECTION_FAVORITE);
    23272359            else if (action == "TOGGLEFAV")
    23282360                ToggleChannelFavorite();
     2361            else if (action == "SELECT")
     2362                CommitQueuedInput();
     2363            else if (action == "TOGGLERECCONTROLS")
     2364                DoToggleRecPictureAttribute();
     2365            else if (action == "TOGGLEBROWSE" && pseudoLiveTVState[aindx])
     2366                ShowOSDTreeMenu();
     2367            else
     2368                handled = false;
     2369        }
     2370
     2371        if (redisplayBrowseInfo)
     2372            BrowseStart();
     2373    }
     2374
     2375    if (StateIsLiveTV(GetState()) && !pseudoLiveTVState[aindx])
     2376    {
     2377        for (unsigned int i = 0; i < actions.size() && !handled; i++)
     2378        {
     2379            QString action = actions[i];
     2380            handled = true;
     2381
     2382            if (action == "NEXTFAV")
     2383                ChangeChannel(CHANNEL_DIRECTION_FAVORITE);
    23292384            else if (action == "TOGGLEINPUTS")
    23302385                ToggleInputs();
    23312386            else if (action == "SWITCHCARDS")
    23322387                SwitchCards();
    2333             else if (action == "SELECT")
    2334                 CommitQueuedInput();
    23352388            else if (action == "GUIDE")
    23362389                LoadMenu();
    23372390            else if (action == "TOGGLEPIPMODE")
     
    23402393                ToggleActiveWindow();
    23412394            else if (action == "SWAPPIP")
    23422395                SwapPIP();
    2343             else if (action == "TOGGLERECCONTROLS")
    2344                 DoToggleRecPictureAttribute();
    23452396            else if (action == "TOGGLEBROWSE")
    23462397                BrowseStart();
    23472398            else if (action == "PREVCHAN")
    23482399                PreviousChannel();
    2349             else if (action == "TOGGLESLEEP")
    2350                 ToggleSleepTimer();
     2400            else if (action == "CHANNELUP")
     2401            {
     2402                if (persistentbrowsemode)
     2403                    BrowseDispInfo(BROWSE_UP);
     2404                else
     2405                    ChangeChannel(CHANNEL_DIRECTION_UP);
     2406            }
     2407            else if (action == "CHANNELDOWN")
     2408            {
     2409                if (persistentbrowsemode)
     2410                    BrowseDispInfo(BROWSE_DOWN);
     2411                else
     2412                    ChangeChannel(CHANNEL_DIRECTION_DOWN);
     2413            }
    23512414            else
    23522415                handled = false;
    23532416        }
     
    23622425            QString action = actions[i];
    23632426            handled = true;
    23642427
    2365             if (action == "INFO")
     2428            if (action == "SELECT")
    23662429            {
    2367                 if (HasQueuedInput())
    2368                     DoArbSeek(ARBSEEK_SET);
    2369                 else
    2370                     ToggleOSD(true);
    2371             }
    2372             else if (action == "SELECT")
    2373             {
    23742430                if (!was_doing_ff_rew)
    23752431                {
    23762432                    if (gContext->GetNumSetting("AltClearSavedPosition", 1)
     
    24222478                    DoSeek(jumptime * 60, tr("Jump Ahead"));
    24232479                }
    24242480            }
    2425             else if (action == "TOGGLESLEEP")
    2426                 ToggleSleepTimer();
    24272481            else
    24282482                handled = false;
    24292483        }
     
    24852539            else
    24862540            {
    24872541                VERBOSE(VB_IMPORTANT, LOC_ERR + "PiP player failed to start");
     2542                delete pipnvp;
     2543                pipnvp = NULL;
    24882544                TeardownPipPlayer();
    24892545            }
    24902546        }
     
    25132569        piprecorder->StopLiveTV();
    25142570
    25152571        TeardownPipPlayer();
     2572
     2573        SetPseudoLiveTV(1, NULL, kPseudoNormalLiveTV);
    25162574    }
    25172575}
    25182576
     
    33133371        if (HasQueuedInput())
    33143372            DoArbSeek(ARBSEEK_FORWARD);
    33153373    }
    3316     else if (StateIsLiveTV(GetState()))
     3374    else if (StateIsLiveTV(GetState()) &&
     3375             !pseudoLiveTVState[(activenvp == nvp) ? 0 : 1])
    33173376    {
    33183377        QString channum = GetQueuedChanNum();
    33193378        if (browsemode)
     
    33223381            if (activenvp == nvp && GetOSD())
    33233382                GetOSD()->HideSet("channel_number");
    33243383        }
    3325         else if (activerecorder->CheckChannel(channum))
     3384        else if (GetQueuedChanID() ||
     3385                 (!channum.isEmpty() && activerecorder->CheckChannel(channum)))
    33263386            ChangeChannel(GetQueuedChanID(), channum);
    3327         else if (GetQueuedInput() != "")
     3387        else if (!GetQueuedInput().isEmpty())
    33283388            ChangeChannel(GetQueuedChanID(), GetQueuedInput());
    33293389    }
    33303390
     
    43684428            QStringList tokens = QStringList::split(" ", message);
    43694429            int cardnum = tokens[1].toInt();
    43704430            int timeuntil = tokens[2].toInt();
     4431            int hasrec    = tokens[3].toInt();
     4432            VERBOSE(VB_IMPORTANT, LOC + message << " hasrec: "<<hasrec);
    43714433
    43724434            if (cardnum == recorder->GetRecorderNumber())
    43734435            {
    43744436                menurunning = false;
    4375                 AskAllowRecording(me->ExtraDataList(), timeuntil);
     4437                AskAllowRecording(me->ExtraDataList(), timeuntil, hasrec);
    43764438            }
     4439            else if (piprecorder &&
     4440                     cardnum == piprecorder->GetRecorderNumber())
     4441            {
     4442                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for recording");
     4443                TogglePIPView();
     4444            }
    43774445        }
    43784446        else if (recorder && message.left(11) == "QUIT_LIVETV")
    43794447        {
     
    43874455                wantsToQuit = false;
    43884456                exitPlayer = true;
    43894457            }
     4458            else if (piprecorder &&
     4459                     cardnum == piprecorder->GetRecorderNumber())
     4460            {
     4461                VERBOSE(VB_GENERAL, LOC + "Disabling PiP for QUIT_LIVETV");
     4462                TogglePIPView();
     4463            }
    43904464        }
     4465        else if (recorder && message.left(12) == "LIVETV_WATCH")
     4466        {
     4467            message = message.simplifyWhiteSpace();
     4468            QStringList tokens = QStringList::split(" ", message);
     4469            int cardnum = tokens[1].toInt();
     4470            int watch   = tokens[2].toInt();
     4471
     4472            uint s = (cardnum == recorder->GetRecorderNumber()) ? 0 : 1;
     4473
     4474            if (cardnum == recorder->GetRecorderNumber() ||
     4475                (piprecorder && cardnum == piprecorder->GetRecorderNumber()))
     4476            {
     4477                if (watch)
     4478                {
     4479                    ProgramInfo *pi = new ProgramInfo();
     4480                    QStringList list = me->ExtraDataList();
     4481                    if (pi->FromStringList(list, 0))
     4482                        SetPseudoLiveTV(s, pi, kPseudoChangeChannel);
     4483                    delete pi;
     4484
     4485                    if (!s && pipnvp)
     4486                        TogglePIPView();
     4487                }
     4488                else
     4489                    SetPseudoLiveTV(s, NULL, kPseudoNormalLiveTV);
     4490            }
     4491        }
    43914492        else if (tvchain && message.left(12) == "LIVETV_CHAIN")
    43924493        {
    43934494            message = message.simplifyWhiteSpace();
     
    45754676    delete program_info;
    45764677}
    45774678
     4679void TV::SetPseudoLiveTV(uint i, const ProgramInfo *pi, PseudoState new_state)
     4680{
     4681    ProgramInfo *old_rec = pseudoLiveTVRec[i];
     4682    ProgramInfo *new_rec = NULL;
     4683
     4684    if (pi)
     4685    {
     4686        new_rec = new ProgramInfo(*pi);
     4687        QString msg = QString("Wants to record: %1 %2 %3 %4")
     4688            .arg(new_rec->title).arg(new_rec->chanstr)
     4689            .arg(new_rec->recstartts.toString())
     4690            .arg(new_rec->recendts.toString());
     4691        VERBOSE(VB_PLAYBACK, LOC + msg);
     4692    }
     4693
     4694    pseudoLiveTVRec[i]   = new_rec;
     4695    pseudoLiveTVState[i] = new_state;
     4696
     4697    if (old_rec)
     4698    {
     4699        QString msg = QString("Done to recording: %1 %2 %3 %4")
     4700            .arg(old_rec->title).arg(old_rec->chanstr)
     4701            .arg(old_rec->recstartts.toString())
     4702            .arg(old_rec->recendts.toString());
     4703        VERBOSE(VB_PLAYBACK, LOC + msg);       
     4704        delete old_rec;
     4705    }
     4706}
     4707
    45784708void TV::ToggleRecord(void)
    45794709{
    45804710    if (browsemode)
     
    46094739    }
    46104740
    46114741    QString cmdmsg("");
     4742    uint s = (activenvp == nvp) ? 0 : 1;
    46124743    if (playbackinfo->GetAutoExpireFromRecorded() == kLiveTVAutoExpire)
    46134744    {
    46144745        int autoexpiredef = gContext->GetNumSetting("AutoExpireDefault", 0);
    46154746        playbackinfo->SetAutoExpire(autoexpiredef);
    46164747        playbackinfo->ApplyRecordRecGroupChange("Default");
    46174748        cmdmsg = tr("Record");
     4749        SetPseudoLiveTV(s, playbackinfo, kPseudoRecording);
     4750        VERBOSE(VB_RECORD, LOC + "Toggling Record on");
    46184751    }
    46194752    else
    46204753    {
    46214754        playbackinfo->SetAutoExpire(kLiveTVAutoExpire);
    46224755        playbackinfo->ApplyRecordRecGroupChange("LiveTV");
    46234756        cmdmsg = tr("Cancel Record");
     4757        SetPseudoLiveTV(s, playbackinfo, kPseudoNormalLiveTV);
     4758        VERBOSE(VB_RECORD, LOC + "Toggling Record off");
    46244759    }
    46254760
    46264761    QString msg = cmdmsg + "\"" + playbackinfo->title + "\"";
  • libs/libmythtv/remoteencoder.h

     
    3636    void PauseRecorder(void);
    3737    void FinishRecording(void);
    3838    void FrontendReady(void);
    39     void CancelNextRecording(void);
     39    void CancelNextRecording(bool cancel);
    4040
    4141    void ToggleInputs(void);
    4242    int ChangeContrast(bool direction);
  • libs/libmythtv/tv_play.h

     
    5353    }
    5454};
    5555
     56typedef enum
     57{
     58    kPseudoNormalLiveTV  = 0,
     59    kPseudoChangeChannel = 1,
     60    kPseudoRecording     = 2,
     61} PseudoState;
     62
    5663class TV : public QObject
    5764{
    5865    Q_OBJECT
     
    97104    // Various commands
    98105    void ShowNoRecorderDialog(void);
    99106    void FinishRecording(void);
    100     void AskAllowRecording(const QStringList &messages, int timeuntil);
     107    void AskAllowRecording(const QStringList&, int, bool);
    101108
    102109    // Boolean queries
    103110
     
    302309
    303310    void GetPlayGroupSettings(const QString &group);
    304311
     312    void SetPseudoLiveTV(uint, const ProgramInfo*, PseudoState);
     313
    305314    static QStringList GetValidRecorderList(uint chanid);
    306315    static QStringList GetValidRecorderList(const QString &channum);
    307316    static QStringList GetValidRecorderList(uint, const QString&);
     
    442451    ProgramInfo *lastProgram;   ///< last program played with this player
    443452    bool         jumpToProgram;
    444453
     454    // Recording to play next, after LiveTV
     455    ProgramInfo *pseudoLiveTVRec[2];
     456    PseudoState  pseudoLiveTVState[2];
     457
    445458    // Video Players
    446459    NuppelVideoPlayer *nvp;
    447460    NuppelVideoPlayer *pipnvp;
  • libs/libmythtv/remoteencoder.cpp

     
    227227    }
    228228}
    229229
    230 void RemoteEncoder::CancelNextRecording(void)
     230void RemoteEncoder::CancelNextRecording(bool cancel)
    231231{
    232232    QStringList strlist = QString("QUERY_RECORDER %1").arg(recordernum);
    233233    strlist << "CANCEL_NEXT_RECORDING";
    234     VERBOSE(VB_IMPORTANT, QString("Sending QUERY_RECORDER %1 - CANCEL_NEXT_RECORDING")
    235                           .arg(recordernum));
     234    strlist << QString::number((cancel) ? 1 : 0);
    236235                         
    237236    SendReceiveStringList(strlist);
    238237}
  • libs/libmythtv/tv_rec.cpp

     
    120120      curRecording(NULL), autoRunJobs(JOB_NONE),
    121121      // Pending recording info
    122122      pendingRecording(NULL),
     123      // Pseudo LiveTV recording
     124      pseudoLiveTVRecording(NULL),
    123125      // tvchain
    124126      tvchain(NULL),
    125127      // RingBuffer info
     
    348350    SetFlags(kFlagAskAllowRecording);
    349351}
    350352
     353/** \fn TVRec::SetPseudoLiveTVRecording(ProgramInfo*)
     354 *  \brief Sets the pseudo LiveTV ProgramInfo
     355 */
     356void TVRec::SetPseudoLiveTVRecording(ProgramInfo *pi)
     357{
     358    ProgramInfo *old_rec = pseudoLiveTVRecording;
     359    pseudoLiveTVRecording = pi;
     360    if (old_rec)
     361        delete old_rec;
     362}
     363
     364/** \fn TVRec::GetRecordEndTime(const ProgramInfo*) const
     365 *  \brief Returns recording end time with proper post-roll
     366 */
     367QDateTime TVRec::GetRecordEndTime(const ProgramInfo *pi) const
     368{
     369    bool spcat = (pi->category == overRecordCategory);
     370    int secs = (spcat) ? overRecordSecCat : overRecordSecNrml;
     371    return pi->recendts.addSecs(secs);
     372}
     373
     374/** \fn TVRec::CancelNextRecording(bool)
     375 *  \brief Tells TVRec to cancel the upcoming recording.
     376 *  \sa RecordPending(const ProgramInfo*,int),
     377 *      TV::AskAllowRecording(const QStringList&,int)
     378 */
     379void TVRec::CancelNextRecording(bool cancel)
     380{
     381    if (cancel)
     382        SetFlags(kFlagCancelNextRecording);
     383    else
     384        ClearFlags(kFlagCancelNextRecording);
     385}
     386
    351387/** \fn TVRec::StartRecording(const ProgramInfo*)
    352388 *  \brief Tells TVRec to Start recording the program "rcinfo"
    353389 *         as soon as possible.
     
    409445    WaitForEventThreadSleep();
    410446
    411447    // If in post-roll, end recording
    412     if (GetState() == kState_RecordingOnly)
     448    if (GetState() == kState_RecordingOnly &&
     449        !HasFlags(kFlagCancelNextRecording))
    413450    {
    414451        stateChangeLock.unlock();
    415452        StopRecording();
    416453        stateChangeLock.lock();
    417454    }
    418455
    419     // Request tuner from Live TV instance
    420     if (internalState == kState_WatchingLiveTV &&
    421         !HasFlags(kFlagCancelNextRecording))
    422     {
    423         QString message = QString("QUIT_LIVETV %1").arg(cardid);
    424         MythEvent me(message);
    425         gContext->dispatch(me);
    426 
    427         MythTimer timer;
    428         timer.start();
    429 
    430         // Wait at least 10 seconds for response
    431         while ((internalState != kState_None) && timer.elapsed() < 10000)
    432             WaitForEventThreadSleep(false, max(10000 - timer.elapsed(), 100));
    433 
    434         // Try again
    435         if (internalState != kState_None)
    436         {
    437             gContext->dispatch(me);
    438 
    439             timer.restart();
    440             // Wait at least 10 seconds for response
    441             while ((internalState != kState_None) && timer.elapsed() < 10000)
    442                 WaitForEventThreadSleep(
    443                     false, max(10000 - timer.elapsed(), 100));
    444         }
    445 
    446         // Try harder
    447         if (internalState != kState_None)
    448         {
    449             SetFlags(kFlagExitPlayer);
    450             WaitForEventThreadSleep();
    451         }
    452     }
    453 
    454456    if (internalState == kState_None)
    455457    {
    456458        if (tvchain)
     
    461463            tvchain = NULL;
    462464        }
    463465
    464         // Add post-roll to new recording end time.
    465         bool spcat = (rcinfo->category == overRecordCategory);
    466         int secs = (spcat) ? overRecordSecCat : overRecordSecNrml;
    467         recordEndTime = rcinfo->recendts.addSecs(secs);
     466        recordEndTime = GetRecordEndTime(rcinfo);
    468467
    469468        // Tell event loop to begin recording.
    470469        curRecording = new ProgramInfo(*rcinfo);
     
    475474
    476475        retval = rsRecording;
    477476    }
     477    else if (!HasFlags(kFlagCancelNextRecording) &&
     478             (GetState() == kState_WatchingLiveTV))
     479    {
     480        SetPseudoLiveTVRecording(new ProgramInfo(*rcinfo));
     481        recordEndTime = GetRecordEndTime(rcinfo);
     482
     483        // We want the frontend to to change channel for recording
     484        // and disable the UI for channel change, PiP, etc.
     485
     486        QString message = QString("LIVETV_WATCH %1 1").arg(cardid);
     487        QStringList prog;
     488        rcinfo->ToStringList(prog);
     489        MythEvent me(message, prog);
     490        gContext->dispatch(me);
     491
     492        retval = rsRecording;
     493    }
    478494    else if (!HasFlags(kFlagCancelNextRecording))
    479495    {
    480496        msg = QString("Wanted to record: %1 %2 %3 %4\n"
     
    493509        retval = rsTunerBusy;
    494510    }
    495511
    496     ClearFlags(kFlagCancelNextRecording);
    497 
    498512    WaitForEventThreadSleep();
    499513
    500514    return retval;
     
    512526        ChangeState(RemoveRecording(GetState()));
    513527        // wait for state change to take effect
    514528        WaitForEventThreadSleep();
     529        ClearFlags(kFlagCancelNextRecording);
    515530    }
    516531}
    517532
     
    675690        tuningRequests.enqueue(TuningRequest(kFlagKillRec|kFlagKillRingBuffer));
    676691        SET_NEXT();
    677692    }
     693    else if (TRANSITION(kState_WatchingLiveTV, kState_RecordingOnly))
     694    {
     695        SetPseudoLiveTVRecording(NULL);
     696
     697        SET_NEXT();
     698    }
    678699    else if (TRANSITION(kState_None, kState_RecordingOnly))
    679700    {
    680701        tuningRequests.enqueue(TuningRequest(kFlagRecording, curRecording));
     
    11351156
    11361157        // If we have a pending recording and AskAllowRecording is set
    11371158        // and the frontend is ready send an ASK_RECORDING query to frontend.
    1138         if (pendingRecording &&
    1139             HasFlags(kFlagAskAllowRecording | kFlagFrontendReady))
     1159        if (pendingRecording && HasFlags(kFlagAskAllowRecording))
    11401160        {
    11411161            ClearFlags(kFlagAskAllowRecording);
    11421162
    1143             int timeuntil = QDateTime::currentDateTime()
    1144                 .secsTo(recordPendingStart);
     1163            CheckForRecGroupChange();
     1164            if (pseudoLiveTVRecording)
     1165                SetFlags(kFlagCancelNextRecording);
    11451166
    1146             QString query = QString("ASK_RECORDING %1 %2")
    1147                 .arg(cardid).arg(timeuntil);
    1148             QStringList messages;
    1149             messages << pendingRecording->title
    1150                      << pendingRecording->chanstr
    1151                      << pendingRecording->chansign
    1152                      << pendingRecording->channame;
    1153            
    1154             MythEvent me(query, messages);
     1167            if (GetState() == kState_WatchingLiveTV)
     1168            {
     1169                int timeuntil = QDateTime::currentDateTime()
     1170                    .secsTo(recordPendingStart);
    11551171
    1156             gContext->dispatch(me);
     1172                QString query = QString("ASK_RECORDING %1 %2 %3")
     1173                    .arg(cardid).arg(timeuntil)
     1174                    .arg(pseudoLiveTVRecording ? 1 : 0);
     1175                VERBOSE(VB_IMPORTANT, LOC + query);
     1176                QStringList messages;
     1177                messages << pendingRecording->title
     1178                         << pendingRecording->chanstr
     1179                         << pendingRecording->chansign
     1180                         << pendingRecording->channame;
     1181                MythEvent me(query, messages);
     1182                gContext->dispatch(me);
     1183            }
    11571184        }
    11581185
    11591186        // If we are recording a program, check if the recording is
     
    11691196        if (curRecording)
    11701197            curRecording->UpdateInUseMark();
    11711198
    1172         if (GetState() == kState_WatchingLiveTV && curRecording &&
    1173             !pendingRecording)
     1199        if (GetState() == kState_WatchingLiveTV)
    11741200        {
    1175             if (QDateTime::currentDateTime() >= curRecording->endts) // change to curRecording->recstartts.addSecs(60) for testing
    1176                 SwitchLiveTVRingBuffer();
     1201            bool enable_livetv_ui = false;
     1202            if (pseudoLiveTVRecording &&
     1203                (QDateTime::currentDateTime() > recordEndTime ||
     1204                 HasFlags(kFlagFinishRecording)))
     1205            {
     1206                SetPseudoLiveTVRecording(NULL);
     1207                enable_livetv_ui = true;
     1208            }
     1209            else if (curRecording &&
     1210                     !pseudoLiveTVRecording && !pendingRecording)
     1211            {
     1212//#define TESTING_RING_BUFFER_SWITCHING
     1213#ifdef TESTING_RING_BUFFER_SWITCHING
     1214                if ((QDateTime::currentDateTime() >=
     1215                     curRecording->recstartts.addSecs(60)))
     1216#else
     1217                if ((QDateTime::currentDateTime() >= curRecording->endts))
     1218#endif
     1219                {
     1220                    SwitchLiveTVRingBuffer();
     1221                    enable_livetv_ui = true;
     1222                }
     1223            }
     1224            if (enable_livetv_ui)
     1225            {
     1226                VERBOSE(VB_IMPORTANT, LOC + "Enabling Full LiveTV UI.");
     1227                QString message = QString("LIVETV_WATCH %1 0").arg(cardid);
     1228                MythEvent me(message);
     1229                gContext->dispatch(me);
     1230            }   
    11771231        }
    11781232
    11791233        // Check for ExitPlayer flag, and if set change to a non-watching
     
    24592513    return "";
    24602514}
    24612515
    2462 /** \fn TVRec::StopLiveTV()
     2516/** \fn TVRec::CheckForRecGroupChange(void)
     2517 *  \brief Check if frontend changed the recording group.
     2518 *
     2519 *   This is needed because the frontend may toggle whether something
     2520 *   should be kept as a recording in the frontend, but this class may
     2521 *   not find out about it in time unless we check the DB when this
     2522 *   information is important.
     2523 */
     2524void TVRec::CheckForRecGroupChange(void)
     2525{
     2526    QMutexLocker lock(&stateChangeLock);
     2527
     2528    if (internalState == kState_None)
     2529        return; // already stopped
     2530
     2531    ProgramInfo *pi = NULL;
     2532    if (curRecording)
     2533    {
     2534        pi = ProgramInfo::GetProgramFromRecorded(
     2535            curRecording->chanid, curRecording->recstartts);
     2536    }
     2537
     2538    if (pi && pi->recgroup != "LiveTV" && !pseudoLiveTVRecording)
     2539    {
     2540        // User wants this recording to continue
     2541        SetPseudoLiveTVRecording(pi);
     2542        pi = NULL;
     2543    }
     2544    else if (pi->recgroup == "LiveTV" && pseudoLiveTVRecording)
     2545    {
     2546        // User wants to abandon scheduled recording
     2547        SetPseudoLiveTVRecording(NULL);
     2548    }
     2549
     2550    if (pi)
     2551        delete pi;
     2552}
     2553
     2554/** \fn TVRec::StopLiveTV(void)
    24632555 *  \brief Tells TVRec to stop a "Live TV" recorder.
    24642556 *  \sa EncoderLink::StopLiveTV(), RemoteEncoder::StopLiveTV()
    24652557 */
    24662558void TVRec::StopLiveTV(void)
    24672559{
    2468     if (GetState() != kState_None)
     2560    QMutexLocker lock(&stateChangeLock);
     2561    VERBOSE(VB_RECORD, "StopLiveTV(void) curRec: "<<curRecording
     2562            <<" pseudoRec: "<<pseudoLiveTVRecording);
     2563
     2564    if (internalState == kState_None)
     2565        return; // already stopped
     2566
     2567    CheckForRecGroupChange();
     2568
     2569    // Figure out next state and if needed recording end time.
     2570    TVState next_state = kState_None;
     2571    bool has_cancel = true;
     2572    if (pseudoLiveTVRecording)
    24692573    {
    2470         QMutexLocker lock(&stateChangeLock);
    2471         ChangeState(kState_None);
    2472         // Wait for state change to take effect...
    2473         WaitForEventThreadSleep();
     2574        recordEndTime = GetRecordEndTime(pseudoLiveTVRecording);
     2575        next_state = kState_RecordingOnly;
     2576        has_cancel = HasFlags(kFlagCancelNextRecording);
     2577    }
    24742578
    2475         tvchain = NULL;
    2476     }
     2579    // Change to the appropriate state
     2580    ChangeState(next_state);
     2581
     2582    // Wait for state change to take effect...
     2583    WaitForEventThreadSleep();
     2584
     2585    if (has_cancel)
     2586        SetFlags(kFlagCancelNextRecording);
     2587
     2588    // We are done with the tvchain...
     2589    tvchain = NULL;
    24772590}
    24782591
    24792592/** \fn TVRec::PauseRecorder(void)
     
    30693182    {
    30703183        // We need there to be a ringbuffer for these modes
    30713184        bool ok;
     3185        ProgramInfo *tmp = pseudoLiveTVRecording;
     3186        pseudoLiveTVRecording = NULL;
    30723187        if (!ringBuffer)
    30733188            ok = CreateLiveTVRingBuffer();
    30743189        else
    30753190            ok = SwitchLiveTVRingBuffer(true, false);
     3191        pseudoLiveTVRecording = tmp;
    30763192        if (!ok)
    30773193        {
    30783194            VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to create RingBuffer 1");
     
    34503566    // Some recorders unpause on Reset, others do not...
    34513567    recorder->Unpause();
    34523568
     3569    if (pseudoLiveTVRecording)
     3570    {
     3571        ProgramInfo *rcinfo1 = pseudoLiveTVRecording;
     3572        QString msg1 = QString("Recording: %1 %2 %3 %4")
     3573            .arg(rcinfo1->title).arg(rcinfo1->chanid)
     3574            .arg(rcinfo1->recstartts.toString())
     3575            .arg(rcinfo1->recendts.toString());
     3576        ProgramInfo *rcinfo2 = tvchain->GetProgramAt(-1);
     3577        QString msg2 = QString("Recording: %1 %2 %3 %4")
     3578            .arg(rcinfo2->title).arg(rcinfo2->chanid)
     3579            .arg(rcinfo2->recstartts.toString())
     3580            .arg(rcinfo2->recendts.toString());
     3581        delete rcinfo2;
     3582        VERBOSE(VB_RECORD, LOC + "Pseudo LiveTV recording starting." +
     3583                "\n\t\t\t" + msg1 + "\n\t\t\t" + msg2);
     3584
     3585        int autoexpiredef = gContext->GetNumSetting("AutoExpireDefault", 0);
     3586        curRecording->SetAutoExpire(autoexpiredef);
     3587        curRecording->ApplyRecordRecGroupChange("Default");
     3588    }
     3589
    34533590    ClearFlags(kFlagNeedToStartRecorder);
    34543591}
    34553592
     
    35783715    }
    35793716
    35803717    QString chanids = QString::number(chanid);
    3581     ProgramInfo *prog = ProgramInfo::GetProgramAtDateTime(chanids,
    3582                                                   mythCurrentDateTime(),
    3583                                                   true);
    35843718
     3719    ProgramInfo *prog = NULL;
     3720    if (pseudoLiveTVRecording)
     3721        prog = new ProgramInfo(*pseudoLiveTVRecording);
     3722    else
     3723        prog = ProgramInfo::GetProgramAtDateTime(
     3724            chanids, mythCurrentDateTime(), true);
     3725
    35853726    if (prog->recstartts == prog->recendts)
    35863727    {
    35873728        VERBOSE(VB_IMPORTANT, LOC_ERR + "GetProgramRingBufferForLiveTV()"
  • libs/libmythtv/osd.cpp

     
    16761676}
    16771677
    16781678void OSD::NewDialogBox(const QString &name, const QString &message,
    1679                        QStringList &options, int length)
     1679                       QStringList &options, int length,
     1680                       int initial_selection)
    16801681{
    16811682    osdlock.lock();
    16821683    OSDSet *container = GetSet(name);
     
    17161717    while (text);
    17171718
    17181719    int numoptions = options.size();
     1720    int offset = availoptions - numoptions;
     1721    initial_selection = max(min(numoptions - 1, initial_selection), 0);
    17191722
    17201723    for (int i = 1; i <= numoptions && i <= availoptions; i++)
    17211724    {
    1722         QString name = QString("option%1").arg(availoptions - numoptions + i);
     1725        QString name = QString("option%1").arg(offset + i);
    17231726        text = (OSDTypeText *)container->GetType(name);
    17241727        if (!text)
    17251728        {
     
    17401743        return;
    17411744    }
    17421745
    1743     opr->SetOffset(availoptions - numoptions);
    1744     opr->SetPosition(0);
     1746    opr->SetOffset(offset);
     1747    opr->SetPosition(initial_selection);
    17451748
    17461749    dialogResponseList[name] = 0;
    17471750
    1748     HighlightDialogSelection(container, availoptions - numoptions);
     1751    HighlightDialogSelection(container, offset + initial_selection);
    17491752
    17501753    if (length > 0)
    17511754        container->DisplayFor(length * 1000000);
  • libs/libmythtv/tv_rec.h

     
    144144    void FinishRecording(void)  { SetFlags(kFlagFinishRecording); }
    145145    /// \brief Tells TVRec that the frontend's TV class is ready for messages.
    146146    void FrontendReady(void)    { SetFlags(kFlagFrontendReady); }
    147     /** \brief Tells TVRec to cancel the upcoming recording.
    148      *  \sa RecordPending(const ProgramInfo*,int),
    149      *      TV::AskAllowRecording(const QStringList&,int) */
    150     void CancelNextRecording(void) { SetFlags(kFlagCancelNextRecording); }
     147    void CancelNextRecording(bool cancel);
    151148    ProgramInfo *GetRecording(void);
    152149
    153150    /// \brief Returns true if event loop has not been told to shut down
     
    234231
    235232  private:
    236233    void SetRingBuffer(RingBuffer *);
     234    void SetPseudoLiveTVRecording(ProgramInfo*);
    237235    void TeardownAll(void);
    238236
    239237    static bool GetDevices(int cardid,
     
    290288
    291289    void StartedRecording(ProgramInfo*);
    292290    void FinishedRecording(ProgramInfo*);
     291    QDateTime GetRecordEndTime(const ProgramInfo*) const;
     292    void CheckForRecGroupChange(void);
    293293
    294294    void SetOption(RecordingProfile &profile, const QString &name);
    295295
     
    349349    ProgramInfo *pendingRecording;
    350350    QDateTime    recordPendingStart;
    351351
     352    // Pseudo LiveTV recording
     353    ProgramInfo *pseudoLiveTVRecording;
     354
    352355    // LiveTV file chain
    353356    LiveTVChain *tvchain;
    354357
  • libs/libmyth/mythcontext.h

     
    221221 *   You must also update this value in
    222222 *   mythplugins/mythweb/includes/mythbackend.php
    223223 */
    224 #define MYTH_PROTO_VERSION "22"
     224#define MYTH_PROTO_VERSION "23"
    225225
    226226/** \class MythContext
    227227 *  \brief This class contains the runtime context for MythTV.
  • programs/mythbackend/encoderlink.h

     
    6262    void StopRecording(void);
    6363    void FinishRecording(void);
    6464    void FrontendReady(void);
    65     void CancelNextRecording(void);
     65    void CancelNextRecording(bool);
    6666    bool WouldConflict(const ProgramInfo *rec);
    6767
    6868    bool IsReallyRecording(void);
  • programs/mythbackend/mainserver.cpp

     
    24202420    }
    24212421    else if (command == "CANCEL_NEXT_RECORDING")
    24222422    {
    2423         VERBOSE(VB_IMPORTANT, "Received: CANCEL_NEXT_RECORDING");
    2424         enc->CancelNextRecording();
     2423        QString cancel = slist[2];
     2424        VERBOSE(VB_IMPORTANT, "Received: CANCEL_NEXT_RECORDING "<<cancel);
     2425        enc->CancelNextRecording(cancel == "1");
    24252426        retlist << "ok";
    24262427    }
    24272428    else if (command == "SPAWN_LIVETV")
     
    35963597    for (; iter != encoderList->end(); ++iter)
    35973598    {
    35983599        EncoderLink *elink = iter.data();
    3599         elink->CancelNextRecording();
     3600        elink->CancelNextRecording(true);
    36003601        ProgramInfo *pinfo = elink->GetRecording();
    36013602        pinfo->ToStringList(strlist);
    36023603        delete pinfo;
  • programs/mythbackend/encoderlink.cpp

     
    203203 *  \brief Tells TVRec there is a pending recording "rec" in "secsleft" seconds.
    204204 *  \param rec      Recording to make.
    205205 *  \param secsleft Seconds to wait before starting recording.
    206  *  \sa StartRecording(const ProgramInfo*), CancelNextRecording()
     206 *  \sa StartRecording(const ProgramInfo*), CancelNextRecording(bool)
    207207 */
    208208void EncoderLink::RecordPending(const ProgramInfo *rec, int secsleft)
    209209{
     
    568568        VERBOSE(VB_IMPORTANT, "Should be local only query: FrontendReady");
    569569}
    570570
    571 /** \fn EncoderLink::CancelNextRecording()
     571/** \fn EncoderLink::CancelNextRecording(bool)
    572572 *  \brief Tells TVRec to cancel the next recording.
    573573 *         <b>This only works on local recorders.</b>
    574574 *
     
    577577 *
    578578 *  \sa RecordPending(const ProgramInfo*,int)
    579579 */
    580 void EncoderLink::CancelNextRecording(void)
     580void EncoderLink::CancelNextRecording(bool cancel)
    581581{
    582582    if (local)
    583         tv->CancelNextRecording();
     583        tv->CancelNextRecording(cancel);
    584584    else
    585585        VERBOSE(VB_IMPORTANT, "Should be local only query: CancelNextRecording");
    586586}