MythTV  master
tv_rec.cpp
Go to the documentation of this file.
1 // C headers
2 #include <chrono> // for milliseconds
3 #include <cstdio>
4 #include <cstdlib>
5 #include <cstring>
6 #include <sched.h> // for sched_yield
7 #include <thread> // for sleep_for
8 #include <utility>
9 
10 // MythTV headers
11 
12 #include "libmythbase/compat.h"
13 #include "libmythbase/mythconfig.h"
15 #include "libmythbase/mythdate.h"
16 #include "libmythbase/mythdb.h"
18 #include "libmythbase/mythrandom.h"
20 #include "libmythbase/remoteutil.h"
22 
23 #include "cardutil.h"
24 #include "channelgroup.h"
25 #include "eitscanner.h"
26 #include "io/mythmediabuffer.h"
27 #include "jobqueue.h"
28 #include "livetvchain.h"
29 #include "mpeg/atscstreamdata.h"
30 #include "mpeg/atsctables.h"
31 #include "mpeg/dvbstreamdata.h"
32 #include "mythsystemevent.h"
33 #include "osd.h"
34 #include "previewgeneratorqueue.h"
35 #include "recorders/channelbase.h"
36 #include "recorders/dtvchannel.h"
37 #include "recorders/dtvrecorder.h"
39 #include "recorders/v4lchannel.h"
40 #include "recorders/vboxutils.h"
41 #include "recordingprofile.h"
42 #include "recordingrule.h"
43 #include "sourceutil.h"
44 #include "tv_rec.h"
45 #include "tvremoteutil.h"
46 
47 #define DEBUG_CHANNEL_PREFIX 0
49 #define LOC QString("TVRec[%1]: ").arg(m_inputId)
50 #define LOC2 QString("TVRec[%1]: ").arg(inputid) // for static functions
51 
52 QReadWriteLock TVRec::s_inputsLock;
53 QMap<uint,TVRec*> TVRec::s_inputs;
54 QMutex TVRec::s_eitLock;
55 
56 static bool is_dishnet_eit(uint inputid);
57 static int init_jobs(const RecordingInfo *rec, RecordingProfile &profile,
58  bool on_host, bool transcode_bfr_comm, bool on_line_comm);
60 static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout);
61 
86 TVRec::TVRec(int inputid)
87  // Various threads
88  : m_eventThread(new MThread("TVRecEvent", this)),
89  // Configuration variables from setup routines
90  m_inputId(inputid)
91 {
92  s_inputs[m_inputId] = this;
93 }
94 
95 bool TVRec::CreateChannel(const QString &startchannel,
96  bool enter_power_save_mode)
97 {
98  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("CreateChannel(%1)")
99  .arg(startchannel));
100  // If this recorder is a child and its parent is not in error, we
101  // do not need nor want to set the channel.
102  bool setchan = true;
103  if (m_parentId)
104  {
105  TVRec *parentTV = GetTVRec(m_parentId);
106  if (parentTV && parentTV->GetState() != kState_Error)
107  setchan = false;
108  }
110  this, m_genOpt, m_dvbOpt, m_fwOpt,
111  startchannel, enter_power_save_mode, m_rbFileExt, setchan);
112 
113 #ifdef USING_VBOX
114  if (m_genOpt.m_inputType == "VBOX")
115  {
116  if (!CardUtil::IsVBoxPresent(m_inputId))
117  {
118  // VBOX presence failed, recorder is marked errored
119  LOG(VB_GENERAL, LOG_ERR, LOC +
120  QString("CreateChannel(%1) failed due to VBOX not responding "
121  "to network check on inputid [%2]")
122  .arg(startchannel).arg(m_inputId));
123  m_channel = nullptr;
124  }
125  }
126 #endif
127 
128 #ifdef USING_SATIP
129  if (m_genOpt.m_inputType == "SATIP")
130  {
131  if (!CardUtil::IsSatIPPresent(m_inputId))
132  {
133  // SatIP box presence failed, recorder is marked errored
134  LOG(VB_GENERAL, LOG_ERR, LOC +
135  QString("CreateChannel(%1) failed due to SatIP box not responding "
136  "to network check on inputid [%2]")
137  .arg(startchannel).arg(m_inputId));
138  m_channel = nullptr;
139  }
140  }
141 #endif
142 
143  if (!m_channel)
144  {
145  SetFlags(kFlagErrored, __FILE__, __LINE__);
146  return false;
147  }
148 
149  return true;
150 }
151 
157 bool TVRec::Init(void)
158 {
159  QMutexLocker lock(&m_stateChangeLock);
160 
162  {
163  LOG(VB_CHANNEL, LOG_ERR, LOC +
164  QString("Failed to GetDevices for input %1")
165  .arg(m_inputId));
166  return false;
167  }
168 
170 
171  // Configure the Channel instance
172  QString startchannel = CardUtil::GetStartChannel(m_inputId);
173  if (startchannel.isEmpty())
174  return false;
175  if (!CreateChannel(startchannel, true))
176  {
177  LOG(VB_CHANNEL, LOG_ERR, LOC +
178  QString("Failed to create channel instance for %1")
179  .arg(startchannel));
180  return false;
181  }
182 
183  // All conflicting inputs for this input
184  if (m_parentId == 0)
185  {
187  }
188 
189  m_transcodeFirst = gCoreContext->GetBoolSetting("AutoTranscodeBeforeAutoCommflag", false);
190  m_earlyCommFlag = gCoreContext->GetBoolSetting("AutoCommflagWhileRecording", false);
191  m_runJobOnHostOnly = gCoreContext->GetBoolSetting("JobsRunOnRecordHost", false);
192  m_eitTransportTimeout = gCoreContext->GetDurSetting<std::chrono::minutes>("EITTransportTimeout", 5min);
193  if (m_eitTransportTimeout < 15s)
194  m_eitTransportTimeout = 15s;
195  m_eitCrawlIdleStart = gCoreContext->GetDurSetting<std::chrono::seconds>("EITCrawIdleStart", 60s);
196  m_eitScanPeriod = gCoreContext->GetDurSetting<std::chrono::minutes>("EITScanPeriod", 15min);
197  if (m_eitScanPeriod < 5min)
198  m_eitScanPeriod = 5min;
199  m_audioSampleRateDB = gCoreContext->GetNumSetting("AudioSampleRate");
200  m_overRecordSecNrml = gCoreContext->GetDurSetting<std::chrono::seconds>("RecordOverTime");
201  m_overRecordSecCat = gCoreContext->GetDurSetting<std::chrono::minutes>("CategoryOverTime");
202  m_overRecordCategory= gCoreContext->GetSetting("OverTimeCategory");
203 
204  m_eventThread->start();
205 
207 
208  return true;
209 }
210 
216 {
217  s_inputs.remove(m_inputId);
218 
220  {
221  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
222  m_eventThread->wait();
223  delete m_eventThread;
224  m_eventThread = nullptr;
225  }
226 
227  if (m_channel)
228  {
229  delete m_channel;
230  m_channel = nullptr;
231  }
232 }
233 
235 {
236  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownAll");
237 
239 
240  if (m_scanner)
241  {
242  delete m_scanner;
243  m_scanner = nullptr;
244  }
245 
247 
248  SetRingBuffer(nullptr);
249 }
250 
252 {
253  QMutexLocker locker(&m_triggerEventLoopLock);
255  m_triggerEventLoopWait.wakeAll();
256 }
257 
265 {
266  if (m_changeState)
267  return kState_ChangingState;
268  return m_internalState;
269 }
270 
279 {
280  QMutexLocker lock(&m_stateChangeLock);
281 
282  ProgramInfo *tmppginfo = nullptr;
283 
285  {
286  tmppginfo = new ProgramInfo(*m_curRecording);
288  }
289  else
290  tmppginfo = new ProgramInfo();
291  tmppginfo->SetInputID(m_inputId);
292 
293  return tmppginfo;
294 }
295 
310 void TVRec::RecordPending(const ProgramInfo *rcinfo, std::chrono::seconds secsleft,
311  bool hasLater)
312 {
313  QMutexLocker statelock(&m_stateChangeLock);
314  QMutexLocker pendlock(&m_pendingRecLock);
315 
316  if (secsleft < 0s)
317  {
318  LOG(VB_RECORD, LOG_INFO, LOC + "Pending recording revoked on " +
319  QString("inputid [%1]").arg(rcinfo->GetInputID()));
320 
321  PendingMap::iterator it = m_pendingRecordings.find(rcinfo->GetInputID());
322  if (it != m_pendingRecordings.end())
323  {
324  (*it).m_ask = false;
325  (*it).m_doNotAsk = true;
326  (*it).m_canceled = true;
327  }
328  return;
329  }
330 
331  LOG(VB_RECORD, LOG_INFO, LOC +
332  QString("RecordPending on inputid [%1]").arg(rcinfo->GetInputID()));
333 
334  PendingInfo pending;
335  pending.m_info = new ProgramInfo(*rcinfo);
336  pending.m_recordingStart = MythDate::current().addSecs(secsleft.count());
337  pending.m_hasLaterShowing = hasLater;
338  pending.m_ask = true;
339  pending.m_doNotAsk = false;
340 
341  m_pendingRecordings[rcinfo->GetInputID()] = pending;
342 
343  // If this isn't a recording for this instance to make, we are done
344  if (rcinfo->GetInputID() != m_inputId)
345  return;
346 
347  // We also need to check our input groups
348  std::vector<uint> inputids = CardUtil::GetConflictingInputs(rcinfo->GetInputID());
349 
350  m_pendingRecordings[rcinfo->GetInputID()].m_possibleConflicts = inputids;
351 
352  pendlock.unlock();
353  statelock.unlock();
354  for (uint inputid : inputids)
355  RemoteRecordPending(inputid, rcinfo, secsleft, hasLater);
356  statelock.relock();
357  pendlock.relock();
358 }
359 
364 {
367  delete old_rec;
368 }
369 
373 QDateTime TVRec::GetRecordEndTime(const ProgramInfo *pi) const
374 {
375  bool spcat = (!m_overRecordCategory.isEmpty() &&
377  std::chrono::seconds secs = (spcat) ? m_overRecordSecCat : m_overRecordSecNrml;
378  return pi->GetRecordingEndTime().addSecs(secs.count());
379 }
380 
386 void TVRec::CancelNextRecording(bool cancel)
387 {
388  QMutexLocker pendlock(&m_pendingRecLock);
389  LOG(VB_RECORD, LOG_INFO, LOC +
390  QString("CancelNextRecording(%1) -- begin").arg(cancel));
391 
392  PendingMap::iterator it = m_pendingRecordings.find(m_inputId);
393  if (it == m_pendingRecordings.end())
394  {
395  LOG(VB_RECORD, LOG_INFO, LOC + QString("CancelNextRecording(%1) -- "
396  "error, unknown recording").arg(cancel));
397  return;
398  }
399 
400  if (cancel)
401  {
402  std::vector<unsigned int> &inputids = (*it).m_possibleConflicts;
403  for (uint inputid : inputids)
404  {
405  LOG(VB_RECORD, LOG_INFO, LOC +
406  QString("CancelNextRecording -- inputid 0x%1")
407  .arg((uint64_t)inputid,0,16));
408 
409  pendlock.unlock();
410  RemoteRecordPending(inputid, (*it).m_info, -1s, false);
411  pendlock.relock();
412  }
413 
414  LOG(VB_RECORD, LOG_INFO, LOC +
415  QString("CancelNextRecording -- inputid [%1]")
416  .arg(m_inputId));
417 
418  RecordPending((*it).m_info, -1s, false);
419  }
420  else
421  {
422  (*it).m_canceled = false;
423  }
424 
425  LOG(VB_RECORD, LOG_INFO, LOC +
426  QString("CancelNextRecording(%1) -- end").arg(cancel));
427 }
428 
437 {
438  RecordingInfo ri1(*pginfo);
441  RecordingInfo *rcinfo = &ri1;
442 
443  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartRecording(%1)")
444  .arg(rcinfo->toString(ProgramInfo::kTitleSubtitle)));
445 
446  QMutexLocker lock(&m_stateChangeLock);
447 
450 
451  // Flush out any pending state changes
453 
454  // We need to do this check early so we don't cancel an overrecord
455  // that we're trying to extend.
459  {
460  int post_roll_seconds = m_curRecording->GetRecordingEndTime()
461  .secsTo(m_recordEndTime);
462 
467 
469  .addSecs(post_roll_seconds);
470 
471  QString msg = QString("updating recording: %1 %2 %3 %4")
472  .arg(m_curRecording->GetTitle(),
473  QString::number(m_curRecording->GetChanID()),
476  LOG(VB_RECORD, LOG_INFO, LOC + msg);
477 
478  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
479 
481  return RecStatus::Recording;
482  }
483 
484  bool cancelNext = false;
485  PendingInfo pendinfo;
486  PendingMap::iterator it;
487 
488  m_pendingRecLock.lock();
489  if ((it = m_pendingRecordings.find(m_inputId)) != m_pendingRecordings.end())
490  {
491  (*it).m_ask = (*it).m_doNotAsk = false;
492  cancelNext = (*it).m_canceled;
493  }
494  m_pendingRecLock.unlock();
495 
496  // Flush out events...
498 
499  // Rescan pending recordings since the event loop may have deleted
500  // a stale entry. If this happens the info pointer will not be valid
501  // since the HandlePendingRecordings loop will have deleted it.
502  m_pendingRecLock.lock();
503  it = m_pendingRecordings.find(m_inputId);
504  bool has_pending = (it != m_pendingRecordings.end());
505  if (has_pending)
506  pendinfo = *it;
507  m_pendingRecLock.unlock();
508 
509  // If the needed input is in a shared input group, and we are
510  // not canceling the recording anyway, check other recorders
511  if (!cancelNext && has_pending && !pendinfo.m_possibleConflicts.empty())
512  {
513  LOG(VB_RECORD, LOG_INFO, LOC +
514  "Checking input group recorders - begin");
515  std::vector<unsigned int> &inputids = pendinfo.m_possibleConflicts;
516 
517  uint mplexid = 0;
518  uint chanid = 0;
519  uint sourceid = 0;
520  std::vector<unsigned int> inputids2;
521  std::vector<TVState> states;
522 
523  // Stop remote recordings if needed
524  for (uint inputid : inputids)
525  {
526  InputInfo busy_input;
527  bool is_busy = RemoteIsBusy(inputid, busy_input);
528 
529  if (is_busy && !sourceid)
530  {
531  mplexid = pendinfo.m_info->QueryMplexID();
532  chanid = pendinfo.m_info->GetChanID();
533  sourceid = pendinfo.m_info->GetSourceID();
534  }
535 
536  if (is_busy &&
537  ((sourceid != busy_input.m_sourceId) ||
538  (mplexid != busy_input.m_mplexId) ||
539  ((mplexid == 0 || mplexid == 32767) &&
540  chanid != busy_input.m_chanId)))
541  {
542  states.push_back((TVState) RemoteGetState(inputid));
543  inputids2.push_back(inputid);
544  }
545  }
546 
547  bool ok = true;
548  for (uint i = 0; (i < inputids2.size()) && ok; i++)
549  {
550  LOG(VB_RECORD, LOG_INFO, LOC +
551  QString("Attempting to stop input [%1] in state %2")
552  .arg(inputids2[i]).arg(StateToString(states[i])));
553 
554  bool success = RemoteStopRecording(inputids2[i]);
555  if (success)
556  {
557  uint state = RemoteGetState(inputids2[i]);
558  LOG(VB_GENERAL, LOG_INFO, LOC + QString("a [%1]: %2")
559  .arg(inputids2[i]).arg(StateToString((TVState)state)));
560  success = (kState_None == state);
561  }
562 
563  // If we managed to stop LiveTV recording, restart playback..
564  if (success && states[i] == kState_WatchingLiveTV)
565  {
566  QString message = QString("QUIT_LIVETV %1").arg(inputids2[i]);
567  MythEvent me(message);
568  gCoreContext->dispatch(me);
569  }
570 
571  LOG(VB_RECORD, LOG_INFO, LOC +
572  QString("Stopping recording on [%1], %2") .arg(inputids2[i])
573  .arg(success ? "succeeded" : "failed"));
574 
575  ok &= success;
576  }
577 
578  // If we failed to stop the remote recordings, don't record
579  if (!ok)
580  {
581  CancelNextRecording(true);
582  cancelNext = true;
583  }
584 
585  inputids.clear();
586 
587  LOG(VB_RECORD, LOG_INFO, LOC + "Checking input group recorders - done");
588  }
589 
590  bool did_switch = false;
591  if (!cancelNext && (GetState() == kState_RecordingOnly))
592  {
594  did_switch = (nullptr != ri2);
595  if (did_switch)
596  {
597  // Make sure scheduler is allowed to end this recording
598  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
599 
601  }
602  else
603  {
604  // If in post-roll, end recording
605  m_stateChangeLock.unlock();
606  StopRecording();
607  m_stateChangeLock.lock();
608  }
609  }
610 
611  if (!cancelNext && (GetState() == kState_None))
612  {
613  if (m_tvChain)
614  {
615  QString message = QString("LIVETV_EXITED");
616  MythEvent me(message, m_tvChain->GetID());
617  gCoreContext->dispatch(me);
618  m_tvChain->DecrRef();
619  m_tvChain = nullptr;
620  }
621 
623 
624  // Tell event loop to begin recording.
625  m_curRecording = new RecordingInfo(*rcinfo);
630 
631  // Make sure scheduler is allowed to end this recording
632  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
633 
636  else
637  LOG(VB_RECORD, LOG_WARNING, LOC + "Still failing.");
639  }
640  else if (!cancelNext && (GetState() == kState_WatchingLiveTV))
641  {
645 
646  // We want the frontend to change channel for recording
647  // and disable the UI for channel change, PiP, etc.
648 
649  QString message = QString("LIVETV_WATCH %1 1").arg(m_inputId);
650  QStringList prog;
651  rcinfo->ToStringList(prog);
652  MythEvent me(message, prog);
653  gCoreContext->dispatch(me);
654  }
655  else if (!did_switch)
656  {
657  QString msg = QString("Wanted to record: %1 %2 %3 %4\n\t\t\t")
658  .arg(rcinfo->GetTitle(),
659  QString::number(rcinfo->GetChanID()),
662 
663  if (cancelNext)
664  {
665  msg += "But a user has canceled this recording";
667  }
668  else
669  {
670  msg += QString("But the current state is: %1")
673  }
674 
676  {
677  msg += QString("\n\t\t\tCurrently recording: %1 %2 %3 %4")
678  .arg(m_curRecording->GetTitle(),
679  QString::number(m_curRecording->GetChanID()),
682  }
683 
684  LOG(VB_GENERAL, LOG_INFO, LOC + msg);
685  }
686 
687  for (const auto & pend : std::as_const(m_pendingRecordings))
688  delete pend.m_info;
689  m_pendingRecordings.clear();
690 
691  if (!did_switch)
692  {
694 
695  QMutexLocker locker(&m_pendingRecLock);
696  if ((m_curRecording) &&
701  {
702  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
703  }
704  return m_recStatus;
705  }
706 
707  return GetRecordingStatus();
708 }
709 
711 {
712  QMutexLocker pendlock(&m_pendingRecLock);
713  return m_recStatus;
714 }
715 
717  RecStatus::Type new_status, int line, bool have_lock)
718 {
719  RecStatus::Type old_status { RecStatus::Unknown };
720  if (have_lock)
721  {
722  old_status = m_recStatus;
723  m_recStatus = new_status;
724  }
725  else
726  {
727  m_pendingRecLock.lock();
728  old_status = m_recStatus;
729  m_recStatus = new_status;
730  m_pendingRecLock.unlock();
731  }
732 
733  LOG(VB_RECORD, LOG_INFO, LOC +
734  QString("SetRecordingStatus(%1->%2) on line %3")
735  .arg(RecStatus::toString(old_status, kSingleRecord),
736  RecStatus::toString(new_status, kSingleRecord),
737  QString::number(line)));
738 }
739 
746 void TVRec::StopRecording(bool killFile)
747 {
748  if (StateIsRecording(GetState()))
749  {
750  QMutexLocker lock(&m_stateChangeLock);
751  if (killFile)
752  SetFlags(kFlagKillRec, __FILE__, __LINE__);
753  else if (m_curRecording)
754  {
755  QDateTime now = MythDate::current(true);
756  if (now < m_curRecording->GetDesiredEndTime())
758  }
760  // wait for state change to take effect
762  ClearFlags(kFlagCancelNextRecording|kFlagKillRec, __FILE__, __LINE__);
763 
765  }
766 }
767 
774 {
775  return (state == kState_RecordingOnly ||
776  state == kState_WatchingLiveTV);
777 }
778 
784 {
785  return (state == kState_WatchingPreRecorded);
786 }
787 
794 {
795  if (StateIsRecording(state))
796  return kState_None;
797 
798  LOG(VB_GENERAL, LOG_ERR, LOC +
799  QString("Unknown state in RemoveRecording: %1")
800  .arg(StateToString(state)));
801  return kState_Error;
802 }
803 
810 {
811  if (StateIsPlaying(state))
812  {
813  if (state == kState_WatchingPreRecorded)
814  return kState_None;
815  return kState_RecordingOnly;
816  }
817 
818  QString msg = "Unknown state in RemovePlaying: %1";
819  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(StateToString(state)));
820 
821  return kState_Error;
822 }
823 
830 {
831  if (!curRec)
832  return;
833 
834  curRec->StartedRecording(m_rbFileExt);
835  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartedRecording(%1) fn(%2)")
836  .arg(curRec->MakeUniqueKey(), curRec->GetPathname()));
837 
838  if (curRec->IsCommercialFree())
840 
841  AutoRunInitType t = (curRec->GetRecordingGroup() == "LiveTV") ?
843  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
844 
845  SendMythSystemRecEvent("REC_STARTED", curRec);
846 }
847 
856 {
857  if (!curRec)
858  return;
859 
860  // Make sure the recording group is up to date
861  const QString recgrp = curRec->QueryRecordingGroup();
862  curRec->SetRecordingGroup(recgrp);
863 
864  bool is_good = true;
865  if (recq)
866  {
867  LOG((recq->IsDamaged()) ? VB_GENERAL : VB_RECORD, LOG_INFO,
868  LOC + QString("FinishedRecording(%1) %2 recq:\n%3")
869  .arg(curRec->MakeUniqueKey(),
870  (recq->IsDamaged()) ? "damaged" : "good",
871  recq->toStringXML()));
872  is_good = !recq->IsDamaged();
873  delete recq;
874  recq = nullptr;
875  }
876 
877  RecStatus::Type ors = curRec->GetRecordingStatus();
878  // Set the final recording status
879  if (curRec->GetRecordingStatus() == RecStatus::Recording)
881  else if (curRec->GetRecordingStatus() != RecStatus::Recorded)
883  curRec->SetRecordingEndTime(MythDate::current(true));
884  is_good &= (curRec->GetRecordingStatus() == RecStatus::Recorded);
885 
886  // Figure out if this was already done for this recording
887  bool was_finished = false;
888  static QMutex s_finRecLock;
889  static QHash<QString,QDateTime> s_finRecMap;
890  {
891  QMutexLocker locker(&s_finRecLock);
892  QDateTime now = MythDate::current();
893  QDateTime expired = now.addSecs(-5LL * 60);
894  QHash<QString,QDateTime>::iterator it = s_finRecMap.begin();
895  while (it != s_finRecMap.end())
896  {
897  if ((*it) < expired)
898  it = s_finRecMap.erase(it);
899  else
900  ++it;
901  }
902  QString key = curRec->MakeUniqueKey();
903  it = s_finRecMap.find(key);
904  if (it != s_finRecMap.end())
905  was_finished = true;
906  else
907  s_finRecMap[key] = now;
908  }
909 
910  // Print something informative to the log
911  LOG(VB_RECORD, LOG_INFO, LOC +
912  QString("FinishedRecording(%1) %2 quality"
913  "\n\t\t\ttitle: %3\n\t\t\t"
914  "in recgroup: %4 status: %5:%6 %7 %8")
915  .arg(curRec->MakeUniqueKey(),
916  is_good ? "Good" : "Bad",
917  curRec->GetTitle(),
918  recgrp,
921  HasFlags(kFlagDummyRecorderRunning)?"is_dummy":"not_dummy",
922  was_finished?"already_finished":"finished_now"));
923 
924  // This has already been called on this recording..
925  if (was_finished)
926  return;
927 
928  // Notify the frontend watching live tv that this file is final
929  if (m_tvChain)
930  m_tvChain->FinishedRecording(curRec);
931 
932  // if this is a dummy recorder, do no more..
934  {
935  curRec->FinishedRecording(true); // so end time is updated
936  SendMythSystemRecEvent("REC_FINISHED", curRec);
937  return;
938  }
939 
940  // Get the width and set the videoprops
941  MarkTypes aspectRatio = curRec->QueryAverageAspectRatio();
942  uint avg_height = curRec->QueryAverageHeight();
943  bool progressive = curRec->QueryAverageScanProgressive();
944  curRec->SaveVideoProperties
945  (VID_4K | VID_1080 | VID_720 | VID_DAMAGED |
946  VID_WIDESCREEN | VID_PROGRESSIVE,
947  ((avg_height > 2000) ? VID_4K :
948  ((avg_height > 1000) ? VID_1080 :
949  ((avg_height > 700) ? VID_720 : 0))) |
950  (progressive ? VID_PROGRESSIVE : 0) |
951  ((is_good) ? 0 : VID_DAMAGED) |
952  (((aspectRatio == MARK_ASPECT_16_9) ||
953  (aspectRatio == MARK_ASPECT_2_21_1)) ? VID_WIDESCREEN : 0));
954 
955  // Make sure really short recordings have positive run time.
956  if (curRec->GetRecordingEndTime() <= curRec->GetRecordingStartTime())
957  {
958  curRec->SetRecordingEndTime(
959  curRec->GetRecordingStartTime().addSecs(60));
960  }
961 
962  // HACK Temporary hack, ensure we've loaded the recording file info, do it now
963  // so that it contains the final filesize information
964  if (!curRec->GetRecordingFile())
965  curRec->LoadRecordingFile();
966 
967  // Generate a preview
968  uint64_t fsize = curRec->GetFilesize();
969  if (curRec->IsLocal() && (fsize >= 1000) &&
971  {
973  }
974 
975  // store recording in recorded table
976  curRec->FinishedRecording(!is_good || (recgrp == "LiveTV"));
977 
978  // send out UPDATE_RECORDING_STATUS message
979  if (recgrp != "LiveTV")
980  {
981  LOG(VB_RECORD, LOG_INFO, LOC +
982  QString("FinishedRecording -- UPDATE_RECORDING_STATUS: %1")
983  .arg(RecStatus::toString(is_good ? curRec->GetRecordingStatus()
985  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
986  .arg(curRec->GetInputID())
987  .arg(curRec->GetChanID())
989  .arg(is_good ? curRec->GetRecordingStatus() : RecStatus::Failed)
990  .arg(curRec->GetRecordingEndTime(MythDate::ISODate)));
991  gCoreContext->dispatch(me);
992  }
993 
994  // send out REC_FINISHED message
995  SendMythSystemRecEvent("REC_FINISHED", curRec);
996 
997  // send out DONE_RECORDING message
998  auto secsSince = MythDate::secsInPast(curRec->GetRecordingStartTime());
999  QString message = QString("DONE_RECORDING %1 %2 %3")
1000  .arg(m_inputId).arg(secsSince.count()).arg(GetFramesWritten());
1001  MythEvent me(message);
1002  gCoreContext->dispatch(me);
1003 
1004  // Handle JobQueue
1005  QHash<QString,int>::iterator autoJob =
1006  m_autoRunJobs.find(curRec->MakeUniqueKey());
1007  if (autoJob == m_autoRunJobs.end())
1008  {
1009  LOG(VB_GENERAL, LOG_INFO,
1010  "autoRunJobs not initialized until FinishedRecording()");
1011  AutoRunInitType t =
1012  (recgrp == "LiveTV") ? kAutoRunNone : kAutoRunProfile;
1013  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
1014  autoJob = m_autoRunJobs.find(curRec->MakeUniqueKey());
1015  }
1016  LOG(VB_JOBQUEUE, LOG_INFO, QString("AutoRunJobs 0x%1").arg(*autoJob,0,16));
1017  if ((recgrp == "LiveTV") || (fsize < 1000) ||
1018  (curRec->GetRecordingStatus() != RecStatus::Recorded) ||
1019  (curRec->GetRecordingStartTime().secsTo(
1020  MythDate::current()) < 120))
1021  {
1024  }
1025  if (*autoJob != JOB_NONE)
1026  JobQueue::QueueRecordingJobs(*curRec, *autoJob);
1027  m_autoRunJobs.erase(autoJob);
1028 }
1029 
1030 // NOLINTBEGIN(cppcoreguidelines-macro-usage)
1031 #define TRANSITION(ASTATE,BSTATE) \
1032  ((m_internalState == (ASTATE)) && (m_desiredNextState == (BSTATE)))
1033 #define SET_NEXT() do { nextState = m_desiredNextState; changed = true; } while(false)
1034 #define SET_LAST() do { nextState = m_internalState; changed = true; } while(false)
1035 // NOLINTEND(cppcoreguidelines-macro-usage)
1036 
1045 {
1046  TVState nextState = m_internalState;
1047 
1048  bool changed = false;
1049 
1050  QString transMsg = QString(" %1 to %2")
1051  .arg(StateToString(nextState), StateToString(m_desiredNextState));
1052 
1054  {
1055  LOG(VB_GENERAL, LOG_ERR, LOC +
1056  "HandleStateChange(): Null transition" + transMsg);
1057  m_changeState = false;
1058  return;
1059  }
1060 
1061  // Stop EIT scanning on this input before any tuning,
1062  // to avoid race condition with it's tuning requests.
1064  {
1065  LOG(VB_EIT, LOG_INFO, LOC + QString("Stop EIT scan on input %1").arg(GetInputId()));
1066 
1068  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1070  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1071  }
1072 
1073  // Stop EIT scanning on all conflicting inputs so that
1074  // the tuner card is available for a new tuning request.
1075  // Conflicting inputs are inputs that have independent video sources
1076  // but that share a tuner card, such as a DVB-S/S2 tuner card that
1077  // connects to multiple satellites with a DiSEqC switch.
1078  if (m_scanner && !m_eitInputs.empty())
1079  {
1080  s_inputsLock.lockForRead();
1081  s_eitLock.lock();
1082  for (auto input : m_eitInputs)
1083  {
1084  auto *tv_rec = s_inputs.value(input);
1085  if (tv_rec && tv_rec->m_scanner && tv_rec->HasFlags(kFlagEITScannerRunning))
1086  {
1087  LOG(VB_EIT, LOG_INFO, LOC +
1088  QString("Stop EIT scan active on conflicting input %1")
1089  .arg(input));
1090  tv_rec->m_scanner->StopActiveScan();
1091  tv_rec->ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1092  tv_rec->TuningShutdowns(TuningRequest(kFlagNoRec));
1094  tv_rec->m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1095  }
1096  }
1097  s_eitLock.unlock();
1098  s_inputsLock.unlock();
1099  }
1100 
1101  // Handle different state transitions
1103  {
1105  SET_NEXT();
1106  }
1108  {
1110  SET_NEXT();
1111  }
1113  {
1114  SetPseudoLiveTVRecording(nullptr);
1115 
1116  SET_NEXT();
1117  }
1119  {
1120  SetPseudoLiveTVRecording(nullptr);
1122  SET_NEXT();
1123  }
1125  {
1128  (GetFlags()&kFlagKillRec)));
1129  SET_NEXT();
1130  }
1131 
1132  QString msg = (changed) ? "Changing from" : "Unknown state transition:";
1133  LOG(VB_GENERAL, LOG_INFO, LOC + msg + transMsg);
1134 
1135  // update internal state variable
1136  m_internalState = nextState;
1137  m_changeState = false;
1138 
1140  {
1142  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1143  }
1144  else
1145  {
1146  m_eitScanStartTime = MythDate::current().addYears(1);
1147  }
1148 }
1149 #undef TRANSITION
1150 #undef SET_NEXT
1151 #undef SET_LAST
1152 
1157 {
1158  QMutexLocker lock(&m_stateChangeLock);
1159  m_desiredNextState = nextState;
1160  m_changeState = true;
1161  WakeEventLoop();
1162 }
1163 
1178 void TVRec::TeardownRecorder(uint request_flags)
1179 {
1180  LOG(VB_RECORD, LOG_INFO, LOC + QString("TeardownRecorder(%1)")
1181  .arg((request_flags & kFlagKillRec) ? "kFlagKillRec" : ""));
1182 
1183  m_pauseNotify = false;
1184  m_isPip = false;
1185 
1187  {
1190  delete m_recorderThread;
1191  m_recorderThread = nullptr;
1192  }
1194  __FILE__, __LINE__);
1195 
1196  RecordingQuality *recq = nullptr;
1197  if (m_recorder)
1198  {
1199  if (GetV4LChannel())
1200  m_channel->SetFd(-1);
1201 
1203 
1204  QMutexLocker locker(&m_stateChangeLock);
1205  delete m_recorder;
1206  m_recorder = nullptr;
1207  }
1208 
1209  if (m_buffer)
1210  {
1211  LOG(VB_FILE, LOG_INFO, LOC + "calling StopReads()");
1212  m_buffer->StopReads();
1213  }
1214 
1215  if (m_curRecording)
1216  {
1217  if (!!(request_flags & kFlagKillRec))
1219 
1221 
1223  delete m_curRecording;
1224  m_curRecording = nullptr;
1225  }
1226 
1227  m_pauseNotify = true;
1228 
1229  if (GetDTVChannel())
1231 }
1232 
1234 {
1235  return dynamic_cast<DTVRecorder*>(m_recorder);
1236 }
1237 
1239 {
1240  if (m_channel &&
1241  ((m_genOpt.m_inputType == "DVB" && m_dvbOpt.m_dvbOnDemand) ||
1242  m_genOpt.m_inputType == "FREEBOX" ||
1243  m_genOpt.m_inputType == "VBOX" ||
1244  m_genOpt.m_inputType == "HDHOMERUN" ||
1245  m_genOpt.m_inputType == "EXTERNAL" ||
1247  {
1248  m_channel->Close();
1249  }
1250 }
1251 
1253 {
1254  return dynamic_cast<DTVChannel*>(m_channel);
1255 }
1256 
1258 {
1259 #ifdef USING_V4L2
1260  return dynamic_cast<V4LChannel*>(m_channel);
1261 #else
1262  return nullptr;
1263 #endif // USING_V4L2
1264 }
1265 
1266 // Check if EIT is enabled for the video source connected to this input
1267 static bool get_use_eit(uint inputid)
1268 {
1269  MSqlQuery query(MSqlQuery::InitCon());
1270  query.prepare(
1271  "SELECT SUM(useeit) "
1272  "FROM videosource, capturecard "
1273  "WHERE videosource.sourceid = capturecard.sourceid AND"
1274  " capturecard.cardid = :INPUTID");
1275  query.bindValue(":INPUTID", inputid);
1276 
1277  if (!query.exec() || !query.isActive())
1278  {
1279  MythDB::DBError("get_use_eit", query);
1280  return false;
1281  }
1282  if (query.next())
1283  return query.value(0).toBool();
1284  return false;
1285 }
1286 
1287 static bool is_dishnet_eit(uint inputid)
1288 {
1289  MSqlQuery query(MSqlQuery::InitCon());
1290  query.prepare(
1291  "SELECT SUM(dishnet_eit) "
1292  "FROM videosource, capturecard "
1293  "WHERE videosource.sourceid = capturecard.sourceid AND"
1294  " capturecard.cardid = :INPUTID");
1295  query.bindValue(":INPUTID", inputid);
1296 
1297  if (!query.exec() || !query.isActive())
1298  {
1299  MythDB::DBError("is_dishnet_eit", query);
1300  return false;
1301  }
1302  if (query.next())
1303  return query.value(0).toBool();
1304  return false;
1305 }
1306 
1307 // Highest capturecard instance number including multirec instances
1308 static int get_highest_input(void)
1309 {
1310  MSqlQuery query(MSqlQuery::InitCon());
1311  query.prepare(
1312  "SELECT MAX(cardid) "
1313  "FROM capturecard ");
1314 
1315  if (!query.exec() || !query.isActive())
1316  {
1317  MythDB::DBError("highest_input", query);
1318  return -1;
1319  }
1320  if (query.next())
1321  return query.value(0).toInt();
1322  return -1;
1323 }
1324 
1325 static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout)
1326 {
1327  // Randomize start time a bit
1328  auto timeout = std::chrono::seconds(MythRandom(0, eitTransportTimeout.count() / 3));
1329 
1330  // Use the highest input number and the current input number
1331  // to distribute the scan start evenly over eitTransportTimeout
1332  int highest_input = get_highest_input();
1333  if (highest_input > 0)
1334  timeout += eitTransportTimeout * inputId / highest_input;
1335 
1336  return timeout;
1337 }
1338 
1340 void TVRec::run(void)
1341 {
1342  QMutexLocker lock(&m_stateChangeLock);
1343  SetFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1344  ClearFlags(kFlagExitPlayer | kFlagFinishRecording, __FILE__, __LINE__);
1345 
1346  // Check whether we should use the EITScanner in this TVRec instance
1347  if (CardUtil::IsEITCapable(m_genOpt.m_inputType) && // Card type capable of receiving EIT?
1348  (!GetDTVChannel() || GetDTVChannel()->IsMaster()) && // Card is master and not a multirec instance
1349  (m_dvbOpt.m_dvbEitScan || get_use_eit(m_inputId))) // EIT is selected for card OR EIT is selected for video source
1350  {
1353  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1354  }
1355  else
1356  {
1357  m_eitScanStartTime = MythDate::current().addYears(10);
1358  }
1359 
1360  while (HasFlags(kFlagRunMainLoop))
1361  {
1362  // If there is a state change queued up, do it...
1363  if (m_changeState)
1364  {
1367  __FILE__, __LINE__);
1368  }
1369 
1370  // Quick exit on fatal errors.
1371  if (IsErrored())
1372  {
1373  LOG(VB_GENERAL, LOG_ERR, LOC +
1374  "RunTV encountered fatal error, exiting event thread.");
1375  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1376  TeardownAll();
1377  return;
1378  }
1379 
1380  // Handle any tuning events.. Blindly grabbing the lock here
1381  // can sometimes cause a deadlock with Init() while it waits
1382  // to make sure this thread starts. Until a better solution
1383  // is found, don't run HandleTuning unless we can safely get
1384  // the lock.
1385  if (s_inputsLock.tryLockForRead())
1386  {
1387  HandleTuning();
1388  s_inputsLock.unlock();
1389  }
1390 
1391  // Tell frontends about pending recordings
1393 
1394  // If we are recording a program, check if the recording is
1395  // over or someone has asked us to finish the recording.
1396  // Add an extra 60 seconds to the recording end time if we
1397  // might want a back to back recording.
1398  QDateTime recEnd = (!m_pendingRecordings.empty()) ?
1399  m_recordEndTime.addSecs(60) : m_recordEndTime;
1400  if ((GetState() == kState_RecordingOnly) &&
1401  (MythDate::current() > recEnd ||
1403  {
1405  ClearFlags(kFlagFinishRecording, __FILE__, __LINE__);
1406  }
1407 
1408  if (m_curRecording)
1409  {
1411 
1412  if (m_recorder)
1413  {
1415 
1416  // Check for recorder errors
1417  if (m_recorder->IsErrored())
1418  {
1420 
1422  {
1423  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
1424  MythEvent me(message);
1425  gCoreContext->dispatch(me);
1426  }
1427  else
1429  }
1430  }
1431  }
1432 
1433  // Check for the end of the current program..
1435  {
1436  QDateTime now = MythDate::current();
1437  bool has_finish = HasFlags(kFlagFinishRecording);
1438  bool has_rec = m_pseudoLiveTVRecording;
1439  bool enable_ui = true;
1440 
1441  m_pendingRecLock.lock();
1442  bool rec_soon =
1444  m_pendingRecLock.unlock();
1445 
1446  if (has_rec && (has_finish || (now > m_recordEndTime)))
1447  {
1448  SetPseudoLiveTVRecording(nullptr);
1449  }
1450  else if (!has_rec && !rec_soon && m_curRecording &&
1451  (now >= m_curRecording->GetScheduledEndTime()))
1452  {
1453  if (!m_switchingBuffer)
1454  {
1455  LOG(VB_RECORD, LOG_INFO, LOC +
1456  "Switching Buffer (" +
1457  QString("!has_rec(%1) && ").arg(has_rec) +
1458  QString("!rec_soon(%1) && (").arg(rec_soon) +
1459  MythDate::toString(now, MythDate::ISODate) + " >= " +
1461  QString("(%1) ))")
1462  .arg(now >= m_curRecording->GetScheduledEndTime()));
1463 
1464  m_switchingBuffer = true;
1465 
1467  false, true);
1468  }
1469  else
1470  {
1471  LOG(VB_RECORD, LOG_INFO, "Waiting for ringbuffer switch");
1472  }
1473  }
1474  else
1475  enable_ui = false;
1476 
1477  if (enable_ui)
1478  {
1479  LOG(VB_RECORD, LOG_INFO, LOC + "Enabling Full LiveTV UI.");
1480  QString message = QString("LIVETV_WATCH %1 0").arg(m_inputId);
1481  MythEvent me(message);
1482  gCoreContext->dispatch(me);
1483  }
1484  }
1485 
1486  // Check for ExitPlayer flag, and if set change to a non-watching
1487  // state (either kState_RecordingOnly or kState_None).
1489  {
1492  else if (StateIsPlaying(m_internalState))
1494  ClearFlags(kFlagExitPlayer, __FILE__, __LINE__);
1495  }
1496 
1497  // Start active EIT scan
1498  bool conflicting_input = false;
1499  if (m_scanner && m_channel &&
1501  {
1502  if (!m_dvbOpt.m_dvbEitScan)
1503  {
1504  LOG(VB_EIT, LOG_INFO, LOC +
1505  QString("EIT scanning disabled for input %1")
1506  .arg(GetInputId()));
1507  m_eitScanStartTime = MythDate::current().addYears(10);
1508  }
1509  else if (!get_use_eit(GetInputId()))
1510  {
1511  LOG(VB_EIT, LOG_INFO, LOC +
1512  QString("EIT scanning disabled for video source %1")
1513  .arg(GetSourceID()));
1514  m_eitScanStartTime = MythDate::current().addYears(10);
1515  }
1516  else
1517  {
1518  LOG(VB_EIT, LOG_INFO, LOC +
1519  QString("EIT scanning enabled for input %1 connected to video source %2 '%3'")
1521 
1522  // Check if another card in the same input group is busy recording.
1523  // This could be either a virtual DVB-device or a second tuner on a single card.
1524  s_inputsLock.lockForRead();
1525  s_eitLock.lock();
1526  bool allow_eit = true;
1527  std::vector<uint> inputids = CardUtil::GetConflictingInputs(m_inputId);
1528  InputInfo busy_input;
1529  for (uint i = 0; i < inputids.size() && allow_eit; ++i)
1530  allow_eit = !RemoteIsBusy(inputids[i], busy_input);
1531 
1532  // Check if another card in the same input group is busy with an EIT scan.
1533  // We cannot start an EIT scan on this input if there is already an EIT scan
1534  // running on a conflicting real input.
1535  // Note that EIT scans never run on virtual inputs.
1536  if (allow_eit)
1537  {
1538  for (auto input : inputids)
1539  {
1540  auto *tv_rec = s_inputs.value(input);
1541  if (tv_rec && tv_rec->m_scanner)
1542  {
1543  conflicting_input = true;
1544  if (tv_rec->HasFlags(kFlagEITScannerRunning))
1545  {
1546  LOG(VB_EIT, LOG_INFO, LOC +
1547  QString("EIT scan on conflicting input %1").arg(input));
1548  allow_eit = false;
1549  busy_input.m_inputId = tv_rec->m_inputId;
1550  break;
1551  }
1552  }
1553  }
1554  }
1555 
1556  if (allow_eit)
1557  {
1558  LOG(VB_EIT, LOG_INFO, LOC +
1559  QString("Start EIT active scan on input %1")
1560  .arg(m_inputId));
1562  SetFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1563  m_eitScanStartTime = MythDate::current().addYears(1);
1564  if (conflicting_input)
1566  else
1567  m_eitScanStopTime = MythDate::current().addYears(1);
1568  }
1569  else
1570  {
1571  const int seconds_postpone = 300;
1572  LOG(VB_EIT, LOG_INFO, LOC +
1573  QString("Postponing EIT scan on input %1 for %2 seconds because input %3 is busy")
1574  .arg(m_inputId).arg(seconds_postpone).arg(busy_input.m_inputId));
1575  m_eitScanStartTime = m_eitScanStartTime.addSecs(seconds_postpone);
1576  }
1577  s_eitLock.unlock();
1578  s_inputsLock.unlock();
1579  }
1580  }
1581 
1582 
1583  // Stop active EIT scan and allow start of the EIT scan on one of the conflicting real inputs.
1585  {
1586  LOG(VB_EIT, LOG_INFO, LOC +
1587  QString("Stop EIT scan on input %1 to allow scan on a conflicting input")
1588  .arg(GetInputId()));
1589 
1591  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1593 
1595  secs += m_eitScanPeriod;
1596  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1597  }
1598 
1599  // We should be no more than a few thousand milliseconds,
1600  // as the end recording code does not have a trigger...
1601  // NOTE: If you change anything here, make sure that
1602  // WaitforEventThreadSleep() will still work...
1603  if (m_tuningRequests.empty() && !m_changeState)
1604  {
1605  lock.unlock(); // stateChangeLock
1606 
1607  {
1608  QMutexLocker locker(&m_triggerEventSleepLock);
1610  m_triggerEventSleepWait.wakeAll();
1611  }
1612 
1613  sched_yield();
1614 
1615  {
1616  QMutexLocker locker(&m_triggerEventLoopLock);
1617  // We check triggerEventLoopSignal because it is possible
1618  // that WakeEventLoop() was called since we
1619  // unlocked the stateChangeLock
1621  {
1623  &m_triggerEventLoopLock, 1000 /* ms */);
1624  }
1625  m_triggerEventLoopSignal = false;
1626  }
1627 
1628  lock.relock(); // stateChangeLock
1629  }
1630  }
1631 
1632  if (GetState() != kState_None)
1633  {
1636  }
1637 
1638  TeardownAll();
1639 }
1640 
1646 bool TVRec::WaitForEventThreadSleep(bool wake, std::chrono::milliseconds time)
1647 {
1648  bool ok = false;
1649  MythTimer t;
1650  t.start();
1651 
1652  while (!ok && (t.elapsed() < time))
1653  {
1654  MythTimer t2;
1655  t2.start();
1656 
1657  if (wake)
1658  WakeEventLoop();
1659 
1660  m_stateChangeLock.unlock();
1661 
1662  sched_yield();
1663 
1664  {
1665  QMutexLocker locker(&m_triggerEventSleepLock);
1668  m_triggerEventSleepSignal = false;
1669  }
1670 
1671  m_stateChangeLock.lock();
1672 
1673  // verify that we were triggered.
1674  ok = (m_tuningRequests.empty() && !m_changeState);
1675 
1676  std::chrono::milliseconds te = t2.elapsed();
1677  if (!ok && te < 10ms)
1678  std::this_thread::sleep_for(10ms - te);
1679  }
1680  return ok;
1681 }
1682 
1684 {
1685  QMutexLocker pendlock(&m_pendingRecLock);
1686 
1687  for (auto it = m_pendingRecordings.begin(); it != m_pendingRecordings.end();)
1688  {
1689  if (MythDate::current() > (*it).m_recordingStart.addSecs(30))
1690  {
1691  LOG(VB_RECORD, LOG_INFO, LOC + "Deleting stale pending recording " +
1692  QString("[%1] '%2'")
1693  .arg((*it).m_info->GetInputID())
1694  .arg((*it).m_info->GetTitle()));
1695 
1696  delete (*it).m_info;
1697  it = m_pendingRecordings.erase(it);
1698  }
1699  else
1700  {
1701  it++;
1702  }
1703  }
1704 
1705  if (m_pendingRecordings.empty())
1706  return;
1707 
1708  // Make sure EIT scan is stopped so it does't interfere
1710  {
1711  LOG(VB_CHANNEL, LOG_INFO,
1712  LOC + "Stopping active EIT scan for pending recording.");
1714  }
1715 
1716  // If we have a pending recording and AskAllowRecording
1717  // or DoNotAskAllowRecording is set and the frontend is
1718  // ready send an ASK_RECORDING query to frontend.
1719 
1720  bool has_rec = false;
1721  auto it = m_pendingRecordings.begin();
1722  if ((1 == m_pendingRecordings.size()) &&
1723  (*it).m_ask &&
1724  ((*it).m_info->GetInputID() == m_inputId) &&
1726  {
1728  has_rec = m_pseudoLiveTVRecording &&
1730  (*it).m_recordingStart);
1731  }
1732 
1733  for (it = m_pendingRecordings.begin(); it != m_pendingRecordings.end(); ++it)
1734  {
1735  if (!(*it).m_ask && !(*it).m_doNotAsk)
1736  continue;
1737 
1738  auto timeuntil = ((*it).m_doNotAsk) ?
1739  -1s: MythDate::secsInFuture((*it).m_recordingStart);
1740 
1741  if (has_rec)
1742  (*it).m_canceled = true;
1743 
1744  QString query = QString("ASK_RECORDING %1 %2 %3 %4")
1745  .arg(m_inputId)
1746  .arg(timeuntil.count())
1747  .arg(has_rec ? 1 : 0)
1748  .arg((*it).m_hasLaterShowing ? 1 : 0);
1749 
1750  LOG(VB_GENERAL, LOG_INFO, LOC + query);
1751 
1752  QStringList msg;
1753  (*it).m_info->ToStringList(msg);
1754  MythEvent me(query, msg);
1755  gCoreContext->dispatch(me);
1756 
1757  (*it).m_ask = (*it).m_doNotAsk = false;
1758  }
1759 }
1760 
1762  uint &parentid,
1763  GeneralDBOptions &gen_opts,
1764  DVBDBOptions &dvb_opts,
1765  FireWireDBOptions &firewire_opts)
1766 {
1767  int testnum = 0;
1768  QString test;
1769 
1770  MSqlQuery query(MSqlQuery::InitCon());
1771  query.prepare(
1772  "SELECT videodevice, vbidevice, audiodevice, "
1773  " audioratelimit, cardtype, "
1774  " skipbtaudio, signal_timeout, channel_timeout, "
1775  " dvb_wait_for_seqstart, "
1776  ""
1777  " dvb_on_demand, dvb_tuning_delay, dvb_eitscan,"
1778  ""
1779  " firewire_speed, firewire_model, firewire_connection, "
1780  " parentid "
1781  ""
1782  "FROM capturecard "
1783  "WHERE cardid = :INPUTID");
1784  query.bindValue(":INPUTID", inputid);
1785 
1786  if (!query.exec() || !query.isActive())
1787  {
1788  MythDB::DBError("getdevices", query);
1789  return false;
1790  }
1791 
1792  if (!query.next())
1793  return false;
1794 
1795  // General options
1796  test = query.value(0).toString();
1797  if (!test.isEmpty())
1798  gen_opts.m_videoDev = test;
1799 
1800  test = query.value(1).toString();
1801  if (!test.isEmpty())
1802  gen_opts.m_vbiDev = test;
1803 
1804  test = query.value(2).toString();
1805  if (!test.isEmpty())
1806  gen_opts.m_audioDev = test;
1807 
1808  gen_opts.m_audioSampleRate = std::max(testnum, query.value(3).toInt());
1809 
1810  test = query.value(4).toString();
1811  if (!test.isEmpty())
1812  gen_opts.m_inputType = test;
1813 
1814  gen_opts.m_skipBtAudio = query.value(5).toBool();
1815 
1816  gen_opts.m_signalTimeout = (uint) std::max(query.value(6).toInt(), 0);
1817  gen_opts.m_channelTimeout = (uint) std::max(query.value(7).toInt(), 0);
1818 
1819  // We should have at least 1000 ms to acquire tables...
1820  int table_timeout = ((int)gen_opts.m_channelTimeout -
1821  (int)gen_opts.m_signalTimeout);
1822  if (table_timeout < 1000)
1823  gen_opts.m_channelTimeout = gen_opts.m_signalTimeout + 1000;
1824 
1825  gen_opts.m_waitForSeqstart = query.value(8).toBool();
1826 
1827  // DVB options
1828  uint dvboff = 9;
1829  dvb_opts.m_dvbOnDemand = query.value(dvboff + 0).toBool();
1830  dvb_opts.m_dvbTuningDelay = std::chrono::milliseconds(query.value(dvboff + 1).toUInt());
1831  dvb_opts.m_dvbEitScan = query.value(dvboff + 2).toBool();
1832 
1833  // Firewire options
1834  uint fireoff = dvboff + 3;
1835  firewire_opts.m_speed = query.value(fireoff + 0).toUInt();
1836 
1837  test = query.value(fireoff + 1).toString();
1838  if (!test.isEmpty())
1839  firewire_opts.m_model = test;
1840 
1841  firewire_opts.m_connection = query.value(fireoff + 2).toUInt();
1842 
1843  parentid = query.value(15).toUInt();
1844 
1845  return true;
1846 }
1847 
1848 static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
1849 {
1850  if (!dtvMon->GetATSCStreamData())
1851  return;
1852 
1853  const MasterGuideTable *mgt = dtvMon->GetATSCStreamData()->GetCachedMGT();
1854  if (!mgt)
1855  return;
1856 
1857  for (uint i = 0; i < mgt->TableCount(); ++i)
1858  {
1859  pid_cache_item_t item(mgt->TablePID(i), mgt->TableType(i));
1860  pid_cache.push_back(item);
1861  }
1862  dtvMon->GetATSCStreamData()->ReturnCachedTable(mgt);
1863 }
1864 
1865 static bool ApplyCachedPids(DTVSignalMonitor *dtvMon, const DTVChannel* channel)
1866 {
1867  pid_cache_t pid_cache;
1868  channel->GetCachedPids(pid_cache);
1869  bool vctpid_cached = false;
1870  for (const auto& pid : pid_cache)
1871  {
1872  if ((pid.GetTableID() == TableID::TVCT) ||
1873  (pid.GetTableID() == TableID::CVCT))
1874  {
1875  vctpid_cached = true;
1876  dtvMon->GetATSCStreamData()->AddListeningPID(pid.GetPID());
1877  }
1878  }
1879  return vctpid_cached;
1880 }
1881 
1898 {
1899  LOG(VB_RECORD, LOG_INFO, LOC + "Setting up table monitoring.");
1900 
1902  DTVChannel *dtvchan = GetDTVChannel();
1903  if (!sm || !dtvchan)
1904  {
1905  LOG(VB_GENERAL, LOG_ERR, LOC + "Setting up table monitoring.");
1906  return false;
1907  }
1908 
1909  MPEGStreamData *sd = nullptr;
1910  if (GetDTVRecorder())
1911  {
1912  sd = GetDTVRecorder()->GetStreamData();
1913  sd->SetCaching(true);
1914  }
1915 
1916  QString recording_type = "all";
1920  const StandardSetting *setting = profile.byName("recordingtype");
1921  if (setting)
1922  recording_type = setting->getValue();
1923 
1924  const QString tuningmode = dtvchan->GetTuningMode();
1925 
1926  // Check if this is an ATSC Channel
1927  int major = dtvchan->GetMajorChannel();
1928  int minor = dtvchan->GetMinorChannel();
1929  if ((minor > 0) && (tuningmode == "atsc"))
1930  {
1931  QString msg = QString("ATSC channel: %1_%2").arg(major).arg(minor);
1932  LOG(VB_RECORD, LOG_INFO, LOC + msg);
1933 
1934  auto *asd = dynamic_cast<ATSCStreamData*>(sd);
1935  if (!asd)
1936  {
1937  sd = asd = new ATSCStreamData(major, minor, m_inputId);
1938  sd->SetCaching(true);
1939  if (GetDTVRecorder())
1940  GetDTVRecorder()->SetStreamData(asd);
1941  }
1942 
1943  asd->Reset();
1944  sm->SetStreamData(sd);
1945  sm->SetChannel(major, minor);
1946  sd->SetRecordingType(recording_type);
1947 
1948  // Try to get pid of VCT from cache and
1949  // require MGT if we don't have VCT pid.
1950  if (!ApplyCachedPids(sm, dtvchan))
1952 
1953  LOG(VB_RECORD, LOG_INFO, LOC +
1954  "Successfully set up ATSC table monitoring.");
1955  return true;
1956  }
1957 
1958  // Check if this is an DVB channel
1959  int progNum = dtvchan->GetProgramNumber();
1960  if ((progNum >= 0) && (tuningmode == "dvb") && CardUtil::IsChannelReusable(m_genOpt.m_inputType))
1961  {
1962  int netid = dtvchan->GetOriginalNetworkID();
1963  int tsid = dtvchan->GetTransportID();
1964 
1965  auto *dsd = dynamic_cast<DVBStreamData*>(sd);
1966  if (!dsd)
1967  {
1968  sd = dsd = new DVBStreamData(netid, tsid, progNum, m_inputId);
1969  sd->SetCaching(true);
1970  if (GetDTVRecorder())
1971  GetDTVRecorder()->SetStreamData(dsd);
1972  }
1973 
1974  LOG(VB_RECORD, LOG_INFO, LOC +
1975  QString("DVB service_id %1 on net_id %2 tsid %3")
1976  .arg(progNum).arg(netid).arg(tsid));
1977 
1979 
1980  dsd->Reset();
1981  sm->SetStreamData(sd);
1982  sm->SetDVBService(netid, tsid, progNum);
1983  sd->SetRecordingType(recording_type);
1984 
1988  sm->SetRotorTarget(1.0F);
1989 
1990  if (EITscan)
1991  {
1993  sm->IgnoreEncrypted(true);
1994  }
1995 
1996  LOG(VB_RECORD, LOG_INFO, LOC +
1997  "Successfully set up DVB table monitoring.");
1998  return true;
1999  }
2000 
2001  // Check if this is an MPEG channel
2002  if (progNum >= 0)
2003  {
2004  if (!sd)
2005  {
2006  sd = new MPEGStreamData(progNum, m_inputId, true);
2007  sd->SetCaching(true);
2008  if (GetDTVRecorder())
2010  }
2011 
2012  QString msg = QString("MPEG program number: %1").arg(progNum);
2013  LOG(VB_RECORD, LOG_INFO, LOC + msg);
2014 
2016 
2017  sd->Reset();
2018  sm->SetStreamData(sd);
2019  sm->SetProgramNumber(progNum);
2020  sd->SetRecordingType(recording_type);
2021 
2025  sm->SetRotorTarget(1.0F);
2026 
2027  if (EITscan)
2028  {
2030  sm->IgnoreEncrypted(true);
2031  }
2032 
2033  LOG(VB_RECORD, LOG_INFO, LOC +
2034  "Successfully set up MPEG table monitoring.");
2035  return true;
2036  }
2037 
2038  // If this is not an ATSC, DVB or MPEG channel then check to make sure
2039  // that we have permanent pidcache entries.
2040  bool ok = false;
2041  if (GetDTVChannel())
2042  {
2043  pid_cache_t pid_cache;
2044  GetDTVChannel()->GetCachedPids(pid_cache);
2045  for (auto item = pid_cache.cbegin(); !ok && item != pid_cache.cend(); ++item)
2046  ok |= item->IsPermanent();
2047  }
2048 
2049  if (!ok)
2050  {
2051  QString msg = "No valid DTV info, ATSC maj(%1) min(%2), MPEG pn(%3)";
2052  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(major).arg(minor).arg(progNum));
2053  }
2054  else
2055  {
2056  LOG(VB_RECORD, LOG_INFO, LOC +
2057  "Successfully set up raw pid monitoring.");
2058  }
2059 
2060  return ok;
2061 }
2062 
2077 bool TVRec::SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
2078 {
2079  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetupSignalMonitor(%1, %2)")
2080  .arg(tablemon).arg(notify));
2081 
2082  // if it already exists, there no need to initialize it
2083  if (m_signalMonitor)
2084  return true;
2085 
2086  // if there is no channel object we can't monitor it
2087  if (!m_channel)
2088  return false;
2089 
2090  // nothing to monitor here either (DummyChannel)
2091  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
2092  return true;
2093 
2094  // make sure statics are initialized
2096 
2099  m_channel, false);
2100 
2101  if (m_signalMonitor)
2102  {
2103  LOG(VB_RECORD, LOG_INFO, LOC + "Signal monitor successfully created");
2104  // If this is a monitor for Digital TV, initialize table monitors
2105  if (GetDTVSignalMonitor() && tablemon &&
2106  !SetupDTVSignalMonitor(EITscan))
2107  {
2108  LOG(VB_GENERAL, LOG_ERR, LOC +
2109  "Failed to setup digital signal monitoring");
2110 
2111  return false;
2112  }
2113 
2116  kSignalMonitoringRate * 5 :
2119 
2120  // Start the monitoring thread
2122  }
2123 
2124  return true;
2125 }
2126 
2132 {
2133  if (!m_signalMonitor)
2134  return;
2135 
2136  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- begin");
2137 
2138  // If this is a DTV signal monitor, save any pids we know about.
2140  DTVChannel *dtvChan = GetDTVChannel();
2141  if (dtvMon && dtvChan)
2142  {
2143  pid_cache_t pid_cache;
2144  GetPidsToCache(dtvMon, pid_cache);
2145  if (!pid_cache.empty())
2146  dtvChan->SaveCachedPids(pid_cache);
2147  }
2148 
2149  if (m_signalMonitor)
2150  {
2151  delete m_signalMonitor;
2152  m_signalMonitor = nullptr;
2153  }
2154 
2155  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- end");
2156 }
2157 
2169 std::chrono::milliseconds TVRec::SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend)
2170 {
2171  QString msg = "SetSignalMonitoringRate(%1, %2)";
2172  LOG(VB_RECORD, LOG_INFO, LOC +
2173  msg.arg(rate.count()).arg(notifyFrontend) + "-- start");
2174 
2175  QMutexLocker lock(&m_stateChangeLock);
2176 
2178  {
2179  LOG(VB_GENERAL, LOG_ERR, LOC +
2180  "Signal Monitoring is notsupported by your hardware.");
2181  return 0ms;
2182  }
2183 
2185  {
2186  LOG(VB_GENERAL, LOG_ERR, LOC +
2187  "Signal can only be monitored in LiveTV Mode.");
2188  return 0ms;
2189  }
2190 
2191  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
2192 
2193  TuningRequest req = (rate > 0ms) ?
2196 
2198 
2199  // Wait for RingBuffer reset
2200  while (!HasFlags(kFlagRingBufferReady))
2202  LOG(VB_RECORD, LOG_INFO, LOC +
2203  msg.arg(rate.count()).arg(notifyFrontend) + " -- end");
2204  return 1ms;
2205 }
2206 
2208 {
2209  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
2210 }
2211 
2223 bool TVRec::ShouldSwitchToAnotherInput(const QString& chanid) const
2224 {
2225  QString msg("");
2226  MSqlQuery query(MSqlQuery::InitCon());
2227 
2228  if (!query.isConnected())
2229  return false;
2230 
2231  query.prepare("SELECT channel.channum, channel.callsign "
2232  "FROM channel "
2233  "WHERE channel.chanid = :CHANID");
2234  query.bindValue(":CHANID", chanid);
2235  if (!query.exec() || !query.next())
2236  {
2237  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2238  return false;
2239  }
2240 
2241  QString channelname = query.value(0).toString();
2242  QString callsign = query.value(1).toString();
2243 
2244  query.prepare(
2245  "SELECT channel.channum "
2246  "FROM channel, capturecard "
2247  "WHERE deleted IS NULL AND "
2248  " ( channel.chanid = :CHANID OR "
2249  " ( channel.channum = :CHANNUM AND "
2250  " channel.callsign = :CALLSIGN ) "
2251  " ) AND "
2252  " channel.sourceid = capturecard.sourceid AND "
2253  " capturecard.cardid = :INPUTID");
2254  query.bindValue(":CHANID", chanid);
2255  query.bindValue(":CHANNUM", channelname);
2256  query.bindValue(":CALLSIGN", callsign);
2257  query.bindValue(":INPUTID", m_inputId);
2258 
2259  if (!query.exec() || !query.isActive())
2260  {
2261  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2262  }
2263  else if (query.size() > 0)
2264  {
2265  msg = "Found channel (%1) on current input[%2].";
2266  LOG(VB_RECORD, LOG_INFO, LOC + msg.arg(channelname).arg(m_inputId));
2267  return false;
2268  }
2269 
2270  // We didn't find it on the current input, so now we check other inputs.
2271  query.prepare(
2272  "SELECT channel.channum, capturecard.cardid "
2273  "FROM channel, capturecard "
2274  "WHERE deleted IS NULL AND "
2275  " ( channel.chanid = :CHANID OR "
2276  " ( channel.channum = :CHANNUM AND "
2277  " channel.callsign = :CALLSIGN ) "
2278  " ) AND "
2279  " channel.sourceid = capturecard.sourceid AND "
2280  " capturecard.cardid != :INPUTID");
2281  query.bindValue(":CHANID", chanid);
2282  query.bindValue(":CHANNUM", channelname);
2283  query.bindValue(":CALLSIGN", callsign);
2284  query.bindValue(":INPUTID", m_inputId);
2285 
2286  if (!query.exec() || !query.isActive())
2287  {
2288  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2289  }
2290  else if (query.next())
2291  {
2292  msg = QString("Found channel (%1) on different input(%2).")
2293  .arg(query.value(0).toString(), query.value(1).toString());
2294  LOG(VB_RECORD, LOG_INFO, LOC + msg);
2295  return true;
2296  }
2297 
2298  msg = QString("Did not find channel(%1) on any input.").arg(channelname);
2299  LOG(VB_RECORD, LOG_ERR, LOC + msg);
2300  return false;
2301 }
2302 
2313 bool TVRec::CheckChannel(const QString& name) const
2314 {
2315  if (!m_channel)
2316  return false;
2317 
2318  return m_channel->CheckChannel(name);
2319 }
2320 
2324 static QString add_spacer(const QString &channel, const QString &spacer)
2325 {
2326  QString chan = channel;
2327  if ((chan.length() >= 2) && !spacer.isEmpty())
2328  return chan.left(chan.length()-1) + spacer + chan.right(1);
2329  return chan;
2330 }
2331 
2359 bool TVRec::CheckChannelPrefix(const QString &prefix,
2360  uint &complete_valid_channel_on_rec,
2361  bool &is_extra_char_useful,
2362  QString &needed_spacer) const
2363 {
2364 #if DEBUG_CHANNEL_PREFIX
2365  LOG(VB_GENERAL, LOG_DEBUG, QString("CheckChannelPrefix(%1)").arg(prefix));
2366 #endif
2367 
2368  static const std::array<const QString,5> s_spacers = { "", "_", "-", "#", "." };
2369 
2370  MSqlQuery query(MSqlQuery::InitCon());
2371  QString basequery = QString(
2372  "SELECT channel.chanid, channel.channum, capturecard.cardid "
2373  "FROM channel, capturecard "
2374  "WHERE deleted IS NULL AND "
2375  " channel.channum LIKE '%1%' AND "
2376  " channel.sourceid = capturecard.sourceid");
2377 
2378  const std::array<const QString,2> inputquery
2379  {
2380  QString(" AND capturecard.cardid = '%1'").arg(m_inputId),
2381  QString(" AND capturecard.cardid != '%1'").arg(m_inputId),
2382  };
2383 
2384  std::vector<unsigned int> fchanid;
2385  std::vector<QString> fchannum;
2386  std::vector<unsigned int> finputid;
2387  std::vector<QString> fspacer;
2388 
2389  for (const auto & str : inputquery)
2390  {
2391  for (const auto & spacer : s_spacers)
2392  {
2393  QString qprefix = add_spacer(
2394  prefix, (spacer == "_") ? "\\_" : spacer);
2395  query.prepare(basequery.arg(qprefix) + str);
2396 
2397  if (!query.exec() || !query.isActive())
2398  {
2399  MythDB::DBError("checkchannel -- locate channum", query);
2400  }
2401  else if (query.size())
2402  {
2403  while (query.next())
2404  {
2405  fchanid.push_back(query.value(0).toUInt());
2406  fchannum.push_back(query.value(1).toString());
2407  finputid.push_back(query.value(2).toUInt());
2408  fspacer.emplace_back(spacer);
2409 #if DEBUG_CHANNEL_PREFIX
2410  LOG(VB_GENERAL, LOG_DEBUG,
2411  QString("(%1,%2) Adding %3 rec %4")
2412  .arg(i).arg(j).arg(query.value(1).toString(),6)
2413  .arg(query.value(2).toUInt()));
2414 #endif
2415  }
2416  }
2417 
2418  if (prefix.length() < 2)
2419  break;
2420  }
2421  }
2422 
2423  // Now process the lists for the info we need...
2424  is_extra_char_useful = false;
2425  complete_valid_channel_on_rec = 0;
2426  needed_spacer.clear();
2427 
2428  if (fchanid.empty())
2429  return false;
2430 
2431  if (fchanid.size() == 1) // Unique channel...
2432  {
2433  needed_spacer = fspacer[0];
2434  bool nc = (fchannum[0] != add_spacer(prefix, fspacer[0]));
2435 
2436  complete_valid_channel_on_rec = (nc) ? 0 : finputid[0];
2437  is_extra_char_useful = nc;
2438  return true;
2439  }
2440 
2441  // If we get this far there is more than one channel
2442  // sharing the prefix we were given.
2443 
2444  // Is an extra characher useful for disambiguation?
2445  is_extra_char_useful = false;
2446  for (uint i = 0; (i < fchannum.size()) && !is_extra_char_useful; i++)
2447  {
2448  is_extra_char_useful = (fchannum[i] != add_spacer(prefix, fspacer[i]));
2449 #if DEBUG_CHANNEL_PREFIX
2450  LOG(VB_GENERAL, LOG_DEBUG, QString("is_extra_char_useful(%1!=%2): %3")
2451  .arg(fchannum[i]).arg(add_spacer(prefix, fspacer[i]))
2452  .arg(is_extra_char_useful));
2453 #endif
2454  }
2455 
2456  // Are any of the channels complete w/o spacer?
2457  // If so set complete_valid_channel_on_rec,
2458  // with a preference for our inputid.
2459  for (size_t i = 0; i < fchannum.size(); i++)
2460  {
2461  if (fchannum[i] == prefix)
2462  {
2463  complete_valid_channel_on_rec = finputid[i];
2464  if (finputid[i] == m_inputId)
2465  break;
2466  }
2467  }
2468 
2469  if (complete_valid_channel_on_rec != 0)
2470  return true;
2471 
2472  // Add a spacer, if one is needed to select a valid channel.
2473  bool spacer_needed = true;
2474  for (uint i = 0; (i < fspacer.size() && spacer_needed); i++)
2475  spacer_needed = !fspacer[i].isEmpty();
2476  if (spacer_needed)
2477  needed_spacer = fspacer[0];
2478 
2479  // If it isn't useful to wait for more characters,
2480  // then try to commit to any true match immediately.
2481  for (size_t i = 0; i < ((is_extra_char_useful) ? 0 : fchanid.size()); i++)
2482  {
2483  if (fchannum[i] == add_spacer(prefix, fspacer[i]))
2484  {
2485  needed_spacer = fspacer[i];
2486  complete_valid_channel_on_rec = finputid[i];
2487  return true;
2488  }
2489  }
2490 
2491  return true;
2492 }
2493 
2495  const QString &channum)
2496 {
2497  if (!m_recorder)
2498  return false;
2499 
2500  QString videoFilters = ChannelUtil::GetVideoFilters(sourceid, channum);
2501  if (!videoFilters.isEmpty())
2502  {
2503  m_recorder->SetVideoFilters(videoFilters);
2504  return true;
2505  }
2506 
2507  return false;
2508 }
2509 
2515 {
2516  return ((m_recorder && m_recorder->IsRecording()) ||
2518 }
2519 
2525 bool TVRec::IsBusy(InputInfo *busy_input, std::chrono::seconds time_buffer) const
2526 {
2527  InputInfo dummy;
2528  if (!busy_input)
2529  busy_input = &dummy;
2530 
2531  busy_input->Clear();
2532 
2533  if (!m_channel)
2534  return false;
2535 
2536  if (!m_channel->GetInputID())
2537  return false;
2538 
2539  uint chanid = 0;
2540 
2541  if (GetState() != kState_None)
2542  {
2543  busy_input->m_inputId = m_channel->GetInputID();
2544  chanid = m_channel->GetChanID();
2545  }
2546 
2547  PendingInfo pendinfo;
2548  bool has_pending = false;
2549  {
2550  m_pendingRecLock.lock();
2551  PendingMap::const_iterator it = m_pendingRecordings.find(m_inputId);
2552  has_pending = (it != m_pendingRecordings.end());
2553  if (has_pending)
2554  pendinfo = *it;
2555  m_pendingRecLock.unlock();
2556  }
2557 
2558  if (!busy_input->m_inputId && has_pending)
2559  {
2560  auto timeLeft = MythDate::secsInFuture(pendinfo.m_recordingStart);
2561 
2562  if (timeLeft <= time_buffer)
2563  {
2564  QString channum;
2565  QString input;
2566  if (pendinfo.m_info->QueryTuningInfo(channum, input))
2567  {
2568  busy_input->m_inputId = m_channel->GetInputID();
2569  chanid = pendinfo.m_info->GetChanID();
2570  }
2571  }
2572  }
2573 
2574  if (busy_input->m_inputId)
2575  {
2576  CardUtil::GetInputInfo(*busy_input);
2577  busy_input->m_chanId = chanid;
2578  busy_input->m_mplexId = ChannelUtil::GetMplexID(busy_input->m_chanId);
2579  busy_input->m_mplexId =
2580  (32767 == busy_input->m_mplexId) ? 0 : busy_input->m_mplexId;
2581  }
2582 
2583  return busy_input->m_inputId != 0U;
2584 }
2585 
2586 
2594 {
2595  QMutexLocker lock(&m_stateChangeLock);
2596 
2597  if (m_recorder)
2598  return m_recorder->GetFrameRate();
2599  return -1.0F;
2600 }
2601 
2609 {
2610  QMutexLocker lock(&m_stateChangeLock);
2611 
2612  if (m_recorder)
2613  return m_recorder->GetFramesWritten();
2614  return -1;
2615 }
2616 
2623 long long TVRec::GetFilePosition(void)
2624 {
2625  QMutexLocker lock(&m_stateChangeLock);
2626 
2627  if (m_buffer)
2628  return m_buffer->GetWritePosition();
2629  return -1;
2630 }
2631 
2639 int64_t TVRec::GetKeyframePosition(uint64_t desired) const
2640 {
2641  QMutexLocker lock(&m_stateChangeLock);
2642 
2643  if (m_recorder)
2644  return m_recorder->GetKeyframePosition(desired);
2645  return -1;
2646 }
2647 
2657  int64_t start, int64_t end, frm_pos_map_t &map) const
2658 {
2659  QMutexLocker lock(&m_stateChangeLock);
2660 
2661  if (m_recorder)
2662  return m_recorder->GetKeyframePositions(start, end, map);
2663 
2664  return false;
2665 }
2666 
2668  int64_t start, int64_t end, frm_pos_map_t &map) const
2669 {
2670  QMutexLocker lock(&m_stateChangeLock);
2671 
2672  if (m_recorder)
2673  return m_recorder->GetKeyframeDurations(start, end, map);
2674 
2675  return false;
2676 }
2677 
2683 long long TVRec::GetMaxBitrate(void) const
2684 {
2685  long long bitrate = 0;
2686  if (m_genOpt.m_inputType == "MPEG")
2687  { // NOLINT(bugprone-branch-clone)
2688  bitrate = 10080000LL; // use DVD max bit rate
2689  }
2690  else if (m_genOpt.m_inputType == "HDPVR")
2691  {
2692  bitrate = 20200000LL; // Peak bit rate for HD-PVR
2693  }
2695  {
2696  bitrate = 22200000LL; // 1080i
2697  }
2698  else // frame grabber
2699  {
2700  bitrate = 10080000LL; // use DVD max bit rate, probably too big
2701  }
2702 
2703  return bitrate;
2704 }
2705 
2711 void TVRec::SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
2712 {
2713  QMutexLocker lock(&m_stateChangeLock);
2714 
2715  m_tvChain = newchain;
2716  m_tvChain->IncrRef(); // mark it for TVRec use
2717  m_tvChain->ReloadAll();
2718 
2719  QString hostprefix = MythCoreContext::GenMythURL(
2722 
2723  m_tvChain->SetHostPrefix(hostprefix);
2725 
2726  m_isPip = pip;
2727  m_liveTVStartChannel = std::move(startchan);
2728 
2729  // Change to WatchingLiveTV
2731  // Wait for state change to take effect
2733 
2734  // Make sure StartRecording can't steal our tuner
2735  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2736 }
2737 
2741 QString TVRec::GetChainID(void)
2742 {
2743  if (m_tvChain)
2744  return m_tvChain->GetID();
2745  return "";
2746 }
2747 
2757 {
2758  QMutexLocker lock(&m_stateChangeLock);
2759 
2761  return; // already stopped
2762 
2763  if (!m_curRecording)
2764  return;
2765 
2766  const QString recgrp = m_curRecording->QueryRecordingGroup();
2768 
2769  if (recgrp != "LiveTV" && !m_pseudoLiveTVRecording)
2770  {
2771  // User wants this recording to continue
2773  }
2774  else if (recgrp == "LiveTV" && m_pseudoLiveTVRecording)
2775  {
2776  // User wants to abandon scheduled recording
2777  SetPseudoLiveTVRecording(nullptr);
2778  }
2779 }
2780 
2791 {
2792  if (!m_channel)
2793  return;
2794 
2795  // Notify scheduler of the recording.
2796  // + set up recording so it can be resumed
2797  rec->SetInputID(m_inputId);
2799 
2800  if (rec->GetRecordingRuleType() == kNotRecording)
2801  {
2804  }
2805 
2806  // + remove any end offset which would mismatch the live session
2807  rec->GetRecordingRule()->m_endOffset = 0;
2808 
2809  // + save RecStatus::Inactive recstatus to so that a reschedule call
2810  // doesn't start recording this on another input before we
2811  // send the SCHEDULER_ADD_RECORDING message to the scheduler.
2813  rec->AddHistory(false);
2814 
2815  // + save RecordingRule so that we get a recordid
2816  // (don't allow RescheduleMatch(), avoiding unneeded reschedule)
2817  rec->GetRecordingRule()->Save(false);
2818 
2819  // + save recordid to recorded entry
2820  rec->ApplyRecordRecID();
2821 
2822  // + set proper recstatus (saved later)
2824 
2825  // + pass proginfo to scheduler and reschedule
2826  QStringList prog;
2827  rec->ToStringList(prog);
2828  MythEvent me("SCHEDULER_ADD_RECORDING", prog);
2829  gCoreContext->dispatch(me);
2830 
2831  // Allow scheduler to end this recording before post-roll,
2832  // if it has another recording for this recorder.
2833  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2834 }
2835 
2837  RecordingProfile *recpro, int line)
2838 {
2839  if (kAutoRunProfile == t)
2840  {
2842  if (!recpro)
2843  {
2844  LoadProfile(nullptr, rec, profile);
2845  recpro = &profile;
2846  }
2847  m_autoRunJobs[rec->MakeUniqueKey()] =
2848  init_jobs(rec, *recpro, m_runJobOnHostOnly,
2850  }
2851  else
2852  {
2854  }
2855  LOG(VB_JOBQUEUE, LOG_INFO,
2856  QString("InitAutoRunJobs for %1, line %2 -> 0x%3")
2857  .arg(rec->MakeUniqueKey()).arg(line)
2858  .arg(m_autoRunJobs[rec->MakeUniqueKey()],0,16));
2859 }
2860 
2872 void TVRec::SetLiveRecording([[maybe_unused]] int recording)
2873 {
2874  LOG(VB_GENERAL, LOG_INFO, LOC +
2875  QString("SetLiveRecording(%1)").arg(recording));
2876  QMutexLocker locker(&m_stateChangeLock);
2877 
2879  bool was_rec = m_pseudoLiveTVRecording;
2881  if (was_rec && !m_pseudoLiveTVRecording)
2882  {
2883  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- cancel");
2884  // cancel -- 'recording' should be 0 or -1
2885  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2886  m_curRecording->SetRecordingGroup("LiveTV");
2887  InitAutoRunJobs(m_curRecording, kAutoRunNone, nullptr, __LINE__);
2888  }
2889  else if (!was_rec && m_pseudoLiveTVRecording)
2890  {
2891  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- record");
2892  // record -- 'recording' should be 1 or -1
2893 
2894  // If the last recording was flagged for keeping
2895  // in the frontend, then add the recording rule
2896  // so that transcode, commfrag, etc can be run.
2899  recstat = m_curRecording->GetRecordingStatus();
2900  m_curRecording->SetRecordingGroup("Default");
2901  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
2902  }
2903 
2904  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
2905  .arg(m_curRecording->GetInputID())
2906  .arg(m_curRecording->GetChanID())
2908  .arg(recstat)
2910 
2911  gCoreContext->dispatch(me);
2912 }
2913 
2919 {
2920  QMutexLocker lock(&m_stateChangeLock);
2921  LOG(VB_RECORD, LOG_INFO, LOC +
2922  QString("StopLiveTV(void) curRec: 0x%1 pseudoRec: 0x%2")
2923  .arg((uint64_t)m_curRecording,0,16)
2924  .arg((uint64_t)m_pseudoLiveTVRecording,0,16));
2925 
2927  return;
2928 
2929  bool hadPseudoLiveTVRec = m_pseudoLiveTVRecording;
2931 
2932  if (!hadPseudoLiveTVRec && m_pseudoLiveTVRecording)
2934 
2935  // Figure out next state and if needed recording end time.
2936  TVState next_state = kState_None;
2938  {
2940  next_state = kState_RecordingOnly;
2941  }
2942 
2943  // Change to the appropriate state
2944  ChangeState(next_state);
2945 
2946  // Wait for state change to take effect...
2948 
2949  // We are done with the tvchain...
2950  if (m_tvChain)
2951  {
2952  m_tvChain->DecrRef();
2953  }
2954  m_tvChain = nullptr;
2955 }
2956 
2966 {
2967  QMutexLocker lock(&m_stateChangeLock);
2968 
2969  if (!m_recorder)
2970  {
2971  LOG(VB_GENERAL, LOG_ERR, LOC +
2972  "PauseRecorder() called with no recorder");
2973  return;
2974  }
2975 
2976  m_recorder->Pause();
2977 }
2978 
2985 {
2986  if (m_pauseNotify)
2987  WakeEventLoop();
2988 }
2989 
2993 void TVRec::ToggleChannelFavorite(const QString& changroupname)
2994 {
2995  QMutexLocker lock(&m_stateChangeLock);
2996 
2997  if (!m_channel)
2998  return;
2999 
3000  // Get current channel id...
3001  uint sourceid = m_channel->GetSourceID();
3002  QString channum = m_channel->GetChannelName();
3003  uint chanid = ChannelUtil::GetChanID(sourceid, channum);
3004 
3005  if (!chanid)
3006  {
3007  LOG(VB_GENERAL, LOG_ERR, LOC +
3008  QString("Channel: \'%1\' was not found in the database.\n"
3009  "\t\tMost likely, the 'starting channel' for this "
3010  "Input Connection is invalid.\n"
3011  "\t\tCould not toggle favorite.").arg(channum));
3012  return;
3013  }
3014 
3015  int changrpid = ChannelGroup::GetChannelGroupId(changroupname);
3016  if (changrpid <1)
3017  {
3018  LOG(VB_RECORD, LOG_ERR, LOC +
3019  QString("ToggleChannelFavorite: Invalid channel group name %1,")
3020  .arg(changroupname));
3021  }
3022  else
3023  {
3024  bool result = ChannelGroup::ToggleChannel(chanid, changrpid, true);
3025 
3026  if (!result)
3027  LOG(VB_RECORD, LOG_ERR, LOC + "Unable to toggle channel favorite.");
3028  else
3029  {
3030  LOG(VB_RECORD, LOG_INFO, LOC +
3031  QString("Toggled channel favorite.channum %1, chan group %2")
3032  .arg(channum, changroupname));
3033  }
3034  }
3035 }
3036 
3043 {
3044  QMutexLocker lock(&m_stateChangeLock);
3045  if (!m_channel)
3046  return -1;
3047 
3048  int ret = m_channel->GetPictureAttribute(attr);
3049 
3050  return (ret < 0) ? -1 : ret / 655;
3051 }
3052 
3061  PictureAttribute attr,
3062  bool direction)
3063 {
3064  QMutexLocker lock(&m_stateChangeLock);
3065  if (!m_channel)
3066  return -1;
3067 
3068  int ret = m_channel->ChangePictureAttribute(type, attr, direction);
3069 
3070  return (ret < 0) ? -1 : ret / 655;
3071 }
3072 
3076 QString TVRec::GetInput(void) const
3077 {
3078  if (m_channel)
3079  return m_channel->GetInputName();
3080  return {};
3081 }
3082 
3087 {
3088  if (m_channel)
3089  return m_channel->GetSourceID();
3090  return 0;
3091 }
3092 
3101 QString TVRec::SetInput(QString input)
3102 {
3103  QMutexLocker lock(&m_stateChangeLock);
3104  QString origIn = input;
3105  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + input + ") -- begin");
3106 
3107  if (!m_channel)
3108  {
3109  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput() -- end no channel class");
3110  return {};
3111  }
3112 
3113  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + origIn + ":" + input +
3114  ") -- end nothing to do");
3115  return input;
3116 }
3117 
3127 void TVRec::SetChannel(const QString& name, uint requestType)
3128 {
3129  QMutexLocker locker1(&m_setChannelLock);
3130  QMutexLocker locker2(&m_stateChangeLock);
3131 
3132  LOG(VB_CHANNEL, LOG_INFO, LOC +
3133  QString("SetChannel(%1) -- begin").arg(name));
3134 
3135  // Detect tuning request type if needed
3136  if (requestType & kFlagDetect)
3137  {
3139  requestType = m_lastTuningRequest.m_flags & (kFlagRec | kFlagNoRec);
3140  }
3141 
3142  // Clear the RingBuffer reset flag, in case we wait for a reset below
3143  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3144 
3145  // Clear out any EITScan channel change requests
3146  auto it = m_tuningRequests.begin();
3147  while (it != m_tuningRequests.end())
3148  {
3149  if ((*it).m_flags & kFlagEITScan)
3150  it = m_tuningRequests.erase(it);
3151  else
3152  ++it;
3153  }
3154 
3155  // Actually add the tuning request to the queue, and
3156  // then wait for it to start tuning
3157  m_tuningRequests.enqueue(TuningRequest(requestType, name));
3159 
3160  // If we are using a recorder, wait for a RingBuffer reset
3161  if (requestType & kFlagRec)
3162  {
3163  while (!HasFlags(kFlagRingBufferReady))
3165  }
3166  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetChannel(%1) -- end").arg(name));
3167 }
3168 
3176 bool TVRec::QueueEITChannelChange(const QString &name)
3177 {
3178  LOG(VB_CHANNEL, LOG_INFO, LOC +
3179  QString("QueueEITChannelChange(%1)").arg(name));
3180 
3181  bool ok = false;
3182  if (m_setChannelLock.tryLock())
3183  {
3184  if (m_stateChangeLock.tryLock())
3185  {
3186  if (m_tuningRequests.empty())
3187  {
3189  ok = true;
3190  }
3191  m_stateChangeLock.unlock();
3192  }
3193  m_setChannelLock.unlock();
3194  }
3195 
3196  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
3197  QString("QueueEITChannelChange(%1) %2")
3198  .arg(name, ok ? "done" : "failed"));
3199 
3200  return ok;
3201 }
3202 
3204  QString &title, QString &subtitle,
3205  QString &desc, QString &category,
3206  QString &starttime, QString &endtime,
3207  QString &callsign, QString &iconpath,
3208  QString &channum, uint &sourceChanid,
3209  QString &seriesid, QString &programid)
3210 {
3211  QString compare = "<=";
3212  QString sortorder = "desc";
3213  uint chanid = 0;
3214 
3215  if (sourceChanid)
3216  {
3217  chanid = sourceChanid;
3218 
3219  if (BROWSE_UP == direction)
3220  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_UP);
3221  else if (BROWSE_DOWN == direction)
3222  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_DOWN);
3223  else if (BROWSE_FAVORITE == direction)
3224  {
3225  chanid = m_channel->GetNextChannel(
3226  chanid, CHANNEL_DIRECTION_FAVORITE);
3227  }
3228  else if (BROWSE_LEFT == direction)
3229  {
3230  compare = "<";
3231  }
3232  else if (BROWSE_RIGHT == direction)
3233  {
3234  compare = ">";
3235  sortorder = "asc";
3236  }
3237  }
3238 
3239  if (!chanid)
3240  {
3241  if (BROWSE_SAME == direction)
3242  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3243  else if (BROWSE_UP == direction)
3244  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_UP);
3245  else if (BROWSE_DOWN == direction)
3246  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_DOWN);
3247  else if (BROWSE_FAVORITE == direction)
3248  {
3249  chanid = m_channel->GetNextChannel(channum,
3251  }
3252  else if (BROWSE_LEFT == direction)
3253  {
3254  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3255  compare = "<";
3256  }
3257  else if (BROWSE_RIGHT == direction)
3258  {
3259  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3260  compare = ">";
3261  sortorder = "asc";
3262  }
3263  }
3264 
3265  QString querystr = QString(
3266  "SELECT title, subtitle, description, category, "
3267  " starttime, endtime, callsign, icon, "
3268  " channum, seriesid, programid "
3269  "FROM program, channel "
3270  "WHERE program.chanid = channel.chanid AND "
3271  " channel.chanid = :CHANID AND "
3272  " starttime %1 :STARTTIME "
3273  "ORDER BY starttime %2 "
3274  "LIMIT 1").arg(compare, sortorder);
3275 
3276  MSqlQuery query(MSqlQuery::InitCon());
3277  query.prepare(querystr);
3278  query.bindValue(":CHANID", chanid);
3279  query.bindValue(":STARTTIME", starttime);
3280 
3281  // Clear everything now in case either query fails.
3282  title = subtitle = desc = category = "";
3283  starttime = endtime = callsign = iconpath = "";
3284  channum = seriesid = programid = "";
3285  sourceChanid = 0;
3286 
3287  // Try to get the program info
3288  if (!query.exec() && !query.isActive())
3289  {
3290  MythDB::DBError("GetNextProgram -- get program info", query);
3291  }
3292  else if (query.next())
3293  {
3294  title = query.value(0).toString();
3295  subtitle = query.value(1).toString();
3296  desc = query.value(2).toString();
3297  category = query.value(3).toString();
3298  starttime = query.value(4).toString();
3299  endtime = query.value(5).toString();
3300  callsign = query.value(6).toString();
3301  iconpath = query.value(7).toString();
3302  channum = query.value(8).toString();
3303  seriesid = query.value(9).toString();
3304  programid = query.value(10).toString();
3305  sourceChanid = chanid;
3306  return;
3307  }
3308 
3309  // Couldn't get program info, so get the channel info instead
3310  query.prepare(
3311  "SELECT channum, callsign, icon "
3312  "FROM channel "
3313  "WHERE chanid = :CHANID");
3314  query.bindValue(":CHANID", chanid);
3315 
3316  if (!query.exec() || !query.isActive())
3317  {
3318  MythDB::DBError("GetNextProgram -- get channel info", query);
3319  }
3320  else if (query.next())
3321  {
3322  sourceChanid = chanid;
3323  channum = query.value(0).toString();
3324  callsign = query.value(1).toString();
3325  iconpath = query.value(2).toString();
3326  }
3327 }
3328 
3329 bool TVRec::GetChannelInfo(uint &chanid, uint &sourceid,
3330  QString &callsign, QString &channum,
3331  QString &channame, QString &xmltvid) const
3332 {
3333  callsign.clear();
3334  channum.clear();
3335  channame.clear();
3336  xmltvid.clear();
3337 
3338  if ((!chanid || !sourceid) && !m_channel)
3339  return false;
3340 
3341  if (!chanid)
3342  chanid = (uint) std::max(m_channel->GetChanID(), 0);
3343 
3344  if (!sourceid)
3345  sourceid = m_channel->GetSourceID();
3346 
3347  MSqlQuery query(MSqlQuery::InitCon());
3348  query.prepare(
3349  "SELECT callsign, channum, name, xmltvid "
3350  "FROM channel "
3351  "WHERE chanid = :CHANID");
3352  query.bindValue(":CHANID", chanid);
3353  if (!query.exec() || !query.isActive())
3354  {
3355  MythDB::DBError("GetChannelInfo", query);
3356  return false;
3357  }
3358 
3359  if (!query.next())
3360  return false;
3361 
3362  callsign = query.value(0).toString();
3363  channum = query.value(1).toString();
3364  channame = query.value(2).toString();
3365  xmltvid = query.value(3).toString();
3366 
3367  return true;
3368 }
3369 
3370 bool TVRec::SetChannelInfo(uint chanid, uint sourceid,
3371  const QString& oldchannum,
3372  const QString& callsign, const QString& channum,
3373  const QString& channame, const QString& xmltvid)
3374 {
3375  if (!chanid || !sourceid || channum.isEmpty())
3376  return false;
3377 
3378  MSqlQuery query(MSqlQuery::InitCon());
3379  query.prepare(
3380  "UPDATE channel "
3381  "SET callsign = :CALLSIGN, "
3382  " channum = :CHANNUM, "
3383  " name = :CHANNAME, "
3384  " xmltvid = :XMLTVID "
3385  "WHERE chanid = :CHANID AND "
3386  " sourceid = :SOURCEID");
3387  query.bindValue(":CALLSIGN", callsign);
3388  query.bindValue(":CHANNUM", channum);
3389  query.bindValue(":CHANNAME", channame);
3390  query.bindValue(":XMLTVID", xmltvid);
3391  query.bindValue(":CHANID", chanid);
3392  query.bindValue(":SOURCEID", sourceid);
3393 
3394  if (!query.exec())
3395  {
3396  MythDB::DBError("SetChannelInfo", query);
3397  return false;
3398  }
3399 
3400  if (m_channel)
3401  m_channel->Renumber(sourceid, oldchannum, channum);
3402 
3403  return true;
3404 }
3405 
3410 {
3411  QMutexLocker lock(&m_stateChangeLock);
3412 
3413  MythMediaBuffer *oldbuffer = m_buffer;
3414  m_buffer = Buffer;
3415 
3416  if (oldbuffer && (oldbuffer != Buffer))
3417  {
3419  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3420  delete oldbuffer;
3421  }
3422 
3423  m_switchingBuffer = false;
3424 }
3425 
3427 {
3428  LOG(VB_GENERAL, LOG_INFO, LOC + "RingBufferChanged()");
3429 
3430  QMutexLocker lock(&m_stateChangeLock);
3431 
3432  if (pginfo)
3433  {
3434  if (m_curRecording)
3435  {
3438  delete m_curRecording;
3439  }
3441  m_curRecording = new RecordingInfo(*pginfo);
3444  }
3445 
3447 }
3448 
3450  QString &input) const
3451 {
3452  QString channum;
3453 
3454  if (request.m_program)
3455  {
3456  request.m_program->QueryTuningInfo(channum, input);
3457  return channum;
3458  }
3459 
3460  channum = request.m_channel;
3461  input = request.m_input;
3462 
3463  // If this is Live TV startup, we need a channel...
3464  if (channum.isEmpty() && (request.m_flags & kFlagLiveTV))
3465  {
3466  if (!m_liveTVStartChannel.isEmpty())
3467  channum = m_liveTVStartChannel;
3468  else
3469  {
3472  }
3473  }
3474  if (request.m_flags & kFlagLiveTV)
3475  m_channel->Init(channum, false);
3476 
3477  if (m_channel && !channum.isEmpty() && (channum.indexOf("NextChannel") >= 0))
3478  {
3479  // FIXME This is just horrible
3480  int dir = channum.right(channum.length() - 12).toInt();
3481  uint chanid = m_channel->GetNextChannel(0, static_cast<ChannelChangeDirection>(dir));
3482  channum = ChannelUtil::GetChanNum(chanid);
3483  }
3484 
3485  return channum;
3486 }
3487 
3489 {
3490  if ((request.m_flags & kFlagAntennaAdjust) || request.m_input.isEmpty() ||
3492  {
3493  return false;
3494  }
3495 
3496  uint sourceid = m_channel->GetSourceID();
3497  QString oldchannum = m_channel->GetChannelName();
3498  QString newchannum = request.m_channel;
3499 
3500  if (ChannelUtil::IsOnSameMultiplex(sourceid, newchannum, oldchannum))
3501  {
3503  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3504 
3505  if (atsc)
3506  {
3507  uint major = 0;
3508  uint minor = 0;
3509  ChannelUtil::GetATSCChannel(sourceid, newchannum, major, minor);
3510 
3511  if (minor && atsc->HasChannel(major, minor))
3512  {
3513  request.m_majorChan = major;
3514  request.m_minorChan = minor;
3515  return true;
3516  }
3517  }
3518 
3519  if (mpeg)
3520  {
3521  uint progNum = ChannelUtil::GetProgramNumber(sourceid, newchannum);
3522  if (mpeg->HasProgram(progNum))
3523  {
3524  request.m_progNum = progNum;
3525  return true;
3526  }
3527  }
3528  }
3529 
3530  return false;
3531 }
3532 
3541 {
3542  if (!m_tuningRequests.empty())
3543  {
3544  TuningRequest request = m_tuningRequests.front();
3545  LOG(VB_RECORD, LOG_INFO, LOC +
3546  "HandleTuning Request: " + request.toString());
3547 
3548  QString input;
3549  request.m_channel = TuningGetChanNum(request, input);
3550  request.m_input = input;
3551 
3552  if (TuningOnSameMultiplex(request))
3553  LOG(VB_CHANNEL, LOG_INFO, LOC + "On same multiplex");
3554 
3555  TuningShutdowns(request);
3556 
3557  // The dequeue isn't safe to do until now because we
3558  // release the stateChangeLock to teardown a recorder
3560 
3561  // Now we start new stuff
3562  if (request.m_flags & (kFlagRecording|kFlagLiveTV|
3564  {
3565  if (!m_recorder)
3566  {
3567  LOG(VB_RECORD, LOG_INFO, LOC +
3568  "No recorder yet, calling TuningFrequency");
3569  TuningFrequency(request);
3570  }
3571  else
3572  {
3573  LOG(VB_RECORD, LOG_INFO, LOC + "Waiting for recorder pause..");
3574  SetFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3575  }
3576  }
3577  m_lastTuningRequest = request;
3578  }
3579 
3581  {
3582  if (!m_recorder || !m_recorder->IsPaused())
3583  return;
3584 
3585  ClearFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3586  LOG(VB_RECORD, LOG_INFO, LOC +
3587  "Recorder paused, calling TuningFrequency");
3589  }
3590 
3591  MPEGStreamData *streamData = nullptr;
3592  if (HasFlags(kFlagWaitingForSignal) && !(streamData = TuningSignalCheck()))
3593  return;
3594 
3596  {
3597  if (m_recorder)
3599  else
3600  TuningNewRecorder(streamData);
3601 
3602  // If we got this far it is safe to set a new starting channel...
3603  if (m_channel)
3605  }
3606 }
3607 
3613 {
3614  LOG(VB_RECORD, LOG_INFO, LOC + QString("TuningShutdowns(%1)")
3615  .arg(request.toString()));
3616 
3617  if (m_scanner && !(request.m_flags & kFlagEITScan) &&
3619  {
3621  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
3623  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
3624  }
3625 
3626  if (m_scanner && !request.IsOnSameMultiplex())
3628 
3630  {
3631  MPEGStreamData *sd = nullptr;
3632  if (GetDTVSignalMonitor())
3635  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3636 
3637  // Delete StreamData if it is not in use by the recorder.
3638  MPEGStreamData *rec_sd = nullptr;
3639  if (GetDTVRecorder())
3640  rec_sd = GetDTVRecorder()->GetStreamData();
3641  if (sd && (sd != rec_sd))
3642  delete sd;
3643  }
3645  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3646 
3647  // At this point any waits are canceled.
3648 
3649  if (request.m_flags & kFlagNoRec)
3650  {
3652  {
3654  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3656  }
3657 
3659  (m_curRecording &&
3662  {
3663  m_stateChangeLock.unlock();
3664  TeardownRecorder(request.m_flags);
3665  m_stateChangeLock.lock();
3666  }
3667  // At this point the recorders are shut down
3668 
3669  CloseChannel();
3670  // At this point the channel is shut down
3671  }
3672 
3673  if (m_buffer && (request.m_flags & kFlagKillRingBuffer))
3674  {
3675  LOG(VB_RECORD, LOG_INFO, LOC + "Tearing down RingBuffer");
3676  SetRingBuffer(nullptr);
3677  // At this point the ringbuffer is shut down
3678  }
3679 
3680  // Clear pending actions from last request
3681  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
3682 }
3683 
3702 {
3703  LOG(VB_GENERAL, LOG_INFO, LOC + QString("TuningFrequency(%1)")
3704  .arg(request.toString()));
3705 
3706  DTVChannel *dtvchan = GetDTVChannel();
3707  if (dtvchan)
3708  {
3709  MPEGStreamData *mpeg = nullptr;
3710 
3711  if (GetDTVRecorder())
3713 
3714  // Tune with SI table standard (dvb, atsc, mpeg) from database, see issue #452
3716 
3717  const QString tuningmode = (HasFlags(kFlagEITScannerRunning)) ?
3718  dtvchan->GetSIStandard() :
3719  dtvchan->GetSuggestedTuningMode(
3721 
3722  dtvchan->SetTuningMode(tuningmode);
3723 
3724  if (request.m_minorChan && (tuningmode == "atsc"))
3725  {
3726  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3727  if (atsc)
3728  atsc->SetDesiredChannel(request.m_majorChan, request.m_minorChan);
3729  }
3730  else if (request.m_progNum >= 0)
3731  {
3732  if (mpeg)
3733  mpeg->SetDesiredProgram(request.m_progNum);
3734  }
3735  }
3736 
3737  if (request.IsOnSameMultiplex())
3738  {
3739  // Update the channel number for SwitchLiveTVRingBuffer (called from
3740  // TuningRestartRecorder). This ensures that the livetvchain will be
3741  // updated with the new channel number
3742  if (m_channel)
3743  {
3745  m_channel->GetChannelName(), request.m_channel );
3746  }
3747 
3748  QStringList slist;
3749  slist<<"message"<<QObject::tr("On known multiplex...");
3750  MythEvent me(QString("SIGNAL %1").arg(m_inputId), slist);
3751  gCoreContext->dispatch(me);
3752 
3753  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3754  return;
3755  }
3756 
3757  QString channum = request.m_channel;
3758 
3759  bool ok1 = true;
3760  if (m_channel)
3761  {
3762  m_channel->Open();
3763  if (!channum.isEmpty())
3764  ok1 = m_channel->SetChannelByString(channum);
3765  else
3766  ok1 = false;
3767  }
3768 
3769  if (!ok1)
3770  {
3771  if (!(request.m_flags & kFlagLiveTV) || !(request.m_flags & kFlagEITScan))
3772  {
3773  if (m_curRecording)
3775 
3776  LOG(VB_GENERAL, LOG_ERR, LOC +
3777  QString("Failed to set channel to %1. Reverting to kState_None")
3778  .arg(channum));
3781  else
3783  return;
3784  }
3785 
3786  LOG(VB_GENERAL, LOG_ERR, LOC +
3787  QString("Failed to set channel to %1.").arg(channum));
3788  }
3789 
3790  bool mpts_only = GetDTVChannel() &&
3791  GetDTVChannel()->GetFormat().compare("MPTS") == 0;
3792  if (mpts_only)
3793  {
3794  // Not using a signal monitor, so just set the status to recording
3796  if (m_curRecording)
3797  {
3799  }
3800  }
3801 
3802 
3803  bool livetv = (request.m_flags & kFlagLiveTV) != 0U;
3804  bool antadj = (request.m_flags & kFlagAntennaAdjust) != 0U;
3805  bool use_sm = !mpts_only && SignalMonitor::IsRequired(m_genOpt.m_inputType);
3806  bool use_dr = use_sm && (livetv || antadj);
3807  bool has_dummy = false;
3808 
3809  if (use_dr)
3810  {
3811  // We need there to be a ringbuffer for these modes
3812  bool ok2 = false;
3814  m_pseudoLiveTVRecording = nullptr;
3815 
3816  m_tvChain->SetInputType("DUMMY");
3817 
3818  if (!m_buffer)
3819  ok2 = CreateLiveTVRingBuffer(channum);
3820  else
3821  ok2 = SwitchLiveTVRingBuffer(channum, true, false);
3823 
3825 
3826  if (!ok2)
3827  {
3828  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 1");
3829  return;
3830  }
3831 
3832  has_dummy = true;
3833  }
3834 
3835  // Start signal monitoring for devices capable of monitoring
3836  if (use_sm)
3837  {
3838  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Signal Monitor");
3839  bool error = false;
3840  if (!SetupSignalMonitor(
3841  !antadj, (request.m_flags & kFlagEITScan) != 0U, livetv || antadj))
3842  {
3843  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to setup signal monitor");
3844  if (m_signalMonitor)
3845  {
3846  delete m_signalMonitor;
3847  m_signalMonitor = nullptr;
3848  }
3849 
3850  // pretend the signal monitor is running to prevent segfault
3851  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3852  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3853  error = true;
3854  }
3855 
3856  if (m_signalMonitor)
3857  {
3858  if (request.m_flags & kFlagEITScan)
3859  {
3861  SetVideoStreamsRequired(0);
3863  }
3864 
3865  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3866  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3867  if (!antadj)
3868  {
3869  QDateTime expire = MythDate::current();
3870 
3871  SetFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3872  if (m_curRecording)
3873  {
3875  // If startRecordingDeadline is passed, this
3876  // recording is marked as failed, so the scheduler
3877  // can try another showing.
3879  expire.addMSecs(m_genOpt.m_channelTimeout);
3881  expire.addMSecs(m_genOpt.m_channelTimeout * 2 / 3);
3882  // Keep trying to record this showing (even if it
3883  // has been marked as failed) until the scheduled
3884  // end time.
3886  m_curRecording->GetRecordingEndTime().addSecs(-10);
3887 
3888  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
3889  QString("Pre-fail start deadline: %1 "
3890  "Start recording deadline: %2 "
3891  "Good signal deadline: %3")
3892  .arg(m_preFailDeadline.toLocalTime()
3893  .toString("hh:mm:ss.zzz"),
3894  m_startRecordingDeadline.toLocalTime()
3895  .toString("hh:mm:ss.zzz"),
3896  m_signalMonitorDeadline.toLocalTime()
3897  .toString("hh:mm:ss.zzz")));
3898  }
3899  else
3900  {
3902  expire.addMSecs(m_genOpt.m_channelTimeout);
3903  }
3905 
3906  //System Event TUNING_TIMEOUT deadline
3908  m_signalEventCmdSent = false;
3909  }
3910  }
3911 
3912  if (has_dummy && m_buffer)
3913  {
3914  // Make sure recorder doesn't point to bogus ringbuffer before
3915  // it is potentially restarted without a new ringbuffer, if
3916  // the next channel won't tune and the user exits LiveTV.
3917  if (m_recorder)
3918  m_recorder->SetRingBuffer(nullptr);
3919 
3920  SetFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3921  LOG(VB_RECORD, LOG_INFO, "DummyDTVRecorder -- started");
3922  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3923  }
3924 
3925  // if we had problems starting the signal monitor,
3926  // we don't want to start the recorder...
3927  if (error)
3928  return;
3929  }
3930 
3931  // Request a recorder, if the command is a recording command
3932  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3933  if (request.m_flags & kFlagRec && !antadj)
3934  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3935 }
3936 
3945 {
3946  RecStatus::Type newRecStatus = RecStatus::Unknown;
3947  bool keep_trying = false;
3948  QDateTime current_time = MythDate::current();
3949 
3950  if ((m_signalMonitor->IsErrored() || current_time > m_signalEventCmdTimeout) &&
3952  {
3953  gCoreContext->SendSystemEvent(QString("TUNING_SIGNAL_TIMEOUT CARDID %1")
3954  .arg(m_inputId));
3955  m_signalEventCmdSent = true;
3956  }
3957 
3958  if (m_signalMonitor->IsAllGood())
3959  {
3960  LOG(VB_RECORD, LOG_INFO, LOC + "TuningSignalCheck: Good signal");
3961  if (m_curRecording && (current_time > m_startRecordingDeadline))
3962  {
3963  newRecStatus = RecStatus::Failing;
3964  m_curRecording->SaveVideoProperties(VID_DAMAGED, VID_DAMAGED);
3965 
3966  QString desc = tr("Good signal seen after %1 ms")
3967  .arg(m_genOpt.m_channelTimeout +
3968  m_startRecordingDeadline.msecsTo(current_time));
3969  QString title = m_curRecording->GetTitle();
3970  if (!m_curRecording->GetSubtitle().isEmpty())
3971  title += " - " + m_curRecording->GetSubtitle();
3972 
3974  "Recording", title,
3975  tr("See 'Tuning timeout' in mythtv-setup "
3976  "for this input."));
3977  gCoreContext->SendEvent(mn);
3978 
3979  LOG(VB_GENERAL, LOG_WARNING, LOC +
3980  QString("It took longer than %1 ms to get a signal lock. "
3981  "Keeping status of '%2'")
3983  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
3984  LOG(VB_GENERAL, LOG_WARNING, LOC +
3985  "See 'Tuning timeout' in mythtv-setup for this input");
3986  }
3987  else
3988  {
3989  newRecStatus = RecStatus::Recording;
3990  }
3991  }
3992  else if (m_signalMonitor->IsErrored() || current_time > m_signalMonitorDeadline)
3993  {
3994  LOG(VB_GENERAL, LOG_ERR, LOC + "TuningSignalCheck: SignalMonitor " +
3995  (m_signalMonitor->IsErrored() ? "failed" : "timed out"));
3996 
3997  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3998  newRecStatus = RecStatus::Failed;
3999 
4001  {
4003  }
4004  }
4005  else if (m_curRecording && !m_reachedPreFail && current_time > m_preFailDeadline)
4006  {
4007  LOG(VB_GENERAL, LOG_ERR, LOC +
4008  "TuningSignalCheck: Hit pre-fail timeout");
4009  SendMythSystemRecEvent("REC_PREFAIL", m_curRecording);
4010  m_reachedPreFail = true;
4011  return nullptr;
4012  }
4014  current_time > m_startRecordingDeadline)
4015  {
4016  newRecStatus = RecStatus::Failing;
4018  keep_trying = true;
4019 
4020  SendMythSystemRecEvent("REC_FAILING", m_curRecording);
4021 
4022  QString desc = tr("Taking more than %1 ms to get a lock.")
4023  .arg(m_genOpt.m_channelTimeout);
4024  QString title = m_curRecording->GetTitle();
4025  if (!m_curRecording->GetSubtitle().isEmpty())
4026  title += " - " + m_curRecording->GetSubtitle();
4027 
4029  "Recording", title,
4030  tr("See 'Tuning timeout' in mythtv-setup "
4031  "for this input."));
4032  mn.SetDuration(30s);
4033  gCoreContext->SendEvent(mn);
4034 
4035  LOG(VB_GENERAL, LOG_WARNING, LOC +
4036  QString("TuningSignalCheck: taking more than %1 ms to get a lock. "
4037  "marking this recording as '%2'.")
4039  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
4040  LOG(VB_GENERAL, LOG_WARNING, LOC +
4041  "See 'Tuning timeout' in mythtv-setup for this input");
4042  }
4043  else
4044  {
4045  if (m_signalMonitorCheckCnt) // Don't flood log file
4047  else
4048  {
4049  LOG(VB_RECORD, LOG_INFO, LOC +
4050  QString("TuningSignalCheck: Still waiting. Will timeout @ %1")
4051  .arg(m_signalMonitorDeadline.toLocalTime()
4052  .toString("hh:mm:ss.zzz")));
4054  }
4055  return nullptr;
4056  }
4057 
4058  SetRecordingStatus(newRecStatus, __LINE__);
4059 
4060  if (m_curRecording)
4061  {
4062  m_curRecording->SetRecordingStatus(newRecStatus);
4063  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
4064  .arg(m_curRecording->GetInputID())
4065  .arg(m_curRecording->GetChanID())
4067  .arg(newRecStatus)
4069  gCoreContext->dispatch(me);
4070  }
4071 
4072  if (keep_trying)
4073  return nullptr;
4074 
4075  // grab useful data from DTV signal monitor before we kill it...
4076  MPEGStreamData *streamData = nullptr;
4077  if (GetDTVSignalMonitor())
4078  streamData = GetDTVSignalMonitor()->GetStreamData();
4079 
4081  {
4082  // shut down signal monitoring
4084  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
4085  }
4086  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
4087 
4088  if (streamData)
4089  {
4090  auto *dsd = dynamic_cast<DVBStreamData*>(streamData);
4091  if (dsd)
4093  if (m_scanner)
4094  {
4095  if (get_use_eit(GetInputId()))
4096  {
4098  }
4099  else
4100  {
4101  LOG(VB_EIT, LOG_INFO, LOC +
4102  QString("EIT scanning disabled for video source %1")
4103  .arg(GetSourceID())); }
4104  }
4105  }
4106 
4107  return streamData;
4108 }
4109 
4111  bool on_host, bool transcode_bfr_comm, bool on_line_comm)
4112 {
4113  if (!rec)
4114  return 0; // no jobs for Live TV recordings..
4115 
4116  int jobs = 0; // start with no jobs
4117 
4118  // grab standard jobs flags from program info
4120 
4121  // disable commercial flagging on PBS, BBC, etc.
4122  if (rec->IsCommercialFree())
4124 
4125  // disable transcoding if the profile does not allow auto transcoding
4126  const StandardSetting *autoTrans = profile.byName("autotranscode");
4127  if ((!autoTrans) || (autoTrans->getValue().toInt() == 0))
4129 
4130  bool ml = JobQueue::JobIsInMask(JOB_METADATA, jobs);
4131  if (ml)
4132  {
4133  // When allowed, metadata lookup should occur at the
4134  // start of a recording to make the additional info
4135  // available immediately (and for use in future jobs).
4136  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4138  rec->GetChanID(),
4139  rec->GetRecordingStartTime(), "", "",
4140  host, JOB_LIVE_REC);
4141 
4142  // don't do regular metadata lookup, we won't need it.
4144  }
4145 
4146  // is commercial flagging enabled, and is on-line comm flagging enabled?
4147  bool rt = JobQueue::JobIsInMask(JOB_COMMFLAG, jobs) && on_line_comm;
4148  // also, we either need transcoding to be disabled or
4149  // we need to be allowed to commercial flag before transcoding?
4150  rt &= JobQueue::JobIsNotInMask(JOB_TRANSCODE, jobs) ||
4151  !transcode_bfr_comm;
4152  if (rt)
4153  {
4154  // queue up real-time (i.e. on-line) commercial flagging.
4155  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4157  rec->GetChanID(),
4158  rec->GetRecordingStartTime(), "", "",
4159  host, JOB_LIVE_REC);
4160 
4161  // don't do regular comm flagging, we won't need it.
4163  }
4164 
4165  return jobs;
4166 }
4167 
4168 QString TVRec::LoadProfile(void *tvchain, RecordingInfo *rec,
4169  RecordingProfile &profile) const
4170 {
4171  // Determine the correct recording profile.
4172  // In LiveTV mode use "Live TV" profile, otherwise use the
4173  // recording's specified profile. If the desired profile can't
4174  // be found, fall back to the "Default" profile for input type.
4175  QString profileName = "Live TV";
4176  if (!tvchain && rec)
4177  profileName = rec->GetRecordingRule()->m_recProfile;
4178 
4179  QString profileRequested = profileName;
4180 
4181  if (profile.loadByType(profileName, m_genOpt.m_inputType,
4183  {
4184  LOG(VB_RECORD, LOG_INFO, LOC +
4185  QString("Using profile '%1' to record")
4186  .arg(profileName));
4187  }
4188  else
4189  {
4190  profileName = "Default";
4191  if (profile.loadByType(profileName, m_genOpt.m_inputType, m_genOpt.m_videoDev))
4192  {
4193  LOG(VB_RECORD, LOG_INFO, LOC +
4194  QString("Profile '%1' not found, using "
4195  "fallback profile '%2' to record")
4196  .arg(profileRequested, profileName));
4197  }
4198  else
4199  {
4200  LOG(VB_RECORD, LOG_ERR, LOC +
4201  QString("Profile '%1' not found, and unable "
4202  "to load fallback profile '%2'. Results "
4203  "may be unpredicable")
4204  .arg(profileRequested, profileName));
4205  }
4206  }
4207 
4208  return profileName;
4209 }
4210 
4215 {
4216  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Recorder");
4217 
4218  bool had_dummyrec = false;
4220  {
4222  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4224  had_dummyrec = true;
4225  }
4226 
4228 
4231 
4232  if (m_tvChain)
4233  {
4234  bool ok = false;
4235  if (!m_buffer)
4236  {
4238  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4239  }
4240  else
4242  true, !had_dummyrec && m_recorder);
4243  if (!ok)
4244  {
4245  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 2");
4246  goto err_ret;
4247  }
4248  rec = m_curRecording; // new'd in Create/SwitchLiveTVRingBuffer()
4249  }
4250 
4252  {
4253  bool write = m_genOpt.m_inputType != "IMPORT";
4254  LOG(VB_GENERAL, LOG_INFO, LOC + QString("rec->GetPathname(): '%1'")
4255  .arg(rec->GetPathname()));
4257  if (!m_buffer->IsOpen() && write)
4258  {
4259  LOG(VB_GENERAL, LOG_ERR, LOC +
4260  QString("RingBuffer '%1' not open...")
4261  .arg(rec->GetPathname()));
4262  SetRingBuffer(nullptr);
4263  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4264  goto err_ret;
4265  }
4266  }
4267 
4268  if (!m_buffer)
4269  {
4270  LOG(VB_GENERAL, LOG_ERR, LOC +
4271  QString("Failed to start recorder! ringBuffer is NULL\n"
4272  "\t\t\t\t Tuning request was %1\n")
4273  .arg(m_lastTuningRequest.toString()));
4274 
4275  if (HasFlags(kFlagLiveTV))
4276  {
4277  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4278  MythEvent me(message);
4279  gCoreContext->dispatch(me);
4280  }
4281  goto err_ret;
4282  }
4283 
4284  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4285  m_channel->Close(); // Needed because of NVR::MJPEGInit()
4286 
4287  LOG(VB_GENERAL, LOG_INFO, LOC + "TuningNewRecorder - CreateRecorder()");
4289 
4290  if (m_recorder)
4291  {
4294  if (m_recorder->IsErrored())
4295  {
4296  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialize recorder!");
4297  delete m_recorder;
4298  m_recorder = nullptr;
4299  }
4300  }
4301 
4302  if (!m_recorder)
4303  {
4304  LOG(VB_GENERAL, LOG_ERR, LOC +
4305  QString("Failed to start recorder!\n"
4306  "\t\t\t\t Tuning request was %1\n")
4307  .arg(m_lastTuningRequest.toString()));
4308 
4309  if (HasFlags(kFlagLiveTV))
4310  {
4311  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4312  MythEvent me(message);
4313  gCoreContext->dispatch(me);
4314  }
4316  if (m_tvChain)
4317  rec = nullptr;
4318  goto err_ret;
4319  }
4320 
4321  if (rec)
4322  m_recorder->SetRecording(rec);
4323 
4324  if (GetDTVRecorder() && streamData)
4325  {
4326  const StandardSetting *setting = profile.byName("recordingtype");
4327  if (setting)
4328  streamData->SetRecordingType(setting->getValue());
4329  GetDTVRecorder()->SetStreamData(streamData);
4330  }
4331 
4332  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4333  m_channel->Open(); // Needed because of NVR::MJPEGInit()
4334 
4335  // Setup for framebuffer capture devices..
4336  if (m_channel)
4337  {
4340  }
4341 
4342  if (GetV4LChannel())
4343  {
4345  CloseChannel();
4346  }
4347 
4348  m_recorderThread = new MThread("RecThread", m_recorder);
4350 
4351  // Wait for recorder to start.
4352  m_stateChangeLock.unlock();
4353  while (!m_recorder->IsRecording() && !m_recorder->IsErrored())
4354  std::this_thread::sleep_for(5us);
4355  m_stateChangeLock.lock();
4356 
4357  if (GetV4LChannel())
4359 
4360  SetFlags(kFlagRecorderRunning | kFlagRingBufferReady, __FILE__, __LINE__);
4361 
4362  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4363 
4364  //workaround for failed import recordings, no signal monitor means we never
4365  //go to recording state and the status here seems to override the status
4366  //set in the importrecorder and backend via setrecordingstatus
4367  if (m_genOpt.m_inputType == "IMPORT")
4368  {
4370  if (m_curRecording)
4372  }
4373  return;
4374 
4375  err_ret:
4376  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
4378 
4379  if (rec)
4380  {
4381  // Make sure the scheduler knows...
4383  LOG(VB_RECORD, LOG_INFO, LOC +
4384  QString("TuningNewRecorder -- UPDATE_RECORDING_STATUS: %1")
4386  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
4387  .arg(rec->GetInputID())
4388  .arg(rec->GetChanID())
4390  .arg(RecStatus::Failed)
4392  gCoreContext->dispatch(me);
4393  }
4394 
4395  if (m_tvChain)
4396  delete rec;
4397 }
4398 
4403 {
4404  LOG(VB_RECORD, LOG_INFO, LOC + "Restarting Recorder");
4405 
4406  bool had_dummyrec = false;
4407 
4408  if (m_curRecording)
4409  {
4412  }
4413 
4415  {
4416  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4417  had_dummyrec = true;
4418  }
4419 
4420  SwitchLiveTVRingBuffer(m_channel->GetChannelName(), true, !had_dummyrec);
4421 
4422  if (had_dummyrec)
4423  {
4425  ProgramInfo *progInfo = m_tvChain->GetProgramAt(-1);
4426  RecordingInfo recinfo(*progInfo);
4427  delete progInfo;
4428  recinfo.SetInputID(m_inputId);
4429  m_recorder->SetRecording(&recinfo);
4430  }
4431  m_recorder->Reset();
4432 
4433  // Set file descriptor of channel from recorder for V4L
4434  if (GetV4LChannel())
4436 
4437  // Some recorders unpause on Reset, others do not...
4438  m_recorder->Unpause();
4439 
4441  {
4443  QString msg1 = QString("Recording: %1 %2 %3 %4")
4444  .arg(rcinfo1->GetTitle(), QString::number(rcinfo1->GetChanID()),
4447  ProgramInfo *rcinfo2 = m_tvChain->GetProgramAt(-1);
4448  QString msg2 = QString("Recording: %1 %2 %3 %4")
4449  .arg(rcinfo2->GetTitle(), QString::number(rcinfo2->GetChanID()),
4452  delete rcinfo2;
4453  LOG(VB_RECORD, LOG_INFO, LOC + "Pseudo LiveTV recording starting." +
4454  "\n\t\t\t" + msg1 + "\n\t\t\t" + msg2);
4455 
4458 
4460 
4461  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
4462  }
4463 
4464  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4465 }
4466 
4467 void TVRec::SetFlags(uint f, const QString & file, int line)
4468 {
4469  QMutexLocker lock(&m_stateChangeLock);
4470  m_stateFlags |= f;
4471  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetFlags(%1) -> %2 @ %3:%4")
4472  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4473  WakeEventLoop();
4474 }
4475 
4476 void TVRec::ClearFlags(uint f, const QString & file, int line)
4477 {
4478  QMutexLocker lock(&m_stateChangeLock);
4479  m_stateFlags &= ~f;
4480  LOG(VB_RECORD, LOG_INFO, LOC + QString("ClearFlags(%1) -> %2 @ %3:%4")
4481  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4482  WakeEventLoop();
4483 }
4484 
4486 {
4487  QString msg("");
4488 
4489  // General flags
4490  if (kFlagFrontendReady & f)
4491  msg += "FrontendReady,";
4492  if (kFlagRunMainLoop & f)
4493  msg += "RunMainLoop,";
4494  if (kFlagExitPlayer & f)
4495  msg += "ExitPlayer,";
4496  if (kFlagFinishRecording & f)
4497  msg += "FinishRecording,";
4498  if (kFlagErrored & f)
4499  msg += "Errored,";
4500  if (kFlagCancelNextRecording & f)
4501  msg += "CancelNextRecording,";
4502 
4503  // Tuning flags
4504  if ((kFlagRec & f) == kFlagRec)
4505  msg += "REC,";
4506  else
4507  {
4508  if (kFlagLiveTV & f)
4509  msg += "LiveTV,";
4510  if (kFlagRecording & f)
4511  msg += "Recording,";
4512  }
4513  if ((kFlagNoRec & f) == kFlagNoRec)
4514  msg += "NOREC,";
4515  else
4516  {
4517  if (kFlagEITScan & f)
4518  msg += "EITScan,";
4519  if (kFlagCloseRec & f)
4520  msg += "CloseRec,";
4521  if (kFlagKillRec & f)
4522  msg += "KillRec,";
4523  if (kFlagAntennaAdjust & f)
4524  msg += "AntennaAdjust,";
4525  }
4527  msg += "PENDINGACTIONS,";
4528  else
4529  {
4530  if (kFlagWaitingForRecPause & f)
4531  msg += "WaitingForRecPause,";
4532  if (kFlagWaitingForSignal & f)
4533  msg += "WaitingForSignal,";
4534  if (kFlagNeedToStartRecorder & f)
4535  msg += "NeedToStartRecorder,";
4536  if (kFlagKillRingBuffer & f)
4537  msg += "KillRingBuffer,";
4538  }
4539  if ((kFlagAnyRunning & f) == kFlagAnyRunning)
4540  msg += "ANYRUNNING,";
4541  else
4542  {
4543  if (kFlagSignalMonitorRunning & f)
4544  msg += "SignalMonitorRunning,";
4545  if (kFlagEITScannerRunning & f)
4546  msg += "EITScannerRunning,";
4548  msg += "ANYRECRUNNING,";
4549  else
4550  {
4551  if (kFlagDummyRecorderRunning & f)
4552  msg += "DummyRecorderRunning,";
4553  if (kFlagRecorderRunning & f)
4554  msg += "RecorderRunning,";
4555  }
4556  }
4557  if (kFlagRingBufferReady & f)
4558  msg += "RingBufferReady,";
4559 
4560  if (msg.isEmpty())
4561  msg = QString("0x%1").arg(f,0,16);
4562 
4563  return msg;
4564 }
4565 
4567 {
4568  QMutexLocker lock(&m_nextLiveTVDirLock);
4569 
4570  bool found = !m_nextLiveTVDir.isEmpty();
4571  if (!found && m_triggerLiveTVDir.wait(&m_nextLiveTVDirLock, 500))
4572  {
4573  found = !m_nextLiveTVDir.isEmpty();
4574  }
4575 
4576  return found;
4577 }
4578 
4579 void TVRec::SetNextLiveTVDir(QString dir)
4580 {
4581  QMutexLocker lock(&m_nextLiveTVDirLock);
4582 
4583  m_nextLiveTVDir = std::move(dir);
4584  m_triggerLiveTVDir.wakeAll();
4585 }
4586 
4589  const QString & channum)
4590 {
4591  LOG(VB_RECORD, LOG_INFO, LOC + "GetProgramRingBufferForLiveTV()");
4592  if (!m_channel || !m_tvChain || !pginfo || !Buffer)
4593  return false;
4594 
4595  m_nextLiveTVDirLock.lock();
4596  m_nextLiveTVDir.clear();
4597  m_nextLiveTVDirLock.unlock();
4598 
4599  // Dispatch this early, the response can take a while.
4600  MythEvent me(QString("QUERY_NEXT_LIVETV_DIR %1").arg(m_inputId));
4601  gCoreContext->dispatch(me);
4602 
4603  uint sourceid = m_channel->GetSourceID();
4604  int chanid = ChannelUtil::GetChanID(sourceid, channum);
4605 
4606  if (chanid < 0)
4607  {
4608  // Test setups might have zero channels
4609  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
4610  chanid = 9999;
4611  else
4612  {
4613  LOG(VB_GENERAL, LOG_ERR, LOC +
4614  QString("Channel: \'%1\' was not found in the database.\n"
4615  "\t\tMost likely, the 'starting channel' for this "
4616  "Input Connection is invalid.\n"
4617  "\t\tCould not start livetv.").arg(channum));
4618  return false;
4619  }
4620  }
4621 
4622  auto hoursMax =
4623  gCoreContext->GetDurSetting<std::chrono::hours>("MaxHoursPerLiveTVRecording", 8h);
4624  if (hoursMax <= 0h)
4625  hoursMax = 8h;
4626 
4627  RecordingInfo *prog = nullptr;
4630  else
4631  {
4632  prog = new RecordingInfo(
4633  chanid, MythDate::current(true), true, hoursMax);
4634  }
4635 
4636  prog->SetInputID(m_inputId);
4637 
4638  if (prog->GetRecordingStartTime() == prog->GetRecordingEndTime())
4639  {
4640  LOG(VB_GENERAL, LOG_ERR, LOC + "GetProgramRingBufferForLiveTV()"
4641  "\n\t\t\tProgramInfo is invalid."
4642  "\n" + prog->toString());
4643  prog->SetScheduledEndTime(prog->GetRecordingStartTime().addSecs(3600));
4645 
4646  prog->SetChanID(chanid);
4647  }
4648 
4651 
4652  prog->SetStorageGroup("LiveTV");
4653 
4654  if (WaitForNextLiveTVDir())
4655  {
4656  QMutexLocker lock(&m_nextLiveTVDirLock);
4658  }
4659  else
4660  {
4661  StorageGroup sgroup("LiveTV", gCoreContext->GetHostName());
4662  prog->SetPathname(sgroup.FindNextDirMostFree());
4663  }
4664 
4666  prog->SetRecordingGroup("LiveTV");
4667 
4668  StartedRecording(prog);
4669 
4670  *Buffer = MythMediaBuffer::Create(prog->GetPathname(), true);
4671  if (!(*Buffer) || !(*Buffer)->IsOpen())
4672  {
4673  LOG(VB_GENERAL, LOG_ERR, LOC + QString("RingBuffer '%1' not open...")
4674  .arg(prog->GetPathname()));
4675 
4676  delete *Buffer;
4677  delete prog;
4678 
4679  return false;
4680  }
4681 
4682  *pginfo = prog;
4683  return true;
4684 }
4685 
4686 bool TVRec::CreateLiveTVRingBuffer(const QString & channum)
4687 {
4688  LOG(VB_RECORD, LOG_INFO, LOC + QString("CreateLiveTVRingBuffer(%1)")
4689  .arg(channum));
4690 
4691  RecordingInfo *pginfo = nullptr;
4692  MythMediaBuffer *buffer = nullptr;
4693 
4694  if (!m_channel ||
4695  !m_channel->CheckChannel(channum))
4696  {
4698  return false;
4699  }
4700 
4701  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4702  {
4703  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4705  LOG(VB_GENERAL, LOG_ERR, LOC +
4706  QString("CreateLiveTVRingBuffer(%1) failed").arg(channum));
4707  return false;
4708  }
4709 
4710  SetRingBuffer(buffer);
4711 
4715 
4716  bool discont = (m_tvChain->TotalSize() > 0);
4718  m_channel->GetInputName(), discont);
4719 
4720  if (m_curRecording)
4721  {
4723  delete m_curRecording;
4724  }
4725 
4726  m_curRecording = pginfo;
4728 
4729  return true;
4730 }
4731 
4732 bool TVRec::SwitchLiveTVRingBuffer(const QString & channum,
4733  bool discont, bool set_rec)
4734 {
4735  QString msg;
4736  if (m_curRecording)
4737  {
4738  msg = QString(" curRec(%1) curRec.size(%2)")
4739  .arg(m_curRecording->MakeUniqueKey())
4740  .arg(m_curRecording->GetFilesize());
4741  }
4742  LOG(VB_RECORD, LOG_INFO, LOC +
4743  QString("SwitchLiveTVRingBuffer(discont %1, set_next_rec %2)")
4744  .arg(discont).arg(set_rec) + msg);
4745 
4746  RecordingInfo *pginfo = nullptr;
4747  MythMediaBuffer *buffer = nullptr;
4748 
4749  if (!m_channel ||
4750  !m_channel->CheckChannel(channum))
4751  {
4753  return false;
4754  }
4755 
4756  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4757  {
4759  return false;
4760  }
4761 
4762  QString oldinputtype = m_tvChain->GetInputType(-1);
4763 
4764  pginfo->MarkAsInUse(true, kRecorderInUseID);
4769  m_channel->GetInputName(), discont);
4770 
4771  if (set_rec && m_recorder)
4772  {
4773  m_recorder->SetNextRecording(pginfo, buffer);
4774  if (discont)
4776  delete pginfo;
4777  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4778  }
4779  else if (!set_rec)
4780  {
4781  // dummy recordings are finished before this
4782  // is called and other recordings must be finished..
4783  if (m_curRecording && oldinputtype != "DUMMY")
4784  {
4787  delete m_curRecording;
4788  }
4789  m_curRecording = pginfo;
4790  SetRingBuffer(buffer);
4791  }
4792  else
4793  {
4794  delete buffer;
4795  }
4796 
4797  return true;
4798 }
4799 
4801 {
4802  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer()");
4803 
4804  if (m_switchingBuffer)
4805  {
4806  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4807  "already switching.");
4808  return nullptr;
4809  }
4810 
4811  if (!m_recorder)
4812  {
4813  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4814  "invalid recorder.");
4815  return nullptr;
4816  }
4817 
4818  if (!m_curRecording)
4819  {
4820  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4821  "invalid recording.");
4822  return nullptr;
4823  }
4824 
4825  if (rcinfo.GetChanID() != m_curRecording->GetChanID())
4826  {
4827  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4828  "Not the same channel.");
4829  return nullptr;
4830  }
4831 
4832  auto *ri = new RecordingInfo(rcinfo);
4834 
4835  QString pn = LoadProfile(nullptr, ri, profile);
4836 
4837  if (pn != m_recProfileName)
4838  {
4839  LOG(VB_RECORD, LOG_ERR, LOC +
4840  QString("SwitchRecordingRingBuffer() -> "
4841  "cannot switch profile '%1' to '%2'")
4842  .arg(m_recProfileName, pn));
4843  return nullptr;
4844  }
4845 
4847 
4848  ri->MarkAsInUse(true, kRecorderInUseID);
4849  StartedRecording(ri);
4850 
4851  bool write = m_genOpt.m_inputType != "IMPORT";
4852  MythMediaBuffer *buffer = MythMediaBuffer::Create(ri->GetPathname(), write);
4853  if (!buffer || !buffer->IsOpen())
4854  {
4855  delete buffer;
4856  ri->SetRecordingStatus(RecStatus::Failed);
4857  FinishedRecording(ri, nullptr);
4858  ri->MarkAsInUse(false, kRecorderInUseID);
4859  delete ri;
4860  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer() -> "
4861  "Failed to create new RB.");
4862  return nullptr;
4863  }
4864 
4865  m_recorder->SetNextRecording(ri, buffer);
4866  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4868  m_switchingBuffer = true;
4869  ri->SetRecordingStatus(RecStatus::Recording);
4870  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer -> done");
4871  return ri;
4872 }
4873 
4875 {
4876  QMap<uint,TVRec*>::const_iterator it = s_inputs.constFind(inputid);
4877  if (it == s_inputs.constEnd())
4878  return nullptr;
4879  return *it;
4880 }
4881 
4882 void TVRec::EnableActiveScan(bool enable)
4883 {
4884  LOG(VB_RECORD, LOG_INFO, LOC + QString("enable:%1").arg(enable));
4885 
4886  if (m_scanner != nullptr)
4887  {
4888  if (enable)
4889  {
4891  && m_eitScanStartTime > MythDate::current().addYears(9))
4892  {
4894  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
4895  }
4896  }
4897  else
4898  {
4899  m_eitScanStartTime = MythDate::current().addYears(10);
4901  {
4903  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
4904  }
4905  }
4906  }
4907 }
4908 
4909 QString TuningRequest::toString(void) const
4910 {
4911  return QString("Program(%1) channel(%2) input(%3) flags(%4)")
4912  .arg(m_program == nullptr ? "NULL" : m_program->toString(),
4913  m_channel.isEmpty() ? "<empty>" : m_channel,
4914  m_input.isEmpty() ? "<empty>" : m_input,
4916 }
4917 
4918 #ifdef USING_DVB
4919 #include "recorders/dvbchannel.h"
4921 {
4922  // Some DVB devices munge the PMT and/or PAT so the CRC check fails.
4923  // We need to tell the stream data class to not check the CRC on
4924  // these devices. This can cause segfaults.
4925  auto * dvb = dynamic_cast<DVBChannel*>(c);
4926  if (dvb != nullptr)
4927  s->SetIgnoreCRC(dvb->HasCRCBug());
4928 }
4929 #else
4931 #endif // USING_DVB
4932 
4933 /* vim: set expandtab tabstop=4 shiftwidth=4: */
GeneralDBOptions
Definition: tv_rec.h:65
TVRec::CreateLiveTVRingBuffer
bool CreateLiveTVRingBuffer(const QString &channum)
Definition: tv_rec.cpp:4686
kLiveTVAutoExpire
@ kLiveTVAutoExpire
Definition: programtypes.h:197
DTVChannel::GetMajorChannel
uint GetMajorChannel(void) const
Returns major channel, 0 if unknown.
Definition: dtvchannel.h:93
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:215
BROWSE_LEFT
@ BROWSE_LEFT
Fetch information on current channel in the past.
Definition: tv.h:43
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
RecStatus::Type
Type
Definition: recordingstatus.h:15
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
ChannelBase::Close
virtual void Close(void)=0
Closes the channel changing hardware to use.
TVRec::SetFlags
void SetFlags(uint f, const QString &file, int line)
Definition: tv_rec.cpp:4467
TVRec::GetKeyframeDurations
bool GetKeyframeDurations(int64_t start, int64_t end, frm_pos_map_t &map) const
Definition: tv_rec.cpp:2667
MythTimer::elapsed
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
Definition: mythtimer.cpp:91
DTVSignalMonitor::AddFlags
void AddFlags(uint64_t _flags) override
Definition: dtvsignalmonitor.cpp:140
dtvchannel.h
TVRec::IsReallyRecording
bool IsReallyRecording(void)
Returns true if frontend can consider the recorder started.
Definition: tv_rec.cpp:2514
mpeg
Definition: mythchrono.h:51
ProgramInfo::MakeUniqueKey
QString MakeUniqueKey(void) const
Creates a unique string that can be used to identify an existing recording.
Definition: programinfo.h:339
TVRec::m_runJobOnHostOnly
bool m_runJobOnHostOnly
Definition: tv_rec.h:360
PendingInfo::m_possibleConflicts
std::vector< uint > m_possibleConflicts
Definition: tv_rec.h:138
ChannelBase::Init
virtual bool Init(QString &startchannel, bool setchan)
Definition: channelbase.cpp:66
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:214
TVRec::kFlagNoRec
static const uint kFlagNoRec
Definition: tv_rec.h:464
TVRec::RecordPending
void RecordPending(const ProgramInfo *rcinfo, std::chrono::seconds secsleft, bool hasLater)
Tells TVRec "rcinfo" is the next pending recording.
Definition: tv_rec.cpp:310
TVRec::kFlagErrored
static const uint kFlagErrored
Definition: tv_rec.h:444
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
TVRec::m_startRecordingDeadline
QDateTime m_startRecordingDeadline
Definition: tv_rec.h:344
TVRec::m_channel
ChannelBase * m_channel
Definition: tv_rec.h:337
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:102
MARK_ASPECT_16_9
@ MARK_ASPECT_16_9
Definition: programtypes.h:67
JobQueue::RemoveJobsFromMask
static void RemoveJobsFromMask(int jobs, int &mask)
Definition: jobqueue.h:202
TVRec::kFlagEITScannerRunning
static const uint kFlagEITScannerRunning
Definition: tv_rec.h:475
RecordingInfo::FinishedRecording
void FinishedRecording(bool allowReRecord)
If not a premature stop, adds program to history of recorded programs.
Definition: recordinginfo.cpp:1269
InputInfo::m_chanId
uint m_chanId
chanid restriction if applicable
Definition: inputinfo.h:51
BROWSE_UP
@ BROWSE_UP
Fetch information on previous channel.
Definition: tv.h:41
JobQueue::JobIsInMask
static bool JobIsInMask(int job, int mask)
Definition: jobqueue.h:198
TVRec::SetPseudoLiveTVRecording
void SetPseudoLiveTVRecording(RecordingInfo *pi)
Sets the pseudo LiveTV RecordingInfo.
Definition: tv_rec.cpp:363
MPEGStreamData::SetVideoStreamsRequired
void SetVideoStreamsRequired(uint num)
Definition: mpegstreamdata.h:249
MARK_ASPECT_2_21_1
@ MARK_ASPECT_2_21_1
Definition: programtypes.h:68
DTVSignalMonitor::SetDVBService
void SetDVBService(uint network_id, uint transport_id, int service_id)
Definition: dtvsignalmonitor.cpp:229
TuningRequest
Definition: tv_rec.h:101
EITScanner::StopEITEventProcessing
void StopEITEventProcessing(void)
Stops inserting Event Information Tables into DB.
Definition: eitscanner.cpp:221
TVRec::WaitForEventThreadSleep
bool WaitForEventThreadSleep(bool wake=true, std::chrono::milliseconds time=std::chrono::milliseconds::max())
Definition: tv_rec.cpp:1646
error
static void error(const char *str,...)
Definition: vbi.cpp:36
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
ProgramInfo::SetRecordingStatus
void SetRecordingStatus(RecStatus::Type status)
Definition: programinfo.h:580
CHANNEL_DIRECTION_DOWN
@ CHANNEL_DIRECTION_DOWN
Definition: tv.h:31
dtvrecorder.h
ProgramInfo::QueryMplexID
uint QueryMplexID(void) const
Queries multiplex any recording would be made on, zero if unknown.
Definition: programinfo.cpp:2644
TVRec::m_recProfileName
QString m_recProfileName
Definition: tv_rec.h:383
ChannelChangeDirection
ChannelChangeDirection
ChannelChangeDirection is an enumeration of possible channel changing directions.
Definition: tv.h:28
TVRec::m_audioSampleRateDB
int m_audioSampleRateDB
Definition: tv_rec.h:364
mythdb.h
RecorderBase::CreateRecorder
static RecorderBase * CreateRecorder(TVRec *tvrec, ChannelBase *channel, RecordingProfile &profile, const GeneralDBOptions &genOpt)
Definition: recorderbase.cpp:859
TVRec::ShouldSwitchToAnotherInput
bool ShouldSwitchToAnotherInput(const QString &chanid) const
Checks if named channel exists on current tuner, or another tuner.
Definition: tv_rec.cpp:2223
SourceUtil::GetSourceName
static QString GetSourceName(uint sourceid)
Definition: sourceutil.cpp:47
TVRec::kFlagRecording
static const uint kFlagRecording
final result desired is a timed recording
Definition: tv_rec.h:451
mythrandom.h
RecordingRule::Save
bool Save(bool sendSig=true)
Definition: recordingrule.cpp:388
SignalMonitor::IsAllGood
virtual bool IsAllGood(void) const
Definition: signalmonitor.h:81
CHANNEL_DIRECTION_UP
@ CHANNEL_DIRECTION_UP
Definition: tv.h:30
JobQueue::QueueJob
static bool QueueJob(int jobType, uint chanid, const QDateTime &recstartts, const QString &args="", const QString &comment="", QString host="", int flags=0, int status=JOB_QUEUED, QDateTime schedruntime=QDateTime())
Definition: jobqueue.cpp:505
CardUtil::GetInputName
static QString GetInputName(uint inputid)
Definition: cardutil.cpp:1771
MythTimer
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
TVRec::m_triggerEventSleepLock
QMutex m_triggerEventSleepLock
Definition: tv_rec.h:401
ChannelBase::Open
virtual bool Open(void)=0
Opens the channel changing hardware for use.
TVRec::m_tuningRequests
TuningQueue m_tuningRequests
Definition: tv_rec.h:394
TVRec::m_eitScanPeriod
std::chrono::seconds m_eitScanPeriod
Definition: tv_rec.h:363
RemoteGetState
uint RemoteGetState(uint inputid)
Definition: tvremoteutil.cpp:31
ChannelBase::GetInputName
virtual QString GetInputName(void) const
Definition: channelbase.h:69
kRecorderInUseID
const QString kRecorderInUseID
Definition: programtypes.cpp:20
MythNotification::SetDuration
void SetDuration(std::chrono::seconds Duration)
Contains a duration during which the notification will be displayed for. The duration is informative ...
Definition: mythnotification.cpp:144
RecordingInfo::ApplyRecordRecID
void ApplyRecordRecID(void)
Sets recordid to match RecordingRule recordid.
Definition: recordinginfo.cpp:538
PictureAdjustType
PictureAdjustType
Definition: tv.h:120
MPEGStreamData::SetCaching
void SetCaching(bool cacheTables)
Definition: mpegstreamdata.h:91
ProgramInfo::SetRecordingID
virtual void SetRecordingID(uint _recordedid)
Definition: programinfo.h:578
TVRec::Init
bool Init(void)
Performs instance initialization, returns true on success.
Definition: tv_rec.cpp:157
SignalMonitor::IsSupported
static bool IsSupported(const QString &cardtype)
Definition: signalmonitor.h:315
MythMediaBuffer::StopReads
void StopReads(void)
Definition: mythmediabuffer.cpp:663
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
eitscanner.h
RecStatus::Tuning
@ Tuning
Definition: recordingstatus.h:21
TVRec::IsBusy
bool IsBusy(InputInfo *busy_input=nullptr, std::chrono::seconds time_buffer=5s) const
Returns true if the recorder is busy, or will be within the next time_buffer seconds.
Definition: tv_rec.cpp:2525
pid_cache_item_t
Definition: channelutil.h:24
EITScanner::StartEITEventProcessing
void StartEITEventProcessing(ChannelBase *channel, EITSource *eitSource)
Start inserting Event Information Tables from the multiplex we happen to be tuned to into the databas...
Definition: eitscanner.cpp:188
RecordingInfo
Holds information on a TV Program one might wish to record.
Definition: recordinginfo.h:35
TVRec::ToggleChannelFavorite
void ToggleChannelFavorite(const QString &changroupname)
Toggles whether the current channel should be on our favorites list.
Definition: tv_rec.cpp:2993
GeneralDBOptions::m_signalTimeout
uint m_signalTimeout
Definition: tv_rec.h:76
TVRec::m_eitTransportTimeout
std::chrono::seconds m_eitTransportTimeout
Definition: tv_rec.h:362
RecordingInfo::GetFilesize
uint64_t GetFilesize(void) const override
Definition: recordinginfo.cpp:1755
ChannelBase::IsOpen
virtual bool IsOpen(void) const =0
Reports whether channel is already open.
ProgramInfo::QueryAverageScanProgressive
bool QueryAverageScanProgressive(void) const
If present in recording this loads average video scan type of the main video stream from database's s...
Definition: programinfo.cpp:4592
RecorderBase::Unpause
virtual void Unpause(void)
Unpause tells recorder to unpause.
Definition: recorderbase.cpp:273
TVRec::kFlagRingBufferReady
static const uint kFlagRingBufferReady
Definition: tv_rec.h:483
ProgramInfo::GetRecordingID
uint GetRecordingID(void) const
Definition: programinfo.h:446
MythMediaBuffer::GetWritePosition
long long GetWritePosition(void) const
Returns how far into a ThreadedFileWriter file we have written.
Definition: mythmediabuffer.cpp:1787
TVRec::m_buffer
MythMediaBuffer * m_buffer
Definition: tv_rec.h:428
RecorderBase::IsErrored
virtual bool IsErrored(void)=0
Tells us whether an unrecoverable error has been encountered.
LiveTVChain::GetID
QString GetID(void) const
Definition: livetvchain.h:54
TVRec::m_triggerLiveTVDir
QWaitCondition m_triggerLiveTVDir
Definition: tv_rec.h:421
RecStatus::Cancelled
@ Cancelled
Definition: recordingstatus.h:25
TVRec::m_eventThread
MThread * m_eventThread
Event processing thread, runs TVRec::run().
Definition: tv_rec.h:353
TVRec::kFlagRecorderRunning
static const uint kFlagRecorderRunning
Definition: tv_rec.h:478
GeneralDBOptions::m_inputType
QString m_inputType
Definition: tv_rec.h:73
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
TVRec::kFlagRec
static const uint kFlagRec
Definition: tv_rec.h:454
JOB_COMMFLAG
@ JOB_COMMFLAG
Definition: jobqueue.h:79
ProgramInfo::kTitleSubtitle
@ kTitleSubtitle
Definition: programinfo.h:509
TVRec::m_recStatus
RecStatus::Type m_recStatus
Definition: tv_rec.h:405
ChannelUtil::GetATSCChannel
static bool GetATSCChannel(uint sourceid, const QString &channum, uint &major, uint &minor)
Definition: channelutil.cpp:1876
TVRec::SetInput
QString SetInput(QString input)
Changes to the specified input.
Definition: tv_rec.cpp:3101
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
ChannelUtil::GetProgramNumber
static int GetProgramNumber(uint sourceid, const QString &channum)
Definition: channelutil.h:197
SignalMonitor::kDTVSigMon_WaitForMGT
static const uint64_t kDTVSigMon_WaitForMGT
Definition: signalmonitor.h:181
TVRec::GetSourceID
uint GetSourceID(void) const
Returns current source id.
Definition: tv_rec.cpp:3086
JobQueue::QueueRecordingJobs
static bool QueueRecordingJobs(const RecordingInfo &recinfo, int jobTypes=JOB_NONE)
Definition: jobqueue.cpp:483
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
TVRec::m_overRecordCategory
QString m_overRecordCategory
Definition: tv_rec.h:367
PendingInfo::m_hasLaterShowing
bool m_hasLaterShowing
Definition: tv_rec.h:134
ProgramInfo::GetCategory
QString GetCategory(void) const
Definition: programinfo.h:369
RecStatus::TunerBusy
@ TunerBusy
Definition: recordingstatus.h:23
DTVRecorder::SetStreamData
virtual void SetStreamData(MPEGStreamData *data)
Definition: dtvrecorder.cpp:218
TVRec::GetProgramRingBufferForLiveTV
bool GetProgramRingBufferForLiveTV(RecordingInfo **pginfo, MythMediaBuffer **Buffer, const QString &channum)
Definition: tv_rec.cpp:4587
JOB_NONE
@ JOB_NONE
Definition: jobqueue.h:75
PendingInfo::m_info
ProgramInfo * m_info
Definition: tv_rec.h:132
MythNotification
Definition: mythnotification.h:29
DTVChannel::GetMinorChannel
uint GetMinorChannel(void) const
Returns minor channel, 0 if unknown.
Definition: dtvchannel.h:97
RecStatus::Unknown
@ Unknown
Definition: recordingstatus.h:31
apply_broken_dvb_driver_crc_hack
static void apply_broken_dvb_driver_crc_hack(ChannelBase *, MPEGStreamData *)
Definition: tv_rec.cpp:4920
TuningRequest::toString
QString toString(void) const
Definition: tv_rec.cpp:4909
RecordingRule::m_endOffset
int m_endOffset
Definition: recordingrule.h:110
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:696
DTVSignalMonitor::GetStreamData
MPEGStreamData * GetStreamData()
Returns the MPEG stream data if it exists.
Definition: dtvsignalmonitor.h:59
LiveTVChain::TotalSize
int TotalSize(void) const
Definition: livetvchain.cpp:388
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:619
TVRec::EnableActiveScan
void EnableActiveScan(bool enable)
Definition: tv_rec.cpp:4882
osd.h
atscstreamdata.h
TVRec::m_curRecording
RecordingInfo * m_curRecording
Definition: tv_rec.h:408
ProgramInfo::SaveCommFlagged
void SaveCommFlagged(CommFlagStatus flag)
Set "commflagged" field in "recorded" table to "flag".
Definition: programinfo.cpp:3333
RecStatus::Recorded
@ Recorded
Definition: recordingstatus.h:28
TVRec::StopRecording
void StopRecording(bool killFile=false)
Changes from a recording state to kState_None.
Definition: tv_rec.cpp:746
RecorderBase::GetKeyframePositions
bool GetKeyframePositions(long long start, long long end, frm_pos_map_t &map) const
Definition: recorderbase.cpp:539
MythMediaBuffer
Definition: mythmediabuffer.h:50
DTVChannel::GetFormat
QString GetFormat(void)
Definition: dtvchannel.h:46
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
ProgramInfo::GetScheduledEndTime
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:397
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
FireWireDBOptions::m_speed
int m_speed
Definition: tv_rec.h:96
RecordingInfo::kLiveTVRecGroup
@ kLiveTVRecGroup
Definition: recordinginfo.h:192
TVRec::GetFramesWritten
long long GetFramesWritten(void)
Returns number of frames written to disk by recorder.
Definition: tv_rec.cpp:2608
TVRec::GetDevices
static bool GetDevices(uint inputid, uint &parentid, GeneralDBOptions &gen_opts, DVBDBOptions &dvb_opts, FireWireDBOptions &firewire_opts)
Definition: tv_rec.cpp:1761
channelbase.h
TableID::CVCT
@ CVCT
Definition: mpegtables.h:363
ProgramInfo::UpdateInUseMark
void UpdateInUseMark(bool force=false)
Definition: programinfo.cpp:4955
TVRec::GetInput
QString GetInput(void) const
Returns current input.
Definition: tv_rec.cpp:3076
ChannelUtil::GetMplexID
static uint GetMplexID(uint sourceid, const QString &channum)
Definition: channelutil.cpp:462
TVRec::kFlagDummyRecorderRunning
static const uint kFlagDummyRecorderRunning
Definition: tv_rec.h:477
ChannelBase::GetChannelName
virtual QString GetChannelName(void) const
Definition: channelbase.h:64
TVRec::m_setChannelLock
QMutex m_setChannelLock
Definition: tv_rec.h:386
RecordingQuality::IsDamaged
bool IsDamaged(void) const
Definition: recordingquality.cpp:108
mythsystemevent.h
build_compdb.file
file
Definition: build_compdb.py:55
RecordingInfo::UpdateRecordingEnd
void UpdateRecordingEnd(void)
Update information in the recorded table when the end-time of a recording is changed.
Definition: recordinginfo.cpp:1309
TVRec::GetDTVChannel
DTVChannel * GetDTVChannel(void)
Definition: tv_rec.cpp:1252
TVRec::kFlagPendingActions
static const uint kFlagPendingActions
Definition: tv_rec.h:471
TVRec::CheckChannelPrefix
bool CheckChannelPrefix(const QString &prefix, uint &complete_valid_channel_on_rec, bool &is_extra_char_useful, QString &needed_spacer) const
Checks a prefix against the channels in the DB.
Definition: tv_rec.cpp:2359
RecorderBase::Pause
virtual void Pause(bool clear=true)
Pause tells recorder to pause, it should not block.
Definition: recorderbase.cpp:263
MasterGuideTable::TableCount
uint TableCount() const
Definition: atsctables.h:120
ProgramInfo::GetRecordingEndTime
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:412
ChannelBase::GetPictureAttribute
virtual int GetPictureAttribute(PictureAttribute) const
Definition: channelbase.h:94
ProgramInfo::GetRecordingGroup
QString GetRecordingGroup(void) const
Definition: programinfo.h:419
TVRec::GetChainID
QString GetChainID(void)
Get the chainid of the livetv instance.
Definition: tv_rec.cpp:2741
TVRec::m_eitScanStopTime
QDateTime m_eitScanStopTime
Definition: tv_rec.h:397
remoteutil.h
hardwareprofile.distros.mythtv_data.data_mythtv.prefix
string prefix
Definition: data_mythtv.py:40
TVRec::m_overRecordSecCat
std::chrono::seconds m_overRecordSecCat
Definition: tv_rec.h:366
RecorderBase::GetKeyframeDurations
bool GetKeyframeDurations(long long start, long long end, frm_pos_map_t &map) const
Definition: recorderbase.cpp:561
ProgramInfo::QueryTuningInfo
bool QueryTuningInfo(QString &channum, QString &input) const
Returns the channel and input needed to record the program.
Definition: programinfo.cpp:5339
GetPidsToCache
static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
Definition: tv_rec.cpp:1848
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
TVRec::m_pauseNotify
bool m_pauseNotify
Definition: tv_rec.h:392
dvbchannel.h
TVRec::TuningOnSameMultiplex
bool TuningOnSameMultiplex(TuningRequest &request)
Definition: tv_rec.cpp:3488
TVRec::TeardownRecorder
void TeardownRecorder(uint request_flags)
Tears down the recorder.
Definition: tv_rec.cpp:1178
kState_Error
@ kState_Error
Error State, if we ever try to enter this state errored is set.
Definition: tv.h:54
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:404
TVRec::GetFilePosition
long long GetFilePosition(void)
Returns total number of bytes written by RingBuffer.
Definition: tv_rec.cpp:2623
ProgramInfo::GetPathname
QString GetPathname(void) const
Definition: programinfo.h:343
TVRec::kFlagCancelNextRecording
static const uint kFlagCancelNextRecording
Definition: tv_rec.h:445
RecordingQuality::toStringXML
QString toStringXML(void) const
Definition: recordingquality.cpp:114
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:627
TVRec::SwitchRecordingRingBuffer
RecordingInfo * SwitchRecordingRingBuffer(const RecordingInfo &rcinfo)
Definition: tv_rec.cpp:4800
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
TVRec::GetRecordEndTime
QDateTime GetRecordEndTime(const ProgramInfo *pi) const
Returns recording end time with proper post-roll.
Definition: tv_rec.cpp:373
RecStatus::toString
static QString toString(RecStatus::Type recstatus, uint id)
Converts "recstatus" into a short (unreadable) string.
Definition: recordingstatus.cpp:40
TVRec::m_recordEndTime
QDateTime m_recordEndTime
Definition: tv_rec.h:409
DTVChannel::GetTuningMode
QString GetTuningMode(void) const
Returns tuning mode last set by SetTuningMode().
Definition: dtvchannel.cpp:73
kState_ChangingState
@ kState_ChangingState
This is a placeholder state which we never actually enter, but is returned by GetState() when we are ...
Definition: tv.h:89
DTVChannel::GetOriginalNetworkID
uint GetOriginalNetworkID(void) const
Returns DVB original_network_id, 0 if unknown.
Definition: dtvchannel.h:101
LiveTVChain::GetProgramAt
ProgramInfo * GetProgramAt(int at) const
Returns program at the desired location.
Definition: livetvchain.cpp:321
kState_None
@ kState_None
None State, this is the initial state in both TV and TVRec, it indicates that we are ready to change ...
Definition: tv.h:58
EITScanner::StopActiveScan
void StopActiveScan(void)
Stop active EIT scan.
Definition: eitscanner.cpp:333
SignalMonitor::IsRequired
static bool IsRequired(const QString &cardtype)
Returns true iff the card type supports signal monitoring.
Definition: signalmonitor.h:310
TVRec::TeardownAll
void TeardownAll(void)
Definition: tv_rec.cpp:234
GeneralDBOptions::m_channelTimeout
uint m_channelTimeout
Definition: tv_rec.h:77
MPEGStreamData::SetIgnoreCRC
void SetIgnoreCRC(bool haveCRCbug)
Definition: mpegstreamdata.h:111
TVRec::m_inputId
uint m_inputId
Definition: tv_rec.h:370
GeneralDBOptions::m_vbiDev
QString m_vbiDev
Definition: tv_rec.h:71
TVRec::m_overRecordSecNrml
std::chrono::seconds m_overRecordSecNrml
Definition: tv_rec.h:365
TVRec::RecorderPaused
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2984
JOB_LIVE_REC
@ JOB_LIVE_REC
Definition: jobqueue.h:61
MythDate::secsInFuture
std::chrono::seconds secsInFuture(const QDateTime &future)
Definition: mythdate.cpp:208
TVRec::m_pendingRecordings
PendingMap m_pendingRecordings
Definition: tv_rec.h:415
TRANSITION
#define TRANSITION(ASTATE, BSTATE)
Definition: tv_rec.cpp:1031
TVRec::kFlagAnyRecRunning
static const uint kFlagAnyRecRunning
Definition: tv_rec.h:479
ChannelBase::InitPictureAttributes
virtual bool InitPictureAttributes(void)
Definition: channelbase.h:93
TVRec::GetInputId
uint GetInputId(void) const
Returns the inputid.
Definition: tv_rec.h:234
ProgramInfo::MarkAsInUse
void MarkAsInUse(bool inuse, const QString &usedFor="")
Tracks a recording's in use status, to prevent deletion and to allow the storage scheduler to perform...
Definition: programinfo.cpp:5146
DTVChannel::GetTransportID
uint GetTransportID(void) const
Returns DVB transport_stream_id, 0 if unknown.
Definition: dtvchannel.h:105
MPEGStreamData::ReturnCachedTable
virtual void ReturnCachedTable(const PSIPTable *psip) const
Definition: mpegstreamdata.cpp:1470
mythdate.h
TVRec::kFlagWaitingForSignal
static const uint kFlagWaitingForSignal
Definition: tv_rec.h:469
sourceutil.h
TVRec::kFlagDetect
static const uint kFlagDetect
Definition: tv_rec.h:484
ProgramInfo::SetPathname
void SetPathname(const QString &pn)
Definition: programinfo.cpp:2438
ProgramInfo::SaveVideoProperties
void SaveVideoProperties(uint mask, uint video_property_flags)
Definition: programinfo.cpp:4905
ProgramInfo::SetRecordingEndTime
void SetRecordingEndTime(const QDateTime &dt)
Definition: programinfo.h:526
TVRec::CreateChannel
bool CreateChannel(const QString &startchannel, bool enter_power_save_mode)
Definition: tv_rec.cpp:95
TVRec::m_autoRunJobs
QHash< QString, int > m_autoRunJobs
Definition: tv_rec.h:411
minor
#define minor(X)
Definition: compat.h:78
RecordingInfo::GetRecordingFile
RecordingFile * GetRecordingFile() const
Definition: recordinginfo.h:282
TVRec::PauseRecorder
void PauseRecorder(void)
Tells "recorder" to pause, used for channel and input changes.
Definition: tv_rec.cpp:2965
programinfo.h
TVRec::NotifySchedulerOfRecording
void NotifySchedulerOfRecording(RecordingInfo *rec)
Tell scheduler about the recording.
Definition: tv_rec.cpp:2790
ATSCStreamData::SetDesiredChannel
void SetDesiredChannel(int major, int minor)
Definition: atscstreamdata.cpp:57
ChannelUtil::GetChanID
static int GetChanID(int db_mplexid, int service_transport_id, int major_channel, int minor_channel, int program_number)
Definition: channelutil.cpp:1312
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:390
mythlogging.h
SignalMonitor::kDVBSigMon_WaitForPos
static const uint64_t kDVBSigMon_WaitForPos
Wait for rotor to complete turning the antenna.
Definition: signalmonitor.h:198
ProgramInfo::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:447
TVRec::SetRecordingStatus
void SetRecordingStatus(RecStatus::Type new_status, int line, bool have_lock=false)
Definition: tv_rec.cpp:716
ProgramInfo::QueryAverageAspectRatio
MarkTypes QueryAverageAspectRatio(void) const
Definition: programinfo.cpp:4542
is_dishnet_eit
static bool is_dishnet_eit(uint inputid)
Definition: tv_rec.cpp:1287
DVBStreamData::SetDishNetEIT
void SetDishNetEIT(bool use_dishnet_eit)
Definition: dvbstreamdata.h:165
LiveTVChain::SetHostPrefix
void SetHostPrefix(const QString &prefix)
Definition: livetvchain.cpp:45
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:760
RemoteStopRecording
bool RemoteStopRecording(uint inputid)
Definition: tvremoteutil.cpp:98
ChannelBase
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:31
RecorderBase::SetRingBuffer
void SetRingBuffer(MythMediaBuffer *Buffer)
Tells recorder to use an externally created ringbuffer.
Definition: recorderbase.cpp:75
hardwareprofile.scan.profile
profile
Definition: scan.py:97
MasterGuideTable::TablePID
uint TablePID(uint i) const
Definition: atsctables.h:132
CardUtil::IsEncoder
static bool IsEncoder(const QString &rawtype)
Definition: cardutil.h:135
RemoteIsBusy
bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
Definition: tvremoteutil.cpp:362
TVRec::kFlagKillRec
static const uint kFlagKillRec
close recorder, discard recording
Definition: tv_rec.h:462
ProgramInfo::SetScheduledEndTime
void SetScheduledEndTime(const QDateTime &dt)
Definition: programinfo.h:524
TuningRequest::m_progNum
int m_progNum
Definition: tv_rec.h:122
ProgramInfo::SetInputID
void SetInputID(uint id)
Definition: programinfo.h:540
DTVChannel::SaveCachedPids
void SaveCachedPids(const pid_cache_t &pid_cache) const
Saves MPEG PIDs to cache to database.
Definition: dtvchannel.cpp:107
MythCoreContext::GetBackendServerPort
int GetBackendServerPort(void)
Returns the locally defined backend control port.
Definition: mythcorecontext.cpp:1064
TVRec::m_recorder
RecorderBase * m_recorder
Definition: tv_rec.h:336
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1544
ChannelBase::StoreInputChannels
virtual void StoreInputChannels(void)
Saves current channel as the default channel for the current input.
Definition: channelbase.cpp:647
TVRec::GetMaxBitrate
long long GetMaxBitrate(void) const
Returns the maximum bits per second this recorder can produce.
Definition: tv_rec.cpp:2683
MythCoreContext::SendEvent
void SendEvent(const MythEvent &event)
Definition: mythcorecontext.cpp:1530
TVRec::kFlagRunMainLoop
static const uint kFlagRunMainLoop
Definition: tv_rec.h:441
ProgramInfo::SetRecordingRuleType
void SetRecordingRuleType(RecordingType type)
Definition: programinfo.h:581
TVRec::RemoveRecording
TVState RemoveRecording(TVState state) const
If "state" is kState_RecordingOnly or kState_WatchingLiveTV, returns a kState_None,...
Definition: tv_rec.cpp:793
TVRec::m_pseudoLiveTVRecording
RecordingInfo * m_pseudoLiveTVRecording
Definition: tv_rec.h:418
MPEGStreamData::SetRecordingType
void SetRecordingType(const QString &recording_type)
Definition: mpegstreamdata.cpp:100
hardwareprofile.i18n.t
t
Definition: i18n.py:36
TVRec::FlagToString
static QString FlagToString(uint f)
Definition: tv_rec.cpp:4485
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:361
MythNotification::kCheck
static const Type kCheck
Definition: mythnotification.h:37
compat.h
TVRec::HandleStateChange
void HandleStateChange(void)
Changes the internalState to the desiredNextState if possible.
Definition: tv_rec.cpp:1044
pid_cache_t
std::vector< pid_cache_item_t > pid_cache_t
Definition: channelutil.h:43
TVRec::kAutoRunNone
@ kAutoRunNone
Definition: tv_rec.h:325
LiveTVChain::SetInputType
void SetInputType(const QString &type)
Definition: livetvchain.cpp:50
ATSCStreamData
Encapsulates data about ATSC stream and emits events for most tables.
Definition: atscstreamdata.h:29
v4lchannel.h
TVRec::m_tvChain
LiveTVChain * m_tvChain
Definition: tv_rec.h:425
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:226
TVRec::CheckChannel
bool CheckChannel(const QString &name) const
Checks if named channel exists on current tuner.
Definition: tv_rec.cpp:2313
SignalMonitor::kDTVSigMon_WaitForPMT
static const uint64_t kDTVSigMon_WaitForPMT
Definition: signalmonitor.h:180
RecorderBase::Reset
virtual void Reset(void)=0
Reset the recorder to the startup state.
TVRec::kFlagSignalMonitorRunning
static const uint kFlagSignalMonitorRunning
Definition: tv_rec.h:474
ProgramInfo::SetRecordingGroup
void SetRecordingGroup(const QString &group)
Definition: programinfo.h:527
TVRec::SetupSignalMonitor
bool SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
This creates a SignalMonitor instance and begins signal monitoring.
Definition: tv_rec.cpp:2077
SignalMonitor::kDTVSigMon_WaitForPAT
static const uint64_t kDTVSigMon_WaitForPAT
Definition: signalmonitor.h:179
MythCoreContext::GetDurSetting
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
Definition: mythcorecontext.h:168
TVRec::TuningGetChanNum
QString TuningGetChanNum(const TuningRequest &request, QString &input) const
Definition: tv_rec.cpp:3449
TVRec::kFlagEITScan
static const uint kFlagEITScan
final result desired is an EIT Scan
Definition: tv_rec.h:458
SignalMonitor::kDTVSigMon_WaitForSDT
static const uint64_t kDTVSigMon_WaitForSDT
Definition: signalmonitor.h:184
TVRec::TeardownSignalMonitor
void TeardownSignalMonitor(void)
If a SignalMonitor instance exists, the monitoring thread is stopped and the instance is deleted.
Definition: tv_rec.cpp:2131
RecorderBase::GetRecordingQuality
virtual RecordingQuality * GetRecordingQuality(const RecordingInfo *ri) const
Returns a report about the current recordings quality.
Definition: recorderbase.cpp:505
TVRec::WaitForNextLiveTVDir
bool WaitForNextLiveTVDir(void)
Definition: tv_rec.cpp:4566
RecStatus::Failing
@ Failing
Definition: recordingstatus.h:17
RecordingInfo::SetDesiredStartTime
void SetDesiredStartTime(const QDateTime &dt)
Definition: recordinginfo.h:243
TVRec::kFlagCloseRec
static const uint kFlagCloseRec
close recorder, keep recording
Definition: tv_rec.h:460
RecordingInfo::GetAutoRunJobs
int GetAutoRunJobs(void) const
Returns a bitmap of which jobs are attached to this RecordingInfo.
Definition: recordinginfo.cpp:506
ProgramInfo::GetSourceID
uint GetSourceID(void) const
Definition: programinfo.h:462
MPEGStreamData
Encapsulates data about MPEG stream and emits events for each table.
Definition: mpegstreamdata.h:85
RecordingRule::m_recProfile
QString m_recProfile
Definition: recordingrule.h:120
TVRec::m_nextLiveTVDir
QString m_nextLiveTVDir
Definition: tv_rec.h:419
TVRec::m_triggerEventSleepWait
QWaitCondition m_triggerEventSleepWait
Definition: tv_rec.h:402
RecorderBase::GetFrameRate
double GetFrameRate(void) const
Returns the latest frame rate.
Definition: recorderbase.h:234
JobQueue::JobIsNotInMask
static bool JobIsNotInMask(int job, int mask)
Definition: jobqueue.h:199
TVRec::CloseChannel
void CloseChannel(void)
Definition: tv_rec.cpp:1238
RecordingRule::m_type
RecordingType m_type
Definition: recordingrule.h:111
RecStatus::Aborted
@ Aborted
Definition: recordingstatus.h:27
vboxutils.h
TVRec::kFlagKillRingBuffer
static const uint kFlagKillRingBuffer
Definition: tv_rec.h:465
TVRec::ChangeState
void ChangeState(TVState nextState)
Puts a state change on the nextState queue.
Definition: tv_rec.cpp:1156
EITScanner::StartActiveScan
void StartActiveScan(TVRec *rec, std::chrono::seconds max_seconds_per_multiplex)
Start active EIT scan.
Definition: eitscanner.cpp:253
DVBStreamData
Definition: dvbstreamdata.h:33
TVRec::m_desiredNextState
TVState m_desiredNextState
Definition: tv_rec.h:390
ProgramInfo::toString
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
Definition: programinfo.cpp:1934
TVRec::m_parentId
uint m_parentId
Definition: tv_rec.h:371
TVRec::run
void run(void) override
Event handling method, contains event loop.
Definition: tv_rec.cpp:1340
MythNotification::kError
static const Type kError
Definition: mythnotification.h:35
RecStatus::Failed
@ Failed
Definition: recordingstatus.h:22
TVRec::m_triggerEventLoopSignal
bool m_triggerEventLoopSignal
Definition: tv_rec.h:400
DTVRecorder::GetStreamData
MPEGStreamData * GetStreamData(void) const
Definition: dtvrecorder.h:57
add_spacer
static QString add_spacer(const QString &channel, const QString &spacer)
Adds the spacer before the last character in chan.
Definition: tv_rec.cpp:2324
RecorderBase::IsRecording
virtual bool IsRecording(void)
Tells whether the StartRecorder() loop is running.
Definition: recorderbase.cpp:243
RecordingRule::GetAutoExpire
AutoExpireType GetAutoExpire(void) const
Definition: recordingrule.h:61
TVRec::TuningShutdowns
void TuningShutdowns(const TuningRequest &request)
This shuts down anything that needs to be shut down before handling the passed in tuning request.
Definition: tv_rec.cpp:3612
TVRec::m_liveTVStartChannel
QString m_liveTVStartChannel
Definition: tv_rec.h:422
storagegroup.h
TVRec::TuningRequest
friend class TuningRequest
Definition: tv_rec.h:146
jobqueue.h
RecorderBase::GetVideoFd
virtual int GetVideoFd(void)=0
Returns file descriptor of recorder device.
TVRec::m_scanner
EITScanner * m_scanner
Definition: tv_rec.h:339
TVRec::m_rbFileExt
QString m_rbFileExt
Definition: tv_rec.h:429
StandardSetting::getValue
virtual QString getValue(void) const
Definition: standardsettings.h:52
LiveTVChain::ReloadAll
void ReloadAll(const QStringList &data=QStringList())
Definition: livetvchain.cpp:210
TVRec::m_eitScanStartTime
QDateTime m_eitScanStartTime
Definition: tv_rec.h:396
TVRec::GetPictureAttribute
int GetPictureAttribute(PictureAttribute attr)
Definition: tv_rec.cpp:3042
TVRec::TuningNewRecorder
void TuningNewRecorder(MPEGStreamData *streamData)
Creates a recorder instance.
Definition: tv_rec.cpp:4214
RecordingInfo::StartedRecording
void StartedRecording(const QString &ext)
Inserts this RecordingInfo into the database as an existing recording.
Definition: recordinginfo.cpp:982
TVRec::GetKeyframePositions
bool GetKeyframePositions(int64_t start, int64_t end, frm_pos_map_t &map) const
Returns byte position in RingBuffer of a keyframes according to recorder.
Definition: tv_rec.cpp:2656
TVRec::s_inputsLock
static QReadWriteLock s_inputsLock
Definition: tv_rec.h:432
TVRec::kFlagWaitingForRecPause
static const uint kFlagWaitingForRecPause
Definition: tv_rec.h:468
RecordingQuality
Definition: recordingquality.h:34
DTVRecorder
This is a specialization of RecorderBase used to handle MPEG-2, MPEG-4, MPEG-4 AVC,...
Definition: dtvrecorder.h:25
CHANNEL_DIRECTION_FAVORITE
@ CHANNEL_DIRECTION_FAVORITE
Definition: tv.h:32
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:137
TVRec::m_eitInputs
std::vector< uint > m_eitInputs
Definition: tv_rec.h:376
uint
unsigned int uint
Definition: compat.h:81
TVRec::kFlagLiveTV
static const uint kFlagLiveTV
final result desired is LiveTV recording
Definition: tv_rec.h:449
TVRec::SetNextLiveTVDir
void SetNextLiveTVDir(QString dir)
Definition: tv_rec.cpp:4579
TVRec::s_eitLock
static QMutex s_eitLock
Definition: tv_rec.h:375
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
TVRec::GetFramerate
float GetFramerate(void)
Returns recordering frame rate from the recorder.
Definition: tv_rec.cpp:2593
TVRec::m_transcodeFirst
bool m_transcodeFirst
Definition: tv_rec.h:358
TVRec::m_signalEventCmdSent
bool m_signalEventCmdSent
Definition: tv_rec.h:342
TVRec::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: tv_rec.cpp:710
TVRec::QueueEITChannelChange
bool QueueEITChannelChange(const QString &name)
Queues up a channel change for the EITScanner.
Definition: tv_rec.cpp:3176
TVRec::m_eitCrawlIdleStart
std::chrono::seconds m_eitCrawlIdleStart
Definition: tv_rec.h:361
TuningRequest::m_minorChan
uint m_minorChan
Definition: tv_rec.h:121
DTVSignalMonitor::GetATSCStreamData
ATSCStreamData * GetATSCStreamData()
Returns the ATSC stream data if it exists.
Definition: dtvsignalmonitor.cpp:555
TVRec::m_triggerEventLoopWait
QWaitCondition m_triggerEventLoopWait
Definition: tv_rec.h:399
DTVChannel::EnterPowerSavingMode
virtual bool EnterPowerSavingMode(void)
Enters power saving mode if the card supports it.
Definition: dtvchannel.h:65
BROWSE_DOWN
@ BROWSE_DOWN
Fetch information on next channel.
Definition: tv.h:42
InputInfo::Clear
virtual void Clear(void)
Definition: inputinfo.cpp:6
CardUtil::IsV4L
static bool IsV4L(const QString &rawtype)
Definition: cardutil.h:145
TVRec::IsErrored
bool IsErrored(void) const
Returns true is "errored" is true, false otherwise.
Definition: tv_rec.h:238
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:912
RecorderBase::GetFramesWritten
virtual long long GetFramesWritten(void)=0
Returns number of frames written to disk.
ProgramInfo::SaveAutoExpire
void SaveAutoExpire(AutoExpireType autoExpire, bool updateDelete=false)
Set "autoexpire" field in "recorded" table to "autoExpire".
Definition: programinfo.cpp:3386
ChannelBase::SetFd
virtual void SetFd(int fd)
Sets file descriptor.
Definition: channelbase.h:55
BROWSE_RIGHT
@ BROWSE_RIGHT
Fetch information on current channel in the future.
Definition: tv.h:44
RecordingInfo::LoadRecordingFile
void LoadRecordingFile()
Definition: recordinginfo.cpp:1719
mythmediabuffer.h
TVRec::GetRecording
ProgramInfo * GetRecording(void)
Allocates and returns a ProgramInfo for the current recording.
Definition: tv_rec.cpp:278
TVRec::SpawnLiveTV
void SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
Tells TVRec to spawn a "Live TV" recorder.
Definition: tv_rec.cpp:2711
GeneralDBOptions::m_skipBtAudio
bool m_skipBtAudio
Definition: tv_rec.h:75
TVRec::CancelNextRecording
void CancelNextRecording(bool cancel)
Tells TVRec to cancel the upcoming recording.
Definition: tv_rec.cpp:386
frm_pos_map_t
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
Definition: programtypes.h:45
tvremoteutil.h
SignalMonitor::Init
static SignalMonitor * Init(const QString &cardtype, int db_cardnum, ChannelBase *channel, bool release_stream)
Definition: signalmonitor.cpp:91
InputInfo::m_inputId
uint m_inputId
unique key in DB for this input
Definition: inputinfo.h:49
PictureAttribute
PictureAttribute
Definition: videoouttypes.h:103
RecorderBase::StopRecording
virtual void StopRecording(void)
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: recorderbase.cpp:224
TVRec::m_triggerEventSleepSignal
bool m_triggerEventSleepSignal
Definition: tv_rec.h:403
ChannelUtil::GetVideoFilters
static QString GetVideoFilters(uint sourceid, const QString &channum)
Definition: channelutil.h:199
RecorderBase::Initialize
virtual void Initialize(void)=0
This is called between SetOptionsFromProfile() and run() to initialize any devices,...
DTVChannel::GetSIStandard
QString GetSIStandard(void) const
Returns PSIP table standard: MPEG, DVB, ATSC, or OpenCable.
Definition: dtvchannel.cpp:45
RecordingRule::m_recGroupID
uint m_recGroupID
Definition: recordingrule.h:123
SET_NEXT
#define SET_NEXT()
Definition: tv_rec.cpp:1033
TVRec::GetNextProgram
void GetNextProgram(BrowseDirection direction, QString &title, QString &subtitle, QString &desc, QString &category, QString &starttime, QString &endtime, QString &callsign, QString &iconpath, QString &channum, uint &chanid, QString &seriesid, QString &programid)
Definition: tv_rec.cpp:3203
SignalMonitor::HasExtraSlowTuning
virtual bool HasExtraSlowTuning(void) const
Definition: signalmonitor.h:60
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:906
dvbstreamdata.h
DTVSignalMonitor::SetProgramNumber
void SetProgramNumber(int progNum)
Definition: dtvsignalmonitor.cpp:214
MasterGuideTable
This table tells the decoder on which PIDs to find other tables, and their sizes and each table's cur...
Definition: atsctables.h:79
TVRec::m_signalMonitor
SignalMonitor * m_signalMonitor
Definition: tv_rec.h:338
BROWSE_FAVORITE
@ BROWSE_FAVORITE
Fetch information on the next favorite channel.
Definition: tv.h:45
TVRec::GetKeyframePosition
int64_t GetKeyframePosition(uint64_t desired) const
Returns byte position in RingBuffer of a keyframe according to recorder.
Definition: tv_rec.cpp:2639
ChannelGroup::ToggleChannel
static bool ToggleChannel(uint chanid, int changrpid, bool delete_chan)
Definition: channelgroup.cpp:19
TuningRequest::m_majorChan
uint m_majorChan
Definition: tv_rec.h:120
kState_WatchingPreRecorded
@ kState_WatchingPreRecorded
Watching Pre-recorded is a TV only state for when we are watching a pre-existing recording.
Definition: tv.h:67
ProgramInfo::GetInputID
uint GetInputID(void) const
Definition: programinfo.h:463
SignalMonitor::SetUpdateRate
void SetUpdateRate(std::chrono::milliseconds msec)
Sets the number of milliseconds between signal monitoring attempts in the signal monitoring thread.
Definition: signalmonitor.h:109
RecorderBase::SavePositionMap
void SavePositionMap(bool force=false, bool finished=false)
Save the seektable to the DB.
Definition: recorderbase.cpp:591
ProgramInfo::SetChanID
void SetChanID(uint _chanid)
Definition: programinfo.h:522
GeneralDBOptions::m_audioSampleRate
int m_audioSampleRate
Definition: tv_rec.h:74
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:31
LiveTVChain::GetInputType
QString GetInputType(int pos=-1) const
Definition: livetvchain.cpp:696
TuningRequest::m_flags
uint m_flags
Definition: tv_rec.h:116
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:372
TVRec::m_nextLiveTVDirLock
QMutex m_nextLiveTVDirLock
Definition: tv_rec.h:420
TVRec::CheckForRecGroupChange
void CheckForRecGroupChange(void)
Check if frontend changed the recording group.
Definition: tv_rec.cpp:2756
ChannelBase::SetChannelByString
virtual bool SetChannelByString(const QString &chan)=0
TVRec::m_internalState
TVState m_internalState
Definition: tv_rec.h:389
ProgramInfo::GetRecordingRuleType
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:451
livetvchain.h
DTVSignalMonitor::IgnoreEncrypted
void IgnoreEncrypted(bool ignore)
Definition: dtvsignalmonitor.h:102
TVRec::m_signalEventCmdTimeout
QDateTime m_signalEventCmdTimeout
Definition: tv_rec.h:341
Buffer
Definition: MythExternControl.h:36
DTVSignalMonitor::SetChannel
void SetChannel(int major, int minor)
Definition: dtvsignalmonitor.cpp:196
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
channelgroup.h
DVBDBOptions::m_dvbEitScan
bool m_dvbEitScan
Definition: tv_rec.h:88
MythDate::secsInPast
std::chrono::seconds secsInPast(const QDateTime &past)
Definition: mythdate.cpp:203
TVRec::m_reachedRecordingDeadline
bool m_reachedRecordingDeadline
Definition: tv_rec.h:347
RecStatus::Recording
@ Recording
Definition: recordingstatus.h:29
TVRec::GetChannelInfo
bool GetChannelInfo(uint &chanid, uint &sourceid, QString &callsign, QString &channum, QString &channame, QString &xmltvid) const
Definition: tv_rec.cpp:3329
TVState
TVState
TVState is an enumeration of the states used by TV and TVRec.
Definition: tv.h:50
RecStatus::Inactive
@ Inactive
Definition: recordingstatus.h:41
ProgramInfo::ToStringList
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
Definition: programinfo.cpp:1267
SignalMonitor::AddListener
void AddListener(SignalMonitorListener *listener)
Definition: signalmonitor.cpp:385
mythcorecontext.h
TVRec::GetV4LChannel
V4LChannel * GetV4LChannel(void)
Definition: tv_rec.cpp:1257
TVRec::m_genOpt
GeneralDBOptions m_genOpt
Definition: tv_rec.h:379
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:666
cardutil.h
ProgramInfo::IsLocal
bool IsLocal(void) const
Definition: programinfo.h:351
TVRec::m_pendingRecLock
QRecursiveMutex m_pendingRecLock
Definition: tv_rec.h:388
TVRec::RingBufferChanged
void RingBufferChanged(MythMediaBuffer *Buffer, RecordingInfo *pginfo, RecordingQuality *recq)
Definition: tv_rec.cpp:3426
JobQueue::AddJobsToMask
static void AddJobsToMask(int jobs, int &mask)
Definition: jobqueue.h:201
TVRec::TuningRestartRecorder
void TuningRestartRecorder(void)
Restarts a stopped recorder or unpauses a paused recorder.
Definition: tv_rec.cpp:4402
TVRec::kSignalMonitoringRate
static constexpr std::chrono::milliseconds kSignalMonitoringRate
How many milliseconds the signal monitor should wait between checks.
Definition: tv_rec.h:437
ChannelBase::CheckChannel
bool CheckChannel(const QString &channum) const
Definition: channelbase.cpp:665
ProgramInfo::QueryAverageHeight
uint QueryAverageHeight(void) const
If present in recording this loads average height of the main video stream from database's stream mar...
Definition: programinfo.cpp:4519
TVRec::SetupDTVSignalMonitor
bool SetupDTVSignalMonitor(bool EITscan)
Tells DTVSignalMonitor what channel to look for.
Definition: tv_rec.cpp:1897
ChannelGroup::GetChannelGroupId
static int GetChannelGroupId(const QString &changroupname)
Definition: channelgroup.cpp:396
TVRec::kFlagAnyRunning
static const uint kFlagAnyRunning
Definition: tv_rec.h:480
RecorderBase::SetNextRecording
void SetNextRecording(const RecordingInfo *ri, MythMediaBuffer *Buffer)
Sets next recording info, to be applied as soon as practical.
Definition: recorderbase.cpp:124
TVRec::SetSignalMonitoringRate
std::chrono::milliseconds SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend=1)
Sets the signal monitoring rate.
Definition: tv_rec.cpp:2169
kNotRecording
@ kNotRecording
Definition: recordingtypes.h:22
PreviewGeneratorQueue::GetPreviewImage
static void GetPreviewImage(const ProgramInfo &pginfo, const QString &token)
Submit a request for the generation of a preview image.
Definition: previewgeneratorqueue.h:89
TVRec::m_dvbOpt
DVBDBOptions m_dvbOpt
Definition: tv_rec.h:380
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
MarkTypes
MarkTypes
Definition: programtypes.h:47
JOB_METADATA
@ JOB_METADATA
Definition: jobqueue.h:80
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
DVBDBOptions
Definition: tv_rec.h:81
GeneralDBOptions::m_videoDev
QString m_videoDev
Definition: tv_rec.h:70
TVRec::kFlagFinishRecording
static const uint kFlagFinishRecording
Definition: tv_rec.h:443
DTVChannel::SetTuningMode
void SetTuningMode(const QString &tuning_mode)
Sets tuning mode: "mpeg", "dvb", "atsc", etc.
Definition: dtvchannel.cpp:87
FireWireDBOptions::m_connection
int m_connection
Definition: tv_rec.h:97
DTVSignalMonitor::SetStreamData
virtual void SetStreamData(MPEGStreamData *data)
Sets the MPEG stream data for DTVSignalMonitor to use, and connects the table signals to the monitor.
Definition: dtvsignalmonitor.cpp:258
kSingleRecord
@ kSingleRecord
Definition: recordingtypes.h:23
BROWSE_SAME
@ BROWSE_SAME
Fetch browse information on current channel and time.
Definition: tv.h:40
TVRec
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:142
FireWireDBOptions
Definition: tv_rec.h:91
RecordingInfo::AddHistory
void AddHistory(bool resched=true, bool forcedup=false, bool future=false)
Adds recording history, creating "record" it if necessary.
Definition: recordinginfo.cpp:1350
TVRec::FinishedRecording
void FinishedRecording(RecordingInfo *curRec, RecordingQuality *recq)
If not a premature stop, adds program to history of recorded programs.
Definition: tv_rec.cpp:855
TVRec::m_signalMonitorCheckCnt
uint m_signalMonitorCheckCnt
Definition: tv_rec.h:346
DTVSignalMonitor::SetRotorTarget
virtual void SetRotorTarget(float)
Sets rotor target pos from 0.0 to 1.0.
Definition: dtvsignalmonitor.h:46
TVRec::kAutoRunProfile
@ kAutoRunProfile
Definition: tv_rec.h:325
RecorderBase::SetVideoFilters
virtual void SetVideoFilters(QString &filters)=0
Tells recorder which filters to use.
TuningRequest::IsOnSameMultiplex
bool IsOnSameMultiplex(void) const
Definition: tv_rec.h:113
TVRec::m_stateFlags
uint m_stateFlags
Definition: tv_rec.h:393
TVRec::WakeEventLoop
void WakeEventLoop(void)
Definition: tv_rec.cpp:251
GeneralDBOptions::m_audioDev
QString m_audioDev
Definition: tv_rec.h:72
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
DTVChannel::GetProgramNumber
int GetProgramNumber(void) const
Returns program number in PAT, -1 if unknown.
Definition: dtvchannel.h:89
LiveTVChain::AppendNewProgram
void AppendNewProgram(ProgramInfo *pginfo, const QString &channum, const QString &inputname, bool discont)
Definition: livetvchain.cpp:61
TVRec::GetState
TVState GetState(void) const
Returns the TVState of the recorder.
Definition: tv_rec.cpp:264
MPEGStreamData::Reset
virtual void Reset(void)
Definition: mpegstreamdata.h:94
TVRec::m_signalMonitorDeadline
QDateTime m_signalMonitorDeadline
Definition: tv_rec.h:345
CardUtil::GetSourceID
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1943
DVBDBOptions::m_dvbTuningDelay
std::chrono::milliseconds m_dvbTuningDelay
Definition: tv_rec.h:87
PendingInfo::m_doNotAsk
bool m_doNotAsk
Definition: tv_rec.h:137
TVRec::SwitchLiveTVRingBuffer
bool SwitchLiveTVRingBuffer(const QString &channum, bool discont, bool set_rec)
Definition: tv_rec.cpp:4732
tv_rec.h
DTVSignalMonitor
This class is intended to detect the presence of needed tables.
Definition: dtvsignalmonitor.h:14
TVRec::StateIsPlaying
static bool StateIsPlaying(TVState state)
Returns true if we are in any state associated with a player.
Definition: tv_rec.cpp:783
ChannelBase::GetInputID
virtual int GetInputID(void) const
Definition: channelbase.h:67
kState_WatchingLiveTV
@ kState_WatchingLiveTV
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
Definition: tv.h:63
RemoteRecordPending
bool RemoteRecordPending(uint inputid, const ProgramInfo *pginfo, std::chrono::seconds secsleft, bool hasLater)
Definition: tvremoteutil.cpp:50
StorageGroup
Definition: storagegroup.h:11
TableID::TVCT
@ TVCT
Definition: mpegtables.h:362
SignalMonitor::Start
virtual void Start()
Start signal monitoring thread.
Definition: signalmonitor.cpp:288
MythMediaBuffer::Create
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, std::chrono::milliseconds Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
Definition: mythmediabuffer.cpp:98
InputInfo
Definition: inputinfo.h:14
previewgeneratorqueue.h
TVRec::m_lastTuningRequest
TuningRequest m_lastTuningRequest
Definition: tv_rec.h:395
SignalMonitor::SetNotifyFrontend
void SetNotifyFrontend(bool notify)
Enables or disables frontend notification of the current signal value.
Definition: signalmonitor.h:92
TVRec::m_recorderThread
MThread * m_recorderThread
Recorder thread, runs RecorderBase::run().
Definition: tv_rec.h:355
atsctables.h
TVRec::StartedRecording
void StartedRecording(RecordingInfo *curRec)
Inserts a "curRec" into the database.
Definition: tv_rec.cpp:829
TVRec::InitAutoRunJobs
void InitAutoRunJobs(RecordingInfo *rec, AutoRunInitType t, RecordingProfile *recpro, int line)
Definition: tv_rec.cpp:2836
BrowseDirection
BrowseDirection
Used to request ProgramInfo for channel browsing.
Definition: tv.h:37
PendingInfo::m_ask
bool m_ask
Definition: tv_rec.h:136
StandardSetting
Definition: standardsettings.h:29
SendMythSystemRecEvent
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
Definition: mythsystemevent.cpp:324
TVRec::GetFlags
uint GetFlags(void) const
Definition: tv_rec.h:245
MPEGStreamData::AddListeningPID
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
Definition: mpegstreamdata.h:120
CardUtil::GetInputInfo
static bool GetInputInfo(InputInfo &input, std::vector< uint > *groupids=nullptr)
Definition: cardutil.cpp:1696
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:838
recordingprofile.h
TVRec::TVRec
TVRec(int _inputid)
Performs instance initialization not requiring access to database.
Definition: tv_rec.cpp:86
ChannelBase::GetSourceID
virtual uint GetSourceID(void) const
Definition: channelbase.h:71
CardUtil::IsEITCapable
static bool IsEITCapable(const QString &rawtype)
Definition: cardutil.h:170
TVRec::kFlagAntennaAdjust
static const uint kFlagAntennaAdjust
antenna adjusting mode (LiveTV without recording).
Definition: tv_rec.h:453
TVRec::kFlagExitPlayer
static const uint kFlagExitPlayer
Definition: tv_rec.h:442
StateToString
QString StateToString(TVState state)
Returns a human readable QString representing a TVState.
Definition: tv.cpp:11
DTVChannel
Class providing a generic interface to digital tuning hardware.
Definition: dtvchannel.h:33
RecorderBase::GetKeyframePosition
long long GetKeyframePosition(long long desired) const
Returns closest keyframe position before the desired frame.
Definition: recorderbase.cpp:520
SignalMonitor::IsErrored
bool IsErrored(void) const
Definition: signalmonitor.h:82
ProgramInfo::SetRecordingRuleID
void SetRecordingRuleID(uint id)
Definition: programinfo.h:538
TVRec::TuningSignalCheck
MPEGStreamData * TuningSignalCheck(void)
This checks if we have a channel lock.
Definition: tv_rec.cpp:3944
TVRec::~TVRec
~TVRec(void) override
Stops the event and scanning threads and deletes any ChannelBase, RingBuffer, and RecorderBase instan...
Definition: tv_rec.cpp:215
ChannelBase::GetNextChannel
virtual uint GetNextChannel(uint chanid, ChannelChangeDirection direction) const
Definition: channelbase.cpp:201
RecordingProfile
Definition: recordingprofile.h:41
TVRec::m_isPip
bool m_isPip
Definition: tv_rec.h:372
DTVChannel::GetCachedPids
void GetCachedPids(pid_cache_t &pid_cache) const
Returns cached MPEG PIDs for last tuned channel.
Definition: dtvchannel.cpp:97
get_highest_input
static int get_highest_input(void)
Definition: tv_rec.cpp:1308
TVRec::SetVideoFiltersForChannel
bool SetVideoFiltersForChannel(uint sourceid, const QString &channum)
Definition: tv_rec.cpp:2494
DTVChannel::GetSuggestedTuningMode
QString GetSuggestedTuningMode(bool is_live_tv) const
Returns suggested tuning mode: "mpeg", "dvb", or "atsc".
Definition: dtvchannel.cpp:57
PendingInfo::m_recordingStart
QDateTime m_recordingStart
Definition: tv_rec.h:133
TuningRequest::m_channel
QString m_channel
Definition: tv_rec.h:118
TVRec::m_fwOpt
FireWireDBOptions m_fwOpt
Definition: tv_rec.h:381
TVRec::HasFlags
bool HasFlags(uint f) const
Definition: tv_rec.h:287
TVRec::GetDTVRecorder
DTVRecorder * GetDTVRecorder(void)
Definition: tv_rec.cpp:1233
ChannelUtil::GetChanNum
static QString GetChanNum(int chan_id)
Returns the channel-number string of the given channel.
Definition: channelutil.cpp:777
MythDeque::enqueue
void enqueue(T d)
Adds item to the back of the list. O(1).
Definition: mythdeque.h:41
RecordingInfo::GetRecordingRule
RecordingRule * GetRecordingRule(void)
Returns the "record" field, creating it if necessary.
Definition: recordinginfo.cpp:926
ProgramInfo::GetRecordingRuleID
uint GetRecordingRuleID(void) const
Definition: programinfo.h:449
CHANNEL_DIRECTION_SAME
@ CHANNEL_DIRECTION_SAME
Definition: tv.h:33
TVRec::StartRecording
RecStatus::Type StartRecording(ProgramInfo *pginfo)
Tells TVRec to Start recording the program "rcinfo" as soon as possible.
Definition: tv_rec.cpp:436
TVRec::SetChannelInfo
bool SetChannelInfo(uint chanid, uint sourceid, const QString &oldchannum, const QString &callsign, const QString &channum, const QString &channame, const QString &xmltvid)
Definition: tv_rec.cpp:3370
RecordingInfo::ApplyRecordRecGroupChange
void ApplyRecordRecGroupChange(const QString &newrecgroup)
Sets the recording group, both in this RecordingInfo and in the database.
Definition: recordinginfo.cpp:655
TVRec::SetLiveRecording
void SetLiveRecording(int recording)
Tells the Scheduler about changes to the recording status of the LiveTV recording.
Definition: tv_rec.cpp:2872
TVRec::kFlagFrontendReady
static const uint kFlagFrontendReady
Definition: tv_rec.h:440
recordingrule.h
MasterGuideTable::TableType
uint TableType(uint i) const
Definition: atsctables.h:124
TVRec::SetChannel
void SetChannel(const QString &name, uint requestType=kFlagDetect)
Changes to a named channel on the current tuner.
Definition: tv_rec.cpp:3127
TVRec::StopLiveTV
void StopLiveTV(void)
Tells TVRec to stop a "Live TV" recorder.
Definition: tv_rec.cpp:2918
TVRec::m_earlyCommFlag
bool m_earlyCommFlag
Definition: tv_rec.h:359
get_use_eit
static bool get_use_eit(uint inputid)
Definition: tv_rec.cpp:1267
MythDeque::dequeue
T dequeue()
Removes item from front of list and returns a copy. O(1).
Definition: mythdeque.h:31
RecorderBase::CheckForRingBufferSwitch
virtual bool CheckForRingBufferSwitch(void)
If requested, switch to new RingBuffer/ProgramInfo objects.
Definition: recorderbase.cpp:351
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition: referencecounter.cpp:101
CardUtil::GetConflictingInputs
static std::vector< uint > GetConflictingInputs(uint inputid)
Definition: cardutil.cpp:2236
ProgramInfo::QueryRecordingGroup
QString QueryRecordingGroup(void) const
Query recgroup from recorded.
Definition: programinfo.cpp:5055
V4LChannel
Implements tuning for TV cards using the V4L driver API, both versions 1 and 2.
Definition: v4lchannel.h:30
TVRec::HandlePendingRecordings
void HandlePendingRecordings(void)
Definition: tv_rec.cpp:1683
TuningRequest::m_input
QString m_input
Definition: tv_rec.h:119
TVRec::TuningFrequency
void TuningFrequency(const TuningRequest &request)
Performs initial tuning required for any tuning event.
Definition: tv_rec.cpp:3701
TVRec::RemovePlaying
TVState RemovePlaying(TVState state) const
Returns TVState that would remove the playing, but potentially keep recording if we are watching an i...
Definition: tv_rec.cpp:809
TVRec::ChangePictureAttribute
int ChangePictureAttribute(PictureAdjustType type, PictureAttribute attr, bool direction)
Returns current value [0,100] if it succeeds, -1 otherwise.
Definition: tv_rec.cpp:3060
ApplyCachedPids
static bool ApplyCachedPids(DTVSignalMonitor *dtvMon, const DTVChannel *channel)
Definition: tv_rec.cpp:1865
TVRec::StateIsRecording
static bool StateIsRecording(TVState state)
Returns true if "state" is kState_RecordingOnly, or kState_WatchingLiveTV.
Definition: tv_rec.cpp:773
JOB_TRANSCODE
@ JOB_TRANSCODE
Definition: jobqueue.h:78
GeneralDBOptions::m_waitForSeqstart
bool m_waitForSeqstart
Definition: tv_rec.h:78
TVRec::m_switchingBuffer
volatile bool m_switchingBuffer
Definition: tv_rec.h:404
TuningRequest::m_program
RecordingInfo * m_program
Definition: tv_rec.h:117
MythCoreContext::dispatch
void dispatch(const MythEvent &event)
Definition: mythcorecontext.cpp:1719
init_jobs
static int init_jobs(const RecordingInfo *rec, RecordingProfile &profile, bool on_host, bool transcode_bfr_comm, bool on_line_comm)
Definition: tv_rec.cpp:4110
TVRec::AutoRunInitType
AutoRunInitType
Definition: tv_rec.h:325
CardUtil::IsChannelReusable
static bool IsChannelReusable(const QString &rawtype)
Definition: cardutil.h:222
ChannelUtil::IsOnSameMultiplex
static bool IsOnSameMultiplex(uint srcid, const QString &new_channum, const QString &old_channum)
Definition: channelutil.cpp:991
dtvsignalmonitor.h
MythRandomStd::MythRandom
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20
TVRec::HandleTuning
void HandleTuning(void)
Handles all tuning events.
Definition: tv_rec.cpp:3540
kState_RecordingOnly
@ kState_RecordingOnly
Recording Only is a TVRec only state for when we are recording a program, but there is no one current...
Definition: tv.h:84
COMM_FLAG_COMMFREE
@ COMM_FLAG_COMMFREE
Definition: programtypes.h:124
ProgramInfo::IsCommercialFree
bool IsCommercialFree(void) const
Definition: programinfo.h:477
RecorderBase::IsPaused
virtual bool IsPaused(bool holding_lock=false) const
Returns true iff recorder is paused.
Definition: recorderbase.cpp:281
RecorderBase::SetRecording
void SetRecording(const RecordingInfo *pginfo)
Changes the Recording from the one set initially with SetOptionsFromProfile().
Definition: recorderbase.cpp:89
TVRec::kFlagNeedToStartRecorder
static const uint kFlagNeedToStartRecorder
Definition: tv_rec.h:470
TVRec::LoadProfile
QString LoadProfile(void *tvchain, RecordingInfo *rec, RecordingProfile &profile) const
Definition: tv_rec.cpp:4168
EITScanner
Acts as glue between ChannelBase, EITSource and EITHelper.
Definition: eitscanner.h:28
TVRec::GetDTVSignalMonitor
DTVSignalMonitor * GetDTVSignalMonitor(void)
Definition: tv_rec.cpp:2207
ProgramInfo::SetStorageGroup
void SetStorageGroup(const QString &group)
Definition: programinfo.h:530
TVRec::SetRingBuffer
void SetRingBuffer(MythMediaBuffer *Buffer)
Sets "ringBuffer", deleting any existing RingBuffer.
Definition: tv_rec.cpp:3409
CardUtil::GetStartChannel
static QString GetStartChannel(uint inputid)
Definition: cardutil.cpp:1790
ATSCStreamData::GetCachedMGT
const MasterGuideTable * GetCachedMGT(bool current=true) const
Definition: atscstreamdata.cpp:773
TVRec::m_stateChangeLock
QRecursiveMutex m_stateChangeLock
Definition: tv_rec.h:387
ProgramInfo::IsSameProgramWeakCheck
bool IsSameProgramWeakCheck(const ProgramInfo &other) const
Checks for duplicate using only title, chanid and startts.
Definition: programinfo.cpp:2171
TVRec::ClearFlags
void ClearFlags(uint f, const QString &file, int line)
Definition: tv_rec.cpp:4476
TVRec::GetTVRec
static TVRec * GetTVRec(uint inputid)
Definition: tv_rec.cpp:4874
InputInfo::m_mplexId
uint m_mplexId
mplexid restriction if applicable
Definition: inputinfo.h:50
ChannelBase::ChangePictureAttribute
virtual int ChangePictureAttribute(PictureAdjustType, PictureAttribute, bool)
Definition: channelbase.h:95
TVRec::m_triggerEventLoopLock
QMutex m_triggerEventLoopLock
Definition: tv_rec.h:398
RecordingInfo::SetDesiredEndTime
void SetDesiredEndTime(const QDateTime &dt)
Definition: recordinginfo.h:244
MythMediaBuffer::IsOpen
virtual bool IsOpen(void) const =0
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:898
PendingInfo
Definition: tv_rec.h:127
TVRec::m_reachedPreFail
bool m_reachedPreFail
Definition: tv_rec.h:349
LiveTVChain::FinishedRecording
void FinishedRecording(ProgramInfo *pginfo)
Definition: livetvchain.cpp:111
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:838
TVRec::m_changeState
bool m_changeState
Definition: tv_rec.h:391
TVRec::s_inputs
static QMap< uint, TVRec * > s_inputs
Definition: tv_rec.h:433
ChannelBase::GetChanID
virtual int GetChanID(void) const
Definition: channelbase.cpp:494
FireWireDBOptions::m_model
QString m_model
Definition: tv_rec.h:98
ProgramInfo::GetSubtitle
QString GetSubtitle(void) const
Definition: programinfo.h:363
eit_start_rand
static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout)
Definition: tv_rec.cpp:1325
LiveTVChain
Keeps track of recordings in a current LiveTV instance.
Definition: livetvchain.h:32
SignalMonitorValue::Init
static void Init()
Initializes the some static constants needed by SignalMonitorValue.
Definition: signalmonitorvalue.cpp:20
LOC
#define LOC
Definition: tv_rec.cpp:49
ProgramInfo::SetRecordingStartTime
void SetRecordingStartTime(const QDateTime &dt)
Definition: programinfo.h:525
TVRec::m_preFailDeadline
QDateTime m_preFailDeadline
Definition: tv_rec.h:348