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