MythTV  master
channelbase.cpp
Go to the documentation of this file.
1 // Std C headers
2 #include <cstdlib>
3 #include <cerrno>
4 
5 // POSIX headers
6 #include <unistd.h>
7 #include <fcntl.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 
11 // C++ headers
12 #include <iostream>
13 #include <algorithm>
14 using namespace std;
15 
16 // Qt headers
17 #include <QCoreApplication>
18 
19 // MythTV headers
20 #ifdef USING_OSX_FIREWIRE
21 #include "darwinfirewiredevice.h"
22 #endif
23 #ifdef USING_LINUX_FIREWIRE
24 #include "linuxfirewiredevice.h"
25 #endif
26 #include "firewirechannel.h"
27 #include "mythcorecontext.h"
28 #include "cetonchannel.h"
29 #include "dummychannel.h"
30 #include "tvremoteutil.h"
31 #include "channelbase.h"
32 #include "channelutil.h"
33 #include "frequencies.h"
34 #include "hdhrchannel.h"
35 #include "iptvchannel.h"
36 #include "mythlogging.h"
37 #include "asichannel.h"
38 #include "dtvchannel.h"
39 #include "dvbchannel.h"
40 #include "v4lchannel.h"
41 #include "ExternalChannel.h"
42 #include "sourceutil.h"
43 #include "exitcodes.h"
44 #include "cardutil.h"
45 #include "compat.h"
46 #include "inputinfo.h"
47 #include "satipchannel.h"
48 
49 #define LOC QString("ChannelBase[%1]: ").arg(m_inputId)
50 
52 {
53  QMutexLocker locker(&m_systemLock);
54  if (m_system)
55  KillScript();
56 }
57 
58 bool ChannelBase::Init(QString &startchannel, bool setchan)
59 {
60  bool ok = false;
61 
62  if (!setchan)
63  ok = IsTunable(startchannel);
64  else
65  ok = SetChannelByString(startchannel);
66 
67  if (ok)
68  return true;
69 
70  // try to find a valid channel if given start channel fails.
71  QString msg1 = QString("Setting start channel '%1' failed, ")
72  .arg(startchannel);
73  QString msg2 = "and we failed to find any suitable channels on any input.";
74  bool msg_error = true;
75 
76  // Attempt to find the requested startchannel
77  for (auto & channel : m_channels)
78  {
79  if (channel.m_chanNum == startchannel &&
80  IsTunable(startchannel))
81  {
82  LOG(VB_CHANNEL, LOG_INFO, LOC +
83  QString("Found startchannel '%1'").arg(startchannel));
84  return true;
85  }
86  }
87 
88  uint mplexid_restriction = 0;
89  uint chanid_restriction = 0;
90 
91  if (!m_channels.empty() &&
92  IsInputAvailable(mplexid_restriction, chanid_restriction))
93  {
95  m_channels, m_channels[0].m_chanId,
96  mplexid_restriction, chanid_restriction, CHANNEL_DIRECTION_UP);
97 
98  auto cit = find(m_channels.begin(), m_channels.end(), chanid);
99 
100  if ((chanid != 0U) && (cit != m_channels.end()))
101  {
102  if (!setchan)
103  {
104  ok = IsTunable((mplexid_restriction || chanid_restriction)
105  ? (*cit).m_chanNum : startchannel);
106  }
107  else
108  ok = SetChannelByString((*cit).m_chanNum);
109 
110  if (ok)
111  {
112  if (mplexid_restriction || chanid_restriction)
113  startchannel = (*cit).m_chanNum;
114  msg2 = QString("selected to '%1' instead.")
115  .arg(startchannel);
116  msg_error = false;
117  }
118  }
119  }
120 
121  LOG(VB_GENERAL, ((msg_error) ? LOG_ERR : LOG_WARNING), LOC +
122  msg1 + "\n\t\t\t" + msg2);
123 
124  return ok;
125 }
126 
127 bool ChannelBase::IsTunable(const QString &channum) const
128 {
129  QString loc = LOC + QString("IsTunable(%1)").arg(channum);
130 
131  if (!m_inputId)
132  {
133  LOG(VB_GENERAL, LOG_ERR, loc + " " +
134  QString("Requested non-existant input"));
135 
136  return false;
137  }
138 
139  uint mplexid_restriction = 0;
140  uint chanid_restriction = 0;
141  if (!IsInputAvailable(mplexid_restriction, chanid_restriction))
142  {
143  LOG(VB_GENERAL, LOG_ERR, loc + " " +
144  QString("Requested channel is on input '%1' "
145  "which is in a busy input group")
146  .arg(m_inputId));
147 
148  return false;
149  }
150 
151  // Fetch tuning data from the database.
152  QString tvformat;
153  QString modulation;
154  QString freqtable;
155  QString freqid;
156  QString dtv_si_std;
157  int finetune = 0;
158  uint64_t frequency = 0;
159  int mpeg_prog_num = 0;
160  uint atsc_major = 0;
161  uint atsc_minor = 0;
162  uint mplexid = 0;
163  uint chanid = 0;
164  uint tsid = 0;
165  uint netid = 0;
166  bool commfree = false;
167 
168  if (!ChannelUtil::GetChannelData(m_sourceId, chanid, channum,
169  tvformat, modulation, freqtable, freqid,
170  finetune, frequency, dtv_si_std,
171  mpeg_prog_num, atsc_major, atsc_minor,
172  tsid, netid, mplexid, commfree))
173  {
174  LOG(VB_GENERAL, LOG_ERR, loc + " " +
175  QString("Failed to find channel in DB on input '%1' ")
176  .arg(m_inputId));
177 
178  return false;
179  }
180 
181  if ((mplexid_restriction && (mplexid != mplexid_restriction)) ||
182  (!mplexid_restriction &&
183  chanid_restriction && (chanid != chanid_restriction)))
184  {
185  LOG(VB_GENERAL, LOG_ERR, loc + " " +
186  QString("Channel is valid, but tuner is busy "
187  "on different multiplex/channel (%1 != %2) / (%3 != %4)")
188  .arg(mplexid).arg(mplexid_restriction)
189  .arg(chanid).arg(chanid_restriction));
190 
191  return false;
192  }
193 
194  return true;
195 }
196 
198 {
199  if (!chanid)
200  {
201  if (!m_inputId)
202  return 0;
203 
204  chanid = ChannelUtil::GetChanID(m_sourceId, m_curChannelName);
205  }
206 
207  uint mplexid_restriction = 0;
208  uint chanid_restriction = 0;
209  (void)IsInputAvailable(mplexid_restriction, chanid_restriction);
210 
212  m_channels, chanid, mplexid_restriction, chanid_restriction,
213  direction);
214 }
215 
216 uint ChannelBase::GetNextChannel(const QString &channum, ChannelChangeDirection direction) const
217 {
218  if (!m_inputId)
219  return 0;
220 
221  uint chanid = ChannelUtil::GetChanID(m_sourceId, channum);
222  return GetNextChannel(chanid, direction);
223 }
224 
226  uint &mplexid_restriction, uint &chanid_restriction) const
227 {
228  if (!m_inputId)
229  {
230  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("no m_inputId"));
231  return false;
232  }
233 
234  InputInfo info;
235 
236  mplexid_restriction = 0;
237  chanid_restriction = 0;
238 
239  vector<uint> inputids = CardUtil::GetConflictingInputs(m_inputId);
240  for (uint inputid : inputids)
241  {
242  if (RemoteIsBusy(inputid, info))
243  {
244  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
245  QString("Input %1 is busy on %2/%3")
246  .arg(info.m_inputId)
247  .arg(info.m_chanId).arg(info.m_mplexId));
248  if (info.m_sourceId != m_sourceId)
249  {
250  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Input is busy"));
251  return false;
252  }
253  mplexid_restriction = info.m_mplexId;
254  chanid_restriction = info.m_chanId;
255  }
256  }
257 
258  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("Input is free on %1/%2")
259  .arg(mplexid_restriction).arg(chanid_restriction));
260  return true;
261 }
262 
265 {
266  if (!m_system)
267  return true;
268 
269  m_system->Term(true);
270 
271  delete m_system;
272  m_system = nullptr;
273  return true;
274 }
275 
277 void ChannelBase::HandleScript(const QString &freqid)
278 {
279  QMutexLocker locker(&m_systemLock);
280 
281  bool ok = true;
282  m_systemStatus = 0; // unknown
283 
284  if (!m_inputId)
285  {
286  m_systemStatus = 2; // failed
287  HandleScriptEnd(true);
288  return;
289  }
290 
291  if (m_externalChanger.isEmpty())
292  {
293  m_systemStatus = 3; // success
294  HandleScriptEnd(true);
295  return;
296  }
297 
298  if (freqid.isEmpty())
299  {
300  LOG(VB_GENERAL, LOG_WARNING, LOC +
301  "A channel changer is set, but the freqid field is empty."
302  "\n\t\t\tWe will return success to ease setup pains, "
303  "but no script is will actually run.");
304  m_systemStatus = 3; // success
305  HandleScriptEnd(true);
306  return;
307  }
308 
309  // It's possible we simply never reaped the process, check status first.
310  if (m_system)
311  GetScriptStatus(true);
312 
313  // If it's still running, try killing it
314  if (m_system)
315  ok = KillScript();
316 
317  // The GetScriptStatus() call above can reset m_systemStatus with
318  // the exit status of the last channel change script invocation, so
319  // we must set it to pending here.
320  m_systemStatus = 1; // pending
321 
322  if (!ok)
323  {
324  LOG(VB_GENERAL, LOG_ERR, LOC +
325  "Can not execute channel changer, previous call to script "
326  "is still running.");
327  m_systemStatus = 2; // failed
328  HandleScriptEnd(ok);
329  }
330  else
331  {
332  if (m_externalChanger.toLower() == "internal")
333  {
334  ok = ChangeInternalChannel(freqid, m_inputId);
335  if (!ok)
336  {
337  LOG(VB_GENERAL, LOG_ERR, LOC + "Can not execute internal channel "
338  "changer.");
339  m_systemStatus = 2; // failed
340  }
341  else
342  m_systemStatus = 3; // success
343 
344  HandleScriptEnd(ok);
345  }
346  else
347  {
348  ok = ChangeExternalChannel(m_externalChanger, freqid);
349  if (!ok)
350  {
351  LOG(VB_GENERAL, LOG_ERR, LOC + "Can not execute channel changer.");
352  m_systemStatus = 2; // failed
353  HandleScriptEnd(ok);
354  }
355  }
356  }
357 }
358 
359 bool ChannelBase::ChangeInternalChannel(const QString &freqid,
360  uint inputid) const
361 {
362 #ifdef USING_FIREWIRE
363  FirewireDevice *device = nullptr;
364  QString fwnode = CardUtil::GetFirewireChangerNode(inputid);
365  uint64_t guid = string_to_guid(fwnode);
366  QString fwmodel = CardUtil::GetFirewireChangerModel(inputid);
367 
368  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Internal channel change to %1 "
369  "on inputid %2, GUID %3 (%4)").arg(freqid).arg(inputid)
370  .arg(fwnode).arg(fwmodel));
371 
372 #ifdef USING_LINUX_FIREWIRE
373  // cppcheck-suppress redundantAssignment
374  device = new LinuxFirewireDevice(
375  guid, 0, 100, true);
376 #endif // USING_LINUX_FIREWIRE
377 
378 #ifdef USING_OSX_FIREWIRE
379  // cppcheck-suppress redundantAssignment
380  device = new DarwinFirewireDevice(guid, 0, 100);
381 #endif // USING_OSX_FIREWIRE
382 
383  if (!device)
384  return false;
385 
386  if (!device->OpenPort())
387  return false;
388 
389  if (!device->SetChannel(fwmodel, 0, freqid.toUInt()))
390  {
391  device->ClosePort();
392  delete device;
393  device = nullptr;
394  return false;
395  }
396 
397  device->ClosePort();
398  delete device;
399  device = nullptr;
400  return true;
401 #else
402  Q_UNUSED(freqid);
403  Q_UNUSED(inputid);
404  return false;
405 #endif
406 }
407 
409 bool ChannelBase::ChangeExternalChannel(const QString &changer,
410  const QString &freqid)
411 {
412  if (m_system)
413  return false;
414 
415  if (changer.isEmpty() || freqid.isEmpty())
416  return false;
417 
418  QString command = QString("%1 %2").arg(changer).arg(freqid);
419  LOG(VB_CHANNEL, LOG_INFO, LOC +
420  QString("Running command: %1").arg(command));
421 
422  m_system = new MythSystemLegacy(command, kMSRunShell | kMSRunBackground);
423  m_system->Run();
424 
425  return true;
426 }
427 
429 {
430  if (!m_system)
431  return m_systemStatus;
432 
433  if (!holding_lock)
434  m_systemLock.lock();
435 
436  m_systemStatus = m_system->Wait();
437  if (m_systemStatus != GENERIC_EXIT_RUNNING &&
438  m_systemStatus != GENERIC_EXIT_START)
439  {
440  delete m_system;
441  m_system = nullptr;
442 
443  HandleScriptEnd(m_systemStatus == GENERIC_EXIT_OK);
444  }
445 
446  LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("GetScriptStatus() %1")
447  .arg(m_systemStatus));
448 
449  uint ret = 0;
450  switch(m_systemStatus)
451  {
452  case GENERIC_EXIT_OK:
453  ret = 3; // success
454  break;
456  case GENERIC_EXIT_START:
457  ret = 1; // pending
458  break;
459  default:
460  ret = 2; // fail
461  break;
462  }
463 
464  LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("GetScriptStatus() %1 -> %2")
465  .arg(m_systemStatus). arg(ret));
466 
467  m_systemStatus = ret;
468 
469  if (!holding_lock)
470  m_systemLock.unlock();
471 
472  return ret;
473 }
474 
477 {
478  if (ok)
479  {
480  LOG(VB_CHANNEL, LOG_INFO, LOC + "Channel change script succeeded.");
481  if (m_inputId)
482  {
483  // Set this as the future start channel for this source
484  m_startChanNum = m_curChannelName;
485  }
486  }
487  else
488  {
489  LOG(VB_GENERAL, LOG_ERR, LOC + "Channel change script failed.");
490  }
491 }
492 
493 int ChannelBase::GetChanID(void) const
494 {
495  if (!m_inputId)
496  return -1;
497 
498  int found = 0;
499  int visible = -1;
500  int id = -1;
502 
503  query.prepare("SELECT chanid,visible FROM channel "
504  "WHERE deleted IS NULL AND "
505  " channum = :CHANNUM AND "
506  " sourceid = :SOURCEID");
507  query.bindValueNoNull(":CHANNUM", m_curChannelName);
508  query.bindValue(":SOURCEID", m_sourceId);
509 
510  if (!query.exec() || !query.isActive())
511  {
512  MythDB::DBError("fetching chanid", query);
513  return -1;
514  }
515 
516  while (query.next())
517  {
518  if (query.value(1).toInt() > 0)
519  {
520  ++found;
521  visible = query.value(0).toInt();
522  }
523  else
524  id = query.value(0).toInt();
525  }
526 
527  if (!found)
528  {
529  LOG(VB_GENERAL, LOG_INFO,
530  QString("No visible channel ids for %1 on sourceid %2")
531  .arg(m_curChannelName).arg(m_sourceId));
532  }
533 
534  if (found > 1)
535  {
536  LOG(VB_GENERAL, LOG_WARNING,
537  QString("Found multiple visible channel ids for %1 on sourceid %2")
538  .arg(m_curChannelName).arg(m_sourceId));
539  }
540 
541  return (visible >= 0 ? visible : id);
542 }
543 
548 {
549  if (!m_inputId)
550  {
551  if (m_pParent)
552  m_inputId = m_pParent->GetInputId();
553  else
554  m_inputId = CardUtil::GetFirstInputID(GetDevice());
555  }
556 
557  if (!m_inputId)
558  {
559  LOG(VB_GENERAL, LOG_ERR,
560  "InitializeInput(): Programmer error, no parent.");
561  return false;
562  }
563 
565  query.prepare(
566  "SELECT sourceid, inputname, "
567  " startchan, externalcommand, "
568  " tunechan "
569  "FROM capturecard "
570  "WHERE cardid = :INPUTID");
571  query.bindValue(":INPUTID", m_inputId);
572 
573  if (!query.exec() || !query.isActive())
574  {
575  MythDB::DBError("ChannelBase::InitializeInput", query);
576  return false;
577  }
578  if (!query.size())
579  {
580  LOG(VB_GENERAL, LOG_ERR, LOC +
581  QString("No capturecard record in database for input %1")
582  .arg(m_inputId));
583  return false;
584  }
585 
586  query.next();
587 
588  m_sourceId = query.value(0).toUInt();
589  m_name = query.value(1).toString();
590  m_startChanNum = query.value(2).toString();
591  m_externalChanger = query.value(3).toString();
592  m_tuneToChannel = query.value(4).toString();
593 
594  if (0 == m_sourceId)
595  {
596  LOG(VB_GENERAL, LOG_ERR, LOC +
597  QString("No video source defined for input %1")
598  .arg(m_inputId));
599  return false;
600  }
601 
602  m_channels = ChannelUtil::GetChannels(m_sourceId, false);
603  QString order = gCoreContext->GetSetting("ChannelOrdering", "channum");
604  ChannelUtil::SortChannels(m_channels, order);
605 
606  if (!IsExternalChannelChangeSupported() &&
607  !m_externalChanger.isEmpty())
608  {
609  LOG(VB_GENERAL, LOG_WARNING, LOC + "External Channel changer is "
610  "set, but this device does not support it.");
611  m_externalChanger.clear();
612  }
613 
614  // print it
615  LOG(VB_CHANNEL, LOG_INFO, LOC +
616  QString("Input #%1: '%2' schan(%3) sourceid(%4)")
617  .arg(m_inputId).arg(m_name).arg(m_startChanNum)
618  .arg(m_sourceId));
619 
620  return true;
621 }
622 
627  const QString &oldChanNum,
628  const QString &newChanNum)
629 {
630  bool skip = (m_name.isEmpty() ||
631  m_startChanNum.isEmpty() ||
632  m_startChanNum != oldChanNum ||
633  m_sourceId != sourceid);
634  if (!skip)
635  m_startChanNum = newChanNum;
636 
637  if (GetSourceID() == sourceid && oldChanNum == m_curChannelName)
638  m_curChannelName = newChanNum;
639 
640  StoreInputChannels();
641 }
642 
647 {
649 
650  if (m_name.isEmpty() || m_startChanNum.isEmpty())
651  return;
652 
653  query.prepare(
654  "UPDATE capturecard "
655  "SET startchan = :STARTCHAN "
656  "WHERE cardid = :CARDINPUTID");
657  query.bindValue(":STARTCHAN", m_startChanNum);
658  query.bindValue(":CARDINPUTID", m_inputId);
659 
660  if (!query.exec() || !query.isActive())
661  MythDB::DBError("StoreInputChannels", query);
662 }
663 
664 bool ChannelBase::CheckChannel(const QString &channum) const
665 {
667  if (!query.isConnected())
668  return false;
669 
670  query.prepare(
671  "SELECT channel.chanid "
672  "FROM channel, capturecard "
673  "WHERE channel.deleted IS NULL AND "
674  " channel.channum = :CHANNUM AND "
675  " channel.sourceid = capturecard.sourceid AND "
676  " capturecard.cardid = :INPUTID AND "
677  " capturecard.hostname = :HOSTNAME");
678  query.bindValue(":CHANNUM", channum);
679  query.bindValue(":INPUTID", m_inputId);
680  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
681 
682  if (!query.exec() || !query.isActive())
683  {
684  MythDB::DBError("checkchannel", query);
685  }
686  else if (query.size() > 0)
687  return true;
688 
689  LOG(VB_CHANNEL, LOG_ERR, LOC +
690  QString("Failed to find channel(%1) on input (%2).")
691  .arg(channum).arg(m_inputId));
692  return false;
693 }
694 
696  TVRec *tvrec,
697  const GeneralDBOptions &genOpt,
698  const DVBDBOptions &dvbOpt,
699  const FireWireDBOptions &fwOpt,
700  const QString &startchannel,
701  bool enter_power_save_mode,
702  QString &rbFileExt,
703  bool setchan)
704 {
705  rbFileExt = "ts";
706 
707  ChannelBase *channel = nullptr;
708  if (genOpt.m_inputType == "DVB")
709  {
710 #ifdef USING_DVB
711  channel = new DVBChannel(genOpt.m_videoDev, tvrec);
712  auto *dvbchannel = dynamic_cast<DVBChannel*>(channel);
713  if (dvbchannel != nullptr)
714  dvbchannel->SetSlowTuning(dvbOpt.m_dvbTuningDelay);
715 #endif
716  }
717  else if (genOpt.m_inputType == "FIREWIRE")
718  {
719 #ifdef USING_FIREWIRE
720  channel = new FirewireChannel(tvrec, genOpt.m_videoDev, fwOpt);
721 #else
722  Q_UNUSED(fwOpt);
723 #endif
724  }
725 #ifdef USING_HDHOMERUN
726  else if (genOpt.m_inputType == "HDHOMERUN")
727  {
728  channel = new HDHRChannel(tvrec, genOpt.m_videoDev);
729  }
730 #endif
731 #ifdef USING_SATIP
732  else if (genOpt.m_inputType == "SATIP")
733  {
734  channel = new SatIPChannel(tvrec, genOpt.m_videoDev);
735  }
736 #endif
737  else if ((genOpt.m_inputType == "IMPORT") ||
738  (genOpt.m_inputType == "DEMO") ||
739  (genOpt.m_inputType == "MPEG" &&
740  genOpt.m_videoDev.toLower().startsWith("file:")))
741  {
742  channel = new DummyChannel(tvrec);
743  rbFileExt = "mpg";
744  }
745 #ifdef USING_IPTV
746  else if (genOpt.m_inputType == "FREEBOX") // IPTV
747  { // NOLINTNEXTLINE(bugprone-branch-clone)
748  channel = new IPTVChannel(tvrec, genOpt.m_videoDev);
749  }
750 #endif
751 #ifdef USING_VBOX
752  else if (genOpt.m_inputType == "VBOX")
753  {
754  channel = new IPTVChannel(tvrec, genOpt.m_videoDev);
755  }
756 #endif
757 #ifdef USING_ASI
758  else if (genOpt.m_inputType == "ASI")
759  {
760  channel = new ASIChannel(tvrec, genOpt.m_videoDev);
761  }
762 #endif
763 #ifdef USING_CETON
764  else if (genOpt.m_inputType == "CETON")
765  {
766  channel = new CetonChannel(tvrec, genOpt.m_videoDev);
767  }
768 #endif
769  else if (genOpt.m_inputType == "V4L2ENC")
770  {
771 #ifdef USING_V4L2
772  channel = new V4LChannel(tvrec, genOpt.m_videoDev);
773 #endif
774  if (genOpt.m_inputType == "MPEG")
775  rbFileExt = "mpg";
776  }
777  else if (CardUtil::IsV4L(genOpt.m_inputType))
778  {
779 #ifdef USING_V4L2
780  channel = new V4LChannel(tvrec, genOpt.m_videoDev);
781 #endif
782  if (genOpt.m_inputType != "HDPVR")
783  {
784  if (genOpt.m_inputType != "MPEG")
785  rbFileExt = "nuv";
786  else
787  rbFileExt = "mpg";
788  }
789  }
790  else if (genOpt.m_inputType == "EXTERNAL")
791  {
792  channel = new ExternalChannel(tvrec, genOpt.m_videoDev);
793  }
794 
795  if (!channel)
796  {
797  QString msg = QString(
798  "%1 card configured on video device %2, \n"
799  "but MythTV was not compiled with %3 support. \n"
800  "\n"
801  "Recompile MythTV with %4 support or remove the card \n"
802  "from the configuration and restart MythTV.")
803  .arg(genOpt.m_inputType).arg(genOpt.m_videoDev)
804  .arg(genOpt.m_inputType).arg(genOpt.m_inputType);
805  LOG(VB_GENERAL, LOG_ERR, "ChannelBase: CreateChannel() Error: \n" +
806  msg + "\n");
807  return nullptr;
808  }
809 
810  if (!channel->Open())
811  {
812  LOG(VB_GENERAL, LOG_ERR, "ChannelBase: CreateChannel() Error: " +
813  QString("Failed to open device %1").arg(genOpt.m_videoDev));
814  delete channel;
815  return nullptr;
816  }
817 
818  QString channum = startchannel;
819  channel->Init(channum, setchan);
820 
821  if (enter_power_save_mode)
822  {
823  if (channel &&
824  ((genOpt.m_inputType == "DVB" && dvbOpt.m_dvbOnDemand) ||
825  genOpt.m_inputType == "HDHOMERUN" ||
826  CardUtil::IsV4L(genOpt.m_inputType)))
827  {
828  channel->Close();
829  }
830  else if (setchan)
831  {
832  auto *dtvchannel = dynamic_cast<DTVChannel*>(channel);
833  if (dtvchannel)
834  dtvchannel->EnterPowerSavingMode();
835  }
836  }
837 
838  return channel;
839 }
840 
842 {
843  if (!IsExternalChannelChangeSupported())
844  return false;
845 
846  if (!m_inputId)
847  {
848  LOG(VB_GENERAL, LOG_ERR, LOC +
849  QString("IsExternalChannelChangeInUse: "
850  "non-existant input"));
851  return false;
852  }
853 
854  return !m_externalChanger.isEmpty();
855 }
856 
858 {
859  return m_pParent ? m_pParent->GetMajorId() : m_inputId;
860 }
GeneralDBOptions
Definition: tv_rec.h:66
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:204
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:126
linuxfirewiredevice.h
dtvchannel.h
channel
QDomElement channel
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:498
ChannelBase::Init
virtual bool Init(QString &startchannel, bool setchan)
Definition: channelbase.cpp:58
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:203
MSqlQuery::bindValueNoNull
void bindValueNoNull(const QString &placeholder, const QVariant &val)
Add a single binding, taking care not to set a NULL value.
Definition: mythdbcon.cpp:869
GENERIC_EXIT_OK
#define GENERIC_EXIT_OK
Exited with no error.
Definition: exitcodes.h:10
InputInfo::m_chanId
uint m_chanId
chanid restriction if applicable
Definition: inputinfo.h:51
ChannelChangeDirection
ChannelChangeDirection
ChannelChangeDirection is an enumeration of possible channel changing directions.
Definition: tv.h:29
MythSystemLegacy
Definition: mythsystemlegacy.h:69
CHANNEL_DIRECTION_UP
@ CHANNEL_DIRECTION_UP
Definition: tv.h:30
ChannelBase::HandleScriptEnd
virtual void HandleScriptEnd(bool ok)
Definition: channelbase.cpp:476
ChannelUtil::GetNextChannel
static uint GetNextChannel(const ChannelInfoList &sorted, uint old_chanid, uint mplexid_restriction, uint chanid_restriction, ChannelChangeDirection direction, bool skip_non_visible=true, bool skip_same_channum_and_callsign=false)
Definition: channelutil.cpp:2339
darwinfirewiredevice.h
CardUtil::GetFirstInputID
static uint GetFirstInputID(const QString &videodevice)
Convenience function for GetInputIDs()
Definition: cardutil.h:258
firewirechannel.h
GeneralDBOptions::m_inputType
QString m_inputType
Definition: tv_rec.h:73
frequencies.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:198
DarwinFirewireDevice
Definition: darwinfirewiredevice.h:11
arg
arg(title).arg(filename).arg(doDelete))
ChannelBase::CreateChannel
static ChannelBase * CreateChannel(TVRec *tvrec, const GeneralDBOptions &genOpt, const DVBDBOptions &dvbOpt, const FireWireDBOptions &fwOpt, const QString &startchannel, bool enter_power_save_mode, QString &rbFileExt, bool setchan)
Definition: channelbase.cpp:695
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
ChannelBase::IsTunable
virtual bool IsTunable(const QString &channum) const
Definition: channelbase.cpp:127
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
CetonChannel
Definition: cetonchannel.h:23
string_to_guid
static uint64_t string_to_guid(const QString &guid)
Definition: avcinfo.h:17
channelbase.h
satipchannel.h
dvbchannel.h
HDHRChannel
Definition: hdhrchannel.h:21
CardUtil::GetFirewireChangerModel
static QString GetFirewireChangerModel(uint inputid)
Definition: cardutil.cpp:1588
ChannelBase::Renumber
virtual void Renumber(uint sourceid, const QString &oldChanNum, const QString &newChanNum)
Changes a channum if we have it cached anywhere.
Definition: channelbase.cpp:626
LinuxFirewireDevice
Definition: linuxfirewiredevice.h:20
ChannelUtil::SortChannels
static void SortChannels(ChannelInfoList &list, const QString &order, bool eliminate_duplicates=false)
Definition: channelutil.cpp:2282
ChannelBase::IsInputAvailable
virtual bool IsInputAvailable(uint &mplexid_restriction, uint &chanid_restriction) const
Switches to another input on hardware, and sets the channel is setstarting is true.
Definition: channelbase.cpp:225
SatIPChannel
Definition: satipchannel.h:13
ChannelBase::HandleScript
void HandleScript(const QString &freqid)
Definition: channelbase.cpp:277
sourceutil.h
cetonchannel.h
ChannelUtil::GetChanID
static int GetChanID(int db_mplexid, int service_transport_id, int major_channel, int minor_channel, int program_number)
Definition: channelutil.cpp:1310
mythlogging.h
ChannelBase
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:32
RemoteIsBusy
bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
Definition: tvremoteutil.cpp:363
ChannelBase::StoreInputChannels
virtual void StoreInputChannels(void)
Saves current channel as the default channel for the current input.
Definition: channelbase.cpp:646
FirewireChannel
FirewireChannel Copyright (c) 2005 by Jim Westfall and Dave Abrahams Distributed as part of MythTV un...
Definition: firewirechannel.h:15
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
CardUtil::GetConflictingInputs
static vector< uint > GetConflictingInputs(uint inputid)
Definition: cardutil.cpp:2068
compat.h
v4lchannel.h
DVBDBOptions::m_dvbOnDemand
bool m_dvbOnDemand
Definition: tv_rec.h:86
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
DVBDBOptions::m_dvbTuningDelay
uint m_dvbTuningDelay
Definition: tv_rec.h:87
ChannelBase::IsExternalChannelChangeInUse
virtual bool IsExternalChannelChangeInUse(void)
Definition: channelbase.cpp:841
IPTVChannel
Definition: iptvchannel.h:25
ChannelUtil::GetChannels
static ChannelInfoList GetChannels(uint sourceid, bool visible_only, const QString &group_by=QString(), uint channel_groupid=0)
Definition: channelutil.h:240
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:135
uint
unsigned int uint
Definition: compat.h:140
ExternalChannel
Definition: ExternalChannel.h:19
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
DTVChannel::EnterPowerSavingMode
virtual bool EnterPowerSavingMode(void)
Enters power saving mode if the card supports it.
Definition: dtvchannel.h:66
CardUtil::IsV4L
static bool IsV4L(const QString &rawtype)
Definition: cardutil.h:140
asichannel.h
CardUtil::GetFirewireChangerNode
static QString GetFirewireChangerNode(uint inputid)
Definition: cardutil.cpp:1571
kMSRunShell
@ kMSRunShell
run process through shell
Definition: mythsystem.h:41
channelutil.h
tvremoteutil.h
InputInfo::m_inputId
uint m_inputId
unique key in DB for this input
Definition: inputinfo.h:49
kMSRunBackground
@ kMSRunBackground
run child in the background
Definition: mythsystem.h:36
iptvchannel.h
LOC
#define LOC
Definition: channelbase.cpp:49
ChannelBase::GetScriptStatus
uint GetScriptStatus(bool holding_lock=false)
Definition: channelbase.cpp:428
ChannelUtil::GetChannelData
static bool GetChannelData(uint sourceid, uint &chanid, const QString &channum, QString &tvformat, QString &modulation, QString &freqtable, QString &freqid, int &finetune, uint64_t &frequency, QString &dtv_si_std, int &mpeg_prog_num, uint &atsc_major, uint &atsc_minor, uint &dvb_transportid, uint &dvb_networkid, uint &mplexid, bool &commfree)
Definition: channelutil.cpp:1883
InputInfo::m_sourceId
uint m_sourceId
associated channel listings source
Definition: inputinfo.h:48
DVBChannel
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:30
ChannelBase::ChangeInternalChannel
bool ChangeInternalChannel(const QString &freqid, uint cardinputid) const
Definition: channelbase.cpp:359
m_name
const char * m_name
Definition: ParseText.cpp:329
ASIChannel
Definition: asichannel.h:16
ChannelBase::KillScript
bool KillScript(void)
Definition: channelbase.cpp:264
mythcorecontext.h
cardutil.h
ChannelBase::CheckChannel
bool CheckChannel(const QString &channum) const
Definition: channelbase.cpp:664
ExternalChannel.h
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
DVBDBOptions
Definition: tv_rec.h:82
GeneralDBOptions::m_videoDev
QString m_videoDev
Definition: tv_rec.h:70
TVRec
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:143
FireWireDBOptions
Definition: tv_rec.h:92
DVBChannel::SetSlowTuning
void SetSlowTuning(uint how_slow_in_ms)
Definition: dvbchannel.h:45
GENERIC_EXIT_START
#define GENERIC_EXIT_START
MythSystemLegacy process starting.
Definition: exitcodes.h:35
inputinfo.h
InputInfo
Definition: inputinfo.h:15
dummychannel.h
ChannelBase::ChangeExternalChannel
bool ChangeExternalChannel(const QString &changer, const QString &freqid)
Definition: channelbase.cpp:409
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:856
DTVChannel
Class providing a generic interface to digital tuning hardware.
Definition: dtvchannel.h:35
ChannelBase::GetNextChannel
virtual uint GetNextChannel(uint chanid, ChannelChangeDirection direction) const
Definition: channelbase.cpp:197
DummyChannel
Definition: dummychannel.h:17
GENERIC_EXIT_RUNNING
#define GENERIC_EXIT_RUNNING
Process is running.
Definition: exitcodes.h:25
FirewireDevice::SetChannel
virtual bool SetChannel(const QString &panel_model, uint alt_method, uint channel)
Definition: firewiredevice.cpp:148
exitcodes.h
hdhrchannel.h
ChannelBase::GetMajorID
int GetMajorID(void)
Definition: channelbase.cpp:857
ChannelBase::InitializeInput
virtual bool InitializeInput(void)
Fills in input map from DB.
Definition: channelbase.cpp:547
V4LChannel
Implements tuning for TV cards using the V4L driver API, both versions 1 and 2.
Definition: v4lchannel.h:37
query
MSqlQuery query(MSqlQuery::InitCon())
ChannelBase::~ChannelBase
virtual ~ChannelBase(void)
Definition: channelbase.cpp:51
FirewireDevice::ClosePort
virtual bool ClosePort(void)=0
InputInfo::m_mplexId
uint m_mplexId
mplexid restriction if applicable
Definition: inputinfo.h:50
find
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
Definition: dvbstreamhandler.cpp:356
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:916
FirewireDevice
Definition: firewiredevice.h:25
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
FirewireDevice::OpenPort
virtual bool OpenPort(void)=0
ChannelBase::GetChanID
virtual int GetChanID(void) const
Definition: channelbase.cpp:493