Ticket #3326: 3326-isbusy-v1.patch

File 3326-isbusy-v1.patch, 34.8 KB (added by danielk, 13 years ago)

Adds TVRec::GetBusyInput?() and an input switching menu as a use case

  • libs/libmythtv/remoteutil.h

     
    2727    int weight;
    2828};
    2929
     30class MPUBLIC InputInfo
     31{
     32  public:
     33    InputInfo() : name(QString::null), sourceid(0), inputid(0), cardid(0) {}
     34    InputInfo(const QString &name, uint sourceid, uint inputid, uint cardid);
     35    InputInfo(const InputInfo &other);
     36    InputInfo &operator=(const InputInfo &other);
     37
     38  public:
     39    QString name;
     40    uint sourceid;
     41    uint inputid;
     42    uint cardid;
     43};
     44
    3045MPUBLIC vector<ProgramInfo *> *RemoteGetRecordedList(bool deltype);
    3146MPUBLIC vector<FileSystemInfo> RemoteGetFreeSpace();
    3247MPUBLIC bool RemoteGetLoad(float load[3]);
     
    5267RemoteEncoder *RemoteRequestFreeRecorderFromList(QStringList &qualifiedRecorders);
    5368MPUBLIC RemoteEncoder *RemoteGetExistingRecorder(ProgramInfo *pginfo);
    5469MPUBLIC RemoteEncoder *RemoteGetExistingRecorder(int recordernum);
     70MPUBLIC vector<uint> RemoteRequestFreeRecorderList(void);
     71MPUBLIC vector<InputInfo> RemoteRequestFreeInputList(
     72    uint cardid, vector<uint> excluded_cardids);
     73MPUBLIC InputInfo RemoteRequestBusyInputID(uint cardid);
    5574MPUBLIC void RemoteGeneratePreviewPixmap(ProgramInfo *pginfo);
    5675MPUBLIC QString RemoteGetPreviewLastModified(ProgramInfo *pginfo);
    5776MPUBLIC void RemoteFillProginfo(ProgramInfo *pginfo,
    5877                                const QString &playbackhostname);
     78MPUBLIC bool RemoteIsBusy(uint cardid);
    5979MPUBLIC int RemoteIsRecording(void);
    6080MPUBLIC int RemoteGetRecordingMask(void);
    6181MPUBLIC int RemoteGetFreeRecorderCount(void);
  • libs/libmythtv/cardutil.h

     
    132132                                 uint sid, const QString &val)
    133133        { return set_on_source(col, cid, sid, val); }
    134134
    135 
     135    // Inputs
    136136    static QString      GetDefaultInput(uint cardid);
    137137    static QStringList  GetInputNames(uint cardid, uint sourceid);
     138    static bool         GetInputInfo(uint inputid, QString &inputname,
     139                                     uint &sourceid, uint &cardid,
     140                                     vector<uint> &groupids);
     141    static uint         GetCardID(uint inputid);
     142    static QString      GetInputName(uint inputid);
     143    static QString      GetDisplayName(uint inputid);
     144    static QString      GetDisplayName(uint cardid, const QString &inputname);
    138145
     146    // Input Groups
     147    static uint         CreateInputGroup(const QString &name);
     148    static bool         LinkInputGroup(uint inputid, uint inputgroupid);
     149    static bool         UnlinkInputGroup(uint inputid, uint inputgroupid);
     150    static vector<uint> GetInputGroups(uint inputid);
     151    static vector<uint> GetGroupCardIDs(uint inputgroupid);
     152
    139153    static QString      GetDeviceLabel(uint    cardid,
    140154                                       QString cardtype,
    141155                                       QString videodevice);
     
    152166                                      int                 parentid = 0);
    153167
    154168    static bool         DeleteCard(uint cardid);
     169    static vector<uint> GetCardList(bool primaryOnly = true);
    155170
    156     // Input Groups
    157     static uint         CreateInputGroup(const QString &name);
    158     static bool         LinkInputGroup(uint inputid, uint inputgroupid);
    159     static bool         UnlinkInputGroup(uint inputid, uint inputgroupid);
    160 
    161171    // DTV info
    162172    static bool         GetTimeouts(uint cardid,
    163173                                    uint &signal_timeout,
  • libs/libmythtv/tv_play.h

     
    258258    QString GetQueuedChanNum(void) const;
    259259    uint    GetQueuedChanID(void)  const { return queuedChanID; }
    260260
    261     void ToggleInputs(void);
     261    void SwitchInputs(uint inputid);
     262    void ToggleInputs(uint inputid = 0);
     263    void SwitchCards(uint chanid = 0, QString channum = "", uint inputid = 0);
    262264
    263     void SwitchCards(uint chanid = 0, QString channum = "");
    264 
    265265    void ToggleSleepTimer(void);
    266266    void ToggleSleepTimer(const QString);
    267267
     
    419419    mutable QMutex     stateLock;
    420420    TVState            internalState;
    421421
     422    uint switchToInputId;
    422423    bool menurunning;
    423424    bool runMainLoop;
    424425    bool wantsToQuit;
  • libs/libmythtv/sourceutil.h

     
    1010class MPUBLIC SourceUtil
    1111{
    1212  public:
     13    static bool    HasDigitalChannel(uint sourceid);
     14    static QString GetSourceName(uint sourceid);
    1315    static QString GetChannelSeparator(uint sourceid);
    1416    static QString GetChannelFormat(uint sourceid);
    1517    static uint    GetChannelCount(uint sourceid);
  • libs/libmythtv/tv_play.cpp

     
    44#include <unistd.h>
    55#include <pthread.h>
    66
     7#include <algorithm>
     8using namespace std;
     9
    710#include <qapplication.h>
    811#include <qregexp.h>
    912#include <qfile.h>
     
    4043#include "DVDRingBuffer.h"
    4144#include "datadirect.h"
    4245#include "sourceutil.h"
     46#include "cardutil.h"
    4347
    4448#ifndef HAVE_ROUND
    4549#define round(x) ((int) ((x) + 0.5))
     
    475479      vbimode(VBIMode::None),
    476480      // State variables
    477481      internalState(kState_None),
     482      switchToInputId(0),
    478483      menurunning(false), runMainLoop(false), wantsToQuit(true),
    479484      exitPlayer(false), paused(false), errored(false),
    480485      stretchAdjustment(false),
     
    19871992            ClearInputQueues(true);
    19881993        }   
    19891994
     1995        if (switchToInputId)
     1996        {
     1997            uint tmp = switchToInputId;
     1998            switchToInputId = 0;
     1999            SwitchInputs(tmp);
     2000        }
     2001
    19902002        if (class LCD * lcd = LCD::Get())
    19912003        {
    19922004            QDateTime curTime = QDateTime::currentDateTime();
     
    39153927        muteTimer->start(kMuteTimeout, true);
    39163928}
    39173929
    3918 void TV::SwitchCards(uint chanid, QString channum)
     3930void TV::SwitchInputs(uint inputid)
    39193931{
     3932    VERBOSE(VB_PLAYBACK, LOC + QString("SwitchInputd(%1)").arg(inputid));
     3933
     3934    if ((uint)activerecorder->GetRecorderNumber() ==
     3935        CardUtil::GetCardID(inputid))
     3936    {
     3937        ToggleInputs(inputid);
     3938    }
     3939    else
     3940    {
     3941        SwitchCards(0, QString::null, inputid);
     3942    }
     3943}
     3944
     3945void TV::SwitchCards(uint chanid, QString channum, uint inputid)
     3946{
    39203947    VERBOSE(VB_PLAYBACK, LOC +
    3921             QString("SwitchCards(%1,'%2')").arg(chanid).arg(channum));
     3948            QString("SwitchCards(%1,'%2',%3)")
     3949            .arg(chanid).arg(channum).arg(inputid));
    39223950
    39233951    RemoteEncoder *testrec = NULL;
    39243952
    39253953    if (!StateIsLiveTV(GetState()) || (activenvp != nvp) || pipnvp)
    39263954        return;
    39273955
    3928     if (/*chanid || */!channum.isEmpty())
     3956    // If we are switching to a channel not on the current recorder
     3957    // we need to find the next free recorder with that channel.
     3958    QStringList reclist;
     3959    if (!channum.isEmpty())
     3960        reclist = GetValidRecorderList(chanid, channum);
     3961    else if (inputid)
    39293962    {
    3930         // If we are switching to a channel not on the current recorder
    3931         // we need to find the next free recorder with that channel.
    3932         QStringList reclist = GetValidRecorderList(chanid, channum);
    3933         testrec = RemoteRequestFreeRecorderFromList(reclist);
     3963        uint cardid = CardUtil::GetCardID(inputid);
     3964        if (cardid)
     3965            reclist.push_back(QString::number(cardid));
    39343966    }
    39353967
     3968    if (!reclist.empty())
     3969        testrec = RemoteRequestFreeRecorderFromList(reclist);
     3970
    39363971    // If we are just switching recorders find first available recorder.
    39373972    if (!testrec)
    39383973        testrec = RemoteRequestNextFreeRecorder(recorder->GetRecorderNumber());
     
    40304065    ITVRestart(true);
    40314066}
    40324067
    4033 void TV::ToggleInputs(void)
     4068void TV::ToggleInputs(uint inputid)
    40344069{
    40354070    // If main Nuppel Video Player is paused, unpause it
    40364071    if (activenvp == nvp && paused)
     
    40474082        inputname = activerecorder->GetInput();
    40484083    else
    40494084    {
    4050         // Pause the backend recorder, send command, and then unpause..
    4051         PauseLiveTV();
    4052         lockTimerOn = false;
    4053         inputname = activerecorder->SetInput("SwitchToNextInput");
    4054         UnpauseLiveTV();
     4085        inputname = "SwitchToNextInput";
     4086        if (inputid)
     4087        {
     4088            QString tmp = CardUtil::GetInputName(inputid);
     4089            inputname = (tmp.isEmpty()) ? inputname : tmp;
     4090        }
     4091
     4092        if (activerecorder->GetInput() != inputname)
     4093        {
     4094            // Pause the backend recorder, send command, and then unpause..
     4095            PauseLiveTV();
     4096            lockTimerOn = false;
     4097            inputname = activerecorder->SetInput(inputname);
     4098            UnpauseLiveTV();
     4099        }
    40554100    }       
    40564101
    40574102    // If activenvp is main nvp, show new input in on screen display
     
    46404685
    46414686void TV::UpdateOSDInput(QString inputname)
    46424687{
    4643     QString displayName = QString::null;
    4644 
    46454688    if (!activerecorder || !tvchain)
    46464689        return;
    46474690
     
    46504693    if (inputname.isEmpty())
    46514694        inputname = tvchain->GetInputName(-1);
    46524695
    4653     // Try to get display name
    4654     MSqlQuery query(MSqlQuery::InitCon());
    4655     query.prepare("SELECT displayname "
    4656                   "FROM cardinput "
    4657                   "WHERE inputname = :INPUTNAME AND "
    4658                   "      cardid    = :CARDID");
    4659     query.bindValue(":CARDID",    cardid);
    4660     query.bindValue(":INPUTNAME", inputname);
    4661     if (query.exec() && query.isActive() && query.next())
    4662         displayName = query.value(0).toString();
    4663 
     4696    QString displayName = CardUtil::GetDisplayName(cardid, inputname);
    46644697    // If a display name doesn't exist use cardid and inputname
    46654698    if (displayName.isEmpty())
    46664699        displayName = QString("%1: %2").arg(cardid).arg(inputname);
     
    65276560            BrowseStart();
    65286561        else if (action == "PREVCHAN")
    65296562            PreviousChannel();
     6563        else if (action.left(14) == "SWITCHTOINPUT_")
     6564            switchToInputId = action.mid(14).toUInt();
    65306565        else
    65316566        {
    65326567            VERBOSE(VB_IMPORTANT, LOC_ERR +
     
    67896824
    67906825    if (freeRecorders)
    67916826    {
     6827        // Picture-in-Picture
    67926828        item = new OSDGenericTree(treeMenu, tr("Picture-in-Picture"));
    67936829        subitem = new OSDGenericTree(item, tr("Enable/Disable"),
    67946830                                     "TOGGLEPIPMODE");
    67956831        subitem = new OSDGenericTree(item, tr("Swap PiP/Main"), "SWAPPIP");
    67966832        subitem = new OSDGenericTree(item, tr("Change Active Window"),
    67976833                                     "TOGGLEPIPWINDOW");
     6834
     6835        // Input switching
     6836        item = NULL;
     6837
     6838        QMap<uint,InputInfo> sources;
     6839        vector<uint> cardids = RemoteRequestFreeRecorderList();
     6840        uint         cardid  = activerecorder->GetRecorderNumber();
     6841        cardids.push_back(cardid);
     6842        stable_sort(cardids.begin(), cardids.end());
     6843
     6844        vector<uint> excluded_cardids;
     6845        excluded_cardids.push_back(cardid);
     6846
     6847        InfoMap info;
     6848        activerecorder->GetChannelInfo(info);
     6849        uint sourceid = info["sourceid"].toUInt();
     6850
     6851        vector<uint>::const_iterator it = cardids.begin();
     6852        for (; it != cardids.end(); ++it)
     6853        {
     6854            vector<InputInfo> inputs = RemoteRequestFreeInputList(
     6855                *it, excluded_cardids);
     6856
     6857            if (inputs.empty())
     6858                continue;
     6859
     6860            if (!item)
     6861                item = new OSDGenericTree(treeMenu, tr("Switch Input"));
     6862
     6863            for (uint i = 0; i < inputs.size(); i++)
     6864            {
     6865                // prefer the current card's input in sources list
     6866                if ((sources.find(inputs[i].sourceid) == sources.end()) ||
     6867                    ((cardid == inputs[i].cardid) &&
     6868                     (cardid != sources[inputs[i].sourceid].cardid)))
     6869                {
     6870                    sources[inputs[i].sourceid] = inputs[i];
     6871                }
     6872
     6873                // don't add current input to list
     6874                if ((inputs[i].cardid   == cardid) &&
     6875                    (inputs[i].sourceid == sourceid))
     6876                {
     6877                    continue;
     6878                }
     6879
     6880                QString name = CardUtil::GetDisplayName(inputs[i].inputid);
     6881                if (name.isEmpty())
     6882                {
     6883                    name = tr("C", "Card") + ":" + QString::number(*it) + " " +
     6884                        tr("I", "Input") + ":" + inputs[i].name;
     6885                }
     6886
     6887                subitem = new OSDGenericTree(
     6888                    item, name,
     6889                    QString("SWITCHTOINPUT_%1").arg(inputs[i].inputid));
     6890            }
     6891        }
     6892
     6893        // Source switching
     6894
     6895        // delete current source from list
     6896        sources.erase(sourceid);
     6897
     6898        // create menu if we have any sources left
     6899        QMap<uint,InputInfo>::const_iterator sit = sources.begin();
     6900        if (sit != sources.end())
     6901            item = new OSDGenericTree(treeMenu, tr("Switch Source"));
     6902        for (; sit != sources.end(); ++sit)
     6903        {
     6904            subitem = new OSDGenericTree(
     6905                item, SourceUtil::GetSourceName((*sit).sourceid),
     6906                QString("SWITCHTOINPUT_%1").arg((*sit).inputid));
     6907        }
    67986908    }
    67996909
    68006910    if (!persistentbrowsemode)
  • libs/libmythtv/cardutil.cpp

     
    377377    return list;
    378378}
    379379
     380bool CardUtil::GetInputInfo(
     381    uint inputid,
     382    QString &inputname, uint &sourceid, uint &cardid, vector<uint> &groupids)
     383{
     384    MSqlQuery query(MSqlQuery::InitCon());
     385    query.prepare("SELECT inputname, sourceid, cardid "
     386                  "FROM cardinput "
     387                  "WHERE cardinputid = :INPUTID");
     388    query.bindValue(":INPUTID", inputid);
     389
     390    if (!query.exec())
     391    {
     392        MythContext::DBError("CardUtil::GetCardID(inputid)", query);
     393        return false;
     394    }
     395
     396    if (!query.next())
     397        return false;
     398
     399    inputname = query.value(0).toString();
     400    sourceid  = query.value(1).toUInt();
     401    cardid    = query.value(2).toUInt();
     402    groupids  = GetInputGroups(inputid);
     403
     404    return true;
     405}
     406
     407uint CardUtil::GetCardID(uint inputid)
     408{
     409    MSqlQuery query(MSqlQuery::InitCon());
     410    query.prepare("SELECT cardid "
     411                  "FROM cardinput "
     412                  "WHERE cardinputid = :INPUTID");
     413    query.bindValue(":INPUTID", inputid);
     414
     415    if (!query.exec())
     416        MythContext::DBError("CardUtil::GetCardID(inputid)", query);
     417    else if (query.next())
     418        return query.value(0).toUInt();
     419
     420    return 0;
     421}
     422
     423QString CardUtil::GetInputName(uint inputid)
     424{
     425    MSqlQuery query(MSqlQuery::InitCon());
     426    query.prepare("SELECT inputname "
     427                  "FROM cardinput "
     428                  "WHERE cardinputid = :INPUTID");
     429    query.bindValue(":INPUTID", inputid);
     430
     431    if (!query.exec())
     432        MythContext::DBError("CardUtil::GetInputName()", query);
     433    else if (query.next())
     434        return query.value(0).toString();
     435
     436    return QString::null;
     437}
     438
     439QString CardUtil::GetDisplayName(uint inputid)
     440{
     441    MSqlQuery query(MSqlQuery::InitCon());
     442    query.prepare("SELECT displayname "
     443                  "FROM cardinput "
     444                  "WHERE cardinputid = :INPUTID");
     445    query.bindValue(":INPUTID", inputid);
     446
     447    if (!query.exec())
     448        MythContext::DBError("CardUtil::GetDisplayName(uint)", query);
     449    else if (query.next())
     450        return QString::fromUtf8(query.value(0).toString());
     451
     452    return QString::null;
     453}
     454
     455QString CardUtil::GetDisplayName(uint cardid, const QString &inputname)
     456{
     457    MSqlQuery query(MSqlQuery::InitCon());
     458    query.prepare("SELECT displayname "
     459                  "FROM cardinput "
     460                  "WHERE inputname = :INPUTNAME AND "
     461                  "      cardid    = :CARDID");
     462    query.bindValue(":INPUTNAME", inputname);
     463    query.bindValue(":CARDID",    cardid);
     464
     465    if (!query.exec())
     466        MythContext::DBError("CardUtil::GetDisplayName(uint,QString)", query);
     467    else if (query.next())
     468        return QString::fromUtf8(query.value(0).toString());
     469
     470    return QString::null;
     471}
     472
    380473uint CardUtil::CreateInputGroup(const QString &name)
    381474{
    382475    MSqlQuery query(MSqlQuery::InitCon());
     
    476569    return true;
    477570}
    478571
     572vector<uint> CardUtil::GetInputGroups(uint inputid)
     573{
     574    vector<uint> list;
     575
     576    MSqlQuery query(MSqlQuery::InitCon());
     577
     578    query.prepare(
     579        "SELECT inputgroupid "
     580        "FROM inputgroup "
     581        "WHERE cardinputid = :INPUTID "
     582        "ORDER BY inputgroupid, cardinputid, inputgroupname");
     583
     584    query.bindValue(":INPUTID", inputid);
     585
     586    if (!query.exec())
     587    {
     588        MythContext::DBError("CardUtil::GetInputGroups()", query);
     589        return list;
     590    }
     591
     592    while (query.next())
     593        list.push_back(query.value(0).toUInt());
     594
     595    return list;
     596}
     597
     598vector<uint> CardUtil::GetGroupCardIDs(uint inputgroupid)
     599{
     600    vector<uint> list;
     601
     602    MSqlQuery query(MSqlQuery::InitCon());
     603
     604    query.prepare(
     605        "SELECT cardinputid "
     606        "FROM inputgroup "
     607        "WHERE inputgroupid = :GROUPID "
     608        "ORDER BY inputgroupid, cardinputid, inputgroupname");
     609
     610    query.bindValue(":GROUPID", inputgroupid);
     611
     612    if (!query.exec())
     613    {
     614        MythContext::DBError("CardUtil::GetInputGroups()", query);
     615        return list;
     616    }
     617
     618    while (query.next())
     619        list.push_back(query.value(0).toUInt());
     620
     621    return list;
     622}
     623
     624
    479625bool CardUtil::GetTimeouts(uint cardid,
    480626                           uint &signal_timeout, uint &channel_timeout)
    481627{
     
    9991145    return true;
    10001146}
    10011147
     1148vector<uint> CardUtil::GetCardList(bool primaryOnly)
     1149{
     1150    vector<uint> list;
     1151
     1152    MSqlQuery query(MSqlQuery::InitCon());
     1153    if (primaryOnly)
     1154    {
     1155        query.prepare(
     1156            "SELECT cardid "
     1157            "FROM capturecard "
     1158            "WHERE parentid='0' "
     1159            "ORDER BY cardid");
     1160    }
     1161    else
     1162    {
     1163        query.prepare(
     1164            "SELECT cardid "
     1165            "FROM capturecard "
     1166            "ORDER BY cardid");
     1167    }
     1168
     1169    if (!query.exec())
     1170        MythContext::DBError("CardUtil::GetCardList()", query);
     1171    else
     1172    {
     1173        while (query.next())
     1174            list.push_back(query.value(0).toUInt());
     1175    }
     1176
     1177    return list;
     1178}
     1179
     1180
    10021181QString CardUtil::GetDeviceName(dvb_dev_type_t type, uint cardnum)
    10031182{
    10041183    if (DVB_DEV_FRONTEND == type)
  • libs/libmythtv/remoteutil.cpp

     
     1#include <qdeepcopy.h>
    12#include <qstringlist.h>
    23
    34#include "util.h"
     
    67#include "mythcontext.h"
    78#include "remoteencoder.h"
    89
     10InputInfo::InputInfo(
     11    const QString &_name, uint _sourceid, uint _inputid, uint _cardid) :
     12    name(QDeepCopy<QString>(_name)),
     13    sourceid(_sourceid),
     14    inputid(_inputid),
     15    cardid(_cardid)
     16{
     17}
     18
     19InputInfo::InputInfo(const InputInfo &other) :
     20    name(QDeepCopy<QString>(other.name)),
     21    sourceid(other.sourceid),
     22    inputid(other.inputid),
     23    cardid(other.cardid)
     24{
     25}
     26
     27InputInfo &InputInfo::operator=(const InputInfo &other)
     28{
     29    name     = QDeepCopy<QString>(other.name);
     30    sourceid = other.sourceid;
     31    inputid  = other.inputid;
     32    cardid   = other.cardid;
     33    return *this;
     34}
     35
    936vector<ProgramInfo *> *RemoteGetRecordedList(bool deltype)
    1037{
    1138    QString str = "QUERY_RECORDINGS ";
     
    291318    return new RemoteEncoder(recordernum, hostname, port);
    292319}
    293320
     321vector<uint> RemoteRequestFreeRecorderList(void)
     322{
     323    vector<uint> list;
     324
     325    QStringList strlist = "GET_FREE_RECORDER_LIST";
     326
     327    if (!gContext->SendReceiveStringList(strlist, true))
     328        return list;
     329
     330    QStringList::const_iterator it = strlist.begin();
     331    for (; it != strlist.end(); ++it)
     332        list.push_back((*it).toUInt());
     333
     334    return list;
     335}
     336
     337vector<InputInfo> RemoteRequestFreeInputList(uint cardid,
     338                                             vector<uint> excluded_cardids)
     339{
     340    vector<InputInfo> list;
     341
     342    QStringList strlist = QString("QUERY_RECORDER %1").arg(cardid);
     343    strlist << "GET_FREE_INPUTS";
     344    for (uint i = 0; i < excluded_cardids.size(); i++)
     345        strlist << QString::number(excluded_cardids[i]);
     346
     347    if (!gContext->SendReceiveStringList(strlist))
     348        return list;
     349
     350    QStringList::const_iterator it = strlist.begin();
     351    if ((it == strlist.end()) || (*it == "EMPTY_LIST"))
     352        return list;
     353
     354    while (it != strlist.end())
     355    {
     356        QString inputname = *it;
     357        uint sourceid, inputid, cardid;
     358        ++it;
     359        if (it == strlist.end())
     360            break;
     361        sourceid = (*it).toUInt();
     362        ++it;
     363        if (it == strlist.end())
     364            break;
     365        inputid = (*it).toUInt();
     366        ++it;
     367        if (it == strlist.end())
     368            break;
     369        cardid = (*it).toUInt();
     370        ++it;
     371
     372        if (!inputname.isEmpty() && sourceid && inputid && cardid)
     373            list.push_back(InputInfo(inputname, sourceid, inputid, cardid));
     374    }
     375
     376    return list;
     377}
     378
     379InputInfo RemoteRequestBusyInputID(uint cardid)
     380{
     381    InputInfo blank;
     382
     383    QStringList strlist = QString("QUERY_RECORDER %1").arg(cardid);
     384    strlist << "GET_BUSY_INPUT";
     385
     386    if (!gContext->SendReceiveStringList(strlist))
     387        return blank;
     388
     389    QStringList::const_iterator it = strlist.begin();
     390    if ((it == strlist.end()) || (*it == "EMPTY_LIST"))
     391        return blank;
     392
     393    InputInfo info;
     394
     395    if (it == strlist.end())
     396        return blank;
     397    info.name = *it;
     398
     399    ++it;
     400    if (it == strlist.end())
     401        return blank;
     402    info.sourceid = (*it).toUInt();
     403
     404    ++it;
     405    if (it == strlist.end())
     406        return blank;
     407    info.inputid = (*it).toUInt();
     408
     409    ++it;
     410    if (it == strlist.end())
     411        return blank;
     412    info.cardid = (*it).toUInt();
     413
     414    if (!info.name.isEmpty() && info.sourceid && info.inputid && info.cardid)
     415        return info;
     416
     417    return blank;
     418}
     419
    294420void RemoteSendMessage(const QString &message)
    295421{
    296422    QStringList strlist = "MESSAGE";
     
    330456        pginfo->FromStringList(strlist, 0);
    331457}
    332458
     459bool RemoteIsBusy(uint cardid)
     460{
     461    QStringList strlist = QString("QUERY_REMOTEENCODER %1").arg(cardid);
     462    strlist << "IS_BUSY";
     463
     464    if (!gContext->SendReceiveStringList(strlist) || strlist.empty())
     465        return true;
     466
     467    bool state = strlist[0].toInt();
     468    return state;
     469}
     470
    333471int RemoteIsRecording(void)
    334472{
    335473    QStringList strlist = "QUERY_ISRECORDING";
  • libs/libmythtv/tv_rec.cpp

     
    5959#include "hdhrrecorder.h"
    6060#include "iptvrecorder.h"
    6161#include "firewirerecorder.h"
     62#include "remoteutil.h"
     63#include "sourceutil.h"
    6264
    6365#ifdef USING_V4L
    6466#include "channel.h"
     
    305307    SetRingBuffer(NULL);
    306308}
    307309
    308 /** \fn TVRec::GetState()
     310/** \fn TVRec::GetState() const
    309311 *  \brief Returns the TVState of the recorder.
    310312 *
    311313 *   If there is a pending state change kState_ChangingState is returned.
    312314 *  \sa EncoderLink::GetState(), \ref recorder_subsystem
    313315 */
    314 TVState TVRec::GetState(void)
     316TVState TVRec::GetState(void) const
    315317{
    316318    if (changeState)
    317319        return kState_ChangingState;
     
    22212223            HasFlags(kFlagDummyRecorderRunning));
    22222224}
    22232225
    2224 /** \fn TVRec::IsBusy()
     2226/** \fn TVRec::IsBusy() const
    22252227 *  \brief Returns true if the recorder is busy, or will be within
    22262228 *         the next 5 seconds.
    22272229 *  \sa EncoderLink::IsBusy(),
    22282230 */
    2229 bool TVRec::IsBusy(void)
     2231bool TVRec::IsBusy(void) const
    22302232{
    22312233    QMutexLocker lock(&stateChangeLock);
    22322234
     
    27172719    return ret / 655;
    27182720}
    27192721
     2722static bool is_input_group_busy(
     2723    uint                inputid,
     2724    uint                groupid,
     2725    const vector<uint> &excluded_cardids,
     2726    QMap<uint,bool>    &busygrp,
     2727    QMap<uint,bool>    &busyrec)
     2728{
     2729    bool is_busy_grp = busygrp[groupid];
     2730    if (!is_busy_grp)
     2731        return false;
     2732
     2733    // quick check...
     2734    vector<uint> cardids = CardUtil::GetGroupCardIDs(groupid);
     2735    for (uint i = 0; i < cardids.size() && !is_busy_grp; i++)
     2736    {
     2737        if (find(excluded_cardids.begin(),
     2738                 excluded_cardids.end(), cardids[i]) != excluded_cardids.end())
     2739            continue;
     2740
     2741        QMap<uint,bool>::const_iterator it = busyrec.find(cardids[i]);
     2742        if (it == busyrec.end())
     2743            busyrec[cardids[i]] = RemoteIsBusy(cardids[i]);
     2744
     2745        is_busy_grp = busyrec[cardids[i]];
     2746    }
     2747
     2748    busygrp[groupid] = is_busy_grp;
     2749    if (!is_busy_grp)
     2750        return false;
     2751
     2752    // check more carefully...
     2753    vector<InputInfo> conflicts;
     2754    for (uint i = 0; i < cardids.size(); i++)
     2755    {
     2756        if (find(excluded_cardids.begin(),
     2757                 excluded_cardids.end(), cardids[i]) != excluded_cardids.end())
     2758            continue;
     2759
     2760        QMap<uint,bool>::const_iterator it = busyrec.find(cardids[i]);
     2761        if (it == busyrec.end())
     2762            busyrec[cardids[i]] = RemoteIsBusy(cardids[i]);
     2763
     2764        if (!busyrec[cardids[i]])
     2765            continue;
     2766
     2767        InputInfo info = RemoteRequestBusyInputID(cardids[i]);
     2768        conflicts.push_back(info);
     2769    }
     2770
     2771    InputInfo in;
     2772    vector<uint> groups;
     2773    in.inputid = inputid;
     2774    if (!CardUtil::GetInputInfo(
     2775            inputid, in.name, in.sourceid, in.cardid, groups))
     2776    {
     2777        return true;
     2778    }
     2779
     2780    // If they aren't using the same source they are definately busy
     2781    bool is_busy_input = false;
     2782    for (uint i = 0; i < conflicts.size() && !is_busy_input; i++)
     2783        is_busy_input = in.sourceid != conflicts[i].sourceid;
     2784    if (is_busy_input)
     2785        return true;
     2786
     2787    // If the source's channels aren't digitally tuned then there is a conflict
     2788    return !SourceUtil::HasDigitalChannel(in.sourceid);
     2789}
     2790
     2791/** \fn TVRec::GetFreeInputs(vector<uint>) const
     2792 *  \brief Returns TVRec's recorders available inputs.
     2793 *
     2794 *  This filters the result of GetConnectedInputs() so that inputs
     2795 *  that belong to an input group which is busy are removed from the
     2796 *  list. Recorders in the excluded cardids will not be considered
     2797 *  busy for the sake of determining free inputs.
     2798 *
     2799 *  Then additional information is added to the list, in addition
     2800 *  to the name of the input this adds the sourceid, inputid,
     2801 *  and cardid.
     2802 *
     2803 */
     2804QStringList TVRec::GetFreeInputs(vector<uint> excluded_cardids) const
     2805{
     2806    QStringList list = GetConnectedInputs();
     2807    if (list.empty())
     2808        return list;
     2809
     2810    // Check each input to make sure it doesn't belong to an
     2811    // input group which is attached to a busy recorder.
     2812    QStringList new_list;
     2813    QMap<uint,bool> busygrp;
     2814    QMap<uint,bool> busyrec;
     2815
     2816    busyrec[cardid] = IsBusy();
     2817
     2818    QStringList::const_iterator it;
     2819    for (it = list.begin(); it != list.end(); ++it)
     2820    {
     2821        uint inputid = channel->GetInputByName(*it);
     2822        QString name;
     2823        uint sourceid, cardid;
     2824        vector<uint> groups;
     2825        if (!CardUtil::GetInputInfo(inputid, name, sourceid, cardid, groups))
     2826            continue;
     2827
     2828        bool is_busy_grp = false;
     2829        for (uint i = 0; i < groups.size() && !is_busy_grp; i++)
     2830        {
     2831            is_busy_grp |= is_input_group_busy(
     2832                inputid, groups[i], excluded_cardids, busygrp, busyrec);
     2833        }
     2834
     2835        if (!is_busy_grp)
     2836        {
     2837            new_list += name;
     2838            new_list += QString::number(sourceid);
     2839            new_list += QString::number(inputid);
     2840            new_list += QString::number(cardid);
     2841        }
     2842    }
     2843
     2844    return new_list;
     2845}
     2846
     2847QStringList TVRec::GetBusyInput(void) const
     2848{
     2849    QMutexLocker lock(&stateChangeLock);
     2850
     2851    QStringList new_list;
     2852    if (!channel)
     2853        return new_list;
     2854
     2855    QStringList list = channel->GetConnectedInputs();
     2856    if (list.empty())
     2857        return new_list;
     2858
     2859    uint inputid = 0;
     2860    if (GetState() != kState_None)
     2861        inputid = channel->GetCurrentInputNum();
     2862
     2863    if (!inputid && pendingRecording)
     2864    {
     2865        int timeLeft = QDateTime::currentDateTime().secsTo(recordPendingStart);
     2866        if (timeLeft <= 5)
     2867        {
     2868            QString channum = QString::null, input = QString::null;
     2869            if (pendingRecording->GetChannel(channum, input))
     2870                inputid = channel->GetInputByName(input);
     2871        }
     2872    }
     2873
     2874    if (inputid)
     2875    {
     2876        QString name;
     2877        uint sourceid, cardid;
     2878        vector<uint> groups;
     2879        if (CardUtil::GetInputInfo(inputid, name, sourceid, cardid, groups))
     2880        {
     2881            new_list += name;
     2882            new_list += QString::number(sourceid);
     2883            new_list += QString::number(inputid);
     2884            new_list += QString::number(cardid);
     2885        }
     2886    }
     2887
     2888    return new_list;
     2889}
     2890
    27202891/** \fn TVRec::GetConnectedInputs(void) const
    27212892 *  \brief Returns TVRec's recorders connected inputs.
    27222893 */
  • libs/libmythtv/tv_rec.h

     
    157157    /// \brief Tells TVRec to stop event loop
    158158    void Stop(void)             { ClearFlags(kFlagRunMainLoop); }
    159159
    160     TVState GetState(void);
     160    TVState GetState(void) const;
    161161    /// \brief Returns "state == kState_RecordingPreRecorded"
    162162    bool IsPlaying(void) { return StateIsPlaying(internalState); }
    163163    /// \brief Returns "state == kState_RecordingRecordedOnly"
     
    166166
    167167    bool SetVideoFiltersForChannel(uint sourceid, const QString &channum);
    168168
    169     bool IsBusy(void);
     169    bool IsBusy(void) const;
    170170    bool IsReallyRecording(void);
    171171
    172172    float GetFramerate(void);
     
    182182
    183183    void SetLiveRecording(int recording);
    184184
     185    QStringList GetFreeInputs(vector<uint> excluded_cardids) const;
     186    QStringList GetBusyInput(void) const;
    185187    QStringList GetConnectedInputs(void) const;
    186188    QString     GetInput(void) const;
    187189    QString     SetInput(QString input, uint requestType = kFlagDetect);
     
    337339    DBox2DBOptions     dboxOpt;
    338340
    339341    // State variables
    340     QMutex        stateChangeLock;
     342    mutable QMutex stateChangeLock;
    341343    TVState        internalState;
    342344    TVState        desiredNextState;
    343345    bool           changeState;
  • libs/libmythtv/sourceutil.cpp

     
    99#include "mythdbcon.h"
    1010#include "util.h"
    1111
     12bool SourceUtil::HasDigitalChannel(uint sourceid)
     13{
     14    MSqlQuery query(MSqlQuery::InitCon());
     15
     16    query.prepare(
     17        "SELECT mplexid, atsc_minor_chan, serviceid "
     18        "FROM videosource "
     19        "WHERE sourceid = :SOURCEID");
     20    query.bindValue(":SOURCEID", sourceid);
     21
     22    if (!query.exec())
     23    {
     24        MythContext::DBError("SourceUtil::HasDigitalChannel()", query);
     25        return false;
     26    }
     27
     28    if (!query.next())
     29        return false;
     30
     31    uint mplexid = query.value(0).toUInt();
     32    uint minor   = query.value(1).toUInt();
     33    uint prognum = query.value(2).toUInt();
     34
     35    mplexid = (32767 == mplexid) ? 0 : mplexid;
     36
     37    return mplexid && (minor || prognum);
     38}
     39
     40QString SourceUtil::GetSourceName(uint sourceid)
     41{
     42    MSqlQuery query(MSqlQuery::InitCon());
     43
     44    query.prepare(
     45        "SELECT name "
     46        "FROM videosource "
     47        "WHERE sourceid = :SOURCEID");
     48    query.bindValue(":SOURCEID", sourceid);
     49
     50    if (!query.exec())
     51    {
     52        MythContext::DBError("SourceUtil::GetSourceName()", query);
     53        return QString::null;
     54    }
     55    else if (!query.next())
     56    {
     57        return QString::null;
     58    }
     59
     60    return query.value(0).toString();
     61}
     62
    1263QString SourceUtil::GetChannelSeparator(uint sourceid)
    1364{
    1465    MSqlQuery query(MSqlQuery::InitCon());
  • programs/mythbackend/encoderlink.h

     
    7676    void PauseRecorder(void);
    7777    void SetLiveRecording(int);
    7878    void SetNextLiveTVDir(QString dir);
     79    QStringList GetFreeInputs(vector<uint> excluded_cardids) const;
    7980    QStringList GetConnectedInputs(void) const;
    8081    QString GetInput(void) const;
    8182    QString SetInput(QString);
  • programs/mythbackend/mainserver.cpp

     
    28142814        enc->SetLiveRecording(recording);
    28152815        retlist << "ok";
    28162816    }
     2817    else if (command == "GET_FREE_INPUTS")
     2818    {
     2819        vector<uint> excluded_cardids;
     2820        for (uint i = 2; i < slist.size(); i++)
     2821            excluded_cardids.push_back(slist[i].toUInt());
     2822
     2823        QStringList ret = enc->GetFreeInputs(excluded_cardids);
     2824
     2825        if (ret.empty())
     2826            retlist << "EMPTY_LIST";
     2827        else
     2828            retlist += ret;
     2829    }
     2830    else if (command == "GET_BUSY_INPUT")
     2831    {
     2832        QStringList ret = enc->GetBusyInput();
     2833        if (ret.empty())
     2834            retlist << "EMPTY_LIST";
     2835        else
     2836            retlist += ret;
     2837    }
    28172838    else if (command == "GET_CONNECTED_INPUTS")
    28182839    {
    28192840        QStringList ret = enc->GetConnectedInputs();
  • programs/mythbackend/encoderlink.cpp

     
    586586        sock->SetNextLiveTVDir(m_capturecardnum, dir);
    587587}
    588588
     589/** \fn EncoderLink::GetFreeInputs(vector<uint>) const
     590 *  \brief Returns TVRec's recorders inputs available for recording now.
     591 *         <b>This only works on local recorders.</b>
     592 *
     593 *  \sa TVRec::GetFreeInputs(vector<uint>) const
     594 */
     595QStringList EncoderLink::GetFreeInputs(vector<uint> excluded_cardids) const
     596{
     597    QStringList list;
     598
     599    if (local)
     600        list = tv->GetFreeInputs(excluded_cardids);
     601    else
     602        VERBOSE(VB_IMPORTANT, "Should be local only query: GetFreeInputs");
     603
     604    return list;
     605}
     606
    589607/** \fn EncoderLink::GetConnectedInputs(void) const
    590608 *  \brief Returns TVRec's recorders connected inputs.
    591609 *         <b>This only works on local recorders.</b>
     
    625643 *
    626644 *   You must call PauseRecorder(void) before calling this.
    627645 *
    628  *  \param input Input to switch to, or "SwitchToNectInput".
     646 *  \param input Input to switch to, or "SwitchToNextInput".
    629647 *  \return input we have switched to
    630648 *  \sa TVRec::SetInput(QString)
    631649 */