MythTV  master
cardutil.cpp
Go to the documentation of this file.
1 // Standard UNIX C headers
2 #include <fcntl.h>
3 #include <unistd.h>
4 
5 #include <algorithm>
6 
7 #if defined(USING_V4L2) || defined(USING_DVB)
8 #include <sys/ioctl.h>
9 #endif
10 
11 // Qt headers
12 #include <QMap>
13 #include <QDir>
14 
15 // MythTV headers
16 #include "libmythbase/mythconfig.h"
17 #include "libmythbase/mythdb.h"
20 #include "libmythbase/mythmiscutil.h" // for ping()
21 
22 #include "cardutil.h"
23 #include "diseqcsettings.h"
24 #include "inputinfo.h"
25 #include "recorders/dvbchannel.h"
26 #include "sourceutil.h"
27 #include "videosource.h"
28 
29 #ifdef USING_DVB
30 #include "recorders/dvbtypes.h"
31 #endif
32 
33 #ifdef USING_V4L2
34 #include "v4l2util.h"
35 #endif
36 
37 #ifdef USING_HDHOMERUN
38 #include HDHOMERUN_HEADERFILE
39 #endif
40 
41 #ifdef USING_VBOX
42 #include "recorders/vboxutils.h"
43 #endif
44 
45 #ifdef USING_SATIP
46 #include "recorders/satiputils.h"
47 #endif
48 
49 #ifdef USING_ASI
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <dveo/asi.h>
53 #include <dveo/master.h>
54 #endif
55 
56 #define LOC QString("CardUtil: ")
57 
59 {
60  QStringList inputTypes {};
61 
62 #ifdef USING_DVB
63  inputTypes += "'DVB'";
64 #endif // USING_DVB
65 
66 #ifdef USING_V4L2
67  inputTypes += "'V4L'";
68  inputTypes += "'MPEG'";
69 #endif // USING_V4L2
70 
71 #ifdef USING_IPTV
72  inputTypes += "'FREEBOX'";
73 #endif // USING_IPTV
74 
75 #ifdef USING_VBOX
76  inputTypes += "'VBOX'";
77 #endif // USING_VBOX
78 
79 #ifdef USING_HDHOMERUN
80  inputTypes += "'HDHOMERUN'";
81 #endif // USING_HDHOMERUN
82 
83 #ifdef USING_SATIP
84  inputTypes += "'SATIP'";
85 #endif // USING_SATIP
86 
87 #ifdef USING_ASI
88  inputTypes += "'ASI'";
89 #endif
90 
91 #ifdef USING_CETON
92  inputTypes += "'CETON'";
93 #endif // USING_CETON
94 
95 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
96  inputTypes += "'EXTERNAL'";
97 #endif
98 
99  if (inputTypes.isEmpty())
100  return "('DUMMY')";
101 
102  return QString("(%1)").arg(inputTypes.join(','));
103 }
104 
105 bool CardUtil::IsCableCardPresent([[maybe_unused]] uint inputid,
106  const QString &inputType)
107 {
108  if (inputType == "HDHOMERUN")
109  {
110 #ifdef USING_HDHOMERUN
111  hdhomerun_tuner_status_t status {};
112  QString device = GetVideoDevice(inputid);
113  hdhomerun_device_t *hdhr =
114  hdhomerun_device_create_from_str(device.toLatin1(), nullptr);
115  if (!hdhr)
116  return false;
117 
118  int oob = hdhomerun_device_get_oob_status(hdhr, nullptr, &status);
119 
120  // if no OOB tuner, oob will be < 1. If no CC present, OOB
121  // status will be "none."
122  if (oob > 0 && (strncmp(status.channel, "none", 4) != 0))
123  {
124  LOG(VB_GENERAL, LOG_INFO, "Cardutil: HDHomeRun Cablecard Present.");
125  hdhomerun_device_destroy(hdhr);
126  return true;
127  }
128 
129  hdhomerun_device_destroy(hdhr);
130 
131 #endif
132  return false;
133  }
134  if (inputType == "CETON")
135  {
136 #ifdef USING_CETON
137  QString device = GetVideoDevice(inputid);
138 
139  QStringList parts = device.split("-");
140  if (parts.size() != 2)
141  {
142  LOG(VB_GENERAL, LOG_ERR,
143  QString("CardUtil: Ceton invalid device id %1").arg(device));
144  return false;
145  }
146 
147  const QString& ip_address = parts.at(0);
148 
149  QStringList tuner_parts = parts.at(1).split(".");
150  if (tuner_parts.size() != 2)
151  {
152  LOG(VB_GENERAL, LOG_ERR, LOC +
153  QString("CardUtil: Ceton invalid device id %1").arg(device));
154  return false;
155  }
156 
157  uint tuner = tuner_parts.at(1).toUInt();
158 
159  QUrlQuery params;
160  params.addQueryItem("i", QString::number(tuner));
161  params.addQueryItem("s", "cas");
162  params.addQueryItem("v", "CardStatus");
163 
164  QUrl url;
165  url.setScheme("http");
166  url.setHost(ip_address);
167  url.setPath("/get_var.json");
168  url.setQuery(params);
169 
170  auto *request = new QNetworkRequest();
171  request->setAttribute(QNetworkRequest::CacheLoadControlAttribute,
172  QNetworkRequest::AlwaysNetwork);
173  request->setUrl(url);
174 
175  QByteArray data;
177 
178  if (!manager->download(request, &data))
179  {
180  LOG(VB_GENERAL, LOG_ERR,
181  QString("CardUtil: Ceton http request failed %1").arg(device));
182  return false;
183  }
184 
185  QString response = QString(data);
186 
187  static const QRegularExpression regex { "^\\{ \"?result\"?: \"(.*)\" \\}$"};
188  auto match = regex.match(response);
189  if (!match.hasMatch())
190  {
191  LOG(VB_GENERAL, LOG_ERR,
192  QString("CardUtil: Ceton unexpected http response: %1").arg(response));
193  return false;
194  }
195 
196  QString result = match.captured(1);
197 
198  if (result == "Inserted")
199  {
200  LOG(VB_GENERAL, LOG_DEBUG, "Cardutil: Ceton CableCARD present.");
201  return true;
202  }
203 
204  LOG(VB_GENERAL, LOG_DEBUG, "Cardutil: Ceton CableCARD not present.");
205  return false;
206 #else
207  return false;
208 #endif
209  }
210  return false;
211 }
212 
213 bool CardUtil::HasTuner(const QString &rawtype,
214  [[maybe_unused]] const QString & device)
215 {
216  if (rawtype == "DVB" || rawtype == "HDHOMERUN" ||
217  rawtype == "FREEBOX" || rawtype == "CETON" ||
218  rawtype == "VBOX" || rawtype == "SATIP")
219  return true;
220 
221 #ifdef USING_V4L2
222  if (rawtype == "V4L2ENC")
223  {
224  V4L2util v4l2(device);
225  return !v4l2 ? false : v4l2.HasTuner();
226  }
227 #endif
228 
229  if (rawtype == "EXTERNAL")
230  {
231  // TODO: query EXTERNAL for capability
232  return true;
233  }
234 
235  return false;
236 }
237 
238 bool CardUtil::IsTunerShared(uint inputidA, uint inputidB)
239 {
240  LOG(VB_GENERAL, LOG_DEBUG, QString("IsTunerShared(%1,%2)")
241  .arg(inputidA).arg(inputidB));
242 
243  MSqlQuery query(MSqlQuery::InitCon());
244  query.prepare("SELECT videodevice, hostname, cardtype "
245  "FROM capturecard "
246  "WHERE ( (cardid = :INPUTID_A) OR "
247  " (cardid = :INPUTID_B) )");
248  query.bindValue(":INPUTID_A", inputidA);
249  query.bindValue(":INPUTID_B", inputidB);
250 
251  if (!query.exec())
252  {
253  MythDB::DBError("CardUtil::is_tuner_shared()", query);
254  return false;
255  }
256 
257  if (!query.next())
258  return false;
259 
260  const QString vdevice = query.value(0).toString();
261  const QString hostname = query.value(1).toString();
262  const QString inputtype = query.value(2).toString();
263 
264  if (!IsTunerSharingCapable(inputtype.toUpper()))
265  return false;
266 
267  if (!query.next())
268  return false;
269 
270  bool ret = ((vdevice == query.value(0).toString()) &&
271  (hostname == query.value(1).toString()) &&
272  (inputtype == query.value(2).toString()));
273 
274  LOG(VB_RECORD, LOG_DEBUG, QString("IsTunerShared(%1,%2) -> %3")
275  .arg(inputidA).arg(inputidB).arg(ret));
276 
277  return ret;
278 }
279 
285 bool CardUtil::IsInputTypePresent(const QString &rawtype, QString hostname)
286 {
287  if (hostname.isEmpty())
289 
290  MSqlQuery query(MSqlQuery::InitCon());
291  QString qstr =
292  "SELECT count(cardtype) "
293  "FROM capturecard "
294  "WHERE capturecard.hostname = :HOSTNAME ";
295 
296  if (!rawtype.isEmpty())
297  qstr += " AND capturecard.cardtype = :INPUTTYPE";
298 
299  query.prepare(qstr);
300 
301  if (!rawtype.isEmpty())
302  query.bindValue(":INPUTTYPE", rawtype.toUpper());
303 
304  query.bindValue(":HOSTNAME", hostname);
305 
306  if (!query.exec())
307  {
308  MythDB::DBError("CardUtil::IsInputTypePresent()", query);
309  return false;
310  }
311 
312  uint count = 0;
313  if (query.next())
314  count = query.value(0).toUInt();
315 
316  return count > 0;
317 }
318 
320 {
321  InputTypes inputtypes;
322 
323  MSqlQuery query(MSqlQuery::InitCon());
324  query.prepare("SELECT DISTINCT cardtype, videodevice "
325  "FROM capturecard");
326 
327  if (!query.exec())
328  {
329  MythDB::DBError("CardUtil::GetInputTypes()", query);
330  }
331  else
332  {
333  QString cardtype;
334 
335  while (query.next())
336  {
337  cardtype = query.value(0).toString();
338  if (cardtype != "V4L2ENC")
339  {
340  inputtypes[cardtype] = "";
341  }
342 #ifdef USING_V4L2
343  else
344  {
345  V4L2util v4l2(query.value(1).toString());
346  if (v4l2.IsOpen())
347  {
348  QString driver_name = "V4L2:" + v4l2.DriverName();
349  inputtypes[driver_name] = v4l2.CardName();
350  }
351  }
352 #endif
353  }
354  }
355 
356  return inputtypes;
357 }
358 
366 QStringList CardUtil::GetInputTypeNames(uint sourceid)
367 {
368  MSqlQuery query(MSqlQuery::InitCon());
369  query.prepare("SELECT cardtype "
370  "FROM capturecard "
371  "WHERE capturecard.sourceid = :SOURCEID "
372  "GROUP BY cardtype");
373  query.bindValue(":SOURCEID", sourceid);
374 
375  QStringList list;
376  if (!query.exec())
377  {
378  MythDB::DBError("CardUtil::GetInputTypes", query);
379  return list;
380  }
381  while (query.next())
382  list.push_back(query.value(0).toString());
383  return list;
384 }
385 
386 
387 
388 
394 QStringList CardUtil::GetVideoDevices(const QString &rawtype, QString hostname)
395 {
396  QStringList list;
397 
398  if (hostname.isEmpty())
400 
401  MSqlQuery query(MSqlQuery::InitCon());
402  QString qstr =
403  "SELECT videodevice "
404  "FROM capturecard "
405  "WHERE hostname = :HOSTNAME";
406 
407  if (!rawtype.isEmpty())
408  qstr += " AND cardtype = :INPUTTYPE";
409 
410  query.prepare(qstr);
411 
412  if (!rawtype.isEmpty())
413  query.bindValue(":INPUTTYPE", rawtype.toUpper());
414 
415  query.bindValue(":HOSTNAME", hostname);
416 
417  if (!query.exec())
418  {
419  MythDB::DBError("CardUtil::GetVideoDevices", query);
420  return list;
421  }
422 
423  QMap<QString,bool> dup;
424  while (query.next())
425  {
426  QString videodevice = query.value(0).toString();
427  if (dup[videodevice])
428  continue;
429 
430  list.push_back(videodevice);
431  dup[videodevice] = true;
432  }
433 
434  return list;
435 }
436 
437 QMap <QString,QStringList> CardUtil::s_videoDeviceCache;
438 
440 {
441  s_videoDeviceCache.clear();
442 }
443 
444 
445 QStringList CardUtil::ProbeVideoDevices(const QString &rawtype)
446 {
447  if (s_videoDeviceCache.contains(rawtype))
448  return s_videoDeviceCache[rawtype];
449 
450  QStringList devs;
451 
452  if (rawtype.toUpper() == "DVB")
453  {
454  QDir dir("/dev/dvb", "adapter*", QDir::Name, QDir::Dirs);
455  QFileInfoList entries = dir.entryInfoList();
456  for (const auto & it : qAsConst(entries))
457  {
458  QDir subdir(it.filePath(), "frontend*", QDir::Name, QDir::Files | QDir::System);
459  const QFileInfoList subil = subdir.entryInfoList();
460  if (subil.isEmpty())
461  continue;
462 
463  for (const auto & subit : qAsConst(subil))
464  devs.push_back(subit.filePath());
465  }
466  }
467  else if (rawtype.toUpper() == "ASI")
468  {
469  QDir dir("/dev/", "asirx*", QDir::Name, QDir::System);
470  QFileInfoList entries = dir.entryInfoList();
471  for (const auto & it : qAsConst(entries))
472  {
473  if (GetASIDeviceNumber(it.filePath()) >= 0)
474  {
475  devs.push_back(it.filePath());
476  continue;
477  }
478  break;
479  }
480  }
481 #ifdef USING_HDHOMERUN
482  else if (rawtype.toUpper() == "HDHOMERUN")
483  {
484 #if HDHOMERUN_VERSION >= 20221010
485  struct hdhomerun_debug_t *dbg = hdhomerun_debug_create();
486  struct hdhomerun_discover_t *ds = hdhomerun_discover_create(dbg);
487 
488  // Find devices
489  uint32_t type { HDHOMERUN_DEVICE_TYPE_TUNER };
490  uint32_t flags { HDHOMERUN_DISCOVER_FLAGS_IPV4_GENERAL |
491  HDHOMERUN_DISCOVER_FLAGS_IPV6_GENERAL };
492  int result =
493  hdhomerun_discover2_find_devices_broadcast(ds, flags, &type, 1);
494 
495  if (result == -1)
496  {
497  LOG(VB_GENERAL, LOG_ERR, "Error finding HDHomerun devices");
498  }
499  else if (result == 0)
500  {
501  LOG(VB_GENERAL, LOG_INFO, "No HDHomerun devices found.");
502  }
503  else
504  {
505  // For each device found
506  struct hdhomerun_discover2_device_t *device = hdhomerun_discover2_iter_device_first(ds);
507  while (device)
508  {
509  uint8_t tuners = hdhomerun_discover2_device_get_tuner_count(device);
510  uint32_t device_id = hdhomerun_discover2_device_get_device_id(device);
511  QString id = QString("%1").arg(device_id, 0, 16, QChar('0')).toUpper();
512  auto *dev1 = hdhomerun_device_create_from_str(id.toLatin1(), nullptr);
513  QString model = hdhomerun_device_get_model_str(dev1);
514 
515  QHostAddress ip;
516  struct sockaddr_storage saddr {};
517  struct hdhomerun_discover2_device_if_t *device_if { nullptr };
518 
519  // Enumerate all addresses
520  device_if = hdhomerun_discover2_iter_device_if_first(device);
521  while (device_if)
522  {
523  hdhomerun_discover2_device_if_get_ip_addr(device_if, &saddr);
524  ip = QHostAddress((struct sockaddr *)&saddr);
525  LOG(VB_GENERAL, LOG_DEBUG,
526  QString("HDHomerun %1 has IP %2").arg(id, ip.toString()));
527  device_if = hdhomerun_discover2_iter_device_if_next(device_if);
528  }
529 
530  // HDHomerun API recommends using first entry
531  device_if = hdhomerun_discover2_iter_device_if_first(device);
532  if (nullptr == device_if)
533  {
534  LOG(VB_GENERAL, LOG_WARNING,
535  QString("HDHomerun %1 has no IP addresses").arg(id));
536  continue;
537  }
538  hdhomerun_discover2_device_if_get_ip_addr(device_if, &saddr);
539  ip = QHostAddress((struct sockaddr *)&saddr);
540 
541  // Create device name
542  QString hdhrdev = QString("%1 %2 %3").arg(id, ip.toString(), model);
543  devs.push_back(hdhrdev);
544  LOG(VB_GENERAL, LOG_INFO,
545  QString("HDHomerun %1: IP %2, model %3, %4 tuners")
546  .arg(id, ip.toString(), model).arg(tuners));
547 
548  device = hdhomerun_discover2_iter_device_next(device);
549  }
550  hdhomerun_discover_destroy(ds);
551  hdhomerun_debug_destroy(dbg);
552  }
553 #else // HDHOMERUN_VERSION >= 20221010
554  uint32_t target_ip = 0;
555  uint32_t device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
556  uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
557  const int max_count = 50;
558  std::array<hdhomerun_discover_device_t,max_count> result_list {};
559 
560  int result = hdhomerun_discover_find_devices_custom_v2(
561  target_ip, device_type, device_id, result_list.data(), result_list.size());
562 
563  if (result == -1)
564  {
565  LOG(VB_GENERAL, LOG_ERR, "Error finding HDHomerun devices");
566  }
567 
568  if (result >= max_count)
569  {
570  LOG(VB_GENERAL, LOG_WARNING,
571  "Warning: may be > 50 HDHomerun devices");
572  }
573 
574  // Return "deviceid ipaddress" pairs
575  for (int i = 0; i < result; i++)
576  {
577  QString id = QString("%1").arg(result_list[i].device_id, 0, 16);
578  QString ip = QString("%1.%2.%3.%4")
579  .arg((result_list[i].ip_addr>>24) & 0xFF)
580  .arg((result_list[i].ip_addr>>16) & 0xFF)
581  .arg((result_list[i].ip_addr>> 8) & 0xFF)
582  .arg((result_list[i].ip_addr>> 0) & 0xFF);
583 
584  QString model = "";
585  hdhomerun_device_t *device = hdhomerun_device_create(
586  result_list[i].device_id, 0, 0, nullptr);
587  if (device)
588  {
589  model = hdhomerun_device_get_model_str(device);
590  hdhomerun_device_destroy(device);
591  }
592 
593  QString hdhrdev = id.toUpper() + " " + ip + " " + model;
594  devs.push_back(hdhrdev);
595  }
596 #endif // HDHOMERUN_VERSION >= 20221010
597  }
598 #endif // USING_HDHOMERUN
599 #ifdef USING_SATIP
600  else if (rawtype.toUpper() == "SATIP")
601  {
602  devs = SatIP::probeDevices();
603  }
604 #endif // USING_SATIP
605 #ifdef USING_VBOX
606  else if (rawtype.toUpper() == "VBOX")
607  {
608  devs = VBox::probeDevices();
609  }
610 #endif // USING_VBOX
611 #ifdef USING_CETON
612  else if (rawtype.toUpper() == "CETON")
613  {
614  // TODO implement CETON probing.
615  LOG(VB_GENERAL, LOG_INFO, "CardUtil::ProbeVideoDevices: "
616  "TODO Probe Ceton devices");
617  }
618 #endif // USING_CETON
619  else
620  {
621  LOG(VB_GENERAL, LOG_ERR, QString("Raw Type: '%1' is not supported")
622  .arg(rawtype));
623  }
624 
625  s_videoDeviceCache.insert(rawtype,devs);
626  return devs;
627 }
628 
629 // Get the list of delivery systems from the card
630 QStringList CardUtil::ProbeDeliverySystems([[maybe_unused]] const QString &device)
631 {
632  QStringList delsyslist;
633 
634 #ifdef USING_DVB
635  int fd_frontend = OpenVideoDevice(device);
636  if (fd_frontend < 0)
637  {
638  return delsyslist;
639  }
640 
641  struct dtv_property prop = {};
642  struct dtv_properties cmd = {};
643 
644  prop.cmd = DTV_API_VERSION;
645  cmd.num = 1;
646  cmd.props = &prop;
647  if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
648  {
649  LOG(VB_GENERAL, LOG_DEBUG,
650  QString("CardUtil(%1): ").arg(device) +
651  QString("dvb api version %1.%2").arg((prop.u.data>>8)&0xff).arg((prop.u.data)&0xff));
652  }
653  else
654  {
655  LOG(VB_GENERAL, LOG_ERR,
656  QString("CardUtil(%1) FE_GET_PROPERTY ioctl failed").arg(device) + ENO);
657  close(fd_frontend);
658  return delsyslist;
659  }
660 
661  delsyslist = ProbeDeliverySystems(fd_frontend);
662 
663  QString msg = "Delivery systems:";
664  for (const auto & item : qAsConst(delsyslist))
665  {
666  msg += " ";
667  msg += item;
668  }
669  LOG(VB_GENERAL, LOG_INFO, QString("CardUtil(%1): ").arg(device) + msg);
670 
671  close(fd_frontend);
672 #endif // USING_DVB
673 
674  return delsyslist;
675 }
676 
677 // Get the list of all supported delivery systems from the card
678 QStringList CardUtil::ProbeDeliverySystems([[maybe_unused]] int fd_frontend)
679 {
680  QStringList delsyslist;
681 
682 #ifdef USING_DVB
683  struct dtv_property prop = {};
684  struct dtv_properties cmd = {};
685 
686  prop.cmd = DTV_ENUM_DELSYS;
687  cmd.num = 1;
688  cmd.props = &prop;
689  if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
690  {
691  for (unsigned int i = 0; i < prop.u.buffer.len; i++)
692  {
693  delsyslist.push_back(DTVModulationSystem::toString(prop.u.buffer.data[i]));
694  }
695  }
696  else
697  {
698  LOG(VB_GENERAL, LOG_ERR, LOC + "FE_GET_PROPERTY ioctl failed " + ENO);
699  }
700 #endif // USING_DVB
701 
702  return delsyslist;
703 }
704 
705 QString CardUtil::ProbeDefaultDeliverySystem([[maybe_unused]] const QString &device)
706 {
707  DTVModulationSystem delsys;
708 
709 #ifdef USING_DVB
710  int fd = OpenVideoDevice(device);
711  if (fd >= 0)
712  {
713  delsys = ProbeBestDeliverySystem(fd);
714  close(fd);
715  }
716 #endif // USING_DVB
717 
718  return delsys.toString();
719 }
720 
721 QString CardUtil::ProbeDVBType(const QString &device)
722 {
723  QString ret = "ERROR_UNKNOWN";
724 
725  if (device.isEmpty())
726  return ret;
727 
728 #ifdef USING_DVB
729  DTVTunerType type = ProbeTunerType(device);
730  ret = (type.toString() != "UNKNOWN") ? type.toString().toUpper() : ret;
731 
732  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("(%1) tuner type:%2 %3")
733  .arg(device).arg(type).arg(ret));
734 #endif // USING_DVB
735 
736  return ret;
737 }
738 
742 QString CardUtil::ProbeDVBFrontendName([[maybe_unused]] const QString &device)
743 {
744  QString ret = "ERROR_UNKNOWN";
745 
746 #ifdef USING_DVB
747  QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
748  QByteArray dev = dvbdev.toLatin1();
749  int fd_frontend = open(dev.constData(), O_RDWR | O_NONBLOCK);
750  if (fd_frontend < 0)
751  return "ERROR_OPEN";
752 
753  struct dvb_frontend_info info {};
754  int err = ioctl(fd_frontend, FE_GET_INFO, &info);
755  if (err < 0)
756  {
757  close(fd_frontend);
758  return "ERROR_PROBE";
759  }
760 
761  ret = info.name;
762 
763  close(fd_frontend);
764 #endif // USING_DVB
765 
766  return ret;
767 }
768 
786 bool CardUtil::HasDVBCRCBug(const QString &device)
787 {
788  QString name = ProbeDVBFrontendName(device);
789  return ((name == "VLSI VES1x93 DVB-S") || // munges PMT
790  (name == "ST STV0299 DVB-S")); // munges PAT
791 }
792 
793 std::chrono::milliseconds CardUtil::GetMinSignalMonitoringDelay(const QString &device)
794 {
795  QString name = ProbeDVBFrontendName(device);
796  if (name.indexOf("DVB-S") >= 0)
797  return 300ms;
798  if (name == "DiBcom 3000P/M-C DVB-T")
799  return 100ms;
800  return 25ms;
801 }
802 
804 {
805  DTVTunerType tunertype;
806 
807  switch (delsys)
808  {
810  tunertype = DTVTunerType::kTunerTypeDVBS1;
811  break;
813  tunertype = DTVTunerType::kTunerTypeDVBS2;
814  break;
817  tunertype = DTVTunerType::kTunerTypeDVBC;
818  break;
820  tunertype = DTVTunerType::kTunerTypeDVBT;
821  break;
823  tunertype = DTVTunerType::kTunerTypeDVBT2;
824  break;
826  tunertype = DTVTunerType::kTunerTypeDVBT;
827  break;
830  tunertype = DTVTunerType::kTunerTypeATSC;
831  break;
834  break;
835  default:
836  LOG(VB_GENERAL, LOG_ERR, LOC +
837  QString("TODO Add to switch case delivery system:%2 %3")
838  .arg(delsys).arg(delsys.toString()));
839  break;
840  }
841 
842  return tunertype;
843 }
844 
845 // Get the currently configured tuner type from the database
847 {
848  DTVModulationSystem delsys = GetDeliverySystem(inputid);
849  DTVTunerType tunertype = ConvertToTunerType(delsys);
850  return tunertype;
851 }
852 
853 // Get the currently configured tuner type from the device
855 {
856  DTVModulationSystem delsys = ProbeCurrentDeliverySystem(fd_frontend);
857  DTVTunerType tunertype = ConvertToTunerType(delsys);
858  return tunertype;
859 }
860 
861 // Get the currently configured tuner type from the device
863 {
865  DTVTunerType tunertype = ConvertToTunerType(delsys);
866  return tunertype;
867 }
868 
869 // Get the tuner type from the multiplex
871 {
872  DTVTunerType tuner_type;
873 
874  MSqlQuery query(MSqlQuery::InitCon());
875  query.prepare(
876  "SELECT mod_sys "
877  "FROM dtv_multiplex "
878  "WHERE dtv_multiplex.mplexid = :MPLEXID");
879  query.bindValue(":MPLEXID", mplexid);
880 
881  if (!query.exec())
882  {
883  MythDB::DBError("CardUtil::GetTunerTypeFromMultiplex", query);
884  return tuner_type;
885  }
886 
887  if (!query.next())
888  {
889  LOG(VB_GENERAL, LOG_ERR, LOC +
890  QString("Could not find entry in dtv_multiplex for mplexid %1")
891  .arg(mplexid));
892 
893  return tuner_type;
894  }
895 
896  DTVModulationSystem mod_sys;
897  mod_sys.Parse(query.value(0).toString());
898  tuner_type = CardUtil::ConvertToTunerType(mod_sys);
899 
900  return tuner_type;
901 }
902 
903 // Get the currently configured delivery system from the database
905 {
906  QString ds = GetDeliverySystemFromDB(inputid);
907  DTVModulationSystem delsys;
908  delsys.Parse(ds);
909  return delsys;
910 }
911 
912 // Get the currently configured delivery system from the device
913 DTVModulationSystem CardUtil::ProbeCurrentDeliverySystem([[maybe_unused]] const QString &device)
914 {
915  DTVModulationSystem delsys;
916 
917  if (device.isEmpty())
918  {
919  return delsys;
920  }
921 
922 #ifdef USING_DVB
923  int fd_frontend = OpenVideoDevice(device);
924  if (fd_frontend < 0)
925  {
926  LOG(VB_GENERAL, LOG_ERR, LOC +
927  QString("open failed (%1)")
928  .arg(device) + ENO);
929  return delsys;
930  }
931 
932  delsys = ProbeCurrentDeliverySystem(fd_frontend);
933 
934  LOG(VB_GENERAL, LOG_DEBUG, QString("CardUtil(%1): delsys:%2 %3")
935  .arg(device).arg(delsys).arg(delsys.toString()));
936 
937  close(fd_frontend);
938 #endif
939 
940  return delsys;
941 }
942 
943 // Get the currently configured delivery system from the device
944 DTVModulationSystem CardUtil::ProbeCurrentDeliverySystem([[maybe_unused]] int fd_frontend)
945 {
946  DTVModulationSystem delsys;
947 
948 #ifdef USING_DVB
949  struct dtv_property prop = {};
950  struct dtv_properties cmd = {};
951 
952  prop.cmd = DTV_DELIVERY_SYSTEM;
953  // prop.u.data = delsys;
954  cmd.num = 1;
955  cmd.props = &prop;
956 
957  int ret = ioctl(fd_frontend, FE_GET_PROPERTY, &cmd);
958  if (ret < 0)
959  {
960  LOG(VB_GENERAL, LOG_ERR, LOC +
961  QString("FE_GET_PROPERTY ioctl failed (fd_frontend:%1)")
962  .arg(fd_frontend) + ENO);
963  return delsys;
964  }
965 
966  delsys = prop.u.data;
967 
968 #endif // USING_DVB
969 
970  return delsys;
971 }
972 
973 // Get the delivery system from database table capturecard.
974 // If there is nothing in the database then get the currently
975 // configured delivery system, check for DVB-T/T2 and DVB-S/S2
976 // and update the database.
977 // Configure the tuner.
978 // Return the tuner type corresponding with the modulation system.
980 {
981  QString type = GetRawInputType(inputid);
982  if ("DVB" != type)
983  return type;
984 
985  DTVTunerType tunertype;
986  int fd_frontend = OpenVideoDevice(inputid);
987  if (fd_frontend < 0)
988  return "ERROR_OPEN";
989 
990  DTVModulationSystem delsys = GetDeliverySystem(inputid);
992  {
993  delsys = ProbeBestDeliverySystem(fd_frontend);
995  {
996  // Update database
997  set_on_input("inputname", inputid, delsys.toString()); // Update DB capturecard
998  LOG(VB_GENERAL, LOG_INFO,
999  QString("CardUtil[%1]: ").arg(inputid) +
1000  QString("Update capturecard delivery system: %1").arg(delsys.toString()));
1001  }
1002  else
1003  {
1004  LOG(VB_GENERAL, LOG_ERR,
1005  QString("CardUtil[%1]: Error probing best delivery system").arg(inputid));
1006  return "ERROR_UNKNOWN";
1007  }
1008  }
1009  SetDeliverySystem(inputid, delsys, fd_frontend);
1010  tunertype = ConvertToTunerType(delsys);
1011  close(fd_frontend);
1012 
1013  QString subtype = "ERROR_UNKNOWN";
1014  if (DTVTunerType::kTunerTypeUnknown != tunertype)
1015  {
1016  subtype = tunertype.toString();
1017  }
1018 
1019  LOG(VB_GENERAL, LOG_DEBUG,
1020  QString("CardUtil[%1]: subtype:%2").arg(inputid).arg(subtype));
1021 
1022  return subtype;
1023 }
1024 
1026 bool CardUtil::IsDVBInputType(const QString &inputType)
1027 {
1028  QString t = inputType.toUpper();
1029  return (t == "DVB") || (t == "QPSK") || (t == "QAM") || (t == "OFDM") ||
1030  (t == "ATSC") || (t == "DVB_S2") || (t == "DVB_T2");
1031 }
1032 
1033 // Get the current delivery system from the card
1034 // Get all supported delivery systems from the card
1035 // If the current delivery system is DVB-T and DVB-T2 is supported then select DVB-T2
1036 // If the current delivery system is DVB-S and DVB-S2 is supported then select DVB-S2
1037 //
1039 {
1040  DTVModulationSystem delsys;
1041 
1042 #ifdef USING_DVB
1043  // Get the current delivery system from the card
1044  delsys = ProbeCurrentDeliverySystem(fd);
1045  LOG(VB_GENERAL, LOG_INFO, LOC +
1046  QString("Current delivery system: %1").arg(delsys.toString()));
1047 
1048  // Get all supported delivery systems from the card
1049  QString msg = "Supported delivery systems:";
1050  QStringList delsyslist = ProbeDeliverySystems(fd);
1051  msg.append(delsyslist.join(" "));
1052  LOG(VB_GENERAL, LOG_DEBUG, LOC + msg);
1053 
1054  // If the current delivery system is DVB-T and DVB-T2 is supported then select DVB-T2
1056  {
1058  if (delsyslist.contains(newdelsys.toString()))
1059  {
1060  LOG(VB_GENERAL, LOG_INFO, LOC +
1061  QString("Changing delivery system from %1 to %2")
1062  .arg(delsys.toString(), newdelsys.toString()));
1063  delsys = newdelsys;
1064  }
1065  }
1066 
1067  // If the current delivery system is DVB-S and DVB-S2 is supported then select DVB-S2
1069  {
1071  if (delsyslist.contains(newdelsys.toString()))
1072  {
1073  LOG(VB_GENERAL, LOG_INFO, LOC +
1074  QString("Changing delivery system from %1 to %2")
1075  .arg(delsys.toString(), newdelsys.toString()));
1076  delsys = newdelsys;
1077  }
1078  }
1079 #endif
1080 
1081  return delsys;
1082 }
1083 
1084 // Get the delivery system from the database
1085 // If not found then get the best delivery system from the card
1086 //
1088  [[maybe_unused]] int fd)
1089 {
1090  DTVModulationSystem delsys;
1091 #ifdef USING_DVB
1092 
1093  // If there is a valid modulation system in the database
1094  // then we return that and do nothing more.
1095  delsys = GetDeliverySystem(inputid);
1097  {
1098  return delsys;
1099  }
1100 
1101  // Nothing in the database, get default and use that
1102  delsys = ProbeBestDeliverySystem(fd);
1103  LOG(VB_GENERAL, LOG_INFO,
1104  QString("CardUtil[%1]: ").arg(inputid) +
1105  QString("No capturecard delivery system in database, using: %1").arg(delsys.toString()));
1106 
1107 #endif
1108 
1109  return delsys;
1110 }
1111 
1112 // Configure the tuner to use the delivery system from database
1113 // If not found then set to the best delivery system from the card
1114 //
1115 int CardUtil::SetDefaultDeliverySystem([[maybe_unused]] uint inputid,
1116  [[maybe_unused]] int fd)
1117 {
1118  int ret = -1;
1119 
1120 #ifdef USING_DVB
1121  DTVModulationSystem delsys = GetOrProbeDeliverySystem(inputid, fd);
1123  {
1124  ret = SetDeliverySystem(inputid, delsys, fd);
1125  }
1126 #endif
1127 
1128  return ret;
1129 }
1130 
1131 // Set delivery system from database
1132 //
1133 int CardUtil::SetDeliverySystem([[maybe_unused]] uint inputid)
1134 {
1135  int ret = -1;
1136 
1137 #ifdef USING_DVB
1138  DTVModulationSystem delsys = GetDeliverySystem(inputid);
1140  {
1141  ret = SetDeliverySystem(inputid, delsys);
1142  }
1143 #endif // USING_DVB
1144 
1145  return ret;
1146 }
1147 
1148 int CardUtil::SetDeliverySystem([[maybe_unused]] uint inputid,
1149  [[maybe_unused]] DTVModulationSystem delsys)
1150 {
1151  int ret = -1;
1152 
1153 #ifdef USING_DVB
1154  QString device = GetVideoDevice(inputid);
1155 
1156  if (device.isEmpty())
1157  {
1158  LOG(VB_GENERAL, LOG_DEBUG,
1159  QString("CardUtil[%1]: ").arg(inputid) +
1160  QString("inputid:%1 ").arg(inputid) +
1161  QString("delsys:%1").arg(delsys.toString()));
1162  return ret;
1163  }
1164 
1165  int fd_frontend = OpenVideoDevice(device);
1166  if (fd_frontend < 0)
1167  {
1168  LOG(VB_GENERAL, LOG_ERR,
1169  QString("CardUtil[%1]: ").arg(inputid) +
1170  QString("open failed (%1)").arg(device) + ENO);
1171  return ret;
1172  }
1173  ret = SetDeliverySystem(inputid, delsys, fd_frontend);
1174 
1175  close(fd_frontend);
1176 #endif // USING_DVB
1177 
1178  return ret;
1179 }
1180 
1181 // Get delivery system from the database and write it to the card
1182 int CardUtil::SetDeliverySystem([[maybe_unused]] uint inputid,
1183  [[maybe_unused]] int fd)
1184 {
1185  int ret = -1;
1186 
1187 #ifdef USING_DVB
1188  DTVModulationSystem delsys = GetDeliverySystem(inputid);
1190  {
1191  ret = SetDeliverySystem(inputid, delsys, fd);
1192  }
1193 #endif // USING_DVB
1194 
1195  return ret;
1196 }
1197 
1198 // Write the delivery system to the card
1199 int CardUtil::SetDeliverySystem([[maybe_unused]] uint inputid,
1200  [[maybe_unused]] DTVModulationSystem delsys,
1201  [[maybe_unused]] int fd)
1202 {
1203  int ret = -1;
1204 
1205 #ifdef USING_DVB
1206  LOG(VB_GENERAL, LOG_INFO,
1207  QString("CardUtil[%1]: ").arg(inputid) +
1208  QString("Set delivery system: %1").arg(delsys.toString()));
1209 
1210  struct dtv_property prop = {};
1211  struct dtv_properties cmd = {};
1212 
1213  prop.cmd = DTV_DELIVERY_SYSTEM;
1214  prop.u.data = delsys;
1215  cmd.num = 1;
1216  cmd.props = &prop;
1217 
1218  ret = ioctl(fd, FE_SET_PROPERTY, &cmd);
1219  if (ret < 0)
1220  {
1221  LOG(VB_GENERAL, LOG_ERR, LOC +
1222  QString("[%1] FE_SET_PROPERTY ioctl failed")
1223  .arg(inputid) + ENO);
1224  return ret;
1225  }
1226 #endif // USING_DVB
1227 
1228  return ret;
1229 }
1230 
1232 {
1233  QString device = GetVideoDevice(inputid);
1234  return OpenVideoDevice(device);
1235 }
1236 
1237 int CardUtil::OpenVideoDevice(const QString &device)
1238 {
1239  if (device.isEmpty())
1240  return -1;
1241 
1242  QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
1243  QByteArray dev = dvbdev.toLatin1();
1244  int fd_frontend = open(dev.constData(), O_RDWR | O_NONBLOCK);
1245  if (fd_frontend < 0)
1246  {
1247  LOG(VB_GENERAL, LOG_ERR, LOC +
1248  QString("Can't open DVB frontend (%1) for %2.")
1249  .arg(dvbdev, device) + ENO);
1250  }
1251  return fd_frontend;
1252 }
1253 
1254 QString get_on_input(const QString &to_get, uint inputid)
1255 {
1256  MSqlQuery query(MSqlQuery::InitCon());
1257  query.prepare(
1258  QString("SELECT %1 ").arg(to_get) +
1259  "FROM capturecard "
1260  "WHERE capturecard.cardid = :INPUTID");
1261  query.bindValue(":INPUTID", inputid);
1262 
1263  if (!query.exec())
1264  MythDB::DBError("CardUtil::get_on_input", query);
1265  else if (query.next())
1266  return query.value(0).toString();
1267 
1268  return {};
1269 }
1270 
1271 bool set_on_input(const QString &to_set, uint inputid, const QString &value)
1272 {
1273  QString tmp = get_on_input("capturecard.cardid", inputid);
1274  if (tmp.isEmpty())
1275  return false;
1276 
1277  MSqlQuery query(MSqlQuery::InitCon());
1278  query.prepare(
1279  QString("UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
1280  "WHERE cardid = :INPUTID");
1281  query.bindValue(":INPUTID", inputid);
1282  query.bindValue(":VALUE", value);
1283 
1284  if (query.exec())
1285  return true;
1286 
1287  MythDB::DBError("CardUtil::set_on_input", query);
1288  return false;
1289 }
1290 
1301 std::vector<uint> CardUtil::GetInputIDs(const QString& videodevice,
1302  const QString& rawtype,
1303  const QString& inputname,
1304  QString hostname)
1305 {
1306  std::vector<uint> list;
1307 
1308  if (hostname.isEmpty())
1310 
1311  MSqlQuery query(MSqlQuery::InitCon());
1312  QString qstr =
1313  "SELECT cardid "
1314  "FROM capturecard "
1315  "WHERE hostname = :HOSTNAME ";
1316  if (!videodevice.isEmpty())
1317  qstr += "AND videodevice = :DEVICE ";
1318  if (!inputname.isEmpty())
1319  qstr += "AND inputname = :INPUTNAME ";
1320  if (!rawtype.isEmpty())
1321  qstr += "AND cardtype = :INPUTTYPE ";
1322  qstr += "ORDER BY cardid";
1323 
1324  query.prepare(qstr);
1325 
1326  query.bindValue(":HOSTNAME", hostname);
1327  if (!videodevice.isEmpty())
1328  query.bindValue(":DEVICE", videodevice);
1329  if (!inputname.isEmpty())
1330  query.bindValue(":INPUTNAME", inputname);
1331  if (!rawtype.isEmpty())
1332  query.bindValue(":INPUTTYPE", rawtype.toUpper());
1333 
1334  if (!query.exec())
1335  MythDB::DBError("CardUtil::GetInputIDs(videodevice...)", query);
1336  else
1337  {
1338  while (query.next())
1339  list.push_back(query.value(0).toUInt());
1340  }
1341 
1342  return list;
1343 }
1344 
1346 {
1347  if (!inputid)
1348  return 0;
1349 
1350  MSqlQuery query(MSqlQuery::InitCon());
1351  QString qstr =
1352  "SELECT COUNT(*) "
1353  "FROM capturecard "
1354  "WHERE parentid = :INPUTID";
1355 
1356  query.prepare(qstr);
1357  query.bindValue(":INPUTID", inputid);
1358 
1359  uint count = 0;
1360 
1361  if (!query.exec())
1362  MythDB::DBError("CardUtil::GetChildInputCount()", query);
1363  else if (query.next())
1364  count = query.value(0).toUInt();
1365 
1366  return count;
1367 }
1368 
1369 std::vector<uint> CardUtil::GetChildInputIDs(uint inputid)
1370 {
1371  std::vector<uint> list;
1372 
1373  if (!inputid)
1374  return list;
1375 
1376  MSqlQuery query(MSqlQuery::InitCon());
1377  QString qstr =
1378  "SELECT cardid "
1379  "FROM capturecard "
1380  "WHERE parentid = :INPUTID "
1381  "ORDER BY cardid";
1382 
1383  query.prepare(qstr);
1384  query.bindValue(":INPUTID", inputid);
1385 
1386  if (!query.exec())
1387  MythDB::DBError("CardUtil::GetChildInputIDs()", query);
1388  else
1389  {
1390  while (query.next())
1391  list.push_back(query.value(0).toUInt());
1392  }
1393 
1394  return list;
1395 }
1396 
1397 static uint clone_capturecard(uint src_inputid, uint orig_dst_inputid)
1398 {
1399  uint dst_inputid = orig_dst_inputid;
1400 
1401  MSqlQuery query(MSqlQuery::InitCon());
1402  if (!dst_inputid)
1403  {
1404  query.prepare(
1405  "DELETE FROM capturecard "
1406  "WHERE videodevice = 'temp_dummy'");
1407 
1408  if (!query.exec())
1409  {
1410  MythDB::DBError("clone_capturecard -- delete temp", query);
1411  return 0;
1412  }
1413 
1414  query.prepare(
1415  "INSERT INTO capturecard "
1416  "SET videodevice = 'temp_dummy'");
1417 
1418  if (!query.exec())
1419  {
1420  MythDB::DBError("clone_capturecard -- insert temp", query);
1421  return 0;
1422  }
1423 
1424  query.prepare(
1425  "SELECT cardid "
1426  "FROM capturecard "
1427  "WHERE videodevice = 'temp_dummy'");
1428 
1429  if (!query.exec())
1430  {
1431  MythDB::DBError("clone_capturecard -- get temp id", query);
1432  return 0;
1433  }
1434 
1435  if (!query.next())
1436  {
1437  LOG(VB_GENERAL, LOG_ERR, "clone_capturecard -- get temp id");
1438  return 0;
1439  }
1440 
1441  dst_inputid = query.value(0).toUInt();
1442  }
1443 
1444  query.prepare(
1445  "SELECT videodevice, audiodevice, vbidevice, "
1446  " cardtype, hostname, signal_timeout, "
1447  " channel_timeout, dvb_wait_for_seqstart, dvb_on_demand, "
1448  " dvb_tuning_delay, dvb_diseqc_type, diseqcid, "
1449  " dvb_eitscan, inputname, sourceid, "
1450  " externalcommand, changer_device, changer_model, "
1451  " tunechan, startchan, displayname, "
1452  " dishnet_eit, recpriority, quicktune, "
1453  " livetvorder, reclimit, "
1454  // See below for special handling of the following.
1455  " schedgroup, schedorder "
1456  "FROM capturecard "
1457  "WHERE cardid = :INPUTID");
1458  query.bindValue(":INPUTID", src_inputid);
1459 
1460  if (!query.exec())
1461  {
1462  MythDB::DBError("clone_capturecard -- get data", query);
1463  return 0;
1464  }
1465  if (!query.next())
1466  {
1467  LOG(VB_GENERAL, LOG_ERR, "clone_cardinput -- get data 2");
1468  return 0;
1469  }
1470 
1471  // Handle schedgroup and schedorder specially. If schedgroup is
1472  // set, schedgroup and schedorder should be false and 0,
1473  // respectively, for all children.
1474  bool schedgroup = query.value(26).toBool();
1475  uint schedorder = query.value(27).toUInt();
1476  if (schedgroup)
1477  {
1478  schedgroup = false;
1479  schedorder = 0;
1480  }
1481 
1482  MSqlQuery query2(MSqlQuery::InitCon());
1483  query2.prepare(
1484  "UPDATE capturecard "
1485  "SET videodevice = :V0, "
1486  " audiodevice = :V1, "
1487  " vbidevice = :V2, "
1488  " cardtype = :V3, "
1489  " hostname = :V4, "
1490  " signal_timeout = :V5, "
1491  " channel_timeout = :V6, "
1492  " dvb_wait_for_seqstart = :V7, "
1493  " dvb_on_demand = :V8, "
1494  " dvb_tuning_delay = :V9, "
1495  " dvb_diseqc_type = :V10, "
1496  " diseqcid = :V11,"
1497  " dvb_eitscan = :V12, "
1498  " inputname = :V13, "
1499  " sourceid = :V14, "
1500  " externalcommand = :V15, "
1501  " changer_device = :V16, "
1502  " changer_model = :V17, "
1503  " tunechan = :V18, "
1504  " startchan = :V19, "
1505  " displayname = :V20, "
1506  " dishnet_eit = :V21, "
1507  " recpriority = :V22, "
1508  " quicktune = :V23, "
1509  " livetvorder = :V24, "
1510  " reclimit = :V25, "
1511  " schedgroup = :SCHEDGROUP, "
1512  " schedorder = :SCHEDORDER, "
1513  " parentid = :PARENTID "
1514  "WHERE cardid = :INPUTID");
1515  for (uint i = 0; i < 26; ++i)
1516  query2.bindValue(QString(":V%1").arg(i), query.value(i).toString());
1517  query2.bindValue(":INPUTID", dst_inputid);
1518  query2.bindValue(":PARENTID", src_inputid);
1519  query2.bindValue(":SCHEDGROUP", schedgroup);
1520  query2.bindValue(":SCHEDORDER", schedorder);
1521 
1522  if (!query2.exec())
1523  {
1524  MythDB::DBError("clone_capturecard -- save data", query2);
1525  if (!orig_dst_inputid)
1526  CardUtil::DeleteInput(dst_inputid);
1527  return 0;
1528  }
1529 
1530  // copy input group linkages
1531  std::vector<uint> src_grps = CardUtil::GetInputGroups(src_inputid);
1532  std::vector<uint> dst_grps = CardUtil::GetInputGroups(dst_inputid);
1533  for (uint dst_grp : dst_grps)
1534  CardUtil::UnlinkInputGroup(dst_inputid, dst_grp);
1535  for (uint src_grp : src_grps)
1536  CardUtil::LinkInputGroup(dst_inputid, src_grp);
1537 
1538  // clone diseqc_config (just points to the same diseqc_tree row)
1539  DiSEqCDevSettings diseqc;
1540  if (diseqc.Load(src_inputid))
1541  diseqc.Store(dst_inputid);
1542 
1543  return dst_inputid;
1544 }
1545 
1546 uint CardUtil::CloneCard(uint src_inputid, uint orig_dst_inputid)
1547 {
1548  QString type = CardUtil::GetRawInputType(src_inputid);
1550  return 0;
1551 
1552  uint dst_inputid = clone_capturecard(src_inputid, orig_dst_inputid);
1553  return dst_inputid;
1554 }
1555 
1556 
1557 bool CardUtil::InputSetMaxRecordings(uint parentid, uint max_recordings)
1558 {
1559  if (max_recordings < 1)
1560  {
1561  LOG(VB_GENERAL, LOG_ERR, LOC +
1562  "InputSetMaxRecording: max must be greater than zero.");
1563  return false;
1564  }
1565 
1566  std::vector<uint> cardids = CardUtil::GetChildInputIDs(parentid);
1567 
1568  // Delete old clone cards as required.
1569  for (size_t i = cardids.size() + 1;
1570  (i > max_recordings) && !cardids.empty(); --i)
1571  {
1572  CardUtil::DeleteInput(cardids.back());
1573  cardids.pop_back();
1574  }
1575 
1576  // Clone this config to existing clone cards.
1577  for (uint id : cardids)
1578  CardUtil::CloneCard(parentid, id);
1579 
1580  // Create new clone cards as required.
1581  for (size_t i = cardids.size() + 1; i < max_recordings; ++i)
1582  {
1583  CardUtil::CloneCard(parentid, 0);
1584  }
1585 
1586  return true;
1587 }
1588 
1589 
1591 {
1592  uint inputid = CloneCard(parentid, 0);
1593 
1594  // Update the reclimit for the parent and all children so the new
1595  // child doesn't get removed the next time mythtv-setup is run.
1596  if (inputid)
1597  {
1598  LOG(VB_GENERAL, LOG_INFO, LOC +
1599  QString("Added child input %1 to parent %2")
1600  .arg(inputid).arg(parentid));
1601  MSqlQuery query(MSqlQuery::InitCon());
1602  query.prepare("UPDATE capturecard "
1603  "SET reclimit = reclimit + 1 "
1604  "WHERE cardid = :PARENTID");
1605  query.bindValue(":PARENTID", parentid);
1606  if (!query.exec())
1607  MythDB::DBError("CardUtil::AddChildInput", query);
1608  }
1609  else
1610  {
1611  LOG(VB_GENERAL, LOG_ERR, LOC +
1612  QString("Failed to add child input to parent %1").arg(parentid));
1613  }
1614 
1615  return inputid;
1616 }
1617 
1619 {
1620  QString fwnode;
1621 
1622  MSqlQuery query(MSqlQuery::InitCon());
1623  query.prepare("SELECT changer_device "
1624  "FROM capturecard WHERE cardid = :INPUTID ");
1625  query.bindValue(":INPUTID", inputid);
1626 
1627  if (query.exec() && query.next())
1628  {
1629  fwnode = query.value(0).toString();
1630  }
1631 
1632  return fwnode;
1633 }
1634 
1636 {
1637  QString fwnode;
1638 
1639  MSqlQuery query(MSqlQuery::InitCon());
1640  query.prepare("SELECT changer_model "
1641  "FROM capturecard WHERE cardid = :INPUTID ");
1642  query.bindValue(":INPUTID", inputid);
1643 
1644  if (query.exec() && query.next())
1645  {
1646  fwnode = query.value(0).toString();
1647  }
1648 
1649  return fwnode;
1650 }
1651 
1652 std::vector<uint> CardUtil::GetInputIDs(uint sourceid)
1653 {
1654  MSqlQuery query(MSqlQuery::InitCon());
1655 
1656  query.prepare(
1657  "SELECT DISTINCT cardid "
1658  "FROM capturecard "
1659  "WHERE sourceid = :SOURCEID");
1660  query.bindValue(":SOURCEID", sourceid);
1661 
1662  std::vector<uint> list;
1663 
1664  if (!query.exec())
1665  {
1666  MythDB::DBError("CardUtil::GetInputIDs(sourceid)", query);
1667  return list;
1668  }
1669 
1670  while (query.next())
1671  list.push_back(query.value(0).toUInt());
1672 
1673  return list;
1674 }
1675 
1676 bool CardUtil::SetStartChannel(uint inputid, const QString &channum)
1677 {
1678  MSqlQuery query(MSqlQuery::InitCon());
1679  query.prepare("UPDATE capturecard "
1680  "SET startchan = :CHANNUM "
1681  "WHERE cardid = :INPUTID");
1682  query.bindValue(":CHANNUM", channum);
1683  query.bindValue(":INPUTID", inputid);
1684 
1685  if (!query.exec())
1686  {
1687  MythDB::DBError("CardUtil::SetStartChannel", query);
1688  return false;
1689  }
1690 
1691  return true;
1692 }
1693 
1694 bool CardUtil::GetInputInfo(InputInfo &input, std::vector<uint> *groupids)
1695 {
1696  if (!input.m_inputId)
1697  return false;
1698 
1699  MSqlQuery query(MSqlQuery::InitCon());
1700  query.prepare("SELECT "
1701  "inputname, sourceid, livetvorder, "
1702  "schedorder, displayname, recpriority, quicktune "
1703  "FROM capturecard "
1704  "WHERE cardid = :INPUTID");
1705  query.bindValue(":INPUTID", input.m_inputId);
1706 
1707  if (!query.exec())
1708  {
1709  MythDB::DBError("CardUtil::GetInputInfo()", query);
1710  return false;
1711  }
1712 
1713  if (!query.next())
1714  return false;
1715 
1716  input.m_name = query.value(0).toString();
1717  input.m_sourceId = query.value(1).toUInt();
1718  input.m_liveTvOrder = query.value(2).toUInt();
1719  input.m_scheduleOrder = query.value(3).toUInt();
1720  input.m_displayName = query.value(4).toString();
1721  input.m_recPriority = query.value(5).toInt();
1722  input.m_quickTune = query.value(6).toBool();
1723 
1724  if (groupids)
1725  *groupids = GetInputGroups(input.m_inputId);
1726 
1727  return true;
1728 }
1729 
1730 QList<InputInfo> CardUtil::GetAllInputInfo()
1731 {
1732  QList<InputInfo> infoInputList;
1733 
1734  MSqlQuery query(MSqlQuery::InitCon());
1735  query.prepare("SELECT cardid, "
1736  "inputname, sourceid, livetvorder, "
1737  "schedorder, displayname, recpriority, quicktune "
1738  "FROM capturecard");
1739 
1740  if (!query.exec())
1741  {
1742  MythDB::DBError("CardUtil::GetAllInputInfo()", query);
1743  return infoInputList;
1744  }
1745 
1746  while (query.next())
1747  {
1748  InputInfo input;
1749  input.m_inputId = query.value(0).toUInt();
1750  input.m_name = query.value(1).toString();
1751  input.m_sourceId = query.value(2).toUInt();
1752  input.m_liveTvOrder = query.value(3).toUInt();
1753  input.m_scheduleOrder = query.value(4).toUInt();
1754  input.m_displayName = query.value(5).toString();
1755  input.m_recPriority = query.value(6).toInt();
1756  input.m_quickTune = query.value(7).toBool();
1757 
1758  infoInputList.push_back(input);
1759  }
1760 
1761  return infoInputList;
1762 }
1763 
1765 {
1766  InputInfo info("None", 0, inputid, 0, 0, 0);
1767  GetInputInfo(info);
1768  return info.m_name;
1769 }
1770 
1771 // Get start channel for a capture card
1772 //
1773 // The start channel is:
1774 // - the last channel used for Live TV as found in field startchan
1775 // - if that is not filled in, the first visible channel from
1776 // the video source of the capture card
1777 //
1778 // The start channel is maintained per capture card instance so
1779 // different capture cards connected to the same video source
1780 // and different multirec instances of the same capture card
1781 // can have a different starting channel value.
1782 //
1784 {
1785  QString startchan;
1786 
1787  MSqlQuery query(MSqlQuery::InitCon());
1788  query.prepare("SELECT startchan "
1789  "FROM capturecard "
1790  "WHERE cardid = :INPUTID");
1791  query.bindValue(":INPUTID", inputid);
1792 
1793  if (!query.exec() || !query.isActive())
1794  {
1795  MythDB::DBError("CardUtil::GetStartChannel#1", query);
1796  }
1797  else if (query.next())
1798  {
1799  startchan = query.value(0).toString();
1800  }
1801 
1802  // Check if starting channel is valid; skip invisible channels.
1803  if (!startchan.isEmpty())
1804  {
1805  query.prepare("SELECT channel.chanid "
1806  "FROM capturecard, channel "
1807  "WHERE capturecard.cardid = :INPUTID AND "
1808  " capturecard.sourceid = channel.sourceid AND "
1809  " channel.deleted IS NULL AND "
1810  " channel.visible > 0 AND "
1811  " channel.channum = :CHANNUM");
1812  query.bindValue(":INPUTID", inputid);
1813  query.bindValue(":CHANNUM", startchan);
1814 
1815  if (!query.exec() || !query.isActive())
1816  {
1817  MythDB::DBError("CardUtil::GetStartChannel#2", query);
1818  }
1819  else if (!query.next())
1820  {
1821  LOG(VB_GENERAL, LOG_WARNING,
1822  QString("CardUtil[%1]: ").arg(inputid) +
1823  QString("Channel %1 on inputid %2 is invalid").arg(startchan).arg(inputid));
1824  startchan.clear();
1825  }
1826  }
1827 
1828  // If we do not have a start channel yet then use the first one available.
1829  // Any visible channel will do so there is no "order by" done.
1830  if (startchan.isEmpty())
1831  {
1832  query.prepare("SELECT channel.channum "
1833  "FROM capturecard, channel "
1834  "WHERE capturecard.cardid = :INPUTID AND "
1835  " capturecard.sourceid = channel.sourceid AND "
1836  " channel.deleted IS NULL AND "
1837  " channel.visible > 0 "
1838  "LIMIT 1");
1839  query.bindValue(":INPUTID", inputid);
1840 
1841  if (!query.exec() || !query.isActive())
1842  {
1843  MythDB::DBError("CardUtil::GetStartChannel#3", query);
1844  }
1845  else if (query.next())
1846  {
1847  startchan = query.value(0).toString();
1848  }
1849  }
1850 
1851  if (startchan.isEmpty())
1852  {
1853  LOG(VB_GENERAL, LOG_WARNING,
1854  QString("CardUtil[%1]: ").arg(inputid) +
1855  QString("No start channel found on inputid %1").arg(inputid));
1856  }
1857  else
1858  {
1859  LOG(VB_GENERAL, LOG_DEBUG,
1860  QString("CardUtil[%1]: ").arg(inputid) +
1861  QString("Start channel %1 on inputid %2").arg(startchan).arg(inputid));
1862  }
1863 
1864  return startchan;
1865 }
1866 
1868 {
1869  if (!inputid)
1870  return {};
1871 
1872  MSqlQuery query(MSqlQuery::InitCon());
1873  query.prepare("SELECT displayname "
1874  "FROM capturecard "
1875  "WHERE cardid = :INPUTID");
1876  query.bindValue(":INPUTID", inputid);
1877 
1878  if (!query.exec())
1879  MythDB::DBError("CardUtil::GetDisplayName(uint)", query);
1880  else if (query.next())
1881  {
1882  QString result = query.value(0).toString();
1883  return result;
1884  }
1885 
1886  return {};
1887 }
1888 
1889 bool CardUtil::IsUniqueDisplayName(const QString &name, uint exclude_inputid)
1890 {
1891  if (name.isEmpty())
1892  return false;
1893 
1894  qsizetype idx { 0 };
1895  QString matching;
1896  bool two { false };
1897  if ((idx = name.indexOf('/')) >= 0)
1898  {
1899  matching = name.right(name.size() - idx -1);
1900  two = false;
1901  }
1902  else
1903  {
1904  matching = name.right(2);
1905  two = true;
1906  }
1907 
1908  MSqlQuery query(MSqlQuery::InitCon());
1909  query.prepare("SELECT cardid, displayname "
1910  "FROM capturecard "
1911  "WHERE parentid = 0 "
1912  " AND cardid <> :INPUTID ");
1913  query.bindValue(":INPUTID", exclude_inputid);
1914 
1915  if (!query.exec())
1916  {
1917  MythDB::DBError("CardUtil::IsUniqueDisplayName()", query);
1918  return false;
1919  }
1920 
1921  while (query.next())
1922  {
1923  QString dn = query.value(1).toString();
1924  if (!two && (idx = dn.indexOf('/')) >= 0)
1925  {
1926  if (dn.right(dn.size() - idx - 1) == matching)
1927  return false;
1928  }
1929  else if (dn.right(2) == matching.right(2))
1930  return false;
1931  }
1932 
1933  return true;
1934 }
1935 
1937 {
1938  MSqlQuery query(MSqlQuery::InitCon());
1939  query.prepare(
1940  "SELECT sourceid "
1941  "FROM capturecard "
1942  "WHERE cardid = :INPUTID");
1943  query.bindValue(":INPUTID", inputid);
1944  if (!query.exec() || !query.isActive())
1945  MythDB::DBError("CardUtil::GetSourceID()", query);
1946  else if (query.next())
1947  return query.value(0).toUInt();
1948 
1949  return 0;
1950 }
1951 
1952 // Is this intentionally leaving out the hostname when updating the
1953 // capturecard table? The hostname value does get set when inserting
1954 // into the capturecard table. (Code written in 2011.)
1956  const uint sourceid,
1957  const QString &inputname,
1958  const QString &externalcommand,
1959  const QString &changer_device,
1960  const QString &changer_model,
1961  const QString &/*hostname*/,
1962  const QString &tunechan,
1963  const QString &startchan,
1964  const QString &displayname,
1965  bool dishnet_eit,
1966  const uint recpriority,
1967  const uint quicktune,
1968  const uint schedorder,
1969  const uint livetvorder)
1970 {
1971  MSqlQuery query(MSqlQuery::InitCon());
1972 
1973  query.prepare(
1974  "UPDATE capturecard "
1975  "SET sourceid = :SOURCEID, "
1976  " inputname = :INPUTNAME, "
1977  " externalcommand = :EXTERNALCOMMAND, "
1978  " changer_device = :CHANGERDEVICE, "
1979  " changer_model = :CHANGERMODEL, "
1980  " tunechan = :TUNECHAN, "
1981  " startchan = :STARTCHAN, "
1982  " displayname = :DISPLAYNAME, "
1983  " dishnet_eit = :DISHNETEIT, "
1984  " recpriority = :RECPRIORITY, "
1985  " quicktune = :QUICKTUNE, "
1986  " schedorder = :SCHEDORDER, "
1987  " livetvorder = :LIVETVORDER "
1988  "WHERE cardid = :INPUTID AND "
1989  " inputname = 'None'");
1990 
1991  query.bindValue(":INPUTID", inputid);
1992  query.bindValue(":SOURCEID", sourceid);
1993  query.bindValue(":INPUTNAME", inputname);
1994  query.bindValue(":EXTERNALCOMMAND", externalcommand);
1995  query.bindValue(":CHANGERDEVICE", changer_device);
1996  query.bindValue(":CHANGERMODEL", changer_model);
1997  query.bindValue(":TUNECHAN", tunechan);
1998  query.bindValue(":STARTCHAN", startchan);
1999  query.bindValueNoNull(":DISPLAYNAME", displayname);
2000  query.bindValue(":DISHNETEIT", dishnet_eit);
2001  query.bindValue(":RECPRIORITY", recpriority);
2002  query.bindValue(":QUICKTUNE", quicktune);
2003  query.bindValue(":SCHEDORDER", schedorder);
2004  query.bindValue(":LIVETVORDER", livetvorder);
2005 
2006  if (!query.exec())
2007  {
2008  MythDB::DBError("CardUtil::CreateCardInput()", query);
2009  return -1;
2010  }
2011 
2012  return inputid;
2013 }
2014 
2015 uint CardUtil::CreateInputGroup(const QString &name)
2016 {
2017  MSqlQuery query(MSqlQuery::InitCon());
2018 
2019  query.prepare("SELECT inputgroupid FROM inputgroup "
2020  "WHERE inputgroupname = :GROUPNAME "
2021  "LIMIT 1");
2022  query.bindValue(":GROUPNAME", name);
2023  if (!query.exec())
2024  {
2025  MythDB::DBError("CardUtil::CreateNewInputGroup 0", query);
2026  return 0;
2027  }
2028 
2029  if (query.next())
2030  return query.value(0).toUInt();
2031 
2032  query.prepare("SELECT MAX(inputgroupid) FROM inputgroup");
2033  if (!query.exec())
2034  {
2035  MythDB::DBError("CardUtil::CreateNewInputGroup 1", query);
2036  return 0;
2037  }
2038 
2039  uint inputgroupid = (query.next()) ? query.value(0).toUInt() + 1 : 1;
2040 
2041  query.prepare(
2042  "INSERT INTO inputgroup "
2043  " (cardinputid, inputgroupid, inputgroupname) "
2044  "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2045  query.bindValue(":INPUTID", 0);
2046  query.bindValue(":GROUPID", inputgroupid);
2047  query.bindValue(":GROUPNAME", name);
2048  if (!query.exec())
2049  {
2050  MythDB::DBError("CardUtil::CreateNewInputGroup 2", query);
2051  return 0;
2052  }
2053 
2054  return inputgroupid;
2055 }
2056 
2058  const QString &type,
2059  const QString &host,
2060  const QString &device)
2061 {
2062  QString name = host + '|' + device;
2063  if (type == "FREEBOX" || type == "IMPORT" ||
2064  type == "DEMO" || type == "EXTERNAL" ||
2065  type == "HDHOMERUN" )
2066  name += QString("|%1").arg(inputid);
2067  return CreateInputGroup(name);
2068 }
2069 
2071 {
2072  MSqlQuery query(MSqlQuery::InitCon());
2073  query.prepare(
2074  "SELECT inputgroupid "
2075  "FROM inputgroup "
2076  "WHERE cardinputid = :INPUTID "
2077  " AND inputgroupname REGEXP '^[a-z_-]*\\\\|'");
2078  query.bindValue(":INPUTID", inputid);
2079 
2080  if (!query.exec())
2081  {
2082  MythDB::DBError("CardUtil::GetDeviceInputGroup()", query);
2083  return 0;
2084  }
2085 
2086  if (query.next())
2087  {
2088  return query.value(0).toUInt();
2089  }
2090 
2091  return 0;
2092 }
2093 
2094 bool CardUtil::LinkInputGroup(uint inputid, uint inputgroupid)
2095 {
2096  MSqlQuery query(MSqlQuery::InitCon());
2097 
2098  query.prepare(
2099  "SELECT cardinputid, inputgroupid, inputgroupname "
2100  "FROM inputgroup "
2101  "WHERE inputgroupid = :GROUPID "
2102  "ORDER BY inputgroupid, cardinputid, inputgroupname");
2103  query.bindValue(":GROUPID", inputgroupid);
2104 
2105  if (!query.exec())
2106  {
2107  MythDB::DBError("CardUtil::LinkInputGroup() 1", query);
2108  return false;
2109  }
2110 
2111  QString name;
2112  while (query.next()) {
2113  name = query.value(2).toString();
2114  uint cardid = query.value(0).toUInt();
2115  // Already linked
2116  if (cardid == inputid)
2117  return true;
2118  }
2119 
2120  // Invalid group id
2121  if (name.isEmpty())
2122  return false;
2123 
2124  query.prepare(
2125  "INSERT INTO inputgroup "
2126  " (cardinputid, inputgroupid, inputgroupname) "
2127  "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
2128 
2129  query.bindValue(":INPUTID", inputid);
2130  query.bindValue(":GROUPID", inputgroupid);
2131  query.bindValue(":GROUPNAME", name);
2132 
2133  if (!query.exec())
2134  {
2135  MythDB::DBError("CardUtil::LinkInputGroup() 2", query);
2136  return false;
2137  }
2138 
2139  // Now that there is a proper linkage, unlink temporary cardid 0
2140  UnlinkInputGroup(0, inputgroupid);
2141 
2142  return true;
2143 }
2144 
2145 bool CardUtil::UnlinkInputGroup(uint inputid, uint inputgroupid)
2146 {
2147  MSqlQuery query(MSqlQuery::InitCon());
2148 
2149  if (!inputid && !inputgroupid)
2150  {
2151  query.prepare(
2152  "DELETE FROM inputgroup "
2153  "WHERE cardinputid NOT IN "
2154  "( SELECT cardid FROM capturecard )");
2155  }
2156  else
2157  {
2158  query.prepare(
2159  "DELETE FROM inputgroup "
2160  "WHERE cardinputid = :INPUTID AND "
2161  " inputgroupid = :GROUPID ");
2162 
2163  query.bindValue(":INPUTID", inputid);
2164  query.bindValue(":GROUPID", inputgroupid);
2165  }
2166 
2167  if (!query.exec())
2168  {
2169  MythDB::DBError("CardUtil::DeleteInputGroup()", query);
2170  return false;
2171  }
2172 
2173  return true;
2174 }
2175 
2176 std::vector<uint> CardUtil::GetInputGroups(uint inputid)
2177 {
2178  std::vector<uint> list;
2179 
2180  MSqlQuery query(MSqlQuery::InitCon());
2181 
2182  query.prepare(
2183  "SELECT inputgroupid "
2184  "FROM inputgroup "
2185  "WHERE cardinputid = :INPUTID "
2186  "ORDER BY inputgroupid, cardinputid, inputgroupname");
2187 
2188  query.bindValue(":INPUTID", inputid);
2189 
2190  if (!query.exec())
2191  {
2192  MythDB::DBError("CardUtil::GetInputGroups()", query);
2193  return list;
2194  }
2195 
2196  while (query.next())
2197  list.push_back(query.value(0).toUInt());
2198 
2199  return list;
2200 }
2201 
2202 std::vector<uint> CardUtil::GetGroupInputIDs(uint inputgroupid)
2203 {
2204  std::vector<uint> list;
2205 
2206  MSqlQuery query(MSqlQuery::InitCon());
2207 
2208  query.prepare(
2209  "SELECT DISTINCT cardid "
2210  "FROM capturecard, inputgroup "
2211  "WHERE inputgroupid = :GROUPID AND "
2212  " capturecard.cardid = inputgroup.cardinputid "
2213  "ORDER BY cardid");
2214 
2215  query.bindValue(":GROUPID", inputgroupid);
2216 
2217  if (!query.exec())
2218  {
2219  MythDB::DBError("CardUtil::GetGroupInputIDs()", query);
2220  return list;
2221  }
2222 
2223  while (query.next())
2224  list.push_back(query.value(0).toUInt());
2225 
2226  return list;
2227 }
2228 
2229 std::vector<uint> CardUtil::GetConflictingInputs(uint inputid)
2230 {
2231  std::vector<uint> inputids;
2232 
2233  MSqlQuery query(MSqlQuery::InitCon());
2234 
2235  query.prepare(
2236  "SELECT DISTINCT c.cardid "
2237  "FROM ( "
2238  " SELECT inputgroupid "
2239  " FROM inputgroup "
2240  " WHERE cardinputid = :INPUTID1 "
2241  ") g "
2242  "JOIN inputgroup ig ON ig.inputgroupid = g.inputgroupid "
2243  "JOIN capturecard c ON c.cardid = ig.cardinputid "
2244  " AND c.cardid <> :INPUTID2 "
2245  "ORDER BY c.cardid");
2246 
2247  query.bindValue(":INPUTID1", inputid);
2248  query.bindValue(":INPUTID2", inputid);
2249 
2250  if (!query.exec())
2251  {
2252  MythDB::DBError("CardUtil::GetConflictingInputs()", query);
2253  return inputids;
2254  }
2255 
2256  while (query.next())
2257  {
2258  inputids.push_back(query.value(0).toUInt());
2259  }
2260 
2261  if (VERBOSE_LEVEL_CHECK(VB_RECORD, LOG_INFO))
2262  {
2263  QString msg = QString("CardUtil[%1]: GetConflictingInputs(%1) ").arg(inputid);
2264  QStringList ids;
2265  for (auto id : inputids)
2266  {
2267  ids.append(QString::number(id));
2268  }
2269  msg.append(ids.join(','));
2270  LOG(VB_RECORD, LOG_INFO, msg);
2271  }
2272  return inputids;
2273 }
2274 
2276  std::chrono::milliseconds &signal_timeout,
2277  std::chrono::milliseconds &channel_timeout)
2278 {
2279  MSqlQuery query(MSqlQuery::InitCon());
2280  query.prepare(
2281  "SELECT signal_timeout, channel_timeout "
2282  "FROM capturecard "
2283  "WHERE cardid = :INPUTID");
2284  query.bindValue(":INPUTID", inputid);
2285 
2286  if (!query.exec() || !query.isActive())
2287  MythDB::DBError("CardUtil::GetTimeouts()", query);
2288  else if (query.next())
2289  {
2290  signal_timeout = std::max(std::chrono::milliseconds(query.value(0).toInt()), 250ms);
2291  channel_timeout = std::max(std::chrono::milliseconds(query.value(1).toInt()), 500ms);
2292  return true;
2293  }
2294 
2295  return false;
2296 }
2297 
2299 {
2300  DiSEqCDevTree *diseqc_tree = DiSEqCDev::FindTree(inputid);
2301 
2302  bool needsConf = false;
2303  if (diseqc_tree)
2304  needsConf = diseqc_tree->IsInNeedOfConf();
2305 
2306  return needsConf;
2307 }
2308 
2309 uint CardUtil::GetQuickTuning(uint inputid, const QString &input_name)
2310 {
2311  uint quicktune = 0;
2312 
2313  MSqlQuery query(MSqlQuery::InitCon());
2314  query.prepare(
2315  "SELECT quicktune "
2316  "FROM capturecard "
2317  "WHERE cardid = :INPUTID AND "
2318  " inputname = :INPUTNAME");
2319  query.bindValue(":INPUTID", inputid);
2320  query.bindValue(":INPUTNAME", input_name);
2321 
2322  if (!query.exec() || !query.isActive())
2323  MythDB::DBError("CardUtil::GetQuickTuning()", query);
2324  else if (query.next())
2325  quicktune = query.value(0).toUInt();
2326 
2327  return quicktune;
2328 }
2329 
2330 bool CardUtil::hasV4L2([[maybe_unused]] int videofd)
2331 {
2332 #ifdef USING_V4L2
2333  struct v4l2_capability vcap {};
2334 
2335  return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
2336  ((vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE) != 0U));
2337 #else // if !USING_V4L2
2338  return false;
2339 #endif // !USING_V4L2
2340 }
2341 
2343  int videofd, QString &input, QString &driver, uint32_t &version,
2344  uint32_t &capabilities)
2345 {
2346  input.clear();
2347  driver.clear();
2348  version = 0;
2349  capabilities = 0;
2350 
2351  if (videofd < 0)
2352  return false;
2353 
2354 #ifdef USING_V4L2
2355  struct v4l2_capability capability {};
2356  if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
2357  {
2358  input = QString::fromLatin1((const char*)capability.card);
2359  driver = QString::fromLatin1((const char*)capability.driver);
2360  version = capability.version;
2361  capabilities = capability.capabilities;
2362  }
2363 #endif // USING_V4L2
2364 
2365  static const QRegularExpression kBracketedDigitRE { R"(\[[0-9]\]$)" };
2366  if (!driver.isEmpty())
2367  driver.remove( kBracketedDigitRE );
2368 
2369  return !input.isEmpty();
2370 }
2371 
2372 InputNames CardUtil::ProbeV4LVideoInputs([[maybe_unused]] int videofd, bool &ok)
2373 {
2374  InputNames list;
2375  ok = false;
2376 
2377 #ifdef USING_V4L2
2378  bool usingv4l2 = hasV4L2(videofd);
2379 
2380  struct v4l2_input vin {};
2381  while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
2382  {
2383  QString input((char *)vin.name);
2384  list[vin.index] = input;
2385  vin.index++;
2386  }
2387  if (vin.index)
2388  {
2389  ok = true;
2390  return list;
2391  }
2392 
2393  // Create an input when none are advertised
2394  if (list.isEmpty())
2395  list[0] = "Television";
2396 
2397  ok = true;
2398 #else // if !USING_V4L2
2399  list[-1] += QObject::tr("ERROR, Compile with V4L support to query inputs");
2400 #endif // !USING_V4L2
2401  return list;
2402 }
2403 
2404 InputNames CardUtil::ProbeV4LAudioInputs([[maybe_unused]] int videofd, bool &ok)
2405 {
2406  InputNames list;
2407  ok = false;
2408 
2409 #ifdef USING_V4L2
2410  bool usingv4l2 = hasV4L2(videofd);
2411 
2412  // V4L v2 query
2413  struct v4l2_audio ain {};
2414  while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMAUDIO, &ain) >= 0))
2415  {
2416  QString input((char *)ain.name);
2417  list[ain.index] = input;
2418  ain.index++;
2419  }
2420  if (ain.index)
2421  {
2422  ok = true;
2423  return list;
2424  }
2425 
2426  ok = true;
2427 #else // if !USING_V4L2
2428  list[-1] += QObject::tr(
2429  "ERROR, Compile with V4L support to query audio inputs");
2430 #endif // !USING_V4L2
2431  return list;
2432 }
2433 
2435 {
2436  InputNames list;
2437  MSqlQuery query(MSqlQuery::InitCon());
2438  query.prepare(
2439  "SELECT cardid, inputname "
2440  "FROM capturecard "
2441  "WHERE hostname = :HOSTNAME "
2442  " AND videodevice = :DEVICE "
2443  " AND parentid = 0 "
2444  " AND inputname <> 'None'");
2445  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
2446  query.bindValue(":DEVICE", device);
2447 
2448  if (!query.exec() || !query.isActive())
2449  MythDB::DBError("CardUtil::GetConfiguredDVBInputs", query);
2450  else
2451  {
2452  while (query.next())
2453  list[query.value(0).toUInt()] = query.value(1).toString();
2454  }
2455  return list;
2456 }
2457 
2458 // Convert DVBv5 frontend capabilities from bitmask to string
2459 //
2460 // Source linuxtv.org v4l-utils/lib/libdvbv5/dvb-v5.c
2461 //
2462 QStringList CardUtil::CapabilitiesToString([[maybe_unused]] uint64_t capabilities)
2463 {
2464  QStringList caps;
2465 #ifdef USING_DVB
2466 
2467  struct fe_caps_name {
2468  unsigned idx;
2469  const char *name;
2470  };
2471 
2472  std::array<fe_caps_name,31> fe_caps_name {{
2473  { FE_CAN_2G_MODULATION, "CAN_2G_MODULATION" },
2474  { FE_CAN_8VSB, "CAN_8VSB" },
2475  { FE_CAN_16VSB, "CAN_16VSB" },
2476  { FE_CAN_BANDWIDTH_AUTO, "CAN_BANDWIDTH_AUTO" },
2477  { FE_CAN_FEC_1_2, "CAN_FEC_1_2" },
2478  { FE_CAN_FEC_2_3, "CAN_FEC_2_3" },
2479  { FE_CAN_FEC_3_4, "CAN_FEC_3_4" },
2480  { FE_CAN_FEC_4_5, "CAN_FEC_4_5" },
2481  { FE_CAN_FEC_5_6, "CAN_FEC_5_6" },
2482  { FE_CAN_FEC_6_7, "CAN_FEC_6_7" },
2483  { FE_CAN_FEC_7_8, "CAN_FEC_7_8" },
2484  { FE_CAN_FEC_8_9, "CAN_FEC_8_9" },
2485  { FE_CAN_FEC_AUTO, "CAN_FEC_AUTO" },
2486  { FE_CAN_GUARD_INTERVAL_AUTO, "CAN_GUARD_INTERVAL_AUTO" },
2487  { FE_CAN_HIERARCHY_AUTO, "CAN_HIERARCHY_AUTO" },
2488  { FE_CAN_INVERSION_AUTO, "CAN_INVERSION_AUTO" },
2489  { FE_CAN_MULTISTREAM, "CAN_MULTISTREAM" },
2490  { FE_CAN_MUTE_TS, "CAN_MUTE_TS" },
2491  { FE_CAN_QAM_16, "CAN_QAM_16" },
2492  { FE_CAN_QAM_32, "CAN_QAM_32" },
2493  { FE_CAN_QAM_64, "CAN_QAM_64" },
2494  { FE_CAN_QAM_128, "CAN_QAM_128" },
2495  { FE_CAN_QAM_256, "CAN_QAM_256" },
2496  { FE_CAN_QAM_AUTO, "CAN_QAM_AUTO" },
2497  { FE_CAN_QPSK, "CAN_QPSK" },
2498  { FE_CAN_RECOVER, "CAN_RECOVER" },
2499  { FE_CAN_TRANSMISSION_MODE_AUTO, "CAN_TRANSMISSION_MODE_AUTO" },
2500  { FE_CAN_TURBO_FEC, "CAN_TURBO_FEC" },
2501  { FE_HAS_EXTENDED_CAPS, "HAS_EXTENDED_CAPS" },
2502  { FE_IS_STUPID, "IS_STUPID" },
2503  { FE_NEEDS_BENDING, "NEEDS_BENDING" },
2504  }};
2505 
2506  for (const auto & cap : fe_caps_name)
2507  {
2508  if (capabilities & cap.idx)
2509  caps.append(cap.name);
2510  }
2511 #endif // USING_DVB
2512  return caps;
2513 }
2514 
2515 QStringList CardUtil::ProbeVideoInputs(const QString& device, const QString& inputtype)
2516 {
2517  QStringList ret;
2518 
2519  if (IsSingleInputType(inputtype))
2520  ret += "MPEG2TS";
2521  else if ("DVB" == inputtype)
2522  ret += ProbeDVBInputs(device);
2523  else
2524  ret += ProbeV4LVideoInputs(device);
2525 
2526  return ret;
2527 }
2528 
2529 QStringList CardUtil::ProbeAudioInputs(const QString& device, const QString& inputtype)
2530 {
2531  LOG(VB_GENERAL, LOG_DEBUG, QString("ProbeAudioInputs(%1,%2)")
2532  .arg(device, inputtype));
2533  QStringList ret;
2534 
2535  if ("HDPVR" == inputtype ||
2536  "V4L2" == inputtype)
2537  ret += ProbeV4LAudioInputs(device);
2538 
2539  return ret;
2540 }
2541 
2542 QStringList CardUtil::ProbeV4LVideoInputs(const QString& device)
2543 {
2544  bool ok = false;
2545  QStringList ret;
2546  QByteArray dev = device.toLatin1();
2547  int videofd = open(dev.constData(), O_RDWR);
2548  if (videofd < 0)
2549  {
2550  ret += QObject::tr("Could not open '%1' "
2551  "to probe its inputs.").arg(device);
2552  return ret;
2553  }
2554  InputNames list = CardUtil::ProbeV4LVideoInputs(videofd, ok);
2555  close(videofd);
2556 
2557  if (!ok)
2558  {
2559  ret += list[-1];
2560  return ret;
2561  }
2562 
2563  InputNames::iterator it;
2564  for (it = list.begin(); it != list.end(); ++it)
2565  {
2566  if (it.key() >= 0)
2567  ret += *it;
2568  }
2569 
2570  return ret;
2571 }
2572 
2573 QStringList CardUtil::ProbeV4LAudioInputs(const QString& device)
2574 {
2575  LOG(VB_GENERAL, LOG_DEBUG, QString("ProbeV4LAudioInputs(%1)").arg(device));
2576 
2577  bool ok = false;
2578  QStringList ret;
2579  int videofd = open(device.toLatin1().constData(), O_RDWR);
2580  if (videofd < 0)
2581  {
2582  LOG(VB_GENERAL, LOG_ERR, "ProbeAudioInputs() -> couldn't open device");
2583  ret += QObject::tr("Could not open '%1' to probe its inputs.")
2584  .arg(device);
2585  return ret;
2586  }
2587  InputNames list = CardUtil::ProbeV4LAudioInputs(videofd, ok);
2588  close(videofd);
2589 
2590  if (!ok)
2591  {
2592  ret += list[-1];
2593  return ret;
2594  }
2595 
2596  InputNames::iterator it;
2597  for (it = list.begin(); it != list.end(); ++it)
2598  {
2599  if (it.key() >= 0)
2600  ret += *it;
2601  }
2602 
2603  return ret;
2604 }
2605 
2606 QStringList CardUtil::ProbeDVBInputs([[maybe_unused]] const QString& device)
2607 {
2608  QStringList ret;
2609 
2610 #ifdef USING_DVB
2611  InputNames list = GetConfiguredDVBInputs(device);
2612  InputNames::iterator it;
2613  for (it = list.begin(); it != list.end(); ++it)
2614  {
2615  if (it.key())
2616  ret += *it;
2617  }
2618 #else
2619  ret += QObject::tr("ERROR, Compile with DVB support to query inputs");
2620 #endif
2621 
2622  return ret;
2623 }
2624 
2625 QString CardUtil::GetDeviceLabel(const QString &inputtype,
2626  const QString &videodevice)
2627 {
2628  return QString("[ %1 : %2 ]").arg(inputtype, videodevice);
2629 }
2630 
2632 {
2633  MSqlQuery query(MSqlQuery::InitCon());
2634  query.prepare("SELECT cardtype, videodevice "
2635  "FROM capturecard WHERE cardid = :INPUTID ");
2636  query.bindValue(":INPUTID", inputid);
2637 
2638  if (query.exec() && query.next())
2639  {
2640  return GetDeviceLabel(query.value(0).toString(),
2641  query.value(1).toString());
2642  }
2643 
2644  return "[ UNKNOWN ]";
2645 }
2646 
2648  const QString &device,
2649  const QString &inputtype,
2650  QStringList &inputs)
2651 {
2652  inputs.clear();
2653  if (IsSingleInputType(inputtype))
2654  inputs += "MPEG2TS";
2655  else if (inputtype == "DVB")
2656  inputs += "DVBInput";
2657  else
2658  inputs += ProbeV4LVideoInputs(device);
2659 }
2660 
2661 int CardUtil::CreateCaptureCard(const QString &videodevice,
2662  const QString &audiodevice,
2663  const QString &vbidevice,
2664  const QString &inputtype,
2665  const uint audioratelimit,
2666  const QString &hostname,
2667  const uint dvb_swfilter,
2668  const uint dvb_sat_type,
2669  bool dvb_wait_for_seqstart,
2670  bool skipbtaudio,
2671  bool dvb_on_demand,
2672  const uint dvb_diseqc_type,
2673  const uint firewire_speed,
2674  const QString &firewire_model,
2675  const uint firewire_connection,
2676  const std::chrono::milliseconds signal_timeout,
2677  const std::chrono::milliseconds channel_timeout,
2678  const uint dvb_tuning_delay,
2679  const uint contrast,
2680  const uint brightness,
2681  const uint colour,
2682  const uint hue,
2683  const uint diseqcid,
2684  bool dvb_eitscan)
2685 {
2686  MSqlQuery query(MSqlQuery::InitCon());
2687 
2688  query.prepare(
2689  "INSERT INTO capturecard "
2690  "(videodevice, audiodevice, vbidevice, cardtype, "
2691  "audioratelimit, hostname, dvb_swfilter, dvb_sat_type, "
2692  "dvb_wait_for_seqstart, skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
2693  "firewire_speed, firewire_model, firewire_connection, signal_timeout, "
2694  "channel_timeout, dvb_tuning_delay, contrast, brightness, colour, "
2695  "hue, diseqcid, dvb_eitscan) "
2696  "VALUES (:VIDEODEVICE, :AUDIODEVICE, :VBIDEVICE, :INPUTTYPE, "
2697  ":AUDIORATELIMIT, :HOSTNAME, :DVBSWFILTER, :DVBSATTYPE, "
2698  ":DVBWAITFORSEQSTART, :SKIPBTAUDIO, :DVBONDEMAND, :DVBDISEQCTYPE, "
2699  ":FIREWIRESPEED, :FIREWIREMODEL, :FIREWIRECONNECTION, :SIGNALTIMEOUT, "
2700  ":CHANNELTIMEOUT, :DVBTUNINGDELAY, :CONTRAST, :BRIGHTNESS, :COLOUR, "
2701  ":HUE, :DISEQCID, :DVBEITSCAN ) ");
2702 
2703  query.bindValue(":VIDEODEVICE", videodevice);
2704  if (audiodevice.length() == 0) // Empty string is set to null
2705  {
2706 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2707  query.bindValue(":AUDIODEVICE", QVariant(QVariant::String));
2708 #else
2709  query.bindValue(":AUDIODEVICE", QVariant(QMetaType(QMetaType::QString)));
2710 #endif
2711  }
2712  else
2713  query.bindValue(":AUDIODEVICE", audiodevice);
2714  if (vbidevice.length() == 0) // Empty string is set to null
2715  {
2716 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2717  query.bindValue(":VBIDEVICE", QVariant(QVariant::String));
2718 #else
2719  query.bindValue(":VBIDEVICE", QVariant(QMetaType(QMetaType::QString)));
2720 #endif
2721  }
2722  else
2723  query.bindValue(":VBIDEVICE", vbidevice);
2724  query.bindValue(":INPUTTYPE", inputtype);
2725  if (audioratelimit == 0) // Value 0 is set to null
2726  {
2727 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2728  query.bindValue(":AUDIORATELIMIT", QVariant(QVariant::UInt));
2729 #else
2730  query.bindValue(":AUDIORATELIMIT", QVariant(QMetaType(QMetaType::UInt)));
2731 #endif
2732  }
2733  else
2734  query.bindValue(":AUDIORATELIMIT", audioratelimit);
2735  query.bindValue(":HOSTNAME", hostname);
2736  query.bindValue(":DVBSWFILTER", dvb_swfilter);
2737  query.bindValue(":DVBSATTYPE", dvb_sat_type);
2738  query.bindValue(":DVBWAITFORSEQSTART", dvb_wait_for_seqstart);
2739  query.bindValue(":SKIPBTAUDIO", skipbtaudio);
2740  query.bindValue(":DVBONDEMAND", dvb_on_demand);
2741  query.bindValue(":DVBDISEQCTYPE", dvb_diseqc_type);
2742  query.bindValue(":FIREWIRESPEED", firewire_speed);
2743  if (firewire_model.length() == 0) // Empty string is set to null
2744  {
2745 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2746  query.bindValue(":FIREWIREMODEL", QVariant(QVariant::String));
2747 #else
2748  query.bindValue(":FIREWIREMODEL", QVariant(QMetaType(QMetaType::QString)));
2749 #endif
2750  }
2751  else
2752  query.bindValue(":FIREWIREMODEL", firewire_model);
2753  query.bindValue(":FIREWIRECONNECTION", firewire_connection);
2754  query.bindValue(":SIGNALTIMEOUT", static_cast<qint64>(signal_timeout.count()));
2755  query.bindValue(":CHANNELTIMEOUT", static_cast<qint64>(channel_timeout.count()));
2756  query.bindValue(":DVBTUNINGDELAY", dvb_tuning_delay);
2757  query.bindValue(":CONTRAST", contrast);
2758  query.bindValue(":BRIGHTNESS", brightness);
2759  query.bindValue(":COLOUR", colour);
2760  query.bindValue(":HUE", hue);
2761  if (diseqcid == 0) // Value 0 is set to null
2762  {
2763 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
2764  query.bindValue(":DISEQCID", QVariant(QVariant::UInt));
2765 #else
2766  query.bindValue(":DISEQCID", QVariant(QMetaType(QMetaType::UInt)));
2767 #endif
2768  }
2769  else
2770  query.bindValue(":DISEQCID", diseqcid);
2771  query.bindValue(":DVBEITSCAN", dvb_eitscan);
2772 
2773  if (!query.exec())
2774  {
2775  MythDB::DBError("CreateCaptureCard", query);
2776  return -1;
2777  }
2778 
2779  query.prepare("SELECT MAX(cardid) FROM capturecard");
2780 
2781  if (!query.exec())
2782  {
2783  MythDB::DBError("CreateCaptureCard maxinput", query);
2784  return -1;
2785  }
2786 
2787  int inputid = -1; /* must be int not uint because of return type. */
2788 
2789  if (query.next())
2790  {
2791  inputid = query.value(0).toInt();
2792  uint groupid = CardUtil::CreateDeviceInputGroup(inputid, inputtype,
2793  hostname, videodevice);
2794  CardUtil::LinkInputGroup(inputid, groupid);
2795  }
2796 
2797  return inputid;
2798 }
2799 
2801 {
2802  std::vector<uint> childids = GetChildInputIDs(inputid);
2803  for (uint childid : childids)
2804  {
2805  if (!DeleteInput(childid))
2806  {
2807  LOG(VB_GENERAL, LOG_ERR, LOC +
2808  QString("CardUtil: Failed to delete child input %1")
2809  .arg(childid));
2810  return false;
2811  }
2812  }
2813 
2814  MSqlQuery query(MSqlQuery::InitCon());
2815 
2816  DiSEqCDevTree tree;
2817  tree.Load(inputid);
2818 
2819  // Delete the capturecard row for this input
2820  query.prepare("DELETE FROM capturecard WHERE cardid = :INPUTID");
2821  query.bindValue(":INPUTID", inputid);
2822  if (!query.exec())
2823  {
2824  MythDB::DBError("DeleteCard -- delete capturecard", query);
2825  return false;
2826  }
2827 
2828  // Update the reclimit of the parent input
2829  query.prepare("UPDATE capturecard SET reclimit=reclimit-1 "
2830  "WHERE cardid = :INPUTID");
2831  query.bindValue(":INPUTID", inputid);
2832  if (!query.exec())
2833  {
2834  MythDB::DBError("DeleteCard -- update capturecard", query);
2835  return false;
2836  }
2837 
2838  // Delete the inputgroup rows for this input
2839  query.prepare("DELETE FROM inputgroup WHERE cardinputid = :INPUTID");
2840  query.bindValue(":INPUTID", inputid);
2841  if (!query.exec())
2842  {
2843  MythDB::DBError("DeleteCard -- delete inputgroup", query);
2844  return false;
2845  }
2846 
2847  // Delete the diseqc tree if no more inputs reference it.
2848  if (tree.Root())
2849  {
2850  query.prepare("SELECT cardid FROM capturecard "
2851  "WHERE diseqcid = :DISEQCID LIMIT 1");
2852  query.bindValue(":DISEQCID", tree.Root()->GetDeviceID());
2853  if (!query.exec())
2854  {
2855  MythDB::DBError("DeleteCard -- find diseqc tree", query);
2856  }
2857  else if (!query.next())
2858  {
2859  tree.SetRoot(nullptr);
2860  tree.Store(inputid);
2861  }
2862  }
2863 
2864  // Delete any unused input groups
2865  UnlinkInputGroup(0, 0);
2866 
2867  return true;
2868 }
2869 
2871 {
2872  MSqlQuery query(MSqlQuery::InitCon());
2873  return (query.exec("TRUNCATE TABLE inputgroup") &&
2874  query.exec("TRUNCATE TABLE diseqc_config") &&
2875  query.exec("TRUNCATE TABLE diseqc_tree") &&
2876  query.exec("TRUNCATE TABLE capturecard") &&
2877  query.exec("TRUNCATE TABLE iptv_channel"));
2878 }
2879 
2880 std::vector<uint> CardUtil::GetInputList(void)
2881 {
2882  std::vector<uint> list;
2883 
2884  MSqlQuery query(MSqlQuery::InitCon());
2885  query.prepare(
2886  "SELECT cardid "
2887  "FROM capturecard "
2888  "ORDER BY cardid");
2889 
2890  if (!query.exec())
2891  MythDB::DBError("CardUtil::GetInputList()", query);
2892  else
2893  {
2894  while (query.next())
2895  list.push_back(query.value(0).toUInt());
2896  }
2897 
2898  return list;
2899 }
2900 
2901 std::vector<uint> CardUtil::GetSchedInputList(void)
2902 {
2903  std::vector<uint> list;
2904 
2905  MSqlQuery query(MSqlQuery::InitCon());
2906  query.prepare(
2907  "SELECT DISTINCT cardid "
2908  "FROM capturecard "
2909  "WHERE schedorder <> 0 "
2910  "ORDER BY schedorder, cardid");
2911 
2912  if (!query.exec())
2913  MythDB::DBError("CardUtil::GetSchedInputList()", query);
2914  else
2915  {
2916  while (query.next())
2917  list.push_back(query.value(0).toUInt());
2918  }
2919 
2920  return list;
2921 }
2922 
2923 std::vector<uint> CardUtil::GetLiveTVInputList(void)
2924 {
2925  std::vector<uint> list;
2926 
2927  MSqlQuery query(MSqlQuery::InitCon());
2928  query.prepare(
2929  "SELECT DISTINCT cardid "
2930  "FROM capturecard "
2931  "WHERE livetvorder <> 0 "
2932  "ORDER BY livetvorder, cardid");
2933 
2934  if (!query.exec())
2935  MythDB::DBError("CardUtil::GetLiveTVInputList()", query);
2936  else
2937  {
2938  while (query.next())
2939  list.push_back(query.value(0).toUInt());
2940  }
2941 
2942  return list;
2943 }
2944 
2945 QString CardUtil::GetDeviceName(dvb_dev_type_t type, const QString &device)
2946 {
2947  QString devname = QString(device);
2948 #if 0
2949  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("DVB Device (%1)").arg(devname));
2950 #endif
2951 
2952  if (DVB_DEV_FRONTEND == type)
2953  {
2954  return devname;
2955  }
2956 
2957  if (DVB_DEV_DVR == type)
2958  {
2959  QString tmp = devname;
2960  tmp = tmp.replace(tmp.indexOf("frontend"), 8, "dvr");
2961  if (QFile::exists(tmp))
2962  {
2963  LOG(VB_RECORD, LOG_DEBUG, LOC +
2964  QString("Adapter Frontend dvr number matches (%1)").arg(tmp));
2965  return tmp;
2966  }
2967 
2968  // Use dvr0, allows multi-standard frontends which only have one dvr
2969  tmp = devname;
2970  tmp = tmp.replace(tmp.indexOf("frontend"), 9, "dvr0");
2971  if (QFile::exists(tmp))
2972  {
2973  LOG(VB_RECORD, LOG_DEBUG, LOC +
2974  QString("Adapter Frontend dvr number not matching, using dvr0 instead (%1)").arg(tmp));
2975  return tmp;
2976  }
2977 
2978  LOG(VB_RECORD, LOG_DEBUG, LOC +
2979  QString("Adapter Frontend no dvr device found for (%1)").arg(devname));
2980  return "";
2981  }
2982 
2983  if (DVB_DEV_DEMUX == type)
2984  {
2985  QString tmp = devname;
2986  tmp = tmp.replace(tmp.indexOf("frontend"), 8, "demux");
2987  if (QFile::exists(tmp))
2988  {
2989  LOG(VB_RECORD, LOG_DEBUG, LOC +
2990  QString("Adapter Frontend demux number matches (%1)").arg(tmp));
2991  return tmp;
2992  }
2993 
2994  // Use demux0, allows multi-standard frontends, which only have one demux
2995  tmp = devname;
2996  tmp = tmp.replace(tmp.indexOf("frontend"), 9, "demux0");
2997  if (QFile::exists(tmp))
2998  {
2999  LOG(VB_RECORD, LOG_DEBUG, LOC +
3000  QString("Adapter Frontend demux number not matching, using demux0 instead (%1)").arg(tmp));
3001  return tmp;
3002  }
3003 
3004  LOG(VB_RECORD, LOG_DEBUG, LOC +
3005  QString("Adapter Frontend no demux device found for (%1)").arg(devname));
3006  return "";
3007  }
3008 
3009  if (DVB_DEV_CA == type)
3010  {
3011  QString tmp = devname;
3012  tmp = tmp.replace(tmp.indexOf("frontend"), 8, "ca");
3013  if (QFile::exists(tmp))
3014  {
3015  LOG(VB_RECORD, LOG_DEBUG, LOC +
3016  QString("Adapter Frontend ca number matches (%1)").arg(tmp));
3017  return tmp;
3018  }
3019 
3020  // Use ca0, allows multi-standard frontends, which only have one ca
3021  tmp = devname;
3022  tmp = tmp.replace(tmp.indexOf("frontend"), 9, "ca0");
3023  if (QFile::exists(tmp))
3024  {
3025  LOG(VB_RECORD, LOG_DEBUG, LOC +
3026  QString("Adapter Frontend ca number not matching, using ca0 instead (%1)").arg(tmp));
3027  return tmp;
3028  }
3029 
3030  LOG(VB_RECORD, LOG_DEBUG, LOC +
3031  QString("Adapter Frontend no ca device found for (%1)").arg(devname));
3032  return "";
3033  }
3034 
3035  if (DVB_DEV_AUDIO == type)
3036  {
3037  return devname.replace(devname.indexOf("frontend"), 8, "audio");
3038  }
3039 
3040  if (DVB_DEV_VIDEO == type)
3041  {
3042  return devname.replace(devname.indexOf("frontend"), 8, "video");
3043  }
3044 
3045  return "";
3046 }
3047 
3048 
3058 bool CardUtil::HDHRdoesDVB([[maybe_unused]] const QString &device)
3059 {
3060 #ifdef USING_HDHOMERUN
3061  hdhomerun_device_t *hdhr =
3062  hdhomerun_device_create_from_str(device.toLatin1(), nullptr);
3063  if (!hdhr)
3064  return false;
3065 
3066  const char *model = hdhomerun_device_get_model_str(hdhr);
3067  if (model && strstr(model, "dvb"))
3068  {
3069  hdhomerun_device_destroy(hdhr);
3070  return true;
3071  }
3072 
3073  hdhomerun_device_destroy(hdhr);
3074 
3075 #endif
3076 
3077  return false;
3078 }
3079 
3084 bool CardUtil::HDHRdoesDVBC([[maybe_unused]] const QString &device)
3085 {
3086 #ifdef USING_HDHOMERUN
3087  hdhomerun_device_t *hdhr =
3088  hdhomerun_device_create_from_str(device.toLatin1(), nullptr);
3089  if (!hdhr)
3090  return false;
3091 
3092  const char *model = hdhomerun_device_get_model_str(hdhr);
3093  if (model && strstr(model, "dvbc"))
3094  {
3095  hdhomerun_device_destroy(hdhr);
3096  return true;
3097  }
3098 
3099  hdhomerun_device_destroy(hdhr);
3100 
3101 #endif
3102 
3103  return false;
3104 }
3105 
3110 QString CardUtil::GetHDHRdesc([[maybe_unused]] const QString &device)
3111 {
3112  QString connectErr = QObject::tr("Unable to connect to device.");
3113 
3114 #ifdef USING_HDHOMERUN
3115  [[maybe_unused]] bool deviceIsIP = false;
3116 
3117  if (device.contains('.')) // Simplistic check, but also allows DNS names
3118  deviceIsIP = true;
3119  else
3120  {
3121  bool validID = false;
3122 
3123  uint32_t dev = device.toUInt(&validID, 16);
3124  if (!validID || !hdhomerun_discover_validate_device_id(dev))
3125  return QObject::tr("Invalid Device ID");
3126  }
3127 
3128  LOG(VB_GENERAL, LOG_INFO, "CardUtil::GetHDHRdescription(" + device +
3129  ") - trying to locate device");
3130 
3131  hdhomerun_device_t *hdhr =
3132  hdhomerun_device_create_from_str(device.toLatin1(), nullptr);
3133  if (!hdhr)
3134  return QObject::tr("Invalid Device ID or address.");
3135 
3136  const char *model = hdhomerun_device_get_model_str(hdhr);
3137  if (!model)
3138  {
3139  hdhomerun_device_destroy(hdhr);
3140  return connectErr;
3141  }
3142 
3143 
3144  QString description = model;
3145  char *sVersion = nullptr;
3146  uint32_t iVersion = 0;
3147 
3148  if (hdhomerun_device_get_version(hdhr, &sVersion, &iVersion))
3149  description += QObject::tr(", firmware: %2").arg(sVersion);
3150 
3151  hdhomerun_device_destroy(hdhr);
3152 
3153  return description;
3154 #else
3155  return connectErr;
3156 #endif
3157 }
3158 
3163 QString CardUtil::GetVBoxdesc([[maybe_unused]] const QString &id,
3164  [[maybe_unused]] const QString &ip,
3165  [[maybe_unused]] const QString &tunerNo,
3166  [[maybe_unused]] const QString &tunerType)
3167 {
3168  QString connectErr = QObject::tr("Unable to connect to device.");
3169 
3170 #ifdef USING_VBOX
3171  VBox *vbox = new VBox(ip);
3172 
3173  if (!vbox->checkConnection())
3174  {
3175  delete vbox;
3176  return connectErr;
3177  }
3178 
3179  QString version;
3180 
3181  if (!vbox->checkVersion(version))
3182  {
3183  QString apiVersionErr = QObject::tr("The VBox software version is too old (%1), we require %2")
3185  delete vbox;
3186  return apiVersionErr;
3187 
3188  }
3189 
3190  delete vbox;
3191 
3192  return QString("V@Box TV Gateway - ID: %1, IP: %2, Tuner: %3-%4")
3193  .arg(id, ip, tunerNo, tunerType);
3194 
3195 #else
3196  return connectErr;
3197 #endif
3198 }
3199 
3200 #ifdef USING_ASI
3201 static QString sys_dev(uint device_num, const QString& dev)
3202 {
3203  return QString("/sys/class/asi/asirx%1/%2").arg(device_num).arg(dev);
3204 }
3205 
3206 static QString read_sys(const QString& sys_dev)
3207 {
3208  QFile f(sys_dev);
3209  f.open(QIODevice::ReadOnly);
3210  QByteArray sdba = f.readAll();
3211  f.close();
3212  return sdba;
3213 }
3214 
3215 static bool write_sys(const QString& sys_dev, const QString& str)
3216 {
3217  QFile f(sys_dev);
3218  f.open(QIODevice::WriteOnly);
3219  QByteArray ba = str.toLocal8Bit();
3220  qint64 offset = 0;
3221  for (uint tries = 0; (offset < ba.size()) && tries < 5; tries++)
3222  {
3223  qint64 written = f.write(ba.data()+offset, ba.size()-offset);
3224  if (written < 0)
3225  return false;
3226  offset += written;
3227  }
3228  return true;
3229 }
3230 #endif
3231 
3232 int CardUtil::GetASIDeviceNumber([[maybe_unused]] const QString &device, QString *error)
3233 {
3234 #ifdef USING_ASI
3235  // basic confirmation
3236  struct stat statbuf {};
3237  if (stat(device.toLocal8Bit().constData(), &statbuf) < 0)
3238  {
3239  if (error)
3240  *error = QString("Unable to stat '%1'").arg(device) + ENO;
3241  return -1;
3242  }
3243 
3244  if (!S_ISCHR(statbuf.st_mode))
3245  {
3246  if (error)
3247  *error = QString("'%1' is not a character device").arg(device);
3248  return -1;
3249  }
3250 
3251  if (!(statbuf.st_rdev & 0x0080))
3252  {
3253  if (error)
3254  *error = QString("'%1' not a DVEO ASI receiver").arg(device);
3255  return -1;
3256  }
3257 
3258  int device_num = statbuf.st_rdev & 0x007f;
3259 
3260  // extra confirmation
3261  QString sys_dev_contents = read_sys(sys_dev(device_num, "dev"));
3262  QStringList sys_dev_clist = sys_dev_contents.split(":");
3263  if (2 != sys_dev_clist.size())
3264  {
3265  if (error)
3266  {
3267  *error = QString("Unable to read '%1'")
3268  .arg(sys_dev(device_num, "dev"));
3269  }
3270  return -1;
3271  }
3272  if (sys_dev_clist[0].toUInt() != (statbuf.st_rdev>>8))
3273  {
3274  if (error)
3275  *error = QString("'%1' not a DVEO ASI device").arg(device);
3276  return -1;
3277  }
3278 
3279  return device_num;
3280 #else
3281  if (error)
3282  *error = "Not compiled with ASI support.";
3283  return -1;
3284 #endif
3285 }
3286 
3287 uint CardUtil::GetASIBufferSize([[maybe_unused]] uint device_num, QString *error)
3288 {
3289 #ifdef USING_ASI
3290  // get the buffer size
3291  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "bufsize"));
3292  bool ok = false;
3293  uint buf_size = sys_bufsize_contents.toUInt(&ok);
3294  if (!ok)
3295  {
3296  if (error)
3297  {
3298  *error = QString("Failed to read buffer size from '%1'")
3299  .arg(sys_dev(device_num, "bufsize"));
3300  }
3301  return 0;
3302  }
3303  return buf_size;
3304 #else
3305  if (error)
3306  *error = "Not compiled with ASI support.";
3307  return 0;
3308 #endif
3309 }
3310 
3311 uint CardUtil::GetASINumBuffers([[maybe_unused]] uint device_num, QString *error)
3312 {
3313 #ifdef USING_ASI
3314  // get the buffer size
3315  QString sys_numbuffers_contents = read_sys(sys_dev(device_num, "buffers"));
3316  bool ok = false;
3317  uint num_buffers = sys_numbuffers_contents.toUInt(&ok);
3318  if (!ok)
3319  {
3320  if (error)
3321  {
3322  *error = QString("Failed to read num buffers from '%1'")
3323  .arg(sys_dev(device_num, "buffers"));
3324  }
3325  return 0;
3326  }
3327  return num_buffers;
3328 #else
3329  if (error)
3330  *error = "Not compiled with ASI support.";
3331  return 0;
3332 #endif
3333 }
3334 
3335 int CardUtil::GetASIMode([[maybe_unused]] uint device_num, QString *error)
3336 {
3337 #ifdef USING_ASI
3338  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "mode"));
3339  bool ok = false;
3340  uint mode = sys_bufsize_contents.toUInt(&ok);
3341  if (!ok)
3342  {
3343  if (error)
3344  {
3345  *error = QString("Failed to read mode from '%1'")
3346  .arg(sys_dev(device_num, "mode"));
3347  }
3348  return -1;
3349  }
3350  return mode;
3351 #else
3352  if (error)
3353  *error = "Not compiled with ASI support.";
3354  return -1;
3355 #endif
3356 }
3357 
3358 bool CardUtil::SetASIMode([[maybe_unused]] uint device_num,
3359  [[maybe_unused]] uint mode,
3360  QString *error)
3361 {
3362 #ifdef USING_ASI
3363  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "mode"));
3364  bool ok = false;
3365  uint old_mode = sys_bufsize_contents.toUInt(&ok);
3366  if (ok && old_mode == mode)
3367  return true;
3368  ok = write_sys(sys_dev(device_num, "mode"), QString("%1\n").arg(mode));
3369  if (!ok && error)
3370  {
3371  *error = QString("Failed to set mode to %1 using '%2'")
3372  .arg(mode).arg(sys_dev(device_num, "mode"));
3373  }
3374  return ok;
3375 #else
3376  if (error)
3377  *error = "Not compiled with ASI support.";
3378  return false;
3379 #endif
3380 }
3381 
3382 #ifdef USING_VBOX
3383 
3387 bool CardUtil::IsVBoxPresent(uint inputid)
3388 {
3389  // should only be called if inputtype == VBOX
3390  if (!inputid )
3391  {
3392  LOG(VB_GENERAL, LOG_ERR, QString("VBOX inputid (%1) not valid, redo mythtv-setup")
3393  .arg(inputid));
3394  return false;
3395  }
3396 
3397  // get sourceid and startchan from table capturecard for inputid
3398  uint chanid = 0;
3399  chanid = ChannelUtil::GetChannelValueInt("chanid",GetSourceID(inputid),GetStartChannel(inputid));
3400  if (!chanid)
3401  {
3402  // no chanid, presume bad setup
3403  LOG(VB_GENERAL, LOG_ERR, QString("VBOX chanid (%1) not found for inputid (%2), redo mythtv-setup")
3404  .arg(chanid).arg(inputid));
3405  return false;
3406  }
3407 
3408  // get timeouts for inputid
3409  std::chrono::milliseconds signal_timeout = 0ms;
3410  std::chrono::milliseconds tuning_timeout = 0ms;
3411  if (!GetTimeouts(inputid,signal_timeout,tuning_timeout))
3412  {
3413  LOG(VB_GENERAL, LOG_ERR, QString("Failed to get timeouts for inputid (%1)")
3414  .arg(inputid));
3415  return false;
3416  }
3417 
3418  // now get url from iptv_channel table
3419  QUrl url;
3420  MSqlQuery query(MSqlQuery::InitCon());
3421  query.prepare("SELECT url "
3422  "FROM iptv_channel "
3423  "WHERE chanid = :CHANID");
3424  query.bindValue(":CHANID", chanid);
3425 
3426  if (!query.exec())
3427  MythDB::DBError("CardUtil::IsVBoxPresent url", query);
3428  else if (query.next())
3429  url = query.value(0).toString();
3430 
3431  // now get just the IP address from the url
3432  QString ip = url.host();
3433  LOG(VB_GENERAL, LOG_INFO, QString("VBOX IP found (%1) for inputid (%2)")
3434  .arg(ip).arg(inputid));
3435 
3436  if (!ping(ip,signal_timeout))
3437  {
3438  LOG(VB_GENERAL, LOG_ERR, QString("VBOX at IP (%1) failed to respond to network ping for inputid (%2) timeout (%3)")
3439  .arg(ip).arg(inputid).arg(signal_timeout.count()));
3440  return false;
3441  }
3442 
3443  return true;
3444 }
3445 #endif
3446 
3447 #ifdef USING_SATIP
3448 
3452 bool CardUtil::IsSatIPPresent(uint inputid)
3453 {
3454  // Should only be called if inputtype == SATIP
3455  if (!inputid )
3456  {
3457  LOG(VB_GENERAL, LOG_ERR, QString("SatIP inputid (%1) not valid, redo mythtv-setup")
3458  .arg(inputid));
3459  return false;
3460  }
3461 
3462  // Get sourceid and startchan from table capturecard for inputid
3463  uint chanid = 0;
3464  chanid = ChannelUtil::GetChannelValueInt("chanid", GetSourceID(inputid), GetStartChannel(inputid));
3465  if (!chanid)
3466  {
3467  // no chanid, presume bad setup
3468  LOG(VB_GENERAL, LOG_ERR, QString("SatIP chanid (%1) not found for inputid (%2), redo mythtv-setup")
3469  .arg(chanid).arg(inputid));
3470  return false;
3471  }
3472 
3473  // Get timeouts for inputid
3474  std::chrono::milliseconds signal_timeout = 0ms;
3475  std::chrono::milliseconds tuning_timeout = 0ms;
3476  if (!GetTimeouts(inputid,signal_timeout,tuning_timeout))
3477  {
3478  LOG(VB_GENERAL, LOG_ERR, QString("Failed to get timeouts for inputid (%1)")
3479  .arg(inputid));
3480  return false;
3481  }
3482 
3483  // Ping the SatIP box to see if it can be reached on the network
3484  QString device = CardUtil::GetVideoDevice(inputid);
3485  QStringList devinfo = device.split(":");
3486  if (devinfo.value(0).toUpper() == "UUID")
3487  {
3488  QString deviceId = QString("uuid:%1").arg(devinfo.value(1));
3489  QString ip = SatIP::findDeviceIP(deviceId);
3490  LOG(VB_GENERAL, LOG_INFO, QString("SatIP[%1] IP address %2 device %3")
3491  .arg(inputid).arg(ip, device));
3492 
3493  if (!ping(ip, signal_timeout))
3494  {
3495  LOG(VB_GENERAL, LOG_ERR, QString("SatIP[%1] at IP %2 failed to respond to network ping (timeout %3)")
3496  .arg(inputid).arg(ip).arg(signal_timeout.count()));
3497  return false;
3498  }
3499  return true;
3500  }
3501  return false;
3502 }
3503 #endif
CardUtil::HDHRdoesDVBC
static bool HDHRdoesDVBC(const QString &device)
If the device is valid, check if the model does DVB-C.
Definition: cardutil.cpp:3084
VBox::checkVersion
bool checkVersion(QString &version)
Definition: vboxutils.cpp:215
manager
static MythSystemLegacyManager * manager
Definition: mythsystemunix.cpp:54
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:216
CardUtil::s_videoDeviceCache
static QMap< QString, QStringList > s_videoDeviceCache
Definition: cardutil.h:471
CardUtil::GetScanableInputTypes
static QString GetScanableInputTypes(void)
Definition: cardutil.cpp:58
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:811
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
CardUtil::IsTunerShared
static bool IsTunerShared(uint inputidA, uint inputidB)
Definition: cardutil.cpp:238
O_NONBLOCK
#define O_NONBLOCK
Definition: compat.h:341
CardUtil::GetInputIDs
static std::vector< uint > GetInputIDs(const QString &videodevice=QString(), const QString &rawtype=QString(), const QString &inputname=QString(), QString hostname=QString())
Returns all inputids of inputs that uses the specified videodevice if specified, and optionally rawty...
Definition: cardutil.cpp:1301
CardUtil::GetVBoxdesc
static QString GetVBoxdesc(const QString &id, const QString &ip, const QString &tunerNo, const QString &tunerType)
Get a nicely formatted string describing the device.
Definition: cardutil.cpp:3163
CardUtil::IsInNeedOfExternalInputConf
static bool IsInNeedOfExternalInputConf(uint inputid)
Definition: cardutil.cpp:2298
DiSEqCDevTree::IsInNeedOfConf
bool IsInNeedOfConf(void) const
Definition: diseqc.cpp:831
MSqlQuery::bindValueNoNull
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
Definition: mythdbcon.cpp:901
CardUtil::CreateCardInput
static int CreateCardInput(uint inputid, uint sourceid, const QString &inputname, const QString &externalcommand, const QString &changer_device, const QString &changer_model, const QString &hostname, const QString &tunechan, const QString &startchan, const QString &displayname, bool dishnet_eit, uint recpriority, uint quicktune, uint schedorder, uint livetvorder)
Definition: cardutil.cpp:1955
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:73
CardUtil::GetDisplayName
static QString GetDisplayName(uint inputid)
Definition: cardutil.cpp:1867
DTVTunerType::kTunerTypeDVBC
static const int kTunerTypeDVBC
Definition: dtvconfparserhelpers.h:95
VBox::checkConnection
bool checkConnection(void)
Definition: vboxutils.cpp:209
CardUtil::GetDeviceLabel
static QString GetDeviceLabel(const QString &inputtype, const QString &videodevice)
Definition: cardutil.cpp:2625
error
static void error(const char *str,...)
Definition: vbi.cpp:36
mythdb.h
CardUtil::GetOrProbeDeliverySystem
static DTVModulationSystem GetOrProbeDeliverySystem(uint inputid, int fd)
Definition: cardutil.cpp:1087
DTVModulationSystem::kModulationSystem_DVBS2
@ kModulationSystem_DVBS2
Definition: dtvconfparserhelpers.h:662
CardUtil::GetVideoDevices
static QStringList GetVideoDevices(const QString &rawtype, QString hostname=QString())
Returns the videodevices of the matching inputs, duplicates removed.
Definition: cardutil.cpp:394
false
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:89
CardUtil::ClearVideoDeviceCache
static void ClearVideoDeviceCache()
Definition: cardutil.cpp:439
CardUtil::GetInputName
static QString GetInputName(uint inputid)
Definition: cardutil.cpp:1764
CardUtil::ProbeV4LAudioInputs
static InputNames ProbeV4LAudioInputs(int videofd, bool &ok)
CardUtil::GetASIDeviceNumber
static int GetASIDeviceNumber(const QString &device, QString *error=nullptr)
Definition: cardutil.cpp:3232
V4L2util::DriverName
QString DriverName(void) const
Definition: v4l2util.h:48
CardUtil::DeleteAllInputs
static bool DeleteAllInputs(void)
Definition: cardutil.cpp:2870
DTVTunerType::kTunerTypeDVBS1
static const int kTunerTypeDVBS1
Definition: dtvconfparserhelpers.h:93
DVB_DEV_VIDEO
@ DVB_DEV_VIDEO
Definition: cardutil.h:35
CardUtil::SetStartChannel
static bool SetStartChannel(uint inputid, const QString &channum)
Definition: cardutil.cpp:1676
DTVModulationSystem::kModulationSystem_DTMB
@ kModulationSystem_DTMB
Definition: dtvconfparserhelpers.h:669
CardUtil::ProbeV4LVideoInputs
static InputNames ProbeV4LVideoInputs(int videofd, bool &ok)
CardUtil::ProbeVideoInputs
static QStringList ProbeVideoInputs(const QString &device, const QString &inputtype=QString())
Definition: cardutil.cpp:2515
CardUtil::ProbeBestDeliverySystem
static DTVModulationSystem ProbeBestDeliverySystem(int fd)
Definition: cardutil.cpp:1038
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:205
CardUtil::HasDVBCRCBug
static bool HasDVBCRCBug(const QString &device)
Returns true if and only if the device munges PAT/PMT tables, and then doesn't fix the CRC.
Definition: cardutil.cpp:786
V4L2util::HasTuner
bool HasTuner(void) const
Definition: v4l2util.cpp:688
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:617
set_on_input
bool set_on_input(const QString &to_set, uint inputid, const QString &value)
Definition: cardutil.cpp:1271
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythDownloadManager
Definition: mythdownloadmanager.h:50
DVB_DEV_CA
@ DVB_DEV_CA
Definition: cardutil.h:33
DiSEqCDevSettings::Load
bool Load(uint card_input_id)
Loads configuration chain from DB for specified card input id.
Definition: diseqc.cpp:128
read_sys
static QString read_sys(const QString &sys_dev)
Definition: cardutil.cpp:3206
CardUtil::ProbeTunerType
static DTVTunerType ProbeTunerType(int fd_frontend)
Definition: cardutil.cpp:854
CardUtil::CloneCard
static uint CloneCard(uint src_inputid, uint dst_inputid)
Definition: cardutil.cpp:1546
CardUtil::IsUniqueDisplayName
static bool IsUniqueDisplayName(const QString &name, uint exclude_inputid)
Definition: cardutil.cpp:1889
dvbchannel.h
SatIP::findDeviceIP
static QString findDeviceIP(const QString &deviceuuid)
Definition: satiputils.cpp:152
CardUtil::GetFirewireChangerModel
static QString GetFirewireChangerModel(uint inputid)
Definition: cardutil.cpp:1635
close
#define close
Definition: compat.h:43
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
CardUtil::ProbeSubTypeName
static QString ProbeSubTypeName(uint inputid)
Definition: cardutil.cpp:979
DTVModulationSystem::kModulationSystem_UNDEFINED
@ kModulationSystem_UNDEFINED
Definition: dtvconfparserhelpers.h:656
CardUtil::ProbeDefaultDeliverySystem
static QString ProbeDefaultDeliverySystem(const QString &device)
Definition: cardutil.cpp:705
DTVTunerType
Definition: dtvconfparserhelpers.h:76
CardUtil::GetASINumBuffers
static uint GetASINumBuffers(uint device_num, QString *error=nullptr)
Definition: cardutil.cpp:3311
CardUtil::ProbeDVBType
static QString ProbeDVBType(const QString &device)
Definition: cardutil.cpp:721
satiputils.h
CardUtil::ProbeVideoDevices
static QStringList ProbeVideoDevices(const QString &rawtype)
Definition: cardutil.cpp:445
DiSEqCDevSettings
DVB-S device settings class.
Definition: diseqc.h:36
CardUtil::SetDefaultDeliverySystem
static int SetDefaultDeliverySystem(uint inputid, int fd)
Definition: cardutil.cpp:1115
CardUtil::ProbeDVBFrontendName
static QString ProbeDVBFrontendName(const QString &device)
Returns the input type from the video device.
Definition: cardutil.cpp:742
CardUtil::GetASIBufferSize
static uint GetASIBufferSize(uint device_num, QString *error=nullptr)
Definition: cardutil.cpp:3287
CardUtil::SetDeliverySystem
static int SetDeliverySystem(uint inputid)
VBOX_MIN_API_VERSION
static constexpr const char * VBOX_MIN_API_VERSION
Definition: vboxutils.h:14
CardUtil::GetInputGroups
static std::vector< uint > GetInputGroups(uint inputid)
Definition: cardutil.cpp:2176
sourceutil.h
CardUtil::UnlinkInputGroup
static bool UnlinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:2145
InputInfo::m_recPriority
int m_recPriority
Definition: inputinfo.h:53
CardUtil::GetAllInputInfo
static QList< InputInfo > GetAllInputInfo()
Definition: cardutil.cpp:1730
dvbtypes.h
mythlogging.h
CardUtil::GetInputList
static std::vector< uint > GetInputList(void)
Definition: cardutil.cpp:2880
SatIP::probeDevices
static QStringList probeDevices(void)
Definition: satiputils.cpp:24
InputInfo::m_liveTvOrder
uint m_liveTvOrder
order for live TV use
Definition: inputinfo.h:55
CardUtil::GetV4LInfo
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:2342
v4l2util.h
CardUtil::IsSingleInputType
static bool IsSingleInputType(const QString &rawtype)
Definition: cardutil.h:212
CardUtil::GetMinSignalMonitoringDelay
static std::chrono::milliseconds GetMinSignalMonitoringDelay(const QString &device)
Definition: cardutil.cpp:793
DTVModulationSystem::kModulationSystem_DVBC_ANNEX_B
@ kModulationSystem_DVBC_ANNEX_B
Definition: dtvconfparserhelpers.h:658
CardUtil::CreateDeviceInputGroup
static uint CreateDeviceInputGroup(uint inputid, const QString &type, const QString &host, const QString &device)
Definition: cardutil.cpp:2057
CardUtil::ProbeDVBInputs
static QStringList ProbeDVBInputs(const QString &device)
Definition: cardutil.cpp:2606
DTVTunerType::kTunerTypeUnknown
static const int kTunerTypeUnknown
Definition: dtvconfparserhelpers.h:103
hardwareprofile.i18n.t
t
Definition: i18n.py:36
CardUtil::GetChildInputIDs
static std::vector< uint > GetChildInputIDs(uint inputid)
Definition: cardutil.cpp:1369
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:549
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
CardUtil::hasV4L2
static bool hasV4L2(int videofd)
Definition: cardutil.cpp:2330
DTVTunerType::toString
QString toString() const
Definition: dtvconfparserhelpers.h:154
vboxutils.h
DiSEqCDevTree::Load
bool Load(const QString &device)
Loads the device tree from the database.
Definition: diseqc.cpp:311
CardUtil::GetDeliverySystemFromDB
static QString GetDeliverySystemFromDB(uint inputid)
Definition: cardutil.h:300
DVB_DEV_AUDIO
@ DVB_DEV_AUDIO
Definition: cardutil.h:34
CardUtil::HasTuner
static bool HasTuner(const QString &rawtype, const QString &device)
Definition: cardutil.cpp:213
DiSEqCDevTree::SetRoot
void SetRoot(DiSEqCDevDevice *root)
Changes the root node of the tree.
Definition: diseqc.cpp:632
dvb_dev_type_t
dvb_dev_type_t
Definition: cardutil.h:28
CardUtil::GetDeviceInputGroup
static uint GetDeviceInputGroup(uint inputid)
Definition: cardutil.cpp:2070
CardUtil::IsDVBInputType
static bool IsDVBInputType(const QString &inputType)
Returns true iff the input_type is one of the DVB types.
Definition: cardutil.cpp:1026
CardUtil::GetTunerType
static DTVTunerType GetTunerType(uint inputid)
Definition: cardutil.cpp:846
uint
unsigned int uint
Definition: compat.h:81
CardUtil::GetTimeouts
static bool GetTimeouts(uint inputid, std::chrono::milliseconds &signal_timeout, std::chrono::milliseconds &channel_timeout)
Definition: cardutil.cpp:2275
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
DiSEqCDev::FindTree
static DiSEqCDevTree * FindTree(uint cardid)
Retrieve device tree.
Definition: diseqc.cpp:237
DiSEqCDevTree::Root
DiSEqCDevDevice * Root(void)
Retrieves the root node in the tree.
Definition: diseqc.h:93
CardUtil::ProbeDeliverySystems
static QStringList ProbeDeliverySystems(const QString &device)
DTVModulationSystem::kModulationSystem_ATSC
@ kModulationSystem_ATSC
Definition: dtvconfparserhelpers.h:667
CardUtil::ProbeCurrentDeliverySystem
static DTVModulationSystem ProbeCurrentDeliverySystem(const QString &device)
CardUtil::GetFirewireChangerNode
static QString GetFirewireChangerNode(uint inputid)
Definition: cardutil.cpp:1618
ChannelUtil::GetChannelValueInt
static int GetChannelValueInt(const QString &channel_field, uint sourceid, const QString &channum)
Definition: channelutil.cpp:976
CardUtil::InputSetMaxRecordings
static bool InputSetMaxRecordings(uint parentid, uint max_recordings)
Definition: cardutil.cpp:1557
InputInfo::m_inputId
uint m_inputId
unique key in DB for this input
Definition: inputinfo.h:49
DTVTunerType::kTunerTypeDVBS2
static const int kTunerTypeDVBS2
Definition: dtvconfparserhelpers.h:94
InputInfo::m_quickTune
bool m_quickTune
Definition: inputinfo.h:56
sys_dev
static QString sys_dev(uint device_num, const QString &dev)
Definition: cardutil.cpp:3201
DTVModulationSystem::toString
QString toString() const
Definition: dtvconfparserhelpers.h:719
CardUtil::GetQuickTuning
static uint GetQuickTuning(uint inputid, const QString &input_name)
Definition: cardutil.cpp:2309
LOC
#define LOC
Definition: cardutil.cpp:56
CardUtil::GetDeviceName
static QString GetDeviceName(dvb_dev_type_t type, const QString &device)
Definition: cardutil.cpp:2945
CardUtil::GetConfiguredDVBInputs
static InputNames GetConfiguredDVBInputs(const QString &device)
Definition: cardutil.cpp:2434
CardUtil::GetRawInputType
static QString GetRawInputType(uint inputid)
Definition: cardutil.h:292
InputInfo::m_scheduleOrder
uint m_scheduleOrder
Definition: inputinfo.h:54
CardUtil::IsInputTypePresent
static bool IsInputTypePresent(const QString &rawtype, QString hostname=QString())
Returns true if the input type is present and connected to an input.
Definition: cardutil.cpp:285
CardUtil::OpenVideoDevice
static int OpenVideoDevice(int inputid)
Definition: cardutil.cpp:1231
InputInfo::m_sourceId
uint m_sourceId
associated channel listings source
Definition: inputinfo.h:48
CardUtil::GetTunerTypeFromMultiplex
static DTVTunerType GetTunerTypeFromMultiplex(uint mplexid)
Definition: cardutil.cpp:870
clone_capturecard
static uint clone_capturecard(uint src_inputid, uint orig_dst_inputid)
Definition: cardutil.cpp:1397
V4L2util::IsOpen
bool IsOpen(void) const
Definition: v4l2util.h:29
CardUtil::IsCableCardPresent
static bool IsCableCardPresent(uint inputid, const QString &inputType)
Definition: cardutil.cpp:105
ping
bool ping(const QString &host, std::chrono::milliseconds timeout)
Can we ping host within timeout seconds?
Definition: mythmiscutil.cpp:199
DVB_DEV_DEMUX
@ DVB_DEV_DEMUX
Definition: cardutil.h:32
DiSEqCDevSettings::Store
bool Store(uint card_input_id) const
Stores configuration chain to DB for specified card input id.
Definition: diseqc.cpp:162
mythmiscutil.h
V4L2util
Definition: v4l2util.h:16
CardUtil::InputTypes
QMap< QString, QString > InputTypes
Definition: cardutil.h:46
DTVModulationSystem
Definition: dtvconfparserhelpers.h:644
cardutil.h
CardUtil::CreateCaptureCard
static int CreateCaptureCard(const QString &videodevice, const QString &audiodevice, const QString &vbidevice, const QString &inputtype, uint audioratelimit, const QString &hostname, uint dvb_swfilter, uint dvb_sat_type, bool dvb_wait_for_seqstart, bool skipbtaudio, bool dvb_on_demand, uint dvb_diseqc_type, uint firewire_speed, const QString &firewire_model, uint firewire_connection, std::chrono::milliseconds signal_timeout, std::chrono::milliseconds channel_timeout, uint dvb_tuning_delay, uint contrast, uint brightness, uint colour, uint hue, uint diseqcid, bool dvb_eitscan)
Definition: cardutil.cpp:2661
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:887
VBox
Definition: vboxutils.h:16
CardUtil::GetInputTypes
static InputTypes GetInputTypes(void)
Definition: cardutil.cpp:319
CardUtil::AddChildInput
static uint AddChildInput(uint parentid)
Definition: cardutil.cpp:1590
CardUtil::GetChildInputCount
static uint GetChildInputCount(uint inputid)
Definition: cardutil.cpp:1345
CardUtil::HDHRdoesDVB
static bool HDHRdoesDVB(const QString &device)
If the device is valid, check if the model does DVB.
Definition: cardutil.cpp:3058
CardUtil::GetDeliverySystem
static DTVModulationSystem GetDeliverySystem(uint inputid)
Definition: cardutil.cpp:904
CardUtil::ProbeAudioInputs
static QStringList ProbeAudioInputs(const QString &device, const QString &inputtype=QString())
Definition: cardutil.cpp:2529
CardUtil::GetHDHRdesc
static QString GetHDHRdesc(const QString &device)
Get a nicely formatted string describing the device.
Definition: cardutil.cpp:3110
CardUtil::GetSourceID
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1936
inputinfo.h
CardUtil::GetSchedInputList
static std::vector< uint > GetSchedInputList(void)
Definition: cardutil.cpp:2901
InputInfo
Definition: inputinfo.h:14
VBox::probeDevices
static QStringList probeDevices(void)
Definition: vboxutils.cpp:29
CardUtil::IsTunerSharingCapable
static bool IsTunerSharingCapable(const QString &rawtype)
Definition: cardutil.h:177
DiSEqCDevTree
DVB-S device tree class. Represents a tree of DVB-S devices.
Definition: diseqc.h:74
get_on_input
QString get_on_input(const QString &to_get, uint inputid)
Definition: cardutil.cpp:1254
CardUtil::GetInputTypeNames
static QStringList GetInputTypeNames(uint sourceid)
Get a list of card input types for a source id.
Definition: cardutil.cpp:366
CardUtil::ConvertToTunerType
static DTVTunerType ConvertToTunerType(DTVModulationSystem delsys)
Definition: cardutil.cpp:803
DTVTunerType::kTunerTypeATSC
static const int kTunerTypeATSC
Definition: dtvconfparserhelpers.h:98
CardUtil::GetInputInfo
static bool GetInputInfo(InputInfo &input, std::vector< uint > *groupids=nullptr)
Definition: cardutil.cpp:1694
InputNames
QMap< int, QString > InputNames
Definition: cardutil.h:22
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:837
DVB_DEV_FRONTEND
@ DVB_DEV_FRONTEND
Definition: cardutil.h:30
DiSEqCDevTree::Store
bool Store(uint cardid, const QString &device="")
Stores the device tree to the database.
Definition: diseqc.cpp:422
musicbrainzngs.caa.hostname
string hostname
Definition: caa.py:17
DiSEqCDevDevice::GetDeviceID
uint GetDeviceID(void) const
Definition: diseqc.h:170
DTVModulationSystem::kModulationSystem_DVBT2
@ kModulationSystem_DVBT2
Definition: dtvconfparserhelpers.h:672
DTVTunerType::kTunerTypeDVBT
static const int kTunerTypeDVBT
Definition: dtvconfparserhelpers.h:96
CardUtil::GetLiveTVInputList
static std::vector< uint > GetLiveTVInputList(void)
Definition: cardutil.cpp:2923
CardUtil::CapabilitiesToString
static QStringList CapabilitiesToString(uint64_t capabilities)
Definition: cardutil.cpp:2462
DTVModulationSystem::kModulationSystem_DVBC_ANNEX_C
@ kModulationSystem_DVBC_ANNEX_C
Definition: dtvconfparserhelpers.h:674
mythdownloadmanager.h
CardUtil::GetDeviceInputNames
static void GetDeviceInputNames(const QString &device, const QString &inputtype, QStringList &inputs)
Definition: cardutil.cpp:2647
DVB_DEV_DVR
@ DVB_DEV_DVR
Definition: cardutil.h:31
CardUtil::GetConflictingInputs
static std::vector< uint > GetConflictingInputs(uint inputid)
Definition: cardutil.cpp:2229
V4L2util::CardName
QString CardName(void) const
Definition: v4l2util.h:49
DTVTunerType::kTunerTypeDVBT2
static const int kTunerTypeDVBT2
Definition: dtvconfparserhelpers.h:97
CardUtil::GetGroupInputIDs
static std::vector< uint > GetGroupInputIDs(uint inputgroupid)
Definition: cardutil.cpp:2202
nv_python_libs.bbciplayer.bbciplayer_api.version
string version
Definition: bbciplayer_api.py:77
InputInfo::m_displayName
QString m_displayName
Definition: inputinfo.h:52
CardUtil::CreateInputGroup
static uint CreateInputGroup(const QString &name)
Definition: cardutil.cpp:2015
CardUtil::LinkInputGroup
static bool LinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:2094
DTVModulationSystem::kModulationSystem_DVBS
@ kModulationSystem_DVBS
Definition: dtvconfparserhelpers.h:661
videosource.h
CardUtil::GetStartChannel
static QString GetStartChannel(uint inputid)
Definition: cardutil.cpp:1783
DTVModulationSystem::kModulationSystem_DVBT
@ kModulationSystem_DVBT
Definition: dtvconfparserhelpers.h:659
diseqcsettings.h
CardUtil::SetASIMode
static bool SetASIMode(uint device_num, uint mode, QString *error=nullptr)
Definition: cardutil.cpp:3358
CardUtil::GetVideoDevice
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:294
DTVModulationSystem::kModulationSystem_DVBC_ANNEX_A
@ kModulationSystem_DVBC_ANNEX_A
Definition: dtvconfparserhelpers.h:657
InputInfo::m_name
QString m_name
input name
Definition: inputinfo.h:47
GetMythDownloadManager
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
Definition: mythdownloadmanager.cpp:145
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:836
write_sys
static bool write_sys(const QString &sys_dev, const QString &str)
Definition: cardutil.cpp:3215
DTVModulationSystem::Parse
bool Parse(const QString &_value)
Definition: dtvconfparserhelpers.h:716
CardUtil::GetASIMode
static int GetASIMode(uint device_num, QString *error=nullptr)
Definition: cardutil.cpp:3335
CardUtil::DeleteInput
static bool DeleteInput(uint inputid)
Definition: cardutil.cpp:2800