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());
1348 while (query.
next())
1349 list.push_back(query.
value(0).toUInt());
1364 "WHERE parentid = :INPUTID";
1373 else if (query.
next())
1374 count = query.
value(0).toUInt();
1381 std::vector<uint> list;
1390 "WHERE parentid = :INPUTID "
1400 while (query.
next())
1401 list.push_back(query.
value(0).toUInt());
1409 uint dst_inputid = orig_dst_inputid;
1415 "DELETE FROM capturecard "
1416 "WHERE videodevice = 'temp_dummy'");
1425 "INSERT INTO capturecard "
1426 "SET videodevice = 'temp_dummy'");
1437 "WHERE videodevice = 'temp_dummy'");
1447 LOG(VB_GENERAL, LOG_ERR,
"clone_capturecard -- get temp id");
1451 dst_inputid = query.
value(0).toUInt();
1455 "SELECT videodevice, audiodevice, vbidevice, "
1456 " cardtype, hostname, signal_timeout, "
1457 " channel_timeout, dvb_wait_for_seqstart, dvb_on_demand, "
1458 " dvb_tuning_delay, dvb_diseqc_type, diseqcid, "
1459 " dvb_eitscan, inputname, sourceid, "
1460 " externalcommand, changer_device, changer_model, "
1461 " tunechan, startchan, displayname, "
1462 " dishnet_eit, recpriority, quicktune, "
1463 " livetvorder, reclimit, "
1465 " schedgroup, schedorder "
1467 "WHERE cardid = :INPUTID");
1468 query.
bindValue(
":INPUTID", src_inputid);
1477 LOG(VB_GENERAL, LOG_ERR,
"clone_cardinput -- get data 2");
1484 bool schedgroup = query.
value(26).toBool();
1485 uint schedorder = query.
value(27).toUInt();
1494 "UPDATE capturecard "
1495 "SET videodevice = :V0, "
1496 " audiodevice = :V1, "
1497 " vbidevice = :V2, "
1500 " signal_timeout = :V5, "
1501 " channel_timeout = :V6, "
1502 " dvb_wait_for_seqstart = :V7, "
1503 " dvb_on_demand = :V8, "
1504 " dvb_tuning_delay = :V9, "
1505 " dvb_diseqc_type = :V10, "
1507 " dvb_eitscan = :V12, "
1508 " inputname = :V13, "
1509 " sourceid = :V14, "
1510 " externalcommand = :V15, "
1511 " changer_device = :V16, "
1512 " changer_model = :V17, "
1513 " tunechan = :V18, "
1514 " startchan = :V19, "
1515 " displayname = :V20, "
1516 " dishnet_eit = :V21, "
1517 " recpriority = :V22, "
1518 " quicktune = :V23, "
1519 " livetvorder = :V24, "
1520 " reclimit = :V25, "
1521 " schedgroup = :SCHEDGROUP, "
1522 " schedorder = :SCHEDORDER, "
1523 " parentid = :PARENTID "
1524 "WHERE cardid = :INPUTID");
1525 for (
uint i = 0; i < 26; ++i)
1526 query2.
bindValue(QString(
":V%1").arg(i), query.
value(i).toString());
1527 query2.
bindValue(
":INPUTID", dst_inputid);
1528 query2.
bindValue(
":PARENTID", src_inputid);
1529 query2.
bindValue(
":SCHEDGROUP", schedgroup);
1530 query2.
bindValue(
":SCHEDORDER", schedorder);
1535 if (!orig_dst_inputid)
1543 for (
uint dst_grp : dst_grps)
1545 for (
uint src_grp : src_grps)
1550 if (diseqc.
Load(src_inputid))
1551 diseqc.
Store(dst_inputid);
1569 if (max_recordings < 1)
1571 LOG(VB_GENERAL, LOG_ERR,
LOC +
1572 "InputSetMaxRecording: max must be greater than zero.");
1579 for (
size_t i = cardids.size() + 1;
1580 (i > max_recordings) && !cardids.empty(); --i)
1587 for (
uint id : cardids)
1591 for (
size_t i = cardids.size() + 1; i < max_recordings; ++i)
1608 LOG(VB_GENERAL, LOG_INFO,
LOC +
1609 QString(
"Added child input %1 to parent %2")
1610 .arg(inputid).arg(parentid));
1612 query.
prepare(
"UPDATE capturecard "
1613 "SET reclimit = reclimit + 1 "
1614 "WHERE cardid = :PARENTID");
1621 LOG(VB_GENERAL, LOG_ERR,
LOC +
1622 QString(
"Failed to add child input to parent %1").arg(parentid));
1633 query.
prepare(
"SELECT changer_device "
1634 "FROM capturecard WHERE cardid = :INPUTID ");
1639 fwnode = query.
value(0).toString();
1650 query.
prepare(
"SELECT changer_model "
1651 "FROM capturecard WHERE cardid = :INPUTID ");
1656 fwnode = query.
value(0).toString();
1667 "SELECT DISTINCT cardid "
1669 "WHERE sourceid = :SOURCEID");
1672 std::vector<uint> list;
1680 while (query.
next())
1681 list.push_back(query.
value(0).toUInt());
1689 query.
prepare(
"UPDATE capturecard "
1690 "SET startchan = :CHANNUM "
1691 "WHERE cardid = :INPUTID");
1711 "inputname, sourceid, livetvorder, "
1712 "schedorder, displayname, recpriority, quicktune "
1714 "WHERE cardid = :INPUTID");
1743 QList<InputInfo> infoInputList;
1746 QString queryStr =
"SELECT cardid, "
1747 "inputname, sourceid, livetvorder, "
1748 "schedorder, displayname, recpriority, quicktune "
1752 queryStr.append(
" WHERE parentid = 0");
1758 return infoInputList;
1761 while (query.
next())
1773 infoInputList.push_back(input);
1776 return infoInputList;
1803 query.
prepare(
"SELECT startchan "
1805 "WHERE cardid = :INPUTID");
1812 else if (query.
next())
1814 startchan = query.
value(0).toString();
1818 if (!startchan.isEmpty())
1820 query.
prepare(
"SELECT channel.chanid "
1821 "FROM capturecard, channel "
1822 "WHERE capturecard.cardid = :INPUTID AND "
1823 " capturecard.sourceid = channel.sourceid AND "
1824 " channel.deleted IS NULL AND "
1825 " channel.visible > 0 AND "
1826 " channel.channum = :CHANNUM");
1834 else if (!query.
next())
1836 LOG(VB_GENERAL, LOG_WARNING,
1837 QString(
"CardUtil[%1]: ").arg(inputid) +
1838 QString(
"Channel %1 on inputid %2 is invalid").arg(startchan).arg(inputid));
1845 if (startchan.isEmpty())
1847 query.
prepare(
"SELECT channel.channum "
1848 "FROM capturecard, channel "
1849 "WHERE capturecard.cardid = :INPUTID AND "
1850 " capturecard.sourceid = channel.sourceid AND "
1851 " channel.deleted IS NULL AND "
1852 " channel.visible > 0 "
1860 else if (query.
next())
1862 startchan = query.
value(0).toString();
1866 if (startchan.isEmpty())
1868 LOG(VB_GENERAL, LOG_WARNING,
1869 QString(
"CardUtil[%1]: ").arg(inputid) +
1870 QString(
"No start channel found on inputid %1").arg(inputid));
1874 LOG(VB_GENERAL, LOG_DEBUG,
1875 QString(
"CardUtil[%1]: ").arg(inputid) +
1876 QString(
"Start channel %1 on inputid %2").arg(startchan).arg(inputid));
1888 query.
prepare(
"SELECT displayname "
1890 "WHERE cardid = :INPUTID");
1895 else if (query.
next())
1897 QString result = query.
value(0).toString();
1911 qsizetype idx = name.indexOf(
'/');
1914 matching = name.right(name.size() - idx -1);
1919 matching = name.right(2);
1924 query.
prepare(
"SELECT cardid, displayname "
1926 "WHERE parentid = 0 "
1927 " AND cardid <> :INPUTID ");
1928 query.
bindValue(
":INPUTID", exclude_inputid);
1936 while (query.
next())
1938 QString dn = query.
value(1).toString();
1939 idx = dn.indexOf(
'/');
1940 if (!two && idx >= 0)
1942 if (dn.right(dn.size() - idx - 1) == matching)
1945 else if (dn.right(2) == matching.right(2))
1960 "WHERE cardid = :INPUTID");
1964 else if (query.
next())
1965 return query.
value(0).toUInt();
1974 const uint sourceid,
1975 const QString &inputname,
1976 const QString &externalcommand,
1977 const QString &changer_device,
1978 const QString &changer_model,
1980 const QString &tunechan,
1981 const QString &startchan,
1982 const QString &displayname,
1984 const uint recpriority,
1985 const uint quicktune,
1986 const uint schedorder,
1987 const uint livetvorder)
1992 "UPDATE capturecard "
1993 "SET sourceid = :SOURCEID, "
1994 " inputname = :INPUTNAME, "
1995 " externalcommand = :EXTERNALCOMMAND, "
1996 " changer_device = :CHANGERDEVICE, "
1997 " changer_model = :CHANGERMODEL, "
1998 " tunechan = :TUNECHAN, "
1999 " startchan = :STARTCHAN, "
2000 " displayname = :DISPLAYNAME, "
2001 " dishnet_eit = :DISHNETEIT, "
2002 " recpriority = :RECPRIORITY, "
2003 " quicktune = :QUICKTUNE, "
2004 " schedorder = :SCHEDORDER, "
2005 " livetvorder = :LIVETVORDER "
2006 "WHERE cardid = :INPUTID AND "
2007 " inputname = 'None'");
2011 query.
bindValue(
":INPUTNAME", inputname);
2012 query.
bindValue(
":EXTERNALCOMMAND", externalcommand);
2013 query.
bindValue(
":CHANGERDEVICE", changer_device);
2014 query.
bindValue(
":CHANGERMODEL", changer_model);
2016 query.
bindValue(
":STARTCHAN", startchan);
2018 query.
bindValue(
":DISHNETEIT", dishnet_eit);
2019 query.
bindValue(
":RECPRIORITY", recpriority);
2020 query.
bindValue(
":QUICKTUNE", quicktune);
2021 query.
bindValue(
":SCHEDORDER", schedorder);
2022 query.
bindValue(
":LIVETVORDER", livetvorder);
2037 query.
prepare(
"SELECT inputgroupid FROM inputgroup "
2038 "WHERE inputgroupname = :GROUPNAME "
2048 return query.
value(0).toUInt();
2050 query.
prepare(
"SELECT MAX(inputgroupid) FROM inputgroup");
2057 uint inputgroupid = (query.
next()) ? query.
value(0).toUInt() + 1 : 1;
2060 "INSERT INTO inputgroup "
2061 " (cardinputid, inputgroupid, inputgroupname) "
2062 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2064 query.
bindValue(
":GROUPID", inputgroupid);
2072 return inputgroupid;
2076 const QString &
type,
2077 const QString &host,
2078 const QString &device)
2080 QString name = host +
'|' + device;
2081 if (
type ==
"FREEBOX" ||
type ==
"IMPORT" ||
2082 type ==
"DEMO" ||
type ==
"EXTERNAL" ||
2083 type ==
"HDHOMERUN" )
2084 name += QString(
"|%1").arg(inputid);
2092 "SELECT inputgroupid "
2094 "WHERE cardinputid = :INPUTID "
2095 " AND inputgroupname REGEXP '^[a-z_-]*\\\\|'");
2106 return query.
value(0).toUInt();
2117 "SELECT cardinputid, inputgroupid, inputgroupname "
2119 "WHERE inputgroupid = :GROUPID "
2120 "ORDER BY inputgroupid, cardinputid, inputgroupname");
2121 query.
bindValue(
":GROUPID", inputgroupid);
2130 while (query.
next()) {
2131 name = query.
value(2).toString();
2134 if (cardid == inputid)
2143 "INSERT INTO inputgroup "
2144 " (cardinputid, inputgroupid, inputgroupname) "
2145 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2148 query.
bindValue(
":GROUPID", inputgroupid);
2167 if (!inputid && !inputgroupid)
2170 "DELETE FROM inputgroup "
2171 "WHERE cardinputid NOT IN "
2172 "( SELECT cardid FROM capturecard )");
2177 "DELETE FROM inputgroup "
2178 "WHERE cardinputid = :INPUTID AND "
2179 " inputgroupid = :GROUPID ");
2182 query.
bindValue(
":GROUPID", inputgroupid);
2196 std::vector<uint> list;
2201 "SELECT inputgroupid "
2203 "WHERE cardinputid = :INPUTID "
2204 "ORDER BY inputgroupid, cardinputid, inputgroupname");
2214 while (query.
next())
2215 list.push_back(query.
value(0).toUInt());
2222 std::vector<uint> list;
2227 "SELECT DISTINCT cardid "
2228 "FROM capturecard, inputgroup "
2229 "WHERE inputgroupid = :GROUPID AND "
2230 " capturecard.cardid = inputgroup.cardinputid "
2233 query.
bindValue(
":GROUPID", inputgroupid);
2241 while (query.
next())
2242 list.push_back(query.
value(0).toUInt());
2249 std::vector<uint> inputids;
2254 "SELECT DISTINCT c.cardid "
2256 " SELECT inputgroupid "
2258 " WHERE cardinputid = :INPUTID1 "
2260 "JOIN inputgroup ig ON ig.inputgroupid = g.inputgroupid "
2261 "JOIN capturecard c ON c.cardid = ig.cardinputid "
2262 " AND c.cardid <> :INPUTID2 "
2263 " AND c.sourceid > 0 "
2264 "ORDER BY c.cardid");
2275 while (query.
next())
2277 inputids.push_back(query.
value(0).toUInt());
2282 QString msg = QString(
"CardUtil[%1]: GetConflictingInputs(%1) ").arg(inputid);
2284 for (
auto id : inputids)
2286 ids.append(QString::number(
id));
2288 msg.append(ids.join(
','));
2289 LOG(VB_RECORD, LOG_INFO, msg);
2295 std::chrono::milliseconds &signal_timeout,
2296 std::chrono::milliseconds &channel_timeout)
2300 "SELECT signal_timeout, channel_timeout "
2302 "WHERE cardid = :INPUTID");
2307 else if (query.
next())
2309 signal_timeout = std::max(std::chrono::milliseconds(query.
value(0).toInt()), 250ms);
2310 channel_timeout = std::max(std::chrono::milliseconds(query.
value(1).toInt()), 500ms);
2321 bool needsConf =
false;
2336 "WHERE cardid = :INPUTID AND "
2337 " inputname = :INPUTNAME");
2339 query.
bindValue(
":INPUTNAME", input_name);
2343 else if (query.
next())
2344 quicktune = query.
value(0).toUInt();
2352 struct v4l2_capability vcap {};
2354 return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
2355 ((vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE) != 0U));
2362 int videofd, QString &input, QString &driver, uint32_t &
version,
2363 uint32_t &capabilities)
2374 struct v4l2_capability capability {};
2375 if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
2377 input = QString::fromLatin1((
const char*)capability.card);
2378 driver = QString::fromLatin1((
const char*)capability.driver);
2380 capabilities = capability.capabilities;
2384 static const QRegularExpression kBracketedDigitRE { R
"(\[[0-9]\]$)" };
2385 if (!driver.isEmpty())
2386 driver.remove( kBracketedDigitRE );
2388 return !input.isEmpty();
2397 bool usingv4l2 =
hasV4L2(videofd);
2399 struct v4l2_input vin {};
2400 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
2402 QString input((
char *)vin.name);
2403 list[vin.index] = input;
2414 list[0] =
"Television";
2418 list[-1] += QObject::tr(
"ERROR, Compile with V4L support to query inputs");
2429 bool usingv4l2 =
hasV4L2(videofd);
2432 struct v4l2_audio ain {};
2433 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMAUDIO, &ain) >= 0))
2435 QString input((
char *)ain.name);
2436 list[ain.index] = input;
2447 list[-1] += QObject::tr(
2448 "ERROR, Compile with V4L support to query audio inputs");
2458 "SELECT cardid, inputname "
2460 "WHERE hostname = :HOSTNAME "
2461 " AND videodevice = :DEVICE "
2462 " AND parentid = 0 "
2463 " AND inputname <> 'None'");
2471 while (query.
next())
2472 list[query.
value(0).toUInt()] = query.
value(1).toString();
2486 struct fe_caps_name {
2491 std::array<fe_caps_name,31> fe_caps_name {{
2492 { FE_CAN_2G_MODULATION,
"CAN_2G_MODULATION" },
2493 { FE_CAN_8VSB,
"CAN_8VSB" },
2494 { FE_CAN_16VSB,
"CAN_16VSB" },
2495 { FE_CAN_BANDWIDTH_AUTO,
"CAN_BANDWIDTH_AUTO" },
2496 { FE_CAN_FEC_1_2,
"CAN_FEC_1_2" },
2497 { FE_CAN_FEC_2_3,
"CAN_FEC_2_3" },
2498 { FE_CAN_FEC_3_4,
"CAN_FEC_3_4" },
2499 { FE_CAN_FEC_4_5,
"CAN_FEC_4_5" },
2500 { FE_CAN_FEC_5_6,
"CAN_FEC_5_6" },
2501 { FE_CAN_FEC_6_7,
"CAN_FEC_6_7" },
2502 { FE_CAN_FEC_7_8,
"CAN_FEC_7_8" },
2503 { FE_CAN_FEC_8_9,
"CAN_FEC_8_9" },
2504 { FE_CAN_FEC_AUTO,
"CAN_FEC_AUTO" },
2505 { FE_CAN_GUARD_INTERVAL_AUTO,
"CAN_GUARD_INTERVAL_AUTO" },
2506 { FE_CAN_HIERARCHY_AUTO,
"CAN_HIERARCHY_AUTO" },
2507 { FE_CAN_INVERSION_AUTO,
"CAN_INVERSION_AUTO" },
2508 { FE_CAN_MULTISTREAM,
"CAN_MULTISTREAM" },
2509 { FE_CAN_MUTE_TS,
"CAN_MUTE_TS" },
2510 { FE_CAN_QAM_16,
"CAN_QAM_16" },
2511 { FE_CAN_QAM_32,
"CAN_QAM_32" },
2512 { FE_CAN_QAM_64,
"CAN_QAM_64" },
2513 { FE_CAN_QAM_128,
"CAN_QAM_128" },
2514 { FE_CAN_QAM_256,
"CAN_QAM_256" },
2515 { FE_CAN_QAM_AUTO,
"CAN_QAM_AUTO" },
2516 { FE_CAN_QPSK,
"CAN_QPSK" },
2517 { FE_CAN_RECOVER,
"CAN_RECOVER" },
2518 { FE_CAN_TRANSMISSION_MODE_AUTO,
"CAN_TRANSMISSION_MODE_AUTO" },
2519 { FE_CAN_TURBO_FEC,
"CAN_TURBO_FEC" },
2520 { FE_HAS_EXTENDED_CAPS,
"HAS_EXTENDED_CAPS" },
2521 { FE_IS_STUPID,
"IS_STUPID" },
2522 { FE_NEEDS_BENDING,
"NEEDS_BENDING" },
2525 for (
const auto & cap : fe_caps_name)
2527 if (capabilities & cap.idx)
2528 caps.append(cap.name);
2540 else if (
"DVB" == inputtype)
2550 LOG(VB_GENERAL, LOG_DEBUG, QString(
"ProbeAudioInputs(%1,%2)")
2551 .arg(device, inputtype));
2554 if (
"HDPVR" == inputtype ||
2555 "V4L2" == inputtype)
2565 QByteArray dev = device.toLatin1();
2566 int videofd = open(dev.constData(), O_RDWR);
2569 ret += QObject::tr(
"Could not open '%1' "
2570 "to probe its inputs.").arg(device);
2582 InputNames::iterator it;
2583 for (it = list.begin(); it != list.end(); ++it)
2594 LOG(VB_GENERAL, LOG_DEBUG, QString(
"ProbeV4LAudioInputs(%1)").arg(device));
2598 int videofd = open(device.toLatin1().constData(), O_RDWR);
2601 LOG(VB_GENERAL, LOG_ERR,
"ProbeAudioInputs() -> couldn't open device");
2602 ret += QObject::tr(
"Could not open '%1' to probe its inputs.")
2615 InputNames::iterator it;
2616 for (it = list.begin(); it != list.end(); ++it)
2631 InputNames::iterator it;
2632 for (it = list.begin(); it != list.end(); ++it)
2638 ret += QObject::tr(
"ERROR, Compile with DVB support to query inputs");
2645 const QString &videodevice)
2647 return QString(
"[ %1 : %2 ]").arg(inputtype, videodevice);
2653 query.
prepare(
"SELECT cardtype, videodevice "
2654 "FROM capturecard WHERE cardid = :INPUTID ");
2660 query.
value(1).toString());
2663 return "[ UNKNOWN ]";
2667 const QString &device,
2668 const QString &inputtype,
2669 QStringList &inputs)
2673 inputs +=
"MPEG2TS";
2674 else if (inputtype ==
"DVB")
2675 inputs +=
"DVBInput";
2681 const QString &audiodevice,
2682 const QString &vbidevice,
2683 const QString &inputtype,
2684 const uint audioratelimit,
2686 const uint dvb_swfilter,
2687 const uint dvb_sat_type,
2688 bool dvb_wait_for_seqstart,
2691 const uint dvb_diseqc_type,
2692 const uint firewire_speed,
2693 const QString &firewire_model,
2694 const uint firewire_connection,
2695 const std::chrono::milliseconds signal_timeout,
2696 const std::chrono::milliseconds channel_timeout,
2697 const uint dvb_tuning_delay,
2698 const uint contrast,
2699 const uint brightness,
2702 const uint diseqcid,
2708 "INSERT INTO capturecard "
2709 "(videodevice, audiodevice, vbidevice, cardtype, "
2710 "audioratelimit, hostname, dvb_swfilter, dvb_sat_type, "
2711 "dvb_wait_for_seqstart, skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
2712 "firewire_speed, firewire_model, firewire_connection, signal_timeout, "
2713 "channel_timeout, dvb_tuning_delay, contrast, brightness, colour, "
2714 "hue, diseqcid, dvb_eitscan) "
2715 "VALUES (:VIDEODEVICE, :AUDIODEVICE, :VBIDEVICE, :INPUTTYPE, "
2716 ":AUDIORATELIMIT, :HOSTNAME, :DVBSWFILTER, :DVBSATTYPE, "
2717 ":DVBWAITFORSEQSTART, :SKIPBTAUDIO, :DVBONDEMAND, :DVBDISEQCTYPE, "
2718 ":FIREWIRESPEED, :FIREWIREMODEL, :FIREWIRECONNECTION, :SIGNALTIMEOUT, "
2719 ":CHANNELTIMEOUT, :DVBTUNINGDELAY, :CONTRAST, :BRIGHTNESS, :COLOUR, "
2720 ":HUE, :DISEQCID, :DVBEITSCAN ) ");
2722 query.
bindValue(
":VIDEODEVICE", videodevice);
2723 if (audiodevice.length() == 0)
2725#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2726 query.
bindValue(
":AUDIODEVICE", QVariant(QVariant::String));
2728 query.
bindValue(
":AUDIODEVICE", QVariant(QMetaType(QMetaType::QString)));
2733 query.
bindValue(
":AUDIODEVICE", audiodevice);
2735 if (vbidevice.length() == 0)
2737#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2738 query.
bindValue(
":VBIDEVICE", QVariant(QVariant::String));
2740 query.
bindValue(
":VBIDEVICE", QVariant(QMetaType(QMetaType::QString)));
2745 query.
bindValue(
":VBIDEVICE", vbidevice);
2747 query.
bindValue(
":INPUTTYPE", inputtype);
2748 if (audioratelimit == 0)
2750#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2751 query.
bindValue(
":AUDIORATELIMIT", QVariant(QVariant::UInt));
2753 query.
bindValue(
":AUDIORATELIMIT", QVariant(QMetaType(QMetaType::UInt)));
2758 query.
bindValue(
":AUDIORATELIMIT", audioratelimit);
2761 query.
bindValue(
":DVBSWFILTER", dvb_swfilter);
2762 query.
bindValue(
":DVBSATTYPE", dvb_sat_type);
2763 query.
bindValue(
":DVBWAITFORSEQSTART", dvb_wait_for_seqstart);
2764 query.
bindValue(
":SKIPBTAUDIO", skipbtaudio);
2765 query.
bindValue(
":DVBONDEMAND", dvb_on_demand);
2766 query.
bindValue(
":DVBDISEQCTYPE", dvb_diseqc_type);
2767 query.
bindValue(
":FIREWIRESPEED", firewire_speed);
2768 if (firewire_model.length() == 0)
2770#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2771 query.
bindValue(
":FIREWIREMODEL", QVariant(QVariant::String));
2773 query.
bindValue(
":FIREWIREMODEL", QVariant(QMetaType(QMetaType::QString)));
2778 query.
bindValue(
":FIREWIREMODEL", firewire_model);
2780 query.
bindValue(
":FIREWIRECONNECTION", firewire_connection);
2781 query.
bindValue(
":SIGNALTIMEOUT",
static_cast<qint64
>(signal_timeout.count()));
2782 query.
bindValue(
":CHANNELTIMEOUT",
static_cast<qint64
>(channel_timeout.count()));
2783 query.
bindValue(
":DVBTUNINGDELAY", dvb_tuning_delay);
2785 query.
bindValue(
":BRIGHTNESS", brightness);
2790#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2791 query.
bindValue(
":DISEQCID", QVariant(QVariant::UInt));
2793 query.
bindValue(
":DISEQCID", QVariant(QMetaType(QMetaType::UInt)));
2800 query.
bindValue(
":DVBEITSCAN", dvb_eitscan);
2808 query.
prepare(
"SELECT MAX(cardid) FROM capturecard");
2820 inputid = query.
value(0).toInt();
2832 for (
uint childid : childids)
2836 LOG(VB_GENERAL, LOG_ERR,
LOC +
2837 QString(
"CardUtil: Failed to delete child input %1")
2849 query.
prepare(
"DELETE FROM capturecard WHERE cardid = :INPUTID");
2858 query.
prepare(
"UPDATE capturecard SET reclimit=reclimit-1 "
2859 "WHERE cardid = :INPUTID");
2868 query.
prepare(
"DELETE FROM inputgroup WHERE cardinputid = :INPUTID");
2879 query.
prepare(
"SELECT cardid FROM capturecard "
2880 "WHERE diseqcid = :DISEQCID LIMIT 1");
2886 else if (!query.
next())
2889 tree.
Store(inputid);
2902 return (query.
exec(
"TRUNCATE TABLE inputgroup") &&
2903 query.
exec(
"TRUNCATE TABLE diseqc_config") &&
2904 query.
exec(
"TRUNCATE TABLE diseqc_tree") &&
2905 query.
exec(
"TRUNCATE TABLE capturecard"));
2910 std::vector<uint> list;
2922 while (query.
next())
2923 list.push_back(query.
value(0).toUInt());
2931 std::vector<uint> list;
2935 "SELECT DISTINCT cardid "
2937 "WHERE schedorder <> 0 "
2938 "ORDER BY schedorder, cardid");
2944 while (query.
next())
2945 list.push_back(query.
value(0).toUInt());
2953 std::vector<uint> list;
2957 "SELECT DISTINCT cardid "
2959 "WHERE livetvorder <> 0 "
2960 "ORDER BY livetvorder, cardid");
2966 while (query.
next())
2967 list.push_back(query.
value(0).toUInt());
2975 QString devname = QString(device);
2977 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"DVB Device (%1)").arg(devname));
2987 QString tmp = devname;
2988 tmp = tmp.replace(tmp.indexOf(
"frontend"), 8,
"dvr");
2991 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2992 QString(
"Adapter Frontend dvr number matches (%1)").arg(tmp));
2998 tmp = tmp.replace(tmp.indexOf(
"frontend"), 9,
"dvr0");
3001 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3002 QString(
"Adapter Frontend dvr number not matching, using dvr0 instead (%1)").arg(tmp));
3006 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3007 QString(
"Adapter Frontend no dvr device found for (%1)").arg(devname));
3013 QString tmp = devname;
3014 tmp = tmp.replace(tmp.indexOf(
"frontend"), 8,
"demux");
3017 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3018 QString(
"Adapter Frontend demux number matches (%1)").arg(tmp));
3024 tmp = tmp.replace(tmp.indexOf(
"frontend"), 9,
"demux0");
3027 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3028 QString(
"Adapter Frontend demux number not matching, using demux0 instead (%1)").arg(tmp));
3032 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3033 QString(
"Adapter Frontend no demux device found for (%1)").arg(devname));
3039 QString tmp = devname;
3040 tmp = tmp.replace(tmp.indexOf(
"frontend"), 8,
"ca");
3043 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3044 QString(
"Adapter Frontend ca number matches (%1)").arg(tmp));
3050 tmp = tmp.replace(tmp.indexOf(
"frontend"), 9,
"ca0");
3053 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3054 QString(
"Adapter Frontend ca number not matching, using ca0 instead (%1)").arg(tmp));
3058 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3059 QString(
"Adapter Frontend no ca device found for (%1)").arg(devname));
3065 return devname.replace(devname.indexOf(
"frontend"), 8,
"audio");
3070 return devname.replace(devname.indexOf(
"frontend"), 8,
"video");
3090 hdhomerun_device_create_from_str(device.toLatin1().constData(),
nullptr);
3094 const char *model = hdhomerun_device_get_model_str(hdhr);
3095 if (model && strstr(model,
"dvb"))
3097 hdhomerun_device_destroy(hdhr);
3101 hdhomerun_device_destroy(hdhr);
3116 hdhomerun_device_create_from_str(device.toLatin1().constData(),
nullptr);
3120 const char *model = hdhomerun_device_get_model_str(hdhr);
3121 if (model && strstr(model,
"dvbc"))
3123 hdhomerun_device_destroy(hdhr);
3127 hdhomerun_device_destroy(hdhr);
3140 QString connectErr = QObject::tr(
"Unable to connect to device.");
3143 [[maybe_unused]]
bool deviceIsIP =
false;
3145 if (device.contains(
'.'))
3149 bool validID =
false;
3151 uint32_t dev = device.toUInt(&validID, 16);
3152 if (!validID || !hdhomerun_discover_validate_device_id(dev))
3153 return QObject::tr(
"Invalid Device ID");
3156 LOG(VB_GENERAL, LOG_INFO,
"CardUtil::GetHDHRdescription(" + device +
3157 ") - trying to locate device");
3160 hdhomerun_device_create_from_str(device.toLatin1().constData(),
nullptr);
3162 return QObject::tr(
"Invalid Device ID or address.");
3164 const char *model = hdhomerun_device_get_model_str(hdhr);
3167 hdhomerun_device_destroy(hdhr);
3172 QString description = model;
3173 char *sVersion =
nullptr;
3174 uint32_t iVersion = 0;
3176 if (hdhomerun_device_get_version(hdhr, &sVersion, &iVersion))
3177 description += QObject::tr(
", firmware: %2").arg(sVersion);
3179 hdhomerun_device_destroy(hdhr);
3192 [[maybe_unused]]
const QString &ip,
3193 [[maybe_unused]]
const QString &tunerNo,
3194 [[maybe_unused]]
const QString &tunerType)
3196 QString connectErr = QObject::tr(
"Unable to connect to device.");
3211 QString apiVersionErr = QObject::tr(
"The VBox software version is too old (%1), we require %2")
3214 return apiVersionErr;
3220 return QString(
"V@Box TV Gateway - ID: %1, IP: %2, Tuner: %3-%4")
3221 .arg(
id, ip, tunerNo, tunerType);
3229static QString sys_dev(
uint device_num,
const QString& dev)
3231 return QString(
"/sys/class/asi/asirx%1/%2").arg(device_num).arg(dev);
3234static QString read_sys(
const QString& sys_dev)
3237 if (!f.open(QIODevice::ReadOnly))
3239 QByteArray sdba = f.readAll();
3244static bool write_sys(
const QString& sys_dev,
const QString& str)
3247 if (!f.open(QIODevice::WriteOnly))
3249 QByteArray ba = str.toLocal8Bit();
3251 for (
uint tries = 0; (offset < ba.size()) && tries < 5; tries++)
3253 qint64 written = f.write(ba.data()+offset, ba.size()-offset);
3266 struct stat statbuf {};
3267 if (stat(device.toLocal8Bit().constData(), &statbuf) < 0)
3270 *
error = QString(
"Unable to stat '%1'").arg(device) +
ENO;
3274 if (!S_ISCHR(statbuf.st_mode))
3277 *
error = QString(
"'%1' is not a character device").arg(device);
3281 if (!(statbuf.st_rdev & 0x0080))
3284 *
error = QString(
"'%1' not a DVEO ASI receiver").arg(device);
3288 int device_num = statbuf.st_rdev & 0x007f;
3291 QString sys_dev_contents = read_sys(sys_dev(device_num,
"dev"));
3292 QStringList sys_dev_clist = sys_dev_contents.split(
":");
3293 if (2 != sys_dev_clist.size())
3297 *
error = QString(
"Unable to read '%1'")
3298 .arg(sys_dev(device_num,
"dev"));
3302 if (sys_dev_clist[0].toUInt() != (statbuf.st_rdev>>8))
3305 *
error = QString(
"'%1' not a DVEO ASI device").arg(device);
3312 *
error =
"Not compiled with ASI support.";
3321 QString sys_bufsize_contents = read_sys(sys_dev(device_num,
"bufsize"));
3323 uint buf_size = sys_bufsize_contents.toUInt(&ok);
3328 *
error = QString(
"Failed to read buffer size from '%1'")
3329 .arg(sys_dev(device_num,
"bufsize"));
3336 *
error =
"Not compiled with ASI support.";
3345 QString sys_numbuffers_contents = read_sys(sys_dev(device_num,
"buffers"));
3347 uint num_buffers = sys_numbuffers_contents.toUInt(&ok);
3352 *
error = QString(
"Failed to read num buffers from '%1'")
3353 .arg(sys_dev(device_num,
"buffers"));
3360 *
error =
"Not compiled with ASI support.";
3368 QString sys_bufsize_contents = read_sys(sys_dev(device_num,
"mode"));
3370 uint mode = sys_bufsize_contents.toUInt(&ok);
3375 *
error = QString(
"Failed to read mode from '%1'")
3376 .arg(sys_dev(device_num,
"mode"));
3383 *
error =
"Not compiled with ASI support.";
3389 [[maybe_unused]]
uint mode,
3393 QString sys_bufsize_contents = read_sys(sys_dev(device_num,
"mode"));
3395 uint old_mode = sys_bufsize_contents.toUInt(&ok);
3396 if (ok && old_mode == mode)
3398 ok = write_sys(sys_dev(device_num,
"mode"), QString(
"%1\n").arg(mode));
3401 *
error = QString(
"Failed to set mode to %1 using '%2'")
3402 .arg(mode).arg(sys_dev(device_num,
"mode"));
3407 *
error =
"Not compiled with ASI support.";
3417bool CardUtil::IsVBoxPresent(
uint inputid)
3422 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX inputid (%1) not valid, redo mythtv-setup")
3433 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX chanid (%1) not found for inputid (%2), redo mythtv-setup")
3434 .arg(chanid).arg(inputid));
3439 std::chrono::milliseconds signal_timeout = 0ms;
3440 std::chrono::milliseconds tuning_timeout = 0ms;
3441 if (!
GetTimeouts(inputid,signal_timeout,tuning_timeout))
3443 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to get timeouts for inputid (%1)")
3451 query.prepare(
"SELECT url "
3452 "FROM iptv_channel "
3453 "WHERE chanid = :CHANID");
3454 query.bindValue(
":CHANID", chanid);
3458 else if (query.next())
3459 url = QUrl(query.value(0).toString());
3464 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX invalid url: %1")
3465 .arg(url.toString()));
3468 QString ip = url.host();
3469 LOG(VB_GENERAL, LOG_INFO, QString(
"VBOX IP found (%1) for inputid (%2)")
3470 .arg(ip).arg(inputid));
3472 if (!
ping(ip,signal_timeout))
3474 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX at IP (%1) failed to respond to network ping for inputid (%2) timeout (%3)")
3475 .arg(ip).arg(inputid).arg(signal_timeout.count()));
3488bool CardUtil::IsSatIPPresent(
uint inputid)
3493 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP inputid (%1) not valid, redo mythtv-setup")
3504 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP chanid (%1) not found for inputid (%2), redo mythtv-setup")
3505 .arg(chanid).arg(inputid));
3510 std::chrono::milliseconds signal_timeout = 0ms;
3511 std::chrono::milliseconds tuning_timeout = 0ms;
3512 if (!
GetTimeouts(inputid,signal_timeout,tuning_timeout))
3514 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to get timeouts for inputid (%1)")
3521 QStringList devinfo = device.split(
":");
3522 if (devinfo.value(0).toUpper() ==
"UUID")
3524 QString deviceId = QString(
"uuid:%1").arg(devinfo.value(1));
3526 LOG(VB_GENERAL, LOG_INFO, QString(
"SatIP[%1] IP address %2 device %3")
3527 .arg(inputid).arg(ip, device));
3529 if (!
ping(ip, signal_timeout))
3531 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP[%1] at IP %2 failed to respond to network ping (timeout %3)")
3532 .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