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