7 #if defined(USING_V4L2) || defined(USING_DVB)
16 #include "libmythbase/mythconfig.h"
37 #ifdef USING_HDHOMERUN
38 #include HDHOMERUN_HEADERFILE
50 #include <sys/types.h>
53 #include <dveo/master.h>
56 #define LOC QString("CardUtil: ")
60 QStringList inputTypes {};
63 inputTypes +=
"'DVB'";
67 inputTypes +=
"'V4L'";
68 inputTypes +=
"'MPEG'";
72 inputTypes +=
"'FREEBOX'";
76 inputTypes +=
"'VBOX'";
79 #ifdef USING_HDHOMERUN
80 inputTypes +=
"'HDHOMERUN'";
81 #endif // USING_HDHOMERUN
84 inputTypes +=
"'SATIP'";
88 inputTypes +=
"'ASI'";
92 inputTypes +=
"'CETON'";
95 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
96 inputTypes +=
"'EXTERNAL'";
99 if (inputTypes.isEmpty())
102 return QString(
"(%1)").arg(inputTypes.join(
','));
106 const QString &inputType)
108 #if (!USING_HDHOMERUN && !USING_CETON)
112 if (inputType ==
"HDHOMERUN")
114 #ifdef USING_HDHOMERUN
115 hdhomerun_tuner_status_t status {};
117 hdhomerun_device_t *hdhr =
118 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
122 int oob = hdhomerun_device_get_oob_status(hdhr,
nullptr, &status);
126 if (oob > 0 && (strncmp(status.channel,
"none", 4) != 0))
128 LOG(VB_GENERAL, LOG_INFO,
"Cardutil: HDHomeRun Cablecard Present.");
129 hdhomerun_device_destroy(hdhr);
133 hdhomerun_device_destroy(hdhr);
138 if (inputType ==
"CETON")
143 QStringList parts = device.split(
"-");
144 if (parts.size() != 2)
146 LOG(VB_GENERAL, LOG_ERR,
147 QString(
"CardUtil: Ceton invalid device id %1").arg(device));
151 const QString& ip_address = parts.at(0);
153 QStringList tuner_parts = parts.at(1).split(
".");
154 if (tuner_parts.size() != 2)
156 LOG(VB_GENERAL, LOG_ERR,
LOC +
157 QString(
"CardUtil: Ceton invalid device id %1").arg(device));
161 uint tuner = tuner_parts.at(1).toUInt();
164 params.addQueryItem(
"i", QString::number(tuner));
165 params.addQueryItem(
"s",
"cas");
166 params.addQueryItem(
"v",
"CardStatus");
169 url.setScheme(
"http");
170 url.setHost(ip_address);
171 url.setPath(
"/get_var.json");
172 url.setQuery(params);
174 auto *request =
new QNetworkRequest();
175 request->setAttribute(QNetworkRequest::CacheLoadControlAttribute,
176 QNetworkRequest::AlwaysNetwork);
177 request->setUrl(url);
182 if (!
manager->download(request, &data))
184 LOG(VB_GENERAL, LOG_ERR,
185 QString(
"CardUtil: Ceton http request failed %1").arg(device));
189 QString response = QString(data);
191 static const QRegularExpression regex {
"^\\{ \"?result\"?: \"(.*)\" \\}$"};
192 auto match = regex.match(response);
193 if (!match.hasMatch())
195 LOG(VB_GENERAL, LOG_ERR,
196 QString(
"CardUtil: Ceton unexpected http response: %1").arg(response));
200 QString result = match.captured(1);
202 if (result ==
"Inserted")
204 LOG(VB_GENERAL, LOG_DEBUG,
"Cardutil: Ceton CableCARD present.");
208 LOG(VB_GENERAL, LOG_DEBUG,
"Cardutil: Ceton CableCARD not present.");
219 if (rawtype ==
"DVB" || rawtype ==
"HDHOMERUN" ||
220 rawtype ==
"FREEBOX" || rawtype ==
"CETON" ||
221 rawtype ==
"VBOX" || rawtype ==
"SATIP")
225 if (rawtype ==
"V4L2ENC")
234 if (rawtype ==
"EXTERNAL")
245 LOG(VB_GENERAL, LOG_DEBUG, QString(
"IsTunerShared(%1,%2)")
246 .arg(inputidA).arg(inputidB));
249 query.
prepare(
"SELECT videodevice, hostname, cardtype "
251 "WHERE ( (cardid = :INPUTID_A) OR "
252 " (cardid = :INPUTID_B) )");
265 const QString vdevice = query.
value(0).toString();
267 const QString inputtype = query.
value(2).toString();
275 bool ret = ((vdevice == query.
value(0).toString()) &&
277 (inputtype == query.
value(2).toString()));
279 LOG(VB_RECORD, LOG_DEBUG, QString(
"IsTunerShared(%1,%2) -> %3")
280 .arg(inputidA).arg(inputidB).arg(ret));
297 "SELECT count(cardtype) "
299 "WHERE capturecard.hostname = :HOSTNAME ";
301 if (!rawtype.isEmpty())
302 qstr +=
" AND capturecard.cardtype = :INPUTTYPE";
306 if (!rawtype.isEmpty())
307 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
319 count = query.
value(0).toUInt();
329 query.
prepare(
"SELECT DISTINCT cardtype, videodevice "
342 cardtype = query.
value(0).toString();
343 if (cardtype !=
"V4L2ENC")
345 inputtypes[cardtype] =
"";
353 QString driver_name =
"V4L2:" + v4l2.
DriverName();
354 inputtypes[driver_name] = v4l2.
CardName();
374 query.
prepare(
"SELECT cardtype "
376 "WHERE capturecard.sourceid = :SOURCEID "
377 "GROUP BY cardtype");
387 list.push_back(query.
value(0).toString());
408 "SELECT videodevice "
410 "WHERE hostname = :HOSTNAME";
412 if (!rawtype.isEmpty())
413 qstr +=
" AND cardtype = :INPUTTYPE";
417 if (!rawtype.isEmpty())
418 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
428 QMap<QString,bool> dup;
431 QString videodevice = query.
value(0).toString();
432 if (dup[videodevice])
435 list.push_back(videodevice);
436 dup[videodevice] =
true;
457 if (rawtype.toUpper() ==
"DVB")
459 QDir dir(
"/dev/dvb",
"adapter*", QDir::Name, QDir::Dirs);
460 QFileInfoList entries = dir.entryInfoList();
461 for (
const auto & it : qAsConst(entries))
463 QDir subdir(it.filePath(),
"frontend*", QDir::Name, QDir::Files | QDir::System);
464 const QFileInfoList subil = subdir.entryInfoList();
468 for (
const auto & subit : qAsConst(subil))
469 devs.push_back(subit.filePath());
472 else if (rawtype.toUpper() ==
"ASI")
474 QDir dir(
"/dev/",
"asirx*", QDir::Name, QDir::System);
475 QFileInfoList entries = dir.entryInfoList();
476 for (
const auto & it : qAsConst(entries))
480 devs.push_back(it.filePath());
486 #ifdef USING_HDHOMERUN
487 else if (rawtype.toUpper() ==
"HDHOMERUN")
489 #if HDHOMERUN_VERSION >= 20221010
490 struct hdhomerun_debug_t *dbg = hdhomerun_debug_create();
491 struct hdhomerun_discover_t *ds = hdhomerun_discover_create(dbg);
494 uint32_t
type { HDHOMERUN_DEVICE_TYPE_TUNER };
495 uint32_t flags { HDHOMERUN_DISCOVER_FLAGS_IPV4_GENERAL |
496 HDHOMERUN_DISCOVER_FLAGS_IPV6_GENERAL };
498 hdhomerun_discover2_find_devices_broadcast(ds, flags, &
type, 1);
502 LOG(VB_GENERAL, LOG_ERR,
"Error finding HDHomerun devices");
504 else if (result == 0)
506 LOG(VB_GENERAL, LOG_INFO,
"No HDHomerun devices found.");
511 struct hdhomerun_discover2_device_t *device = hdhomerun_discover2_iter_device_first(ds);
514 uint8_t tuners = hdhomerun_discover2_device_get_tuner_count(device);
515 uint32_t device_id = hdhomerun_discover2_device_get_device_id(device);
516 QString
id = QString(
"%1").arg(device_id, 0, 16, QChar(
'0')).toUpper();
517 auto *dev1 = hdhomerun_device_create_from_str(
id.toLatin1(),
nullptr);
518 QString model = hdhomerun_device_get_model_str(dev1);
521 struct sockaddr_storage saddr {};
522 struct hdhomerun_discover2_device_if_t *device_if {
nullptr };
525 device_if = hdhomerun_discover2_iter_device_if_first(device);
528 hdhomerun_discover2_device_if_get_ip_addr(device_if, &saddr);
529 ip = QHostAddress((
struct sockaddr *)&saddr);
530 LOG(VB_GENERAL, LOG_DEBUG,
531 QString(
"HDHomerun %1 has IP %2").arg(
id, ip.toString()));
532 device_if = hdhomerun_discover2_iter_device_if_next(device_if);
536 device_if = hdhomerun_discover2_iter_device_if_first(device);
537 if (
nullptr == device_if)
539 LOG(VB_GENERAL, LOG_WARNING,
540 QString(
"HDHomerun %1 has no IP addresses").arg(
id));
543 hdhomerun_discover2_device_if_get_ip_addr(device_if, &saddr);
544 ip = QHostAddress((
struct sockaddr *)&saddr);
547 QString hdhrdev = QString(
"%1 %2 %3").arg(
id, ip.toString(), model);
548 devs.push_back(hdhrdev);
549 LOG(VB_GENERAL, LOG_INFO,
550 QString(
"HDHomerun %1: IP %2, model %3, %4 tuners")
551 .arg(
id, ip.toString(), model).arg(tuners));
553 device = hdhomerun_discover2_iter_device_next(device);
555 hdhomerun_discover_destroy(ds);
556 hdhomerun_debug_destroy(dbg);
558 #else // HDHOMERUN_VERSION >= 20221010
559 uint32_t target_ip = 0;
560 uint32_t device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
561 uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
562 const int max_count = 50;
563 std::array<hdhomerun_discover_device_t,max_count> result_list {};
565 int result = hdhomerun_discover_find_devices_custom_v2(
566 target_ip, device_type, device_id, result_list.data(), result_list.size());
570 LOG(VB_GENERAL, LOG_ERR,
"Error finding HDHomerun devices");
573 if (result >= max_count)
575 LOG(VB_GENERAL, LOG_WARNING,
576 "Warning: may be > 50 HDHomerun devices");
580 for (
int i = 0; i < result; i++)
582 QString
id = QString(
"%1").arg(result_list[i].device_id, 0, 16);
583 QString ip = QString(
"%1.%2.%3.%4")
584 .arg((result_list[i].ip_addr>>24) & 0xFF)
585 .arg((result_list[i].ip_addr>>16) & 0xFF)
586 .arg((result_list[i].ip_addr>> 8) & 0xFF)
587 .arg((result_list[i].ip_addr>> 0) & 0xFF);
590 hdhomerun_device_t *device = hdhomerun_device_create(
591 result_list[i].device_id, 0, 0,
nullptr);
594 model = hdhomerun_device_get_model_str(device);
595 hdhomerun_device_destroy(device);
598 QString hdhrdev =
id.toUpper() +
" " + ip +
" " + model;
599 devs.push_back(hdhrdev);
601 #endif // HDHOMERUN_VERSION >= 20221010
603 #endif // USING_HDHOMERUN
605 else if (rawtype.toUpper() ==
"SATIP")
609 #endif // USING_SATIP
611 else if (rawtype.toUpper() ==
"VBOX")
617 else if (rawtype.toUpper() ==
"CETON")
620 LOG(VB_GENERAL, LOG_INFO,
"CardUtil::ProbeVideoDevices: "
621 "TODO Probe Ceton devices");
623 #endif // USING_CETON
626 LOG(VB_GENERAL, LOG_ERR, QString(
"Raw Type: '%1' is not supported")
637 QStringList delsyslist;
646 struct dtv_property prop = {};
647 struct dtv_properties cmd = {};
649 prop.cmd = DTV_API_VERSION;
652 if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
654 LOG(VB_GENERAL, LOG_DEBUG,
655 QString(
"CardUtil(%1): ").arg(device) +
656 QString(
"dvb api version %1.%2").arg((prop.u.data>>8)&0xff).arg((prop.u.data)&0xff));
660 LOG(VB_GENERAL, LOG_ERR,
661 QString(
"CardUtil(%1) FE_GET_PROPERTY ioctl failed").arg(device) +
ENO);
668 QString msg =
"Delivery systems:";
669 for (
const auto & item : qAsConst(delsyslist))
674 LOG(VB_GENERAL, LOG_INFO, QString(
"CardUtil(%1): ").arg(device) + msg);
687 QStringList delsyslist;
690 struct dtv_property prop = {};
691 struct dtv_properties cmd = {};
693 prop.cmd = DTV_ENUM_DELSYS;
696 if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
698 for (
unsigned int i = 0; i < prop.u.buffer.len; i++)
705 LOG(VB_GENERAL, LOG_ERR,
LOC +
"FE_GET_PROPERTY ioctl failed " +
ENO);
708 Q_UNUSED(fd_frontend);
734 QString ret =
"ERROR_UNKNOWN";
736 if (device.isEmpty())
741 ret = (
type.toString() !=
"UNKNOWN") ?
type.toString().toUpper() : ret;
743 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"(%1) tuner type:%2 %3")
744 .arg(device).arg(
type).arg(ret));
755 QString ret =
"ERROR_UNKNOWN";
759 QByteArray dev = dvbdev.toLatin1();
760 int fd_frontend = open(dev.constData(), O_RDWR |
O_NONBLOCK);
764 struct dvb_frontend_info info {};
765 int err = ioctl(fd_frontend, FE_GET_INFO, &info);
769 return "ERROR_PROBE";
802 return ((name ==
"VLSI VES1x93 DVB-S") ||
803 (name ==
"ST STV0299 DVB-S"));
809 if (name.indexOf(
"DVB-S") >= 0)
811 if (name ==
"DiBcom 3000P/M-C DVB-T")
849 LOG(VB_GENERAL, LOG_ERR,
LOC +
850 QString(
"TODO Add to switch case delivery system:%2 %3")
851 .arg(delsys).arg(delsys.
toString()));
890 "FROM dtv_multiplex "
891 "WHERE dtv_multiplex.mplexid = :MPLEXID");
902 LOG(VB_GENERAL, LOG_ERR,
LOC +
903 QString(
"Could not find entry in dtv_multiplex for mplexid %1")
930 if (device.isEmpty())
939 LOG(VB_GENERAL, LOG_ERR,
LOC +
940 QString(
"open failed (%1)")
947 LOG(VB_GENERAL, LOG_DEBUG, QString(
"CardUtil(%1): delsys:%2 %3")
948 .arg(device).arg(delsys).arg(delsys.
toString()));
964 struct dtv_property prop = {};
965 struct dtv_properties cmd = {};
967 prop.cmd = DTV_DELIVERY_SYSTEM;
972 int ret = ioctl(fd_frontend, FE_GET_PROPERTY, &cmd);
975 LOG(VB_GENERAL, LOG_ERR,
LOC +
976 QString(
"FE_GET_PROPERTY ioctl failed (fd_frontend:%1)")
977 .arg(fd_frontend) +
ENO);
981 delsys = prop.u.data;
984 Q_UNUSED(fd_frontend);
1004 if (fd_frontend < 0)
1005 return "ERROR_OPEN";
1015 LOG(VB_GENERAL, LOG_INFO,
1016 QString(
"CardUtil[%1]: ").arg(inputid) +
1017 QString(
"Update capturecard delivery system: %1").arg(delsys.
toString()));
1021 LOG(VB_GENERAL, LOG_ERR,
1022 QString(
"CardUtil[%1]: Error probing best delivery system").arg(inputid));
1023 return "ERROR_UNKNOWN";
1030 QString subtype =
"ERROR_UNKNOWN";
1036 LOG(VB_GENERAL, LOG_DEBUG,
1037 QString(
"CardUtil[%1]: subtype:%2").arg(inputid).arg(subtype));
1045 QString
t = inputType.toUpper();
1046 return (
t ==
"DVB") || (
t ==
"QPSK") || (
t ==
"QAM") || (
t ==
"OFDM") ||
1047 (
t ==
"ATSC") || (
t ==
"DVB_S2") || (
t ==
"DVB_T2");
1062 LOG(VB_GENERAL, LOG_INFO,
LOC +
1063 QString(
"Current delivery system: %1").arg(delsys.
toString()));
1066 QString msg =
"Supported delivery systems:";
1068 msg.append(delsyslist.join(
" "));
1069 LOG(VB_GENERAL, LOG_DEBUG,
LOC + msg);
1075 if (delsyslist.contains(newdelsys.
toString()))
1077 LOG(VB_GENERAL, LOG_INFO,
LOC +
1078 QString(
"Changing delivery system from %1 to %2")
1088 if (delsyslist.contains(newdelsys.
toString()))
1090 LOG(VB_GENERAL, LOG_INFO,
LOC +
1091 QString(
"Changing delivery system from %1 to %2")
1121 LOG(VB_GENERAL, LOG_INFO,
1122 QString(
"CardUtil[%1]: ").arg(inputid) +
1123 QString(
"No capturecard delivery system in database, using: %1").arg(delsys.
toString()));
1180 if (device.isEmpty())
1182 LOG(VB_GENERAL, LOG_DEBUG,
1183 QString(
"CardUtil[%1]: ").arg(inputid) +
1184 QString(
"inputid:%1 ").arg(inputid) +
1185 QString(
"delsys:%1").arg(delsys.
toString()));
1190 if (fd_frontend < 0)
1192 LOG(VB_GENERAL, LOG_ERR,
1193 QString(
"CardUtil[%1]: ").arg(inputid) +
1194 QString(
"open failed (%1)").arg(device) +
ENO);
1233 LOG(VB_GENERAL, LOG_INFO,
1234 QString(
"CardUtil[%1]: ").arg(inputid) +
1235 QString(
"Set delivery system: %1").arg(delsys.
toString()));
1237 struct dtv_property prop = {};
1238 struct dtv_properties cmd = {};
1240 prop.cmd = DTV_DELIVERY_SYSTEM;
1241 prop.u.data = delsys;
1245 ret = ioctl(fd, FE_SET_PROPERTY, &cmd);
1248 LOG(VB_GENERAL, LOG_ERR,
LOC +
1249 QString(
"[%1] FE_SET_PROPERTY ioctl failed")
1250 .arg(inputid) +
ENO);
1270 if (device.isEmpty())
1274 QByteArray dev = dvbdev.toLatin1();
1275 int fd_frontend = open(dev.constData(), O_RDWR |
O_NONBLOCK);
1276 if (fd_frontend < 0)
1278 LOG(VB_GENERAL, LOG_ERR,
LOC +
1279 QString(
"Can't open DVB frontend (%1) for %2.")
1280 .arg(dvbdev, device) +
ENO);
1289 QString(
"SELECT %1 ").arg(to_get) +
1291 "WHERE capturecard.cardid = :INPUTID");
1296 else if (query.
next())
1297 return query.
value(0).toString();
1310 QString(
"UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
1311 "WHERE cardid = :INPUTID");
1333 const QString& rawtype,
1334 const QString& inputname,
1337 std::vector<uint> list;
1346 "WHERE hostname = :HOSTNAME ";
1347 if (!videodevice.isEmpty())
1348 qstr +=
"AND videodevice = :DEVICE ";
1349 if (!inputname.isEmpty())
1350 qstr +=
"AND inputname = :INPUTNAME ";
1351 if (!rawtype.isEmpty())
1352 qstr +=
"AND cardtype = :INPUTTYPE ";
1353 qstr +=
"ORDER BY cardid";
1358 if (!videodevice.isEmpty())
1359 query.
bindValue(
":DEVICE", videodevice);
1360 if (!inputname.isEmpty())
1361 query.
bindValue(
":INPUTNAME", inputname);
1362 if (!rawtype.isEmpty())
1363 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
1369 while (query.
next())
1370 list.push_back(query.
value(0).toUInt());
1385 "WHERE parentid = :INPUTID";
1394 else if (query.
next())
1395 count = query.
value(0).toUInt();
1402 std::vector<uint> list;
1411 "WHERE parentid = :INPUTID "
1421 while (query.
next())
1422 list.push_back(query.
value(0).toUInt());
1430 uint dst_inputid = orig_dst_inputid;
1436 "DELETE FROM capturecard "
1437 "WHERE videodevice = 'temp_dummy'");
1446 "INSERT INTO capturecard "
1447 "SET videodevice = 'temp_dummy'");
1458 "WHERE videodevice = 'temp_dummy'");
1468 LOG(VB_GENERAL, LOG_ERR,
"clone_capturecard -- get temp id");
1472 dst_inputid = query.
value(0).toUInt();
1476 "SELECT videodevice, audiodevice, vbidevice, "
1477 " cardtype, hostname, signal_timeout, "
1478 " channel_timeout, dvb_wait_for_seqstart, dvb_on_demand, "
1479 " dvb_tuning_delay, dvb_diseqc_type, diseqcid, "
1480 " dvb_eitscan, inputname, sourceid, "
1481 " externalcommand, changer_device, changer_model, "
1482 " tunechan, startchan, displayname, "
1483 " dishnet_eit, recpriority, quicktune, "
1484 " livetvorder, reclimit, "
1486 " schedgroup, schedorder "
1488 "WHERE cardid = :INPUTID");
1489 query.
bindValue(
":INPUTID", src_inputid);
1498 LOG(VB_GENERAL, LOG_ERR,
"clone_cardinput -- get data 2");
1505 bool schedgroup = query.
value(26).toBool();
1506 uint schedorder = query.
value(27).toUInt();
1515 "UPDATE capturecard "
1516 "SET videodevice = :V0, "
1517 " audiodevice = :V1, "
1518 " vbidevice = :V2, "
1521 " signal_timeout = :V5, "
1522 " channel_timeout = :V6, "
1523 " dvb_wait_for_seqstart = :V7, "
1524 " dvb_on_demand = :V8, "
1525 " dvb_tuning_delay = :V9, "
1526 " dvb_diseqc_type = :V10, "
1528 " dvb_eitscan = :V12, "
1529 " inputname = :V13, "
1530 " sourceid = :V14, "
1531 " externalcommand = :V15, "
1532 " changer_device = :V16, "
1533 " changer_model = :V17, "
1534 " tunechan = :V18, "
1535 " startchan = :V19, "
1536 " displayname = :V20, "
1537 " dishnet_eit = :V21, "
1538 " recpriority = :V22, "
1539 " quicktune = :V23, "
1540 " livetvorder = :V24, "
1541 " reclimit = :V25, "
1542 " schedgroup = :SCHEDGROUP, "
1543 " schedorder = :SCHEDORDER, "
1544 " parentid = :PARENTID "
1545 "WHERE cardid = :INPUTID");
1546 for (
uint i = 0; i < 26; ++i)
1547 query2.
bindValue(QString(
":V%1").arg(i), query.
value(i).toString());
1548 query2.
bindValue(
":INPUTID", dst_inputid);
1549 query2.
bindValue(
":PARENTID", src_inputid);
1550 query2.
bindValue(
":SCHEDGROUP", schedgroup);
1551 query2.
bindValue(
":SCHEDORDER", schedorder);
1556 if (!orig_dst_inputid)
1564 for (
uint dst_grp : dst_grps)
1566 for (
uint src_grp : src_grps)
1571 if (diseqc.
Load(src_inputid))
1572 diseqc.
Store(dst_inputid);
1590 if (max_recordings < 1)
1592 LOG(VB_GENERAL, LOG_ERR,
LOC +
1593 "InputSetMaxRecording: max must be greater than zero.");
1600 for (
size_t i = cardids.size() + 1;
1601 (i > max_recordings) && !cardids.empty(); --i)
1608 for (
uint id : cardids)
1612 for (
size_t i = cardids.size() + 1; i < max_recordings; ++i)
1629 LOG(VB_GENERAL, LOG_INFO,
LOC +
1630 QString(
"Added child input %1 to parent %2")
1631 .arg(inputid).arg(parentid));
1633 query.
prepare(
"UPDATE capturecard "
1634 "SET reclimit = reclimit + 1 "
1635 "WHERE cardid = :PARENTID");
1642 LOG(VB_GENERAL, LOG_ERR,
LOC +
1643 QString(
"Failed to add child input to parent %1").arg(parentid));
1654 query.
prepare(
"SELECT changer_device "
1655 "FROM capturecard WHERE cardid = :INPUTID ");
1660 fwnode = query.
value(0).toString();
1671 query.
prepare(
"SELECT changer_model "
1672 "FROM capturecard WHERE cardid = :INPUTID ");
1677 fwnode = query.
value(0).toString();
1688 "SELECT DISTINCT cardid "
1690 "WHERE sourceid = :SOURCEID");
1693 std::vector<uint> list;
1701 while (query.
next())
1702 list.push_back(query.
value(0).toUInt());
1710 query.
prepare(
"UPDATE capturecard "
1711 "SET startchan = :CHANNUM "
1712 "WHERE cardid = :INPUTID");
1732 "inputname, sourceid, livetvorder, "
1733 "schedorder, displayname, recpriority, quicktune "
1735 "WHERE cardid = :INPUTID");
1763 QList<InputInfo> infoInputList;
1766 query.
prepare(
"SELECT cardid, "
1767 "inputname, sourceid, livetvorder, "
1768 "schedorder, displayname, recpriority, quicktune "
1769 "FROM capturecard");
1774 return infoInputList;
1777 while (query.
next())
1789 infoInputList.push_back(input);
1792 return infoInputList;
1797 InputInfo info(
"None", 0, inputid, 0, 0, 0);
1819 query.
prepare(
"SELECT startchan "
1821 "WHERE cardid = :INPUTID");
1828 else if (query.
next())
1830 startchan = query.
value(0).toString();
1834 if (!startchan.isEmpty())
1836 query.
prepare(
"SELECT channel.chanid "
1837 "FROM capturecard, channel "
1838 "WHERE capturecard.cardid = :INPUTID AND "
1839 " capturecard.sourceid = channel.sourceid AND "
1840 " channel.deleted IS NULL AND "
1841 " channel.visible > 0 AND "
1842 " channel.channum = :CHANNUM");
1850 else if (!query.
next())
1852 LOG(VB_GENERAL, LOG_WARNING,
1853 QString(
"CardUtil[%1]: ").arg(inputid) +
1854 QString(
"Channel %1 on inputid %2 is invalid").arg(startchan).arg(inputid));
1861 if (startchan.isEmpty())
1863 query.
prepare(
"SELECT channel.channum "
1864 "FROM capturecard, channel "
1865 "WHERE capturecard.cardid = :INPUTID AND "
1866 " capturecard.sourceid = channel.sourceid AND "
1867 " channel.deleted IS NULL AND "
1868 " channel.visible > 0 "
1876 else if (query.
next())
1878 startchan = query.
value(0).toString();
1882 if (startchan.isEmpty())
1884 LOG(VB_GENERAL, LOG_WARNING,
1885 QString(
"CardUtil[%1]: ").arg(inputid) +
1886 QString(
"No start channel found on inputid %1").arg(inputid));
1890 LOG(VB_GENERAL, LOG_DEBUG,
1891 QString(
"CardUtil[%1]: ").arg(inputid) +
1892 QString(
"Start channel %1 on inputid %2").arg(startchan).arg(inputid));
1904 query.
prepare(
"SELECT displayname "
1906 "WHERE cardid = :INPUTID");
1911 else if (query.
next())
1913 QString result = query.
value(0).toString();
1925 qsizetype idx { 0 };
1928 if ((idx = name.indexOf(
'/')) >= 0)
1930 matching = name.right(name.size() - idx -1);
1935 matching = name.right(2);
1940 query.
prepare(
"SELECT cardid, displayname "
1942 "WHERE parentid = 0 "
1943 " AND cardid <> :INPUTID ");
1944 query.
bindValue(
":INPUTID", exclude_inputid);
1952 while (query.
next())
1954 QString dn = query.
value(1).toString();
1955 if (!two && (idx = dn.indexOf(
'/')) >= 0)
1957 if (dn.right(dn.size() - idx - 1) == matching)
1960 else if (dn.right(2) == matching.right(2))
1973 "WHERE cardid = :INPUTID");
1977 else if (query.
next())
1978 return query.
value(0).toUInt();
1987 const uint sourceid,
1988 const QString &inputname,
1989 const QString &externalcommand,
1990 const QString &changer_device,
1991 const QString &changer_model,
1993 const QString &tunechan,
1994 const QString &startchan,
1995 const QString &displayname,
1997 const uint recpriority,
1998 const uint quicktune,
1999 const uint schedorder,
2000 const uint livetvorder)
2005 "UPDATE capturecard "
2006 "SET sourceid = :SOURCEID, "
2007 " inputname = :INPUTNAME, "
2008 " externalcommand = :EXTERNALCOMMAND, "
2009 " changer_device = :CHANGERDEVICE, "
2010 " changer_model = :CHANGERMODEL, "
2011 " tunechan = :TUNECHAN, "
2012 " startchan = :STARTCHAN, "
2013 " displayname = :DISPLAYNAME, "
2014 " dishnet_eit = :DISHNETEIT, "
2015 " recpriority = :RECPRIORITY, "
2016 " quicktune = :QUICKTUNE, "
2017 " schedorder = :SCHEDORDER, "
2018 " livetvorder = :LIVETVORDER "
2019 "WHERE cardid = :INPUTID AND "
2020 " inputname = 'None'");
2024 query.
bindValue(
":INPUTNAME", inputname);
2025 query.
bindValue(
":EXTERNALCOMMAND", externalcommand);
2026 query.
bindValue(
":CHANGERDEVICE", changer_device);
2027 query.
bindValue(
":CHANGERMODEL", changer_model);
2029 query.
bindValue(
":STARTCHAN", startchan);
2031 query.
bindValue(
":DISHNETEIT", dishnet_eit);
2032 query.
bindValue(
":RECPRIORITY", recpriority);
2033 query.
bindValue(
":QUICKTUNE", quicktune);
2034 query.
bindValue(
":SCHEDORDER", schedorder);
2035 query.
bindValue(
":LIVETVORDER", livetvorder);
2050 query.
prepare(
"SELECT inputgroupid FROM inputgroup "
2051 "WHERE inputgroupname = :GROUPNAME "
2061 return query.
value(0).toUInt();
2063 query.
prepare(
"SELECT MAX(inputgroupid) FROM inputgroup");
2070 uint inputgroupid = (query.
next()) ? query.
value(0).toUInt() + 1 : 1;
2073 "INSERT INTO inputgroup "
2074 " (cardinputid, inputgroupid, inputgroupname) "
2075 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2077 query.
bindValue(
":GROUPID", inputgroupid);
2085 return inputgroupid;
2089 const QString &
type,
2090 const QString &host,
2091 const QString &device)
2093 QString name = host +
'|' + device;
2094 if (
type ==
"FREEBOX" ||
type ==
"IMPORT" ||
2095 type ==
"DEMO" ||
type ==
"EXTERNAL" ||
2096 type ==
"HDHOMERUN" )
2097 name += QString(
"|%1").arg(inputid);
2105 "SELECT inputgroupid "
2107 "WHERE cardinputid = :INPUTID "
2108 " AND inputgroupname REGEXP '^[a-z_-]*\\\\|'");
2119 return query.
value(0).toUInt();
2130 "SELECT cardinputid, inputgroupid, inputgroupname "
2132 "WHERE inputgroupid = :GROUPID "
2133 "ORDER BY inputgroupid, cardinputid, inputgroupname");
2134 query.
bindValue(
":GROUPID", inputgroupid);
2143 while (query.
next()) {
2144 name = query.
value(2).toString();
2147 if (cardid == inputid)
2156 "INSERT INTO inputgroup "
2157 " (cardinputid, inputgroupid, inputgroupname) "
2158 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2161 query.
bindValue(
":GROUPID", inputgroupid);
2180 if (!inputid && !inputgroupid)
2183 "DELETE FROM inputgroup "
2184 "WHERE cardinputid NOT IN "
2185 "( SELECT cardid FROM capturecard )");
2190 "DELETE FROM inputgroup "
2191 "WHERE cardinputid = :INPUTID AND "
2192 " inputgroupid = :GROUPID ");
2195 query.
bindValue(
":GROUPID", inputgroupid);
2209 std::vector<uint> list;
2214 "SELECT inputgroupid "
2216 "WHERE cardinputid = :INPUTID "
2217 "ORDER BY inputgroupid, cardinputid, inputgroupname");
2227 while (query.
next())
2228 list.push_back(query.
value(0).toUInt());
2235 std::vector<uint> list;
2240 "SELECT DISTINCT cardid "
2241 "FROM capturecard, inputgroup "
2242 "WHERE inputgroupid = :GROUPID AND "
2243 " capturecard.cardid = inputgroup.cardinputid "
2246 query.
bindValue(
":GROUPID", inputgroupid);
2254 while (query.
next())
2255 list.push_back(query.
value(0).toUInt());
2262 std::vector<uint> inputids;
2267 "SELECT DISTINCT c.cardid "
2269 " SELECT inputgroupid "
2271 " WHERE cardinputid = :INPUTID1 "
2273 "JOIN inputgroup ig ON ig.inputgroupid = g.inputgroupid "
2274 "JOIN capturecard c ON c.cardid = ig.cardinputid "
2275 " AND c.cardid <> :INPUTID2 "
2276 "ORDER BY c.cardid");
2287 while (query.
next())
2289 inputids.push_back(query.
value(0).toUInt());
2294 QString msg = QString(
"CardUtil[%1]: GetConflictingInputs(%1) ").arg(inputid);
2296 for (
auto id : inputids)
2298 ids.append(QString::number(
id));
2300 msg.append(ids.join(
','));
2301 LOG(VB_RECORD, LOG_INFO, msg);
2307 std::chrono::milliseconds &signal_timeout,
2308 std::chrono::milliseconds &channel_timeout)
2312 "SELECT signal_timeout, channel_timeout "
2314 "WHERE cardid = :INPUTID");
2319 else if (query.
next())
2321 signal_timeout = std::max(std::chrono::milliseconds(query.
value(0).toInt()), 250ms);
2322 channel_timeout = std::max(std::chrono::milliseconds(query.
value(1).toInt()), 500ms);
2333 bool needsConf =
false;
2348 "WHERE cardid = :INPUTID AND "
2349 " inputname = :INPUTNAME");
2351 query.
bindValue(
":INPUTNAME", input_name);
2355 else if (query.
next())
2356 quicktune = query.
value(0).toUInt();
2365 struct v4l2_capability vcap {};
2367 return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
2368 ((vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE) != 0U));
2369 #else // if !USING_V4L2
2371 #endif // !USING_V4L2
2375 int videofd, QString &input, QString &driver, uint32_t &
version,
2376 uint32_t &capabilities)
2387 struct v4l2_capability capability {};
2388 if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
2390 input = QString::fromLatin1((
const char*)capability.card);
2391 driver = QString::fromLatin1((
const char*)capability.driver);
2393 capabilities = capability.capabilities;
2395 #endif // USING_V4L2
2397 static const QRegularExpression kBracketedDigitRE { R
"(\[[0-9]\]$)" };
2398 if (!driver.isEmpty())
2399 driver.remove( kBracketedDigitRE );
2401 return !input.isEmpty();
2412 bool usingv4l2 =
hasV4L2(videofd);
2414 struct v4l2_input vin {};
2415 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
2417 QString input((
char *)vin.name);
2418 list[vin.index] = input;
2429 list[0] =
"Television";
2432 #else // if !USING_V4L2
2433 list[-1] += QObject::tr(
"ERROR, Compile with V4L support to query inputs");
2434 #endif // !USING_V4L2
2446 bool usingv4l2 =
hasV4L2(videofd);
2449 struct v4l2_audio ain {};
2450 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMAUDIO, &ain) >= 0))
2452 QString input((
char *)ain.name);
2453 list[ain.index] = input;
2463 #else // if !USING_V4L2
2464 list[-1] += QObject::tr(
2465 "ERROR, Compile with V4L support to query audio inputs");
2466 #endif // !USING_V4L2
2475 "SELECT cardid, inputname "
2477 "WHERE hostname = :HOSTNAME "
2478 " AND videodevice = :DEVICE "
2479 " AND parentid = 0 "
2480 " AND inputname <> 'None'");
2488 while (query.
next())
2489 list[query.
value(0).toUInt()] = query.
value(1).toString();
2503 struct fe_caps_name {
2508 std::array<fe_caps_name,31> fe_caps_name {{
2509 { FE_CAN_2G_MODULATION,
"CAN_2G_MODULATION" },
2510 { FE_CAN_8VSB,
"CAN_8VSB" },
2511 { FE_CAN_16VSB,
"CAN_16VSB" },
2512 { FE_CAN_BANDWIDTH_AUTO,
"CAN_BANDWIDTH_AUTO" },
2513 { FE_CAN_FEC_1_2,
"CAN_FEC_1_2" },
2514 { FE_CAN_FEC_2_3,
"CAN_FEC_2_3" },
2515 { FE_CAN_FEC_3_4,
"CAN_FEC_3_4" },
2516 { FE_CAN_FEC_4_5,
"CAN_FEC_4_5" },
2517 { FE_CAN_FEC_5_6,
"CAN_FEC_5_6" },
2518 { FE_CAN_FEC_6_7,
"CAN_FEC_6_7" },
2519 { FE_CAN_FEC_7_8,
"CAN_FEC_7_8" },
2520 { FE_CAN_FEC_8_9,
"CAN_FEC_8_9" },
2521 { FE_CAN_FEC_AUTO,
"CAN_FEC_AUTO" },
2522 { FE_CAN_GUARD_INTERVAL_AUTO,
"CAN_GUARD_INTERVAL_AUTO" },
2523 { FE_CAN_HIERARCHY_AUTO,
"CAN_HIERARCHY_AUTO" },
2524 { FE_CAN_INVERSION_AUTO,
"CAN_INVERSION_AUTO" },
2525 { FE_CAN_MULTISTREAM,
"CAN_MULTISTREAM" },
2526 { FE_CAN_MUTE_TS,
"CAN_MUTE_TS" },
2527 { FE_CAN_QAM_16,
"CAN_QAM_16" },
2528 { FE_CAN_QAM_32,
"CAN_QAM_32" },
2529 { FE_CAN_QAM_64,
"CAN_QAM_64" },
2530 { FE_CAN_QAM_128,
"CAN_QAM_128" },
2531 { FE_CAN_QAM_256,
"CAN_QAM_256" },
2532 { FE_CAN_QAM_AUTO,
"CAN_QAM_AUTO" },
2533 { FE_CAN_QPSK,
"CAN_QPSK" },
2534 { FE_CAN_RECOVER,
"CAN_RECOVER" },
2535 { FE_CAN_TRANSMISSION_MODE_AUTO,
"CAN_TRANSMISSION_MODE_AUTO" },
2536 { FE_CAN_TURBO_FEC,
"CAN_TURBO_FEC" },
2537 { FE_HAS_EXTENDED_CAPS,
"HAS_EXTENDED_CAPS" },
2538 { FE_IS_STUPID,
"IS_STUPID" },
2539 { FE_NEEDS_BENDING,
"NEEDS_BENDING" },
2542 for (
const auto & cap : fe_caps_name)
2544 if (capabilities & cap.idx)
2545 caps.append(cap.name);
2548 Q_UNUSED(capabilities);
2559 else if (
"DVB" == inputtype)
2569 LOG(VB_GENERAL, LOG_DEBUG, QString(
"ProbeAudioInputs(%1,%2)")
2570 .arg(device, inputtype));
2573 if (
"HDPVR" == inputtype ||
2574 "V4L2" == inputtype)
2584 QByteArray dev = device.toLatin1();
2585 int videofd = open(dev.constData(), O_RDWR);
2588 ret += QObject::tr(
"Could not open '%1' "
2589 "to probe its inputs.").arg(device);
2601 InputNames::iterator it;
2602 for (it = list.begin(); it != list.end(); ++it)
2613 LOG(VB_GENERAL, LOG_DEBUG, QString(
"ProbeV4LAudioInputs(%1)").arg(device));
2617 int videofd = open(device.toLatin1().constData(), O_RDWR);
2620 LOG(VB_GENERAL, LOG_ERR,
"ProbeAudioInputs() -> couldn't open device");
2621 ret += QObject::tr(
"Could not open '%1' to probe its inputs.")
2634 InputNames::iterator it;
2635 for (it = list.begin(); it != list.end(); ++it)
2650 InputNames::iterator it;
2651 for (it = list.begin(); it != list.end(); ++it)
2658 ret += QObject::tr(
"ERROR, Compile with DVB support to query inputs");
2665 const QString &videodevice)
2667 return QString(
"[ %1 : %2 ]").arg(inputtype, videodevice);
2673 query.
prepare(
"SELECT cardtype, videodevice "
2674 "FROM capturecard WHERE cardid = :INPUTID ");
2680 query.
value(1).toString());
2683 return "[ UNKNOWN ]";
2687 const QString &device,
2688 const QString &inputtype,
2689 QStringList &inputs)
2693 inputs +=
"MPEG2TS";
2694 else if (inputtype ==
"DVB")
2695 inputs +=
"DVBInput";
2701 const QString &audiodevice,
2702 const QString &vbidevice,
2703 const QString &inputtype,
2704 const uint audioratelimit,
2706 const uint dvb_swfilter,
2707 const uint dvb_sat_type,
2708 bool dvb_wait_for_seqstart,
2711 const uint dvb_diseqc_type,
2712 const uint firewire_speed,
2713 const QString &firewire_model,
2714 const uint firewire_connection,
2715 const std::chrono::milliseconds signal_timeout,
2716 const std::chrono::milliseconds channel_timeout,
2717 const uint dvb_tuning_delay,
2718 const uint contrast,
2719 const uint brightness,
2722 const uint diseqcid,
2728 "INSERT INTO capturecard "
2729 "(videodevice, audiodevice, vbidevice, cardtype, "
2730 "audioratelimit, hostname, dvb_swfilter, dvb_sat_type, "
2731 "dvb_wait_for_seqstart, skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
2732 "firewire_speed, firewire_model, firewire_connection, signal_timeout, "
2733 "channel_timeout, dvb_tuning_delay, contrast, brightness, colour, "
2734 "hue, diseqcid, dvb_eitscan) "
2735 "VALUES (:VIDEODEVICE, :AUDIODEVICE, :VBIDEVICE, :INPUTTYPE, "
2736 ":AUDIORATELIMIT, :HOSTNAME, :DVBSWFILTER, :DVBSATTYPE, "
2737 ":DVBWAITFORSEQSTART, :SKIPBTAUDIO, :DVBONDEMAND, :DVBDISEQCTYPE, "
2738 ":FIREWIRESPEED, :FIREWIREMODEL, :FIREWIRECONNECTION, :SIGNALTIMEOUT, "
2739 ":CHANNELTIMEOUT, :DVBTUNINGDELAY, :CONTRAST, :BRIGHTNESS, :COLOUR, "
2740 ":HUE, :DISEQCID, :DVBEITSCAN ) ");
2742 query.
bindValue(
":VIDEODEVICE", videodevice);
2743 if (audiodevice.length() == 0)
2745 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2746 query.
bindValue(
":AUDIODEVICE", QVariant(QVariant::String));
2748 query.
bindValue(
":AUDIODEVICE", QVariant(QMetaType(QMetaType::QString)));
2752 query.
bindValue(
":AUDIODEVICE", audiodevice);
2753 if (vbidevice.length() == 0)
2755 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2756 query.
bindValue(
":VBIDEVICE", QVariant(QVariant::String));
2758 query.
bindValue(
":VBIDEVICE", QVariant(QMetaType(QMetaType::QString)));
2762 query.
bindValue(
":VBIDEVICE", vbidevice);
2763 query.
bindValue(
":INPUTTYPE", inputtype);
2764 if (audioratelimit == 0)
2766 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2767 query.
bindValue(
":AUDIORATELIMIT", QVariant(QVariant::UInt));
2769 query.
bindValue(
":AUDIORATELIMIT", QVariant(QMetaType(QMetaType::UInt)));
2773 query.
bindValue(
":AUDIORATELIMIT", audioratelimit);
2775 query.
bindValue(
":DVBSWFILTER", dvb_swfilter);
2776 query.
bindValue(
":DVBSATTYPE", dvb_sat_type);
2777 query.
bindValue(
":DVBWAITFORSEQSTART", dvb_wait_for_seqstart);
2778 query.
bindValue(
":SKIPBTAUDIO", skipbtaudio);
2779 query.
bindValue(
":DVBONDEMAND", dvb_on_demand);
2780 query.
bindValue(
":DVBDISEQCTYPE", dvb_diseqc_type);
2781 query.
bindValue(
":FIREWIRESPEED", firewire_speed);
2782 if (firewire_model.length() == 0)
2784 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2785 query.
bindValue(
":FIREWIREMODEL", QVariant(QVariant::String));
2787 query.
bindValue(
":FIREWIREMODEL", QVariant(QMetaType(QMetaType::QString)));
2791 query.
bindValue(
":FIREWIREMODEL", firewire_model);
2792 query.
bindValue(
":FIREWIRECONNECTION", firewire_connection);
2793 query.
bindValue(
":SIGNALTIMEOUT",
static_cast<qint64
>(signal_timeout.count()));
2794 query.
bindValue(
":CHANNELTIMEOUT",
static_cast<qint64
>(channel_timeout.count()));
2795 query.
bindValue(
":DVBTUNINGDELAY", dvb_tuning_delay);
2797 query.
bindValue(
":BRIGHTNESS", brightness);
2802 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2803 query.
bindValue(
":DISEQCID", QVariant(QVariant::UInt));
2805 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") &&
2916 query.
exec(
"TRUNCATE TABLE iptv_channel"));
2921 std::vector<uint> list;
2933 while (query.
next())
2934 list.push_back(query.
value(0).toUInt());
2942 std::vector<uint> list;
2946 "SELECT DISTINCT cardid "
2948 "WHERE schedorder <> 0 "
2949 "ORDER BY schedorder, cardid");
2955 while (query.
next())
2956 list.push_back(query.
value(0).toUInt());
2964 std::vector<uint> list;
2968 "SELECT DISTINCT cardid "
2970 "WHERE livetvorder <> 0 "
2971 "ORDER BY livetvorder, cardid");
2977 while (query.
next())
2978 list.push_back(query.
value(0).toUInt());
2986 QString devname = QString(device);
2988 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"DVB Device (%1)").arg(devname));
2998 QString
tmp = devname;
2999 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 8,
"dvr");
3000 if (QFile::exists(
tmp))
3002 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3003 QString(
"Adapter Frontend dvr number matches (%1)").arg(
tmp));
3009 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 9,
"dvr0");
3010 if (QFile::exists(
tmp))
3012 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3013 QString(
"Adapter Frontend dvr number not matching, using dvr0 instead (%1)").arg(
tmp));
3017 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3018 QString(
"Adapter Frontend no dvr device found for (%1)").arg(devname));
3024 QString
tmp = devname;
3025 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 8,
"demux");
3026 if (QFile::exists(
tmp))
3028 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3029 QString(
"Adapter Frontend demux number matches (%1)").arg(
tmp));
3035 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 9,
"demux0");
3036 if (QFile::exists(
tmp))
3038 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3039 QString(
"Adapter Frontend demux number not matching, using demux0 instead (%1)").arg(
tmp));
3043 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3044 QString(
"Adapter Frontend no demux device found for (%1)").arg(devname));
3050 QString
tmp = devname;
3051 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 8,
"ca");
3052 if (QFile::exists(
tmp))
3054 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3055 QString(
"Adapter Frontend ca number matches (%1)").arg(
tmp));
3061 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 9,
"ca0");
3062 if (QFile::exists(
tmp))
3064 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3065 QString(
"Adapter Frontend ca number not matching, using ca0 instead (%1)").arg(
tmp));
3069 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3070 QString(
"Adapter Frontend no ca device found for (%1)").arg(devname));
3076 return devname.replace(devname.indexOf(
"frontend"), 8,
"audio");
3081 return devname.replace(devname.indexOf(
"frontend"), 8,
"video");
3101 #ifdef USING_HDHOMERUN
3102 hdhomerun_device_t *hdhr =
3103 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
3107 const char *model = hdhomerun_device_get_model_str(hdhr);
3108 if (model && strstr(model,
"dvb"))
3110 hdhomerun_device_destroy(hdhr);
3114 hdhomerun_device_destroy(hdhr);
3129 #ifdef USING_HDHOMERUN
3130 hdhomerun_device_t *hdhr =
3131 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
3135 const char *model = hdhomerun_device_get_model_str(hdhr);
3136 if (model && strstr(model,
"dvbc"))
3138 hdhomerun_device_destroy(hdhr);
3142 hdhomerun_device_destroy(hdhr);
3155 QString connectErr = QObject::tr(
"Unable to connect to device.");
3157 #ifdef USING_HDHOMERUN
3158 bool deviceIsIP =
false;
3160 if (device.contains(
'.'))
3164 bool validID =
false;
3166 uint32_t dev = device.toUInt(&validID, 16);
3167 if (!validID || !hdhomerun_discover_validate_device_id(dev))
3168 return QObject::tr(
"Invalid Device ID");
3172 LOG(VB_GENERAL, LOG_INFO,
"CardUtil::GetHDHRdescription(" + device +
3173 ") - trying to locate device");
3175 hdhomerun_device_t *hdhr =
3176 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
3178 return QObject::tr(
"Invalid Device ID or address.");
3180 const char *model = hdhomerun_device_get_model_str(hdhr);
3183 hdhomerun_device_destroy(hdhr);
3188 QString description = model;
3189 char *sVersion =
nullptr;
3190 uint32_t iVersion = 0;
3192 if (hdhomerun_device_get_version(hdhr, &sVersion, &iVersion))
3193 description += QObject::tr(
", firmware: %2").arg(sVersion);
3195 hdhomerun_device_destroy(hdhr);
3210 const QString &tunerNo,
const QString &tunerType)
3212 QString connectErr = QObject::tr(
"Unable to connect to device.");
3227 QString apiVersionErr = QObject::tr(
"The VBox software version is too old (%1), we require %2")
3230 return apiVersionErr;
3236 return QString(
"V@Box TV Gateway - ID: %1, IP: %2, Tuner: %3-%4")
3237 .arg(
id, ip, tunerNo, tunerType);
3252 return QString(
"/sys/class/asi/asirx%1/%2").arg(device_num).arg(dev);
3258 f.open(QIODevice::ReadOnly);
3259 QByteArray sdba = f.readAll();
3267 f.open(QIODevice::WriteOnly);
3268 QByteArray ba = str.toLocal8Bit();
3270 for (
uint tries = 0; (offset < ba.size()) && tries < 5; tries++)
3272 qint64 written = f.write(ba.data()+offset, ba.size()-offset);
3285 struct stat statbuf {};
3286 if (stat(device.toLocal8Bit().constData(), &statbuf) < 0)
3289 *
error = QString(
"Unable to stat '%1'").arg(device) +
ENO;
3293 if (!S_ISCHR(statbuf.st_mode))
3296 *
error = QString(
"'%1' is not a character device").arg(device);
3300 if (!(statbuf.st_rdev & 0x0080))
3303 *
error = QString(
"'%1' not a DVEO ASI receiver").arg(device);
3307 int device_num = statbuf.st_rdev & 0x007f;
3311 QStringList sys_dev_clist = sys_dev_contents.split(
":");
3312 if (2 != sys_dev_clist.size())
3316 *
error = QString(
"Unable to read '%1'")
3317 .arg(
sys_dev(device_num,
"dev"));
3321 if (sys_dev_clist[0].toUInt() != (statbuf.st_rdev>>8))
3324 *
error = QString(
"'%1' not a DVEO ASI device").arg(device);
3332 *
error =
"Not compiled with ASI support.";
3341 QString sys_bufsize_contents =
read_sys(
sys_dev(device_num,
"bufsize"));
3343 uint buf_size = sys_bufsize_contents.toUInt(&ok);
3348 *
error = QString(
"Failed to read buffer size from '%1'")
3349 .arg(
sys_dev(device_num,
"bufsize"));
3357 *
error =
"Not compiled with ASI support.";
3366 QString sys_numbuffers_contents =
read_sys(
sys_dev(device_num,
"buffers"));
3368 uint num_buffers = sys_numbuffers_contents.toUInt(&ok);
3373 *
error = QString(
"Failed to read num buffers from '%1'")
3374 .arg(
sys_dev(device_num,
"buffers"));
3382 *
error =
"Not compiled with ASI support.";
3392 uint mode = sys_bufsize_contents.toUInt(&ok);
3397 *
error = QString(
"Failed to read mode from '%1'")
3398 .arg(
sys_dev(device_num,
"mode"));
3406 *
error =
"Not compiled with ASI support.";
3416 uint old_mode = sys_bufsize_contents.toUInt(&ok);
3417 if (ok && old_mode == mode)
3422 *
error = QString(
"Failed to set mode to %1 using '%2'")
3423 .arg(mode).arg(
sys_dev(device_num,
"mode"));
3427 Q_UNUSED(device_num);
3430 *
error =
"Not compiled with ASI support.";
3440 bool CardUtil::IsVBoxPresent(
uint inputid)
3445 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX inputid (%1) not valid, redo mythtv-setup")
3456 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX chanid (%1) not found for inputid (%2), redo mythtv-setup")
3457 .arg(chanid).arg(inputid));
3462 std::chrono::milliseconds signal_timeout = 0ms;
3463 std::chrono::milliseconds tuning_timeout = 0ms;
3464 if (!
GetTimeouts(inputid,signal_timeout,tuning_timeout))
3466 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to get timeouts for inputid (%1)")
3474 query.prepare(
"SELECT url "
3475 "FROM iptv_channel "
3476 "WHERE chanid = :CHANID");
3477 query.bindValue(
":CHANID", chanid);
3481 else if (query.next())
3482 url = query.value(0).toString();
3485 QString ip = url.host();
3486 LOG(VB_GENERAL, LOG_INFO, QString(
"VBOX IP found (%1) for inputid (%2)")
3487 .arg(ip).arg(inputid));
3489 if (!
ping(ip,signal_timeout))
3491 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX at IP (%1) failed to respond to network ping for inputid (%2) timeout (%3)")
3492 .arg(ip).arg(inputid).arg(signal_timeout.count()));
3505 bool CardUtil::IsSatIPPresent(
uint inputid)
3510 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP inputid (%1) not valid, redo mythtv-setup")
3521 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP chanid (%1) not found for inputid (%2), redo mythtv-setup")
3522 .arg(chanid).arg(inputid));
3527 std::chrono::milliseconds signal_timeout = 0ms;
3528 std::chrono::milliseconds tuning_timeout = 0ms;
3529 if (!
GetTimeouts(inputid,signal_timeout,tuning_timeout))
3531 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to get timeouts for inputid (%1)")
3538 QStringList devinfo = device.split(
":");
3539 if (devinfo.value(0).toUpper() ==
"UUID")
3541 QString deviceId = QString(
"uuid:%1").arg(devinfo.value(1));
3543 LOG(VB_GENERAL, LOG_INFO, QString(
"SatIP[%1] IP address %2 device %3")
3544 .arg(inputid).arg(ip, device));
3546 if (!
ping(ip, signal_timeout))
3548 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP[%1] at IP %2 failed to respond to network ping (timeout %3)")
3549 .arg(inputid).arg(ip).arg(signal_timeout.count()));