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  prop.cmd = DTV_API_VERSION;
592  cmd.num = 1;
593  cmd.props = &prop;
594  if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
595  {
596  LOG(VB_GENERAL, LOG_INFO,
597  QString("CardUtil(%1): ").arg(device) +
598  QString("dvb api version %1.%2").arg((prop.u.data>>8)&0xff).arg((prop.u.data)&0xff));
599  }
600  else
601  {
602  LOG(VB_GENERAL, LOG_ERR,
603  QString("CardUtil(%1) FE_GET_PROPERTY ioctl failed").arg(device) + ENO);
604  close(fd_frontend);
605  return delsyslist;
606  }
607 
608  delsyslist = ProbeDeliverySystems(fd_frontend);
609 
610  QStringList::iterator it = delsyslist.begin();
611  QString msg = "Delivery systems:";
612  for (; it != delsyslist.end(); ++it)
613  {
614  msg += " ";
615  msg += *it;
616  }
617  LOG(VB_GENERAL, LOG_INFO, QString("CardUtil(%1): ").arg(device) + msg);
618 
619  close(fd_frontend);
620 #else
621  Q_UNUSED(device);
622 #endif // USING_DVB
623 
624  return delsyslist;
625 }
626 
627 // Get the list of all supported delivery systems from the card
628 QStringList CardUtil::ProbeDeliverySystems(int fd_frontend)
629 {
630  QStringList delsyslist;
631 
632 #ifdef USING_DVB
633  struct dtv_property prop = {};
634  struct dtv_properties cmd = {};
635 
636  prop.cmd = DTV_ENUM_DELSYS;
637  cmd.num = 1;
638  cmd.props = &prop;
639  if (ioctl(fd_frontend, FE_GET_PROPERTY, &cmd) == 0)
640  {
641  for (unsigned int i = 0; i < prop.u.buffer.len; i++)
642  {
643  delsyslist.push_back(DTVModulationSystem::toString(prop.u.buffer.data[i]));
644  }
645  }
646  else
647  {
648  LOG(VB_GENERAL, LOG_ERR, LOC + "FE_GET_PROPERTY ioctl failed " + ENO);
649  }
650 #else
651  Q_UNUSED(fd_frontend);
652 #endif // USING_DVB
653 
654  return delsyslist;
655 }
656 
657 QString CardUtil::ProbeDefaultDeliverySystem(const QString &device)
658 {
659  DTVModulationSystem delsys;
660 
661 #ifdef USING_DVB
662  int fd = OpenVideoDevice(device);
663  if (fd >= 0)
664  {
665  delsys = ProbeBestDeliverySystem(fd);
666  close(fd);
667  }
668 #else
669  Q_UNUSED(device);
670 #endif // USING_DVB
671 
672  return delsys.toString();
673 }
674 
675 QString CardUtil::ProbeDVBType(const QString &device)
676 {
677  QString ret = "ERROR_UNKNOWN";
678 
679  if (device.isEmpty())
680  return ret;
681 
682 #ifdef USING_DVB
683  DTVTunerType type = ProbeTunerType(device);
684  ret = (type.toString() != "UNKNOWN") ? type.toString().toUpper() : ret;
685 
686  LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("(%1) tuner type:%2 %3")
687  .arg(device).arg(type).arg(ret));
688 #endif // USING_DVB
689 
690  return ret;
691 }
692 
696 QString CardUtil::ProbeDVBFrontendName(const QString &device)
697 {
698  QString ret = "ERROR_UNKNOWN";
699 
700 #ifdef USING_DVB
701  QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
702  QByteArray dev = dvbdev.toLatin1();
703  int fd_frontend = open(dev.constData(), O_RDWR | O_NONBLOCK);
704  if (fd_frontend < 0)
705  return "ERROR_OPEN";
706 
707  struct dvb_frontend_info info;
708  memset(&info, 0, sizeof(info));
709  int err = ioctl(fd_frontend, FE_GET_INFO, &info);
710  if (err < 0)
711  {
712  close(fd_frontend);
713  return "ERROR_PROBE";
714  }
715 
716  ret = info.name;
717 
718  close(fd_frontend);
719 #else
720  Q_UNUSED(device);
721 #endif // USING_DVB
722 
723  return ret;
724 }
725 
743 bool CardUtil::HasDVBCRCBug(const QString &device)
744 {
745  QString name = ProbeDVBFrontendName(device);
746  return ((name == "VLSI VES1x93 DVB-S") || // munges PMT
747  (name == "ST STV0299 DVB-S")); // munges PAT
748 }
749 
751 {
752  QString name = ProbeDVBFrontendName(device);
753  if (name.indexOf("DVB-S") >= 0)
754  return 300;
755  if (name == "DiBcom 3000P/M-C DVB-T")
756  return 100;
757  return 25;
758 }
759 
761 {
762  DTVTunerType tunertype;
763 
764  switch (delsys)
765  {
767  tunertype = DTVTunerType::kTunerTypeDVBS1;
768  break;
770  tunertype = DTVTunerType::kTunerTypeDVBS2;
771  break;
773  tunertype = DTVTunerType::kTunerTypeDVBC;
774  break;
776  tunertype = DTVTunerType::kTunerTypeDVBT;
777  break;
779  tunertype = DTVTunerType::kTunerTypeDVBT2;
780  break;
782  tunertype = DTVTunerType::kTunerTypeATSC;
783  break;
786  break;
787  default:
788  LOG(VB_GENERAL, LOG_ERR, LOC +
789  QString("TODO Add to switch case delivery system:%2 %3")
790  .arg(delsys).arg(delsys.toString()));
791  break;
792  }
793 
794  return tunertype;
795 }
796 
797 // Get the currently configured tuner type from the database
799 {
800  DTVModulationSystem delsys = GetDeliverySystem(inputid);
801  DTVTunerType tunertype = ConvertToTunerType(delsys);
802  return tunertype;
803 }
804 
805 // Get the currently configured tuner type from the device
807 {
808  DTVModulationSystem delsys = ProbeCurrentDeliverySystem(fd_frontend);
809  DTVTunerType tunertype = ConvertToTunerType(delsys);
810  return tunertype;
811 }
812 
813 // Get the currently configured tuner type from the device
815 {
817  DTVTunerType tunertype = ConvertToTunerType(delsys);
818  return tunertype;
819 }
820 
821 // Get the currently configured delivery system from the database
823 {
824  QString delsys_db = GetDeliverySystemFromDB(inputid);
825  DTVModulationSystem delsys;
826  delsys.Parse(delsys_db);
827  return delsys;
828 }
829 
830 // Get the currently configured delivery system from the device
832 {
833  DTVModulationSystem delsys;
834 
835  if (device.isEmpty())
836  {
837  return delsys;
838  }
839 
840 #ifdef USING_DVB
841  int fd_frontend = OpenVideoDevice(device);
842  if (fd_frontend < 0)
843  {
844  LOG(VB_GENERAL, LOG_ERR, LOC +
845  QString("open failed (%1)")
846  .arg(device) + ENO);
847  return delsys;
848  }
849 
850  delsys = ProbeCurrentDeliverySystem(fd_frontend);
851 
852  LOG(VB_GENERAL, LOG_DEBUG, QString("CardUtil(%1): delsys:%2 %3")
853  .arg(device).arg(delsys).arg(delsys.toString()));
854 
855  close(fd_frontend);
856 #else
857  Q_UNUSED(device);
858 #endif
859 
860  return delsys;
861 }
862 
863 // Get the currently configured delivery system from the device
865 {
866  DTVModulationSystem delsys;
867 
868 #ifdef USING_DVB
869  struct dtv_property prop = {};
870  struct dtv_properties cmd = {};
871 
872  prop.cmd = DTV_DELIVERY_SYSTEM;
873  // prop.u.data = delsys;
874  cmd.num = 1;
875  cmd.props = &prop;
876 
877  int ret = ioctl(fd_frontend, FE_GET_PROPERTY, &cmd);
878  if (ret < 0)
879  {
880  LOG(VB_GENERAL, LOG_ERR, LOC +
881  QString("FE_GET_PROPERTY ioctl failed (fd_frontend:%1)")
882  .arg(fd_frontend) + ENO);
883  return delsys;
884  }
885 
886  delsys.Parse(DTVModulationSystem::toString(prop.u.data));
887 
888 #else
889  Q_UNUSED(fd_frontend);
890 #endif // USING_DVB
891 
892  return delsys;
893 }
894 
895 // Get the delivery system from database table capturecard.
896 // If there is nothing in the database then get the currently
897 // configured delivery system, check for DVB-T/T2 and DVB-S/S2
898 // and update the database.
899 // Configure the tuner.
900 // Return the tuner type corresponding with the modulation system.
902 {
903  QString type = GetRawInputType(inputid);
904  if ("DVB" != type)
905  return type;
906 
907  QString device = GetVideoDevice(inputid);
908 
909  DTVTunerType tunertype;
910  int fd_frontend = OpenVideoDevice(inputid);
911  if (fd_frontend < 0)
912  return "ERROR_OPEN";
913 
914  DTVModulationSystem delsys = GetDeliverySystem(inputid);
916  {
917  delsys = ProbeBestDeliverySystem(fd_frontend);
919  {
920  // Update database
921  set_on_input("inputname", inputid, delsys.toString()); // Update DB capturecard
922  LOG(VB_GENERAL, LOG_INFO,
923  QString("CardUtil[%1]: ").arg(inputid) +
924  QString("Update capturecard delivery system: %1").arg(delsys.toString()));
925  }
926  else
927  {
928  LOG(VB_GENERAL, LOG_ERR,
929  QString("CardUtil[%1]: Error probing best delivery system").arg(inputid));
930  return "ERROR_UNKNOWN";
931  }
932  }
933  SetDeliverySystem(inputid, delsys, fd_frontend);
934  tunertype = ConvertToTunerType(delsys);
935  close(fd_frontend);
936 
937  QString subtype = "ERROR_UNKNOWN";
938  if (DTVTunerType::kTunerTypeUnknown != tunertype)
939  {
940  subtype = tunertype.toString();
941  }
942 
943  LOG(VB_GENERAL, LOG_DEBUG,
944  QString("CardUtil[%1]: subtype:%2").arg(inputid).arg(subtype));
945 
946  return subtype;
947 }
948 
950 bool CardUtil::IsDVBInputType(const QString &inputType)
951 {
952  QString t = inputType.toUpper();
953  return (t == "DVB") || (t == "QPSK") || (t == "QAM") || (t == "OFDM") ||
954  (t == "ATSC") || (t == "DVB_S2") || (t == "DVB_T2");
955 }
956 
957 // Get the current delivery system from the card
958 // Get all supported delivery systems from the card
959 // If the current delivery system is DVB-T and DVB-T2 is supported then select DVB-T2
960 // If the current delivery system is DVB-S and DVB-S2 is supported then select DVB-S2
961 //
963 {
964  DTVModulationSystem delsys;
965 
966 #ifdef USING_DVB
967  // Get the current delivery system from the card
968  delsys = ProbeCurrentDeliverySystem(fd);
969  LOG(VB_GENERAL, LOG_INFO, LOC +
970  QString("Current delivery system: %1").arg(delsys.toString()));
971 
972  // Get all supported delivery systems from the card
973  QString msg = "Supported delivery systems:";
974  QStringList delsyslist = ProbeDeliverySystems(fd);
975  QStringList::iterator it = delsyslist.begin();
976  for (; it != delsyslist.end(); it++)
977  {
978  msg += " ";
979  msg += *it;
980  }
981  LOG(VB_GENERAL, LOG_INFO, LOC + msg);
982 
983  // If the current delivery system is DVB-T and DVB-T2 is supported then select DVB-T2
985  {
987  if (delsyslist.contains(newdelsys.toString()))
988  {
989  LOG(VB_GENERAL, LOG_INFO, LOC +
990  QString("Changing delivery system from %1 to %2")
991  .arg(delsys.toString()).arg(newdelsys.toString()));
992  delsys = newdelsys;
993  }
994  }
995 
996  // If the current delivery system is DVB-S and DVB-S2 is supported then select DVB-S2
998  {
1000  if (delsyslist.contains(newdelsys.toString()))
1001  {
1002  LOG(VB_GENERAL, LOG_INFO, LOC +
1003  QString("Changing delivery system from %1 to %2")
1004  .arg(delsys.toString()).arg(newdelsys.toString()));
1005  delsys = newdelsys;
1006  }
1007  }
1008 #else
1009  Q_UNUSED(fd);
1010 #endif
1011 
1012  return delsys;
1013 }
1014 
1015 // Get the delivery system from the database
1016 // If not found then get the best delivery system from the card
1017 //
1019 {
1020  DTVModulationSystem delsys;
1021 #ifdef USING_DVB
1022 
1023  // If there is a valid modulation system in the database
1024  // then we return that and do nothing more.
1025  delsys = GetDeliverySystem(inputid);
1027  {
1028  return delsys;
1029  }
1030 
1031  // Nothing in the database, get default and use that
1032  delsys = ProbeBestDeliverySystem(fd);
1033  LOG(VB_GENERAL, LOG_INFO,
1034  QString("CardUtil[%1]: ").arg(inputid) +
1035  QString("No capturecard delivery system in database, using: %1").arg(delsys.toString()));
1036 
1037 #else
1038  Q_UNUSED(inputid);
1039  Q_UNUSED(fd);
1040 #endif
1041 
1042  return delsys;
1043 }
1044 
1045 // Configure the tuner to use the delivery system from database
1046 // If not found then set to the best delivery system from the card
1047 //
1049 {
1050  int ret = -1;
1051 
1052 #ifdef USING_DVB
1053  DTVModulationSystem delsys = GetOrProbeDeliverySystem(inputid, fd);
1055  {
1056  ret = SetDeliverySystem(inputid, delsys, fd);
1057  }
1058 #else
1059  Q_UNUSED(inputid);
1060  Q_UNUSED(fd);
1061 #endif
1062 
1063  return ret;
1064 }
1065 
1066 // Set delivery system from database
1067 //
1069 {
1070  int ret = -1;
1071 
1072 #ifdef USING_DVB
1073  DTVModulationSystem delsys = GetDeliverySystem(inputid);
1075  {
1076  ret = SetDeliverySystem(inputid, delsys);
1077  }
1078 #else
1079  Q_UNUSED(inputid);
1080 #endif // USING_DVB
1081 
1082  return ret;
1083 }
1084 
1086 {
1087  int ret = -1;
1088 
1089 #ifdef USING_DVB
1090  QString device = GetVideoDevice(inputid);
1091 
1092  if (device.isEmpty())
1093  {
1094  LOG(VB_GENERAL, LOG_DEBUG,
1095  QString("CardUtil[%1]: ").arg(inputid) +
1096  QString("inputid:%1 ").arg(inputid) +
1097  QString("delsys:%1").arg(delsys.toString()));
1098  return ret;
1099  }
1100 
1101  int fd_frontend = OpenVideoDevice(device);
1102  if (fd_frontend < 0)
1103  {
1104  LOG(VB_GENERAL, LOG_ERR,
1105  QString("CardUtil[%1]: ").arg(inputid) +
1106  QString("open failed (%1)").arg(device) + ENO);
1107  return ret;
1108  }
1109  ret = SetDeliverySystem(inputid, delsys, fd_frontend);
1110 
1111  close(fd_frontend);
1112 #else
1113  Q_UNUSED(inputid);
1114  Q_UNUSED(delsys);
1115 #endif // USING_DVB
1116 
1117  return ret;
1118 }
1119 
1120 // Get delivery system from the database and write it to the card
1121 int CardUtil::SetDeliverySystem(uint inputid, int fd)
1122 {
1123  int ret = -1;
1124 
1125 #ifdef USING_DVB
1126  DTVModulationSystem delsys = GetDeliverySystem(inputid);
1128  {
1129  ret = SetDeliverySystem(inputid, delsys, fd);
1130  }
1131 #else
1132  Q_UNUSED(inputid);
1133  Q_UNUSED(fd);
1134 #endif // USING_DVB
1135 
1136  return ret;
1137 }
1138 
1139 // Write the delivery system to the card
1141 {
1142  int ret = -1;
1143 
1144 #ifdef USING_DVB
1145  LOG(VB_GENERAL, LOG_INFO,
1146  QString("CardUtil[%1]: ").arg(inputid) +
1147  QString("Set delivery system: %1").arg(delsys.toString()));
1148 
1149  struct dtv_property prop = {};
1150  struct dtv_properties cmd = {};
1151 
1152  prop.cmd = DTV_DELIVERY_SYSTEM;
1153  prop.u.data = delsys;
1154  cmd.num = 1;
1155  cmd.props = &prop;
1156 
1157  ret = ioctl(fd, FE_SET_PROPERTY, &cmd);
1158  if (ret < 0)
1159  {
1160  LOG(VB_GENERAL, LOG_ERR, LOC +
1161  QString("[%1] FE_SET_PROPERTY ioctl failed")
1162  .arg(inputid) + ENO);
1163  return ret;
1164  }
1165 #else
1166  Q_UNUSED(inputid);
1167  Q_UNUSED(delsys);
1168  Q_UNUSED(fd);
1169 #endif // USING_DVB
1170 
1171  return ret;
1172 }
1173 
1175 {
1176  QString device = GetVideoDevice(inputid);
1177  return OpenVideoDevice(device);
1178 }
1179 
1180 int CardUtil::OpenVideoDevice(const QString &device)
1181 {
1182  if (device.isEmpty())
1183  return -1;
1184 
1185  QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
1186  QByteArray dev = dvbdev.toLatin1();
1187  int fd_frontend = open(dev.constData(), O_RDWR | O_NONBLOCK);
1188  if (fd_frontend < 0)
1189  {
1190  LOG(VB_GENERAL, LOG_ERR, LOC +
1191  QString("Can't open DVB frontend (%1) for %2.")
1192  .arg(dvbdev).arg(device) + ENO);
1193  }
1194  return fd_frontend;
1195 }
1196 
1197 QString get_on_input(const QString &to_get, uint inputid)
1198 {
1199  MSqlQuery query(MSqlQuery::InitCon());
1200  query.prepare(
1201  QString("SELECT %1 ").arg(to_get) +
1202  "FROM capturecard "
1203  "WHERE capturecard.cardid = :INPUTID");
1204  query.bindValue(":INPUTID", inputid);
1205 
1206  if (!query.exec())
1207  MythDB::DBError("CardUtil::get_on_source", query);
1208  else if (query.next())
1209  return query.value(0).toString();
1210 
1211  return QString();
1212 }
1213 
1214 bool set_on_input(const QString &to_set, uint inputid, const QString &value)
1215 {
1216  QString tmp = get_on_input("capturecard.cardid", inputid);
1217  if (tmp.isEmpty())
1218  return false;
1219 
1220  MSqlQuery query(MSqlQuery::InitCon());
1221  query.prepare(
1222  QString("UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
1223  "WHERE cardid = :INPUTID");
1224  query.bindValue(":INPUTID", inputid);
1225  query.bindValue(":VALUE", value);
1226 
1227  if (query.exec())
1228  return true;
1229 
1230  MythDB::DBError("CardUtil::set_on_input", query);
1231  return false;
1232 }
1233 
1244 vector<uint> CardUtil::GetInputIDs(const QString& videodevice,
1245  const QString& rawtype,
1246  const QString& inputname,
1247  QString hostname)
1248 {
1249  vector<uint> list;
1250 
1251  if (hostname.isEmpty())
1253 
1254  MSqlQuery query(MSqlQuery::InitCon());
1255  QString qstr =
1256  "SELECT cardid "
1257  "FROM capturecard "
1258  "WHERE hostname = :HOSTNAME ";
1259  if (!videodevice.isEmpty())
1260  qstr += "AND videodevice = :DEVICE ";
1261  if (!inputname.isEmpty())
1262  qstr += "AND inputname = :INPUTNAME ";
1263  if (!rawtype.isEmpty())
1264  qstr += "AND cardtype = :INPUTTYPE ";
1265  qstr += "ORDER BY cardid";
1266 
1267  query.prepare(qstr);
1268 
1269  query.bindValue(":HOSTNAME", hostname);
1270  if (!videodevice.isEmpty())
1271  query.bindValue(":DEVICE", videodevice);
1272  if (!inputname.isEmpty())
1273  query.bindValue(":INPUTNAME", inputname);
1274  if (!rawtype.isEmpty())
1275  query.bindValue(":INPUTTYPE", rawtype.toUpper());
1276 
1277  if (!query.exec())
1278  MythDB::DBError("CardUtil::GetInputIDs(videodevice...)", query);
1279  else
1280  {
1281  while (query.next())
1282  list.push_back(query.value(0).toUInt());
1283  }
1284 
1285  return list;
1286 }
1287 
1289 {
1290  if (!inputid)
1291  return 0;
1292 
1293  MSqlQuery query(MSqlQuery::InitCon());
1294  QString qstr =
1295  "SELECT COUNT(*) "
1296  "FROM capturecard "
1297  "WHERE parentid = :INPUTID";
1298 
1299  query.prepare(qstr);
1300  query.bindValue(":INPUTID", inputid);
1301 
1302  uint count = 0;
1303 
1304  if (!query.exec())
1305  MythDB::DBError("CardUtil::GetChildInputCount()", query);
1306  else if (query.next())
1307  count = query.value(0).toUInt();
1308 
1309  return count;
1310 }
1311 
1312 vector<uint> CardUtil::GetChildInputIDs(uint inputid)
1313 {
1314  vector<uint> list;
1315 
1316  if (!inputid)
1317  return list;
1318 
1319  MSqlQuery query(MSqlQuery::InitCon());
1320  QString qstr =
1321  "SELECT cardid "
1322  "FROM capturecard "
1323  "WHERE parentid = :INPUTID "
1324  "ORDER BY cardid";
1325 
1326  query.prepare(qstr);
1327  query.bindValue(":INPUTID", inputid);
1328 
1329  if (!query.exec())
1330  MythDB::DBError("CardUtil::GetChildInputIDs()", query);
1331  else
1332  {
1333  while (query.next())
1334  list.push_back(query.value(0).toUInt());
1335  }
1336 
1337  return list;
1338 }
1339 
1340 static uint clone_capturecard(uint src_inputid, uint orig_dst_inputid)
1341 {
1342  uint dst_inputid = orig_dst_inputid;
1343 
1344  MSqlQuery query(MSqlQuery::InitCon());
1345  if (!dst_inputid)
1346  {
1347  query.prepare(
1348  "DELETE FROM capturecard "
1349  "WHERE videodevice = 'temp_dummy'");
1350 
1351  if (!query.exec())
1352  {
1353  MythDB::DBError("clone_capturecard -- delete temp", query);
1354  return 0;
1355  }
1356 
1357  query.prepare(
1358  "INSERT INTO capturecard "
1359  "SET videodevice = 'temp_dummy'");
1360 
1361  if (!query.exec())
1362  {
1363  MythDB::DBError("clone_capturecard -- insert temp", query);
1364  return 0;
1365  }
1366 
1367  query.prepare(
1368  "SELECT cardid "
1369  "FROM capturecard "
1370  "WHERE videodevice = 'temp_dummy'");
1371 
1372  if (!query.exec())
1373  {
1374  MythDB::DBError("clone_capturecard -- get temp id", query);
1375  return 0;
1376  }
1377 
1378  if (!query.next())
1379  {
1380  LOG(VB_GENERAL, LOG_ERR, "clone_capturecard -- get temp id");
1381  return 0;
1382  }
1383 
1384  dst_inputid = query.value(0).toUInt();
1385  }
1386 
1387  query.prepare(
1388  "SELECT videodevice, audiodevice, vbidevice, "
1389  " cardtype, hostname, signal_timeout, "
1390  " channel_timeout, dvb_wait_for_seqstart, dvb_on_demand, "
1391  " dvb_tuning_delay, dvb_diseqc_type, diseqcid, "
1392  " dvb_eitscan, inputname, sourceid, "
1393  " externalcommand, changer_device, changer_model, "
1394  " tunechan, startchan, displayname, "
1395  " dishnet_eit, recpriority, quicktune, "
1396  " livetvorder, reclimit, "
1397  // See below for special handling of the following.
1398  " schedgroup, schedorder "
1399  "FROM capturecard "
1400  "WHERE cardid = :INPUTID");
1401  query.bindValue(":INPUTID", src_inputid);
1402 
1403  if (!query.exec())
1404  {
1405  MythDB::DBError("clone_capturecard -- get data", query);
1406  return 0;
1407  }
1408  if (!query.next())
1409  {
1410  LOG(VB_GENERAL, LOG_ERR, "clone_cardinput -- get data 2");
1411  return 0;
1412  }
1413 
1414  // Hangel schedgroup and schedorder specially. If schedgroup is
1415  // set, schedgroup and schedorder should be false and 0,
1416  // respectively, for all children.
1417  bool schedgroup = query.value(26).toBool();
1418  uint schedorder = query.value(27).toUInt();
1419  if (schedgroup)
1420  {
1421  schedgroup = false;
1422  schedorder = 0;
1423  }
1424 
1425  MSqlQuery query2(MSqlQuery::InitCon());
1426  query2.prepare(
1427  "UPDATE capturecard "
1428  "SET videodevice = :V0, "
1429  " audiodevice = :V1, "
1430  " vbidevice = :V2, "
1431  " cardtype = :V3, "
1432  " hostname = :V4, "
1433  " signal_timeout = :V5, "
1434  " channel_timeout = :V6, "
1435  " dvb_wait_for_seqstart = :V7, "
1436  " dvb_on_demand = :V8, "
1437  " dvb_tuning_delay = :V9, "
1438  " dvb_diseqc_type = :V10, "
1439  " diseqcid = :V11,"
1440  " dvb_eitscan = :V12, "
1441  " inputname = :V13, "
1442  " sourceid = :V14, "
1443  " externalcommand = :V15, "
1444  " changer_device = :V16, "
1445  " changer_model = :V17, "
1446  " tunechan = :V18, "
1447  " startchan = :V19, "
1448  " displayname = :V20, "
1449  " dishnet_eit = :V21, "
1450  " recpriority = :V22, "
1451  " quicktune = :V23, "
1452  " livetvorder = :V24, "
1453  " reclimit = :V25, "
1454  " schedgroup = :SCHEDGROUP, "
1455  " schedorder = :SCHEDORDER, "
1456  " parentid = :PARENTID "
1457  "WHERE cardid = :INPUTID");
1458  for (uint i = 0; i < 26; ++i)
1459  query2.bindValue(QString(":V%1").arg(i), query.value(i).toString());
1460  query2.bindValue(":INPUTID", dst_inputid);
1461  query2.bindValue(":PARENTID", src_inputid);
1462  query2.bindValue(":SCHEDGROUP", schedgroup);
1463  query2.bindValue(":SCHEDORDER", schedorder);
1464 
1465  if (!query2.exec())
1466  {
1467  MythDB::DBError("clone_capturecard -- save data", query2);
1468  if (!orig_dst_inputid)
1469  CardUtil::DeleteInput(dst_inputid);
1470  return 0;
1471  }
1472 
1473  // copy input group linkages
1474  vector<uint> src_grps = CardUtil::GetInputGroups(src_inputid);
1475  vector<uint> dst_grps = CardUtil::GetInputGroups(dst_inputid);
1476  for (size_t j = 0; j < dst_grps.size(); j++)
1477  CardUtil::UnlinkInputGroup(dst_inputid, dst_grps[j]);
1478  for (size_t j = 0; j < src_grps.size(); j++)
1479  CardUtil::LinkInputGroup(dst_inputid, src_grps[j]);
1480 
1481  // clone diseqc_config (just points to the same diseqc_tree row)
1482  DiSEqCDevSettings diseqc;
1483  if (diseqc.Load(src_inputid))
1484  diseqc.Store(dst_inputid);
1485 
1486  return dst_inputid;
1487 }
1488 
1489 uint CardUtil::CloneCard(uint src_inputid, uint orig_dst_inputid)
1490 {
1491  QString type = CardUtil::GetRawInputType(src_inputid);
1493  return 0;
1494 
1495  uint dst_inputid = clone_capturecard(src_inputid, orig_dst_inputid);
1496  return dst_inputid;
1497 }
1498 
1500 {
1501  uint inputid = CloneCard(parentid, 0);
1502 
1503  // Update the reclimit for the parent and all children so the new
1504  // child doesn't get removed the next time mythtv-setup is run.
1505  if (inputid)
1506  {
1507  LOG(VB_GENERAL, LOG_INFO, LOC +
1508  QString("Added child input %1 to parent %2")
1509  .arg(inputid).arg(parentid));
1510  MSqlQuery query(MSqlQuery::InitCon());
1511  query.prepare("UPDATE capturecard "
1512  "SET reclimit = reclimit + 1 "
1513  "WHERE cardid = :PARENTID");
1514  query.bindValue(":PARENTID", parentid);
1515  if (!query.exec())
1516  MythDB::DBError("CardUtil::AddChildInput", query);
1517  }
1518  else
1519  {
1520  LOG(VB_GENERAL, LOG_ERR, LOC +
1521  QString("Failed to add child input to parent %1").arg(parentid));
1522  }
1523 
1524  return inputid;
1525 }
1526 
1528 {
1529  QString fwnode;
1530 
1531  MSqlQuery query(MSqlQuery::InitCon());
1532  query.prepare("SELECT changer_device "
1533  "FROM capturecard WHERE cardid = :INPUTID ");
1534  query.bindValue(":INPUTID", inputid);
1535 
1536  if (query.exec() && query.next())
1537  {
1538  fwnode = query.value(0).toString();
1539  }
1540 
1541  return fwnode;
1542 }
1543 
1545 {
1546  QString fwnode;
1547 
1548  MSqlQuery query(MSqlQuery::InitCon());
1549  query.prepare("SELECT changer_model "
1550  "FROM capturecard WHERE cardid = :INPUTID ");
1551  query.bindValue(":INPUTID", inputid);
1552 
1553  if (query.exec() && query.next())
1554  {
1555  fwnode = query.value(0).toString();
1556  }
1557 
1558  return fwnode;
1559 }
1560 
1561 vector<uint> CardUtil::GetInputIDs(uint sourceid)
1562 {
1563  MSqlQuery query(MSqlQuery::InitCon());
1564 
1565  query.prepare(
1566  "SELECT DISTINCT cardid "
1567  "FROM capturecard "
1568  "WHERE sourceid = :SOURCEID");
1569  query.bindValue(":SOURCEID", sourceid);
1570 
1571  vector<uint> list;
1572 
1573  if (!query.exec())
1574  {
1575  MythDB::DBError("CardUtil::GetInputIDs()", query);
1576  return list;
1577  }
1578 
1579  while (query.next())
1580  list.push_back(query.value(0).toUInt());
1581 
1582  return list;
1583 }
1584 
1585 bool CardUtil::SetStartChannel(uint inputid, const QString &channum)
1586 {
1587  MSqlQuery query(MSqlQuery::InitCon());
1588  query.prepare("UPDATE capturecard "
1589  "SET startchan = :CHANNUM "
1590  "WHERE cardid = :INPUTID");
1591  query.bindValue(":CHANNUM", channum);
1592  query.bindValue(":INPUTID", inputid);
1593 
1594  if (!query.exec())
1595  {
1596  MythDB::DBError("set_startchan", query);
1597  return false;
1598  }
1599 
1600  return true;
1601 }
1602 
1603 bool CardUtil::GetInputInfo(InputInfo &input, vector<uint> *groupids)
1604 {
1605  if (!input.m_inputid)
1606  return false;
1607 
1608  MSqlQuery query(MSqlQuery::InitCon());
1609  query.prepare("SELECT "
1610  "inputname, sourceid, livetvorder, "
1611  "schedorder, displayname, recpriority, quicktune "
1612  "FROM capturecard "
1613  "WHERE cardid = :INPUTID");
1614  query.bindValue(":INPUTID", input.m_inputid);
1615 
1616  if (!query.exec())
1617  {
1618  MythDB::DBError("CardUtil::GetInputInfo()", query);
1619  return false;
1620  }
1621 
1622  if (!query.next())
1623  return false;
1624 
1625  input.m_name = query.value(0).toString();
1626  input.m_sourceid = query.value(1).toUInt();
1627  input.m_livetvorder = query.value(2).toUInt();
1628  input.m_scheduleOrder = query.value(3).toUInt();
1629  input.m_displayName = query.value(4).toString();
1630  input.m_recPriority = query.value(5).toInt();
1631  input.m_quickTune = query.value(6).toBool();
1632 
1633  if (input.m_displayName.isEmpty())
1634  input.m_displayName = QObject::tr("Input %1:%2")
1635  .arg(input.m_inputid).arg(input.m_name);
1636 
1637  if (groupids)
1638  *groupids = GetInputGroups(input.m_inputid);
1639 
1640  return true;
1641 }
1642 
1643 QList<InputInfo> CardUtil::GetAllInputInfo()
1644 {
1645  QList<InputInfo> infoInputList;
1646 
1647  MSqlQuery query(MSqlQuery::InitCon());
1648  query.prepare("SELECT cardid, "
1649  "inputname, sourceid, livetvorder, "
1650  "schedorder, displayname, recpriority, quicktune "
1651  "FROM capturecard");
1652 
1653  if (!query.exec())
1654  {
1655  MythDB::DBError("CardUtil::GetAllInputInfo()", query);
1656  return infoInputList;
1657  }
1658 
1659  while (query.next())
1660  {
1661  InputInfo input;
1662  input.m_inputid = query.value(0).toUInt();
1663  input.m_name = query.value(1).toString();
1664  input.m_sourceid = query.value(2).toUInt();
1665  input.m_livetvorder = query.value(3).toUInt();
1666  input.m_scheduleOrder = query.value(4).toUInt();
1667  input.m_displayName = query.value(5).toString();
1668  input.m_recPriority = query.value(6).toInt();
1669  input.m_quickTune = query.value(7).toBool();
1670 
1671  infoInputList.push_back(input);
1672  }
1673 
1674  return infoInputList;
1675 }
1676 
1678 {
1679  InputInfo info("None", 0, inputid, 0, 0, 0);
1680  GetInputInfo(info);
1681  return info.m_name;
1682 }
1683 
1685 {
1686  MSqlQuery query(MSqlQuery::InitCon());
1687  query.prepare("SELECT startchan "
1688  "FROM capturecard "
1689  "WHERE cardid = :INPUTID");
1690  query.bindValue(":INPUTID", inputid);
1691 
1692  if (!query.exec())
1693  MythDB::DBError("CardUtil::GetStartingChannel(uint)", query);
1694  else if (query.next())
1695  return query.value(0).toString();
1696 
1697  return QString();
1698 }
1699 
1701 {
1702  if (!inputid)
1703  return QString();
1704 
1705  MSqlQuery query(MSqlQuery::InitCon());
1706  query.prepare("SELECT displayname, cardid, inputname "
1707  "FROM capturecard "
1708  "WHERE cardid = :INPUTID");
1709  query.bindValue(":INPUTID", inputid);
1710 
1711  if (!query.exec())
1712  MythDB::DBError("CardUtil::GetDisplayName(uint)", query);
1713  else if (query.next())
1714  {
1715  QString result = query.value(0).toString();
1716  if (result.isEmpty())
1717  result = QString("%1: %2").arg(query.value(1).toInt())
1718  .arg(query.value(2).toString());
1719  return result;
1720  }
1721 
1722  return QString();
1723 }
1724 
1726 {
1727  MSqlQuery query(MSqlQuery::InitCon());
1728  query.prepare(
1729  "SELECT sourceid "
1730  "FROM capturecard "
1731  "WHERE cardid = :INPUTID");
1732  query.bindValue(":INPUTID", inputid);
1733  if (!query.exec() || !query.isActive())
1734  MythDB::DBError("CardUtil::GetSourceID()", query);
1735  else if (query.next())
1736  return query.value(0).toUInt();
1737 
1738  return 0;
1739 }
1740 
1741 // Is this intentionally leaving out the hostname when updating the
1742 // capturecard table? The hostname value does get set when inserting
1743 // into the capturecard table. (Code written in 2011.)
1745  const uint sourceid,
1746  const QString &inputname,
1747  const QString &externalcommand,
1748  const QString &changer_device,
1749  const QString &changer_model,
1750  const QString &/*hostname*/,
1751  const QString &tunechan,
1752  const QString &startchan,
1753  const QString &displayname,
1754  bool dishnet_eit,
1755  const uint recpriority,
1756  const uint quicktune,
1757  const uint schedorder,
1758  const uint livetvorder)
1759 {
1760  MSqlQuery query(MSqlQuery::InitCon());
1761 
1762  query.prepare(
1763  "UPDATE capturecard "
1764  "SET sourceid = :SOURCEID, "
1765  " inputname = :INPUTNAME, "
1766  " externalcommand = :EXTERNALCOMMAND, "
1767  " changer_device = :CHANGERDEVICE, "
1768  " changer_model = :CHANGERMODEL, "
1769  " tunechan = :TUNECHAN, "
1770  " startchan = :STARTCHAN, "
1771  " displayname = :DISPLAYNAME, "
1772  " dishnet_eit = :DISHNETEIT, "
1773  " recpriority = :RECPRIORITY, "
1774  " quicktune = :QUICKTUNE, "
1775  " schedorder = :SCHEDORDER, "
1776  " livetvorder = :LIVETVORDER "
1777  "WHERE cardid = :INPUTID AND "
1778  " inputname = 'None'");
1779 
1780  query.bindValue(":INPUTID", inputid);
1781  query.bindValue(":SOURCEID", sourceid);
1782  query.bindValue(":INPUTNAME", inputname);
1783  query.bindValue(":EXTERNALCOMMAND", externalcommand);
1784  query.bindValue(":CHANGERDEVICE", changer_device);
1785  query.bindValue(":CHANGERMODEL", changer_model);
1786  query.bindValue(":TUNECHAN", tunechan);
1787  query.bindValue(":STARTCHAN", startchan);
1788  query.bindValue(":DISPLAYNAME", displayname.isNull() ? "" : displayname);
1789  query.bindValue(":DISHNETEIT", dishnet_eit);
1790  query.bindValue(":RECPRIORITY", recpriority);
1791  query.bindValue(":QUICKTUNE", quicktune);
1792  query.bindValue(":SCHEDORDER", schedorder);
1793  query.bindValue(":LIVETVORDER", livetvorder);
1794 
1795  if (!query.exec())
1796  {
1797  MythDB::DBError("CreateCardInput", query);
1798  return -1;
1799  }
1800 
1801  return inputid;
1802 }
1803 
1805 {
1806  MSqlQuery query(MSqlQuery::InitCon());
1807 
1808  query.prepare("SELECT inputgroupid FROM inputgroup "
1809  "WHERE inputgroupname = :GROUPNAME "
1810  "LIMIT 1");
1811  query.bindValue(":GROUPNAME", name);
1812  if (!query.exec())
1813  {
1814  MythDB::DBError("CreateNewInputGroup 0", query);
1815  return 0;
1816  }
1817 
1818  if (query.next())
1819  return query.value(0).toUInt();
1820 
1821  query.prepare("SELECT MAX(inputgroupid) FROM inputgroup");
1822  if (!query.exec())
1823  {
1824  MythDB::DBError("CreateNewInputGroup 1", query);
1825  return 0;
1826  }
1827 
1828  uint inputgroupid = (query.next()) ? query.value(0).toUInt() + 1 : 1;
1829 
1830  query.prepare(
1831  "INSERT INTO inputgroup "
1832  " (cardinputid, inputgroupid, inputgroupname) "
1833  "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
1834  query.bindValue(":INPUTID", 0);
1835  query.bindValue(":GROUPID", inputgroupid);
1836  query.bindValue(":GROUPNAME", name);
1837  if (!query.exec())
1838  {
1839  MythDB::DBError("CreateNewInputGroup 2", query);
1840  return 0;
1841  }
1842 
1843  return inputgroupid;
1844 }
1845 
1847  const QString &type,
1848  const QString &host,
1849  const QString &device)
1850 {
1851  QString name = host + '|' + device;
1852  if (type == "FREEBOX" || type == "IMPORT" ||
1853  type == "DEMO" || type == "EXTERNAL" ||
1854  type == "HDHOMERUN")
1855  name += QString("|%1").arg(inputid);
1856  return CreateInputGroup(name);
1857 }
1858 
1860 {
1861  MSqlQuery query(MSqlQuery::InitCon());
1862  query.prepare(
1863  "SELECT inputgroupid "
1864  "FROM inputgroup "
1865  "WHERE cardinputid = :INPUTID "
1866  " AND inputgroupname REGEXP '^[a-z_-]*\\\\|'");
1867  query.bindValue(":INPUTID", inputid);
1868 
1869  if (!query.exec())
1870  {
1871  MythDB::DBError("CardUtil::GetDeviceInputGroup()", query);
1872  return 0;
1873  }
1874 
1875  if (query.next())
1876  {
1877  return query.value(0).toUInt();
1878  }
1879 
1880  return 0;
1881 }
1882 
1883 bool CardUtil::LinkInputGroup(uint inputid, uint inputgroupid)
1884 {
1885  MSqlQuery query(MSqlQuery::InitCon());
1886 
1887  query.prepare(
1888  "SELECT cardinputid, inputgroupid, inputgroupname "
1889  "FROM inputgroup "
1890  "WHERE inputgroupid = :GROUPID "
1891  "ORDER BY inputgroupid, cardinputid, inputgroupname");
1892  query.bindValue(":GROUPID", inputgroupid);
1893 
1894  if (!query.exec())
1895  {
1896  MythDB::DBError("CardUtil::CreateInputGroup() 1", query);
1897  return false;
1898  }
1899 
1900  if (!query.next())
1901  return false;
1902 
1903  const QString name = query.value(2).toString();
1904 
1905  query.prepare(
1906  "INSERT INTO inputgroup "
1907  " (cardinputid, inputgroupid, inputgroupname) "
1908  "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
1909 
1910  query.bindValue(":INPUTID", inputid);
1911  query.bindValue(":GROUPID", inputgroupid);
1912  query.bindValue(":GROUPNAME", name);
1913 
1914  if (!query.exec())
1915  {
1916  MythDB::DBError("CardUtil::CreateInputGroup() 2", query);
1917  return false;
1918  }
1919 
1920  return true;
1921 }
1922 
1923 bool CardUtil::UnlinkInputGroup(uint inputid, uint inputgroupid)
1924 {
1925  MSqlQuery query(MSqlQuery::InitCon());
1926 
1927  if (!inputid && !inputgroupid)
1928  {
1929  query.prepare(
1930  "DELETE FROM inputgroup "
1931  "WHERE cardinputid NOT IN "
1932  "( SELECT cardid FROM capturecard )");
1933  }
1934  else
1935  {
1936  query.prepare(
1937  "DELETE FROM inputgroup "
1938  "WHERE cardinputid = :INPUTID AND "
1939  " inputgroupid = :GROUPID ");
1940 
1941  query.bindValue(":INPUTID", inputid);
1942  query.bindValue(":GROUPID", inputgroupid);
1943  }
1944 
1945  if (!query.exec())
1946  {
1947  MythDB::DBError("CardUtil::DeleteInputGroup()", query);
1948  return false;
1949  }
1950 
1951  return true;
1952 }
1953 
1954 vector<uint> CardUtil::GetInputGroups(uint inputid)
1955 {
1956  vector<uint> list;
1957 
1958  MSqlQuery query(MSqlQuery::InitCon());
1959 
1960  query.prepare(
1961  "SELECT inputgroupid "
1962  "FROM inputgroup "
1963  "WHERE cardinputid = :INPUTID "
1964  "ORDER BY inputgroupid, cardinputid, inputgroupname");
1965 
1966  query.bindValue(":INPUTID", inputid);
1967 
1968  if (!query.exec())
1969  {
1970  MythDB::DBError("CardUtil::GetInputGroups()", query);
1971  return list;
1972  }
1973 
1974  while (query.next())
1975  list.push_back(query.value(0).toUInt());
1976 
1977  return list;
1978 }
1979 
1980 vector<uint> CardUtil::GetGroupInputIDs(uint inputgroupid)
1981 {
1982  vector<uint> list;
1983 
1984  MSqlQuery query(MSqlQuery::InitCon());
1985 
1986  query.prepare(
1987  "SELECT DISTINCT cardid "
1988  "FROM capturecard, inputgroup "
1989  "WHERE inputgroupid = :GROUPID AND "
1990  " capturecard.cardid = inputgroup.cardinputid "
1991  "ORDER BY cardid");
1992 
1993  query.bindValue(":GROUPID", inputgroupid);
1994 
1995  if (!query.exec())
1996  {
1997  MythDB::DBError("CardUtil::GetGroupInputIDs()", query);
1998  return list;
1999  }
2000 
2001  while (query.next())
2002  list.push_back(query.value(0).toUInt());
2003 
2004  return list;
2005 }
2006 
2008 {
2009  LOG(VB_RECORD, LOG_INFO,
2010  QString("CardUtil[%1]: GetConflictingInputs() input %1").arg(inputid));
2011 
2012  vector<uint> inputids;
2013 
2014  MSqlQuery query(MSqlQuery::InitCon());
2015 
2016  query.prepare(
2017  "SELECT DISTINCT c.cardid "
2018  "FROM ( "
2019  " SELECT inputgroupid "
2020  " FROM inputgroup "
2021  " WHERE cardinputid = :INPUTID1 "
2022  ") g "
2023  "JOIN inputgroup ig ON ig.inputgroupid = g.inputgroupid "
2024  "JOIN capturecard c ON c.cardid = ig.cardinputid "
2025  " AND c.cardid <> :INPUTID2 "
2026  "ORDER BY c.cardid");
2027 
2028  query.bindValue(":INPUTID1", inputid);
2029  query.bindValue(":INPUTID2", inputid);
2030 
2031  if (!query.exec())
2032  {
2033  MythDB::DBError("CardUtil::GetConflictingInputs()", query);
2034  return inputids;
2035  }
2036 
2037  while (query.next())
2038  {
2039  inputids.push_back(query.value(0).toUInt());
2040  LOG(VB_RECORD, LOG_INFO,
2041  QString("CardUtil[%1]: GetConflictingInputs() got input %2")
2042  .arg(inputid).arg(inputids.back()));
2043  }
2044 
2045  return inputids;
2046 }
2047 
2049  uint &signal_timeout, uint &channel_timeout)
2050 {
2051  MSqlQuery query(MSqlQuery::InitCon());
2052  query.prepare(
2053  "SELECT signal_timeout, channel_timeout "
2054  "FROM capturecard "
2055  "WHERE cardid = :INPUTID");
2056  query.bindValue(":INPUTID", inputid);
2057 
2058  if (!query.exec() || !query.isActive())
2059  MythDB::DBError("CardUtil::GetTimeouts()", query);
2060  else if (query.next())
2061  {
2062  signal_timeout = (uint) max(query.value(0).toInt(), 250);
2063  channel_timeout = (uint) max(query.value(1).toInt(), 500);
2064  return true;
2065  }
2066 
2067  return false;
2068 }
2069 
2071 {
2072  DiSEqCDev dev;
2073  DiSEqCDevTree *diseqc_tree = dev.FindTree(inputid);
2074 
2075  bool needsConf = false;
2076  if (diseqc_tree)
2077  needsConf = diseqc_tree->IsInNeedOfConf();
2078 
2079  return needsConf;
2080 }
2081 
2082 uint CardUtil::GetQuickTuning(uint inputid, const QString &input_name)
2083 {
2084  uint quicktune = 0;
2085 
2086  MSqlQuery query(MSqlQuery::InitCon());
2087  query.prepare(
2088  "SELECT quicktune "
2089  "FROM capturecard "
2090  "WHERE cardid = :INPUTID AND "
2091  " inputname = :INPUTNAME");
2092  query.bindValue(":INPUTID", inputid);
2093  query.bindValue(":INPUTNAME", input_name);
2094 
2095  if (!query.exec() || !query.isActive())
2096  MythDB::DBError("CardUtil::GetQuickTuning()", query);
2097  else if (query.next())
2098  quicktune = query.value(0).toUInt();
2099 
2100  return quicktune;
2101 }
2102 
2103 bool CardUtil::hasV4L2(int videofd)
2104 {
2105  (void) videofd;
2106 #ifdef USING_V4L2
2107  struct v4l2_capability vcap;
2108  memset(&vcap, 0, sizeof(vcap));
2109 
2110  return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
2111  ((vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE) != 0U));
2112 #else // if !USING_V4L2
2113  return false;
2114 #endif // !USING_V4L2
2115 }
2116 
2118  int videofd, QString &input, QString &driver, uint32_t &version,
2119  uint32_t &capabilities)
2120 {
2121  input.clear();
2122  driver.clear();
2123  version = 0;
2124  capabilities = 0;
2125 
2126  if (videofd < 0)
2127  return false;
2128 
2129 #ifdef USING_V4L2
2130  // First try V4L2 query
2131  struct v4l2_capability capability;
2132  memset(&capability, 0, sizeof(struct v4l2_capability));
2133  if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
2134  {
2135  input = QString::fromLatin1((const char*)capability.card);
2136  driver = QString::fromLatin1((const char*)capability.driver);
2137  version = capability.version;
2138  capabilities = capability.capabilities;
2139  }
2140 #ifdef USING_V4L1
2141  else // Fallback to V4L1 query
2142  {
2143  struct video_capability capability2;
2144  if (ioctl(videofd, VIDIOCGCAP, &capability2) >= 0)
2145  input = QString::fromLatin1((const char*)capability2.name);
2146  }
2147 #endif // USING_V4L1
2148 #endif // USING_V4L2
2149 
2150  if (!driver.isEmpty())
2151  driver.remove( QRegExp("\\[[0-9]\\]$") );
2152 
2153  return !input.isEmpty();
2154 }
2155 
2156 InputNames CardUtil::ProbeV4LVideoInputs(int videofd, bool &ok)
2157 {
2158  (void) videofd;
2159 
2160  InputNames list;
2161  ok = false;
2162 
2163 #ifdef USING_V4L2
2164  bool usingv4l2 = hasV4L2(videofd);
2165 
2166  // V4L v2 query
2167  struct v4l2_input vin;
2168  memset(&vin, 0, sizeof(vin));
2169  while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
2170  {
2171  QString input((char *)vin.name);
2172  list[vin.index] = input;
2173  vin.index++;
2174  }
2175  if (vin.index)
2176  {
2177  ok = true;
2178  return list;
2179  }
2180 
2181 #ifdef USING_V4L1
2182  // V4L v1 query
2183  struct video_capability vidcap;
2184  memset(&vidcap, 0, sizeof(vidcap));
2185  if (ioctl(videofd, VIDIOCGCAP, &vidcap) != 0)
2186  {
2187  QString msg = QObject::tr("Could not query inputs.");
2188  LOG(VB_GENERAL, LOG_ERR, "ProbeV4LVideoInputs(): Error, " + msg + ENO);
2189  list[-1] = msg;
2190  vidcap.channels = 0;
2191  }
2192 
2193  for (int i = 0; i < vidcap.channels; i++)
2194  {
2195  struct video_channel test;
2196  memset(&test, 0, sizeof(test));
2197  test.channel = i;
2198 
2199  if (ioctl(videofd, VIDIOCGCHAN, &test) != 0)
2200  {
2201  LOG(VB_GENERAL, LOG_ERR, "ProbeV4LVideoInputs(): Error, " +
2202  QString("Could determine name of input #%1"
2203  "\n\t\t\tNot adding it to the list.")
2204  .arg(test.channel) + ENO);
2205  continue;
2206  }
2207 
2208  list[i] = test.name;
2209  }
2210 #endif // USING_V4L1
2211 
2212  // Create an input when none are advertised
2213  if (list.isEmpty())
2214  list[0] = "Television";
2215 
2216  ok = true;
2217 #else // if !USING_V4L2
2218  list[-1] += QObject::tr("ERROR, Compile with V4L support to query inputs");
2219 #endif // !USING_V4L2
2220  return list;
2221 }
2222 
2223 InputNames CardUtil::ProbeV4LAudioInputs(int videofd, bool &ok)
2224 {
2225  (void) videofd;
2226 
2227  InputNames list;
2228  ok = false;
2229 
2230 #ifdef USING_V4L2
2231  bool usingv4l2 = hasV4L2(videofd);
2232 
2233  // V4L v2 query
2234  struct v4l2_audio ain;
2235  memset(&ain, 0, sizeof(ain));
2236  while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMAUDIO, &ain) >= 0))
2237  {
2238  QString input((char *)ain.name);
2239  list[ain.index] = input;
2240  ain.index++;
2241  }
2242  if (ain.index)
2243  {
2244  ok = true;
2245  return list;
2246  }
2247 
2248  ok = true;
2249 #else // if !USING_V4L2
2250  list[-1] += QObject::tr(
2251  "ERROR, Compile with V4L support to query audio inputs");
2252 #endif // !USING_V4L2
2253  return list;
2254 }
2255 
2256 InputNames CardUtil::GetConfiguredDVBInputs(const QString &device)
2257 {
2258  InputNames list;
2259  MSqlQuery query(MSqlQuery::InitCon());
2260  query.prepare(
2261  "SELECT cardid, inputname "
2262  "FROM capturecard "
2263  "WHERE hostname = :HOSTNAME "
2264  " AND videodevice = :DEVICE "
2265  " AND parentid = 0 "
2266  " AND inputname <> 'None'");
2267  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
2268  query.bindValue(":DEVICE", device);
2269 
2270  if (!query.exec() || !query.isActive())
2271  MythDB::DBError("CardUtil::GetConfiguredDVBInputs", query);
2272  else
2273  {
2274  while (query.next())
2275  list[query.value(0).toUInt()] = query.value(1).toString();
2276  }
2277  return list;
2278 }
2279 
2280 QStringList CardUtil::ProbeVideoInputs(const QString& device, const QString& inputtype)
2281 {
2282  QStringList ret;
2283 
2284  if (IsSingleInputType(inputtype))
2285  ret += "MPEG2TS";
2286  else if ("DVB" == inputtype)
2287  ret += ProbeDVBInputs(device);
2288  else
2289  ret += ProbeV4LVideoInputs(device);
2290 
2291  return ret;
2292 }
2293 
2294 QStringList CardUtil::ProbeAudioInputs(const QString& device, const QString& inputtype)
2295 {
2296  LOG(VB_GENERAL, LOG_DEBUG, QString("ProbeAudioInputs(%1,%2)")
2297  .arg(device).arg(inputtype));
2298  QStringList ret;
2299 
2300  if ("HDPVR" == inputtype ||
2301  "V4L2" == inputtype)
2302  ret += ProbeV4LAudioInputs(device);
2303 
2304  return ret;
2305 }
2306 
2307 QStringList CardUtil::ProbeV4LVideoInputs(const QString& device)
2308 {
2309  bool ok;
2310  QStringList ret;
2311  QByteArray dev = device.toLatin1();
2312  int videofd = open(dev.constData(), O_RDWR);
2313  if (videofd < 0)
2314  {
2315  ret += QObject::tr("Could not open '%1' "
2316  "to probe its inputs.").arg(device);
2317  return ret;
2318  }
2319  InputNames list = CardUtil::ProbeV4LVideoInputs(videofd, ok);
2320  close(videofd);
2321 
2322  if (!ok)
2323  {
2324  ret += list[-1];
2325  return ret;
2326  }
2327 
2328  InputNames::iterator it;
2329  for (it = list.begin(); it != list.end(); ++it)
2330  {
2331  if (it.key() >= 0)
2332  ret += *it;
2333  }
2334 
2335  return ret;
2336 }
2337 
2338 QStringList CardUtil::ProbeV4LAudioInputs(const QString& device)
2339 {
2340  LOG(VB_GENERAL, LOG_DEBUG, QString("ProbeV4LAudioInputs(%1)").arg(device));
2341 
2342  bool ok;
2343  QStringList ret;
2344  int videofd = open(device.toLatin1().constData(), O_RDWR);
2345  if (videofd < 0)
2346  {
2347  LOG(VB_GENERAL, LOG_ERR, "ProbeAudioInputs() -> couldn't open device");
2348  ret += QObject::tr("Could not open '%1' to probe its inputs.")
2349  .arg(device);
2350  return ret;
2351  }
2352  InputNames list = CardUtil::ProbeV4LAudioInputs(videofd, ok);
2353  close(videofd);
2354 
2355  if (!ok)
2356  {
2357  ret += list[-1];
2358  return ret;
2359  }
2360 
2361  InputNames::iterator it;
2362  for (it = list.begin(); it != list.end(); ++it)
2363  {
2364  if (it.key() >= 0)
2365  ret += *it;
2366  }
2367 
2368  return ret;
2369 }
2370 
2371 QStringList CardUtil::ProbeDVBInputs(const QString& device)
2372 {
2373  QStringList ret;
2374 
2375 #ifdef USING_DVB
2376  InputNames list = GetConfiguredDVBInputs(device);
2377  InputNames::iterator it;
2378  for (it = list.begin(); it != list.end(); ++it)
2379  {
2380  if (it.key())
2381  ret += *it;
2382  }
2383 #else
2384  (void) device;
2385  ret += QObject::tr("ERROR, Compile with DVB support to query inputs");
2386 #endif
2387 
2388  return ret;
2389 }
2390 
2391 QString CardUtil::GetDeviceLabel(const QString &inputtype,
2392  const QString &videodevice)
2393 {
2394  return QString("[ %1 : %2 ]").arg(inputtype).arg(videodevice);
2395 }
2396 
2397 QString CardUtil::GetDeviceLabel(uint inputid)
2398 {
2399  QString devlabel;
2400  MSqlQuery query(MSqlQuery::InitCon());
2401  query.prepare("SELECT cardtype, videodevice "
2402  "FROM capturecard WHERE cardid = :INPUTID ");
2403  query.bindValue(":INPUTID", inputid);
2404 
2405  if (query.exec() && query.next())
2406  {
2407  return GetDeviceLabel(query.value(0).toString(),
2408  query.value(1).toString());
2409  }
2410 
2411  return "[ UNKNOWN ]";
2412 }
2413 
2415  const QString &device,
2416  const QString &inputtype,
2417  QStringList &inputs)
2418 {
2419  inputs.clear();
2420  if (IsSingleInputType(inputtype))
2421  inputs += "MPEG2TS";
2422  else if (inputtype == "DVB")
2423  inputs += "DVBInput";
2424  else
2425  inputs += ProbeV4LVideoInputs(device);
2426 }
2427 
2428 int CardUtil::CreateCaptureCard(const QString &videodevice,
2429  const QString &audiodevice,
2430  const QString &vbidevice,
2431  const QString &inputtype,
2432  const uint audioratelimit,
2433  const QString &hostname,
2434  const uint dvb_swfilter,
2435  const uint dvb_sat_type,
2436  bool dvb_wait_for_seqstart,
2437  bool skipbtaudio,
2438  bool dvb_on_demand,
2439  const uint dvb_diseqc_type,
2440  const uint firewire_speed,
2441  const QString &firewire_model,
2442  const uint firewire_connection,
2443  const uint signal_timeout,
2444  const uint channel_timeout,
2445  const uint dvb_tuning_delay,
2446  const uint contrast,
2447  const uint brightness,
2448  const uint colour,
2449  const uint hue,
2450  const uint diseqcid,
2451  bool dvb_eitscan)
2452 {
2453  MSqlQuery query(MSqlQuery::InitCon());
2454 
2455  query.prepare(
2456  "INSERT INTO capturecard "
2457  "(videodevice, audiodevice, vbidevice, cardtype, "
2458  "audioratelimit, hostname, dvb_swfilter, dvb_sat_type, "
2459  "dvb_wait_for_seqstart, skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
2460  "firewire_speed, firewire_model, firewire_connection, signal_timeout, "
2461  "channel_timeout, dvb_tuning_delay, contrast, brightness, colour, "
2462  "hue, diseqcid, dvb_eitscan) "
2463  "VALUES (:VIDEODEVICE, :AUDIODEVICE, :VBIDEVICE, :INPUTTYPE, "
2464  ":AUDIORATELIMIT, :HOSTNAME, :DVBSWFILTER, :DVBSATTYPE, "
2465  ":DVBWAITFORSEQSTART, :SKIPBTAUDIO, :DVBONDEMAND, :DVBDISEQCTYPE, "
2466  ":FIREWIRESPEED, :FIREWIREMODEL, :FIREWIRECONNECTION, :SIGNALTIMEOUT, "
2467  ":CHANNELTIMEOUT, :DVBTUNINGDELAY, :CONTRAST, :BRIGHTNESS, :COLOUR, "
2468  ":HUE, :DISEQCID, :DVBEITSCAN ) ");
2469 
2470  query.bindValue(":VIDEODEVICE", videodevice);
2471  query.bindValue(":AUDIODEVICE", audiodevice);
2472  query.bindValue(":VBIDEVICE", vbidevice);
2473  query.bindValue(":INPUTTYPE", inputtype);
2474  query.bindValue(":AUDIORATELIMIT", audioratelimit);
2475  query.bindValue(":HOSTNAME", hostname);
2476  query.bindValue(":DVBSWFILTER", dvb_swfilter);
2477  query.bindValue(":DVBSATTYPE", dvb_sat_type);
2478  query.bindValue(":DVBWAITFORSEQSTART", dvb_wait_for_seqstart);
2479  query.bindValue(":SKIPBTAUDIO", skipbtaudio);
2480  query.bindValue(":DVBONDEMAND", dvb_on_demand);
2481  query.bindValue(":DVBDISEQCTYPE", dvb_diseqc_type);
2482  query.bindValue(":FIREWIRESPEED", firewire_speed);
2483  query.bindValue(":FIREWIREMODEL", firewire_model);
2484  query.bindValue(":FIREWIRECONNECTION", firewire_connection);
2485  query.bindValue(":SIGNALTIMEOUT", signal_timeout);
2486  query.bindValue(":CHANNELTIMEOUT", channel_timeout);
2487  query.bindValue(":DVBTUNINGDELAY", dvb_tuning_delay);
2488  query.bindValue(":CONTRAST", contrast);
2489  query.bindValue(":BRIGHTNESS", brightness);
2490  query.bindValue(":COLOUR", colour);
2491  query.bindValue(":HUE", hue);
2492  query.bindValue(":DISEQCID", diseqcid);
2493  query.bindValue(":DVBEITSCAN", dvb_eitscan);
2494 
2495  if (!query.exec())
2496  {
2497  MythDB::DBError("CreateCaptureCard", query);
2498  return -1;
2499  }
2500 
2501  query.prepare("SELECT MAX(cardid) FROM capturecard");
2502 
2503  if (!query.exec())
2504  {
2505  MythDB::DBError("CreateCaptureCard maxinput", query);
2506  return -1;
2507  }
2508 
2509  int inputid = -1; /* must be int not uint because of return type. */
2510 
2511  if (query.next())
2512  {
2513  inputid = query.value(0).toInt();
2514  uint groupid = CardUtil::CreateDeviceInputGroup(inputid, inputtype,
2515  hostname, videodevice);
2516  CardUtil::LinkInputGroup(inputid, groupid);
2517  }
2518 
2519  return inputid;
2520 }
2521 
2522 bool CardUtil::DeleteInput(uint inputid)
2523 {
2524  vector<uint> childids = GetChildInputIDs(inputid);
2525  for (size_t i = 0; i < childids.size(); ++i)
2526  {
2527  if (!DeleteInput(childids[i]))
2528  {
2529  LOG(VB_GENERAL, LOG_ERR, LOC +
2530  QString("CardUtil: Failed to delete child input %1")
2531  .arg(childids[i]));
2532  return false;
2533  }
2534  }
2535 
2536  MSqlQuery query(MSqlQuery::InitCon());
2537 
2538  DiSEqCDevTree tree;
2539  tree.Load(inputid);
2540 
2541  // Delete the capturecard row for this input
2542  query.prepare("DELETE FROM capturecard WHERE cardid = :INPUTID");
2543  query.bindValue(":INPUTID", inputid);
2544  if (!query.exec())
2545  {
2546  MythDB::DBError("DeleteCard -- delete capturecard", query);
2547  return false;
2548  }
2549 
2550  // Update the reclimit of the parent input
2551  query.prepare("UPDATE capturecard SET reclimit=reclimit-1 "
2552  "WHERE cardid = :INPUTID");
2553  query.bindValue(":INPUTID", inputid);
2554  if (!query.exec())
2555  {
2556  MythDB::DBError("DeleteCard -- update capturecard", query);
2557  return false;
2558  }
2559 
2560  // Delete the inputgroup rows for this input
2561  query.prepare("DELETE FROM inputgroup WHERE cardinputid = :INPUTID");
2562  query.bindValue(":INPUTID", inputid);
2563  if (!query.exec())
2564  {
2565  MythDB::DBError("DeleteCard -- delete inputgroup", query);
2566  return false;
2567  }
2568 
2569  // Delete the diseqc tree if no more inputs reference it.
2570  if (tree.Root())
2571  {
2572  query.prepare("SELECT cardid FROM capturecard "
2573  "WHERE diseqcid = :DISEQCID LIMIT 1");
2574  query.bindValue(":DISEQCID", tree.Root()->GetDeviceID());
2575  if (!query.exec())
2576  {
2577  MythDB::DBError("DeleteCard -- find diseqc tree", query);
2578  }
2579  else if (!query.next())
2580  {
2581  tree.SetRoot(nullptr);
2582  tree.Store(inputid);
2583  }
2584  }
2585 
2586  // delete any unused input groups
2587  UnlinkInputGroup(0, 0);
2588 
2589  return true;
2590 }
2591 
2592 bool CardUtil::DeleteAllInputs(void)
2593 {
2594  MSqlQuery query(MSqlQuery::InitCon());
2595  return (query.exec("TRUNCATE TABLE inputgroup") &&
2596  query.exec("TRUNCATE TABLE diseqc_config") &&
2597  query.exec("TRUNCATE TABLE diseqc_tree") &&
2598  query.exec("TRUNCATE TABLE capturecard") &&
2599  query.exec("TRUNCATE TABLE iptv_channel"));
2600 }
2601 
2602 vector<uint> CardUtil::GetInputList(void)
2603 {
2604  vector<uint> list;
2605 
2606  MSqlQuery query(MSqlQuery::InitCon());
2607  query.prepare(
2608  "SELECT cardid "
2609  "FROM capturecard "
2610  "ORDER BY cardid");
2611 
2612  if (!query.exec())
2613  MythDB::DBError("CardUtil::GetInputList()", query);
2614  else
2615  {
2616  while (query.next())
2617  list.push_back(query.value(0).toUInt());
2618  }
2619 
2620  return list;
2621 }
2622 
2623 vector<uint> CardUtil::GetSchedInputList(void)
2624 {
2625  vector<uint> list;
2626 
2627  MSqlQuery query(MSqlQuery::InitCon());
2628  query.prepare(
2629  "SELECT DISTINCT cardid "
2630  "FROM capturecard "
2631  "WHERE schedorder <> 0 "
2632  "ORDER BY schedorder, cardid");
2633 
2634  if (!query.exec())
2635  MythDB::DBError("CardUtil::GetSchedInputList()", query);
2636  else
2637  {
2638  while (query.next())
2639  list.push_back(query.value(0).toUInt());
2640  }
2641 
2642  return list;
2643 }
2644 
2645 vector<uint> CardUtil::GetLiveTVInputList(void)
2646 {
2647  vector<uint> list;
2648 
2649  MSqlQuery query(MSqlQuery::InitCon());
2650  query.prepare(
2651  "SELECT DISTINCT cardid "
2652  "FROM capturecard "
2653  "WHERE livetvorder <> 0 "
2654  "ORDER BY livetvorder, cardid");
2655 
2656  if (!query.exec())
2657  MythDB::DBError("CardUtil::GetLiveTVInputList()", query);
2658  else
2659  {
2660  while (query.next())
2661  list.push_back(query.value(0).toUInt());
2662  }
2663 
2664  return list;
2665 }
2666 
2667 QString CardUtil::GetDeviceName(dvb_dev_type_t type, const QString &device)
2668 {
2669  QString devname = QString(device);
2670  LOG(VB_RECORD, LOG_DEBUG, LOC + QString("DVB Device (%1)").arg(devname));
2671  QString tmp = devname;
2672 
2673  if (DVB_DEV_FRONTEND == type)
2674  return devname;
2675  if (DVB_DEV_DVR == type)
2676  {
2677  tmp = tmp.replace(devname.indexOf("frontend"), 8, "dvr");
2678  if (QFile::exists(tmp))
2679  {
2680  LOG(VB_RECORD, LOG_DEBUG, LOC +
2681  QString("Adapter Frontend dvr number matches (%1)").arg(tmp));
2682  return tmp;
2683  }
2684 
2685  // use dvr0, allows multi-standard frontends which only have one dvr
2686  devname = devname.replace(devname.indexOf("frontend"), 9, "dvr0");
2687  LOG(VB_RECORD, LOG_DEBUG, LOC +
2688  QString("Adapter Frontend dvr number not matching, using dvr0 instead (%1)").arg(devname));
2689  return devname;
2690  }
2691  if (DVB_DEV_DEMUX == type)
2692  {
2693  tmp = tmp.replace(devname.indexOf("frontend"), 8, "demux");
2694  if (QFile::exists(tmp))
2695  {
2696  LOG(VB_RECORD, LOG_DEBUG, LOC +
2697  QString("Adapter Frontend demux number matches (%1)").arg(tmp));
2698  return tmp;
2699  }
2700 
2701  // use demux0, allows multi-standard frontends, which only have one demux
2702  devname = devname.replace(devname.indexOf("frontend"), 9, "demux0");
2703  LOG(VB_RECORD, LOG_DEBUG, LOC +
2704  QString("Adapter Frontend demux number not matching, using demux0 instead (%1)").arg(devname));
2705  return devname;
2706  }
2707  if (DVB_DEV_CA == type)
2708  {
2709  tmp = tmp.replace(devname.indexOf("frontend"), 8, "ca");
2710  if (QFile::exists(tmp))
2711  {
2712  LOG(VB_RECORD, LOG_DEBUG, LOC +
2713  QString("Adapter Frontend ca number matches (%1)").arg(tmp));
2714  return tmp;
2715  }
2716 
2717  // use ca0, allows multi-standard frontends, which only have one ca
2718  devname = devname.replace(devname.indexOf("frontend"), 9, "ca0");
2719  LOG(VB_RECORD, LOG_DEBUG, LOC +
2720  QString("Adapter Frontend ca number not matching, using ca0 instead (%1)").arg(devname));
2721  return devname;
2722  }
2723  if (DVB_DEV_AUDIO == type)
2724  return devname.replace(devname.indexOf("frontend"), 8, "audio");
2725  if (DVB_DEV_VIDEO == type)
2726  return devname.replace(devname.indexOf("frontend"), 8, "video");
2727 
2728  return "";
2729 }
2730 
2731 
2741 bool CardUtil::HDHRdoesDVB(const QString &device)
2742 {
2743  (void) device;
2744 
2745 #ifdef USING_HDHOMERUN
2746  hdhomerun_device_t *hdhr;
2747  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), nullptr);
2748  if (!hdhr)
2749  return false;
2750 
2751  const char *model = hdhomerun_device_get_model_str(hdhr);
2752  if (model && strstr(model, "dvb"))
2753  {
2754  hdhomerun_device_destroy(hdhr);
2755  return true;
2756  }
2757 
2758  hdhomerun_device_destroy(hdhr);
2759 
2760 #endif
2761 
2762  return false;
2763 }
2764 
2769 QString CardUtil::GetHDHRdesc(const QString &device)
2770 {
2771  QString connectErr = QObject::tr("Unable to connect to device.");
2772 
2773 #ifdef USING_HDHOMERUN
2774  bool deviceIsIP = false;
2775 
2776  if (device.contains('.')) // Simplistic check, but also allows DNS names
2777  deviceIsIP = true;
2778  else
2779  {
2780  bool validID;
2781 
2782  uint32_t dev = device.toUInt(&validID, 16);
2783  if (!validID || !hdhomerun_discover_validate_device_id(dev))
2784  return QObject::tr("Invalid Device ID");
2785  }
2786  (void) deviceIsIP;
2787 
2788  LOG(VB_GENERAL, LOG_INFO, "CardUtil::GetHDHRdescription(" + device +
2789  ") - trying to locate device");
2790 
2791  hdhomerun_device_t *hdhr;
2792  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), nullptr);
2793  if (!hdhr)
2794  return QObject::tr("Invalid Device ID or address.");
2795 
2796  const char *model = hdhomerun_device_get_model_str(hdhr);
2797  if (!model)
2798  {
2799  hdhomerun_device_destroy(hdhr);
2800  return connectErr;
2801  }
2802 
2803 
2804  QString description = model;
2805  char *sVersion;
2806  uint32_t iVersion;
2807 
2808  if (hdhomerun_device_get_version(hdhr, &sVersion, &iVersion))
2809  description += QObject::tr(", firmware: %2").arg(sVersion);
2810 
2811  hdhomerun_device_destroy(hdhr);
2812 
2813  return description;
2814 #else
2815 
2816  (void) device;
2817  return connectErr;
2818 #endif
2819 }
2820 
2825 QString CardUtil::GetVBoxdesc(const QString &id, const QString &ip,
2826  const QString &tunerNo, const QString &tunerType)
2827 {
2828  QString connectErr = QObject::tr("Unable to connect to device.");
2829 
2830 #ifdef USING_VBOX
2831  VBox *vbox = new VBox(ip);
2832 
2833  if (!vbox->checkConnection())
2834  {
2835  delete vbox;
2836  return connectErr;
2837  }
2838 
2839  QString version;
2840 
2841  if (!vbox->checkVersion(version))
2842  {
2843  QString apiVersionErr = QObject::tr("The VBox software version is too old (%1), we require %2")
2844  .arg(version).arg(VBOX_MIN_API_VERSION);
2845  delete vbox;
2846  return apiVersionErr;
2847 
2848  }
2849 
2850  delete vbox;
2851 
2852  return QString("V@Box TV Gateway - ID: %1, IP: %2, Tuner: %3-%4").arg(id)
2853  .arg(ip).arg(tunerNo).arg(tunerType);
2854 
2855 #else
2856  (void) id;
2857  (void) ip;
2858  (void) tunerNo;
2859  (void) tunerType;
2860 
2861  return connectErr;
2862 #endif
2863 }
2864 
2865 #ifdef USING_ASI
2866 static QString sys_dev(uint device_num, const QString& dev)
2867 {
2868  return QString("/sys/class/asi/asirx%1/%2").arg(device_num).arg(dev);
2869 }
2870 
2871 static QString read_sys(const QString& sys_dev)
2872 {
2873  QFile f(sys_dev);
2874  f.open(QIODevice::ReadOnly);
2875  QByteArray sdba = f.readAll();
2876  f.close();
2877  return sdba;
2878 }
2879 
2880 static bool write_sys(const QString& sys_dev, const QString& str)
2881 {
2882  QFile f(sys_dev);
2883  f.open(QIODevice::WriteOnly);
2884  QByteArray ba = str.toLocal8Bit();
2885  qint64 offset = 0;
2886  for (uint tries = 0; (offset < ba.size()) && tries < 5; tries++)
2887  {
2888  qint64 written = f.write(ba.data()+offset, ba.size()-offset);
2889  if (written < 0)
2890  return false;
2891  offset += written;
2892  }
2893  return true;
2894 }
2895 #endif
2896 
2897 int CardUtil::GetASIDeviceNumber(const QString &device, QString *error)
2898 {
2899 #ifdef USING_ASI
2900  // basic confirmation
2901  struct stat statbuf;
2902  memset(&statbuf, 0, sizeof(statbuf));
2903  if (stat(device.toLocal8Bit().constData(), &statbuf) < 0)
2904  {
2905  if (error)
2906  *error = QString("Unable to stat '%1'").arg(device) + ENO;
2907  return -1;
2908  }
2909 
2910  if (!S_ISCHR(statbuf.st_mode))
2911  {
2912  if (error)
2913  *error = QString("'%1' is not a character device").arg(device);
2914  return -1;
2915  }
2916 
2917  if (!(statbuf.st_rdev & 0x0080))
2918  {
2919  if (error)
2920  *error = QString("'%1' not a DVEO ASI receiver").arg(device);
2921  return -1;
2922  }
2923 
2924  int device_num = statbuf.st_rdev & 0x007f;
2925 
2926  // extra confirmation
2927  QString sys_dev_contents = read_sys(sys_dev(device_num, "dev"));
2928  QStringList sys_dev_clist = sys_dev_contents.split(":");
2929  if (2 != sys_dev_clist.size())
2930  {
2931  if (error)
2932  {
2933  *error = QString("Unable to read '%1'")
2934  .arg(sys_dev(device_num, "dev"));
2935  }
2936  return -1;
2937  }
2938  if (sys_dev_clist[0].toUInt() != (statbuf.st_rdev>>8))
2939  {
2940  if (error)
2941  *error = QString("'%1' not a DVEO ASI device").arg(device);
2942  return -1;
2943  }
2944 
2945  return device_num;
2946 #else
2947  (void) device;
2948  if (error)
2949  *error = "Not compiled with ASI support.";
2950  return -1;
2951 #endif
2952 }
2953 
2954 uint CardUtil::GetASIBufferSize(uint device_num, QString *error)
2955 {
2956 #ifdef USING_ASI
2957  // get the buffer size
2958  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "bufsize"));
2959  bool ok;
2960  uint buf_size = sys_bufsize_contents.toUInt(&ok);
2961  if (!ok)
2962  {
2963  if (error)
2964  {
2965  *error = QString("Failed to read buffer size from '%1'")
2966  .arg(sys_dev(device_num, "bufsize"));
2967  }
2968  return 0;
2969  }
2970  return buf_size;
2971 #else
2972  (void) device_num;
2973  if (error)
2974  *error = "Not compiled with ASI support.";
2975  return 0;
2976 #endif
2977 }
2978 
2979 uint CardUtil::GetASINumBuffers(uint device_num, QString *error)
2980 {
2981 #ifdef USING_ASI
2982  // get the buffer size
2983  QString sys_numbuffers_contents = read_sys(sys_dev(device_num, "buffers"));
2984  bool ok;
2985  uint num_buffers = sys_numbuffers_contents.toUInt(&ok);
2986  if (!ok)
2987  {
2988  if (error)
2989  {
2990  *error = QString("Failed to read num buffers from '%1'")
2991  .arg(sys_dev(device_num, "buffers"));
2992  }
2993  return 0;
2994  }
2995  return num_buffers;
2996 #else
2997  (void) device_num;
2998  if (error)
2999  *error = "Not compiled with ASI support.";
3000  return 0;
3001 #endif
3002 }
3003 
3004 int CardUtil::GetASIMode(uint device_num, QString *error)
3005 {
3006 #ifdef USING_ASI
3007  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "mode"));
3008  bool ok;
3009  uint mode = sys_bufsize_contents.toUInt(&ok);
3010  if (!ok)
3011  {
3012  if (error)
3013  {
3014  *error = QString("Failed to read mode from '%1'")
3015  .arg(sys_dev(device_num, "mode"));
3016  }
3017  return -1;
3018  }
3019  return mode;
3020 #else
3021  (void) device_num;
3022  if (error)
3023  *error = "Not compiled with ASI support.";
3024  return -1;
3025 #endif
3026 }
3027 
3028 bool CardUtil::SetASIMode(uint device_num, uint mode, QString *error)
3029 {
3030 #ifdef USING_ASI
3031  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "mode"));
3032  bool ok;
3033  uint old_mode = sys_bufsize_contents.toUInt(&ok);
3034  if (ok && old_mode == mode)
3035  return true;
3036  ok = write_sys(sys_dev(device_num, "mode"), QString("%1\n").arg(mode));
3037  if (!ok && error)
3038  {
3039  *error = QString("Failed to set mode to %1 using '%2'")
3040  .arg(mode).arg(sys_dev(device_num, "mode"));
3041  }
3042  return ok;
3043 #else
3044  Q_UNUSED(device_num);
3045  Q_UNUSED(mode);
3046  if (error)
3047  *error = "Not compiled with ASI support.";
3048  return false;
3049 #endif
3050 }
3051 
3056 bool CardUtil::IsVBoxPresent(uint inputid)
3057 {
3058  // should only be called if inputtype == VBOX
3059  if (!inputid )
3060  {
3061  LOG(VB_GENERAL, LOG_ERR, QString("VBOX inputid (%1) not valid, redo mythtv-setup")
3062  .arg(inputid));
3063  return false;
3064  }
3065 
3066  // get sourceid and startchan from table capturecard for inputid
3067  uint chanid = 0;
3068  chanid = ChannelUtil::GetChannelValueInt("chanid",GetSourceID(inputid),GetStartingChannel(inputid));
3069  if (!chanid)
3070  {
3071  // no chanid, presume bad setup
3072  LOG(VB_GENERAL, LOG_ERR, QString("VBOX chanid (%1) not found for inputid (%2) , redo mythtv-setup")
3073  .arg(chanid).arg(inputid));
3074  return false;
3075  }
3076 
3077  // get timeouts for inputid
3078  uint signal_timeout = 0;
3079  uint tuning_timeout = 0;
3080  if (!GetTimeouts(inputid,signal_timeout,tuning_timeout))
3081  {
3082  LOG(VB_GENERAL, LOG_ERR, QString("Failed to get timeouts for inputid (%1)")
3083  .arg(inputid));
3084  return false;
3085  }
3086 
3087  signal_timeout = signal_timeout/1000; //convert to seconds
3088 
3089  // now get url from iptv_channel table
3090  QUrl url;
3091  MSqlQuery query(MSqlQuery::InitCon());
3092  query.prepare("SELECT url "
3093  "FROM iptv_channel "
3094  "WHERE chanid = :CHANID");
3095  query.bindValue(":CHANID", chanid);
3096 
3097  if (!query.exec())
3098  MythDB::DBError("CardUtil::IsVBoxPresent url", query);
3099  else if (query.next())
3100  url = query.value(0).toString();
3101 
3102  //now get just the IP address from the url
3103  QString ip = url.host();
3104  LOG(VB_GENERAL, LOG_INFO, QString("VBOX IP found (%1) for inputid (%2)")
3105  .arg(ip).arg(inputid));
3106 
3107  if (!ping(ip,signal_timeout))
3108  {
3109  LOG(VB_GENERAL, LOG_ERR, QString("VBOX at IP (%1) failed to respond to network ping for inputid (%2) timeout (%3)")
3110  .arg(ip).arg(inputid).arg(signal_timeout));
3111  return false;
3112  }
3113 
3114  return true;
3115 }
static int SetDefaultDeliverySystem(uint inputid, int fd)
Definition: cardutil.cpp:1048
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:1174
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:743
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:1677
DiSEqCDevDevice * Root(void)
Retrieves the root node in the tree.
Definition: diseqc.h:92
static DTVModulationSystem ProbeCurrentDeliverySystem(const QString &device)
Definition: cardutil.cpp:831
static DTVModulationSystem GetDeliverySystem(uint inputid)
Definition: cardutil.cpp:822
static bool IsTunerShared(uint inputidA, uint inputidB)
Definition: cardutil.cpp:253
static int SetDeliverySystem(uint inputid)
Definition: cardutil.cpp:1068
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:1585
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:1804
static const int kTunerTypeATSC
static QString ProbeDVBType(const QString &device)
Definition: cardutil.cpp:675
static void ClearVideoDeviceCache()
Definition: cardutil.cpp:452
static vector< uint > GetConflictingInputs(uint inputid)
Definition: cardutil.cpp:2007
static QString ProbeSubTypeName(uint inputid)
Definition: cardutil.cpp:901
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:843
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:696
static QMap< QString, QStringList > s_videoDeviceCache
Definition: cardutil.h:437
static uint AddChildInput(uint parentid)
Definition: cardutil.cpp:1499
static bool IsInNeedOfExternalInputConf(uint inputid)
Definition: cardutil.cpp:2070
uint m_inputid
unique key in DB for this input
Definition: inputinfo.h:71
static DTVModulationSystem ProbeBestDeliverySystem(int fd)
Definition: cardutil.cpp:962
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:1018
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:1214
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:1489
bool Store(uint cardid, const QString &device="")
Stores the device tree to the database.
Definition: diseqc.cpp:426
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:2117
static bool GetTimeouts(uint inputid, uint &signal_timeout, uint &channel_timeout)
Definition: cardutil.cpp:2048
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:2082
void SetRoot(DiSEqCDevDevice *root)
Changes the root node of the tree.
Definition: diseqc.cpp:639
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:1859
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:798
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:1544
string hostname
Definition: caa.py:17
static vector< uint > GetSchedInputList(void)
static vector< uint > GetGroupInputIDs(uint inputgroupid)
Definition: cardutil.cpp:1980
static int GetChannelValueInt(const QString &channel_field, uint sourceid, const QString &channum)
static vector< uint > GetChildInputIDs(uint inputid)
Definition: cardutil.cpp:1312
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:1244
static bool UnlinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1923
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
static QList< InputInfo > GetAllInputInfo()
Definition: cardutil.cpp:1643
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:760
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:1527
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:1288
#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:806
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:1340
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:1744
QString get_on_input(const QString &to_get, uint inputid)
Definition: cardutil.cpp:1197
QMap< int, QString > InputNames
Definition: cardutil.h:20
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1725
static bool hasV4L2(int videofd)
Definition: cardutil.cpp:2103
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:1883
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:1603
static QString ProbeDefaultDeliverySystem(const QString &device)
Definition: cardutil.cpp:657
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:950
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:1954
QString toString() const
static uint GetMinSignalMonitoringDelay(const QString &device)
Definition: cardutil.cpp:750
static uint CreateDeviceInputGroup(uint inputid, const QString &type, const QString &host, const QString &device)
Definition: cardutil.cpp:1846
static QString GetStartingChannel(uint inputid)
Definition: cardutil.cpp:1684
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:1700