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