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