00001
00002 #include <fcntl.h>
00003 #include <unistd.h>
00004
00005 #include <algorithm>
00006
00007 #if defined(USING_V4L) || defined(USING_DVB)
00008 #include <sys/ioctl.h>
00009 #endif
00010
00011
00012 #include <qmap.h>
00013 #include <qdir.h>
00014
00015
00016 #include "cardutil.h"
00017 #include "videosource.h"
00018 #include "mythcontext.h"
00019 #include "mythdbcon.h"
00020 #include "dvbchannel.h"
00021 #include "diseqcsettings.h"
00022
00023 #ifdef USING_DVB
00024 #include "dvbtypes.h"
00025 #endif
00026
00027 #ifdef USING_V4L
00028 #include "videodev_myth.h"
00029 #endif
00030
00031 #define LOC QString("CardUtil: ")
00032 #define LOC_WARN QString("CardUtil, Warning: ")
00033 #define LOC_ERR QString("CardUtil, Error: ")
00034
00035 bool CardUtil::IsTunerShared(uint cardidA, uint cardidB)
00036 {
00037 VERBOSE(VB_IMPORTANT, QString("IsTunerShared(%1,%2)")
00038 .arg(cardidA).arg(cardidB));
00039
00040 MSqlQuery query(MSqlQuery::InitCon());
00041 query.prepare("SELECT videodevice, hostname, cardtype "
00042 "FROM capturecard "
00043 "WHERE ( (cardid = :CARDID_A) OR "
00044 " (cardid = :CARDID_B) )");
00045 query.bindValue(":CARDID_A", cardidA);
00046 query.bindValue(":CARDID_B", cardidB);
00047
00048 if (!query.exec())
00049 {
00050 MythContext::DBError("CardUtil::is_tuner_shared", query);
00051 return false;
00052 }
00053
00054 if (!query.next())
00055 return false;
00056
00057 const QString vdevice = query.value(0).toString();
00058 const QString hostname = query.value(1).toString();
00059 const QString cardtype = query.value(2).toString();
00060
00061 if (!IsTunerSharingCapable(cardtype.upper()))
00062 return false;
00063
00064 if (!query.next())
00065 return false;
00066
00067 bool ret = ((vdevice == query.value(0).toString()) &&
00068 (hostname == query.value(1).toString()) &&
00069 (cardtype == query.value(2).toString()));
00070
00071 VERBOSE(VB_RECORD, QString("IsTunerShared(%1,%2) -> %3")
00072 .arg(cardidA).arg(cardidB).arg(ret));
00073
00074 return ret;
00075 }
00076
00082 bool CardUtil::IsCardTypePresent(const QString &rawtype, QString hostname)
00083 {
00084 if (hostname.isEmpty())
00085 hostname = gContext->GetHostName();
00086
00087 MSqlQuery query(MSqlQuery::InitCon());
00088 QString qstr =
00089 "SELECT count(cardtype) "
00090 "FROM capturecard, cardinput "
00091 "WHERE cardinput.cardid = capturecard.cardid AND "
00092 " capturecard.hostname = :HOSTNAME";
00093
00094 if (!rawtype.isEmpty())
00095 qstr += " AND capturecard.cardtype = :CARDTYPE";
00096
00097 query.prepare(qstr);
00098
00099 if (!rawtype.isEmpty())
00100 query.bindValue(":CARDTYPE", rawtype.upper());
00101
00102 query.bindValue(":HOSTNAME", hostname);
00103
00104 if (!query.exec())
00105 {
00106 MythContext::DBError("CardUtil::IsCardTypePresent", query);
00107 return false;
00108 }
00109
00110 uint count = 0;
00111 if (query.next())
00112 count = query.value(0).toUInt();
00113
00114 return count > 0;
00115 }
00116
00122 QStringVec CardUtil::GetVideoDevices(const QString &rawtype, QString hostname)
00123 {
00124 QStringVec list;
00125
00126 if (hostname.isEmpty())
00127 hostname = gContext->GetHostName();
00128
00129 MSqlQuery query(MSqlQuery::InitCon());
00130 QString qstr =
00131 "SELECT videodevice "
00132 "FROM capturecard "
00133 "WHERE hostname = :HOSTNAME";
00134
00135 if (!rawtype.isEmpty())
00136 qstr += " AND cardtype = :CARDTYPE";
00137
00138 query.prepare(qstr);
00139
00140 if (!rawtype.isEmpty())
00141 query.bindValue(":CARDTYPE", rawtype.upper());
00142
00143 query.bindValue(":HOSTNAME", hostname);
00144
00145 if (!query.exec())
00146 {
00147 MythContext::DBError("CardUtil::GetVideoDevices", query);
00148 return list;
00149 }
00150
00151 QMap<QString,bool> dup;
00152 while (query.next())
00153 {
00154 QString videodevice = query.value(0).toString();
00155 if (dup[videodevice])
00156 continue;
00157
00158 list.push_back(videodevice);
00159 dup[videodevice] = true;
00160 }
00161
00162 return list;
00163 }
00164
00165 QStringVec CardUtil::ProbeVideoDevices(const QString &rawtype)
00166 {
00167 QStringVec devs;
00168
00169 if (rawtype.upper() == "DVB")
00170 {
00171 QDir dir("/dev/dvb", "adapter*", QDir::Name, QDir::All);
00172 const QFileInfoList *il = dir.entryInfoList();
00173 if (!il)
00174 return devs;
00175
00176 vector<uint> list;
00177 QMap<uint,bool> dups;
00178 QFileInfoListIterator it( *il );
00179 QFileInfo *fi;
00180
00181 for (; (fi = it.current()) != 0; ++it)
00182 {
00183 if (fi->fileName().left(7).lower() != "adapter")
00184 continue;
00185
00186 bool ok;
00187 uint num = fi->fileName().mid(7).toUInt(&ok);
00188 if (!ok || dups[num])
00189 continue;
00190
00191 list.push_back(num);
00192 dups[num] = true;
00193 }
00194
00195 stable_sort(list.begin(), list.end());
00196
00197 for (uint i = 0; i < list.size(); i++)
00198 devs.push_back(QString::number(list[i]));
00199 }
00200 else
00201 {
00202 VERBOSE(VB_IMPORTANT, QString("CardUtil::ProbeVideoDevices: ") +
00203 QString("Raw Type: '%1' is not supported").arg(rawtype));
00204 }
00205
00206 return devs;
00207 }
00208
00209 QString CardUtil::ProbeDVBType(uint device)
00210 {
00211 QString ret = "ERROR_UNKNOWN";
00212 (void) device;
00213
00214 #ifdef USING_DVB
00215 QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
00216 int fd_frontend = open(dvbdev.ascii(), O_RDONLY | O_NONBLOCK);
00217 if (fd_frontend < 0)
00218 {
00219 VERBOSE(VB_IMPORTANT, "Can't open DVB frontend (" + dvbdev + ").");
00220 return ret;
00221 }
00222
00223 struct dvb_frontend_info info;
00224 int err = ioctl(fd_frontend, FE_GET_INFO, &info);
00225 if (err < 0)
00226 {
00227 close(fd_frontend);
00228 VERBOSE(VB_IMPORTANT, "FE_GET_INFO ioctl failed (" + dvbdev + ").");
00229 return ret;
00230 }
00231 close(fd_frontend);
00232
00233 DTVTunerType type(info.type);
00234 ret = (type.toString() != "UNKNOWN") ? type.toString().upper() : ret;
00235 #endif // USING_DVB
00236
00237 return ret;
00238 }
00239
00243 QString CardUtil::ProbeDVBFrontendName(uint device)
00244 {
00245 QString ret = "ERROR_UNKNOWN";
00246 (void) device;
00247
00248 #ifdef USING_DVB
00249 QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
00250 int fd_frontend = open(dvbdev.ascii(), O_RDWR | O_NONBLOCK);
00251 if (fd_frontend < 0)
00252 return "ERROR_OPEN";
00253
00254 struct dvb_frontend_info info;
00255 int err = ioctl(fd_frontend, FE_GET_INFO, &info);
00256 if (err < 0)
00257 {
00258 close(fd_frontend);
00259 return "ERROR_PROBE";
00260 }
00261
00262 ret = info.name;
00263
00264 close(fd_frontend);
00265 #endif // USING_DVB
00266
00267 return ret;
00268 }
00269
00287 bool CardUtil::HasDVBCRCBug(uint device)
00288 {
00289 QString name = ProbeDVBFrontendName(device);
00290 return ((name == "VLSI VES1x93 DVB-S") ||
00291 (name == "ST STV0299 DVB-S"));
00292 }
00293
00294 uint CardUtil::GetMinSignalMonitoringDelay(uint device)
00295 {
00296 QString name = ProbeDVBFrontendName(device);
00297 if (name.find("DVB-S") >= 0)
00298 return 300;
00299 if (name == "DiBcom 3000P/M-C DVB-T")
00300 return 100;
00301 return 25;
00302 }
00303
00304 QString CardUtil::ProbeSubTypeName(uint cardid)
00305 {
00306 QString type = GetRawCardType(cardid);
00307 if ("DVB" != type)
00308 return type;
00309
00310 QString device = GetVideoDevice(cardid);
00311
00312 if (device.isEmpty())
00313 return "ERROR_OPEN";
00314
00315 return ProbeDVBType(device.toUInt());
00316 }
00317
00321 bool CardUtil::IsDVBCardType(const QString card_type)
00322 {
00323 QString ct = card_type.upper();
00324 return (ct == "DVB") || (ct == "QAM") || (ct == "QPSK") ||
00325 (ct == "OFDM") || (ct == "ATSC");
00326 }
00327
00328 QString get_on_cardid(const QString &to_get, uint cardid)
00329 {
00330 MSqlQuery query(MSqlQuery::InitCon());
00331 query.prepare(
00332 QString("SELECT %1 ").arg(to_get) +
00333 "FROM capturecard "
00334 "WHERE capturecard.cardid = :CARDID");
00335 query.bindValue(":CARDID", cardid);
00336
00337 if (!query.exec())
00338 MythContext::DBError("CardUtil::get_on_source", query);
00339 else if (query.next())
00340 return query.value(0).toString();
00341
00342 return QString::null;
00343 }
00344
00345 bool set_on_source(const QString &to_set, uint cardid, uint sourceid,
00346 const QString value)
00347 {
00348 QString tmp = get_on_cardid("capturecard.cardid", cardid);
00349 if (tmp.isEmpty())
00350 return false;
00351
00352 bool ok;
00353 uint input_cardid = tmp.toUInt(&ok);
00354 if (!ok)
00355 return false;
00356
00357 MSqlQuery query(MSqlQuery::InitCon());
00358 query.prepare(
00359 QString("UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
00360 "WHERE cardid = :CARDID");
00361 query.bindValue(":CARDID", input_cardid);
00362 query.bindValue(":VALUE", value);
00363
00364 if (query.exec())
00365 return true;
00366
00367 MythContext::DBError("CardUtil::set_on_source", query);
00368 return false;
00369 }
00370
00380 vector<uint> CardUtil::GetCardIDs(const QString &videodevice,
00381 QString rawtype,
00382 QString hostname)
00383 {
00384 vector<uint> list;
00385
00386 if (hostname.isEmpty())
00387 hostname = gContext->GetHostName();
00388
00389 MSqlQuery query(MSqlQuery::InitCon());
00390 QString qstr =
00391 "SELECT cardid "
00392 "FROM capturecard "
00393 "WHERE videodevice = :DEVICE AND "
00394 " hostname = :HOSTNAME";
00395
00396 if (!rawtype.isEmpty())
00397 qstr += " AND cardtype = :CARDTYPE";
00398
00399 qstr += " ORDER BY cardid";
00400
00401 query.prepare(qstr);
00402
00403 query.bindValue(":DEVICE", videodevice);
00404 query.bindValue(":HOSTNAME", hostname);
00405
00406 if (!rawtype.isEmpty())
00407 query.bindValue(":CARDTYPE", rawtype.upper());
00408
00409 if (!query.exec())
00410 MythContext::DBError("CardUtil::GetCardIDs(videodevice...)", query);
00411 else
00412 {
00413 while (query.next())
00414 list.push_back(query.value(0).toUInt());
00415 }
00416
00417 return list;
00418 }
00419
00420 static uint clone_capturecard(uint src_cardid, uint orig_dst_cardid)
00421 {
00422 uint dst_cardid = orig_dst_cardid;
00423
00424 MSqlQuery query(MSqlQuery::InitCon());
00425 if (!dst_cardid)
00426 {
00427 query.prepare(
00428 "DELETE FROM capturecard "
00429 "WHERE videodevice = 'temp_dummy'");
00430
00431 if (!query.exec())
00432 {
00433 MythContext::DBError("clone_capturecard -- delete temp", query);
00434 return 0;
00435 }
00436
00437 query.prepare(
00438 "INSERT INTO capturecard "
00439 "SET videodevice = 'temp_dummy'");
00440
00441 if (!query.exec())
00442 {
00443 MythContext::DBError("clone_capturecard -- insert temp", query);
00444 return 0;
00445 }
00446
00447 query.prepare(
00448 "SELECT cardid "
00449 "FROM capturecard "
00450 "WHERE videodevice = 'temp_dummy'");
00451
00452 if (!query.exec())
00453 {
00454 MythContext::DBError("clone_capturecard -- get temp id", query);
00455 return 0;
00456 }
00457
00458 if (!query.next())
00459 {
00460 VERBOSE(VB_IMPORTANT, "clone_capturecard -- get temp id");
00461 return 0;
00462 }
00463
00464 dst_cardid = query.value(0).toUInt();
00465 }
00466
00467 query.prepare(
00468 "SELECT videodevice, cardtype, defaultinput, "
00469 " hostname, signal_timeout, channel_timeout, "
00470 " dvb_wait_for_seqstart, dvb_on_demand, dvb_tuning_delay, "
00471 " dvb_diseqc_type, diseqcid, dvb_eitscan "
00472 "FROM capturecard "
00473 "WHERE cardid = :CARDID");
00474 query.bindValue(":CARDID", src_cardid);
00475
00476 if (!query.exec())
00477 {
00478 MythContext::DBError("clone_capturecard -- get data", query);
00479 return 0;
00480 }
00481 if (!query.next())
00482 {
00483 VERBOSE(VB_IMPORTANT, "clone_cardinput -- get data 2");
00484 return 0;
00485 }
00486
00487 MSqlQuery query2(MSqlQuery::InitCon());
00488 query2.prepare(
00489 "UPDATE capturecard "
00490 "SET videodevice = :V0, "
00491 " cardtype = :V1, "
00492 " defaultinput = :V2, "
00493 " hostname = :V3, "
00494 " signal_timeout = :V4, "
00495 " channel_timeout = :V5, "
00496 " dvb_wait_for_seqstart = :V6, "
00497 " dvb_on_demand = :V7, "
00498 " dvb_tuning_delay = :V8, "
00499 " dvb_diseqc_type = :V9, "
00500 " diseqcid = :V10,"
00501 " dvb_eitscan = :V11 "
00502 "WHERE cardid = :CARDID");
00503 for (uint i = 0; i < 12; i++)
00504 query2.bindValue(QString(":V%1").arg(i), query.value(i).toString());
00505 query2.bindValue(":CARDID", dst_cardid);
00506
00507 if (!query2.exec())
00508 {
00509 MythContext::DBError("clone_capturecard -- save data", query2);
00510 if (!orig_dst_cardid)
00511 CardUtil::DeleteCard(dst_cardid);
00512 return 0;
00513 }
00514
00515 return dst_cardid;
00516 }
00517
00518 bool clone_cardinputs(uint src_cardid, uint dst_cardid)
00519 {
00520 vector<uint> src_inputs = CardUtil::GetInputIDs(src_cardid);
00521 vector<uint> dst_inputs = CardUtil::GetInputIDs(dst_cardid);
00522 vector<QString> src_names;
00523 vector<QString> dst_names;
00524 QMap<uint,bool> dst_keep;
00525
00526 for (uint i = 0; i < src_inputs.size(); i++)
00527 src_names.push_back(CardUtil::GetInputName(src_inputs[i]));
00528
00529 for (uint i = 0; i < dst_inputs.size(); i++)
00530 dst_names.push_back(CardUtil::GetInputName(dst_inputs[i]));
00531
00532 bool ok = true;
00533
00534 MSqlQuery query(MSqlQuery::InitCon());
00535 MSqlQuery query2(MSqlQuery::InitCon());
00536
00537 for (uint i = 0; i < src_inputs.size(); i++)
00538 {
00539 query.prepare(
00540 "SELECT sourceid, inputname, externalcommand, "
00541 " preference, tunechan, startchan, "
00542 " freetoaironly, displayname, radioservices, "
00543 " dishnet_eit, recpriority, quicktune "
00544 "FROM cardinput "
00545 "WHERE cardinputid = :INPUTID");
00546 query.bindValue(":INPUTID", src_inputs[i]);
00547 if (!query.exec())
00548 {
00549 MythContext::DBError("clone_cardinput -- get data", query);
00550 ok = false;
00551 break;
00552 }
00553 if (!query.next())
00554 {
00555 VERBOSE(VB_IMPORTANT, "clone_cardinput -- get data 2");
00556 ok = false;
00557 break;
00558 }
00559
00560 int match = -1;
00561 for (uint j = 0; j < dst_inputs.size(); j++)
00562 {
00563 if (src_names[i] == dst_names[j])
00564 {
00565 match = (int) j;
00566 break;
00567 }
00568 }
00569
00570 uint dst_inputid = 0;
00571 if (match >= 0)
00572 {
00573 dst_keep[match] = true;
00574
00575
00576 query2.prepare(
00577 "UPDATE cardinput "
00578 "SET sourceid = :V0, "
00579 " inputname = :V1, "
00580 " externalcommand = :V2, "
00581 " preference = :V3, "
00582 " tunechan = :V4, "
00583 " startchan = :V5, "
00584 " freetoaironly = :V6, "
00585 " displayname = :V7, "
00586 " radioservices = :V8, "
00587 " dishnet_eit = :V9, "
00588 " recpriority = :V10, "
00589 " quicktune = :V11 "
00590 "WHERE cardinputid = :INPUTID");
00591
00592 for (uint j = 0; j < 12; j++)
00593 {
00594 query2.bindValue(QString(":V%1").arg(j),
00595 query.value(j).toString());
00596 }
00597 query2.bindValue(":INPUTID", dst_inputs[match]);
00598
00599 if (!query2.exec())
00600 {
00601 MythContext::DBError("clone_cardinput -- update data", query2);
00602 ok = false;
00603 break;
00604 }
00605
00606 dst_inputid = dst_inputs[match];
00607 }
00608 else
00609 {
00610
00611
00612 query2.prepare(
00613 "INSERT cardinput "
00614 "SET cardid = :CARDID, "
00615 " sourceid = :V0, "
00616 " inputname = :V1, "
00617 " externalcommand = :V2, "
00618 " preference = :V3, "
00619 " tunechan = :V4, "
00620 " startchan = :V5, "
00621 " freetoaironly = :V6, "
00622 " displayname = :V7, "
00623 " radioservices = :V8, "
00624 " dishnet_eit = :V9, "
00625 " recpriority = :V10, "
00626 " quicktune = :V11 ");
00627
00628 query2.bindValue(":CARDID", dst_cardid);
00629 for (uint j = 0; j < 12; j++)
00630 {
00631 query2.bindValue(QString(":V%1").arg(j),
00632 query.value(j).toString());
00633 }
00634
00635 if (!query2.exec())
00636 {
00637 MythContext::DBError("clone_cardinput -- insert data", query2);
00638 ok = false;
00639 break;
00640 }
00641
00642 query2.prepare(
00643 "SELECT cardinputid "
00644 "FROM cardinput "
00645 "WHERE cardid = :CARDID AND "
00646 " inputname = :NAME");
00647 query2.bindValue(":CARDID", dst_cardid);
00648 query2.bindValue(":NAME", query.value(1).toString());
00649 if (!query2.exec())
00650 {
00651 MythContext::DBError("clone_cardinput -- "
00652 "insert, query inputid", query2);
00653 ok = false;
00654 break;
00655 }
00656 if (!query2.next())
00657 {
00658 VERBOSE(VB_IMPORTANT, "clone_cardinput -- insert failed");
00659 ok = false;
00660 break;
00661 }
00662
00663 dst_inputid = query2.value(0).toUInt();
00664 }
00665
00666
00667 vector<uint> src_grps = CardUtil::GetInputGroups(src_inputs[i]);
00668 vector<uint> dst_grps = CardUtil::GetInputGroups(dst_inputid);
00669 for (uint j = 0; j < dst_grps.size(); j++)
00670 CardUtil::UnlinkInputGroup(dst_inputid, dst_grps[j]);
00671 for (uint j = 0; j < src_grps.size(); j++)
00672 CardUtil::LinkInputGroup(dst_inputid, src_grps[j]);
00673
00674
00675 DiSEqCDevSettings diseqc;
00676 if (diseqc.Load(src_inputs[i]))
00677 diseqc.Store(dst_inputid);
00678 }
00679
00680
00681 for (uint i = 0; i < dst_inputs.size(); i++)
00682 {
00683 if (!dst_keep[i])
00684 ok &= CardUtil::DeleteInput(dst_inputs[i]);
00685 }
00686
00687 return ok;
00688 }
00689
00690 bool CardUtil::CloneCard(uint src_cardid, uint orig_dst_cardid)
00691 {
00692 QString type = CardUtil::GetRawCardType(src_cardid);
00693 if (!IsTunerSharingCapable(type))
00694 return false;
00695
00696 uint dst_cardid = clone_capturecard(src_cardid, orig_dst_cardid);
00697 if (!dst_cardid)
00698 return false;
00699
00700 if (!clone_cardinputs(src_cardid, dst_cardid) && !orig_dst_cardid)
00701 {
00702 DeleteCard(dst_cardid);
00703 return false;
00704 }
00705
00706 return true;
00707 }
00708
00709 vector<uint> CardUtil::GetCloneCardIDs(uint cardid)
00710 {
00711 vector<uint> list;
00712 MSqlQuery query(MSqlQuery::InitCon());
00713 query.prepare(
00714 "SELECT cardtype, videodevice, hostname "
00715 "FROM capturecard "
00716 "WHERE cardid = :CARDID");
00717 query.bindValue(":CARDID", cardid);
00718
00719 if (!query.exec())
00720 {
00721 MythContext::DBError("CardUtil::GetCloneCardIDs() 1", query);
00722 return list;
00723 }
00724
00725 if (!query.next())
00726 return list;
00727
00728 QString rawtype = query.value(0).toString();
00729 QString videodevice = query.value(1).toString();
00730 QString hostname = query.value(2).toString();
00731
00732 if (!IsTunerSharingCapable(rawtype))
00733 return list;
00734
00735 query.prepare(
00736 "SELECT cardid "
00737 "FROM capturecard "
00738 "WHERE cardid != :CARDID AND "
00739 " videodevice = :DEVICE AND "
00740 " cardtype = :TYPE AND "
00741 " hostname = :HOSTNAME");
00742 query.bindValue(":CARDID", cardid);
00743 query.bindValue(":DEVICE", videodevice);
00744 query.bindValue(":TYPE", rawtype);
00745 query.bindValue(":HOSTNAME", hostname);
00746
00747 if (!query.exec())
00748 {
00749 MythContext::DBError("CardUtil::GetCloneCardIDs() 2", query);
00750 return list;
00751 }
00752
00753 while (query.next())
00754 list.push_back(query.value(0).toUInt());
00755
00756 return list;
00757 }
00758
00759 vector<uint> CardUtil::GetCardIDs(uint sourceid)
00760 {
00761 MSqlQuery query(MSqlQuery::InitCon());
00762
00763 query.prepare(
00764 "SELECT DISTINCT cardid "
00765 "FROM cardinput "
00766 "WHERE sourceid = :SOURCEID");
00767 query.bindValue(":SOURCEID", sourceid);
00768
00769 vector<uint> list;
00770
00771 if (!query.exec())
00772 {
00773 MythContext::DBError("CardUtil::GetCardIDs()", query);
00774 return list;
00775 }
00776
00777 while (query.next())
00778 list.push_back(query.value(0).toUInt());
00779
00780 return list;
00781 }
00782
00788 QString CardUtil::GetDefaultInput(uint nCardID)
00789 {
00790 QString str = QString::null;
00791 MSqlQuery query(MSqlQuery::InitCon());
00792 query.prepare("SELECT defaultinput "
00793 "FROM capturecard "
00794 "WHERE capturecard.cardid = :CARDID");
00795 query.bindValue(":CARDID", nCardID);
00796
00797 if (!query.exec() || !query.isActive())
00798 MythContext::DBError("CardUtil::GetDefaultInput()", query);
00799 else if (query.next())
00800 str = query.value(0).toString();
00801
00802 return str;
00803 }
00804
00805 QStringList CardUtil::GetInputNames(uint cardid, uint sourceid)
00806 {
00807 QStringList list;
00808 MSqlQuery query(MSqlQuery::InitCon());
00809 query.prepare("SELECT inputname "
00810 "FROM cardinput "
00811 "WHERE sourceid = :SOURCEID AND "
00812 " cardid = :CARDID");
00813 query.bindValue(":SOURCEID", sourceid);
00814 query.bindValue(":CARDID", cardid);
00815
00816 if (!query.exec() || !query.isActive())
00817 {
00818 MythContext::DBError("CardUtil::GetInputNames()", query);
00819 }
00820 else
00821 {
00822 while (query.next())
00823 list = query.value(0).toString();
00824 }
00825
00826 return list;
00827 }
00828
00829 bool CardUtil::GetInputInfo(InputInfo &input, vector<uint> *groupids)
00830 {
00831 if (!input.inputid)
00832 return false;
00833
00834 MSqlQuery query(MSqlQuery::InitCon());
00835 query.prepare("SELECT inputname, sourceid, cardid "
00836 "FROM cardinput "
00837 "WHERE cardinputid = :INPUTID");
00838 query.bindValue(":INPUTID", input.inputid);
00839
00840 if (!query.exec())
00841 {
00842 MythContext::DBError("CardUtil::GetInputInfo()", query);
00843 return false;
00844 }
00845
00846 if (!query.next())
00847 return false;
00848
00849 input.name = query.value(0).toString();
00850 input.sourceid = query.value(1).toUInt();
00851 input.cardid = query.value(2).toUInt();
00852
00853 if (groupids)
00854 *groupids = GetInputGroups(input.inputid);
00855
00856 return true;
00857 }
00858
00859 uint CardUtil::GetCardID(uint inputid)
00860 {
00861 InputInfo info(QString::null, 0, inputid, 0, 0);
00862 GetInputInfo(info);
00863 return info.cardid;
00864 }
00865
00866 QString CardUtil::GetInputName(uint inputid)
00867 {
00868 InputInfo info(QString::null, 0, inputid, 0, 0);
00869 GetInputInfo(info);
00870 return info.name;
00871 }
00872
00873 QString CardUtil::GetDisplayName(uint inputid)
00874 {
00875 MSqlQuery query(MSqlQuery::InitCon());
00876 query.prepare("SELECT displayname "
00877 "FROM cardinput "
00878 "WHERE cardinputid = :INPUTID");
00879 query.bindValue(":INPUTID", inputid);
00880
00881 if (!query.exec())
00882 MythContext::DBError("CardUtil::GetDisplayName(uint)", query);
00883 else if (query.next())
00884 return QString::fromUtf8(query.value(0).toString());
00885
00886 return QString::null;
00887 }
00888
00889 QString CardUtil::GetDisplayName(uint cardid, const QString &inputname)
00890 {
00891 MSqlQuery query(MSqlQuery::InitCon());
00892 query.prepare("SELECT displayname "
00893 "FROM cardinput "
00894 "WHERE inputname = :INPUTNAME AND "
00895 " cardid = :CARDID");
00896 query.bindValue(":INPUTNAME", inputname);
00897 query.bindValue(":CARDID", cardid);
00898
00899 if (!query.exec())
00900 MythContext::DBError("CardUtil::GetDisplayName(uint,QString)", query);
00901 else if (query.next())
00902 return QString::fromUtf8(query.value(0).toString());
00903
00904 return QString::null;
00905 }
00906
00907 vector<uint> CardUtil::GetInputIDs(uint cardid)
00908 {
00909 vector<uint> list;
00910
00911 MSqlQuery query(MSqlQuery::InitCon());
00912 query.prepare(
00913 "SELECT cardinputid "
00914 "FROM cardinput "
00915 "WHERE cardid = :CARDID");
00916
00917 query.bindValue(":CARDID", cardid);
00918
00919 if (!query.exec())
00920 {
00921 MythContext::DBError("CardUtil::GetInputIDs(uint)", query);
00922 return list;
00923 }
00924
00925 while (query.next())
00926 list.push_back(query.value(0).toUInt());
00927
00928 return list;
00929 }
00930
00931 bool CardUtil::DeleteInput(uint inputid)
00932 {
00933 MSqlQuery query(MSqlQuery::InitCon());
00934 query.prepare(
00935 "DELETE FROM cardinput "
00936 "WHERE cardinputid = :INPUTID");
00937 query.bindValue(":INPUTID", inputid);
00938
00939 if (!query.exec())
00940 {
00941 MythContext::DBError("DeleteInput", query);
00942 return false;
00943 }
00944
00945 return true;
00946 }
00947
00948 bool CardUtil::DeleteOrphanInputs(void)
00949 {
00950 MSqlQuery query(MSqlQuery::InitCon());
00951 query.prepare("SELECT cardinputid "
00952 "FROM cardinput "
00953 "LEFT JOIN capturecard "
00954 "ON (capturecard.cardid = cardinput.cardid) "
00955 "WHERE capturecard.cardid IS NULL");
00956 if (!query.exec())
00957 {
00958 MythContext::DBError("DeleteOrphanInputs -- query disconnects", query);
00959 return false;
00960 }
00961
00962 bool ok = true;
00963 while (query.next())
00964 {
00965 uint inputid = query.value(0).toUInt();
00966 if (DeleteInput(inputid))
00967 {
00968 VERBOSE(VB_IMPORTANT, QString("DeleteOrphanInputs -- ") +
00969 QString("Removed orphan input %1").arg(inputid));
00970 }
00971 else
00972 {
00973 ok = false;
00974 VERBOSE(VB_IMPORTANT, QString("DeleteOrphanInputs -- ") +
00975 QString("Failed to remove orphan input %1")
00976 .arg(inputid));
00977 }
00978 }
00979
00980 return ok;
00981 }
00982
00983 uint CardUtil::CreateInputGroup(const QString &name)
00984 {
00985 MSqlQuery query(MSqlQuery::InitCon());
00986 query.prepare("SELECT MAX(inputgroupid) FROM inputgroup");
00987 if (!query.exec())
00988 {
00989 MythContext::DBError("CreateNewInputGroup 1", query);
00990 return 0;
00991 }
00992 uint inputgroupid = (query.next()) ? query.value(0).toUInt() + 1 : 1;
00993
00994 query.prepare(
00995 "INSERT INTO inputgroup "
00996 " (cardinputid, inputgroupid, inputgroupname) "
00997 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
00998
00999 query.bindValue(":INPUTID", 0);
01000 query.bindValue(":GROUPID", inputgroupid);
01001 query.bindValue(":GROUPNAME", name.utf8());
01002
01003 if (!query.exec())
01004 {
01005 MythContext::DBError("CreateNewInputGroup 2", query);
01006 return 0;
01007 }
01008
01009 return inputgroupid;
01010 }
01011
01012 bool CardUtil::CreateInputGroupIfNeeded(uint cardid)
01013 {
01014
01015
01016 vector<uint> ingrps = CardUtil::GetSharedInputGroups(cardid);
01017 vector<uint> inputs = CardUtil::GetInputIDs(cardid);
01018
01019 if (ingrps.empty() && !inputs.empty())
01020 {
01021 QString dev = CardUtil::GetVideoDevice(cardid);
01022 QString name = QString::null;
01023 uint id = 0;
01024 for (uint i = 0; !id && (i < 100); i++)
01025 {
01026 name = QString("DVB%1").arg(dev.toUInt());
01027 name += (i) ? QString(":%1").arg(i) : QString("");
01028 id = CardUtil::CreateInputGroup(name);
01029 }
01030 if (!id)
01031 {
01032 VERBOSE(VB_IMPORTANT, "Failed to create input group");
01033 return false;
01034 }
01035
01036 bool ok = true;
01037 for (uint i = 0; i < inputs.size(); i++)
01038 ok &= CardUtil::LinkInputGroup(inputs[i], id);
01039
01040 if (!ok)
01041 VERBOSE(VB_IMPORTANT, "Failed to link to new input group");
01042
01043 return ok;
01044 }
01045
01046 return true;
01047 }
01048
01049 bool CardUtil::LinkInputGroup(uint inputid, uint inputgroupid)
01050 {
01051 MSqlQuery query(MSqlQuery::InitCon());
01052
01053 query.prepare(
01054 "SELECT cardinputid, inputgroupid, inputgroupname "
01055 "FROM inputgroup "
01056 "WHERE inputgroupid = :GROUPID "
01057 "ORDER BY inputgroupid, cardinputid, inputgroupname");
01058 query.bindValue(":GROUPID", inputgroupid);
01059
01060 if (!query.exec())
01061 {
01062 MythContext::DBError("CardUtil::CreateInputGroup() 1", query);
01063 return false;
01064 }
01065
01066 if (!query.next())
01067 return false;
01068
01069 const QString name = QString::fromUtf8(query.value(2).toString());
01070
01071 query.prepare(
01072 "INSERT INTO inputgroup "
01073 " (cardinputid, inputgroupid, inputgroupname) "
01074 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
01075
01076 query.bindValue(":INPUTID", inputid);
01077 query.bindValue(":GROUPID", inputgroupid);
01078 query.bindValue(":GROUPNAME", name.utf8());
01079
01080 if (!query.exec())
01081 {
01082 MythContext::DBError("CardUtil::CreateInputGroup() 2", query);
01083 return false;
01084 }
01085
01086 return true;
01087 }
01088
01089 bool CardUtil::UnlinkInputGroup(uint inputid, uint inputgroupid)
01090 {
01091 MSqlQuery query(MSqlQuery::InitCon());
01092
01093 if (!inputid && !inputgroupid)
01094 {
01095 query.prepare(
01096 "DELETE FROM inputgroup "
01097 "WHERE cardinputid = 0 ");
01098 }
01099 else
01100 {
01101 query.prepare(
01102 "DELETE FROM inputgroup "
01103 "WHERE cardinputid = :INPUTID AND "
01104 " inputgroupid = :GROUPID ");
01105
01106 query.bindValue(":INPUTID", inputid);
01107 query.bindValue(":GROUPID", inputgroupid);
01108 }
01109
01110 if (!query.exec())
01111 {
01112 MythContext::DBError("CardUtil::DeleteInputGroup()", query);
01113 return false;
01114 }
01115
01116 return true;
01117 }
01118
01119 vector<uint> CardUtil::GetInputGroups(uint inputid)
01120 {
01121 vector<uint> list;
01122
01123 MSqlQuery query(MSqlQuery::InitCon());
01124
01125 query.prepare(
01126 "SELECT inputgroupid "
01127 "FROM inputgroup "
01128 "WHERE cardinputid = :INPUTID "
01129 "ORDER BY inputgroupid, cardinputid, inputgroupname");
01130
01131 query.bindValue(":INPUTID", inputid);
01132
01133 if (!query.exec())
01134 {
01135 MythContext::DBError("CardUtil::GetInputGroups()", query);
01136 return list;
01137 }
01138
01139 while (query.next())
01140 list.push_back(query.value(0).toUInt());
01141
01142 return list;
01143 }
01144
01145 vector<uint> CardUtil::GetSharedInputGroups(uint cardid)
01146 {
01147 vector<uint> list;
01148
01149 vector<uint> inputs = GetInputIDs(cardid);
01150 if (inputs.empty())
01151 return list;
01152
01153 list = GetInputGroups(inputs[0]);
01154 for (uint i = 1; (i < inputs.size()) && list.size(); i++)
01155 {
01156 vector<uint> curlist = GetInputGroups(inputs[i]);
01157 vector<uint> newlist;
01158 for (uint j = 0; j < list.size(); j++)
01159 {
01160 if (find(curlist.begin(), curlist.end(), list[j]) != curlist.end())
01161 newlist.push_back(list[j]);
01162 }
01163 list = newlist;
01164 }
01165
01166 return list;
01167 }
01168
01169 vector<uint> CardUtil::GetGroupCardIDs(uint inputgroupid)
01170 {
01171 vector<uint> list;
01172
01173 MSqlQuery query(MSqlQuery::InitCon());
01174
01175 query.prepare(
01176 "SELECT DISTINCT cardid "
01177 "FROM cardinput, inputgroup "
01178 "WHERE inputgroupid = :GROUPID AND "
01179 " cardinput.cardinputid = inputgroup.cardinputid "
01180 "ORDER BY cardid");
01181
01182 query.bindValue(":GROUPID", inputgroupid);
01183
01184 if (!query.exec())
01185 {
01186 MythContext::DBError("CardUtil::GetGroupCardIDs()", query);
01187 return list;
01188 }
01189
01190 while (query.next())
01191 list.push_back(query.value(0).toUInt());
01192
01193 return list;
01194 }
01195
01196 vector<uint> CardUtil::GetConflictingCards(uint inputid, uint exclude_cardid)
01197 {
01198 vector<uint> inputgroupids = CardUtil::GetInputGroups(inputid);
01199
01200 for (uint i = 0; i < inputgroupids.size(); i++)
01201 {
01202 VERBOSE(VB_RECORD, LOC +
01203 QString(" Group ID %1").arg(inputgroupids[i]));
01204 }
01205
01206 vector<uint> cardids;
01207 for (uint i = 0; i < inputgroupids.size(); i++)
01208 {
01209 vector<uint> tmp = CardUtil::GetGroupCardIDs(inputgroupids[i]);
01210 for (uint j = 0; j < tmp.size(); j++)
01211 {
01212 if (tmp[j] == exclude_cardid)
01213 continue;
01214
01215 if (find(cardids.begin(), cardids.end(), tmp[j]) != cardids.end())
01216 continue;
01217
01218 cardids.push_back(tmp[j]);
01219 }
01220 }
01221
01222 for (uint i = 0; i < cardids.size(); i++)
01223 VERBOSE(VB_RECORD, LOC + QString(" Card ID %1").arg(cardids[i]));
01224
01225 return cardids;
01226 }
01227
01228 bool CardUtil::GetTimeouts(uint cardid,
01229 uint &signal_timeout, uint &channel_timeout)
01230 {
01231 MSqlQuery query(MSqlQuery::InitCon());
01232 query.prepare(
01233 "SELECT signal_timeout, channel_timeout "
01234 "FROM capturecard "
01235 "WHERE cardid = :CARDID");
01236 query.bindValue(":CARDID", cardid);
01237
01238 if (!query.exec() || !query.isActive())
01239 MythContext::DBError("CardUtil::GetTimeouts()", query);
01240 else if (query.next())
01241 {
01242 signal_timeout = (uint) max(query.value(0).toInt(), 250);
01243 channel_timeout = (uint) max(query.value(1).toInt(), 500);
01244 return true;
01245 }
01246
01247 return false;
01248 }
01249
01250 bool CardUtil::IgnoreEncrypted(uint cardid, const QString &input_name)
01251 {
01252 bool freetoair = true;
01253 MSqlQuery query(MSqlQuery::InitCon());
01254 query.prepare(
01255 "SELECT freetoaironly "
01256 "FROM cardinput "
01257 "WHERE cardid = :CARDID AND "
01258 " inputname = :INPUTNAME");
01259 query.bindValue(":CARDID", cardid);
01260 query.bindValue(":INPUTNAME", input_name);
01261
01262 if (!query.exec() || !query.isActive())
01263 MythContext::DBError("CardUtil::IgnoreEncrypted()", query);
01264 else if (query.next())
01265 freetoair = query.value(0).toBool();
01266
01267 return freetoair;
01268 }
01269
01270 bool CardUtil::TVOnly(uint cardid, const QString &input_name)
01271 {
01272 bool radioservices = true;
01273
01274 MSqlQuery query(MSqlQuery::InitCon());
01275 query.prepare(
01276 "SELECT radioservices "
01277 "FROM cardinput "
01278 "WHERE cardid = :CARDID AND "
01279 " inputname = :INPUTNAME");
01280 query.bindValue(":CARDID", cardid);
01281 query.bindValue(":INPUTNAME", input_name);
01282
01283 if (!query.exec() || !query.isActive())
01284 MythContext::DBError("CardUtil::TVOnly()", query);
01285 else if (query.next())
01286 radioservices = query.value(0).toBool();
01287
01288 return !radioservices;
01289 }
01290
01291 bool CardUtil::IsInNeedOfExternalInputConf(uint cardid)
01292 {
01293 DiSEqCDev dev;
01294 DiSEqCDevTree *diseqc_tree = dev.FindTree(cardid);
01295
01296 bool needsConf = false;
01297 if (diseqc_tree)
01298 needsConf = diseqc_tree->IsInNeedOfConf();
01299
01300 return needsConf;
01301 }
01302
01303 uint CardUtil::GetQuickTuning(uint cardid, const QString &input_name)
01304 {
01305 uint quicktune = 0;
01306
01307 MSqlQuery query(MSqlQuery::InitCon());
01308 query.prepare(
01309 "SELECT quicktune "
01310 "FROM cardinput "
01311 "WHERE cardid = :CARDID AND "
01312 " inputname = :INPUTNAME");
01313 query.bindValue(":CARDID", cardid);
01314 query.bindValue(":INPUTNAME", input_name);
01315
01316 if (!query.exec() || !query.isActive())
01317 MythContext::DBError("CardUtil::GetQuickTuning()", query);
01318 else if (query.next())
01319 quicktune = query.value(0).toUInt();
01320
01321 return quicktune;
01322 }
01323
01324 bool CardUtil::hasV4L2(int videofd)
01325 {
01326 (void) videofd;
01327 #ifdef USING_V4L
01328 struct v4l2_capability vcap;
01329 bzero(&vcap, sizeof(vcap));
01330
01331 return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
01332 (vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE));
01333 #else // if !USING_V4L
01334 return false;
01335 #endif // !USING_V4L
01336 }
01337
01338 bool CardUtil::GetV4LInfo(
01339 int videofd, QString &card, QString &driver, uint32_t &version)
01340 {
01341 card = driver = QString::null;
01342 version = 0;
01343
01344 if (videofd < 0)
01345 return false;
01346
01347 #ifdef USING_V4L
01348
01349 struct v4l2_capability capability;
01350 bzero(&capability, sizeof(struct v4l2_capability));
01351 if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
01352 {
01353 card.setAscii((char*)capability.card);
01354 driver.setAscii((char*)capability.driver);
01355 version = capability.version;
01356 }
01357 else
01358 {
01359 struct video_capability capability;
01360 if (ioctl(videofd, VIDIOCGCAP, &capability) >= 0)
01361 card.setAscii((char*)capability.name);
01362 }
01363 #endif // !USING_V4L
01364
01365 return !card.isEmpty();
01366 }
01367
01368 InputNames CardUtil::probeV4LInputs(int videofd, bool &ok)
01369 {
01370 (void) videofd;
01371
01372 InputNames list;
01373 ok = false;
01374
01375 #ifdef USING_V4L
01376 bool usingv4l2 = hasV4L2(videofd);
01377
01378
01379 struct v4l2_input vin;
01380 bzero(&vin, sizeof(vin));
01381 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
01382 {
01383 QString input((char *)vin.name);
01384 list[vin.index] = input;
01385 vin.index++;
01386 }
01387 if (vin.index)
01388 {
01389 ok = true;
01390 return list;
01391 }
01392
01393
01394 struct video_capability vidcap;
01395 bzero(&vidcap, sizeof(vidcap));
01396 if (ioctl(videofd, VIDIOCGCAP, &vidcap) != 0)
01397 {
01398 QString msg = QObject::tr("Could not query inputs.");
01399 VERBOSE(VB_IMPORTANT, msg + ENO);
01400 list[-1] = msg;
01401 vidcap.channels = 0;
01402 }
01403
01404 for (int i = 0; i < vidcap.channels; i++)
01405 {
01406 struct video_channel test;
01407 bzero(&test, sizeof(test));
01408 test.channel = i;
01409
01410 if (ioctl(videofd, VIDIOCGCHAN, &test) != 0)
01411 {
01412 VERBOSE(VB_IMPORTANT,
01413 QString("Could determine name of input #%1"
01414 "\n\t\t\tNot adding it to the list.")
01415 .arg(test.channel) + ENO);
01416 continue;
01417 }
01418
01419 list[i] = test.name;
01420 }
01421
01422
01423 if (!list.size())
01424 list[0] = "Television";
01425
01426 ok = true;
01427 #else // if !USING_V4L
01428 list[-1] += QObject::tr("ERROR, Compile with V4L support to query inputs");
01429 #endif // !USING_V4L
01430 return list;
01431 }
01432
01433 InputNames CardUtil::GetConfiguredDVBInputs(uint cardid)
01434 {
01435 InputNames list;
01436 MSqlQuery query(MSqlQuery::InitCon());
01437 query.prepare(
01438 "SELECT cardinputid, inputname "
01439 "FROM cardinput "
01440 "WHERE cardid = :CARDID");
01441 query.bindValue(":CARDID", cardid);
01442
01443 if (!query.exec() || !query.isActive())
01444 MythContext::DBError("CardUtil::GetConfiguredDVBInputs", query);
01445 else
01446 {
01447 while (query.next())
01448 list[query.value(0).toUInt()] = query.value(1).toString();
01449 }
01450 return list;
01451 }
01452
01453 QStringList CardUtil::probeInputs(QString device, QString cardtype)
01454 {
01455 QStringList ret;
01456
01457 if (("FIREWIRE" == cardtype) ||
01458 ("FREEBOX" == cardtype) ||
01459 ("DBOX2" == cardtype) ||
01460 ("HDHOMERUN" == cardtype))
01461 {
01462 ret += "MPEG2TS";
01463 }
01464 else if ("DVB" == cardtype)
01465 ret += probeDVBInputs(device);
01466 else
01467 ret += probeV4LInputs(device);
01468
01469 return ret;
01470 }
01471
01472 QStringList CardUtil::probeV4LInputs(QString device)
01473 {
01474 bool ok;
01475 QStringList ret;
01476 int videofd = open(device.ascii(), O_RDWR);
01477 if (videofd < 0)
01478 {
01479 ret += QObject::tr("Could not open '%1' "
01480 "to probe its inputs.").arg(device);
01481 return ret;
01482 }
01483 InputNames list = CardUtil::probeV4LInputs(videofd, ok);
01484 close(videofd);
01485
01486 if (!ok)
01487 {
01488 ret += list[-1];
01489 return ret;
01490 }
01491
01492 InputNames::iterator it;
01493 for (it = list.begin(); it != list.end(); ++it)
01494 {
01495 if (it.key() >= 0)
01496 ret += *it;
01497 }
01498
01499 return ret;
01500 }
01501
01502 QStringList CardUtil::probeDVBInputs(QString device)
01503 {
01504 QStringList ret;
01505
01506 #ifdef USING_DVB
01507 uint cardid = CardUtil::GetFirstCardID(device);
01508 if (!cardid)
01509 return ret;
01510
01511 InputNames list = GetConfiguredDVBInputs(cardid);
01512 InputNames::iterator it;
01513 for (it = list.begin(); it != list.end(); ++it)
01514 {
01515 if (it.key())
01516 ret += *it;
01517 }
01518 #else
01519 (void) device;
01520 ret += QObject::tr("ERROR, Compile with DVB support to query inputs");
01521 #endif
01522
01523 return ret;
01524 }
01525
01526 QString CardUtil::GetDeviceLabel(uint cardid,
01527 QString cardtype,
01528 QString videodevice)
01529 {
01530 QString label = QString::null;
01531
01532 if (cardtype == "DBOX2")
01533 {
01534 MSqlQuery query(MSqlQuery::InitCon());
01535 query.prepare(
01536 "SELECT dbox2_host, dbox2_port, dbox2_httpport "
01537 "FROM capturecard "
01538 "WHERE cardid = :CARDID");
01539 query.bindValue(":CARDID", cardid);
01540
01541 if (!query.exec() || !query.isActive() || !query.next())
01542 label = "[ DB ERROR ]";
01543 else
01544 label = QString("[ DBOX2 : IP %1 Port %2 HttpPort %3 ]")
01545 .arg(query.value(0).toString())
01546 .arg(query.value(1).toString())
01547 .arg(query.value(2).toString());
01548 }
01549 else if (cardtype == "HDHOMERUN")
01550 {
01551 MSqlQuery query(MSqlQuery::InitCon());
01552 query.prepare(
01553 "SELECT dbox2_port "
01554 "FROM capturecard "
01555 "WHERE cardid = :CARDID");
01556 query.bindValue(":CARDID", cardid);
01557
01558 if (!query.exec() || !query.isActive() || !query.next())
01559 label = "[ DB ERROR ]";
01560 else
01561 label = QString("[ HDHomeRun : ID %1 Port %2 ]")
01562 .arg(videodevice).arg(query.value(0).toString());
01563 }
01564 else
01565 {
01566 label = QString("[ %1 : %2 ]").arg(cardtype).arg(videodevice);
01567 }
01568
01569 return label;
01570 }
01571
01572 void CardUtil::GetCardInputs(
01573 uint cardid,
01574 const QString &device,
01575 const QString &cardtype,
01576 QStringList &inputLabels,
01577 vector<CardInput*> &cardInputs)
01578 {
01579 QStringList inputs;
01580 bool is_dtv = !IsEncoder(cardtype) && !IsUnscanable(cardtype);
01581
01582 if (("FIREWIRE" == cardtype) ||
01583 ("FREEBOX" == cardtype) ||
01584 ("DBOX2" == cardtype) ||
01585 ("HDHOMERUN" == cardtype))
01586 {
01587 inputs += "MPEG2TS";
01588 }
01589 else if ("DVB" != cardtype)
01590 inputs += probeV4LInputs(device);
01591
01592 QString dev_label = GetDeviceLabel(cardid, cardtype, device);
01593
01594 QStringList::iterator it = inputs.begin();
01595 for (; it != inputs.end(); ++it)
01596 {
01597 CardInput *cardinput = new CardInput(is_dtv, false, false, cardid);
01598 cardinput->loadByInput(cardid, (*it));
01599 inputLabels.push_back(
01600 dev_label + QString(" (%1) -> %2")
01601 .arg(*it).arg(cardinput->getSourceName()));
01602 cardInputs.push_back(cardinput);
01603 }
01604
01605 #ifdef USING_DVB
01606 if ("DVB" == cardtype)
01607 {
01608 bool needs_conf = IsInNeedOfExternalInputConf(cardid);
01609 InputNames list = GetConfiguredDVBInputs(cardid);
01610 if (!needs_conf && list.empty())
01611 list[0] = "DVBInput";
01612
01613 InputNames::const_iterator it;
01614 for (it = list.begin(); it != list.end(); ++it)
01615 {
01616 CardInput *cardinput = new CardInput(is_dtv, true, false, cardid);
01617 cardinput->loadByInput(cardid, *it);
01618 inputLabels.push_back(
01619 dev_label + QString(" (%1) -> %2")
01620 .arg(*it).arg(cardinput->getSourceName()));
01621 cardInputs.push_back(cardinput);
01622 }
01623
01624
01625 if (needs_conf)
01626 {
01627 CardInput *newcard = new CardInput(is_dtv, true, true, cardid);
01628 QString newname = QString("DVBInput #%1").arg(list.size() + 1);
01629 newcard->loadByInput(cardid, newname);
01630 inputLabels.push_back(dev_label + " " + QObject::tr("New Input"));
01631 cardInputs.push_back(newcard);
01632 }
01633 }
01634 #endif // USING_DVB
01635 }
01636
01637 bool CardUtil::DeleteCard(uint cardid)
01638 {
01639 MSqlQuery query(MSqlQuery::InitCon());
01640 bool ok = true;
01641
01642 if (!cardid)
01643 return true;
01644
01645
01646 DiSEqCDevTree tree;
01647 tree.Load(cardid);
01648 if (!tree.Root())
01649 {
01650 tree.SetRoot(NULL);
01651 tree.Store(cardid);
01652 }
01653
01654
01655 QString rawtype = GetRawCardType(cardid);
01656 QString videodevice = GetVideoDevice(cardid);
01657 if (IsTunerSharingCapable(rawtype) && !videodevice.isEmpty())
01658 {
01659 query.prepare(
01660 "SELECT cardid "
01661 "FROM capturecard "
01662 "WHERE videodevice = :DEVICE AND "
01663 " cardid > :CARDID");
01664 query.bindValue(":DEVICE", videodevice);
01665 query.bindValue(":CARDID", cardid);
01666
01667 if (!query.exec())
01668 {
01669 MythContext::DBError("DeleteCard -- find clone cards", query);
01670 return false;
01671 }
01672
01673 while (query.next())
01674 ok &= DeleteCard(query.value(0).toUInt());
01675
01676 if (!ok)
01677 return false;
01678 }
01679
01680
01681 vector<uint> inputs = CardUtil::GetInputIDs(cardid);
01682 for (uint i = 0; i < inputs.size(); i++)
01683 ok &= CardUtil::DeleteInput(inputs[i]);
01684
01685 if (!ok)
01686 return false;
01687
01688
01689 query.prepare("DELETE FROM capturecard WHERE cardid = :CARDID");
01690 query.bindValue(":CARDID", cardid);
01691
01692 if (!query.exec())
01693 {
01694 MythContext::DBError("DeleteCard -- delete row", query);
01695 ok = false;
01696 }
01697
01698 if (ok)
01699 {
01700
01701 DeleteOrphanInputs();
01702 UnlinkInputGroup(0,0);
01703 }
01704
01705 return ok;
01706 }
01707
01708 bool CardUtil::DeleteAllCards(void)
01709 {
01710 MSqlQuery query(MSqlQuery::InitCon());
01711 return (query.exec("TRUNCATE TABLE inputgroup") &&
01712 query.exec("TRUNCATE TABLE diseqc_config") &&
01713 query.exec("TRUNCATE TABLE diseqc_tree") &&
01714 query.exec("TRUNCATE TABLE cardinput") &&
01715 query.exec("TRUNCATE TABLE capturecard"));
01716 }
01717
01718 vector<uint> CardUtil::GetCardList(void)
01719 {
01720 vector<uint> list;
01721
01722 MSqlQuery query(MSqlQuery::InitCon());
01723 query.prepare(
01724 "SELECT cardid "
01725 "FROM capturecard "
01726 "ORDER BY cardid");
01727
01728 if (!query.exec())
01729 MythContext::DBError("CardUtil::GetCardList()", query);
01730 else
01731 {
01732 while (query.next())
01733 list.push_back(query.value(0).toUInt());
01734 }
01735
01736 return list;
01737 }
01738
01739
01740 QString CardUtil::GetDeviceName(dvb_dev_type_t type, uint cardnum)
01741 {
01742 if (DVB_DEV_FRONTEND == type)
01743 return QString("/dev/dvb/adapter%1/frontend0").arg(cardnum);
01744 else if (DVB_DEV_DVR == type)
01745 return QString("/dev/dvb/adapter%1/dvr0").arg(cardnum);
01746 else if (DVB_DEV_DEMUX == type)
01747 return QString("/dev/dvb/adapter%1/demux0").arg(cardnum);
01748 else if (DVB_DEV_CA == type)
01749 return QString("/dev/dvb/adapter%1/ca0").arg(cardnum);
01750 else if (DVB_DEV_AUDIO == type)
01751 return QString("/dev/dvb/adapter%1/audio0").arg(cardnum);
01752 else if (DVB_DEV_VIDEO == type)
01753 return QString("/dev/dvb/adapter%1/video0").arg(cardnum);
01754
01755 return "";
01756 }