7#include "libmythbase/mythconfig.h"
9#if CONFIG_V4L2 || CONFIG_DVB
15#if QT_VERSION >= QT_VERSION_CHECK(6,5,0)
16#include <QtSystemDetection>
20#include <QRegularExpression>
46#include HDHOMERUN_HEADERFILE
61#include <dveo/master.h>
64#define LOC QString("CardUtil: ")
68 QStringList inputTypes {};
71 inputTypes +=
"'DVB'";
75 inputTypes +=
"'V4L'";
76 inputTypes +=
"'MPEG'";
80 inputTypes +=
"'FREEBOX'";
84 inputTypes +=
"'VBOX'";
88 inputTypes +=
"'HDHOMERUN'";
92 inputTypes +=
"'SATIP'";
96 inputTypes +=
"'ASI'";
100 inputTypes +=
"'CETON'";
104 inputTypes +=
"'EXTERNAL'";
107 if (inputTypes.isEmpty())
110 return QString(
"(%1)").arg(inputTypes.join(
','));
114 const QString &inputType)
116 if (inputType ==
"HDHOMERUN")
119 hdhomerun_tuner_status_t status {};
122 hdhomerun_device_create_from_str(device.toLatin1().constData(),
nullptr);
126 int oob = hdhomerun_device_get_oob_status(hdhr,
nullptr, &status);
130 if (oob > 0 && (strncmp(status.channel,
"none", 4) != 0))
132 LOG(VB_GENERAL, LOG_INFO,
"Cardutil: HDHomeRun Cablecard Present.");
133 hdhomerun_device_destroy(hdhr);
137 hdhomerun_device_destroy(hdhr);
142 if (inputType ==
"CETON")
147 QStringList parts = device.split(
"-");
148 if (parts.size() != 2)
150 LOG(VB_GENERAL, LOG_ERR,
151 QString(
"CardUtil: Ceton invalid device id %1").arg(device));
155 const QString& ip_address = parts.at(0);
157 QStringList tuner_parts = parts.at(1).split(
".");
158 if (tuner_parts.size() != 2)
160 LOG(VB_GENERAL, LOG_ERR,
LOC +
161 QString(
"CardUtil: Ceton invalid device id %1").arg(device));
165 uint tuner = tuner_parts.at(1).toUInt();
168 params.addQueryItem(
"i", QString::number(tuner));
169 params.addQueryItem(
"s",
"cas");
170 params.addQueryItem(
"v",
"CardStatus");
173 url.setScheme(
"http");
174 url.setHost(ip_address);
175 url.setPath(
"/get_var.json");
176 url.setQuery(params);
178 auto *request =
new QNetworkRequest();
179 request->setAttribute(QNetworkRequest::CacheLoadControlAttribute,
180 QNetworkRequest::AlwaysNetwork);
181 request->setUrl(url);
186 if (!
manager->download(request, &data))
188 LOG(VB_GENERAL, LOG_ERR,
189 QString(
"CardUtil: Ceton http request failed %1").arg(device));
193 QString response = QString(data);
195 static const QRegularExpression regex {
"^\\{ \"?result\"?: \"(.*)\" \\}$"};
196 auto match = regex.match(response);
197 if (!match.hasMatch())
199 LOG(VB_GENERAL, LOG_ERR,
200 QString(
"CardUtil: Ceton unexpected http response: %1").arg(response));
204 QString result = match.captured(1);
206 if (result ==
"Inserted")
208 LOG(VB_GENERAL, LOG_DEBUG,
"Cardutil: Ceton CableCARD present.");
212 LOG(VB_GENERAL, LOG_DEBUG,
"Cardutil: Ceton CableCARD not present.");
222 [[maybe_unused]]
const QString & device)
224 if (rawtype ==
"DVB" || rawtype ==
"HDHOMERUN" ||
225 rawtype ==
"FREEBOX" || rawtype ==
"CETON" ||
226 rawtype ==
"VBOX" || rawtype ==
"SATIP")
230 if (rawtype ==
"V4L2ENC")
237 if (rawtype ==
"EXTERNAL")
248 LOG(VB_GENERAL, LOG_DEBUG, QString(
"IsTunerShared(%1,%2)")
249 .arg(inputidA).arg(inputidB));
252 query.
prepare(
"SELECT videodevice, hostname, cardtype "
254 "WHERE ( (cardid = :INPUTID_A) OR "
255 " (cardid = :INPUTID_B) )");
268 const QString vdevice = query.
value(0).toString();
270 const QString inputtype = query.
value(2).toString();
278 bool ret = ((vdevice == query.
value(0).toString()) &&
280 (inputtype == query.
value(2).toString()));
282 LOG(VB_RECORD, LOG_DEBUG, QString(
"IsTunerShared(%1,%2) -> %3")
283 .arg(inputidA).arg(inputidB).arg(ret));
300 "SELECT count(cardtype) "
302 "WHERE capturecard.hostname = :HOSTNAME ";
304 if (!rawtype.isEmpty())
305 qstr +=
" AND capturecard.cardtype = :INPUTTYPE";
309 if (!rawtype.isEmpty())
310 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
322 count = query.
value(0).toUInt();
332 query.
prepare(
"SELECT DISTINCT cardtype, videodevice "
345 cardtype = query.
value(0).toString();
346 if (cardtype !=
"V4L2ENC")
348 inputtypes[cardtype] =
"";
356 QString driver_name =
"V4L2:" + v4l2.
DriverName();
357 inputtypes[driver_name] = v4l2.
CardName();
377 query.
prepare(
"SELECT cardtype "
379 "WHERE capturecard.sourceid = :SOURCEID "
380 "GROUP BY cardtype");
390 list.push_back(query.
value(0).toString());
411 "SELECT videodevice "
413 "WHERE hostname = :HOSTNAME";
415 if (!rawtype.isEmpty())
416 qstr +=
" AND cardtype = :INPUTTYPE";
420 if (!rawtype.isEmpty())
421 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
431 QMap<QString,bool> dup;
434 QString videodevice = query.
value(0).toString();
435 if (dup[videodevice])
438 list.push_back(videodevice);
439 dup[videodevice] =
true;
460 if (rawtype.toUpper() ==
"DVB")
462 QDir dir(
"/dev/dvb",
"adapter*", QDir::Name, QDir::Dirs);
463 QFileInfoList entries = dir.entryInfoList();
464 for (
const auto & it : std::as_const(entries))
466 QDir subdir(it.filePath(),
"frontend*", QDir::Name, QDir::Files | QDir::System);
467 const QFileInfoList subil = subdir.entryInfoList();
471 for (
const auto & subit : std::as_const(subil))
472 devs.push_back(subit.filePath());
475 else if (rawtype.toUpper() ==
"ASI")
477 QDir dir(
"/dev/",
"asirx*", QDir::Name, QDir::System);
478 QFileInfoList entries = dir.entryInfoList();
479 for (
const auto & it : std::as_const(entries))
483 devs.push_back(it.filePath());
490 else if (rawtype.toUpper() ==
"HDHOMERUN")
492#if HDHOMERUN_VERSION >= 20221010
493 struct hdhomerun_debug_t *dbg = hdhomerun_debug_create();
494 struct hdhomerun_discover_t *ds = hdhomerun_discover_create(dbg);
497 uint32_t
type { HDHOMERUN_DEVICE_TYPE_TUNER };
498 uint32_t flags { HDHOMERUN_DISCOVER_FLAGS_IPV4_GENERAL |
499 HDHOMERUN_DISCOVER_FLAGS_IPV6_GENERAL };
501 hdhomerun_discover2_find_devices_broadcast(ds, flags, &
type, 1);
505 LOG(VB_GENERAL, LOG_ERR,
"Error finding HDHomerun devices");
507 else if (result == 0)
509 LOG(VB_GENERAL, LOG_INFO,
"No HDHomerun devices found.");
514 struct hdhomerun_discover2_device_t *device = hdhomerun_discover2_iter_device_first(ds);
517 uint8_t tuners = hdhomerun_discover2_device_get_tuner_count(device);
518 uint32_t device_id = hdhomerun_discover2_device_get_device_id(device);
519 QString
id = QString(
"%1").arg(device_id, 0, 16, QChar(
'0')).toUpper();
520 auto *dev1 = hdhomerun_device_create_from_str(
id.toLatin1().constData(),
nullptr);
521 QString model = hdhomerun_device_get_model_str(dev1);
524 struct sockaddr_storage saddr {};
525 struct hdhomerun_discover2_device_if_t *device_if {
nullptr };
528 device_if = hdhomerun_discover2_iter_device_if_first(device);
531 hdhomerun_discover2_device_if_get_ip_addr(device_if, &saddr);
532 ip = QHostAddress((
struct sockaddr *)&saddr);
533 LOG(VB_GENERAL, LOG_DEBUG,
534 QString(
"HDHomerun %1 has IP %2").arg(
id, ip.toString()));
535 device_if = hdhomerun_discover2_iter_device_if_next(device_if);
539 device_if = hdhomerun_discover2_iter_device_if_first(device);
540 if (
nullptr == device_if)
542 LOG(VB_GENERAL, LOG_WARNING,
543 QString(
"HDHomerun %1 has no IP addresses").arg(
id));
546 hdhomerun_discover2_device_if_get_ip_addr(device_if, &saddr);
547 ip = QHostAddress((
struct sockaddr *)&saddr);
550 QString hdhrdev = QString(
"%1 %2 %3").arg(
id, ip.toString(), model);
551 devs.push_back(hdhrdev);
552 LOG(VB_GENERAL, LOG_INFO,
553 QString(
"HDHomerun %1: IP %2, model %3, %4 tuners")
554 .arg(
id, ip.toString(), model).arg(tuners));
556 device = hdhomerun_discover2_iter_device_next(device);
558 hdhomerun_discover_destroy(ds);
559 hdhomerun_debug_destroy(dbg);
561#elif HDHOMERUN_VERSION >= 20190625
562 uint32_t target_ip = 0;
563 uint32_t device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
564 uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
565 const int max_count = 50;
566 std::array<hdhomerun_discover_device_t,max_count> result_list {};
568 int result = hdhomerun_discover_find_devices_custom_v2(
569 target_ip, device_type, device_id, result_list.data(), result_list.size());
573 LOG(VB_GENERAL, LOG_ERR,
"Error finding HDHomerun devices");
576 if (result >= max_count)
578 LOG(VB_GENERAL, LOG_WARNING,
579 "Warning: may be > 50 HDHomerun devices");
583 for (
int i = 0; i < result; i++)
585 QString
id = QString(
"%1").arg(result_list[i].device_id, 0, 16);
586 QString ip = QString(
"%1.%2.%3.%4")
587 .arg((result_list[i].ip_addr>>24) & 0xFF)
588 .arg((result_list[i].ip_addr>>16) & 0xFF)
589 .arg((result_list[i].ip_addr>> 8) & 0xFF)
590 .arg((result_list[i].ip_addr>> 0) & 0xFF);
594 result_list[i].device_id, 0, 0,
nullptr);
597 model = hdhomerun_device_get_model_str(device);
598 hdhomerun_device_destroy(device);
601 QString hdhrdev =
id.toUpper() +
" " + ip +
" " + model;
602 devs.push_back(hdhrdev);
605 #error Unsupported version of libhhomerun
610 else if (rawtype.toUpper() ==
"SATIP")
616 else if (rawtype.toUpper() ==
"VBOX")
622 else if (rawtype.toUpper() ==
"CETON")
625 LOG(VB_GENERAL, LOG_INFO,
"CardUtil::ProbeVideoDevices: "
626 "TODO Probe Ceton devices");
631 LOG(VB_GENERAL, LOG_ERR, QString(
"Raw Type: '%1' is not supported")
642 QStringList delsyslist;
651 struct dtv_property prop = {};
652 struct dtv_properties cmd = {};
654 prop.cmd = DTV_API_VERSION;
657 if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
659 LOG(VB_GENERAL, LOG_DEBUG,
660 QString(
"CardUtil(%1): ").arg(device) +
661 QString(
"dvb api version %1.%2").arg((prop.u.data>>8)&0xff).arg((prop.u.data)&0xff));
665 LOG(VB_GENERAL, LOG_ERR,
666 QString(
"CardUtil(%1) FE_GET_PROPERTY ioctl failed").arg(device) +
ENO);
673 QString msg =
"Delivery systems:";
674 for (
const auto & item : std::as_const(delsyslist))
679 LOG(VB_GENERAL, LOG_INFO, QString(
"CardUtil(%1): ").arg(device) + msg);
690 QStringList delsyslist;
693 struct dtv_property prop = {};
694 struct dtv_properties cmd = {};
696 prop.cmd = DTV_ENUM_DELSYS;
699 if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
701 for (
unsigned int i = 0; i < prop.u.buffer.len; i++)
708 LOG(VB_GENERAL, LOG_ERR,
LOC +
"FE_GET_PROPERTY ioctl failed " +
ENO);
733 QString ret =
"ERROR_UNKNOWN";
735 if (device.isEmpty())
740 ret = (
type.toString() !=
"UNKNOWN") ?
type.toString().toUpper() : ret;
742 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"(%1) tuner type:%2 %3")
743 .arg(device).arg(
type.toInt()).arg(ret));
754 QString ret =
"ERROR_UNKNOWN";
758 QByteArray dev = dvbdev.toLatin1();
759 int fd_frontend = open(dev.constData(), O_RDWR |
O_NONBLOCK);
763 struct dvb_frontend_info
info {};
764 int err = ioctl(fd_frontend, FE_GET_INFO, &
info);
768 return "ERROR_PROBE";
799 return ((name ==
"VLSI VES1x93 DVB-S") ||
800 (name ==
"ST STV0299 DVB-S"));
806 if (name.indexOf(
"DVB-S") >= 0)
808 if (name ==
"DiBcom 3000P/M-C DVB-T")
846 LOG(VB_GENERAL, LOG_ERR,
LOC +
847 QString(
"TODO Add to switch case delivery system:%2 %3")
887 "FROM dtv_multiplex "
888 "WHERE dtv_multiplex.mplexid = :MPLEXID");
899 LOG(VB_GENERAL, LOG_ERR,
LOC +
900 QString(
"Could not find entry in dtv_multiplex for mplexid %1")
927 if (device.isEmpty())
936 LOG(VB_GENERAL, LOG_ERR,
LOC +
937 QString(
"open failed (%1)")
944 LOG(VB_GENERAL, LOG_DEBUG, QString(
"CardUtil(%1): delsys:%2 %3")
959 struct dtv_property prop = {};
960 struct dtv_properties cmd = {};
962 prop.cmd = DTV_DELIVERY_SYSTEM;
967 int ret = ioctl(fd_frontend, FE_GET_PROPERTY, &cmd);
970 LOG(VB_GENERAL, LOG_ERR,
LOC +
971 QString(
"FE_GET_PROPERTY ioctl failed (fd_frontend:%1)")
972 .arg(fd_frontend) +
ENO);
976 delsys = prop.u.data;
1008 LOG(VB_GENERAL, LOG_INFO,
1009 QString(
"CardUtil[%1]: ").arg(inputid) +
1010 QString(
"Update capturecard delivery system: %1").arg(delsys.
toString()));
1014 LOG(VB_GENERAL, LOG_ERR,
1015 QString(
"CardUtil[%1]: Error probing best delivery system").arg(inputid));
1016 return "ERROR_UNKNOWN";
1023 QString subtype =
"ERROR_UNKNOWN";
1029 LOG(VB_GENERAL, LOG_DEBUG,
1030 QString(
"CardUtil[%1]: subtype:%2").arg(inputid).arg(subtype));
1038 QString
t = inputType.toUpper();
1039 return (
t ==
"DVB") || (
t ==
"QPSK") || (
t ==
"QAM") || (
t ==
"OFDM") ||
1040 (
t ==
"ATSC") || (
t ==
"DVB_S2") || (
t ==
"DVB_T2");
1055 LOG(VB_GENERAL, LOG_INFO,
LOC +
1056 QString(
"Current delivery system: %1").arg(delsys.
toString()));
1059 QString msg =
"Supported delivery systems:";
1061 msg.append(delsyslist.join(
" "));
1062 LOG(VB_GENERAL, LOG_DEBUG,
LOC + msg);
1068 if (delsyslist.contains(newdelsys.
toString()))
1070 LOG(VB_GENERAL, LOG_INFO,
LOC +
1071 QString(
"Changing delivery system from %1 to %2")
1081 if (delsyslist.contains(newdelsys.
toString()))
1083 LOG(VB_GENERAL, LOG_INFO,
LOC +
1084 QString(
"Changing delivery system from %1 to %2")
1098 [[maybe_unused]]
int fd)
1113 LOG(VB_GENERAL, LOG_INFO,
1114 QString(
"CardUtil[%1]: ").arg(inputid) +
1115 QString(
"No capturecard delivery system in database, using: %1").arg(delsys.
toString()));
1126 [[maybe_unused]]
int fd)
1166 if (device.isEmpty())
1168 LOG(VB_GENERAL, LOG_DEBUG,
1169 QString(
"CardUtil[%1]: ").arg(inputid) +
1170 QString(
"inputid:%1 ").arg(inputid) +
1171 QString(
"delsys:%1").arg(delsys.toString()));
1176 if (fd_frontend < 0)
1178 LOG(VB_GENERAL, LOG_ERR,
1179 QString(
"CardUtil[%1]: ").arg(inputid) +
1180 QString(
"open failed (%1)").arg(device) +
ENO);
1193 [[maybe_unused]]
int fd)
1211 [[maybe_unused]]
int fd)
1216 LOG(VB_GENERAL, LOG_INFO,
1217 QString(
"CardUtil[%1]: ").arg(inputid) +
1218 QString(
"Set delivery system: %1").arg(delsys.toString()));
1220 struct dtv_property prop = {};
1221 struct dtv_properties cmd = {};
1223 prop.cmd = DTV_DELIVERY_SYSTEM;
1224 prop.u.data = delsys;
1228 ret = ioctl(fd, FE_SET_PROPERTY, &cmd);
1231 LOG(VB_GENERAL, LOG_ERR,
LOC +
1232 QString(
"[%1] FE_SET_PROPERTY ioctl failed")
1233 .arg(inputid) +
ENO);
1249 if (device.isEmpty())
1253 QByteArray dev = dvbdev.toLatin1();
1254 int fd_frontend = open(dev.constData(), O_RDWR |
O_NONBLOCK);
1255 if (fd_frontend < 0)
1257 LOG(VB_GENERAL, LOG_ERR,
LOC +
1258 QString(
"Can't open DVB frontend (%1) for %2.")
1259 .arg(dvbdev, device) +
ENO);
1268 QString(
"SELECT %1 ").arg(to_get) +
1270 "WHERE capturecard.cardid = :INPUTID");
1275 else if (query.
next())
1276 return query.
value(0).toString();
1283 QString tmp =
get_on_input(
"capturecard.cardid", inputid);
1289 QString(
"UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
1290 "WHERE cardid = :INPUTID");
1312 const QString& rawtype,
1313 const QString& inputname,
1316 std::vector<uint> list;
1325 "WHERE hostname = :HOSTNAME ";
1326 if (!videodevice.isEmpty())
1327 qstr +=
"AND videodevice = :DEVICE ";
1328 if (!inputname.isEmpty())
1329 qstr +=
"AND inputname = :INPUTNAME ";
1330 if (!rawtype.isEmpty())
1331 qstr +=
"AND cardtype = :INPUTTYPE ";
1332 qstr +=
"ORDER BY cardid";
1337 if (!videodevice.isEmpty())
1338 query.
bindValue(
":DEVICE", videodevice);
1339 if (!inputname.isEmpty())
1340 query.
bindValue(
":INPUTNAME", inputname);
1341 if (!rawtype.isEmpty())
1342 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
1350 while (query.
next())
1351 list.push_back(query.
value(0).toUInt());
1366 "WHERE parentid = :INPUTID";
1375 else if (query.
next())
1376 count = query.
value(0).toUInt();
1383 std::vector<uint> list;
1392 "WHERE parentid = :INPUTID "
1404 while (query.
next())
1405 list.push_back(query.
value(0).toUInt());
1413 uint dst_inputid = orig_dst_inputid;
1419 "DELETE FROM capturecard "
1420 "WHERE videodevice = 'temp_dummy'");
1429 "INSERT INTO capturecard "
1430 "SET videodevice = 'temp_dummy'");
1441 "WHERE videodevice = 'temp_dummy'");
1451 LOG(VB_GENERAL, LOG_ERR,
"clone_capturecard -- get temp id");
1455 dst_inputid = query.
value(0).toUInt();
1459 "SELECT videodevice, audiodevice, vbidevice, "
1460 " cardtype, hostname, signal_timeout, "
1461 " channel_timeout, dvb_wait_for_seqstart, dvb_on_demand, "
1462 " dvb_tuning_delay, dvb_diseqc_type, diseqcid, "
1463 " dvb_eitscan, inputname, sourceid, "
1464 " externalcommand, changer_device, changer_model, "
1465 " tunechan, startchan, displayname, "
1466 " dishnet_eit, recpriority, quicktune, "
1467 " livetvorder, reclimit, "
1469 " schedgroup, schedorder "
1471 "WHERE cardid = :INPUTID");
1472 query.
bindValue(
":INPUTID", src_inputid);
1481 LOG(VB_GENERAL, LOG_ERR,
"clone_cardinput -- get data 2");
1488 bool schedgroup = query.
value(26).toBool();
1489 uint schedorder = query.
value(27).toUInt();
1498 "UPDATE capturecard "
1499 "SET videodevice = :V0, "
1500 " audiodevice = :V1, "
1501 " vbidevice = :V2, "
1504 " signal_timeout = :V5, "
1505 " channel_timeout = :V6, "
1506 " dvb_wait_for_seqstart = :V7, "
1507 " dvb_on_demand = :V8, "
1508 " dvb_tuning_delay = :V9, "
1509 " dvb_diseqc_type = :V10, "
1511 " dvb_eitscan = :V12, "
1512 " inputname = :V13, "
1513 " sourceid = :V14, "
1514 " externalcommand = :V15, "
1515 " changer_device = :V16, "
1516 " changer_model = :V17, "
1517 " tunechan = :V18, "
1518 " startchan = :V19, "
1519 " displayname = :V20, "
1520 " dishnet_eit = :V21, "
1521 " recpriority = :V22, "
1522 " quicktune = :V23, "
1523 " livetvorder = :V24, "
1524 " reclimit = :V25, "
1525 " schedgroup = :SCHEDGROUP, "
1526 " schedorder = :SCHEDORDER, "
1527 " parentid = :PARENTID "
1528 "WHERE cardid = :INPUTID");
1529 for (
uint i = 0; i < 26; ++i)
1530 query2.
bindValue(QString(
":V%1").arg(i), query.
value(i).toString());
1531 query2.
bindValue(
":INPUTID", dst_inputid);
1532 query2.
bindValue(
":PARENTID", src_inputid);
1533 query2.
bindValue(
":SCHEDGROUP", schedgroup);
1534 query2.
bindValue(
":SCHEDORDER", schedorder);
1539 if (!orig_dst_inputid)
1547 for (
uint dst_grp : dst_grps)
1549 for (
uint src_grp : src_grps)
1554 if (diseqc.
Load(src_inputid))
1555 diseqc.
Store(dst_inputid);
1573 if (max_recordings < 1)
1575 LOG(VB_GENERAL, LOG_ERR,
LOC +
1576 "InputSetMaxRecording: max must be greater than zero.");
1583 for (
size_t i = cardids.size() + 1;
1584 (i > max_recordings) && !cardids.empty(); --i)
1591 for (
uint id : cardids)
1595 for (
size_t i = cardids.size() + 1; i < max_recordings; ++i)
1612 LOG(VB_GENERAL, LOG_INFO,
LOC +
1613 QString(
"Added child input %1 to parent %2")
1614 .arg(inputid).arg(parentid));
1616 query.
prepare(
"UPDATE capturecard "
1617 "SET reclimit = reclimit + 1 "
1618 "WHERE cardid = :PARENTID");
1625 LOG(VB_GENERAL, LOG_ERR,
LOC +
1626 QString(
"Failed to add child input to parent %1").arg(parentid));
1637 query.
prepare(
"SELECT changer_device "
1638 "FROM capturecard WHERE cardid = :INPUTID ");
1643 fwnode = query.
value(0).toString();
1654 query.
prepare(
"SELECT changer_model "
1655 "FROM capturecard WHERE cardid = :INPUTID ");
1660 fwnode = query.
value(0).toString();
1671 "SELECT DISTINCT cardid "
1673 "WHERE sourceid = :SOURCEID");
1676 std::vector<uint> list;
1684 while (query.
next())
1685 list.push_back(query.
value(0).toUInt());
1693 query.
prepare(
"UPDATE capturecard "
1694 "SET startchan = :CHANNUM "
1695 "WHERE cardid = :INPUTID");
1715 "inputname, sourceid, livetvorder, "
1716 "schedorder, displayname, recpriority, quicktune "
1718 "WHERE cardid = :INPUTID");
1747 QList<InputInfo> infoInputList;
1750 QString queryStr =
"SELECT cardid, "
1751 "inputname, sourceid, livetvorder, "
1752 "schedorder, displayname, recpriority, quicktune "
1756 queryStr.append(
" WHERE parentid = 0");
1762 return infoInputList;
1765 while (query.
next())
1777 infoInputList.push_back(input);
1780 return infoInputList;
1807 query.
prepare(
"SELECT startchan "
1809 "WHERE cardid = :INPUTID");
1816 else if (query.
next())
1818 startchan = query.
value(0).toString();
1822 if (!startchan.isEmpty())
1824 query.
prepare(
"SELECT channel.chanid "
1825 "FROM capturecard, channel "
1826 "WHERE capturecard.cardid = :INPUTID AND "
1827 " capturecard.sourceid = channel.sourceid AND "
1828 " channel.deleted IS NULL AND "
1829 " channel.visible > 0 AND "
1830 " channel.channum = :CHANNUM");
1838 else if (!query.
next())
1840 LOG(VB_GENERAL, LOG_WARNING,
1841 QString(
"CardUtil[%1]: ").arg(inputid) +
1842 QString(
"Channel %1 on inputid %2 is invalid").arg(startchan).arg(inputid));
1849 if (startchan.isEmpty())
1851 query.
prepare(
"SELECT channel.channum "
1852 "FROM capturecard, channel "
1853 "WHERE capturecard.cardid = :INPUTID AND "
1854 " capturecard.sourceid = channel.sourceid AND "
1855 " channel.deleted IS NULL AND "
1856 " channel.visible > 0 "
1864 else if (query.
next())
1866 startchan = query.
value(0).toString();
1870 if (startchan.isEmpty())
1872 LOG(VB_GENERAL, LOG_WARNING,
1873 QString(
"CardUtil[%1]: ").arg(inputid) +
1874 QString(
"No start channel found on inputid %1").arg(inputid));
1878 LOG(VB_GENERAL, LOG_DEBUG,
1879 QString(
"CardUtil[%1]: ").arg(inputid) +
1880 QString(
"Start channel %1 on inputid %2").arg(startchan).arg(inputid));
1892 query.
prepare(
"SELECT displayname "
1894 "WHERE cardid = :INPUTID");
1901 else if (query.
next())
1903 QString result = query.
value(0).toString();
1917 qsizetype idx = name.indexOf(
'/');
1920 matching = name.right(name.size() - idx -1);
1925 matching = name.right(2);
1930 query.
prepare(
"SELECT cardid, displayname "
1932 "WHERE parentid = 0 "
1933 " AND cardid <> :INPUTID ");
1934 query.
bindValue(
":INPUTID", exclude_inputid);
1942 while (query.
next())
1944 QString dn = query.
value(1).toString();
1945 idx = dn.indexOf(
'/');
1946 if (!two && idx >= 0)
1948 if (dn.right(dn.size() - idx - 1) == matching)
1951 else if (dn.right(2) == matching.right(2))
1966 "WHERE cardid = :INPUTID");
1970 else if (query.
next())
1971 return query.
value(0).toUInt();
1980 const uint sourceid,
1981 const QString &inputname,
1982 const QString &externalcommand,
1983 const QString &changer_device,
1984 const QString &changer_model,
1986 const QString &tunechan,
1987 const QString &startchan,
1988 const QString &displayname,
1990 const uint recpriority,
1991 const uint quicktune,
1992 const uint schedorder,
1993 const uint livetvorder)
1998 "UPDATE capturecard "
1999 "SET sourceid = :SOURCEID, "
2000 " inputname = :INPUTNAME, "
2001 " externalcommand = :EXTERNALCOMMAND, "
2002 " changer_device = :CHANGERDEVICE, "
2003 " changer_model = :CHANGERMODEL, "
2004 " tunechan = :TUNECHAN, "
2005 " startchan = :STARTCHAN, "
2006 " displayname = :DISPLAYNAME, "
2007 " dishnet_eit = :DISHNETEIT, "
2008 " recpriority = :RECPRIORITY, "
2009 " quicktune = :QUICKTUNE, "
2010 " schedorder = :SCHEDORDER, "
2011 " livetvorder = :LIVETVORDER "
2012 "WHERE cardid = :INPUTID AND "
2013 " inputname = 'None'");
2017 query.
bindValue(
":INPUTNAME", inputname);
2018 query.
bindValue(
":EXTERNALCOMMAND", externalcommand);
2019 query.
bindValue(
":CHANGERDEVICE", changer_device);
2020 query.
bindValue(
":CHANGERMODEL", changer_model);
2022 query.
bindValue(
":STARTCHAN", startchan);
2024 query.
bindValue(
":DISHNETEIT", dishnet_eit);
2025 query.
bindValue(
":RECPRIORITY", recpriority);
2026 query.
bindValue(
":QUICKTUNE", quicktune);
2027 query.
bindValue(
":SCHEDORDER", schedorder);
2028 query.
bindValue(
":LIVETVORDER", livetvorder);
2043 query.
prepare(
"SELECT inputgroupid FROM inputgroup "
2044 "WHERE inputgroupname = :GROUPNAME "
2054 return query.
value(0).toUInt();
2056 query.
prepare(
"SELECT MAX(inputgroupid) FROM inputgroup");
2063 uint inputgroupid = (query.
next()) ? query.
value(0).toUInt() + 1 : 1;
2066 "INSERT INTO inputgroup "
2067 " (cardinputid, inputgroupid, inputgroupname) "
2068 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2070 query.
bindValue(
":GROUPID", inputgroupid);
2078 return inputgroupid;
2082 const QString &
type,
2083 const QString &host,
2084 const QString &device)
2086 QString name = host +
'|' + device;
2087 if (
type ==
"FREEBOX" ||
type ==
"IMPORT" ||
2088 type ==
"DEMO" ||
type ==
"EXTERNAL" ||
2089 type ==
"HDHOMERUN" )
2090 name += QString(
"|%1").arg(inputid);
2098 "SELECT inputgroupid "
2100 "WHERE cardinputid = :INPUTID "
2101 " AND inputgroupname REGEXP '^[a-z_-]*\\\\|'");
2112 return query.
value(0).toUInt();
2123 "SELECT cardinputid, inputgroupid, inputgroupname "
2125 "WHERE inputgroupid = :GROUPID "
2126 "ORDER BY inputgroupid, cardinputid, inputgroupname");
2127 query.
bindValue(
":GROUPID", inputgroupid);
2136 while (query.
next()) {
2137 name = query.
value(2).toString();
2140 if (cardid == inputid)
2149 "INSERT INTO inputgroup "
2150 " (cardinputid, inputgroupid, inputgroupname) "
2151 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2154 query.
bindValue(
":GROUPID", inputgroupid);
2173 if (!inputid && !inputgroupid)
2176 "DELETE FROM inputgroup "
2177 "WHERE cardinputid NOT IN "
2178 "( SELECT cardid FROM capturecard )");
2183 "DELETE FROM inputgroup "
2184 "WHERE cardinputid = :INPUTID AND "
2185 " inputgroupid = :GROUPID ");
2188 query.
bindValue(
":GROUPID", inputgroupid);
2202 std::vector<uint> list;
2207 "SELECT inputgroupid "
2209 "WHERE cardinputid = :INPUTID "
2210 "ORDER BY inputgroupid, cardinputid, inputgroupname");
2220 while (query.
next())
2221 list.push_back(query.
value(0).toUInt());
2228 std::vector<uint> list;
2233 "SELECT DISTINCT cardid "
2234 "FROM capturecard, inputgroup "
2235 "WHERE inputgroupid = :GROUPID AND "
2236 " capturecard.cardid = inputgroup.cardinputid "
2239 query.
bindValue(
":GROUPID", inputgroupid);
2247 while (query.
next())
2248 list.push_back(query.
value(0).toUInt());
2255 std::vector<uint> inputids;
2260 "SELECT DISTINCT c.cardid "
2262 " SELECT inputgroupid "
2264 " WHERE cardinputid = :INPUTID1 "
2266 "JOIN inputgroup ig ON ig.inputgroupid = g.inputgroupid "
2267 "JOIN capturecard c ON c.cardid = ig.cardinputid "
2268 " AND c.cardid <> :INPUTID2 "
2269 " AND c.sourceid > 0 "
2270 "ORDER BY c.cardid");
2281 while (query.
next())
2283 inputids.push_back(query.
value(0).toUInt());
2288 QString msg = QString(
"CardUtil[%1]: GetConflictingInputs(%1) ").arg(inputid);
2290 for (
auto id : inputids)
2292 ids.append(QString::number(
id));
2294 msg.append(ids.join(
','));
2295 LOG(VB_RECORD, LOG_INFO, msg);
2301 std::chrono::milliseconds &signal_timeout,
2302 std::chrono::milliseconds &channel_timeout)
2306 "SELECT signal_timeout, channel_timeout "
2308 "WHERE cardid = :INPUTID");
2315 else if (query.
next())
2317 signal_timeout = std::max(std::chrono::milliseconds(query.
value(0).toInt()), 250ms);
2318 channel_timeout = std::max(std::chrono::milliseconds(query.
value(1).toInt()), 500ms);
2329 bool needsConf =
false;
2344 "WHERE cardid = :INPUTID AND "
2345 " inputname = :INPUTNAME");
2347 query.
bindValue(
":INPUTNAME", input_name);
2351 else if (query.
next())
2352 quicktune = query.
value(0).toUInt();
2360 struct v4l2_capability vcap {};
2362 return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
2363 ((vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE) != 0U));
2370 int videofd, QString &input, QString &driver, uint32_t &
version,
2371 uint32_t &capabilities)
2382 struct v4l2_capability capability {};
2383 if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
2385 input = QString::fromLatin1((
const char*)capability.card);
2386 driver = QString::fromLatin1((
const char*)capability.driver);
2388 capabilities = capability.capabilities;
2392 static const QRegularExpression kBracketedDigitRE { R
"(\[[0-9]\]$)" };
2393 if (!driver.isEmpty())
2394 driver.remove( kBracketedDigitRE );
2396 return !input.isEmpty();
2405 bool usingv4l2 =
hasV4L2(videofd);
2407 struct v4l2_input vin {};
2408 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
2410 QString input((
char *)vin.name);
2411 list[vin.index] = input;
2422 list[0] =
"Television";
2426 list[-1] += QObject::tr(
"ERROR, Compile with V4L support to query inputs");
2437 bool usingv4l2 =
hasV4L2(videofd);
2440 struct v4l2_audio ain {};
2441 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMAUDIO, &ain) >= 0))
2443 QString input((
char *)ain.name);
2444 list[ain.index] = input;
2455 list[-1] += QObject::tr(
2456 "ERROR, Compile with V4L support to query audio inputs");
2466 "SELECT cardid, inputname "
2468 "WHERE hostname = :HOSTNAME "
2469 " AND videodevice = :DEVICE "
2470 " AND parentid = 0 "
2471 " AND inputname <> 'None'");
2481 while (query.
next())
2482 list[query.
value(0).toUInt()] = query.
value(1).toString();
2496 struct fe_caps_name {
2501 std::array<fe_caps_name,31> fe_caps_name {{
2502 { .idx=FE_CAN_2G_MODULATION, .name=
"CAN_2G_MODULATION" },
2503 { .idx=FE_CAN_8VSB, .name=
"CAN_8VSB" },
2504 { .idx=FE_CAN_16VSB, .name=
"CAN_16VSB" },
2505 { .idx=FE_CAN_BANDWIDTH_AUTO, .name=
"CAN_BANDWIDTH_AUTO" },
2506 { .idx=FE_CAN_FEC_1_2, .name=
"CAN_FEC_1_2" },
2507 { .idx=FE_CAN_FEC_2_3, .name=
"CAN_FEC_2_3" },
2508 { .idx=FE_CAN_FEC_3_4, .name=
"CAN_FEC_3_4" },
2509 { .idx=FE_CAN_FEC_4_5, .name=
"CAN_FEC_4_5" },
2510 { .idx=FE_CAN_FEC_5_6, .name=
"CAN_FEC_5_6" },
2511 { .idx=FE_CAN_FEC_6_7, .name=
"CAN_FEC_6_7" },
2512 { .idx=FE_CAN_FEC_7_8, .name=
"CAN_FEC_7_8" },
2513 { .idx=FE_CAN_FEC_8_9, .name=
"CAN_FEC_8_9" },
2514 { .idx=FE_CAN_FEC_AUTO, .name=
"CAN_FEC_AUTO" },
2515 { .idx=FE_CAN_GUARD_INTERVAL_AUTO, .name=
"CAN_GUARD_INTERVAL_AUTO" },
2516 { .idx=FE_CAN_HIERARCHY_AUTO, .name=
"CAN_HIERARCHY_AUTO" },
2517 { .idx=FE_CAN_INVERSION_AUTO, .name=
"CAN_INVERSION_AUTO" },
2518 { .idx=FE_CAN_MULTISTREAM, .name=
"CAN_MULTISTREAM" },
2519 { .idx=FE_CAN_MUTE_TS, .name=
"CAN_MUTE_TS" },
2520 { .idx=FE_CAN_QAM_16, .name=
"CAN_QAM_16" },
2521 { .idx=FE_CAN_QAM_32, .name=
"CAN_QAM_32" },
2522 { .idx=FE_CAN_QAM_64, .name=
"CAN_QAM_64" },
2523 { .idx=FE_CAN_QAM_128, .name=
"CAN_QAM_128" },
2524 { .idx=FE_CAN_QAM_256, .name=
"CAN_QAM_256" },
2525 { .idx=FE_CAN_QAM_AUTO, .name=
"CAN_QAM_AUTO" },
2526 { .idx=FE_CAN_QPSK, .name=
"CAN_QPSK" },
2527 { .idx=FE_CAN_RECOVER, .name=
"CAN_RECOVER" },
2528 { .idx=FE_CAN_TRANSMISSION_MODE_AUTO, .name=
"CAN_TRANSMISSION_MODE_AUTO" },
2529 { .idx=FE_CAN_TURBO_FEC, .name=
"CAN_TURBO_FEC" },
2530 { .idx=FE_HAS_EXTENDED_CAPS, .name=
"HAS_EXTENDED_CAPS" },
2531 { .idx=FE_IS_STUPID, .name=
"IS_STUPID" },
2532 { .idx=FE_NEEDS_BENDING, .name=
"NEEDS_BENDING" },
2535 for (
const auto & cap : fe_caps_name)
2537 if (capabilities & cap.idx)
2538 caps.append(cap.name);
2550 else if (
"DVB" == inputtype)
2560 LOG(VB_GENERAL, LOG_DEBUG, QString(
"ProbeAudioInputs(%1,%2)")
2561 .arg(device, inputtype));
2564 if (
"HDPVR" == inputtype ||
2565 "V4L2" == inputtype)
2575 QByteArray dev = device.toLatin1();
2576 int videofd = open(dev.constData(), O_RDWR);
2579 ret += QObject::tr(
"Could not open '%1' "
2580 "to probe its inputs.").arg(device);
2592 InputNames::iterator it;
2593 for (it = list.begin(); it != list.end(); ++it)
2604 LOG(VB_GENERAL, LOG_DEBUG, QString(
"ProbeV4LAudioInputs(%1)").arg(device));
2608 int videofd = open(device.toLatin1().constData(), O_RDWR);
2611 LOG(VB_GENERAL, LOG_ERR,
"ProbeAudioInputs() -> couldn't open device");
2612 ret += QObject::tr(
"Could not open '%1' to probe its inputs.")
2625 InputNames::iterator it;
2626 for (it = list.begin(); it != list.end(); ++it)
2641 InputNames::iterator it;
2642 for (it = list.begin(); it != list.end(); ++it)
2648 ret += QObject::tr(
"ERROR, Compile with DVB support to query inputs");
2655 const QString &videodevice)
2657 return QString(
"[ %1 : %2 ]").arg(inputtype, videodevice);
2663 query.
prepare(
"SELECT cardtype, videodevice "
2664 "FROM capturecard WHERE cardid = :INPUTID ");
2670 query.
value(1).toString());
2673 return "[ UNKNOWN ]";
2677 const QString &device,
2678 const QString &inputtype,
2679 QStringList &inputs)
2683 inputs +=
"MPEG2TS";
2684 else if (inputtype ==
"DVB")
2685 inputs +=
"DVBInput";
2691 const QString &audiodevice,
2692 const QString &vbidevice,
2693 const QString &inputtype,
2694 const uint audioratelimit,
2696 const uint dvb_swfilter,
2697 const uint dvb_sat_type,
2698 bool dvb_wait_for_seqstart,
2701 const uint dvb_diseqc_type,
2702 const uint firewire_speed,
2703 const QString &firewire_model,
2704 const uint firewire_connection,
2705 const std::chrono::milliseconds signal_timeout,
2706 const std::chrono::milliseconds channel_timeout,
2707 const uint dvb_tuning_delay,
2708 const uint contrast,
2709 const uint brightness,
2712 const uint diseqcid,
2718 "INSERT INTO capturecard "
2719 "(videodevice, audiodevice, vbidevice, cardtype, "
2720 "audioratelimit, hostname, dvb_swfilter, dvb_sat_type, "
2721 "dvb_wait_for_seqstart, skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
2722 "firewire_speed, firewire_model, firewire_connection, signal_timeout, "
2723 "channel_timeout, dvb_tuning_delay, contrast, brightness, colour, "
2724 "hue, diseqcid, dvb_eitscan) "
2725 "VALUES (:VIDEODEVICE, :AUDIODEVICE, :VBIDEVICE, :INPUTTYPE, "
2726 ":AUDIORATELIMIT, :HOSTNAME, :DVBSWFILTER, :DVBSATTYPE, "
2727 ":DVBWAITFORSEQSTART, :SKIPBTAUDIO, :DVBONDEMAND, :DVBDISEQCTYPE, "
2728 ":FIREWIRESPEED, :FIREWIREMODEL, :FIREWIRECONNECTION, :SIGNALTIMEOUT, "
2729 ":CHANNELTIMEOUT, :DVBTUNINGDELAY, :CONTRAST, :BRIGHTNESS, :COLOUR, "
2730 ":HUE, :DISEQCID, :DVBEITSCAN ) ");
2732 query.
bindValue(
":VIDEODEVICE", videodevice);
2733 if (audiodevice.length() == 0)
2735#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2736 query.
bindValue(
":AUDIODEVICE", QVariant(QVariant::String));
2738 query.
bindValue(
":AUDIODEVICE", QVariant(QMetaType(QMetaType::QString)));
2743 query.
bindValue(
":AUDIODEVICE", audiodevice);
2745 if (vbidevice.length() == 0)
2747#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2748 query.
bindValue(
":VBIDEVICE", QVariant(QVariant::String));
2750 query.
bindValue(
":VBIDEVICE", QVariant(QMetaType(QMetaType::QString)));
2755 query.
bindValue(
":VBIDEVICE", vbidevice);
2757 query.
bindValue(
":INPUTTYPE", inputtype);
2758 if (audioratelimit == 0)
2760#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2761 query.
bindValue(
":AUDIORATELIMIT", QVariant(QVariant::UInt));
2763 query.
bindValue(
":AUDIORATELIMIT", QVariant(QMetaType(QMetaType::UInt)));
2768 query.
bindValue(
":AUDIORATELIMIT", audioratelimit);
2771 query.
bindValue(
":DVBSWFILTER", dvb_swfilter);
2772 query.
bindValue(
":DVBSATTYPE", dvb_sat_type);
2773 query.
bindValue(
":DVBWAITFORSEQSTART", dvb_wait_for_seqstart);
2774 query.
bindValue(
":SKIPBTAUDIO", skipbtaudio);
2775 query.
bindValue(
":DVBONDEMAND", dvb_on_demand);
2776 query.
bindValue(
":DVBDISEQCTYPE", dvb_diseqc_type);
2777 query.
bindValue(
":FIREWIRESPEED", firewire_speed);
2778 if (firewire_model.length() == 0)
2780#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2781 query.
bindValue(
":FIREWIREMODEL", QVariant(QVariant::String));
2783 query.
bindValue(
":FIREWIREMODEL", QVariant(QMetaType(QMetaType::QString)));
2788 query.
bindValue(
":FIREWIREMODEL", firewire_model);
2790 query.
bindValue(
":FIREWIRECONNECTION", firewire_connection);
2791 query.
bindValue(
":SIGNALTIMEOUT",
static_cast<qint64
>(signal_timeout.count()));
2792 query.
bindValue(
":CHANNELTIMEOUT",
static_cast<qint64
>(channel_timeout.count()));
2793 query.
bindValue(
":DVBTUNINGDELAY", dvb_tuning_delay);
2795 query.
bindValue(
":BRIGHTNESS", brightness);
2800#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2801 query.
bindValue(
":DISEQCID", QVariant(QVariant::UInt));
2803 query.
bindValue(
":DISEQCID", QVariant(QMetaType(QMetaType::UInt)));
2810 query.
bindValue(
":DVBEITSCAN", dvb_eitscan);
2818 query.
prepare(
"SELECT MAX(cardid) FROM capturecard");
2830 inputid = query.
value(0).toInt();
2842 for (
uint childid : childids)
2846 LOG(VB_GENERAL, LOG_ERR,
LOC +
2847 QString(
"CardUtil: Failed to delete child input %1")
2859 query.
prepare(
"DELETE FROM capturecard WHERE cardid = :INPUTID");
2868 query.
prepare(
"UPDATE capturecard SET reclimit=reclimit-1 "
2869 "WHERE cardid = :INPUTID");
2878 query.
prepare(
"DELETE FROM inputgroup WHERE cardinputid = :INPUTID");
2889 query.
prepare(
"SELECT cardid FROM capturecard "
2890 "WHERE diseqcid = :DISEQCID LIMIT 1");
2896 else if (!query.
next())
2899 tree.
Store(inputid);
2912 return (query.
exec(
"TRUNCATE TABLE inputgroup") &&
2913 query.
exec(
"TRUNCATE TABLE diseqc_config") &&
2914 query.
exec(
"TRUNCATE TABLE diseqc_tree") &&
2915 query.
exec(
"TRUNCATE TABLE capturecard"));
2920 std::vector<uint> list;
2934 while (query.
next())
2935 list.push_back(query.
value(0).toUInt());
2943 std::vector<uint> list;
2947 "SELECT DISTINCT cardid "
2949 "WHERE schedorder <> 0 "
2950 "ORDER BY schedorder, cardid");
2958 while (query.
next())
2959 list.push_back(query.
value(0).toUInt());
2967 std::vector<uint> list;
2971 "SELECT DISTINCT cardid "
2973 "WHERE livetvorder <> 0 "
2974 "ORDER BY livetvorder, cardid");
2982 while (query.
next())
2983 list.push_back(query.
value(0).toUInt());
2991 QString devname = QString(device);
2993 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"DVB Device (%1)").arg(devname));
3003 QString tmp = devname;
3004 tmp = tmp.replace(tmp.indexOf(
"frontend"), 8,
"dvr");
3007 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3008 QString(
"Adapter Frontend dvr number matches (%1)").arg(tmp));
3014 tmp = tmp.replace(tmp.indexOf(
"frontend"), 9,
"dvr0");
3017 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3018 QString(
"Adapter Frontend dvr number not matching, using dvr0 instead (%1)").arg(tmp));
3022 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3023 QString(
"Adapter Frontend no dvr device found for (%1)").arg(devname));
3029 QString tmp = devname;
3030 tmp = tmp.replace(tmp.indexOf(
"frontend"), 8,
"demux");
3033 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3034 QString(
"Adapter Frontend demux number matches (%1)").arg(tmp));
3040 tmp = tmp.replace(tmp.indexOf(
"frontend"), 9,
"demux0");
3043 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3044 QString(
"Adapter Frontend demux number not matching, using demux0 instead (%1)").arg(tmp));
3048 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3049 QString(
"Adapter Frontend no demux device found for (%1)").arg(devname));
3055 QString tmp = devname;
3056 tmp = tmp.replace(tmp.indexOf(
"frontend"), 8,
"ca");
3059 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3060 QString(
"Adapter Frontend ca number matches (%1)").arg(tmp));
3066 tmp = tmp.replace(tmp.indexOf(
"frontend"), 9,
"ca0");
3069 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3070 QString(
"Adapter Frontend ca number not matching, using ca0 instead (%1)").arg(tmp));
3074 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3075 QString(
"Adapter Frontend no ca device found for (%1)").arg(devname));
3081 return devname.replace(devname.indexOf(
"frontend"), 8,
"audio");
3086 return devname.replace(devname.indexOf(
"frontend"), 8,
"video");
3106 hdhomerun_device_create_from_str(device.toLatin1().constData(),
nullptr);
3110 const char *model = hdhomerun_device_get_model_str(hdhr);
3111 if (model && strstr(model,
"dvb"))
3113 hdhomerun_device_destroy(hdhr);
3117 hdhomerun_device_destroy(hdhr);
3132 hdhomerun_device_create_from_str(device.toLatin1().constData(),
nullptr);
3136 const char *model = hdhomerun_device_get_model_str(hdhr);
3137 if (model && strstr(model,
"dvbc"))
3139 hdhomerun_device_destroy(hdhr);
3143 hdhomerun_device_destroy(hdhr);
3156 QString connectErr = QObject::tr(
"Unable to connect to device.");
3159 [[maybe_unused]]
bool deviceIsIP =
false;
3161 if (device.contains(
'.'))
3167 bool validID =
false;
3169 uint32_t dev = device.toUInt(&validID, 16);
3170 if (!validID || !hdhomerun_discover_validate_device_id(dev))
3171 return QObject::tr(
"Invalid Device ID");
3174 LOG(VB_GENERAL, LOG_INFO,
"CardUtil::GetHDHRdescription(" + device +
3175 ") - trying to locate device");
3178 hdhomerun_device_create_from_str(device.toLatin1().constData(),
nullptr);
3180 return QObject::tr(
"Invalid Device ID or address.");
3182 const char *model = hdhomerun_device_get_model_str(hdhr);
3185 hdhomerun_device_destroy(hdhr);
3190 QString description = model;
3191 char *sVersion =
nullptr;
3192 uint32_t iVersion = 0;
3194 if (hdhomerun_device_get_version(hdhr, &sVersion, &iVersion))
3195 description += QObject::tr(
", firmware: %2").arg(sVersion);
3197 hdhomerun_device_destroy(hdhr);
3210 [[maybe_unused]]
const QString &ip,
3211 [[maybe_unused]]
const QString &tunerNo,
3212 [[maybe_unused]]
const QString &tunerType)
3214 QString connectErr = QObject::tr(
"Unable to connect to device.");
3229 QString apiVersionErr = QObject::tr(
"The VBox software version is too old (%1), we require %2")
3232 return apiVersionErr;
3238 return QString(
"V@Box TV Gateway - ID: %1, IP: %2, Tuner: %3-%4")
3239 .arg(
id, ip, tunerNo, tunerType);
3247static QString sys_dev(
uint device_num,
const QString& dev)
3249 return QString(
"/sys/class/asi/asirx%1/%2").arg(device_num).arg(dev);
3252static QString read_sys(
const QString& sys_dev)
3255 if (!f.open(QIODevice::ReadOnly))
3257 QByteArray sdba = f.readAll();
3262static bool write_sys(
const QString& sys_dev,
const QString& str)
3265 if (!f.open(QIODevice::WriteOnly))
3267 QByteArray ba = str.toLocal8Bit();
3269 for (
uint tries = 0; (offset < ba.size()) && tries < 5; tries++)
3271 qint64 written = f.write(ba.data()+offset, ba.size()-offset);
3284 struct stat statbuf {};
3285 if (stat(device.toLocal8Bit().constData(), &statbuf) < 0)
3288 *
error = QString(
"Unable to stat '%1'").arg(device) +
ENO;
3292 if (!S_ISCHR(statbuf.st_mode))
3295 *
error = QString(
"'%1' is not a character device").arg(device);
3299 if (!(statbuf.st_rdev & 0x0080))
3302 *
error = QString(
"'%1' not a DVEO ASI receiver").arg(device);
3306 int device_num = statbuf.st_rdev & 0x007f;
3309 QString sys_dev_contents = read_sys(sys_dev(device_num,
"dev"));
3310 QStringList sys_dev_clist = sys_dev_contents.split(
":");
3311 if (2 != sys_dev_clist.size())
3315 *
error = QString(
"Unable to read '%1'")
3316 .arg(sys_dev(device_num,
"dev"));
3320 if (sys_dev_clist[0].toUInt() != (statbuf.st_rdev>>8))
3323 *
error = QString(
"'%1' not a DVEO ASI device").arg(device);
3330 *
error =
"Not compiled with ASI support.";
3339 QString sys_bufsize_contents = read_sys(sys_dev(device_num,
"bufsize"));
3341 uint buf_size = sys_bufsize_contents.toUInt(&ok);
3346 *
error = QString(
"Failed to read buffer size from '%1'")
3347 .arg(sys_dev(device_num,
"bufsize"));
3354 *
error =
"Not compiled with ASI support.";
3363 QString sys_numbuffers_contents = read_sys(sys_dev(device_num,
"buffers"));
3365 uint num_buffers = sys_numbuffers_contents.toUInt(&ok);
3370 *
error = QString(
"Failed to read num buffers from '%1'")
3371 .arg(sys_dev(device_num,
"buffers"));
3378 *
error =
"Not compiled with ASI support.";
3386 QString sys_bufsize_contents = read_sys(sys_dev(device_num,
"mode"));
3388 uint mode = sys_bufsize_contents.toUInt(&ok);
3393 *
error = QString(
"Failed to read mode from '%1'")
3394 .arg(sys_dev(device_num,
"mode"));
3401 *
error =
"Not compiled with ASI support.";
3407 [[maybe_unused]]
uint mode,
3411 QString sys_bufsize_contents = read_sys(sys_dev(device_num,
"mode"));
3413 uint old_mode = sys_bufsize_contents.toUInt(&ok);
3414 if (ok && old_mode == mode)
3416 ok = write_sys(sys_dev(device_num,
"mode"), QString(
"%1\n").arg(mode));
3419 *
error = QString(
"Failed to set mode to %1 using '%2'")
3420 .arg(mode).arg(sys_dev(device_num,
"mode"));
3425 *
error =
"Not compiled with ASI support.";
3435bool CardUtil::IsVBoxPresent(
uint inputid)
3440 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX inputid (%1) not valid, redo mythtv-setup")
3451 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX chanid (%1) not found for inputid (%2), redo mythtv-setup")
3452 .arg(chanid).arg(inputid));
3457 std::chrono::milliseconds signal_timeout = 0ms;
3458 std::chrono::milliseconds tuning_timeout = 0ms;
3459 if (!
GetTimeouts(inputid,signal_timeout,tuning_timeout))
3461 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to get timeouts for inputid (%1)")
3469 query.prepare(
"SELECT url "
3470 "FROM iptv_channel "
3471 "WHERE chanid = :CHANID");
3472 query.bindValue(
":CHANID", chanid);
3476 else if (query.next())
3477 url = QUrl(query.value(0).toString());
3482 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX invalid url: %1")
3483 .arg(url.toString()));
3486 QString ip = url.host();
3487 LOG(VB_GENERAL, LOG_INFO, QString(
"VBOX IP found (%1) for inputid (%2)")
3488 .arg(ip).arg(inputid));
3490 if (!
ping(ip,signal_timeout))
3492 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX at IP (%1) failed to respond to network ping for inputid (%2) timeout (%3)")
3493 .arg(ip).arg(inputid).arg(signal_timeout.count()));
3506bool CardUtil::IsSatIPPresent(
uint inputid)
3511 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP inputid (%1) not valid, redo mythtv-setup")
3522 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP chanid (%1) not found for inputid (%2), redo mythtv-setup")
3523 .arg(chanid).arg(inputid));
3528 std::chrono::milliseconds signal_timeout = 0ms;
3529 std::chrono::milliseconds tuning_timeout = 0ms;
3530 if (!
GetTimeouts(inputid,signal_timeout,tuning_timeout))
3532 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to get timeouts for inputid (%1)")
3539 QStringList devinfo = device.split(
":");
3540 if (devinfo.value(0).toUpper() ==
"UUID")
3542 QString deviceId = QString(
"uuid:%1").arg(devinfo.value(1));
3544 LOG(VB_GENERAL, LOG_INFO, QString(
"SatIP[%1] IP address %2 device %3")
3545 .arg(inputid).arg(ip, device));
3547 if (!
ping(ip, signal_timeout))
3549 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP[%1] at IP %2 failed to respond to network ping (timeout %3)")
3550 .arg(inputid).arg(ip).arg(signal_timeout.count()));
static uint clone_capturecard(uint src_inputid, uint orig_dst_inputid)
QString get_on_input(const QString &to_get, uint inputid)
bool set_on_input(const QString &to_set, uint inputid, const QString &value)
QMap< int, QString > InputNames
static uint GetQuickTuning(uint inputid, const QString &input_name)
static int GetASIDeviceNumber(const QString &device, QString *error=nullptr)
static int OpenVideoDevice(int inputid)
static bool IsTunerShared(uint inputidA, uint inputidB)
static bool IsTunerSharingCapable(const QString &rawtype)
static void GetDeviceInputNames(const QString &device, const QString &inputtype, QStringList &inputs)
static InputNames ProbeV4LVideoInputs(int videofd, bool &ok)
static int SetDefaultDeliverySystem(uint inputid, int fd)
static uint CreateInputGroup(const QString &name)
static QString GetFirewireChangerModel(uint inputid)
static QString GetRawInputType(uint inputid)
static std::vector< uint > GetSchedInputList(void)
static bool HDHRdoesDVB(const QString &device)
If the device is valid, check if the model does DVB.
static QString ProbeDVBFrontendName(const QString &device)
Returns the input type from the video device.
static QString ProbeDVBType(const QString &device)
static bool GetInputInfo(InputInfo &input, std::vector< uint > *groupids=nullptr)
static bool InputSetMaxRecordings(uint parentid, uint max_recordings)
static QStringList ProbeDeliverySystems(const QString &device)
static DTVModulationSystem GetDeliverySystem(uint inputid)
static uint CreateDeviceInputGroup(uint inputid, const QString &type, const QString &host, const QString &device)
static QString GetStartChannel(uint inputid)
static QString GetDeviceLabel(const QString &inputtype, const QString &videodevice)
static DTVModulationSystem ProbeBestDeliverySystem(int fd)
static int SetDeliverySystem(uint inputid)
static QString GetVBoxdesc(const QString &id, const QString &ip, const QString &tunerNo, const QString &tunerType)
Get a nicely formatted string describing the device.
static std::vector< uint > GetInputList(void)
static DTVModulationSystem GetOrProbeDeliverySystem(uint inputid, int fd)
static QStringList GetVideoDevices(const QString &rawtype, QString hostname=QString())
Returns the videodevices of the matching inputs, duplicates removed.
static QStringList GetInputTypeNames(uint sourceid)
Get a list of card input types for a source id.
static QMap< QString, QStringList > s_videoDeviceCache
static bool HasDVBCRCBug(const QString &device)
Returns true if and only if the device munges PAT/PMT tables, and then doesn't fix the CRC.
static bool IsInputTypePresent(const QString &rawtype, QString hostname=QString())
Returns true if the input type is present and connected to an input.
static uint GetASINumBuffers(uint device_num, QString *error=nullptr)
static bool HasTuner(const QString &rawtype, const QString &device)
static uint GetASIBufferSize(uint device_num, QString *error=nullptr)
static QString GetInputName(uint inputid)
static DTVTunerType GetTunerType(uint inputid)
static QString GetDeliverySystemFromDB(uint inputid)
static QStringList ProbeDVBInputs(const QString &device)
static bool UnlinkInputGroup(uint inputid, uint inputgroupid)
static bool LinkInputGroup(uint inputid, uint inputgroupid)
static InputNames ProbeV4LAudioInputs(int videofd, bool &ok)
static QString GetVideoDevice(uint inputid)
static bool GetTimeouts(uint inputid, std::chrono::milliseconds &signal_timeout, std::chrono::milliseconds &channel_timeout)
static bool IsInNeedOfExternalInputConf(uint inputid)
static std::chrono::milliseconds GetMinSignalMonitoringDelay(const QString &device)
static uint AddChildInput(uint parentid)
static DTVTunerType ProbeTunerType(int fd_frontend)
static void ClearVideoDeviceCache()
static QString GetHDHRdesc(const QString &device)
Get a nicely formatted string describing the device.
static uint CloneCard(uint src_inputid, uint dst_inputid)
static std::vector< uint > GetInputGroups(uint inputid)
static std::vector< uint > GetInputIDs(const QString &videodevice=QString(), const QString &rawtype=QString(), const QString &inputname=QString(), QString hostname=QString())
Returns all inputids of inputs that uses the specified videodevice if specified, and optionally rawty...
static std::vector< uint > GetChildInputIDs(uint inputid)
static std::vector< uint > GetLiveTVInputList(void)
static InputNames GetConfiguredDVBInputs(const QString &device)
static bool HDHRdoesDVBC(const QString &device)
If the device is valid, check if the model does DVB-C.
static uint GetSourceID(uint inputid)
static QString GetDeviceName(dvb_dev_type_t type, const QString &device)
static QStringList CapabilitiesToString(uint64_t capabilities)
static QString GetFirewireChangerNode(uint inputid)
static std::vector< uint > GetGroupInputIDs(uint inputgroupid)
static bool SetStartChannel(uint inputid, const QString &channum)
static QString GetDisplayName(uint inputid)
static bool DeleteInput(uint inputid)
static int GetASIMode(uint device_num, QString *error=nullptr)
static QString ProbeDefaultDeliverySystem(const QString &device)
static QStringList ProbeVideoDevices(const QString &rawtype)
static bool IsUniqueDisplayName(const QString &name, uint exclude_inputid)
static QString GetScanableInputTypes(void)
static int CreateCardInput(uint inputid, uint sourceid, const QString &inputname, const QString &externalcommand, const QString &changer_device, const QString &changer_model, const QString &hostname, const QString &tunechan, const QString &startchan, const QString &displayname, bool dishnet_eit, uint recpriority, uint quicktune, uint schedorder, uint livetvorder)
static bool SetASIMode(uint device_num, uint mode, QString *error=nullptr)
static DTVModulationSystem ProbeCurrentDeliverySystem(const QString &device)
static std::vector< uint > GetConflictingInputs(uint inputid)
static uint GetChildInputCount(uint inputid)
static bool IsCableCardPresent(uint inputid, const QString &inputType)
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
static bool IsSingleInputType(const QString &rawtype)
static DTVTunerType GetTunerTypeFromMultiplex(uint mplexid)
static QList< InputInfo > GetAllInputInfo(bool virtTuners)
static DTVTunerType ConvertToTunerType(DTVModulationSystem delsys)
static QString ProbeSubTypeName(uint inputid)
QMap< QString, QString > InputTypes
static bool hasV4L2(int videofd)
static QStringList ProbeVideoInputs(const QString &device, const QString &inputtype=QString())
static bool IsDVBInputType(const QString &inputType)
Returns true iff the input_type is one of the DVB types.
static bool DeleteAllInputs(void)
static int CreateCaptureCard(const QString &videodevice, const QString &audiodevice, const QString &vbidevice, const QString &inputtype, uint audioratelimit, const QString &hostname, uint dvb_swfilter, uint dvb_sat_type, bool dvb_wait_for_seqstart, bool skipbtaudio, bool dvb_on_demand, uint dvb_diseqc_type, uint firewire_speed, const QString &firewire_model, uint firewire_connection, std::chrono::milliseconds signal_timeout, std::chrono::milliseconds channel_timeout, uint dvb_tuning_delay, uint contrast, uint brightness, uint colour, uint hue, uint diseqcid, bool dvb_eitscan)
static InputTypes GetInputTypes(void)
static QStringList ProbeAudioInputs(const QString &device, const QString &inputtype=QString())
static uint GetDeviceInputGroup(uint inputid)
static int GetChannelValueInt(const QString &channel_field, uint sourceid, const QString &channum)
@ kModulationSystem_DVBS2
@ kModulationSystem_DVBT2
@ kModulationSystem_DVBC_ANNEX_A
@ kModulationSystem_UNDEFINED
@ kModulationSystem_DVBC_ANNEX_C
@ kModulationSystem_DVBC_ANNEX_B
bool Parse(const QString &_value)
static const int kTunerTypeDVBS2
static const int kTunerTypeDVBT
static const int kTunerTypeUnknown
static const int kTunerTypeDVBC
static const int kTunerTypeDVBS1
static const int kTunerTypeDVBT2
static const int kTunerTypeATSC
uint GetDeviceID(void) const
DVB-S device settings class.
bool Store(uint card_input_id) const
Stores configuration chain to DB for specified card input id.
bool Load(uint card_input_id)
Loads configuration chain from DB for specified card input id.
bool Load(const QString &device)
Loads the device tree from the database.
void SetRoot(DiSEqCDevDevice *root)
Changes the root node of the tree.
bool Store(uint cardid, const QString &device="")
Stores the device tree to the database.
DiSEqCDevDevice * Root(void)
Retrieves the root node in the tree.
bool IsInNeedOfConf(void) const
static DiSEqCDevTree * FindTree(uint cardid)
Retrieve device tree.
QSqlQuery wrapper that fetches a DB connection from the connection pool.
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
QVariant value(int i) const
bool isActive(void) const
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
QString GetHostName(void)
static void DBError(const QString &where, const MSqlQuery &query)
static QString findDeviceIP(const QString &deviceuuid)
static QStringList probeDevices(void)
bool HasTuner(void) const
QString DriverName(void) const
QString CardName(void) const
bool checkVersion(QString &version)
static QStringList probeDevices(void)
bool checkConnection(void)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
bool ping(const QString &host, std::chrono::milliseconds timeout)
Can we ping host within timeout seconds?
static MythSystemLegacyManager * manager
static constexpr const char * VBOX_MIN_API_VERSION