7 #if defined(USING_V4L2) || defined(USING_DVB)
14 #include <QRegularExpression>
18 #include "libmythbase/mythconfig.h"
40 #ifdef USING_HDHOMERUN
41 #include HDHOMERUN_HEADERFILE
53 #include <sys/types.h>
56 #include <dveo/master.h>
59 #define LOC QString("CardUtil: ")
63 QStringList inputTypes {};
66 inputTypes +=
"'DVB'";
70 inputTypes +=
"'V4L'";
71 inputTypes +=
"'MPEG'";
75 inputTypes +=
"'FREEBOX'";
79 inputTypes +=
"'VBOX'";
82 #ifdef USING_HDHOMERUN
83 inputTypes +=
"'HDHOMERUN'";
84 #endif // USING_HDHOMERUN
87 inputTypes +=
"'SATIP'";
91 inputTypes +=
"'ASI'";
95 inputTypes +=
"'CETON'";
98 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
99 inputTypes +=
"'EXTERNAL'";
102 if (inputTypes.isEmpty())
105 return QString(
"(%1)").arg(inputTypes.join(
','));
109 const QString &inputType)
111 if (inputType ==
"HDHOMERUN")
113 #ifdef USING_HDHOMERUN
114 hdhomerun_tuner_status_t status {};
116 hdhomerun_device_t *hdhr =
117 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
121 int oob = hdhomerun_device_get_oob_status(hdhr,
nullptr, &status);
125 if (oob > 0 && (strncmp(status.channel,
"none", 4) != 0))
127 LOG(VB_GENERAL, LOG_INFO,
"Cardutil: HDHomeRun Cablecard Present.");
128 hdhomerun_device_destroy(hdhr);
132 hdhomerun_device_destroy(hdhr);
137 if (inputType ==
"CETON")
142 QStringList parts = device.split(
"-");
143 if (parts.size() != 2)
145 LOG(VB_GENERAL, LOG_ERR,
146 QString(
"CardUtil: Ceton invalid device id %1").arg(device));
150 const QString& ip_address = parts.at(0);
152 QStringList tuner_parts = parts.at(1).split(
".");
153 if (tuner_parts.size() != 2)
155 LOG(VB_GENERAL, LOG_ERR,
LOC +
156 QString(
"CardUtil: Ceton invalid device id %1").arg(device));
160 uint tuner = tuner_parts.at(1).toUInt();
163 params.addQueryItem(
"i", QString::number(tuner));
164 params.addQueryItem(
"s",
"cas");
165 params.addQueryItem(
"v",
"CardStatus");
168 url.setScheme(
"http");
169 url.setHost(ip_address);
170 url.setPath(
"/get_var.json");
171 url.setQuery(params);
173 auto *request =
new QNetworkRequest();
174 request->setAttribute(QNetworkRequest::CacheLoadControlAttribute,
175 QNetworkRequest::AlwaysNetwork);
176 request->setUrl(url);
181 if (!
manager->download(request, &data))
183 LOG(VB_GENERAL, LOG_ERR,
184 QString(
"CardUtil: Ceton http request failed %1").arg(device));
188 QString response = QString(data);
190 static const QRegularExpression regex {
"^\\{ \"?result\"?: \"(.*)\" \\}$"};
191 auto match = regex.match(response);
192 if (!match.hasMatch())
194 LOG(VB_GENERAL, LOG_ERR,
195 QString(
"CardUtil: Ceton unexpected http response: %1").arg(response));
199 QString result = match.captured(1);
201 if (result ==
"Inserted")
203 LOG(VB_GENERAL, LOG_DEBUG,
"Cardutil: Ceton CableCARD present.");
207 LOG(VB_GENERAL, LOG_DEBUG,
"Cardutil: Ceton CableCARD not present.");
217 [[maybe_unused]]
const QString & device)
219 if (rawtype ==
"DVB" || rawtype ==
"HDHOMERUN" ||
220 rawtype ==
"FREEBOX" || rawtype ==
"CETON" ||
221 rawtype ==
"VBOX" || rawtype ==
"SATIP")
225 if (rawtype ==
"V4L2ENC")
232 if (rawtype ==
"EXTERNAL")
243 LOG(VB_GENERAL, LOG_DEBUG, QString(
"IsTunerShared(%1,%2)")
244 .arg(inputidA).arg(inputidB));
247 query.
prepare(
"SELECT videodevice, hostname, cardtype "
249 "WHERE ( (cardid = :INPUTID_A) OR "
250 " (cardid = :INPUTID_B) )");
263 const QString vdevice = query.
value(0).toString();
265 const QString inputtype = query.
value(2).toString();
273 bool ret = ((vdevice == query.
value(0).toString()) &&
275 (inputtype == query.
value(2).toString()));
277 LOG(VB_RECORD, LOG_DEBUG, QString(
"IsTunerShared(%1,%2) -> %3")
278 .arg(inputidA).arg(inputidB).arg(ret));
295 "SELECT count(cardtype) "
297 "WHERE capturecard.hostname = :HOSTNAME ";
299 if (!rawtype.isEmpty())
300 qstr +=
" AND capturecard.cardtype = :INPUTTYPE";
304 if (!rawtype.isEmpty())
305 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
317 count = query.
value(0).toUInt();
327 query.
prepare(
"SELECT DISTINCT cardtype, videodevice "
340 cardtype = query.
value(0).toString();
341 if (cardtype !=
"V4L2ENC")
343 inputtypes[cardtype] =
"";
351 QString driver_name =
"V4L2:" + v4l2.
DriverName();
352 inputtypes[driver_name] = v4l2.
CardName();
372 query.
prepare(
"SELECT cardtype "
374 "WHERE capturecard.sourceid = :SOURCEID "
375 "GROUP BY cardtype");
385 list.push_back(query.
value(0).toString());
406 "SELECT videodevice "
408 "WHERE hostname = :HOSTNAME";
410 if (!rawtype.isEmpty())
411 qstr +=
" AND cardtype = :INPUTTYPE";
415 if (!rawtype.isEmpty())
416 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
426 QMap<QString,bool> dup;
429 QString videodevice = query.
value(0).toString();
430 if (dup[videodevice])
433 list.push_back(videodevice);
434 dup[videodevice] =
true;
455 if (rawtype.toUpper() ==
"DVB")
457 QDir dir(
"/dev/dvb",
"adapter*", QDir::Name, QDir::Dirs);
458 QFileInfoList entries = dir.entryInfoList();
459 for (
const auto & it : std::as_const(entries))
461 QDir subdir(it.filePath(),
"frontend*", QDir::Name, QDir::Files | QDir::System);
462 const QFileInfoList subil = subdir.entryInfoList();
466 for (
const auto & subit : std::as_const(subil))
467 devs.push_back(subit.filePath());
470 else if (rawtype.toUpper() ==
"ASI")
472 QDir dir(
"/dev/",
"asirx*", QDir::Name, QDir::System);
473 QFileInfoList entries = dir.entryInfoList();
474 for (
const auto & it : std::as_const(entries))
478 devs.push_back(it.filePath());
484 #ifdef USING_HDHOMERUN
485 else if (rawtype.toUpper() ==
"HDHOMERUN")
487 #if HDHOMERUN_VERSION >= 20221010
488 struct hdhomerun_debug_t *dbg = hdhomerun_debug_create();
489 struct hdhomerun_discover_t *ds = hdhomerun_discover_create(dbg);
492 uint32_t
type { HDHOMERUN_DEVICE_TYPE_TUNER };
493 uint32_t flags { HDHOMERUN_DISCOVER_FLAGS_IPV4_GENERAL |
494 HDHOMERUN_DISCOVER_FLAGS_IPV6_GENERAL };
496 hdhomerun_discover2_find_devices_broadcast(ds, flags, &
type, 1);
500 LOG(VB_GENERAL, LOG_ERR,
"Error finding HDHomerun devices");
502 else if (result == 0)
504 LOG(VB_GENERAL, LOG_INFO,
"No HDHomerun devices found.");
509 struct hdhomerun_discover2_device_t *device = hdhomerun_discover2_iter_device_first(ds);
512 uint8_t tuners = hdhomerun_discover2_device_get_tuner_count(device);
513 uint32_t device_id = hdhomerun_discover2_device_get_device_id(device);
514 QString
id = QString(
"%1").arg(device_id, 0, 16, QChar(
'0')).toUpper();
515 auto *dev1 = hdhomerun_device_create_from_str(
id.toLatin1(),
nullptr);
516 QString model = hdhomerun_device_get_model_str(dev1);
519 struct sockaddr_storage saddr {};
520 struct hdhomerun_discover2_device_if_t *device_if {
nullptr };
523 device_if = hdhomerun_discover2_iter_device_if_first(device);
526 hdhomerun_discover2_device_if_get_ip_addr(device_if, &saddr);
527 ip = QHostAddress((
struct sockaddr *)&saddr);
528 LOG(VB_GENERAL, LOG_DEBUG,
529 QString(
"HDHomerun %1 has IP %2").arg(
id, ip.toString()));
530 device_if = hdhomerun_discover2_iter_device_if_next(device_if);
534 device_if = hdhomerun_discover2_iter_device_if_first(device);
535 if (
nullptr == device_if)
537 LOG(VB_GENERAL, LOG_WARNING,
538 QString(
"HDHomerun %1 has no IP addresses").arg(
id));
541 hdhomerun_discover2_device_if_get_ip_addr(device_if, &saddr);
542 ip = QHostAddress((
struct sockaddr *)&saddr);
545 QString hdhrdev = QString(
"%1 %2 %3").arg(
id, ip.toString(), model);
546 devs.push_back(hdhrdev);
547 LOG(VB_GENERAL, LOG_INFO,
548 QString(
"HDHomerun %1: IP %2, model %3, %4 tuners")
549 .arg(
id, ip.toString(), model).arg(tuners));
551 device = hdhomerun_discover2_iter_device_next(device);
553 hdhomerun_discover_destroy(ds);
554 hdhomerun_debug_destroy(dbg);
556 #else // HDHOMERUN_VERSION >= 20221010
557 uint32_t target_ip = 0;
558 uint32_t device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
559 uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
560 const int max_count = 50;
561 std::array<hdhomerun_discover_device_t,max_count> result_list {};
563 int result = hdhomerun_discover_find_devices_custom_v2(
564 target_ip, device_type, device_id, result_list.data(), result_list.size());
568 LOG(VB_GENERAL, LOG_ERR,
"Error finding HDHomerun devices");
571 if (result >= max_count)
573 LOG(VB_GENERAL, LOG_WARNING,
574 "Warning: may be > 50 HDHomerun devices");
578 for (
int i = 0; i < result; i++)
580 QString
id = QString(
"%1").arg(result_list[i].device_id, 0, 16);
581 QString ip = QString(
"%1.%2.%3.%4")
582 .arg((result_list[i].ip_addr>>24) & 0xFF)
583 .arg((result_list[i].ip_addr>>16) & 0xFF)
584 .arg((result_list[i].ip_addr>> 8) & 0xFF)
585 .arg((result_list[i].ip_addr>> 0) & 0xFF);
588 hdhomerun_device_t *device = hdhomerun_device_create(
589 result_list[i].device_id, 0, 0,
nullptr);
592 model = hdhomerun_device_get_model_str(device);
593 hdhomerun_device_destroy(device);
596 QString hdhrdev =
id.toUpper() +
" " + ip +
" " + model;
597 devs.push_back(hdhrdev);
599 #endif // HDHOMERUN_VERSION >= 20221010
601 #endif // USING_HDHOMERUN
603 else if (rawtype.toUpper() ==
"SATIP")
607 #endif // USING_SATIP
609 else if (rawtype.toUpper() ==
"VBOX")
615 else if (rawtype.toUpper() ==
"CETON")
618 LOG(VB_GENERAL, LOG_INFO,
"CardUtil::ProbeVideoDevices: "
619 "TODO Probe Ceton devices");
621 #endif // USING_CETON
624 LOG(VB_GENERAL, LOG_ERR, QString(
"Raw Type: '%1' is not supported")
635 QStringList delsyslist;
644 struct dtv_property prop = {};
645 struct dtv_properties cmd = {};
647 prop.cmd = DTV_API_VERSION;
650 if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
652 LOG(VB_GENERAL, LOG_DEBUG,
653 QString(
"CardUtil(%1): ").arg(device) +
654 QString(
"dvb api version %1.%2").arg((prop.u.data>>8)&0xff).arg((prop.u.data)&0xff));
658 LOG(VB_GENERAL, LOG_ERR,
659 QString(
"CardUtil(%1) FE_GET_PROPERTY ioctl failed").arg(device) +
ENO);
666 QString msg =
"Delivery systems:";
667 for (
const auto & item : std::as_const(delsyslist))
672 LOG(VB_GENERAL, LOG_INFO, QString(
"CardUtil(%1): ").arg(device) + msg);
683 QStringList delsyslist;
686 struct dtv_property prop = {};
687 struct dtv_properties cmd = {};
689 prop.cmd = DTV_ENUM_DELSYS;
692 if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
694 for (
unsigned int i = 0; i < prop.u.buffer.len; i++)
701 LOG(VB_GENERAL, LOG_ERR,
LOC +
"FE_GET_PROPERTY ioctl failed " +
ENO);
726 QString ret =
"ERROR_UNKNOWN";
728 if (device.isEmpty())
733 ret = (
type.toString() !=
"UNKNOWN") ?
type.toString().toUpper() : ret;
735 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"(%1) tuner type:%2 %3")
736 .arg(device).arg(
type).arg(ret));
747 QString ret =
"ERROR_UNKNOWN";
751 QByteArray dev = dvbdev.toLatin1();
752 int fd_frontend = open(dev.constData(), O_RDWR |
O_NONBLOCK);
756 struct dvb_frontend_info
info {};
757 int err = ioctl(fd_frontend, FE_GET_INFO, &
info);
761 return "ERROR_PROBE";
792 return ((name ==
"VLSI VES1x93 DVB-S") ||
793 (name ==
"ST STV0299 DVB-S"));
799 if (name.indexOf(
"DVB-S") >= 0)
801 if (name ==
"DiBcom 3000P/M-C DVB-T")
839 LOG(VB_GENERAL, LOG_ERR,
LOC +
840 QString(
"TODO Add to switch case delivery system:%2 %3")
841 .arg(delsys).arg(delsys.
toString()));
880 "FROM dtv_multiplex "
881 "WHERE dtv_multiplex.mplexid = :MPLEXID");
892 LOG(VB_GENERAL, LOG_ERR,
LOC +
893 QString(
"Could not find entry in dtv_multiplex for mplexid %1")
920 if (device.isEmpty())
929 LOG(VB_GENERAL, LOG_ERR,
LOC +
930 QString(
"open failed (%1)")
937 LOG(VB_GENERAL, LOG_DEBUG, QString(
"CardUtil(%1): delsys:%2 %3")
938 .arg(device).arg(delsys).arg(delsys.
toString()));
952 struct dtv_property prop = {};
953 struct dtv_properties cmd = {};
955 prop.cmd = DTV_DELIVERY_SYSTEM;
960 int ret = ioctl(fd_frontend, FE_GET_PROPERTY, &cmd);
963 LOG(VB_GENERAL, LOG_ERR,
LOC +
964 QString(
"FE_GET_PROPERTY ioctl failed (fd_frontend:%1)")
965 .arg(fd_frontend) +
ENO);
969 delsys = prop.u.data;
1001 LOG(VB_GENERAL, LOG_INFO,
1002 QString(
"CardUtil[%1]: ").arg(inputid) +
1003 QString(
"Update capturecard delivery system: %1").arg(delsys.
toString()));
1007 LOG(VB_GENERAL, LOG_ERR,
1008 QString(
"CardUtil[%1]: Error probing best delivery system").arg(inputid));
1009 return "ERROR_UNKNOWN";
1016 QString subtype =
"ERROR_UNKNOWN";
1022 LOG(VB_GENERAL, LOG_DEBUG,
1023 QString(
"CardUtil[%1]: subtype:%2").arg(inputid).arg(subtype));
1031 QString
t = inputType.toUpper();
1032 return (
t ==
"DVB") || (
t ==
"QPSK") || (
t ==
"QAM") || (
t ==
"OFDM") ||
1033 (
t ==
"ATSC") || (
t ==
"DVB_S2") || (
t ==
"DVB_T2");
1048 LOG(VB_GENERAL, LOG_INFO,
LOC +
1049 QString(
"Current delivery system: %1").arg(delsys.
toString()));
1052 QString msg =
"Supported delivery systems:";
1054 msg.append(delsyslist.join(
" "));
1055 LOG(VB_GENERAL, LOG_DEBUG,
LOC + msg);
1061 if (delsyslist.contains(newdelsys.
toString()))
1063 LOG(VB_GENERAL, LOG_INFO,
LOC +
1064 QString(
"Changing delivery system from %1 to %2")
1074 if (delsyslist.contains(newdelsys.
toString()))
1076 LOG(VB_GENERAL, LOG_INFO,
LOC +
1077 QString(
"Changing delivery system from %1 to %2")
1091 [[maybe_unused]]
int fd)
1106 LOG(VB_GENERAL, LOG_INFO,
1107 QString(
"CardUtil[%1]: ").arg(inputid) +
1108 QString(
"No capturecard delivery system in database, using: %1").arg(delsys.
toString()));
1119 [[maybe_unused]]
int fd)
1159 if (device.isEmpty())
1161 LOG(VB_GENERAL, LOG_DEBUG,
1162 QString(
"CardUtil[%1]: ").arg(inputid) +
1163 QString(
"inputid:%1 ").arg(inputid) +
1164 QString(
"delsys:%1").arg(delsys.toString()));
1169 if (fd_frontend < 0)
1171 LOG(VB_GENERAL, LOG_ERR,
1172 QString(
"CardUtil[%1]: ").arg(inputid) +
1173 QString(
"open failed (%1)").arg(device) +
ENO);
1186 [[maybe_unused]]
int fd)
1204 [[maybe_unused]]
int fd)
1209 LOG(VB_GENERAL, LOG_INFO,
1210 QString(
"CardUtil[%1]: ").arg(inputid) +
1211 QString(
"Set delivery system: %1").arg(delsys.toString()));
1213 struct dtv_property prop = {};
1214 struct dtv_properties cmd = {};
1216 prop.cmd = DTV_DELIVERY_SYSTEM;
1217 prop.u.data = delsys;
1221 ret = ioctl(fd, FE_SET_PROPERTY, &cmd);
1224 LOG(VB_GENERAL, LOG_ERR,
LOC +
1225 QString(
"[%1] FE_SET_PROPERTY ioctl failed")
1226 .arg(inputid) +
ENO);
1242 if (device.isEmpty())
1246 QByteArray dev = dvbdev.toLatin1();
1247 int fd_frontend = open(dev.constData(), O_RDWR |
O_NONBLOCK);
1248 if (fd_frontend < 0)
1250 LOG(VB_GENERAL, LOG_ERR,
LOC +
1251 QString(
"Can't open DVB frontend (%1) for %2.")
1252 .arg(dvbdev, device) +
ENO);
1261 QString(
"SELECT %1 ").arg(to_get) +
1263 "WHERE capturecard.cardid = :INPUTID");
1268 else if (query.
next())
1269 return query.
value(0).toString();
1282 QString(
"UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
1283 "WHERE cardid = :INPUTID");
1305 const QString& rawtype,
1306 const QString& inputname,
1309 std::vector<uint> list;
1318 "WHERE hostname = :HOSTNAME ";
1319 if (!videodevice.isEmpty())
1320 qstr +=
"AND videodevice = :DEVICE ";
1321 if (!inputname.isEmpty())
1322 qstr +=
"AND inputname = :INPUTNAME ";
1323 if (!rawtype.isEmpty())
1324 qstr +=
"AND cardtype = :INPUTTYPE ";
1325 qstr +=
"ORDER BY cardid";
1330 if (!videodevice.isEmpty())
1331 query.
bindValue(
":DEVICE", videodevice);
1332 if (!inputname.isEmpty())
1333 query.
bindValue(
":INPUTNAME", inputname);
1334 if (!rawtype.isEmpty())
1335 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
1341 while (query.
next())
1342 list.push_back(query.
value(0).toUInt());
1357 "WHERE parentid = :INPUTID";
1366 else if (query.
next())
1367 count = query.
value(0).toUInt();
1374 std::vector<uint> list;
1383 "WHERE parentid = :INPUTID "
1393 while (query.
next())
1394 list.push_back(query.
value(0).toUInt());
1402 uint dst_inputid = orig_dst_inputid;
1408 "DELETE FROM capturecard "
1409 "WHERE videodevice = 'temp_dummy'");
1418 "INSERT INTO capturecard "
1419 "SET videodevice = 'temp_dummy'");
1430 "WHERE videodevice = 'temp_dummy'");
1440 LOG(VB_GENERAL, LOG_ERR,
"clone_capturecard -- get temp id");
1444 dst_inputid = query.
value(0).toUInt();
1448 "SELECT videodevice, audiodevice, vbidevice, "
1449 " cardtype, hostname, signal_timeout, "
1450 " channel_timeout, dvb_wait_for_seqstart, dvb_on_demand, "
1451 " dvb_tuning_delay, dvb_diseqc_type, diseqcid, "
1452 " dvb_eitscan, inputname, sourceid, "
1453 " externalcommand, changer_device, changer_model, "
1454 " tunechan, startchan, displayname, "
1455 " dishnet_eit, recpriority, quicktune, "
1456 " livetvorder, reclimit, "
1458 " schedgroup, schedorder "
1460 "WHERE cardid = :INPUTID");
1461 query.
bindValue(
":INPUTID", src_inputid);
1470 LOG(VB_GENERAL, LOG_ERR,
"clone_cardinput -- get data 2");
1477 bool schedgroup = query.
value(26).toBool();
1478 uint schedorder = query.
value(27).toUInt();
1487 "UPDATE capturecard "
1488 "SET videodevice = :V0, "
1489 " audiodevice = :V1, "
1490 " vbidevice = :V2, "
1493 " signal_timeout = :V5, "
1494 " channel_timeout = :V6, "
1495 " dvb_wait_for_seqstart = :V7, "
1496 " dvb_on_demand = :V8, "
1497 " dvb_tuning_delay = :V9, "
1498 " dvb_diseqc_type = :V10, "
1500 " dvb_eitscan = :V12, "
1501 " inputname = :V13, "
1502 " sourceid = :V14, "
1503 " externalcommand = :V15, "
1504 " changer_device = :V16, "
1505 " changer_model = :V17, "
1506 " tunechan = :V18, "
1507 " startchan = :V19, "
1508 " displayname = :V20, "
1509 " dishnet_eit = :V21, "
1510 " recpriority = :V22, "
1511 " quicktune = :V23, "
1512 " livetvorder = :V24, "
1513 " reclimit = :V25, "
1514 " schedgroup = :SCHEDGROUP, "
1515 " schedorder = :SCHEDORDER, "
1516 " parentid = :PARENTID "
1517 "WHERE cardid = :INPUTID");
1518 for (
uint i = 0; i < 26; ++i)
1519 query2.
bindValue(QString(
":V%1").arg(i), query.
value(i).toString());
1520 query2.
bindValue(
":INPUTID", dst_inputid);
1521 query2.
bindValue(
":PARENTID", src_inputid);
1522 query2.
bindValue(
":SCHEDGROUP", schedgroup);
1523 query2.
bindValue(
":SCHEDORDER", schedorder);
1528 if (!orig_dst_inputid)
1536 for (
uint dst_grp : dst_grps)
1538 for (
uint src_grp : src_grps)
1543 if (diseqc.
Load(src_inputid))
1544 diseqc.
Store(dst_inputid);
1562 if (max_recordings < 1)
1564 LOG(VB_GENERAL, LOG_ERR,
LOC +
1565 "InputSetMaxRecording: max must be greater than zero.");
1572 for (
size_t i = cardids.size() + 1;
1573 (i > max_recordings) && !cardids.empty(); --i)
1580 for (
uint id : cardids)
1584 for (
size_t i = cardids.size() + 1; i < max_recordings; ++i)
1601 LOG(VB_GENERAL, LOG_INFO,
LOC +
1602 QString(
"Added child input %1 to parent %2")
1603 .arg(inputid).arg(parentid));
1605 query.
prepare(
"UPDATE capturecard "
1606 "SET reclimit = reclimit + 1 "
1607 "WHERE cardid = :PARENTID");
1614 LOG(VB_GENERAL, LOG_ERR,
LOC +
1615 QString(
"Failed to add child input to parent %1").arg(parentid));
1626 query.
prepare(
"SELECT changer_device "
1627 "FROM capturecard WHERE cardid = :INPUTID ");
1632 fwnode = query.
value(0).toString();
1643 query.
prepare(
"SELECT changer_model "
1644 "FROM capturecard WHERE cardid = :INPUTID ");
1649 fwnode = query.
value(0).toString();
1660 "SELECT DISTINCT cardid "
1662 "WHERE sourceid = :SOURCEID");
1665 std::vector<uint> list;
1673 while (query.
next())
1674 list.push_back(query.
value(0).toUInt());
1682 query.
prepare(
"UPDATE capturecard "
1683 "SET startchan = :CHANNUM "
1684 "WHERE cardid = :INPUTID");
1704 "inputname, sourceid, livetvorder, "
1705 "schedorder, displayname, recpriority, quicktune "
1707 "WHERE cardid = :INPUTID");
1736 QList<InputInfo> infoInputList;
1739 QString queryStr =
"SELECT cardid, "
1740 "inputname, sourceid, livetvorder, "
1741 "schedorder, displayname, recpriority, quicktune "
1745 queryStr.append(
" WHERE parentid = 0");
1751 return infoInputList;
1754 while (query.
next())
1766 infoInputList.push_back(input);
1769 return infoInputList;
1796 query.
prepare(
"SELECT startchan "
1798 "WHERE cardid = :INPUTID");
1805 else if (query.
next())
1807 startchan = query.
value(0).toString();
1811 if (!startchan.isEmpty())
1813 query.
prepare(
"SELECT channel.chanid "
1814 "FROM capturecard, channel "
1815 "WHERE capturecard.cardid = :INPUTID AND "
1816 " capturecard.sourceid = channel.sourceid AND "
1817 " channel.deleted IS NULL AND "
1818 " channel.visible > 0 AND "
1819 " channel.channum = :CHANNUM");
1827 else if (!query.
next())
1829 LOG(VB_GENERAL, LOG_WARNING,
1830 QString(
"CardUtil[%1]: ").arg(inputid) +
1831 QString(
"Channel %1 on inputid %2 is invalid").arg(startchan).arg(inputid));
1838 if (startchan.isEmpty())
1840 query.
prepare(
"SELECT channel.channum "
1841 "FROM capturecard, channel "
1842 "WHERE capturecard.cardid = :INPUTID AND "
1843 " capturecard.sourceid = channel.sourceid AND "
1844 " channel.deleted IS NULL AND "
1845 " channel.visible > 0 "
1853 else if (query.
next())
1855 startchan = query.
value(0).toString();
1859 if (startchan.isEmpty())
1861 LOG(VB_GENERAL, LOG_WARNING,
1862 QString(
"CardUtil[%1]: ").arg(inputid) +
1863 QString(
"No start channel found on inputid %1").arg(inputid));
1867 LOG(VB_GENERAL, LOG_DEBUG,
1868 QString(
"CardUtil[%1]: ").arg(inputid) +
1869 QString(
"Start channel %1 on inputid %2").arg(startchan).arg(inputid));
1881 query.
prepare(
"SELECT displayname "
1883 "WHERE cardid = :INPUTID");
1888 else if (query.
next())
1890 QString result = query.
value(0).toString();
1904 qsizetype idx = name.indexOf(
'/');
1907 matching = name.right(name.size() - idx -1);
1912 matching = name.right(2);
1917 query.
prepare(
"SELECT cardid, displayname "
1919 "WHERE parentid = 0 "
1920 " AND cardid <> :INPUTID ");
1921 query.
bindValue(
":INPUTID", exclude_inputid);
1929 while (query.
next())
1931 QString dn = query.
value(1).toString();
1932 idx = dn.indexOf(
'/');
1933 if (!two && idx >= 0)
1935 if (dn.right(dn.size() - idx - 1) == matching)
1938 else if (dn.right(2) == matching.right(2))
1953 "WHERE cardid = :INPUTID");
1957 else if (query.
next())
1958 return query.
value(0).toUInt();
1967 const uint sourceid,
1968 const QString &inputname,
1969 const QString &externalcommand,
1970 const QString &changer_device,
1971 const QString &changer_model,
1973 const QString &tunechan,
1974 const QString &startchan,
1975 const QString &displayname,
1977 const uint recpriority,
1978 const uint quicktune,
1979 const uint schedorder,
1980 const uint livetvorder)
1985 "UPDATE capturecard "
1986 "SET sourceid = :SOURCEID, "
1987 " inputname = :INPUTNAME, "
1988 " externalcommand = :EXTERNALCOMMAND, "
1989 " changer_device = :CHANGERDEVICE, "
1990 " changer_model = :CHANGERMODEL, "
1991 " tunechan = :TUNECHAN, "
1992 " startchan = :STARTCHAN, "
1993 " displayname = :DISPLAYNAME, "
1994 " dishnet_eit = :DISHNETEIT, "
1995 " recpriority = :RECPRIORITY, "
1996 " quicktune = :QUICKTUNE, "
1997 " schedorder = :SCHEDORDER, "
1998 " livetvorder = :LIVETVORDER "
1999 "WHERE cardid = :INPUTID AND "
2000 " inputname = 'None'");
2004 query.
bindValue(
":INPUTNAME", inputname);
2005 query.
bindValue(
":EXTERNALCOMMAND", externalcommand);
2006 query.
bindValue(
":CHANGERDEVICE", changer_device);
2007 query.
bindValue(
":CHANGERMODEL", changer_model);
2009 query.
bindValue(
":STARTCHAN", startchan);
2011 query.
bindValue(
":DISHNETEIT", dishnet_eit);
2012 query.
bindValue(
":RECPRIORITY", recpriority);
2013 query.
bindValue(
":QUICKTUNE", quicktune);
2014 query.
bindValue(
":SCHEDORDER", schedorder);
2015 query.
bindValue(
":LIVETVORDER", livetvorder);
2030 query.
prepare(
"SELECT inputgroupid FROM inputgroup "
2031 "WHERE inputgroupname = :GROUPNAME "
2041 return query.
value(0).toUInt();
2043 query.
prepare(
"SELECT MAX(inputgroupid) FROM inputgroup");
2050 uint inputgroupid = (query.
next()) ? query.
value(0).toUInt() + 1 : 1;
2053 "INSERT INTO inputgroup "
2054 " (cardinputid, inputgroupid, inputgroupname) "
2055 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2057 query.
bindValue(
":GROUPID", inputgroupid);
2065 return inputgroupid;
2069 const QString &
type,
2070 const QString &host,
2071 const QString &device)
2073 QString name = host +
'|' + device;
2074 if (
type ==
"FREEBOX" ||
type ==
"IMPORT" ||
2075 type ==
"DEMO" ||
type ==
"EXTERNAL" ||
2076 type ==
"HDHOMERUN" )
2077 name += QString(
"|%1").arg(inputid);
2085 "SELECT inputgroupid "
2087 "WHERE cardinputid = :INPUTID "
2088 " AND inputgroupname REGEXP '^[a-z_-]*\\\\|'");
2099 return query.
value(0).toUInt();
2110 "SELECT cardinputid, inputgroupid, inputgroupname "
2112 "WHERE inputgroupid = :GROUPID "
2113 "ORDER BY inputgroupid, cardinputid, inputgroupname");
2114 query.
bindValue(
":GROUPID", inputgroupid);
2123 while (query.
next()) {
2124 name = query.
value(2).toString();
2127 if (cardid == inputid)
2136 "INSERT INTO inputgroup "
2137 " (cardinputid, inputgroupid, inputgroupname) "
2138 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2141 query.
bindValue(
":GROUPID", inputgroupid);
2160 if (!inputid && !inputgroupid)
2163 "DELETE FROM inputgroup "
2164 "WHERE cardinputid NOT IN "
2165 "( SELECT cardid FROM capturecard )");
2170 "DELETE FROM inputgroup "
2171 "WHERE cardinputid = :INPUTID AND "
2172 " inputgroupid = :GROUPID ");
2175 query.
bindValue(
":GROUPID", inputgroupid);
2189 std::vector<uint> list;
2194 "SELECT inputgroupid "
2196 "WHERE cardinputid = :INPUTID "
2197 "ORDER BY inputgroupid, cardinputid, inputgroupname");
2207 while (query.
next())
2208 list.push_back(query.
value(0).toUInt());
2215 std::vector<uint> list;
2220 "SELECT DISTINCT cardid "
2221 "FROM capturecard, inputgroup "
2222 "WHERE inputgroupid = :GROUPID AND "
2223 " capturecard.cardid = inputgroup.cardinputid "
2226 query.
bindValue(
":GROUPID", inputgroupid);
2234 while (query.
next())
2235 list.push_back(query.
value(0).toUInt());
2242 std::vector<uint> inputids;
2247 "SELECT DISTINCT c.cardid "
2249 " SELECT inputgroupid "
2251 " WHERE cardinputid = :INPUTID1 "
2253 "JOIN inputgroup ig ON ig.inputgroupid = g.inputgroupid "
2254 "JOIN capturecard c ON c.cardid = ig.cardinputid "
2255 " AND c.cardid <> :INPUTID2 "
2256 " AND c.sourceid > 0 "
2257 "ORDER BY c.cardid");
2268 while (query.
next())
2270 inputids.push_back(query.
value(0).toUInt());
2275 QString msg = QString(
"CardUtil[%1]: GetConflictingInputs(%1) ").arg(inputid);
2277 for (
auto id : inputids)
2279 ids.append(QString::number(
id));
2281 msg.append(ids.join(
','));
2282 LOG(VB_RECORD, LOG_INFO, msg);
2288 std::chrono::milliseconds &signal_timeout,
2289 std::chrono::milliseconds &channel_timeout)
2293 "SELECT signal_timeout, channel_timeout "
2295 "WHERE cardid = :INPUTID");
2300 else if (query.
next())
2302 signal_timeout = std::max(std::chrono::milliseconds(query.
value(0).toInt()), 250ms);
2303 channel_timeout = std::max(std::chrono::milliseconds(query.
value(1).toInt()), 500ms);
2314 bool needsConf =
false;
2329 "WHERE cardid = :INPUTID AND "
2330 " inputname = :INPUTNAME");
2332 query.
bindValue(
":INPUTNAME", input_name);
2336 else if (query.
next())
2337 quicktune = query.
value(0).toUInt();
2345 struct v4l2_capability vcap {};
2347 return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
2348 ((vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE) != 0U));
2349 #else // if !USING_V4L2
2351 #endif // !USING_V4L2
2355 int videofd, QString &input, QString &driver, uint32_t &
version,
2356 uint32_t &capabilities)
2367 struct v4l2_capability capability {};
2368 if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
2370 input = QString::fromLatin1((
const char*)capability.card);
2371 driver = QString::fromLatin1((
const char*)capability.driver);
2373 capabilities = capability.capabilities;
2375 #endif // USING_V4L2
2377 static const QRegularExpression kBracketedDigitRE { R
"(\[[0-9]\]$)" };
2378 if (!driver.isEmpty())
2379 driver.remove( kBracketedDigitRE );
2381 return !input.isEmpty();
2390 bool usingv4l2 =
hasV4L2(videofd);
2392 struct v4l2_input vin {};
2393 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
2395 QString input((
char *)vin.name);
2396 list[vin.index] = input;
2407 list[0] =
"Television";
2410 #else // if !USING_V4L2
2411 list[-1] += QObject::tr(
"ERROR, Compile with V4L support to query inputs");
2412 #endif // !USING_V4L2
2422 bool usingv4l2 =
hasV4L2(videofd);
2425 struct v4l2_audio ain {};
2426 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMAUDIO, &ain) >= 0))
2428 QString input((
char *)ain.name);
2429 list[ain.index] = input;
2439 #else // if !USING_V4L2
2440 list[-1] += QObject::tr(
2441 "ERROR, Compile with V4L support to query audio inputs");
2442 #endif // !USING_V4L2
2451 "SELECT cardid, inputname "
2453 "WHERE hostname = :HOSTNAME "
2454 " AND videodevice = :DEVICE "
2455 " AND parentid = 0 "
2456 " AND inputname <> 'None'");
2464 while (query.
next())
2465 list[query.
value(0).toUInt()] = query.
value(1).toString();
2479 struct fe_caps_name {
2484 std::array<fe_caps_name,31> fe_caps_name {{
2485 { FE_CAN_2G_MODULATION,
"CAN_2G_MODULATION" },
2486 { FE_CAN_8VSB,
"CAN_8VSB" },
2487 { FE_CAN_16VSB,
"CAN_16VSB" },
2488 { FE_CAN_BANDWIDTH_AUTO,
"CAN_BANDWIDTH_AUTO" },
2489 { FE_CAN_FEC_1_2,
"CAN_FEC_1_2" },
2490 { FE_CAN_FEC_2_3,
"CAN_FEC_2_3" },
2491 { FE_CAN_FEC_3_4,
"CAN_FEC_3_4" },
2492 { FE_CAN_FEC_4_5,
"CAN_FEC_4_5" },
2493 { FE_CAN_FEC_5_6,
"CAN_FEC_5_6" },
2494 { FE_CAN_FEC_6_7,
"CAN_FEC_6_7" },
2495 { FE_CAN_FEC_7_8,
"CAN_FEC_7_8" },
2496 { FE_CAN_FEC_8_9,
"CAN_FEC_8_9" },
2497 { FE_CAN_FEC_AUTO,
"CAN_FEC_AUTO" },
2498 { FE_CAN_GUARD_INTERVAL_AUTO,
"CAN_GUARD_INTERVAL_AUTO" },
2499 { FE_CAN_HIERARCHY_AUTO,
"CAN_HIERARCHY_AUTO" },
2500 { FE_CAN_INVERSION_AUTO,
"CAN_INVERSION_AUTO" },
2501 { FE_CAN_MULTISTREAM,
"CAN_MULTISTREAM" },
2502 { FE_CAN_MUTE_TS,
"CAN_MUTE_TS" },
2503 { FE_CAN_QAM_16,
"CAN_QAM_16" },
2504 { FE_CAN_QAM_32,
"CAN_QAM_32" },
2505 { FE_CAN_QAM_64,
"CAN_QAM_64" },
2506 { FE_CAN_QAM_128,
"CAN_QAM_128" },
2507 { FE_CAN_QAM_256,
"CAN_QAM_256" },
2508 { FE_CAN_QAM_AUTO,
"CAN_QAM_AUTO" },
2509 { FE_CAN_QPSK,
"CAN_QPSK" },
2510 { FE_CAN_RECOVER,
"CAN_RECOVER" },
2511 { FE_CAN_TRANSMISSION_MODE_AUTO,
"CAN_TRANSMISSION_MODE_AUTO" },
2512 { FE_CAN_TURBO_FEC,
"CAN_TURBO_FEC" },
2513 { FE_HAS_EXTENDED_CAPS,
"HAS_EXTENDED_CAPS" },
2514 { FE_IS_STUPID,
"IS_STUPID" },
2515 { FE_NEEDS_BENDING,
"NEEDS_BENDING" },
2518 for (
const auto & cap : fe_caps_name)
2520 if (capabilities & cap.idx)
2521 caps.append(cap.name);
2533 else if (
"DVB" == inputtype)
2543 LOG(VB_GENERAL, LOG_DEBUG, QString(
"ProbeAudioInputs(%1,%2)")
2544 .arg(device, inputtype));
2547 if (
"HDPVR" == inputtype ||
2548 "V4L2" == inputtype)
2558 QByteArray dev = device.toLatin1();
2559 int videofd = open(dev.constData(), O_RDWR);
2562 ret += QObject::tr(
"Could not open '%1' "
2563 "to probe its inputs.").arg(device);
2575 InputNames::iterator it;
2576 for (it = list.begin(); it != list.end(); ++it)
2587 LOG(VB_GENERAL, LOG_DEBUG, QString(
"ProbeV4LAudioInputs(%1)").arg(device));
2591 int videofd = open(device.toLatin1().constData(), O_RDWR);
2594 LOG(VB_GENERAL, LOG_ERR,
"ProbeAudioInputs() -> couldn't open device");
2595 ret += QObject::tr(
"Could not open '%1' to probe its inputs.")
2608 InputNames::iterator it;
2609 for (it = list.begin(); it != list.end(); ++it)
2624 InputNames::iterator it;
2625 for (it = list.begin(); it != list.end(); ++it)
2631 ret += QObject::tr(
"ERROR, Compile with DVB support to query inputs");
2638 const QString &videodevice)
2640 return QString(
"[ %1 : %2 ]").arg(inputtype, videodevice);
2646 query.
prepare(
"SELECT cardtype, videodevice "
2647 "FROM capturecard WHERE cardid = :INPUTID ");
2653 query.
value(1).toString());
2656 return "[ UNKNOWN ]";
2660 const QString &device,
2661 const QString &inputtype,
2662 QStringList &inputs)
2666 inputs +=
"MPEG2TS";
2667 else if (inputtype ==
"DVB")
2668 inputs +=
"DVBInput";
2674 const QString &audiodevice,
2675 const QString &vbidevice,
2676 const QString &inputtype,
2677 const uint audioratelimit,
2679 const uint dvb_swfilter,
2680 const uint dvb_sat_type,
2681 bool dvb_wait_for_seqstart,
2684 const uint dvb_diseqc_type,
2685 const uint firewire_speed,
2686 const QString &firewire_model,
2687 const uint firewire_connection,
2688 const std::chrono::milliseconds signal_timeout,
2689 const std::chrono::milliseconds channel_timeout,
2690 const uint dvb_tuning_delay,
2691 const uint contrast,
2692 const uint brightness,
2695 const uint diseqcid,
2701 "INSERT INTO capturecard "
2702 "(videodevice, audiodevice, vbidevice, cardtype, "
2703 "audioratelimit, hostname, dvb_swfilter, dvb_sat_type, "
2704 "dvb_wait_for_seqstart, skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
2705 "firewire_speed, firewire_model, firewire_connection, signal_timeout, "
2706 "channel_timeout, dvb_tuning_delay, contrast, brightness, colour, "
2707 "hue, diseqcid, dvb_eitscan) "
2708 "VALUES (:VIDEODEVICE, :AUDIODEVICE, :VBIDEVICE, :INPUTTYPE, "
2709 ":AUDIORATELIMIT, :HOSTNAME, :DVBSWFILTER, :DVBSATTYPE, "
2710 ":DVBWAITFORSEQSTART, :SKIPBTAUDIO, :DVBONDEMAND, :DVBDISEQCTYPE, "
2711 ":FIREWIRESPEED, :FIREWIREMODEL, :FIREWIRECONNECTION, :SIGNALTIMEOUT, "
2712 ":CHANNELTIMEOUT, :DVBTUNINGDELAY, :CONTRAST, :BRIGHTNESS, :COLOUR, "
2713 ":HUE, :DISEQCID, :DVBEITSCAN ) ");
2715 query.
bindValue(
":VIDEODEVICE", videodevice);
2716 if (audiodevice.length() == 0)
2718 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2719 query.
bindValue(
":AUDIODEVICE", QVariant(QVariant::String));
2721 query.
bindValue(
":AUDIODEVICE", QVariant(QMetaType(QMetaType::QString)));
2726 query.
bindValue(
":AUDIODEVICE", audiodevice);
2728 if (vbidevice.length() == 0)
2730 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2731 query.
bindValue(
":VBIDEVICE", QVariant(QVariant::String));
2733 query.
bindValue(
":VBIDEVICE", QVariant(QMetaType(QMetaType::QString)));
2738 query.
bindValue(
":VBIDEVICE", vbidevice);
2740 query.
bindValue(
":INPUTTYPE", inputtype);
2741 if (audioratelimit == 0)
2743 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2744 query.
bindValue(
":AUDIORATELIMIT", QVariant(QVariant::UInt));
2746 query.
bindValue(
":AUDIORATELIMIT", QVariant(QMetaType(QMetaType::UInt)));
2751 query.
bindValue(
":AUDIORATELIMIT", audioratelimit);
2754 query.
bindValue(
":DVBSWFILTER", dvb_swfilter);
2755 query.
bindValue(
":DVBSATTYPE", dvb_sat_type);
2756 query.
bindValue(
":DVBWAITFORSEQSTART", dvb_wait_for_seqstart);
2757 query.
bindValue(
":SKIPBTAUDIO", skipbtaudio);
2758 query.
bindValue(
":DVBONDEMAND", dvb_on_demand);
2759 query.
bindValue(
":DVBDISEQCTYPE", dvb_diseqc_type);
2760 query.
bindValue(
":FIREWIRESPEED", firewire_speed);
2761 if (firewire_model.length() == 0)
2763 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2764 query.
bindValue(
":FIREWIREMODEL", QVariant(QVariant::String));
2766 query.
bindValue(
":FIREWIREMODEL", QVariant(QMetaType(QMetaType::QString)));
2771 query.
bindValue(
":FIREWIREMODEL", firewire_model);
2773 query.
bindValue(
":FIREWIRECONNECTION", firewire_connection);
2774 query.
bindValue(
":SIGNALTIMEOUT",
static_cast<qint64
>(signal_timeout.count()));
2775 query.
bindValue(
":CHANNELTIMEOUT",
static_cast<qint64
>(channel_timeout.count()));
2776 query.
bindValue(
":DVBTUNINGDELAY", dvb_tuning_delay);
2778 query.
bindValue(
":BRIGHTNESS", brightness);
2783 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2784 query.
bindValue(
":DISEQCID", QVariant(QVariant::UInt));
2786 query.
bindValue(
":DISEQCID", QVariant(QMetaType(QMetaType::UInt)));
2793 query.
bindValue(
":DVBEITSCAN", dvb_eitscan);
2801 query.
prepare(
"SELECT MAX(cardid) FROM capturecard");
2813 inputid = query.
value(0).toInt();
2825 for (
uint childid : childids)
2829 LOG(VB_GENERAL, LOG_ERR,
LOC +
2830 QString(
"CardUtil: Failed to delete child input %1")
2842 query.
prepare(
"DELETE FROM capturecard WHERE cardid = :INPUTID");
2851 query.
prepare(
"UPDATE capturecard SET reclimit=reclimit-1 "
2852 "WHERE cardid = :INPUTID");
2861 query.
prepare(
"DELETE FROM inputgroup WHERE cardinputid = :INPUTID");
2872 query.
prepare(
"SELECT cardid FROM capturecard "
2873 "WHERE diseqcid = :DISEQCID LIMIT 1");
2879 else if (!query.
next())
2882 tree.
Store(inputid);
2895 return (query.
exec(
"TRUNCATE TABLE inputgroup") &&
2896 query.
exec(
"TRUNCATE TABLE diseqc_config") &&
2897 query.
exec(
"TRUNCATE TABLE diseqc_tree") &&
2898 query.
exec(
"TRUNCATE TABLE capturecard"));
2903 std::vector<uint> list;
2915 while (query.
next())
2916 list.push_back(query.
value(0).toUInt());
2924 std::vector<uint> list;
2928 "SELECT DISTINCT cardid "
2930 "WHERE schedorder <> 0 "
2931 "ORDER BY schedorder, cardid");
2937 while (query.
next())
2938 list.push_back(query.
value(0).toUInt());
2946 std::vector<uint> list;
2950 "SELECT DISTINCT cardid "
2952 "WHERE livetvorder <> 0 "
2953 "ORDER BY livetvorder, cardid");
2959 while (query.
next())
2960 list.push_back(query.
value(0).toUInt());
2968 QString devname = QString(device);
2970 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"DVB Device (%1)").arg(devname));
2980 QString
tmp = devname;
2981 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 8,
"dvr");
2984 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2985 QString(
"Adapter Frontend dvr number matches (%1)").arg(
tmp));
2991 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 9,
"dvr0");
2994 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2995 QString(
"Adapter Frontend dvr number not matching, using dvr0 instead (%1)").arg(
tmp));
2999 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3000 QString(
"Adapter Frontend no dvr device found for (%1)").arg(devname));
3006 QString
tmp = devname;
3007 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 8,
"demux");
3010 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3011 QString(
"Adapter Frontend demux number matches (%1)").arg(
tmp));
3017 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 9,
"demux0");
3020 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3021 QString(
"Adapter Frontend demux number not matching, using demux0 instead (%1)").arg(
tmp));
3025 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3026 QString(
"Adapter Frontend no demux device found for (%1)").arg(devname));
3032 QString
tmp = devname;
3033 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 8,
"ca");
3036 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3037 QString(
"Adapter Frontend ca number matches (%1)").arg(
tmp));
3043 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 9,
"ca0");
3046 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3047 QString(
"Adapter Frontend ca number not matching, using ca0 instead (%1)").arg(
tmp));
3051 LOG(VB_RECORD, LOG_DEBUG,
LOC +
3052 QString(
"Adapter Frontend no ca device found for (%1)").arg(devname));
3058 return devname.replace(devname.indexOf(
"frontend"), 8,
"audio");
3063 return devname.replace(devname.indexOf(
"frontend"), 8,
"video");
3081 #ifdef USING_HDHOMERUN
3082 hdhomerun_device_t *hdhr =
3083 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
3087 const char *model = hdhomerun_device_get_model_str(hdhr);
3088 if (model && strstr(model,
"dvb"))
3090 hdhomerun_device_destroy(hdhr);
3094 hdhomerun_device_destroy(hdhr);
3107 #ifdef USING_HDHOMERUN
3108 hdhomerun_device_t *hdhr =
3109 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
3113 const char *model = hdhomerun_device_get_model_str(hdhr);
3114 if (model && strstr(model,
"dvbc"))
3116 hdhomerun_device_destroy(hdhr);
3120 hdhomerun_device_destroy(hdhr);
3133 QString connectErr = QObject::tr(
"Unable to connect to device.");
3135 #ifdef USING_HDHOMERUN
3136 [[maybe_unused]]
bool deviceIsIP =
false;
3138 if (device.contains(
'.'))
3142 bool validID =
false;
3144 uint32_t dev = device.toUInt(&validID, 16);
3145 if (!validID || !hdhomerun_discover_validate_device_id(dev))
3146 return QObject::tr(
"Invalid Device ID");
3149 LOG(VB_GENERAL, LOG_INFO,
"CardUtil::GetHDHRdescription(" + device +
3150 ") - trying to locate device");
3152 hdhomerun_device_t *hdhr =
3153 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
3155 return QObject::tr(
"Invalid Device ID or address.");
3157 const char *model = hdhomerun_device_get_model_str(hdhr);
3160 hdhomerun_device_destroy(hdhr);
3165 QString description = model;
3166 char *sVersion =
nullptr;
3167 uint32_t iVersion = 0;
3169 if (hdhomerun_device_get_version(hdhr, &sVersion, &iVersion))
3170 description += QObject::tr(
", firmware: %2").arg(sVersion);
3172 hdhomerun_device_destroy(hdhr);
3185 [[maybe_unused]]
const QString &ip,
3186 [[maybe_unused]]
const QString &tunerNo,
3187 [[maybe_unused]]
const QString &tunerType)
3189 QString connectErr = QObject::tr(
"Unable to connect to device.");
3204 QString apiVersionErr = QObject::tr(
"The VBox software version is too old (%1), we require %2")
3207 return apiVersionErr;
3213 return QString(
"V@Box TV Gateway - ID: %1, IP: %2, Tuner: %3-%4")
3214 .arg(
id, ip, tunerNo, tunerType);
3224 return QString(
"/sys/class/asi/asirx%1/%2").arg(device_num).arg(dev);
3230 f.open(QIODevice::ReadOnly);
3231 QByteArray sdba = f.readAll();
3239 f.open(QIODevice::WriteOnly);
3240 QByteArray ba = str.toLocal8Bit();
3242 for (
uint tries = 0; (offset < ba.size()) && tries < 5; tries++)
3244 qint64 written = f.write(ba.data()+offset, ba.size()-offset);
3257 struct stat statbuf {};
3258 if (stat(device.toLocal8Bit().constData(), &statbuf) < 0)
3261 *
error = QString(
"Unable to stat '%1'").arg(device) +
ENO;
3265 if (!S_ISCHR(statbuf.st_mode))
3268 *
error = QString(
"'%1' is not a character device").arg(device);
3272 if (!(statbuf.st_rdev & 0x0080))
3275 *
error = QString(
"'%1' not a DVEO ASI receiver").arg(device);
3279 int device_num = statbuf.st_rdev & 0x007f;
3283 QStringList sys_dev_clist = sys_dev_contents.split(
":");
3284 if (2 != sys_dev_clist.size())
3288 *
error = QString(
"Unable to read '%1'")
3289 .arg(
sys_dev(device_num,
"dev"));
3293 if (sys_dev_clist[0].toUInt() != (statbuf.st_rdev>>8))
3296 *
error = QString(
"'%1' not a DVEO ASI device").arg(device);
3303 *
error =
"Not compiled with ASI support.";
3312 QString sys_bufsize_contents =
read_sys(
sys_dev(device_num,
"bufsize"));
3314 uint buf_size = sys_bufsize_contents.toUInt(&ok);
3319 *
error = QString(
"Failed to read buffer size from '%1'")
3320 .arg(
sys_dev(device_num,
"bufsize"));
3327 *
error =
"Not compiled with ASI support.";
3336 QString sys_numbuffers_contents =
read_sys(
sys_dev(device_num,
"buffers"));
3338 uint num_buffers = sys_numbuffers_contents.toUInt(&ok);
3343 *
error = QString(
"Failed to read num buffers from '%1'")
3344 .arg(
sys_dev(device_num,
"buffers"));
3351 *
error =
"Not compiled with ASI support.";
3361 uint mode = sys_bufsize_contents.toUInt(&ok);
3366 *
error = QString(
"Failed to read mode from '%1'")
3367 .arg(
sys_dev(device_num,
"mode"));
3374 *
error =
"Not compiled with ASI support.";
3380 [[maybe_unused]]
uint mode,
3386 uint old_mode = sys_bufsize_contents.toUInt(&ok);
3387 if (ok && old_mode == mode)
3392 *
error = QString(
"Failed to set mode to %1 using '%2'")
3393 .arg(mode).arg(
sys_dev(device_num,
"mode"));
3398 *
error =
"Not compiled with ASI support.";
3408 bool CardUtil::IsVBoxPresent(
uint inputid)
3413 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX inputid (%1) not valid, redo mythtv-setup")
3424 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX chanid (%1) not found for inputid (%2), redo mythtv-setup")
3425 .arg(chanid).arg(inputid));
3430 std::chrono::milliseconds signal_timeout = 0ms;
3431 std::chrono::milliseconds tuning_timeout = 0ms;
3432 if (!
GetTimeouts(inputid,signal_timeout,tuning_timeout))
3434 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to get timeouts for inputid (%1)")
3442 query.prepare(
"SELECT url "
3443 "FROM iptv_channel "
3444 "WHERE chanid = :CHANID");
3445 query.bindValue(
":CHANID", chanid);
3449 else if (query.next())
3450 url = query.value(0).toString();
3453 QString ip = url.host();
3454 LOG(VB_GENERAL, LOG_INFO, QString(
"VBOX IP found (%1) for inputid (%2)")
3455 .arg(ip).arg(inputid));
3457 if (!
ping(ip,signal_timeout))
3459 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX at IP (%1) failed to respond to network ping for inputid (%2) timeout (%3)")
3460 .arg(ip).arg(inputid).arg(signal_timeout.count()));
3473 bool CardUtil::IsSatIPPresent(
uint inputid)
3478 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP inputid (%1) not valid, redo mythtv-setup")
3489 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP chanid (%1) not found for inputid (%2), redo mythtv-setup")
3490 .arg(chanid).arg(inputid));
3495 std::chrono::milliseconds signal_timeout = 0ms;
3496 std::chrono::milliseconds tuning_timeout = 0ms;
3497 if (!
GetTimeouts(inputid,signal_timeout,tuning_timeout))
3499 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to get timeouts for inputid (%1)")
3506 QStringList devinfo = device.split(
":");
3507 if (devinfo.value(0).toUpper() ==
"UUID")
3509 QString deviceId = QString(
"uuid:%1").arg(devinfo.value(1));
3511 LOG(VB_GENERAL, LOG_INFO, QString(
"SatIP[%1] IP address %2 device %3")
3512 .arg(inputid).arg(ip, device));
3514 if (!
ping(ip, signal_timeout))
3516 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP[%1] at IP %2 failed to respond to network ping (timeout %3)")
3517 .arg(inputid).arg(ip).arg(signal_timeout.count()));