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