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