7 #if defined(USING_V4L2) || defined(USING_DVB)
16 #include "libmythbase/mythconfig.h"
37 #ifdef USING_HDHOMERUN
38 #include HDHOMERUN_HEADERFILE
51 #include <sys/types.h>
54 #include <dveo/master.h>
57 #define LOC QString("CardUtil: ")
61 QStringList inputTypes {};
64 inputTypes +=
"'DVB'";
68 inputTypes +=
"'V4L'";
69 inputTypes +=
"'MPEG'";
73 inputTypes +=
"'FREEBOX'";
77 inputTypes +=
"'VBOX'";
80 #ifdef USING_HDHOMERUN
81 inputTypes +=
"'HDHOMERUN'";
82 #endif // USING_HDHOMERUN
85 inputTypes +=
"'SATIP'";
89 inputTypes +=
"'ASI'";
93 inputTypes +=
"'CETON'";
96 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
97 inputTypes +=
"'EXTERNAL'";
100 if (inputTypes.isEmpty())
103 return QString(
"(%1)").arg(inputTypes.join(
','));
107 const QString &inputType)
109 #if (!USING_HDHOMERUN && !USING_CETON)
113 if (inputType ==
"HDHOMERUN")
115 #ifdef USING_HDHOMERUN
116 hdhomerun_tuner_status_t status {};
118 hdhomerun_device_t *hdhr =
119 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
123 int oob = hdhomerun_device_get_oob_status(hdhr,
nullptr, &status);
127 if (oob > 0 && (strncmp(status.channel,
"none", 4) != 0))
129 LOG(VB_GENERAL, LOG_INFO,
"Cardutil: HDHomeRun Cablecard Present.");
130 hdhomerun_device_destroy(hdhr);
134 hdhomerun_device_destroy(hdhr);
139 if (inputType ==
"CETON")
144 QStringList parts = device.split(
"-");
145 if (parts.size() != 2)
147 LOG(VB_GENERAL, LOG_ERR,
148 QString(
"CardUtil: Ceton invalid device id %1").arg(device));
152 const QString& ip_address = parts.at(0);
154 QStringList tuner_parts = parts.at(1).split(
".");
155 if (tuner_parts.size() != 2)
157 LOG(VB_GENERAL, LOG_ERR,
LOC +
158 QString(
"CardUtil: Ceton invalid device id %1").arg(device));
162 uint tuner = tuner_parts.at(1).toUInt();
165 params.addQueryItem(
"i", QString::number(tuner));
166 params.addQueryItem(
"s",
"cas");
167 params.addQueryItem(
"v",
"CardStatus");
170 url.setScheme(
"http");
171 url.setHost(ip_address);
172 url.setPath(
"/get_var.json");
173 url.setQuery(params);
175 auto *request =
new QNetworkRequest();
176 request->setAttribute(QNetworkRequest::CacheLoadControlAttribute,
177 QNetworkRequest::AlwaysNetwork);
178 request->setUrl(url);
183 if (!
manager->download(request, &data))
185 LOG(VB_GENERAL, LOG_ERR,
186 QString(
"CardUtil: Ceton http request failed %1").arg(device));
190 QString response = QString(data);
192 static const QRegularExpression regex {
"^\\{ \"?result\"?: \"(.*)\" \\}$"};
193 auto match = regex.match(response);
194 if (!match.hasMatch())
196 LOG(VB_GENERAL, LOG_ERR,
197 QString(
"CardUtil: Ceton unexpected http response: %1").arg(response));
201 QString result = match.captured(1);
203 if (result ==
"Inserted")
205 LOG(VB_GENERAL, LOG_DEBUG,
"Cardutil: Ceton CableCARD present.");
209 LOG(VB_GENERAL, LOG_DEBUG,
"Cardutil: Ceton CableCARD not present.");
220 if (rawtype ==
"DVB" || rawtype ==
"HDHOMERUN" ||
221 rawtype ==
"FREEBOX" || rawtype ==
"CETON" ||
222 rawtype ==
"VBOX" || rawtype ==
"SATIP")
226 if (rawtype ==
"V4L2ENC")
235 if (rawtype ==
"EXTERNAL")
246 LOG(VB_GENERAL, LOG_DEBUG, QString(
"IsTunerShared(%1,%2)")
247 .arg(inputidA).arg(inputidB));
250 query.
prepare(
"SELECT videodevice, hostname, cardtype "
252 "WHERE ( (cardid = :INPUTID_A) OR "
253 " (cardid = :INPUTID_B) )");
266 const QString vdevice = query.
value(0).toString();
268 const QString inputtype = query.
value(2).toString();
276 bool ret = ((vdevice == query.
value(0).toString()) &&
278 (inputtype == query.
value(2).toString()));
280 LOG(VB_RECORD, LOG_DEBUG, QString(
"IsTunerShared(%1,%2) -> %3")
281 .arg(inputidA).arg(inputidB).arg(ret));
298 "SELECT count(cardtype) "
300 "WHERE capturecard.hostname = :HOSTNAME ";
302 if (!rawtype.isEmpty())
303 qstr +=
" AND capturecard.cardtype = :INPUTTYPE";
307 if (!rawtype.isEmpty())
308 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
320 count = query.
value(0).toUInt();
330 query.
prepare(
"SELECT DISTINCT cardtype, videodevice "
343 cardtype = query.
value(0).toString();
344 if (cardtype !=
"V4L2ENC")
346 inputtypes[cardtype] =
"";
354 QString driver_name =
"V4L2:" + v4l2.
DriverName();
355 inputtypes[driver_name] = v4l2.
CardName();
375 query.
prepare(
"SELECT cardtype "
377 "WHERE capturecard.sourceid = :SOURCEID "
378 "GROUP BY cardtype");
388 list.push_back(query.
value(0).toString());
409 "SELECT videodevice "
411 "WHERE hostname = :HOSTNAME";
413 if (!rawtype.isEmpty())
414 qstr +=
" AND cardtype = :INPUTTYPE";
418 if (!rawtype.isEmpty())
419 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
429 QMap<QString,bool> dup;
432 QString videodevice = query.
value(0).toString();
433 if (dup[videodevice])
436 list.push_back(videodevice);
437 dup[videodevice] =
true;
458 if (rawtype.toUpper() ==
"DVB")
460 QDir dir(
"/dev/dvb",
"adapter*", QDir::Name, QDir::Dirs);
461 QFileInfoList entries = dir.entryInfoList();
462 for (
const auto & it : qAsConst(entries))
464 QDir subdir(it.filePath(),
"frontend*", QDir::Name, QDir::Files | QDir::System);
465 const QFileInfoList subil = subdir.entryInfoList();
469 for (
const auto & subit : qAsConst(subil))
470 devs.push_back(subit.filePath());
473 else if (rawtype.toUpper() ==
"ASI")
475 QDir dir(
"/dev/",
"asirx*", QDir::Name, QDir::System);
476 QFileInfoList entries = dir.entryInfoList();
477 for (
const auto & it : qAsConst(entries))
481 devs.push_back(it.filePath());
487 #ifdef USING_HDHOMERUN
488 else if (rawtype.toUpper() ==
"HDHOMERUN")
490 uint32_t target_ip = 0;
491 uint32_t device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
492 uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
493 const int max_count = 50;
494 std::array<hdhomerun_discover_device_t,max_count> result_list {};
497 int result = hdhomerun_discover_find_devices_custom_v2(
498 target_ip, device_type, device_id, result_list.data(), result_list.size());
500 int result = hdhomerun_discover_find_devices_custom(
501 target_ip, device_type, device_id, result_list.data(), result_list.size());
506 LOG(VB_GENERAL, LOG_ERR,
"Error finding HDHomerun devices");
509 if (result >= max_count)
511 LOG(VB_GENERAL, LOG_WARNING,
512 "Warning: may be > 50 HDHomerun devices");
516 for (
int i = 0; i < result; i++)
518 QString
id = QString(
"%1").arg(result_list[i].device_id, 0, 16);
519 QString ip = QString(
"%1.%2.%3.%4")
520 .arg((result_list[i].ip_addr>>24) & 0xFF)
521 .arg((result_list[i].ip_addr>>16) & 0xFF)
522 .arg((result_list[i].ip_addr>> 8) & 0xFF)
523 .arg((result_list[i].ip_addr>> 0) & 0xFF);
526 hdhomerun_device_t *device = hdhomerun_device_create(
527 result_list[i].device_id, 0, 0,
nullptr);
530 model = hdhomerun_device_get_model_str(device);
531 hdhomerun_device_destroy(device);
534 QString hdhrdev =
id.toUpper() +
" " + ip +
" " + model;
535 devs.push_back(hdhrdev);
538 #endif // USING_HDHOMERUN
540 else if (rawtype.toUpper() ==
"SATIP")
544 #endif // USING_SATIP
546 else if (rawtype.toUpper() ==
"VBOX")
552 else if (rawtype.toUpper() ==
"CETON")
555 LOG(VB_GENERAL, LOG_INFO,
"CardUtil::ProbeVideoDevices: "
556 "TODO Probe Ceton devices");
558 #endif // USING_CETON
561 LOG(VB_GENERAL, LOG_ERR, QString(
"Raw Type: '%1' is not supported")
572 QStringList delsyslist;
581 struct dtv_property prop = {};
582 struct dtv_properties cmd = {};
584 prop.cmd = DTV_API_VERSION;
587 if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
589 LOG(VB_GENERAL, LOG_DEBUG,
590 QString(
"CardUtil(%1): ").arg(device) +
591 QString(
"dvb api version %1.%2").arg((prop.u.data>>8)&0xff).arg((prop.u.data)&0xff));
595 LOG(VB_GENERAL, LOG_ERR,
596 QString(
"CardUtil(%1) FE_GET_PROPERTY ioctl failed").arg(device) +
ENO);
603 QString msg =
"Delivery systems:";
604 for (
const auto & item : qAsConst(delsyslist))
609 LOG(VB_GENERAL, LOG_INFO, QString(
"CardUtil(%1): ").arg(device) + msg);
622 QStringList delsyslist;
625 struct dtv_property prop = {};
626 struct dtv_properties cmd = {};
628 prop.cmd = DTV_ENUM_DELSYS;
631 if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
633 for (
unsigned int i = 0; i < prop.u.buffer.len; i++)
640 LOG(VB_GENERAL, LOG_ERR,
LOC +
"FE_GET_PROPERTY ioctl failed " +
ENO);
643 Q_UNUSED(fd_frontend);
669 QString ret =
"ERROR_UNKNOWN";
671 if (device.isEmpty())
676 ret = (
type.toString() !=
"UNKNOWN") ?
type.toString().toUpper() : ret;
678 LOG(VB_GENERAL, LOG_DEBUG,
LOC + QString(
"(%1) tuner type:%2 %3")
679 .arg(device).arg(
type).arg(ret));
690 QString ret =
"ERROR_UNKNOWN";
694 QByteArray dev = dvbdev.toLatin1();
695 int fd_frontend = open(dev.constData(), O_RDWR |
O_NONBLOCK);
699 struct dvb_frontend_info info {};
700 int err = ioctl(fd_frontend, FE_GET_INFO, &info);
704 return "ERROR_PROBE";
737 return ((name ==
"VLSI VES1x93 DVB-S") ||
738 (name ==
"ST STV0299 DVB-S"));
744 if (name.indexOf(
"DVB-S") >= 0)
746 if (name ==
"DiBcom 3000P/M-C DVB-T")
784 LOG(VB_GENERAL, LOG_ERR,
LOC +
785 QString(
"TODO Add to switch case delivery system:%2 %3")
786 .arg(delsys).arg(delsys.
toString()));
825 "FROM dtv_multiplex "
826 "WHERE dtv_multiplex.mplexid = :MPLEXID");
837 LOG(VB_GENERAL, LOG_ERR,
LOC +
838 QString(
"Could not find entry in dtv_multiplex for mplexid %1")
865 if (device.isEmpty())
874 LOG(VB_GENERAL, LOG_ERR,
LOC +
875 QString(
"open failed (%1)")
882 LOG(VB_GENERAL, LOG_DEBUG, QString(
"CardUtil(%1): delsys:%2 %3")
883 .arg(device).arg(delsys).arg(delsys.
toString()));
899 struct dtv_property prop = {};
900 struct dtv_properties cmd = {};
902 prop.cmd = DTV_DELIVERY_SYSTEM;
907 int ret = ioctl(fd_frontend, FE_GET_PROPERTY, &cmd);
910 LOG(VB_GENERAL, LOG_ERR,
LOC +
911 QString(
"FE_GET_PROPERTY ioctl failed (fd_frontend:%1)")
912 .arg(fd_frontend) +
ENO);
916 delsys = prop.u.data;
919 Q_UNUSED(fd_frontend);
950 LOG(VB_GENERAL, LOG_INFO,
951 QString(
"CardUtil[%1]: ").arg(inputid) +
952 QString(
"Update capturecard delivery system: %1").arg(delsys.
toString()));
956 LOG(VB_GENERAL, LOG_ERR,
957 QString(
"CardUtil[%1]: Error probing best delivery system").arg(inputid));
958 return "ERROR_UNKNOWN";
965 QString subtype =
"ERROR_UNKNOWN";
971 LOG(VB_GENERAL, LOG_DEBUG,
972 QString(
"CardUtil[%1]: subtype:%2").arg(inputid).arg(subtype));
980 QString
t = inputType.toUpper();
981 return (
t ==
"DVB") || (
t ==
"QPSK") || (
t ==
"QAM") || (
t ==
"OFDM") ||
982 (
t ==
"ATSC") || (
t ==
"DVB_S2") || (
t ==
"DVB_T2");
997 LOG(VB_GENERAL, LOG_INFO,
LOC +
998 QString(
"Current delivery system: %1").arg(delsys.
toString()));
1001 QString msg =
"Supported delivery systems:";
1003 msg.append(delsyslist.join(
" "));
1004 LOG(VB_GENERAL, LOG_DEBUG,
LOC + msg);
1010 if (delsyslist.contains(newdelsys.
toString()))
1012 LOG(VB_GENERAL, LOG_INFO,
LOC +
1013 QString(
"Changing delivery system from %1 to %2")
1023 if (delsyslist.contains(newdelsys.
toString()))
1025 LOG(VB_GENERAL, LOG_INFO,
LOC +
1026 QString(
"Changing delivery system from %1 to %2")
1056 LOG(VB_GENERAL, LOG_INFO,
1057 QString(
"CardUtil[%1]: ").arg(inputid) +
1058 QString(
"No capturecard delivery system in database, using: %1").arg(delsys.
toString()));
1115 if (device.isEmpty())
1117 LOG(VB_GENERAL, LOG_DEBUG,
1118 QString(
"CardUtil[%1]: ").arg(inputid) +
1119 QString(
"inputid:%1 ").arg(inputid) +
1120 QString(
"delsys:%1").arg(delsys.
toString()));
1125 if (fd_frontend < 0)
1127 LOG(VB_GENERAL, LOG_ERR,
1128 QString(
"CardUtil[%1]: ").arg(inputid) +
1129 QString(
"open failed (%1)").arg(device) +
ENO);
1168 LOG(VB_GENERAL, LOG_INFO,
1169 QString(
"CardUtil[%1]: ").arg(inputid) +
1170 QString(
"Set delivery system: %1").arg(delsys.
toString()));
1172 struct dtv_property prop = {};
1173 struct dtv_properties cmd = {};
1175 prop.cmd = DTV_DELIVERY_SYSTEM;
1176 prop.u.data = delsys;
1180 ret = ioctl(fd, FE_SET_PROPERTY, &cmd);
1183 LOG(VB_GENERAL, LOG_ERR,
LOC +
1184 QString(
"[%1] FE_SET_PROPERTY ioctl failed")
1185 .arg(inputid) +
ENO);
1205 if (device.isEmpty())
1209 QByteArray dev = dvbdev.toLatin1();
1210 int fd_frontend = open(dev.constData(), O_RDWR |
O_NONBLOCK);
1211 if (fd_frontend < 0)
1213 LOG(VB_GENERAL, LOG_ERR,
LOC +
1214 QString(
"Can't open DVB frontend (%1) for %2.")
1215 .arg(dvbdev, device) +
ENO);
1224 QString(
"SELECT %1 ").arg(to_get) +
1226 "WHERE capturecard.cardid = :INPUTID");
1231 else if (query.
next())
1232 return query.
value(0).toString();
1245 QString(
"UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
1246 "WHERE cardid = :INPUTID");
1268 const QString& rawtype,
1269 const QString& inputname,
1272 std::vector<uint> list;
1281 "WHERE hostname = :HOSTNAME ";
1282 if (!videodevice.isEmpty())
1283 qstr +=
"AND videodevice = :DEVICE ";
1284 if (!inputname.isEmpty())
1285 qstr +=
"AND inputname = :INPUTNAME ";
1286 if (!rawtype.isEmpty())
1287 qstr +=
"AND cardtype = :INPUTTYPE ";
1288 qstr +=
"ORDER BY cardid";
1293 if (!videodevice.isEmpty())
1294 query.
bindValue(
":DEVICE", videodevice);
1295 if (!inputname.isEmpty())
1296 query.
bindValue(
":INPUTNAME", inputname);
1297 if (!rawtype.isEmpty())
1298 query.
bindValue(
":INPUTTYPE", rawtype.toUpper());
1304 while (query.
next())
1305 list.push_back(query.
value(0).toUInt());
1320 "WHERE parentid = :INPUTID";
1329 else if (query.
next())
1330 count = query.
value(0).toUInt();
1337 std::vector<uint> list;
1346 "WHERE parentid = :INPUTID "
1356 while (query.
next())
1357 list.push_back(query.
value(0).toUInt());
1365 uint dst_inputid = orig_dst_inputid;
1371 "DELETE FROM capturecard "
1372 "WHERE videodevice = 'temp_dummy'");
1381 "INSERT INTO capturecard "
1382 "SET videodevice = 'temp_dummy'");
1393 "WHERE videodevice = 'temp_dummy'");
1403 LOG(VB_GENERAL, LOG_ERR,
"clone_capturecard -- get temp id");
1407 dst_inputid = query.
value(0).toUInt();
1411 "SELECT videodevice, audiodevice, vbidevice, "
1412 " cardtype, hostname, signal_timeout, "
1413 " channel_timeout, dvb_wait_for_seqstart, dvb_on_demand, "
1414 " dvb_tuning_delay, dvb_diseqc_type, diseqcid, "
1415 " dvb_eitscan, inputname, sourceid, "
1416 " externalcommand, changer_device, changer_model, "
1417 " tunechan, startchan, displayname, "
1418 " dishnet_eit, recpriority, quicktune, "
1419 " livetvorder, reclimit, "
1421 " schedgroup, schedorder "
1423 "WHERE cardid = :INPUTID");
1424 query.
bindValue(
":INPUTID", src_inputid);
1433 LOG(VB_GENERAL, LOG_ERR,
"clone_cardinput -- get data 2");
1440 bool schedgroup = query.
value(26).toBool();
1441 uint schedorder = query.
value(27).toUInt();
1450 "UPDATE capturecard "
1451 "SET videodevice = :V0, "
1452 " audiodevice = :V1, "
1453 " vbidevice = :V2, "
1456 " signal_timeout = :V5, "
1457 " channel_timeout = :V6, "
1458 " dvb_wait_for_seqstart = :V7, "
1459 " dvb_on_demand = :V8, "
1460 " dvb_tuning_delay = :V9, "
1461 " dvb_diseqc_type = :V10, "
1463 " dvb_eitscan = :V12, "
1464 " inputname = :V13, "
1465 " sourceid = :V14, "
1466 " externalcommand = :V15, "
1467 " changer_device = :V16, "
1468 " changer_model = :V17, "
1469 " tunechan = :V18, "
1470 " startchan = :V19, "
1471 " displayname = :V20, "
1472 " dishnet_eit = :V21, "
1473 " recpriority = :V22, "
1474 " quicktune = :V23, "
1475 " livetvorder = :V24, "
1476 " reclimit = :V25, "
1477 " schedgroup = :SCHEDGROUP, "
1478 " schedorder = :SCHEDORDER, "
1479 " parentid = :PARENTID "
1480 "WHERE cardid = :INPUTID");
1481 for (
uint i = 0; i < 26; ++i)
1482 query2.
bindValue(QString(
":V%1").arg(i), query.
value(i).toString());
1483 query2.
bindValue(
":INPUTID", dst_inputid);
1484 query2.
bindValue(
":PARENTID", src_inputid);
1485 query2.
bindValue(
":SCHEDGROUP", schedgroup);
1486 query2.
bindValue(
":SCHEDORDER", schedorder);
1491 if (!orig_dst_inputid)
1499 for (
uint dst_grp : dst_grps)
1501 for (
uint src_grp : src_grps)
1506 if (diseqc.
Load(src_inputid))
1507 diseqc.
Store(dst_inputid);
1530 LOG(VB_GENERAL, LOG_INFO,
LOC +
1531 QString(
"Added child input %1 to parent %2")
1532 .arg(inputid).arg(parentid));
1534 query.
prepare(
"UPDATE capturecard "
1535 "SET reclimit = reclimit + 1 "
1536 "WHERE cardid = :PARENTID");
1543 LOG(VB_GENERAL, LOG_ERR,
LOC +
1544 QString(
"Failed to add child input to parent %1").arg(parentid));
1555 query.
prepare(
"SELECT changer_device "
1556 "FROM capturecard WHERE cardid = :INPUTID ");
1561 fwnode = query.
value(0).toString();
1572 query.
prepare(
"SELECT changer_model "
1573 "FROM capturecard WHERE cardid = :INPUTID ");
1578 fwnode = query.
value(0).toString();
1589 "SELECT DISTINCT cardid "
1591 "WHERE sourceid = :SOURCEID");
1594 std::vector<uint> list;
1602 while (query.
next())
1603 list.push_back(query.
value(0).toUInt());
1611 query.
prepare(
"UPDATE capturecard "
1612 "SET startchan = :CHANNUM "
1613 "WHERE cardid = :INPUTID");
1633 "inputname, sourceid, livetvorder, "
1634 "schedorder, displayname, recpriority, quicktune "
1636 "WHERE cardid = :INPUTID");
1664 QList<InputInfo> infoInputList;
1667 query.
prepare(
"SELECT cardid, "
1668 "inputname, sourceid, livetvorder, "
1669 "schedorder, displayname, recpriority, quicktune "
1670 "FROM capturecard");
1675 return infoInputList;
1678 while (query.
next())
1690 infoInputList.push_back(input);
1693 return infoInputList;
1698 InputInfo info(
"None", 0, inputid, 0, 0, 0);
1720 query.
prepare(
"SELECT startchan "
1722 "WHERE cardid = :INPUTID");
1729 else if (query.
next())
1731 startchan = query.
value(0).toString();
1735 if (!startchan.isEmpty())
1737 query.
prepare(
"SELECT channel.chanid "
1738 "FROM capturecard, channel "
1739 "WHERE capturecard.cardid = :INPUTID AND "
1740 " capturecard.sourceid = channel.sourceid AND "
1741 " channel.deleted IS NULL AND "
1742 " channel.visible > 0 AND "
1743 " channel.channum = :CHANNUM");
1751 else if (!query.
next())
1753 LOG(VB_GENERAL, LOG_DEBUG,
1754 QString(
"CardUtil[%1]: ").arg(inputid) +
1755 QString(
"Channel %1 on inputid %2 is invalid").arg(startchan).arg(inputid));
1762 if (startchan.isEmpty())
1764 query.
prepare(
"SELECT channel.channum "
1765 "FROM capturecard, channel "
1766 "WHERE capturecard.cardid = :INPUTID AND "
1767 " capturecard.sourceid = channel.sourceid AND "
1768 " channel.deleted IS NULL AND "
1769 " channel.visible > 0 "
1777 else if (query.
next())
1779 startchan = query.
value(0).toString();
1783 if (startchan.isEmpty())
1785 LOG(VB_GENERAL, LOG_DEBUG,
1786 QString(
"CardUtil[%1]: ").arg(inputid) +
1787 QString(
"No start channel found on inputid %1").arg(inputid));
1791 LOG(VB_GENERAL, LOG_DEBUG,
1792 QString(
"CardUtil[%1]: ").arg(inputid) +
1793 QString(
"Start channel %1 on inputid %2").arg(startchan).arg(inputid));
1805 query.
prepare(
"SELECT displayname "
1807 "WHERE cardid = :INPUTID");
1812 else if (query.
next())
1814 QString result = query.
value(0).toString();
1827 query.
prepare(
"SELECT cardid "
1829 "WHERE parentid = 0 "
1830 " AND cardid <> :INPUTID "
1831 " AND right(displayname, 2) = :NAME");
1832 query.
bindValue(
":NAME", name.right(2));
1833 query.
bindValue(
":INPUTID", exclude_inputid);
1842 return !query.
next();
1851 "WHERE cardid = :INPUTID");
1855 else if (query.
next())
1856 return query.
value(0).toUInt();
1865 const uint sourceid,
1866 const QString &inputname,
1867 const QString &externalcommand,
1868 const QString &changer_device,
1869 const QString &changer_model,
1871 const QString &tunechan,
1872 const QString &startchan,
1873 const QString &displayname,
1875 const uint recpriority,
1876 const uint quicktune,
1877 const uint schedorder,
1878 const uint livetvorder)
1883 "UPDATE capturecard "
1884 "SET sourceid = :SOURCEID, "
1885 " inputname = :INPUTNAME, "
1886 " externalcommand = :EXTERNALCOMMAND, "
1887 " changer_device = :CHANGERDEVICE, "
1888 " changer_model = :CHANGERMODEL, "
1889 " tunechan = :TUNECHAN, "
1890 " startchan = :STARTCHAN, "
1891 " displayname = :DISPLAYNAME, "
1892 " dishnet_eit = :DISHNETEIT, "
1893 " recpriority = :RECPRIORITY, "
1894 " quicktune = :QUICKTUNE, "
1895 " schedorder = :SCHEDORDER, "
1896 " livetvorder = :LIVETVORDER "
1897 "WHERE cardid = :INPUTID AND "
1898 " inputname = 'None'");
1902 query.
bindValue(
":INPUTNAME", inputname);
1903 query.
bindValue(
":EXTERNALCOMMAND", externalcommand);
1904 query.
bindValue(
":CHANGERDEVICE", changer_device);
1905 query.
bindValue(
":CHANGERMODEL", changer_model);
1907 query.
bindValue(
":STARTCHAN", startchan);
1909 query.
bindValue(
":DISHNETEIT", dishnet_eit);
1910 query.
bindValue(
":RECPRIORITY", recpriority);
1911 query.
bindValue(
":QUICKTUNE", quicktune);
1912 query.
bindValue(
":SCHEDORDER", schedorder);
1913 query.
bindValue(
":LIVETVORDER", livetvorder);
1928 query.
prepare(
"SELECT inputgroupid FROM inputgroup "
1929 "WHERE inputgroupname = :GROUPNAME "
1939 return query.
value(0).toUInt();
1941 query.
prepare(
"SELECT MAX(inputgroupid) FROM inputgroup");
1948 uint inputgroupid = (query.
next()) ? query.
value(0).toUInt() + 1 : 1;
1951 "INSERT INTO inputgroup "
1952 " (cardinputid, inputgroupid, inputgroupname) "
1953 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
1955 query.
bindValue(
":GROUPID", inputgroupid);
1963 return inputgroupid;
1967 const QString &
type,
1968 const QString &host,
1969 const QString &device)
1971 QString name = host +
'|' + device;
1972 if (
type ==
"FREEBOX" ||
type ==
"IMPORT" ||
1973 type ==
"DEMO" ||
type ==
"EXTERNAL" ||
1974 type ==
"HDHOMERUN" ||
type ==
"SATIP")
1975 name += QString(
"|%1").arg(inputid);
1983 "SELECT inputgroupid "
1985 "WHERE cardinputid = :INPUTID "
1986 " AND inputgroupname REGEXP '^[a-z_-]*\\\\|'");
1997 return query.
value(0).toUInt();
2008 "SELECT cardinputid, inputgroupid, inputgroupname "
2010 "WHERE inputgroupid = :GROUPID "
2011 "ORDER BY inputgroupid, cardinputid, inputgroupname");
2012 query.
bindValue(
":GROUPID", inputgroupid);
2023 const QString name = query.
value(2).toString();
2026 "INSERT INTO inputgroup "
2027 " (cardinputid, inputgroupid, inputgroupname) "
2028 "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2031 query.
bindValue(
":GROUPID", inputgroupid);
2047 if (!inputid && !inputgroupid)
2050 "DELETE FROM inputgroup "
2051 "WHERE cardinputid NOT IN "
2052 "( SELECT cardid FROM capturecard )");
2057 "DELETE FROM inputgroup "
2058 "WHERE cardinputid = :INPUTID AND "
2059 " inputgroupid = :GROUPID ");
2062 query.
bindValue(
":GROUPID", inputgroupid);
2076 std::vector<uint> list;
2081 "SELECT inputgroupid "
2083 "WHERE cardinputid = :INPUTID "
2084 "ORDER BY inputgroupid, cardinputid, inputgroupname");
2094 while (query.
next())
2095 list.push_back(query.
value(0).toUInt());
2102 std::vector<uint> list;
2107 "SELECT DISTINCT cardid "
2108 "FROM capturecard, inputgroup "
2109 "WHERE inputgroupid = :GROUPID AND "
2110 " capturecard.cardid = inputgroup.cardinputid "
2113 query.
bindValue(
":GROUPID", inputgroupid);
2121 while (query.
next())
2122 list.push_back(query.
value(0).toUInt());
2129 std::vector<uint> inputids;
2134 "SELECT DISTINCT c.cardid "
2136 " SELECT inputgroupid "
2138 " WHERE cardinputid = :INPUTID1 "
2140 "JOIN inputgroup ig ON ig.inputgroupid = g.inputgroupid "
2141 "JOIN capturecard c ON c.cardid = ig.cardinputid "
2142 " AND c.cardid <> :INPUTID2 "
2143 "ORDER BY c.cardid");
2154 while (query.
next())
2156 inputids.push_back(query.
value(0).toUInt());
2161 QString msg = QString(
"CardUtil[%1]: GetConflictingInputs(%1) ").arg(inputid);
2163 for (
auto id : inputids)
2165 ids.append(QString::number(
id));
2167 msg.append(ids.join(
','));
2168 LOG(VB_RECORD, LOG_INFO, msg);
2174 std::chrono::milliseconds &signal_timeout,
2175 std::chrono::milliseconds &channel_timeout)
2179 "SELECT signal_timeout, channel_timeout "
2181 "WHERE cardid = :INPUTID");
2186 else if (query.
next())
2188 signal_timeout = std::max(std::chrono::milliseconds(query.
value(0).toInt()), 250ms);
2189 channel_timeout = std::max(std::chrono::milliseconds(query.
value(1).toInt()), 500ms);
2200 bool needsConf =
false;
2215 "WHERE cardid = :INPUTID AND "
2216 " inputname = :INPUTNAME");
2218 query.
bindValue(
":INPUTNAME", input_name);
2222 else if (query.
next())
2223 quicktune = query.
value(0).toUInt();
2232 struct v4l2_capability vcap {};
2234 return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
2235 ((vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE) != 0U));
2236 #else // if !USING_V4L2
2238 #endif // !USING_V4L2
2242 int videofd, QString &input, QString &driver, uint32_t &
version,
2243 uint32_t &capabilities)
2254 struct v4l2_capability capability {};
2255 if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
2257 input = QString::fromLatin1((
const char*)capability.card);
2258 driver = QString::fromLatin1((
const char*)capability.driver);
2260 capabilities = capability.capabilities;
2262 #endif // USING_V4L2
2264 if (!driver.isEmpty())
2265 driver.remove( QRegularExpression(R
"(\[[0-9]\]$)") );
2267 return !input.isEmpty();
2278 bool usingv4l2 =
hasV4L2(videofd);
2280 struct v4l2_input vin {};
2281 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
2283 QString input((
char *)vin.name);
2284 list[vin.index] = input;
2295 list[0] =
"Television";
2298 #else // if !USING_V4L2
2299 list[-1] += QObject::tr(
"ERROR, Compile with V4L support to query inputs");
2300 #endif // !USING_V4L2
2312 bool usingv4l2 =
hasV4L2(videofd);
2315 struct v4l2_audio ain {};
2316 while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMAUDIO, &ain) >= 0))
2318 QString input((
char *)ain.name);
2319 list[ain.index] = input;
2329 #else // if !USING_V4L2
2330 list[-1] += QObject::tr(
2331 "ERROR, Compile with V4L support to query audio inputs");
2332 #endif // !USING_V4L2
2341 "SELECT cardid, inputname "
2343 "WHERE hostname = :HOSTNAME "
2344 " AND videodevice = :DEVICE "
2345 " AND parentid = 0 "
2346 " AND inputname <> 'None'");
2354 while (query.
next())
2355 list[query.
value(0).toUInt()] = query.
value(1).toString();
2369 struct fe_caps_name {
2374 std::array<fe_caps_name,31> fe_caps_name {{
2375 { FE_CAN_2G_MODULATION,
"CAN_2G_MODULATION" },
2376 { FE_CAN_8VSB,
"CAN_8VSB" },
2377 { FE_CAN_16VSB,
"CAN_16VSB" },
2378 { FE_CAN_BANDWIDTH_AUTO,
"CAN_BANDWIDTH_AUTO" },
2379 { FE_CAN_FEC_1_2,
"CAN_FEC_1_2" },
2380 { FE_CAN_FEC_2_3,
"CAN_FEC_2_3" },
2381 { FE_CAN_FEC_3_4,
"CAN_FEC_3_4" },
2382 { FE_CAN_FEC_4_5,
"CAN_FEC_4_5" },
2383 { FE_CAN_FEC_5_6,
"CAN_FEC_5_6" },
2384 { FE_CAN_FEC_6_7,
"CAN_FEC_6_7" },
2385 { FE_CAN_FEC_7_8,
"CAN_FEC_7_8" },
2386 { FE_CAN_FEC_8_9,
"CAN_FEC_8_9" },
2387 { FE_CAN_FEC_AUTO,
"CAN_FEC_AUTO" },
2388 { FE_CAN_GUARD_INTERVAL_AUTO,
"CAN_GUARD_INTERVAL_AUTO" },
2389 { FE_CAN_HIERARCHY_AUTO,
"CAN_HIERARCHY_AUTO" },
2390 { FE_CAN_INVERSION_AUTO,
"CAN_INVERSION_AUTO" },
2391 { FE_CAN_MULTISTREAM,
"CAN_MULTISTREAM" },
2392 { FE_CAN_MUTE_TS,
"CAN_MUTE_TS" },
2393 { FE_CAN_QAM_16,
"CAN_QAM_16" },
2394 { FE_CAN_QAM_32,
"CAN_QAM_32" },
2395 { FE_CAN_QAM_64,
"CAN_QAM_64" },
2396 { FE_CAN_QAM_128,
"CAN_QAM_128" },
2397 { FE_CAN_QAM_256,
"CAN_QAM_256" },
2398 { FE_CAN_QAM_AUTO,
"CAN_QAM_AUTO" },
2399 { FE_CAN_QPSK,
"CAN_QPSK" },
2400 { FE_CAN_RECOVER,
"CAN_RECOVER" },
2401 { FE_CAN_TRANSMISSION_MODE_AUTO,
"CAN_TRANSMISSION_MODE_AUTO" },
2402 { FE_CAN_TURBO_FEC,
"CAN_TURBO_FEC" },
2403 { FE_HAS_EXTENDED_CAPS,
"HAS_EXTENDED_CAPS" },
2404 { FE_IS_STUPID,
"IS_STUPID" },
2405 { FE_NEEDS_BENDING,
"NEEDS_BENDING" },
2408 for (
const auto & cap : fe_caps_name)
2410 if (capabilities & cap.idx)
2411 caps.append(cap.name);
2414 Q_UNUSED(capabilities);
2425 else if (
"DVB" == inputtype)
2435 LOG(VB_GENERAL, LOG_DEBUG, QString(
"ProbeAudioInputs(%1,%2)")
2436 .arg(device, inputtype));
2439 if (
"HDPVR" == inputtype ||
2440 "V4L2" == inputtype)
2450 QByteArray dev = device.toLatin1();
2451 int videofd = open(dev.constData(), O_RDWR);
2454 ret += QObject::tr(
"Could not open '%1' "
2455 "to probe its inputs.").arg(device);
2467 InputNames::iterator it;
2468 for (it = list.begin(); it != list.end(); ++it)
2479 LOG(VB_GENERAL, LOG_DEBUG, QString(
"ProbeV4LAudioInputs(%1)").arg(device));
2483 int videofd = open(device.toLatin1().constData(), O_RDWR);
2486 LOG(VB_GENERAL, LOG_ERR,
"ProbeAudioInputs() -> couldn't open device");
2487 ret += QObject::tr(
"Could not open '%1' to probe its inputs.")
2500 InputNames::iterator it;
2501 for (it = list.begin(); it != list.end(); ++it)
2516 InputNames::iterator it;
2517 for (it = list.begin(); it != list.end(); ++it)
2524 ret += QObject::tr(
"ERROR, Compile with DVB support to query inputs");
2531 const QString &videodevice)
2533 return QString(
"[ %1 : %2 ]").arg(inputtype, videodevice);
2539 query.
prepare(
"SELECT cardtype, videodevice "
2540 "FROM capturecard WHERE cardid = :INPUTID ");
2546 query.
value(1).toString());
2549 return "[ UNKNOWN ]";
2553 const QString &device,
2554 const QString &inputtype,
2555 QStringList &inputs)
2559 inputs +=
"MPEG2TS";
2560 else if (inputtype ==
"DVB")
2561 inputs +=
"DVBInput";
2567 const QString &audiodevice,
2568 const QString &vbidevice,
2569 const QString &inputtype,
2570 const uint audioratelimit,
2572 const uint dvb_swfilter,
2573 const uint dvb_sat_type,
2574 bool dvb_wait_for_seqstart,
2577 const uint dvb_diseqc_type,
2578 const uint firewire_speed,
2579 const QString &firewire_model,
2580 const uint firewire_connection,
2581 const std::chrono::milliseconds signal_timeout,
2582 const std::chrono::milliseconds channel_timeout,
2583 const uint dvb_tuning_delay,
2584 const uint contrast,
2585 const uint brightness,
2588 const uint diseqcid,
2594 "INSERT INTO capturecard "
2595 "(videodevice, audiodevice, vbidevice, cardtype, "
2596 "audioratelimit, hostname, dvb_swfilter, dvb_sat_type, "
2597 "dvb_wait_for_seqstart, skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
2598 "firewire_speed, firewire_model, firewire_connection, signal_timeout, "
2599 "channel_timeout, dvb_tuning_delay, contrast, brightness, colour, "
2600 "hue, diseqcid, dvb_eitscan) "
2601 "VALUES (:VIDEODEVICE, :AUDIODEVICE, :VBIDEVICE, :INPUTTYPE, "
2602 ":AUDIORATELIMIT, :HOSTNAME, :DVBSWFILTER, :DVBSATTYPE, "
2603 ":DVBWAITFORSEQSTART, :SKIPBTAUDIO, :DVBONDEMAND, :DVBDISEQCTYPE, "
2604 ":FIREWIRESPEED, :FIREWIREMODEL, :FIREWIRECONNECTION, :SIGNALTIMEOUT, "
2605 ":CHANNELTIMEOUT, :DVBTUNINGDELAY, :CONTRAST, :BRIGHTNESS, :COLOUR, "
2606 ":HUE, :DISEQCID, :DVBEITSCAN ) ");
2608 query.
bindValue(
":VIDEODEVICE", videodevice);
2609 query.
bindValue(
":AUDIODEVICE", audiodevice);
2610 query.
bindValue(
":VBIDEVICE", vbidevice);
2611 query.
bindValue(
":INPUTTYPE", inputtype);
2612 query.
bindValue(
":AUDIORATELIMIT", audioratelimit);
2614 query.
bindValue(
":DVBSWFILTER", dvb_swfilter);
2615 query.
bindValue(
":DVBSATTYPE", dvb_sat_type);
2616 query.
bindValue(
":DVBWAITFORSEQSTART", dvb_wait_for_seqstart);
2617 query.
bindValue(
":SKIPBTAUDIO", skipbtaudio);
2618 query.
bindValue(
":DVBONDEMAND", dvb_on_demand);
2619 query.
bindValue(
":DVBDISEQCTYPE", dvb_diseqc_type);
2620 query.
bindValue(
":FIREWIRESPEED", firewire_speed);
2621 query.
bindValue(
":FIREWIREMODEL", firewire_model);
2622 query.
bindValue(
":FIREWIRECONNECTION", firewire_connection);
2623 query.
bindValue(
":SIGNALTIMEOUT",
static_cast<qint64
>(signal_timeout.count()));
2624 query.
bindValue(
":CHANNELTIMEOUT",
static_cast<qint64
>(channel_timeout.count()));
2625 query.
bindValue(
":DVBTUNINGDELAY", dvb_tuning_delay);
2627 query.
bindValue(
":BRIGHTNESS", brightness);
2631 query.
bindValue(
":DVBEITSCAN", dvb_eitscan);
2639 query.
prepare(
"SELECT MAX(cardid) FROM capturecard");
2651 inputid = query.
value(0).toInt();
2663 for (
uint childid : childids)
2667 LOG(VB_GENERAL, LOG_ERR,
LOC +
2668 QString(
"CardUtil: Failed to delete child input %1")
2680 query.
prepare(
"DELETE FROM capturecard WHERE cardid = :INPUTID");
2689 query.
prepare(
"UPDATE capturecard SET reclimit=reclimit-1 "
2690 "WHERE cardid = :INPUTID");
2699 query.
prepare(
"DELETE FROM inputgroup WHERE cardinputid = :INPUTID");
2710 query.
prepare(
"SELECT cardid FROM capturecard "
2711 "WHERE diseqcid = :DISEQCID LIMIT 1");
2717 else if (!query.
next())
2720 tree.
Store(inputid);
2733 return (query.
exec(
"TRUNCATE TABLE inputgroup") &&
2734 query.
exec(
"TRUNCATE TABLE diseqc_config") &&
2735 query.
exec(
"TRUNCATE TABLE diseqc_tree") &&
2736 query.
exec(
"TRUNCATE TABLE capturecard") &&
2737 query.
exec(
"TRUNCATE TABLE iptv_channel"));
2742 std::vector<uint> list;
2754 while (query.
next())
2755 list.push_back(query.
value(0).toUInt());
2763 std::vector<uint> list;
2767 "SELECT DISTINCT cardid "
2769 "WHERE schedorder <> 0 "
2770 "ORDER BY schedorder, cardid");
2776 while (query.
next())
2777 list.push_back(query.
value(0).toUInt());
2785 std::vector<uint> list;
2789 "SELECT DISTINCT cardid "
2791 "WHERE livetvorder <> 0 "
2792 "ORDER BY livetvorder, cardid");
2798 while (query.
next())
2799 list.push_back(query.
value(0).toUInt());
2807 QString devname = QString(device);
2809 LOG(VB_RECORD, LOG_DEBUG,
LOC + QString(
"DVB Device (%1)").arg(devname));
2819 QString
tmp = devname;
2820 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 8,
"dvr");
2821 if (QFile::exists(
tmp))
2823 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2824 QString(
"Adapter Frontend dvr number matches (%1)").arg(
tmp));
2830 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 9,
"dvr0");
2831 if (QFile::exists(
tmp))
2833 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2834 QString(
"Adapter Frontend dvr number not matching, using dvr0 instead (%1)").arg(
tmp));
2838 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2839 QString(
"Adapter Frontend no dvr device found for (%1)").arg(devname));
2845 QString
tmp = devname;
2846 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 8,
"demux");
2847 if (QFile::exists(
tmp))
2849 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2850 QString(
"Adapter Frontend demux number matches (%1)").arg(
tmp));
2856 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 9,
"demux0");
2857 if (QFile::exists(
tmp))
2859 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2860 QString(
"Adapter Frontend demux number not matching, using demux0 instead (%1)").arg(
tmp));
2864 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2865 QString(
"Adapter Frontend no demux device found for (%1)").arg(devname));
2871 QString
tmp = devname;
2872 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 8,
"ca");
2873 if (QFile::exists(
tmp))
2875 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2876 QString(
"Adapter Frontend ca number matches (%1)").arg(
tmp));
2882 tmp =
tmp.replace(
tmp.indexOf(
"frontend"), 9,
"ca0");
2883 if (QFile::exists(
tmp))
2885 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2886 QString(
"Adapter Frontend ca number not matching, using ca0 instead (%1)").arg(
tmp));
2890 LOG(VB_RECORD, LOG_DEBUG,
LOC +
2891 QString(
"Adapter Frontend no ca device found for (%1)").arg(devname));
2897 return devname.replace(devname.indexOf(
"frontend"), 8,
"audio");
2902 return devname.replace(devname.indexOf(
"frontend"), 8,
"video");
2922 #ifdef USING_HDHOMERUN
2923 hdhomerun_device_t *hdhr =
2924 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
2928 const char *model = hdhomerun_device_get_model_str(hdhr);
2929 if (model && strstr(model,
"dvb"))
2931 hdhomerun_device_destroy(hdhr);
2935 hdhomerun_device_destroy(hdhr);
2950 #ifdef USING_HDHOMERUN
2951 hdhomerun_device_t *hdhr =
2952 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
2956 const char *model = hdhomerun_device_get_model_str(hdhr);
2957 if (model && strstr(model,
"dvbc"))
2959 hdhomerun_device_destroy(hdhr);
2963 hdhomerun_device_destroy(hdhr);
2976 QString connectErr = QObject::tr(
"Unable to connect to device.");
2978 #ifdef USING_HDHOMERUN
2979 bool deviceIsIP =
false;
2981 if (device.contains(
'.'))
2985 bool validID =
false;
2987 uint32_t dev = device.toUInt(&validID, 16);
2988 if (!validID || !hdhomerun_discover_validate_device_id(dev))
2989 return QObject::tr(
"Invalid Device ID");
2993 LOG(VB_GENERAL, LOG_INFO,
"CardUtil::GetHDHRdescription(" + device +
2994 ") - trying to locate device");
2996 hdhomerun_device_t *hdhr =
2997 hdhomerun_device_create_from_str(device.toLatin1(),
nullptr);
2999 return QObject::tr(
"Invalid Device ID or address.");
3001 const char *model = hdhomerun_device_get_model_str(hdhr);
3004 hdhomerun_device_destroy(hdhr);
3009 QString description = model;
3010 char *sVersion =
nullptr;
3011 uint32_t iVersion = 0;
3013 if (hdhomerun_device_get_version(hdhr, &sVersion, &iVersion))
3014 description += QObject::tr(
", firmware: %2").arg(sVersion);
3016 hdhomerun_device_destroy(hdhr);
3031 const QString &tunerNo,
const QString &tunerType)
3033 QString connectErr = QObject::tr(
"Unable to connect to device.");
3048 QString apiVersionErr = QObject::tr(
"The VBox software version is too old (%1), we require %2")
3051 return apiVersionErr;
3057 return QString(
"V@Box TV Gateway - ID: %1, IP: %2, Tuner: %3-%4")
3058 .arg(
id, ip, tunerNo, tunerType);
3073 return QString(
"/sys/class/asi/asirx%1/%2").arg(device_num).arg(dev);
3079 f.open(QIODevice::ReadOnly);
3080 QByteArray sdba = f.readAll();
3088 f.open(QIODevice::WriteOnly);
3089 QByteArray ba = str.toLocal8Bit();
3091 for (
uint tries = 0; (offset < ba.size()) && tries < 5; tries++)
3093 qint64 written = f.write(ba.data()+offset, ba.size()-offset);
3106 struct stat statbuf {};
3107 if (stat(device.toLocal8Bit().constData(), &statbuf) < 0)
3110 *
error = QString(
"Unable to stat '%1'").arg(device) +
ENO;
3114 if (!S_ISCHR(statbuf.st_mode))
3117 *
error = QString(
"'%1' is not a character device").arg(device);
3121 if (!(statbuf.st_rdev & 0x0080))
3124 *
error = QString(
"'%1' not a DVEO ASI receiver").arg(device);
3128 int device_num = statbuf.st_rdev & 0x007f;
3132 QStringList sys_dev_clist = sys_dev_contents.split(
":");
3133 if (2 != sys_dev_clist.size())
3137 *
error = QString(
"Unable to read '%1'")
3138 .arg(
sys_dev(device_num,
"dev"));
3142 if (sys_dev_clist[0].toUInt() != (statbuf.st_rdev>>8))
3145 *
error = QString(
"'%1' not a DVEO ASI device").arg(device);
3153 *
error =
"Not compiled with ASI support.";
3162 QString sys_bufsize_contents =
read_sys(
sys_dev(device_num,
"bufsize"));
3164 uint buf_size = sys_bufsize_contents.toUInt(&ok);
3169 *
error = QString(
"Failed to read buffer size from '%1'")
3170 .arg(
sys_dev(device_num,
"bufsize"));
3178 *
error =
"Not compiled with ASI support.";
3187 QString sys_numbuffers_contents =
read_sys(
sys_dev(device_num,
"buffers"));
3189 uint num_buffers = sys_numbuffers_contents.toUInt(&ok);
3194 *
error = QString(
"Failed to read num buffers from '%1'")
3195 .arg(
sys_dev(device_num,
"buffers"));
3203 *
error =
"Not compiled with ASI support.";
3213 uint mode = sys_bufsize_contents.toUInt(&ok);
3218 *
error = QString(
"Failed to read mode from '%1'")
3219 .arg(
sys_dev(device_num,
"mode"));
3227 *
error =
"Not compiled with ASI support.";
3237 uint old_mode = sys_bufsize_contents.toUInt(&ok);
3238 if (ok && old_mode == mode)
3243 *
error = QString(
"Failed to set mode to %1 using '%2'")
3244 .arg(mode).arg(
sys_dev(device_num,
"mode"));
3248 Q_UNUSED(device_num);
3251 *
error =
"Not compiled with ASI support.";
3261 bool CardUtil::IsVBoxPresent(
uint inputid)
3266 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX inputid (%1) not valid, redo mythtv-setup")
3277 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX chanid (%1) not found for inputid (%2), redo mythtv-setup")
3278 .arg(chanid).arg(inputid));
3283 std::chrono::milliseconds signal_timeout = 0ms;
3284 std::chrono::milliseconds tuning_timeout = 0ms;
3285 if (!
GetTimeouts(inputid,signal_timeout,tuning_timeout))
3287 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to get timeouts for inputid (%1)")
3295 query.prepare(
"SELECT url "
3296 "FROM iptv_channel "
3297 "WHERE chanid = :CHANID");
3298 query.bindValue(
":CHANID", chanid);
3302 else if (query.next())
3303 url = query.value(0).toString();
3306 QString ip = url.host();
3307 LOG(VB_GENERAL, LOG_INFO, QString(
"VBOX IP found (%1) for inputid (%2)")
3308 .arg(ip).arg(inputid));
3310 if (!
ping(ip,signal_timeout))
3312 LOG(VB_GENERAL, LOG_ERR, QString(
"VBOX at IP (%1) failed to respond to network ping for inputid (%2) timeout (%3)")
3313 .arg(ip).arg(inputid).arg(signal_timeout.count()));
3326 bool CardUtil::IsSatIPPresent(
uint inputid)
3331 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP inputid (%1) not valid, redo mythtv-setup")
3342 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP chanid (%1) not found for inputid (%2), redo mythtv-setup")
3343 .arg(chanid).arg(inputid));
3348 std::chrono::milliseconds signal_timeout = 0ms;
3349 std::chrono::milliseconds tuning_timeout = 0ms;
3350 if (!
GetTimeouts(inputid,signal_timeout,tuning_timeout))
3352 LOG(VB_GENERAL, LOG_ERR, QString(
"Failed to get timeouts for inputid (%1)")
3359 QStringList devinfo = device.split(
":");
3360 if (devinfo.value(0).toUpper() ==
"UUID")
3362 QString deviceId = QString(
"uuid:%1").arg(devinfo.value(1));
3364 LOG(VB_GENERAL, LOG_INFO, QString(
"SatIP[%1] IP address %2 device %3")
3365 .arg(inputid).arg(ip, device));
3367 if (!
ping(ip, signal_timeout))
3369 LOG(VB_GENERAL, LOG_ERR, QString(
"SatIP[%1] at IP %2 failed to respond to network ping (timeout %3)")
3370 .arg(inputid).arg(ip).arg(signal_timeout.count()));