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 
27 #ifdef USING_DVB
28 #include "dvbtypes.h"
29 #endif
30 
31 #ifdef USING_V4L1
32 #include <linux/videodev.h>
33 #endif
34 
35 #ifdef USING_V4L2
36 #include "v4l2util.h"
37 #endif
38 
39 #ifdef USING_HDHOMERUN
40 #include "hdhomerun.h"
41 #endif
42 
43 #ifdef USING_VBOX
44 #include "vboxutils.h"
45 #include "mythmiscutil.h"
46 #endif
47 
48 #ifdef USING_ASI
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <dveo/asi.h>
52 #include <dveo/master.h>
53 #endif
54 
55 #define LOC QString("CardUtil: ")
56 
58 {
59  QString inputTypes = "";
60 
61 #ifdef USING_DVB
62  inputTypes += "'DVB'";
63 #endif // USING_DVB
64 
65 #ifdef USING_V4L2
66  if (!inputTypes.isEmpty())
67  inputTypes += ",";
68  inputTypes += "'V4L'";
69 # ifdef USING_IVTV
70  inputTypes += ",'MPEG'";
71 # endif // USING_IVTV
72 #endif // USING_V4L2
73 
74 #ifdef USING_IPTV
75  if (!inputTypes.isEmpty())
76  inputTypes += ",";
77  inputTypes += "'FREEBOX'";
78 #endif // USING_IPTV
79 
80 #ifdef USING_VBOX
81  if (!inputTypes.isEmpty())
82  inputTypes += ",";
83  inputTypes += "'VBOX'";
84 #endif // USING_VBOX
85 
86 #ifdef USING_HDHOMERUN
87  if (!inputTypes.isEmpty())
88  inputTypes += ",";
89  inputTypes += "'HDHOMERUN'";
90 #endif // USING_HDHOMERUN
91 
92 #ifdef USING_ASI
93  if (!inputTypes.isEmpty())
94  inputTypes += ",";
95  inputTypes += "'ASI'";
96 #endif
97 
98 #ifdef USING_CETON
99  if (!inputTypes.isEmpty())
100  inputTypes += ",";
101  inputTypes += "'CETON'";
102 #endif // USING_CETON
103 
104 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
105  if (!inputTypes.isEmpty())
106  inputTypes += ",";
107  inputTypes += "'EXTERNAL'";
108 #endif
109 
110  if (inputTypes.isEmpty())
111  inputTypes = "'DUMMY'";
112 
113  return QString("(%1)").arg(inputTypes);
114 }
115 
117  const QString &inputType)
118 {
119  if (inputType == "HDHOMERUN")
120  {
121 #ifdef USING_HDHOMERUN
122  hdhomerun_device_t *hdhr;
123  hdhomerun_tuner_status_t status;
124  QString device = GetVideoDevice(inputid);
125  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), NULL);
126  if (!hdhr)
127  return false;
128 
129  int oob = -1;
130  oob = hdhomerun_device_get_oob_status(hdhr, NULL, &status);
131 
132  // if no OOB tuner, oob will be < 1. If no CC present, OOB
133  // status will be "none."
134  if (oob > 0 && (strncmp(status.channel, "none", 4) != 0))
135  {
136  LOG(VB_GENERAL, LOG_INFO, "Cardutil: HDHomeRun Cablecard Present.");
137  hdhomerun_device_destroy(hdhr);
138  return true;
139  }
140 
141  hdhomerun_device_destroy(hdhr);
142 
143 #endif
144  return false;
145  }
146  else if (inputType == "CETON")
147  {
148 #ifdef USING_CETON
149  // TODO FIXME implement detection of Cablecard presence
150  LOG(VB_GENERAL, LOG_INFO, "Cardutil: TODO Ceton Is Cablecard Present?");
151  return true;
152 #else
153  return false;
154 #endif
155  }
156  else
157  return false;
158 }
159 
160 bool CardUtil::HasTuner(const QString &rawtype, const QString & device)
161 {
162  if (rawtype == "DVB" || rawtype == "HDHOMERUN" ||
163  rawtype == "FREEBOX" || rawtype == "CETON" || rawtype == "VBOX")
164  return true;
165 
166 #ifdef USING_V4L2
167  if (rawtype == "V4L2ENC")
168  {
169  V4L2util v4l2(device);
170  return !v4l2 ? false : v4l2.HasTuner();
171  }
172 #endif
173 
174  if (rawtype == "EXTERNAL")
175  {
176  // TODO: query EXTERNAL for capability
177  return true;
178  }
179 
180  return false;
181 }
182 
183 bool CardUtil::IsTunerShared(uint inputidA, uint inputidB)
184 {
185  LOG(VB_GENERAL, LOG_DEBUG, QString("IsTunerShared(%1,%2)")
186  .arg(inputidA).arg(inputidB));
187 
188  MSqlQuery query(MSqlQuery::InitCon());
189  query.prepare("SELECT videodevice, hostname, cardtype "
190  "FROM capturecard "
191  "WHERE ( (cardid = :INPUTID_A) OR "
192  " (cardid = :INPUTID_B) )");
193  query.bindValue(":INPUTID_A", inputidA);
194  query.bindValue(":INPUTID_B", inputidB);
195 
196  if (!query.exec())
197  {
198  MythDB::DBError("CardUtil::is_tuner_shared", query);
199  return false;
200  }
201 
202  if (!query.next())
203  return false;
204 
205  const QString vdevice = query.value(0).toString();
206  const QString hostname = query.value(1).toString();
207  const QString inputtype = query.value(2).toString();
208 
209  if (!IsTunerSharingCapable(inputtype.toUpper()))
210  return false;
211 
212  if (!query.next())
213  return false;
214 
215  bool ret = ((vdevice == query.value(0).toString()) &&
216  (hostname == query.value(1).toString()) &&
217  (inputtype == query.value(2).toString()));
218 
219  LOG(VB_RECORD, LOG_DEBUG, QString("IsTunerShared(%1,%2) -> %3")
220  .arg(inputidA).arg(inputidB).arg(ret));
221 
222  return ret;
223 }
224 
230 bool CardUtil::IsInputTypePresent(const QString &rawtype, QString hostname)
231 {
232  if (hostname.isEmpty())
233  hostname = gCoreContext->GetHostName();
234 
235  MSqlQuery query(MSqlQuery::InitCon());
236  QString qstr =
237  "SELECT count(cardtype) "
238  "FROM capturecard "
239  "WHERE capturecard.hostname = :HOSTNAME ";
240 
241  if (!rawtype.isEmpty())
242  qstr += " AND capturecard.cardtype = :INPUTTYPE";
243 
244  query.prepare(qstr);
245 
246  if (!rawtype.isEmpty())
247  query.bindValue(":INPUTTYPE", rawtype.toUpper());
248 
249  query.bindValue(":HOSTNAME", hostname);
250 
251  if (!query.exec())
252  {
253  MythDB::DBError("CardUtil::IsInputTypePresent", query);
254  return false;
255  }
256 
257  uint count = 0;
258  if (query.next())
259  count = query.value(0).toUInt();
260 
261  return count > 0;
262 }
263 
265 {
266  InputTypes inputtypes;
267 
268  MSqlQuery query(MSqlQuery::InitCon());
269  query.prepare("SELECT DISTINCT cardtype, videodevice "
270  "FROM capturecard");
271 
272  if (!query.exec())
273  {
274  MythDB::DBError("CardUtil::GetInputTypes()", query);
275  }
276  else
277  {
278  QString cardtype;
279 
280  while (query.next())
281  {
282  cardtype = query.value(0).toString();
283  if (cardtype != "V4L2ENC")
284  inputtypes[cardtype] = "";
285 #ifdef USING_V4L2
286  else
287  {
288  V4L2util v4l2(query.value(1).toString());
289  if (v4l2.IsOpen())
290  {
291  QString driver_name = "V4L2:" + v4l2.DriverName();
292  inputtypes[driver_name] = v4l2.CardName();
293  }
294  }
295 #endif
296  }
297  }
298 
299  return inputtypes;
300 }
301 
307 QStringList CardUtil::GetVideoDevices(const QString &rawtype, QString hostname)
308 {
309  QStringList list;
310 
311  if (hostname.isEmpty())
312  hostname = gCoreContext->GetHostName();
313 
314  MSqlQuery query(MSqlQuery::InitCon());
315  QString qstr =
316  "SELECT videodevice "
317  "FROM capturecard "
318  "WHERE hostname = :HOSTNAME";
319 
320  if (!rawtype.isEmpty())
321  qstr += " AND cardtype = :INPUTTYPE";
322 
323  query.prepare(qstr);
324 
325  if (!rawtype.isEmpty())
326  query.bindValue(":INPUTTYPE", rawtype.toUpper());
327 
328  query.bindValue(":HOSTNAME", hostname);
329 
330  if (!query.exec())
331  {
332  MythDB::DBError("CardUtil::GetVideoDevices", query);
333  return list;
334  }
335 
336  QMap<QString,bool> dup;
337  while (query.next())
338  {
339  QString videodevice = query.value(0).toString();
340  if (dup[videodevice])
341  continue;
342 
343  list.push_back(videodevice);
344  dup[videodevice] = true;
345  }
346 
347  return list;
348 }
349 
350 QStringList CardUtil::ProbeVideoDevices(const QString &rawtype)
351 {
352  QStringList devs;
353 
354  if (rawtype.toUpper() == "DVB")
355  {
356  QDir dir("/dev/dvb", "adapter*", QDir::Name, QDir::Dirs);
357  const QFileInfoList il = dir.entryInfoList();
358  if (il.isEmpty())
359  return devs;
360 
361  QFileInfoList::const_iterator it = il.begin();
362 
363  for (; it != il.end(); ++it)
364  {
365  QDir subdir(it->filePath(), "frontend*", QDir::Name, QDir::Files | QDir::System);
366  const QFileInfoList subil = subdir.entryInfoList();
367  if (subil.isEmpty())
368  continue;
369 
370  QFileInfoList::const_iterator subit = subil.begin();
371  for (; subit != subil.end(); ++subit)
372  devs.push_back(subit->filePath());
373  }
374  }
375  else if (rawtype.toUpper() == "ASI")
376  {
377  QDir dir("/dev/", "asirx*", QDir::Name, QDir::System);
378  const QFileInfoList il = dir.entryInfoList();
379  if (il.isEmpty())
380  return devs;
381 
382  QFileInfoList::const_iterator it = il.begin();
383  for (; it != il.end(); ++it)
384  {
385  if (GetASIDeviceNumber(it->filePath()) >= 0)
386  {
387  devs.push_back(it->filePath());
388  continue;
389  }
390  break;
391  }
392  }
393 #ifdef USING_HDHOMERUN
394  else if (rawtype.toUpper() == "HDHOMERUN")
395  {
396  uint32_t target_ip = 0;
397  uint32_t device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
398  uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
399  const int max_count = 50;
400  hdhomerun_discover_device_t result_list[max_count];
401 
402  int result = hdhomerun_discover_find_devices_custom(
403  target_ip, device_type, device_id, result_list, max_count);
404 
405  if (result == -1)
406  {
407  LOG(VB_GENERAL, LOG_ERR, "Error finding HDHomerun devices");
408  return devs;
409  }
410 
411  if (result >= max_count)
412  {
413  LOG(VB_GENERAL, LOG_WARNING,
414  "Warning: may be > 50 HDHomerun devices");
415  }
416 
417  // Return "deviceid ipaddress" pairs
418  for (int i = 0; i < result; i++)
419  {
420  QString id = QString("%1").arg(result_list[i].device_id, 0, 16);
421  QString ip = QString("%1.%2.%3.%4")
422  .arg((result_list[i].ip_addr>>24) & 0xFF)
423  .arg((result_list[i].ip_addr>>16) & 0xFF)
424  .arg((result_list[i].ip_addr>> 8) & 0xFF)
425  .arg((result_list[i].ip_addr>> 0) & 0xFF);
426 
427  for (int tuner = 0; tuner < result_list[i].tuner_count; tuner++)
428  {
429  QString hdhrdev = id.toUpper() + " " + ip + " " +
430  QString("%1").arg(tuner);
431  devs.push_back(hdhrdev);
432  }
433  }
434  }
435 #endif // USING_HDHOMERUN
436 #ifdef USING_VBOX
437  else if (rawtype.toUpper() == "VBOX")
438  {
439  devs = VBox::probeDevices();
440  }
441 #endif // USING_VBOX
442 #ifdef USING_CETON
443  else if (rawtype.toUpper() == "CETON")
444  {
445  // TODO implement CETON probing.
446  LOG(VB_GENERAL, LOG_INFO, "CardUtil::ProbeVideoDevices: "
447  "TODO Probe Ceton devices");
448  }
449 #endif // USING_CETON
450  else
451  {
452  LOG(VB_GENERAL, LOG_ERR, QString("Raw Type: '%1' is not supported")
453  .arg(rawtype));
454  }
455 
456  return devs;
457 }
458 
459 QString CardUtil::ProbeDVBType(const QString &device)
460 {
461  QString ret = "ERROR_UNKNOWN";
462 
463  if (device.isEmpty())
464  return ret;
465 
466 #ifdef USING_DVB
467  QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
468  QByteArray dev = dvbdev.toLatin1();
469 
470  int fd_frontend = open(dev.constData(), O_RDWR | O_NONBLOCK);
471  if (fd_frontend < 0)
472  {
473  LOG(VB_GENERAL, LOG_ERR, QString("Can't open DVB frontend (%1) for %2.")
474  .arg(dvbdev).arg(device));
475  return ret;
476  }
477 
478  struct dvb_frontend_info info;
479  memset(&info, 0, sizeof(info));
480  int err = ioctl(fd_frontend, FE_GET_INFO, &info);
481  if (err < 0)
482  {
483  close(fd_frontend);
484  LOG(VB_GENERAL, LOG_ERR, QString("FE_GET_INFO ioctl failed (%1)")
485  .arg(dvbdev) + ENO);
486  return ret;
487  }
488  close(fd_frontend);
489 
490  DTVTunerType type(info.type);
491 #if HAVE_FE_CAN_2G_MODULATION
492  if (info.caps & FE_CAN_2G_MODULATION)
493  {
494  if (type == DTVTunerType::kTunerTypeDVBS1)
496  else if (type == DTVTunerType::kTunerTypeDVBT)
498  }
499 #endif // HAVE_FE_CAN_2G_MODULATION
500  ret = (type.toString() != "UNKNOWN") ? type.toString().toUpper() : ret;
501 #endif // USING_DVB
502 
503  return ret;
504 }
505 
509 QString CardUtil::ProbeDVBFrontendName(const QString &device)
510 {
511  QString ret = "ERROR_UNKNOWN";
512  (void) device;
513 
514 #ifdef USING_DVB
515  QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
516  QByteArray dev = dvbdev.toLatin1();
517  int fd_frontend = open(dev.constData(), O_RDWR | O_NONBLOCK);
518  if (fd_frontend < 0)
519  return "ERROR_OPEN";
520 
521  struct dvb_frontend_info info;
522  memset(&info, 0, sizeof(info));
523  int err = ioctl(fd_frontend, FE_GET_INFO, &info);
524  if (err < 0)
525  {
526  close(fd_frontend);
527  return "ERROR_PROBE";
528  }
529 
530  ret = info.name;
531 
532  close(fd_frontend);
533 #endif // USING_DVB
534 
535  return ret;
536 }
537 
555 bool CardUtil::HasDVBCRCBug(const QString &device)
556 {
557  QString name = ProbeDVBFrontendName(device);
558  return ((name == "VLSI VES1x93 DVB-S") || // munges PMT
559  (name == "ST STV0299 DVB-S")); // munges PAT
560 }
561 
563 {
564  QString name = ProbeDVBFrontendName(device);
565  if (name.indexOf("DVB-S") >= 0)
566  return 300;
567  if (name == "DiBcom 3000P/M-C DVB-T")
568  return 100;
569  return 25;
570 }
571 
573 {
574  QString type = GetRawInputType(inputid);
575  if ("DVB" != type)
576  return type;
577 
578  QString device = GetVideoDevice(inputid);
579 
580  if (device.isEmpty())
581  return "ERROR_OPEN";
582 
583  return ProbeDVBType(device);
584 }
585 
587 bool CardUtil::IsDVBInputType(const QString &inputType)
588 {
589  QString t = inputType.toUpper();
590  return (t == "DVB") || (t == "QAM") || (t == "QPSK") ||
591  (t == "OFDM") || (t == "ATSC") || (t == "DVB_S2");
592 }
593 
594 QString get_on_input(const QString &to_get, uint inputid)
595 {
596  MSqlQuery query(MSqlQuery::InitCon());
597  query.prepare(
598  QString("SELECT %1 ").arg(to_get) +
599  "FROM capturecard "
600  "WHERE capturecard.cardid = :INPUTID");
601  query.bindValue(":INPUTID", inputid);
602 
603  if (!query.exec())
604  MythDB::DBError("CardUtil::get_on_source", query);
605  else if (query.next())
606  return query.value(0).toString();
607 
608  return QString::null;
609 }
610 
611 bool set_on_input(const QString &to_set, uint inputid, const QString &value)
612 {
613  QString tmp = get_on_input("capturecard.cardid", inputid);
614  if (tmp.isEmpty())
615  return false;
616 
617  MSqlQuery query(MSqlQuery::InitCon());
618  query.prepare(
619  QString("UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
620  "WHERE cardid = :INPUTID");
621  query.bindValue(":INPUTID", inputid);
622  query.bindValue(":VALUE", value);
623 
624  if (query.exec())
625  return true;
626 
627  MythDB::DBError("CardUtil::set_on_input", query);
628  return false;
629 }
630 
640 vector<uint> CardUtil::GetInputIDs(QString videodevice,
641  QString rawtype,
642  QString inputname,
643  QString hostname)
644 {
645  vector<uint> list;
646 
647  if (hostname.isEmpty())
648  hostname = gCoreContext->GetHostName();
649 
650  MSqlQuery query(MSqlQuery::InitCon());
651  QString qstr =
652  "SELECT cardid "
653  "FROM capturecard "
654  "WHERE hostname = :HOSTNAME ";
655  if (!videodevice.isEmpty())
656  qstr += "AND videodevice = :DEVICE ";
657  if (!inputname.isEmpty())
658  qstr += "AND inputname = :INPUTNAME ";
659  if (!rawtype.isEmpty())
660  qstr += "AND cardtype = :INPUTTYPE ";
661  qstr += "ORDER BY cardid";
662 
663  query.prepare(qstr);
664 
665  query.bindValue(":HOSTNAME", hostname);
666  if (!videodevice.isEmpty())
667  query.bindValue(":DEVICE", videodevice);
668  if (!inputname.isEmpty())
669  query.bindValue(":INPUTNAME", inputname);
670  if (!rawtype.isEmpty())
671  query.bindValue(":INPUTTYPE", rawtype.toUpper());
672 
673  if (!query.exec())
674  MythDB::DBError("CardUtil::GetInputIDs(videodevice...)", query);
675  else
676  {
677  while (query.next())
678  list.push_back(query.value(0).toUInt());
679  }
680 
681  return list;
682 }
683 
685 {
686  if (!inputid)
687  return 0;
688 
689  MSqlQuery query(MSqlQuery::InitCon());
690  QString qstr =
691  "SELECT COUNT(*) "
692  "FROM capturecard "
693  "WHERE parentid = :INPUTID";
694 
695  query.prepare(qstr);
696  query.bindValue(":INPUTID", inputid);
697 
698  uint count = 0;
699 
700  if (!query.exec())
701  MythDB::DBError("CardUtil::GetChildInputCount()", query);
702  else if (query.next())
703  count = query.value(0).toUInt();
704 
705  return count;
706 }
707 
708 vector<uint> CardUtil::GetChildInputIDs(uint inputid)
709 {
710  vector<uint> list;
711 
712  if (!inputid)
713  return list;
714 
715  MSqlQuery query(MSqlQuery::InitCon());
716  QString qstr =
717  "SELECT cardid "
718  "FROM capturecard "
719  "WHERE parentid = :INPUTID "
720  "ORDER BY cardid";
721 
722  query.prepare(qstr);
723  query.bindValue(":INPUTID", inputid);
724 
725  if (!query.exec())
726  MythDB::DBError("CardUtil::GetChildInputIDs()", query);
727  else
728  {
729  while (query.next())
730  list.push_back(query.value(0).toUInt());
731  }
732 
733  return list;
734 }
735 
736 static uint clone_capturecard(uint src_inputid, uint orig_dst_inputid)
737 {
738  uint dst_inputid = orig_dst_inputid;
739 
740  MSqlQuery query(MSqlQuery::InitCon());
741  if (!dst_inputid)
742  {
743  query.prepare(
744  "DELETE FROM capturecard "
745  "WHERE videodevice = 'temp_dummy'");
746 
747  if (!query.exec())
748  {
749  MythDB::DBError("clone_capturecard -- delete temp", query);
750  return 0;
751  }
752 
753  query.prepare(
754  "INSERT INTO capturecard "
755  "SET videodevice = 'temp_dummy'");
756 
757  if (!query.exec())
758  {
759  MythDB::DBError("clone_capturecard -- insert temp", query);
760  return 0;
761  }
762 
763  query.prepare(
764  "SELECT cardid "
765  "FROM capturecard "
766  "WHERE videodevice = 'temp_dummy'");
767 
768  if (!query.exec())
769  {
770  MythDB::DBError("clone_capturecard -- get temp id", query);
771  return 0;
772  }
773 
774  if (!query.next())
775  {
776  LOG(VB_GENERAL, LOG_ERR, "clone_capturecard -- get temp id");
777  return 0;
778  }
779 
780  dst_inputid = query.value(0).toUInt();
781  }
782 
783  query.prepare(
784  "SELECT videodevice, audiodevice, vbidevice, "
785  " cardtype, hostname, signal_timeout, "
786  " channel_timeout, dvb_wait_for_seqstart, dvb_on_demand, "
787  " dvb_tuning_delay, dvb_diseqc_type, diseqcid, "
788  " dvb_eitscan, inputname, sourceid, "
789  " externalcommand, changer_device, changer_model, "
790  " tunechan, startchan, displayname, "
791  " dishnet_eit, recpriority, quicktune, "
792  " livetvorder, reclimit, "
793  // See below for special handling of the following.
794  " schedgroup, schedorder "
795  "FROM capturecard "
796  "WHERE cardid = :INPUTID");
797  query.bindValue(":INPUTID", src_inputid);
798 
799  if (!query.exec())
800  {
801  MythDB::DBError("clone_capturecard -- get data", query);
802  return 0;
803  }
804  if (!query.next())
805  {
806  LOG(VB_GENERAL, LOG_ERR, "clone_cardinput -- get data 2");
807  return 0;
808  }
809 
810  // Hangel schedgroup and schedorder specially. If schedgroup is
811  // set, schedgroup and schedorder should be false and 0,
812  // respectively, for all children.
813  bool schedgroup = query.value(26).toBool();
814  uint schedorder = query.value(27).toUInt();
815  if (schedgroup)
816  {
817  schedgroup = false;
818  schedorder = 0;
819  }
820 
821  MSqlQuery query2(MSqlQuery::InitCon());
822  query2.prepare(
823  "UPDATE capturecard "
824  "SET videodevice = :V0, "
825  " audiodevice = :V1, "
826  " vbidevice = :V2, "
827  " cardtype = :V3, "
828  " hostname = :V4, "
829  " signal_timeout = :V5, "
830  " channel_timeout = :V6, "
831  " dvb_wait_for_seqstart = :V7, "
832  " dvb_on_demand = :V8, "
833  " dvb_tuning_delay = :V9, "
834  " dvb_diseqc_type = :V10, "
835  " diseqcid = :V11,"
836  " dvb_eitscan = :V12, "
837  " inputname = :V13, "
838  " sourceid = :V14, "
839  " externalcommand = :V15, "
840  " changer_device = :V16, "
841  " changer_model = :V17, "
842  " tunechan = :V18, "
843  " startchan = :V19, "
844  " displayname = :V20, "
845  " dishnet_eit = :V21, "
846  " recpriority = :V22, "
847  " quicktune = :V23, "
848  " livetvorder = :V24, "
849  " reclimit = :V25, "
850  " schedgroup = :SCHEDGROUP, "
851  " schedorder = :SCHEDORDER, "
852  " parentid = :PARENTID "
853  "WHERE cardid = :INPUTID");
854  for (uint i = 0; i < 26; ++i)
855  query2.bindValue(QString(":V%1").arg(i), query.value(i).toString());
856  query2.bindValue(":INPUTID", dst_inputid);
857  query2.bindValue(":PARENTID", src_inputid);
858  query2.bindValue(":SCHEDGROUP", schedgroup);
859  query2.bindValue(":SCHEDORDER", schedorder);
860 
861  if (!query2.exec())
862  {
863  MythDB::DBError("clone_capturecard -- save data", query2);
864  if (!orig_dst_inputid)
865  CardUtil::DeleteCard(dst_inputid);
866  return 0;
867  }
868 
869  // copy input group linkages
870  vector<uint> src_grps = CardUtil::GetInputGroups(src_inputid);
871  vector<uint> dst_grps = CardUtil::GetInputGroups(dst_inputid);
872  for (uint j = 0; j < dst_grps.size(); j++)
873  CardUtil::UnlinkInputGroup(dst_inputid, dst_grps[j]);
874  for (uint j = 0; j < src_grps.size(); j++)
875  CardUtil::LinkInputGroup(dst_inputid, src_grps[j]);
876 
877  // clone diseqc_config (just points to the same diseqc_tree row)
878  DiSEqCDevSettings diseqc;
879  if (diseqc.Load(src_inputid))
880  diseqc.Store(dst_inputid);
881 
882  return dst_inputid;
883 }
884 
885 bool CardUtil::CloneCard(uint src_inputid, uint orig_dst_inputid)
886 {
887  QString type = CardUtil::GetRawInputType(src_inputid);
888  if (!IsTunerSharingCapable(type))
889  return false;
890 
891  uint dst_inputid = clone_capturecard(src_inputid, orig_dst_inputid);
892  if (!dst_inputid)
893  return false;
894 
895  return true;
896 }
897 
899 {
900  QString fwnode;
901 
902  MSqlQuery query(MSqlQuery::InitCon());
903  query.prepare("SELECT changer_device "
904  "FROM capturecard WHERE cardid = :INPUTID ");
905  query.bindValue(":INPUTID", inputid);
906 
907  if (query.exec() && query.next())
908  {
909  fwnode = query.value(0).toString();
910  }
911 
912  return fwnode;
913 }
914 
916 {
917  QString fwnode;
918 
919  MSqlQuery query(MSqlQuery::InitCon());
920  query.prepare("SELECT changer_model "
921  "FROM capturecard WHERE cardid = :INPUTID ");
922  query.bindValue(":INPUTID", inputid);
923 
924  if (query.exec() && query.next())
925  {
926  fwnode = query.value(0).toString();
927  }
928 
929  return fwnode;
930 }
931 
932 vector<uint> CardUtil::GetInputIDs(uint sourceid)
933 {
934  MSqlQuery query(MSqlQuery::InitCon());
935 
936  query.prepare(
937  "SELECT DISTINCT cardid "
938  "FROM capturecard "
939  "WHERE sourceid = :SOURCEID");
940  query.bindValue(":SOURCEID", sourceid);
941 
942  vector<uint> list;
943 
944  if (!query.exec())
945  {
946  MythDB::DBError("CardUtil::GetInputIDs()", query);
947  return list;
948  }
949 
950  while (query.next())
951  list.push_back(query.value(0).toUInt());
952 
953  return list;
954 }
955 
956 bool CardUtil::SetStartChannel(uint inputid, const QString &channum)
957 {
958  MSqlQuery query(MSqlQuery::InitCon());
959  query.prepare("UPDATE capturecard "
960  "SET startchan = :CHANNUM "
961  "WHERE cardid = :INPUTID");
962  query.bindValue(":CHANNUM", channum);
963  query.bindValue(":INPUTID", inputid);
964 
965  if (!query.exec())
966  {
967  MythDB::DBError("set_startchan", query);
968  return false;
969  }
970 
971  return true;
972 }
973 
974 bool CardUtil::GetInputInfo(InputInfo &input, vector<uint> *groupids)
975 {
976  if (!input.inputid)
977  return false;
978 
979  MSqlQuery query(MSqlQuery::InitCon());
980  query.prepare("SELECT "
981  "inputname, sourceid, livetvorder, "
982  "schedorder, displayname, recpriority, quicktune "
983  "FROM capturecard "
984  "WHERE cardid = :INPUTID");
985  query.bindValue(":INPUTID", input.inputid);
986 
987  if (!query.exec())
988  {
989  MythDB::DBError("CardUtil::GetInputInfo()", query);
990  return false;
991  }
992 
993  if (!query.next())
994  return false;
995 
996  input.name = query.value(0).toString();
997  input.sourceid = query.value(1).toUInt();
998  input.livetvorder = query.value(2).toUInt();
999  input.scheduleOrder = query.value(3).toUInt();
1000  input.displayName = query.value(4).toString();
1001  input.recPriority = query.value(5).toInt();
1002  input.quickTune = query.value(6).toBool();
1003 
1004  if (input.displayName.isEmpty())
1005  input.displayName = QObject::tr("Input %1:%2")
1006  .arg(input.inputid).arg(input.name);
1007 
1008  if (groupids)
1009  *groupids = GetInputGroups(input.inputid);
1010 
1011  return true;
1012 }
1013 
1014 QList<InputInfo> CardUtil::GetAllInputInfo()
1015 {
1016  QList<InputInfo> infoInputList;
1017 
1018  MSqlQuery query(MSqlQuery::InitCon());
1019  query.prepare("SELECT cardid, "
1020  "inputname, sourceid, livetvorder, "
1021  "schedorder, displayname, recpriority, quicktune "
1022  "FROM capturecard");
1023 
1024  if (!query.exec())
1025  {
1026  MythDB::DBError("CardUtil::GetAllInputInfo()", query);
1027  return infoInputList;
1028  }
1029 
1030  while (query.next())
1031  {
1032  InputInfo input;
1033  input.inputid = query.value(0).toUInt();
1034  input.name = query.value(1).toString();
1035  input.sourceid = query.value(2).toUInt();
1036  input.livetvorder = query.value(3).toUInt();
1037  input.scheduleOrder = query.value(4).toUInt();
1038  input.displayName = query.value(5).toString();
1039  input.recPriority = query.value(6).toInt();
1040  input.quickTune = query.value(7).toBool();
1041 
1042  infoInputList.push_back(input);
1043  }
1044 
1045  return infoInputList;
1046 }
1047 
1049 {
1050  InputInfo info("None", 0, inputid, 0, 0, 0);
1051  GetInputInfo(info);
1052  return info.name;
1053 }
1054 
1056 {
1057  MSqlQuery query(MSqlQuery::InitCon());
1058  query.prepare("SELECT startchan "
1059  "FROM capturecard "
1060  "WHERE cardid = :INPUTID");
1061  query.bindValue(":INPUTID", inputid);
1062 
1063  if (!query.exec())
1064  MythDB::DBError("CardUtil::GetStartingChannel(uint)", query);
1065  else if (query.next())
1066  return query.value(0).toString();
1067 
1068  return QString::null;
1069 }
1070 
1072 {
1073  if (!inputid)
1074  return QString::null;
1075 
1076  MSqlQuery query(MSqlQuery::InitCon());
1077  query.prepare("SELECT displayname, cardid, cardtype, inputname "
1078  "FROM capturecard "
1079  "WHERE cardid = :INPUTID");
1080  query.bindValue(":INPUTID", inputid);
1081 
1082  if (!query.exec())
1083  MythDB::DBError("CardUtil::GetDisplayName(uint)", query);
1084  else if (query.next())
1085  {
1086  QString result = query.value(0).toString();
1087  if (result.isEmpty())
1088  result = QString("%1: %2/%3").arg(query.value(1).toInt())
1089  .arg(query.value(2).toString()).arg(query.value(3).toString());
1090  return result;
1091  }
1092 
1093  return QString::null;
1094 }
1095 
1097 {
1098  MSqlQuery query(MSqlQuery::InitCon());
1099  query.prepare(
1100  "SELECT sourceid "
1101  "FROM capturecard "
1102  "WHERE cardid = :INPUTID");
1103  query.bindValue(":INPUTID", inputid);
1104  if (!query.exec() || !query.isActive())
1105  MythDB::DBError("CardUtil::GetSourceID()", query);
1106  else if (query.next())
1107  return query.value(0).toUInt();
1108 
1109  return 0;
1110 }
1111 
1113  const uint sourceid,
1114  const QString &inputname,
1115  const QString &externalcommand,
1116  const QString &changer_device,
1117  const QString &changer_model,
1118  const QString &hostname,
1119  const QString &tunechan,
1120  const QString &startchan,
1121  const QString &displayname,
1122  bool dishnet_eit,
1123  const uint recpriority,
1124  const uint quicktune,
1125  const uint schedorder,
1126  const uint livetvorder)
1127 {
1128  MSqlQuery query(MSqlQuery::InitCon());
1129 
1130  query.prepare(
1131  "UPDATE capturecard "
1132  "SET sourceid = :SOURCEID, "
1133  " inputname = :INPUTNAME, "
1134  " externalcommand = :EXTERNALCOMMAND, "
1135  " changer_device = :CHANGERDEVICE, "
1136  " changer_model = :CHANGERMODEL, "
1137  " tunechan = :TUNECHAN, "
1138  " startchan = :STARTCHAN, "
1139  " displayname = :DISPLAYNAME, "
1140  " dishnet_eit = :DISHNETEIT, "
1141  " recpriority = :RECPRIORITY, "
1142  " quicktune = :QUICKTUNE, "
1143  " schedorder = :SCHEDORDER, "
1144  " livetvorder = :LIVETVORDER "
1145  "WHERE cardid = :INPUTID AND "
1146  " inputname = 'None'");
1147 
1148  query.bindValue(":INPUTID", inputid);
1149  query.bindValue(":SOURCEID", sourceid);
1150  query.bindValue(":INPUTNAME", inputname);
1151  query.bindValue(":EXTERNALCOMMAND", externalcommand);
1152  query.bindValue(":CHANGERDEVICE", changer_device);
1153  query.bindValue(":CHANGERMODEL", changer_model);
1154  query.bindValue(":TUNECHAN", tunechan);
1155  query.bindValue(":STARTCHAN", startchan);
1156  query.bindValue(":DISPLAYNAME", displayname.isNull() ? "" : displayname);
1157  query.bindValue(":DISHNETEIT", dishnet_eit);
1158  query.bindValue(":RECPRIORITY", recpriority);
1159  query.bindValue(":QUICKTUNE", quicktune);
1160  query.bindValue(":SCHEDORDER", schedorder);
1161  query.bindValue(":LIVETVORDER", livetvorder);
1162 
1163  if (!query.exec())
1164  {
1165  MythDB::DBError("CreateCardInput", query);
1166  return -1;
1167  }
1168 
1169  return inputid;
1170 }
1171 
1173 {
1174  MSqlQuery query(MSqlQuery::InitCon());
1175  query.prepare(
1176  "UPDATE capturecard "
1177  "SET sourceid = 0, "
1178  " inputname = 'None', "
1179  " externalcommand = '', "
1180  " changer_device = '', "
1181  " changer_model = '', "
1182  " tunechan = '', "
1183  " startchan = '', "
1184  " displayname = '', "
1185  " dishnet_eit = 0, "
1186  " recpriority = 0, "
1187  " quicktune = 0, "
1188  " schedorder = 1, "
1189  " livetvorder = 1 "
1190  "WHERE cardid = :INPUTID");
1191  query.bindValue(":INPUTID", inputid);
1192 
1193  if (!query.exec())
1194  {
1195  MythDB::DBError("DeleteInput", query);
1196  return false;
1197  }
1198 
1199  query.prepare("DELETE FROM inputgroup "
1200  "WHERE cardinputid = :INPUTID AND "
1201  " inputgroupname LIKE 'user:%'");
1202  query.bindValue(":INPUTID", inputid);
1203 
1204  if (!query.exec())
1205  {
1206  MythDB::DBError("DeleteInput2", query);
1207  return false;
1208  }
1209 
1210  return true;
1211 }
1212 
1214 {
1215  MSqlQuery query(MSqlQuery::InitCon());
1216 
1217  query.prepare("SELECT inputgroupid FROM inputgroup "
1218  "WHERE inputgroupname = :GROUPNAME "
1219  "LIMIT 1");
1220  query.bindValue(":GROUPNAME", name);
1221  if (!query.exec())
1222  {
1223  MythDB::DBError("CreateNewInputGroup 0", query);
1224  return 0;
1225  }
1226 
1227  if (query.next())
1228  return query.value(0).toUInt();
1229 
1230  query.prepare("SELECT MAX(inputgroupid) FROM inputgroup");
1231  if (!query.exec())
1232  {
1233  MythDB::DBError("CreateNewInputGroup 1", query);
1234  return 0;
1235  }
1236 
1237  uint inputgroupid = (query.next()) ? query.value(0).toUInt() + 1 : 1;
1238 
1239  query.prepare(
1240  "INSERT INTO inputgroup "
1241  " (cardinputid, inputgroupid, inputgroupname) "
1242  "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
1243  query.bindValue(":INPUTID", 0);
1244  query.bindValue(":GROUPID", inputgroupid);
1245  query.bindValue(":GROUPNAME", name);
1246  if (!query.exec())
1247  {
1248  MythDB::DBError("CreateNewInputGroup 2", query);
1249  return 0;
1250  }
1251 
1252  return inputgroupid;
1253 }
1254 
1256  const QString &type,
1257  const QString &host,
1258  const QString &device)
1259 {
1260  QString name = host + '|' + device;
1261  if (type == "FREEBOX" || type == "IMPORT" ||
1262  type == "DEMO" || type == "EXTERNAL")
1263  name += QString("|%1").arg(inputid);
1264  return CreateInputGroup(name);
1265 }
1266 
1268 {
1269  MSqlQuery query(MSqlQuery::InitCon());
1270  query.prepare(
1271  "SELECT inputgroupid "
1272  "FROM inputgroup "
1273  "WHERE cardinputid = :INPUTID "
1274  " AND inputgroupname REGEXP '^[a-z_-]*\\\\|'");
1275  query.bindValue(":INPUTID", inputid);
1276 
1277  if (!query.exec())
1278  {
1279  MythDB::DBError("CardUtil::GetDeviceInputGroup()", query);
1280  return false;
1281  }
1282 
1283  if (query.next())
1284  {
1285  return query.value(0).toUInt();
1286  }
1287 
1288  return 0;
1289 }
1290 
1291 bool CardUtil::LinkInputGroup(uint inputid, uint inputgroupid)
1292 {
1293  MSqlQuery query(MSqlQuery::InitCon());
1294 
1295  query.prepare(
1296  "SELECT cardinputid, inputgroupid, inputgroupname "
1297  "FROM inputgroup "
1298  "WHERE inputgroupid = :GROUPID "
1299  "ORDER BY inputgroupid, cardinputid, inputgroupname");
1300  query.bindValue(":GROUPID", inputgroupid);
1301 
1302  if (!query.exec())
1303  {
1304  MythDB::DBError("CardUtil::CreateInputGroup() 1", query);
1305  return false;
1306  }
1307 
1308  if (!query.next())
1309  return false;
1310 
1311  const QString name = query.value(2).toString();
1312 
1313  query.prepare(
1314  "INSERT INTO inputgroup "
1315  " (cardinputid, inputgroupid, inputgroupname) "
1316  "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
1317 
1318  query.bindValue(":INPUTID", inputid);
1319  query.bindValue(":GROUPID", inputgroupid);
1320  query.bindValue(":GROUPNAME", name);
1321 
1322  if (!query.exec())
1323  {
1324  MythDB::DBError("CardUtil::CreateInputGroup() 2", query);
1325  return false;
1326  }
1327 
1328  return true;
1329 }
1330 
1331 bool CardUtil::UnlinkInputGroup(uint inputid, uint inputgroupid)
1332 {
1333  MSqlQuery query(MSqlQuery::InitCon());
1334 
1335  if (!inputid && !inputgroupid)
1336  {
1337  query.prepare(
1338  "DELETE FROM inputgroup "
1339  "WHERE cardinputid NOT IN "
1340  "( SELECT cardid FROM capturecard )");
1341  }
1342  else
1343  {
1344  query.prepare(
1345  "DELETE FROM inputgroup "
1346  "WHERE cardinputid = :INPUTID AND "
1347  " inputgroupid = :GROUPID ");
1348 
1349  query.bindValue(":INPUTID", inputid);
1350  query.bindValue(":GROUPID", inputgroupid);
1351  }
1352 
1353  if (!query.exec())
1354  {
1355  MythDB::DBError("CardUtil::DeleteInputGroup()", query);
1356  return false;
1357  }
1358 
1359  return true;
1360 }
1361 
1362 vector<uint> CardUtil::GetInputGroups(uint inputid)
1363 {
1364  vector<uint> list;
1365 
1366  MSqlQuery query(MSqlQuery::InitCon());
1367 
1368  query.prepare(
1369  "SELECT inputgroupid "
1370  "FROM inputgroup "
1371  "WHERE cardinputid = :INPUTID "
1372  "ORDER BY inputgroupid, cardinputid, inputgroupname");
1373 
1374  query.bindValue(":INPUTID", inputid);
1375 
1376  if (!query.exec())
1377  {
1378  MythDB::DBError("CardUtil::GetInputGroups()", query);
1379  return list;
1380  }
1381 
1382  while (query.next())
1383  list.push_back(query.value(0).toUInt());
1384 
1385  return list;
1386 }
1387 
1388 vector<uint> CardUtil::GetGroupInputIDs(uint inputgroupid)
1389 {
1390  vector<uint> list;
1391 
1392  MSqlQuery query(MSqlQuery::InitCon());
1393 
1394  query.prepare(
1395  "SELECT DISTINCT cardid "
1396  "FROM capturecard, inputgroup "
1397  "WHERE inputgroupid = :GROUPID AND "
1398  " capturecard.cardid = inputgroup.cardinputid "
1399  "ORDER BY cardid");
1400 
1401  query.bindValue(":GROUPID", inputgroupid);
1402 
1403  if (!query.exec())
1404  {
1405  MythDB::DBError("CardUtil::GetGroupInputIDs()", query);
1406  return list;
1407  }
1408 
1409  while (query.next())
1410  list.push_back(query.value(0).toUInt());
1411 
1412  return list;
1413 }
1414 
1416 {
1417  LOG(VB_RECORD, LOG_INFO,
1418  LOC + QString("GetConflictingInputs() input %1").arg(inputid));
1419 
1420  vector<uint> inputids;
1421 
1422  MSqlQuery query(MSqlQuery::InitCon());
1423 
1424  query.prepare(
1425  "SELECT DISTINCT c.cardid "
1426  "FROM ( "
1427  " SELECT inputgroupid "
1428  " FROM inputgroup "
1429  " WHERE cardinputid = :INPUTID1 "
1430  ") g "
1431  "JOIN inputgroup ig ON ig.inputgroupid = g.inputgroupid "
1432  "JOIN capturecard c ON c.cardid = ig.cardinputid "
1433  " AND c.cardid <> :INPUTID2 "
1434  "ORDER BY c.cardid");
1435 
1436  query.bindValue(":INPUTID1", inputid);
1437  query.bindValue(":INPUTID2", inputid);
1438 
1439  if (!query.exec())
1440  {
1441  MythDB::DBError("CardUtil::GetConflictingInputs()", query);
1442  return inputids;
1443  }
1444 
1445  while (query.next())
1446  {
1447  inputids.push_back(query.value(0).toUInt());
1448  LOG(VB_RECORD, LOG_INFO,
1449  LOC + QString("GetConflictingInputs() got input %1").arg(inputids.back()));
1450  }
1451 
1452  return inputids;
1453 }
1454 
1456  uint &signal_timeout, uint &channel_timeout)
1457 {
1458  MSqlQuery query(MSqlQuery::InitCon());
1459  query.prepare(
1460  "SELECT signal_timeout, channel_timeout "
1461  "FROM capturecard "
1462  "WHERE cardid = :INPUTID");
1463  query.bindValue(":INPUTID", inputid);
1464 
1465  if (!query.exec() || !query.isActive())
1466  MythDB::DBError("CardUtil::GetTimeouts()", query);
1467  else if (query.next())
1468  {
1469  signal_timeout = (uint) max(query.value(0).toInt(), 250);
1470  channel_timeout = (uint) max(query.value(1).toInt(), 500);
1471  return true;
1472  }
1473 
1474  return false;
1475 }
1476 
1478 {
1479  DiSEqCDev dev;
1480  DiSEqCDevTree *diseqc_tree = dev.FindTree(inputid);
1481 
1482  bool needsConf = false;
1483  if (diseqc_tree)
1484  needsConf = diseqc_tree->IsInNeedOfConf();
1485 
1486  return needsConf;
1487 }
1488 
1489 uint CardUtil::GetQuickTuning(uint inputid, const QString &input_name)
1490 {
1491  uint quicktune = 0;
1492 
1493  MSqlQuery query(MSqlQuery::InitCon());
1494  query.prepare(
1495  "SELECT quicktune "
1496  "FROM capturecard "
1497  "WHERE cardid = :INPUTID AND "
1498  " inputname = :INPUTNAME");
1499  query.bindValue(":INPUTID", inputid);
1500  query.bindValue(":INPUTNAME", input_name);
1501 
1502  if (!query.exec() || !query.isActive())
1503  MythDB::DBError("CardUtil::GetQuickTuning()", query);
1504  else if (query.next())
1505  quicktune = query.value(0).toUInt();
1506 
1507  return quicktune;
1508 }
1509 
1510 bool CardUtil::hasV4L2(int videofd)
1511 {
1512  (void) videofd;
1513 #ifdef USING_V4L2
1514  struct v4l2_capability vcap;
1515  memset(&vcap, 0, sizeof(vcap));
1516 
1517  return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
1518  (vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE));
1519 #else // if !USING_V4L2
1520  return false;
1521 #endif // !USING_V4L2
1522 }
1523 
1525  int videofd, QString &input, QString &driver, uint32_t &version,
1526  uint32_t &capabilities)
1527 {
1528  input = driver = QString::null;
1529  version = 0;
1530  capabilities = 0;
1531 
1532  if (videofd < 0)
1533  return false;
1534 
1535 #ifdef USING_V4L2
1536  // First try V4L2 query
1537  struct v4l2_capability capability;
1538  memset(&capability, 0, sizeof(struct v4l2_capability));
1539  if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
1540  {
1541  input = QString::fromLatin1((const char*)capability.card);
1542  driver = QString::fromLatin1((const char*)capability.driver);
1543  version = capability.version;
1544  capabilities = capability.capabilities;
1545  }
1546 #ifdef USING_V4L1
1547  else // Fallback to V4L1 query
1548  {
1549  struct video_capability capability;
1550  if (ioctl(videofd, VIDIOCGCAP, &capability) >= 0)
1551  input = QString::fromLatin1((const char*)capability.name);
1552  }
1553 #endif // USING_V4L1
1554 #endif // USING_V4L2
1555 
1556  if (!driver.isEmpty())
1557  driver.remove( QRegExp("\\[[0-9]\\]$") );
1558 
1559  return !input.isEmpty();
1560 }
1561 
1563 {
1564  (void) videofd;
1565 
1566  InputNames list;
1567  ok = false;
1568 
1569 #ifdef USING_V4L2
1570  bool usingv4l2 = hasV4L2(videofd);
1571 
1572  // V4L v2 query
1573  struct v4l2_input vin;
1574  memset(&vin, 0, sizeof(vin));
1575  while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
1576  {
1577  QString input((char *)vin.name);
1578  list[vin.index] = input;
1579  vin.index++;
1580  }
1581  if (vin.index)
1582  {
1583  ok = true;
1584  return list;
1585  }
1586 
1587 #ifdef USING_V4L1
1588  // V4L v1 query
1589  struct video_capability vidcap;
1590  memset(&vidcap, 0, sizeof(vidcap));
1591  if (ioctl(videofd, VIDIOCGCAP, &vidcap) != 0)
1592  {
1593  QString msg = QObject::tr("Could not query inputs.");
1594  LOG(VB_GENERAL, LOG_ERR, "ProbeV4LVideoInputs(): Error, " + msg + ENO);
1595  list[-1] = msg;
1596  vidcap.channels = 0;
1597  }
1598 
1599  for (int i = 0; i < vidcap.channels; i++)
1600  {
1601  struct video_channel test;
1602  memset(&test, 0, sizeof(test));
1603  test.channel = i;
1604 
1605  if (ioctl(videofd, VIDIOCGCHAN, &test) != 0)
1606  {
1607  LOG(VB_GENERAL, LOG_ERR, "ProbeV4LVideoInputs(): Error, " +
1608  QString("Could determine name of input #%1"
1609  "\n\t\t\tNot adding it to the list.")
1610  .arg(test.channel) + ENO);
1611  continue;
1612  }
1613 
1614  list[i] = test.name;
1615  }
1616 #endif // USING_V4L1
1617 
1618  // Create an input when none are advertised
1619  if (list.isEmpty())
1620  list[0] = "Television";
1621 
1622  ok = true;
1623 #else // if !USING_V4L2
1624  list[-1] += QObject::tr("ERROR, Compile with V4L support to query inputs");
1625 #endif // !USING_V4L2
1626  return list;
1627 }
1628 
1630 {
1631  (void) videofd;
1632 
1633  InputNames list;
1634  ok = false;
1635 
1636 #ifdef USING_V4L2
1637  bool usingv4l2 = hasV4L2(videofd);
1638 
1639  // V4L v2 query
1640  struct v4l2_audio ain;
1641  memset(&ain, 0, sizeof(ain));
1642  while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMAUDIO, &ain) >= 0))
1643  {
1644  QString input((char *)ain.name);
1645  list[ain.index] = input;
1646  ain.index++;
1647  }
1648  if (ain.index)
1649  {
1650  ok = true;
1651  return list;
1652  }
1653 
1654  ok = true;
1655 #else // if !USING_V4L2
1656  list[-1] += QObject::tr(
1657  "ERROR, Compile with V4L support to query audio inputs");
1658 #endif // !USING_V4L2
1659  return list;
1660 }
1661 
1663 {
1664  InputNames list;
1665  MSqlQuery query(MSqlQuery::InitCon());
1666  query.prepare(
1667  "SELECT cardid, inputname "
1668  "FROM capturecard "
1669  "WHERE hostname = :HOSTNAME "
1670  " AND videodevice = :DEVICE "
1671  " AND parentid = 0 "
1672  " AND inputname <> 'None'");
1673  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
1674  query.bindValue(":DEVICE", device);
1675 
1676  if (!query.exec() || !query.isActive())
1677  MythDB::DBError("CardUtil::GetConfiguredDVBInputs", query);
1678  else
1679  {
1680  while (query.next())
1681  list[query.value(0).toUInt()] = query.value(1).toString();
1682  }
1683  return list;
1684 }
1685 
1686 QStringList CardUtil::ProbeVideoInputs(QString device, QString inputtype)
1687 {
1688  QStringList ret;
1689 
1690  if (IsSingleInputType(inputtype))
1691  ret += "MPEG2TS";
1692  else if ("DVB" == inputtype)
1693  ret += ProbeDVBInputs(device);
1694  else
1695  ret += ProbeV4LVideoInputs(device);
1696 
1697  return ret;
1698 }
1699 
1700 QStringList CardUtil::ProbeAudioInputs(QString device, QString inputtype)
1701 {
1702  LOG(VB_GENERAL, LOG_DEBUG, QString("ProbeAudioInputs(%1,%2)")
1703  .arg(device).arg(inputtype));
1704  QStringList ret;
1705 
1706  if ("HDPVR" == inputtype ||
1707  "V4L2" == inputtype)
1708  ret += ProbeV4LAudioInputs(device);
1709 
1710  return ret;
1711 }
1712 
1713 QStringList CardUtil::ProbeV4LVideoInputs(QString device)
1714 {
1715  bool ok;
1716  QStringList ret;
1717  QByteArray dev = device.toLatin1();
1718  int videofd = open(dev.constData(), O_RDWR);
1719  if (videofd < 0)
1720  {
1721  ret += QObject::tr("Could not open '%1' "
1722  "to probe its inputs.").arg(device);
1723  return ret;
1724  }
1725  InputNames list = CardUtil::ProbeV4LVideoInputs(videofd, ok);
1726  close(videofd);
1727 
1728  if (!ok)
1729  {
1730  ret += list[-1];
1731  return ret;
1732  }
1733 
1734  InputNames::iterator it;
1735  for (it = list.begin(); it != list.end(); ++it)
1736  {
1737  if (it.key() >= 0)
1738  ret += *it;
1739  }
1740 
1741  return ret;
1742 }
1743 
1744 QStringList CardUtil::ProbeV4LAudioInputs(QString device)
1745 {
1746  LOG(VB_GENERAL, LOG_DEBUG, QString("ProbeV4LAudioInputs(%1)").arg(device));
1747 
1748  bool ok;
1749  QStringList ret;
1750  int videofd = open(device.toLatin1().constData(), O_RDWR);
1751  if (videofd < 0)
1752  {
1753  LOG(VB_GENERAL, LOG_ERR, "ProbeAudioInputs() -> couldn't open device");
1754  ret += QObject::tr("Could not open '%1' to probe its inputs.")
1755  .arg(device);
1756  return ret;
1757  }
1758  InputNames list = CardUtil::ProbeV4LAudioInputs(videofd, ok);
1759  close(videofd);
1760 
1761  if (!ok)
1762  {
1763  ret += list[-1];
1764  return ret;
1765  }
1766 
1767  InputNames::iterator it;
1768  for (it = list.begin(); it != list.end(); ++it)
1769  {
1770  if (it.key() >= 0)
1771  ret += *it;
1772  }
1773 
1774  return ret;
1775 }
1776 
1777 QStringList CardUtil::ProbeDVBInputs(QString device)
1778 {
1779  QStringList ret;
1780 
1781 #ifdef USING_DVB
1782  InputNames list = GetConfiguredDVBInputs(device);
1783  InputNames::iterator it;
1784  for (it = list.begin(); it != list.end(); ++it)
1785  {
1786  if (it.key())
1787  ret += *it;
1788  }
1789 #else
1790  (void) device;
1791  ret += QObject::tr("ERROR, Compile with DVB support to query inputs");
1792 #endif
1793 
1794  return ret;
1795 }
1796 
1797 QString CardUtil::GetDeviceLabel(const QString &inputtype,
1798  const QString &videodevice)
1799 {
1800  return QString("[ %1 : %2 ]").arg(inputtype).arg(videodevice);
1801 }
1802 
1804 {
1805  QString devlabel;
1806  MSqlQuery query(MSqlQuery::InitCon());
1807  query.prepare("SELECT cardtype, videodevice "
1808  "FROM capturecard WHERE cardid = :INPUTID ");
1809  query.bindValue(":INPUTID", inputid);
1810 
1811  if (query.exec() && query.next())
1812  {
1813  return GetDeviceLabel(query.value(0).toString(),
1814  query.value(1).toString());
1815  }
1816 
1817  return "[ UNKNOWN ]";
1818 }
1819 
1821  uint inputid,
1822  const QString &device,
1823  const QString &inputtype,
1824  QStringList &inputs)
1825 {
1826  inputs.clear();
1827  if (IsSingleInputType(inputtype))
1828  inputs += "MPEG2TS";
1829  else if (inputtype == "DVB")
1830  inputs += "DVBInput";
1831  else
1832  inputs += ProbeV4LVideoInputs(device);
1833 }
1834 
1835 int CardUtil::CreateCaptureCard(const QString &videodevice,
1836  const QString &audiodevice,
1837  const QString &vbidevice,
1838  const QString &inputtype,
1839  const uint audioratelimit,
1840  const QString &hostname,
1841  const uint dvb_swfilter,
1842  const uint dvb_sat_type,
1843  bool dvb_wait_for_seqstart,
1844  bool skipbtaudio,
1845  bool dvb_on_demand,
1846  const uint dvb_diseqc_type,
1847  const uint firewire_speed,
1848  const QString &firewire_model,
1849  const uint firewire_connection,
1850  const uint signal_timeout,
1851  const uint channel_timeout,
1852  const uint dvb_tuning_delay,
1853  const uint contrast,
1854  const uint brightness,
1855  const uint colour,
1856  const uint hue,
1857  const uint diseqcid,
1858  bool dvb_eitscan)
1859 {
1860  MSqlQuery query(MSqlQuery::InitCon());
1861 
1862  query.prepare(
1863  "INSERT INTO capturecard "
1864  "(videodevice, audiodevice, vbidevice, cardtype, "
1865  "audioratelimit, hostname, dvb_swfilter, dvb_sat_type, "
1866  "dvb_wait_for_seqstart, skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
1867  "firewire_speed, firewire_model, firewire_connection, signal_timeout, "
1868  "channel_timeout, dvb_tuning_delay, contrast, brightness, colour, "
1869  "hue, diseqcid, dvb_eitscan) "
1870  "VALUES (:VIDEODEVICE, :AUDIODEVICE, :VBIDEVICE, :INPUTTYPE, "
1871  ":AUDIORATELIMIT, :HOSTNAME, :DVBSWFILTER, :DVBSATTYPE, "
1872  ":DVBWAITFORSEQSTART, :SKIPBTAUDIO, :DVBONDEMAND, :DVBDISEQCTYPE, "
1873  ":FIREWIRESPEED, :FIREWIREMODEL, :FIREWIRECONNECTION, :SIGNALTIMEOUT, "
1874  ":CHANNELTIMEOUT, :DVBTUNINGDELAY, :CONTRAST, :BRIGHTNESS, :COLOUR, "
1875  ":HUE, :DISEQCID, :DVBEITSCAN ) ");
1876 
1877  query.bindValue(":VIDEODEVICE", videodevice);
1878  query.bindValue(":AUDIODEVICE", audiodevice);
1879  query.bindValue(":VBIDEVICE", vbidevice);
1880  query.bindValue(":INPUTTYPE", inputtype);
1881  query.bindValue(":AUDIORATELIMIT", audioratelimit);
1882  query.bindValue(":HOSTNAME", hostname);
1883  query.bindValue(":DVBSWFILTER", dvb_swfilter);
1884  query.bindValue(":DVBSATTYPE", dvb_sat_type);
1885  query.bindValue(":DVBWAITFORSEQSTART", dvb_wait_for_seqstart);
1886  query.bindValue(":SKIPBTAUDIO", skipbtaudio);
1887  query.bindValue(":DVBONDEMAND", dvb_on_demand);
1888  query.bindValue(":DVBDISEQCTYPE", dvb_diseqc_type);
1889  query.bindValue(":FIREWIRESPEED", firewire_speed);
1890  query.bindValue(":FIREWIREMODEL", firewire_model);
1891  query.bindValue(":FIREWIRECONNECTION", firewire_connection);
1892  query.bindValue(":SIGNALTIMEOUT", signal_timeout);
1893  query.bindValue(":CHANNELTIMEOUT", channel_timeout);
1894  query.bindValue(":DVBTUNINGDELAY", dvb_tuning_delay);
1895  query.bindValue(":CONTRAST", contrast);
1896  query.bindValue(":BRIGHTNESS", brightness);
1897  query.bindValue(":COLOUR", colour);
1898  query.bindValue(":HUE", hue);
1899  query.bindValue(":DISEQCID", diseqcid);
1900  query.bindValue(":DVBEITSCAN", dvb_eitscan);
1901 
1902  if (!query.exec())
1903  {
1904  MythDB::DBError("CreateCaptureCard", query);
1905  return -1;
1906  }
1907 
1908  query.prepare("SELECT MAX(cardid) FROM capturecard");
1909 
1910  if (!query.exec())
1911  {
1912  MythDB::DBError("CreateCaptureCard maxinput", query);
1913  return -1;
1914  }
1915 
1916  int inputid = -1; /* must be int not uint because of return type. */
1917 
1918  if (query.next())
1919  {
1920  inputid = query.value(0).toInt();
1921  uint groupid = CardUtil::CreateDeviceInputGroup(inputid, inputtype,
1922  hostname, videodevice);
1923  CardUtil::LinkInputGroup(inputid, groupid);
1924  }
1925 
1926  return inputid;
1927 }
1928 
1930 {
1931  MSqlQuery query(MSqlQuery::InitCon());
1932  bool ok = true;
1933 
1934  if (!inputid)
1935  return true;
1936 
1937  DiSEqCDevTree tree;
1938  tree.Load(inputid);
1939 
1940  // delete any clones
1941  QString rawtype = GetRawInputType(inputid);
1942  QString videodevice = GetVideoDevice(inputid);
1943  if (IsTunerSharingCapable(rawtype) && !videodevice.isEmpty())
1944  {
1945  query.prepare(
1946  "SELECT cardid "
1947  "FROM capturecard "
1948  "WHERE parentid = :INPUTID");
1949  query.bindValue(":INPUTID", inputid);
1950 
1951  if (!query.exec())
1952  {
1953  MythDB::DBError("DeleteCard -- find clone inputs", query);
1954  return false;
1955  }
1956 
1957  while (query.next())
1958  ok &= DeleteCard(query.value(0).toUInt());
1959 
1960  if (!ok)
1961  return false;
1962  }
1963 
1964  ok &= CardUtil::DeleteInput(inputid);
1965 
1966  if (!ok)
1967  return false;
1968 
1969  // actually delete the capturecard row for this input
1970  query.prepare("DELETE FROM capturecard WHERE cardid = :INPUTID");
1971  query.bindValue(":INPUTID", inputid);
1972 
1973  if (!query.exec())
1974  {
1975  MythDB::DBError("DeleteCard -- delete row", query);
1976  ok = false;
1977  }
1978 
1979  if (ok)
1980  {
1981  // Delete the diseqc tree if no more inputs reference it.
1982  if (tree.Root())
1983  {
1984  query.prepare("SELECT cardid FROM capturecard "
1985  "WHERE diseqcid = :DISEQCID LIMIT 1");
1986  query.bindValue(":DISEQCID", tree.Root()->GetDeviceID());
1987  if (!query.exec())
1988  {
1989  MythDB::DBError("DeleteCard -- find diseqc tree", query);
1990  }
1991  else if (!query.next())
1992  {
1993  tree.SetRoot(NULL);
1994  tree.Store(inputid);
1995  }
1996  }
1997 
1998  // delete any unused input groups
1999  UnlinkInputGroup(0,0);
2000  }
2001 
2002  return ok;
2003 }
2004 
2006 {
2007  MSqlQuery query(MSqlQuery::InitCon());
2008  return (query.exec("TRUNCATE TABLE inputgroup") &&
2009  query.exec("TRUNCATE TABLE diseqc_config") &&
2010  query.exec("TRUNCATE TABLE diseqc_tree") &&
2011  query.exec("TRUNCATE TABLE capturecard") &&
2012  query.exec("TRUNCATE TABLE iptv_channel"));
2013 }
2014 
2015 vector<uint> CardUtil::GetInputList(void)
2016 {
2017  vector<uint> list;
2018 
2019  MSqlQuery query(MSqlQuery::InitCon());
2020  query.prepare(
2021  "SELECT cardid "
2022  "FROM capturecard "
2023  "ORDER BY cardid");
2024 
2025  if (!query.exec())
2026  MythDB::DBError("CardUtil::GetInputList()", query);
2027  else
2028  {
2029  while (query.next())
2030  list.push_back(query.value(0).toUInt());
2031  }
2032 
2033  return list;
2034 }
2035 
2037 {
2038  vector<uint> list;
2039 
2040  MSqlQuery query(MSqlQuery::InitCon());
2041  query.prepare(
2042  "SELECT DISTINCT cardid "
2043  "FROM capturecard "
2044  "WHERE schedorder <> 0 "
2045  "ORDER BY schedorder, cardid");
2046 
2047  if (!query.exec())
2048  MythDB::DBError("CardUtil::GetSchedInputList()", query);
2049  else
2050  {
2051  while (query.next())
2052  list.push_back(query.value(0).toUInt());
2053  }
2054 
2055  return list;
2056 }
2057 
2059 {
2060  vector<uint> list;
2061 
2062  MSqlQuery query(MSqlQuery::InitCon());
2063  query.prepare(
2064  "SELECT DISTINCT cardid "
2065  "FROM capturecard "
2066  "WHERE livetvorder <> 0 "
2067  "ORDER BY livetvorder, cardid");
2068 
2069  if (!query.exec())
2070  MythDB::DBError("CardUtil::GetLiveTVInputList()", query);
2071  else
2072  {
2073  while (query.next())
2074  list.push_back(query.value(0).toUInt());
2075  }
2076 
2077  return list;
2078 }
2079 
2080 QString CardUtil::GetDeviceName(dvb_dev_type_t type, const QString &device)
2081 {
2082  QString devname = QString(device);
2083 
2084  if (DVB_DEV_FRONTEND == type)
2085  return devname;
2086  else if (DVB_DEV_DVR == type)
2087  return devname.replace(devname.indexOf("frontend"), 8, "dvr");
2088  else if (DVB_DEV_DEMUX == type)
2089  return devname.replace(devname.indexOf("frontend"), 8, "demux");
2090  else if (DVB_DEV_CA == type)
2091  return devname.replace(devname.indexOf("frontend"), 8, "ca");
2092  else if (DVB_DEV_AUDIO == type)
2093  return devname.replace(devname.indexOf("frontend"), 8, "audio");
2094  else if (DVB_DEV_VIDEO == type)
2095  return devname.replace(devname.indexOf("frontend"), 8, "video");
2096 
2097  return "";
2098 }
2099 
2109 bool CardUtil::HDHRdoesDVB(const QString &device)
2110 {
2111  (void) device;
2112 
2113 #ifdef USING_HDHOMERUN
2114  hdhomerun_device_t *hdhr;
2115  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), NULL);
2116  if (!hdhr)
2117  return false;
2118 
2119  const char *model = hdhomerun_device_get_model_str(hdhr);
2120  if (model && strstr(model, "dvb"))
2121  {
2122  hdhomerun_device_destroy(hdhr);
2123  return true;
2124  }
2125 
2126  hdhomerun_device_destroy(hdhr);
2127 
2128 #endif
2129 
2130  return false;
2131 }
2132 
2137 QString CardUtil::GetHDHRdesc(const QString &device)
2138 {
2139  QString connectErr = QObject::tr("Unable to connect to device.");
2140 
2141 #ifdef USING_HDHOMERUN
2142  bool deviceIsIP = false;
2143  uint32_t dev;
2144 
2145  if (device.contains('.')) // Simplistic check, but also allows DNS names
2146  deviceIsIP = true;
2147  else
2148  {
2149  bool validID;
2150 
2151  dev = device.toUInt(&validID, 16);
2152  if (!validID || !hdhomerun_discover_validate_device_id(dev))
2153  return QObject::tr("Invalid Device ID");
2154  }
2155  (void) deviceIsIP;
2156 
2157  LOG(VB_GENERAL, LOG_INFO, "CardUtil::GetHDHRdescription(" + device +
2158  ") - trying to locate device");
2159 
2160  hdhomerun_device_t *hdhr;
2161  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), NULL);
2162  if (!hdhr)
2163  return QObject::tr("Invalid Device ID or address.");
2164 
2165  const char *model = hdhomerun_device_get_model_str(hdhr);
2166  if (!model)
2167  {
2168  hdhomerun_device_destroy(hdhr);
2169  return connectErr;
2170  }
2171 
2172 
2173  QString description = model;
2174  char *sVersion;
2175  uint32_t iVersion;
2176 
2177  if (hdhomerun_device_get_version(hdhr, &sVersion, &iVersion))
2178  description += QObject::tr(", firmware: %2").arg(sVersion);
2179 
2180  hdhomerun_device_destroy(hdhr);
2181 
2182  return description;
2183 #else
2184 
2185  (void) device;
2186  return connectErr;
2187 #endif
2188 }
2189 
2194 QString CardUtil::GetVBoxdesc(const QString &id, const QString &ip,
2195  const QString &tunerNo, const QString &tunerType)
2196 {
2197  QString connectErr = QObject::tr("Unable to connect to device.");
2198 
2199 #ifdef USING_VBOX
2200  VBox *vbox = new VBox(ip);
2201 
2202  if (!vbox->checkConnection())
2203  {
2204  delete vbox;
2205  return connectErr;
2206  }
2207 
2208  QString version;
2209 
2210  if (!vbox->checkVersion(version))
2211  {
2212  QString apiVersionErr = QObject::tr("The VBox software version is too old (%1), we require %2")
2213  .arg(version).arg(VBOX_MIN_API_VERSION);
2214  delete vbox;
2215  return apiVersionErr;
2216 
2217  }
2218 
2219  delete vbox;
2220 
2221  return QString("V@Box TV Gateway - ID: %1, IP: %2, Tuner: %3-%4").arg(id)
2222  .arg(ip).arg(tunerNo).arg(tunerType);
2223 
2224 #else
2225  (void) id;
2226  (void) ip;
2227  (void) tunerNo;
2228  (void) tunerType;
2229 
2230  return connectErr;
2231 #endif
2232 }
2233 
2234 #ifdef USING_ASI
2235 static QString sys_dev(uint device_num, QString dev)
2236 {
2237  return QString("/sys/class/asi/asirx%1/%2").arg(device_num).arg(dev);
2238 }
2239 
2240 static QString read_sys(QString sys_dev)
2241 {
2242  QFile f(sys_dev);
2243  f.open(QIODevice::ReadOnly);
2244  QByteArray sdba = f.readAll();
2245  f.close();
2246  return sdba;
2247 }
2248 
2249 static bool write_sys(QString sys_dev, QString str)
2250 {
2251  QFile f(sys_dev);
2252  f.open(QIODevice::WriteOnly);
2253  QByteArray ba = str.toLocal8Bit();
2254  qint64 offset = 0;
2255  for (uint tries = 0; (offset < ba.size()) && tries < 5; tries++)
2256  {
2257  qint64 written = f.write(ba.data()+offset, ba.size()-offset);
2258  if (written < 0)
2259  return false;
2260  offset += written;
2261  }
2262  return true;
2263 }
2264 #endif
2265 
2266 int CardUtil::GetASIDeviceNumber(const QString &device, QString *error)
2267 {
2268 #ifdef USING_ASI
2269  // basic confirmation
2270  struct stat statbuf;
2271  memset(&statbuf, 0, sizeof(statbuf));
2272  if (stat(device.toLocal8Bit().constData(), &statbuf) < 0)
2273  {
2274  if (error)
2275  *error = QString("Unable to stat '%1'").arg(device) + ENO;
2276  return -1;
2277  }
2278 
2279  if (!S_ISCHR(statbuf.st_mode))
2280  {
2281  if (error)
2282  *error = QString("'%1' is not a character device").arg(device);
2283  return -1;
2284  }
2285 
2286  if (!(statbuf.st_rdev & 0x0080))
2287  {
2288  if (error)
2289  *error = QString("'%1' not a DVEO ASI receiver").arg(device);
2290  return -1;
2291  }
2292 
2293  int device_num = statbuf.st_rdev & 0x007f;
2294 
2295  // extra confirmation
2296  QString sys_dev_contents = read_sys(sys_dev(device_num, "dev"));
2297  QStringList sys_dev_clist = sys_dev_contents.split(":");
2298  if (2 != sys_dev_clist.size())
2299  {
2300  if (error)
2301  {
2302  *error = QString("Unable to read '%1'")
2303  .arg(sys_dev(device_num, "dev"));
2304  }
2305  return -1;
2306  }
2307  if (sys_dev_clist[0].toUInt() != (statbuf.st_rdev>>8))
2308  {
2309  if (error)
2310  *error = QString("'%1' not a DVEO ASI device").arg(device);
2311  return -1;
2312  }
2313 
2314  return device_num;
2315 #else
2316  (void) device;
2317  if (error)
2318  *error = "Not compiled with ASI support.";
2319  return -1;
2320 #endif
2321 }
2322 
2324 {
2325 #ifdef USING_ASI
2326  // get the buffer size
2327  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "bufsize"));
2328  bool ok;
2329  uint buf_size = sys_bufsize_contents.toUInt(&ok);
2330  if (!ok)
2331  {
2332  if (error)
2333  {
2334  *error = QString("Failed to read buffer size from '%1'")
2335  .arg(sys_dev(device_num, "bufsize"));
2336  }
2337  return 0;
2338  }
2339  return buf_size;
2340 #else
2341  (void) device_num;
2342  if (error)
2343  *error = "Not compiled with ASI support.";
2344  return 0;
2345 #endif
2346 }
2347 
2349 {
2350 #ifdef USING_ASI
2351  // get the buffer size
2352  QString sys_numbuffers_contents = read_sys(sys_dev(device_num, "buffers"));
2353  bool ok;
2354  uint num_buffers = sys_numbuffers_contents.toUInt(&ok);
2355  if (!ok)
2356  {
2357  if (error)
2358  {
2359  *error = QString("Failed to read num buffers from '%1'")
2360  .arg(sys_dev(device_num, "buffers"));
2361  }
2362  return 0;
2363  }
2364  return num_buffers;
2365 #else
2366  (void) device_num;
2367  if (error)
2368  *error = "Not compiled with ASI support.";
2369  return 0;
2370 #endif
2371 }
2372 
2373 int CardUtil::GetASIMode(uint device_num, QString *error)
2374 {
2375 #ifdef USING_ASI
2376  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "mode"));
2377  bool ok;
2378  uint mode = sys_bufsize_contents.toUInt(&ok);
2379  if (!ok)
2380  {
2381  if (error)
2382  {
2383  *error = QString("Failed to read mode from '%1'")
2384  .arg(sys_dev(device_num, "mode"));
2385  }
2386  return -1;
2387  }
2388  return mode;
2389 #else
2390  (void) device_num;
2391  if (error)
2392  *error = "Not compiled with ASI support.";
2393  return -1;
2394 #endif
2395 }
2396 
2397 bool CardUtil::SetASIMode(uint device_num, uint mode, QString *error)
2398 {
2399 #ifdef USING_ASI
2400  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "mode"));
2401  bool ok;
2402  uint old_mode = sys_bufsize_contents.toUInt(&ok);
2403  if (ok && old_mode == mode)
2404  return true;
2405  ok = write_sys(sys_dev(device_num, "mode"), QString("%1\n").arg(mode));
2406  if (!ok && error)
2407  {
2408  *error = QString("Failed to set mode to %1 using '%2'")
2409  .arg(mode).arg(sys_dev(device_num, "mode"));
2410  }
2411  return ok;
2412 #else
2413  (void) device_num;
2414  if (error)
2415  *error = "Not compiled with ASI support.";
2416  return false;
2417 #endif
2418 }
2419 
2425 {
2426  // should only be called if inputtype == VBOX
2427  if (!inputid )
2428  {
2429  LOG(VB_GENERAL, LOG_ERR, QString("VBOX inputid (%1) not valid, redo mythtv-setup")
2430  .arg(inputid));
2431  return false;
2432  }
2433 
2434  // get sourceid and startchan from table capturecard for inputid
2435  uint chanid = 0;
2436  chanid = ChannelUtil::GetChannelValueInt("chanid",GetSourceID(inputid),GetStartingChannel(inputid));
2437  if (!chanid)
2438  {
2439  // no chanid, presume bad setup
2440  LOG(VB_GENERAL, LOG_ERR, QString("VBOX chanid (%1) not found for inputid (%2) , redo mythtv-setup")
2441  .arg(chanid).arg(inputid));
2442  return false;
2443  }
2444 
2445  // get timeouts for inputid
2446  uint signal_timeout = 0;
2447  uint tuning_timeout = 0;
2448  if (!GetTimeouts(inputid,signal_timeout,tuning_timeout))
2449  {
2450  LOG(VB_GENERAL, LOG_ERR, QString("Failed to get timeouts for inputid (%1)")
2451  .arg(inputid));
2452  return false;
2453  }
2454 
2455  signal_timeout = signal_timeout/1000; //convert to seconds
2456 
2457  // now get url from iptv_channel table
2458  QUrl url;
2459  MSqlQuery query(MSqlQuery::InitCon());
2460  query.prepare("SELECT url "
2461  "FROM iptv_channel "
2462  "WHERE chanid = :CHANID");
2463  query.bindValue(":CHANID", chanid);
2464 
2465  if (!query.exec())
2466  MythDB::DBError("CardUtil::IsVBoxPresent url", query);
2467  else if (query.next())
2468  url = query.value(0).toString();
2469 
2470  //now get just the IP address from the url
2471  QString ip ="";
2472  ip = url.host();
2473  LOG(VB_GENERAL, LOG_INFO, QString("VBOX IP found (%1) for inputid (%2)")
2474  .arg(ip).arg(inputid));
2475 
2476  if (!ping(ip,signal_timeout))
2477  {
2478  LOG(VB_GENERAL, LOG_ERR, QString("VBOX at IP (%1) failed to respond to network ping for inputid (%2) timeout (%3)")
2479  .arg(ip).arg(inputid).arg(signal_timeout));
2480  return false;
2481  }
2482 
2483  return true;
2484 }
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:794
uint scheduleOrder
Definition: inputinfo.h:77
dvb_dev_type_t
Definition: cardutil.h:29
static bool IsTunerSharingCapable(const QString &rawtype)
Definition: cardutil.h:163
static bool HasDVBCRCBug(const QString &device)
Returns true if and only if the device munges PAT/PMT tables, and then doesn&#39;t fix the CRC...
Definition: cardutil.cpp:555
int recPriority
Definition: inputinfo.h:76
static QStringList ProbeVideoDevices(const QString &rawtype)
Definition: cardutil.cpp:350
void bindValue(const QString &placeholder, const QVariant &val)
Definition: mythdbcon.cpp:893
DVB-S device settings class.
Definition: diseqc.h:37
__u8 driver[16]
Definition: videodev2.h:386
static QString GetInputName(uint inputid)
Definition: cardutil.cpp:1048
DiSEqCDevDevice * Root(void)
Retrieves the root node in the tree.
Definition: diseqc.h:94
static uint GetASINumBuffers(uint device_num, QString *error=NULL)
Definition: cardutil.cpp:2348
static bool IsTunerShared(uint inputidA, uint inputidB)
Definition: cardutil.cpp:183
DiSEqCDevTree * FindTree(uint cardid)
Retrieve device tree.
Definition: diseqc.cpp:248
__u32 index
Definition: videodev2.h:1369
static const int kTunerTypeDVBT
static bool SetStartChannel(uint inputid, const QString &channum)
Definition: cardutil.cpp:956
static QStringList GetVideoDevices(const QString &rawtype, QString hostname=QString::null)
Returns the videodevices of the matching inputs, duplicates removed.
Definition: cardutil.cpp:307
uint GetDeviceID(void) const
Definition: diseqc.h:164
static uint CreateInputGroup(const QString &name)
Definition: cardutil.cpp:1213
static QString ProbeDVBType(const QString &device)
Definition: cardutil.cpp:459
static vector< uint > GetInputIDs(QString videodevice=QString::null, QString rawtype=QString::null, QString inputname=QString::null, QString hostname=QString::null)
Returns all inputids of inputs that uses the specified videodevice if specified, and optionally rawty...
Definition: cardutil.cpp:640
static vector< uint > GetConflictingInputs(uint inputid)
Definition: cardutil.cpp:1415
static QString GetDeviceLabel(const QString &inputtype, const QString &videodevice)
Definition: cardutil.cpp:1797
static QString ProbeSubTypeName(uint inputid)
Definition: cardutil.cpp:572
static void error(const char *str,...)
Definition: vbi.c:41
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)
Definition: cardutil.cpp:1835
uint sourceid
associated channel listings source
Definition: inputinfo.h:71
bool IsInNeedOfConf(void) const
Definition: diseqc.cpp:846
bool checkVersion(QString &version)
Definition: vboxutils.cpp:221
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:509
static QStringList ProbeDVBInputs(QString device)
Definition: cardutil.cpp:1777
static bool IsInNeedOfExternalInputConf(uint inputid)
Definition: cardutil.cpp:1477
static bool write_sys(QString sys_dev, QString str)
Definition: cardutil.cpp:2249
__u8 name[32]
Definition: videodev2.h:1673
QMap< QString, QString > InputTypes
Definition: cardutil.h:45
unsigned int uint
Definition: compat.h:136
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static bool GetInputInfo(InputInfo &info, vector< uint > *groupids=NULL)
Definition: cardutil.cpp:974
static vector< uint > GetSchedInputList(void)
Definition: cardutil.cpp:2036
bool set_on_input(const QString &to_set, uint inputid, const QString &value)
Definition: cardutil.cpp:611
static bool DeleteInput(uint inputid)
Definition: cardutil.cpp:1172
static const int kTunerTypeDVBS1
static bool HasTuner(const QString &rawtype, const QString &device)
Definition: cardutil.cpp:160
bool Load(uint card_input_id)
Loads configuration chain from DB for specified card input id.
Definition: diseqc.cpp:137
bool Store(uint cardid, const QString &device="")
Stores the device tree to the database.
Definition: diseqc.cpp:434
__u32 type
Definition: videodev2.h:1038
static QString sys_dev(uint device_num, QString dev)
Definition: cardutil.cpp:2235
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:1524
static vector< uint > GetLiveTVInputList(void)
Definition: cardutil.cpp:2058
static bool GetTimeouts(uint inputid, uint &signal_timeout, uint &channel_timeout)
Definition: cardutil.cpp:1455
QVariant value(int i) const
Definition: mythdbcon.h:182
static QString GetVBoxdesc(const QString &id, const QString &ip, const QString &tunerNo, const QString &tunerType)
Get a nicely formatted string describing the device.
Definition: cardutil.cpp:2194
QString displayName
Definition: inputinfo.h:75
voidpf uLong offset
Definition: ioapi.h:142
static const int kTunerTypeDVBS2
static QStringList ProbeAudioInputs(QString device, QString inputtype=QString::null)
Definition: cardutil.cpp:1700
const char * name
Definition: ParseText.cpp:338
static const int kTunerTypeDVBT2
struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP
Definition: videodev2.h:385
static InputNames ProbeV4LAudioInputs(int videofd, bool &ok)
Definition: cardutil.cpp:1629
void SetRoot(DiSEqCDevDevice *root)
Changes the root node of the tree.
Definition: diseqc.cpp:647
static bool IsDVBInputType(const QString &input_type)
Returns true iff the input_type is one of the DVB types.
Definition: cardutil.cpp:587
uint livetvorder
order for live TV use
Definition: inputinfo.h:78
static bool IsSingleInputType(const QString &rawtype)
Definition: cardutil.h:197
unsigned char t
Definition: ParseText.cpp:339
__u8 card[32]
Definition: videodev2.h:387
static QString GetDeviceName(dvb_dev_type_t, const QString &device)
Definition: cardutil.cpp:2080
static bool IsCableCardPresent(uint inputid, const QString &inputType)
Definition: cardutil.cpp:116
static uint GetDeviceInputGroup(uint inputid)
Definition: cardutil.cpp:1267
bool ping(const QString &host, int timeout)
Can we ping host within timeout seconds?
bool isActive(void) const
Definition: mythdbcon.h:188
bool Store(uint card_input_id) const
Stores configuration chain to DB for specified card input id.
Definition: diseqc.cpp:171
static QString GetFirewireChangerModel(uint inputid)
Definition: cardutil.cpp:915
string hostname
Definition: caa.py:17
static vector< uint > GetGroupInputIDs(uint inputgroupid)
Definition: cardutil.cpp:1388
static int GetChannelValueInt(const QString &channel_field, uint sourceid, const QString &channum)
static vector< uint > GetChildInputIDs(uint inputid)
Definition: cardutil.cpp:708
static bool UnlinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1331
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
static QList< InputInfo > GetAllInputInfo()
Definition: cardutil.cpp:1014
static InputNames GetConfiguredDVBInputs(const QString &device)
Definition: cardutil.cpp:1662
static uint GetQuickTuning(uint inputid, const QString &inputname)
Definition: cardutil.cpp:1489
static bool HDHRdoesDVB(const QString &device)
If the device is valid, check if the model does DVB.
Definition: cardutil.cpp:2109
__u32 index
Definition: videodev2.h:1672
static uint GetASIBufferSize(uint device_num, QString *error=NULL)
Definition: cardutil.cpp:2323
uint inputid
unique key in DB for this input
Definition: inputinfo.h:72
static int GetASIDeviceNumber(const QString &device, QString *error=NULL)
Definition: cardutil.cpp:2266
static QStringList ProbeVideoInputs(QString device, QString inputtype=QString::null)
Definition: cardutil.cpp:1686
static bool SetASIMode(uint device_num, uint mode, QString *error=NULL)
Definition: cardutil.cpp:2397
static bool CloneCard(uint src_inputid, uint dst_inputid)
Definition: cardutil.cpp:885
static vector< uint > GetInputList(void)
Definition: cardutil.cpp:2015
bool Load(const QString &device)
Definition: diseqc.cpp:331
static QString GetFirewireChangerNode(uint inputid)
Definition: cardutil.cpp:898
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:273
static QStringList probeDevices(void)
Definition: vboxutils.cpp:37
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:819
bool quickTune
Definition: inputinfo.h:79
static uint GetChildInputCount(uint inputid)
Definition: cardutil.cpp:684
__u32 capabilities
Definition: videodev2.h:1045
bool HasTuner(void) const
Definition: v4l2util.cpp:698
QString name
input name
Definition: inputinfo.h:70
__u8 name[32]
Definition: videodev2.h:1370
static uint clone_capturecard(uint src_inputid, uint orig_dst_inputid)
Definition: cardutil.cpp:736
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:1112
static bool IsVBoxPresent(uint inputid)
Returns true if the VBox responds to a ping.
Definition: cardutil.cpp:2424
QString get_on_input(const QString &to_get, uint inputid)
Definition: cardutil.cpp:594
static bool DeleteCard(uint inputid)
Definition: cardutil.cpp:1929
QMap< int, QString > InputNames
Definition: cardutil.h:22
static const QString LOC
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1096
static bool hasV4L2(int videofd)
Definition: cardutil.cpp:1510
const char int mode
Definition: ioapi.h:135
static QString GetRawInputType(uint inputid)
Definition: cardutil.h:271
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:619
bool checkConnection(void)
Definition: vboxutils.cpp:215
static bool LinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1291
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:181
static bool DeleteAllCards(void)
Definition: cardutil.cpp:2005
QString GetHostName(void)
__s32 value
Definition: videodev2.h:1042
static InputTypes GetInputTypes(void)
Definition: cardutil.cpp:264
DVB-S device tree class.
Definition: diseqc.h:75
QString DriverName(void) const
Definition: v4l2util.h:45
static InputNames ProbeV4LVideoInputs(int videofd, bool &ok)
Definition: cardutil.cpp:1562
__u32 capabilities
Definition: videodev2.h:390
static int GetASIMode(uint device_num, QString *error=NULL)
Definition: cardutil.cpp:2373
static bool IsInputTypePresent(const QString &rawtype, QString hostname=QString::null)
Returns true if the input type is present and connected to an input.
Definition: cardutil.cpp:230
static QString GetHDHRdesc(const QString &device)
Get a nicely formatted string describing the device.
Definition: cardutil.cpp:2137
static QString GetScanableInputTypes(void)
Definition: cardutil.cpp:57
static vector< uint > GetInputGroups(uint inputid)
Definition: cardutil.cpp:1362
QString toString() const
static uint GetMinSignalMonitoringDelay(const QString &device)
Definition: cardutil.cpp:562
static uint CreateDeviceInputGroup(uint inputid, const QString &type, const QString &host, const QString &device)
Definition: cardutil.cpp:1255
static QString GetStartingChannel(uint inputid)
Definition: cardutil.cpp:1055
Main DVB-S device interface.
Definition: diseqc.h:52
static void GetDeviceInputNames(uint inputid, const QString &device, const QString &inputtype, QStringList &inputs)
Definition: cardutil.cpp:1820
static QString read_sys(QString sys_dev)
Definition: cardutil.cpp:2240
static QString GetDisplayName(uint inputid)
Definition: cardutil.cpp:1071