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  {
291  tmppginfo = new ProgramInfo();
292  }
293  tmppginfo->SetInputID(m_inputId);
294 
295  return tmppginfo;
296 }
297 
312 void TVRec::RecordPending(const ProgramInfo *rcinfo, std::chrono::seconds secsleft,
313  bool hasLater)
314 {
315  QMutexLocker statelock(&m_stateChangeLock);
316  QMutexLocker pendlock(&m_pendingRecLock);
317 
318  if (secsleft < 0s)
319  {
320  LOG(VB_RECORD, LOG_INFO, LOC + "Pending recording revoked on " +
321  QString("inputid [%1]").arg(rcinfo->GetInputID()));
322 
323  PendingMap::iterator it = m_pendingRecordings.find(rcinfo->GetInputID());
324  if (it != m_pendingRecordings.end())
325  {
326  (*it).m_ask = false;
327  (*it).m_doNotAsk = true;
328  (*it).m_canceled = true;
329  }
330  return;
331  }
332 
333  LOG(VB_RECORD, LOG_INFO, LOC +
334  QString("RecordPending on inputid [%1]").arg(rcinfo->GetInputID()));
335 
336  PendingInfo pending;
337  pending.m_info = new ProgramInfo(*rcinfo);
338  pending.m_recordingStart = MythDate::current().addSecs(secsleft.count());
339  pending.m_hasLaterShowing = hasLater;
340  pending.m_ask = true;
341  pending.m_doNotAsk = false;
342 
343  m_pendingRecordings[rcinfo->GetInputID()] = pending;
344 
345  // If this isn't a recording for this instance to make, we are done
346  if (rcinfo->GetInputID() != m_inputId)
347  return;
348 
349  // We also need to check our input groups
350  std::vector<uint> inputids = CardUtil::GetConflictingInputs(rcinfo->GetInputID());
351 
352  m_pendingRecordings[rcinfo->GetInputID()].m_possibleConflicts = inputids;
353 
354  pendlock.unlock();
355  statelock.unlock();
356  for (uint inputid : inputids)
357  RemoteRecordPending(inputid, rcinfo, secsleft, hasLater);
358  statelock.relock();
359  pendlock.relock();
360 }
361 
366 {
369  delete old_rec;
370 }
371 
375 QDateTime TVRec::GetRecordEndTime(const ProgramInfo *pi) const
376 {
377  bool spcat = (!m_overRecordCategory.isEmpty() &&
379  std::chrono::seconds secs = (spcat) ? m_overRecordSecCat : m_overRecordSecNrml;
380  return pi->GetRecordingEndTime().addSecs(secs.count());
381 }
382 
388 void TVRec::CancelNextRecording(bool cancel)
389 {
390  QMutexLocker pendlock(&m_pendingRecLock);
391  LOG(VB_RECORD, LOG_INFO, LOC +
392  QString("CancelNextRecording(%1) -- begin").arg(cancel));
393 
394  PendingMap::iterator it = m_pendingRecordings.find(m_inputId);
395  if (it == m_pendingRecordings.end())
396  {
397  LOG(VB_RECORD, LOG_INFO, LOC + QString("CancelNextRecording(%1) -- "
398  "error, unknown recording").arg(cancel));
399  return;
400  }
401 
402  if (cancel)
403  {
404  std::vector<unsigned int> &inputids = (*it).m_possibleConflicts;
405  for (uint inputid : inputids)
406  {
407  LOG(VB_RECORD, LOG_INFO, LOC +
408  QString("CancelNextRecording -- inputid 0x%1")
409  .arg((uint64_t)inputid,0,16));
410 
411  pendlock.unlock();
412  RemoteRecordPending(inputid, (*it).m_info, -1s, false);
413  pendlock.relock();
414  }
415 
416  LOG(VB_RECORD, LOG_INFO, LOC +
417  QString("CancelNextRecording -- inputid [%1]")
418  .arg(m_inputId));
419 
420  RecordPending((*it).m_info, -1s, false);
421  }
422  else
423  {
424  (*it).m_canceled = false;
425  }
426 
427  LOG(VB_RECORD, LOG_INFO, LOC +
428  QString("CancelNextRecording(%1) -- end").arg(cancel));
429 }
430 
439 {
440  RecordingInfo ri1(*pginfo);
443  RecordingInfo *rcinfo = &ri1;
444 
445  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartRecording(%1)")
446  .arg(rcinfo->toString(ProgramInfo::kTitleSubtitle)));
447 
448  QMutexLocker lock(&m_stateChangeLock);
449 
452 
453  // Flush out any pending state changes
455 
456  // We need to do this check early so we don't cancel an overrecord
457  // that we're trying to extend.
461  {
462  int post_roll_seconds = m_curRecording->GetRecordingEndTime()
463  .secsTo(m_recordEndTime);
464 
469 
471  .addSecs(post_roll_seconds);
472 
473  QString msg = QString("updating recording: %1 %2 %3 %4")
474  .arg(m_curRecording->GetTitle(),
475  QString::number(m_curRecording->GetChanID()),
478  LOG(VB_RECORD, LOG_INFO, LOC + msg);
479 
480  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
481 
483  return RecStatus::Recording;
484  }
485 
486  bool cancelNext = false;
487  PendingInfo pendinfo;
488 
489  m_pendingRecLock.lock();
490  PendingMap::iterator it = m_pendingRecordings.find(m_inputId);
491  if (it != m_pendingRecordings.end())
492  {
493  (*it).m_ask = (*it).m_doNotAsk = false;
494  cancelNext = (*it).m_canceled;
495  }
496  m_pendingRecLock.unlock();
497 
498  // Flush out events...
500 
501  // Rescan pending recordings since the event loop may have deleted
502  // a stale entry. If this happens the info pointer will not be valid
503  // since the HandlePendingRecordings loop will have deleted it.
504  m_pendingRecLock.lock();
505  it = m_pendingRecordings.find(m_inputId);
506  bool has_pending = (it != m_pendingRecordings.end());
507  if (has_pending)
508  pendinfo = *it;
509  m_pendingRecLock.unlock();
510 
511  // If the needed input is in a shared input group, and we are
512  // not canceling the recording anyway, check other recorders
513  if (!cancelNext && has_pending && !pendinfo.m_possibleConflicts.empty())
514  {
515  LOG(VB_RECORD, LOG_INFO, LOC +
516  "Checking input group recorders - begin");
517  std::vector<unsigned int> &inputids = pendinfo.m_possibleConflicts;
518 
519  uint mplexid = 0;
520  uint chanid = 0;
521  uint sourceid = 0;
522  std::vector<unsigned int> inputids2;
523  std::vector<TVState> states;
524 
525  // Stop remote recordings if needed
526  for (uint inputid : inputids)
527  {
528  InputInfo busy_input;
529  bool is_busy = RemoteIsBusy(inputid, busy_input);
530 
531  if (is_busy && !sourceid)
532  {
533  mplexid = pendinfo.m_info->QueryMplexID();
534  chanid = pendinfo.m_info->GetChanID();
535  sourceid = pendinfo.m_info->GetSourceID();
536  }
537 
538  if (is_busy &&
539  ((sourceid != busy_input.m_sourceId) ||
540  (mplexid != busy_input.m_mplexId) ||
541  ((mplexid == 0 || mplexid == 32767) &&
542  chanid != busy_input.m_chanId)))
543  {
544  states.push_back((TVState) RemoteGetState(inputid));
545  inputids2.push_back(inputid);
546  }
547  }
548 
549  bool ok = true;
550  for (uint i = 0; (i < inputids2.size()) && ok; i++)
551  {
552  LOG(VB_RECORD, LOG_INFO, LOC +
553  QString("Attempting to stop input [%1] in state %2")
554  .arg(inputids2[i]).arg(StateToString(states[i])));
555 
556  bool success = RemoteStopRecording(inputids2[i]);
557  if (success)
558  {
559  uint state = RemoteGetState(inputids2[i]);
560  LOG(VB_GENERAL, LOG_INFO, LOC + QString("a [%1]: %2")
561  .arg(inputids2[i]).arg(StateToString((TVState)state)));
562  success = (kState_None == state);
563  }
564 
565  // If we managed to stop LiveTV recording, restart playback..
566  if (success && states[i] == kState_WatchingLiveTV)
567  {
568  QString message = QString("QUIT_LIVETV %1").arg(inputids2[i]);
569  MythEvent me(message);
570  gCoreContext->dispatch(me);
571  }
572 
573  LOG(VB_RECORD, LOG_INFO, LOC +
574  QString("Stopping recording on [%1], %2") .arg(inputids2[i])
575  .arg(success ? "succeeded" : "failed"));
576 
577  ok &= success;
578  }
579 
580  // If we failed to stop the remote recordings, don't record
581  if (!ok)
582  {
583  CancelNextRecording(true);
584  cancelNext = true;
585  }
586 
587  inputids.clear();
588 
589  LOG(VB_RECORD, LOG_INFO, LOC + "Checking input group recorders - done");
590  }
591 
592  bool did_switch = false;
593  if (!cancelNext && (GetState() == kState_RecordingOnly))
594  {
596  did_switch = (nullptr != ri2);
597  if (did_switch)
598  {
599  // Make sure scheduler is allowed to end this recording
600  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
601 
603  }
604  else
605  {
606  // If in post-roll, end recording
607  m_stateChangeLock.unlock();
608  StopRecording();
609  m_stateChangeLock.lock();
610  }
611  }
612 
613  if (!cancelNext && (GetState() == kState_None))
614  {
615  if (m_tvChain)
616  {
617  QString message = QString("LIVETV_EXITED");
618  MythEvent me(message, m_tvChain->GetID());
619  gCoreContext->dispatch(me);
620  m_tvChain->DecrRef();
621  m_tvChain = nullptr;
622  }
623 
625 
626  // Tell event loop to begin recording.
627  m_curRecording = new RecordingInfo(*rcinfo);
632 
633  // Make sure scheduler is allowed to end this recording
634  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
635 
638  else
639  LOG(VB_RECORD, LOG_WARNING, LOC + "Still failing.");
641  }
642  else if (!cancelNext && (GetState() == kState_WatchingLiveTV))
643  {
647 
648  // We want the frontend to change channel for recording
649  // and disable the UI for channel change, PiP, etc.
650 
651  QString message = QString("LIVETV_WATCH %1 1").arg(m_inputId);
652  QStringList prog;
653  rcinfo->ToStringList(prog);
654  MythEvent me(message, prog);
655  gCoreContext->dispatch(me);
656  }
657  else if (!did_switch)
658  {
659  QString msg = QString("Wanted to record: %1 %2 %3 %4\n\t\t\t")
660  .arg(rcinfo->GetTitle(),
661  QString::number(rcinfo->GetChanID()),
664 
665  if (cancelNext)
666  {
667  msg += "But a user has canceled this recording";
669  }
670  else
671  {
672  msg += QString("But the current state is: %1")
675  }
676 
678  {
679  msg += QString("\n\t\t\tCurrently recording: %1 %2 %3 %4")
680  .arg(m_curRecording->GetTitle(),
681  QString::number(m_curRecording->GetChanID()),
684  }
685 
686  LOG(VB_GENERAL, LOG_INFO, LOC + msg);
687  }
688 
689  for (const auto & pend : std::as_const(m_pendingRecordings))
690  delete pend.m_info;
691  m_pendingRecordings.clear();
692 
693  if (!did_switch)
694  {
696 
697  QMutexLocker locker(&m_pendingRecLock);
698  if ((m_curRecording) &&
703  {
704  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
705  }
706  return m_recStatus;
707  }
708 
709  return GetRecordingStatus();
710 }
711 
713 {
714  QMutexLocker pendlock(&m_pendingRecLock);
715  return m_recStatus;
716 }
717 
719  RecStatus::Type new_status, int line, bool have_lock)
720 {
721  RecStatus::Type old_status { RecStatus::Unknown };
722  if (have_lock)
723  {
724  old_status = m_recStatus;
725  m_recStatus = new_status;
726  }
727  else
728  {
729  m_pendingRecLock.lock();
730  old_status = m_recStatus;
731  m_recStatus = new_status;
732  m_pendingRecLock.unlock();
733  }
734 
735  LOG(VB_RECORD, LOG_INFO, LOC +
736  QString("SetRecordingStatus(%1->%2) on line %3")
737  .arg(RecStatus::toString(old_status, kSingleRecord),
738  RecStatus::toString(new_status, kSingleRecord),
739  QString::number(line)));
740 }
741 
748 void TVRec::StopRecording(bool killFile)
749 {
750  if (StateIsRecording(GetState()))
751  {
752  QMutexLocker lock(&m_stateChangeLock);
753  if (killFile)
754  SetFlags(kFlagKillRec, __FILE__, __LINE__);
755  else if (m_curRecording)
756  {
757  QDateTime now = MythDate::current(true);
758  if (now < m_curRecording->GetDesiredEndTime())
760  }
762  // wait for state change to take effect
764  ClearFlags(kFlagCancelNextRecording|kFlagKillRec, __FILE__, __LINE__);
765 
767  }
768 }
769 
776 {
777  return (state == kState_RecordingOnly ||
778  state == kState_WatchingLiveTV);
779 }
780 
786 {
787  return (state == kState_WatchingPreRecorded);
788 }
789 
796 {
797  if (StateIsRecording(state))
798  return kState_None;
799 
800  LOG(VB_GENERAL, LOG_ERR, LOC +
801  QString("Unknown state in RemoveRecording: %1")
802  .arg(StateToString(state)));
803  return kState_Error;
804 }
805 
812 {
813  if (StateIsPlaying(state))
814  {
815  if (state == kState_WatchingPreRecorded)
816  return kState_None;
817  return kState_RecordingOnly;
818  }
819 
820  QString msg = "Unknown state in RemovePlaying: %1";
821  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(StateToString(state)));
822 
823  return kState_Error;
824 }
825 
832 {
833  if (!curRec)
834  return;
835 
836  curRec->StartedRecording(m_rbFileExt);
837  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartedRecording(%1) fn(%2)")
838  .arg(curRec->MakeUniqueKey(), curRec->GetPathname()));
839 
840  if (curRec->IsCommercialFree())
842 
843  AutoRunInitType t = (curRec->GetRecordingGroup() == "LiveTV") ?
845  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
846 
847  SendMythSystemRecEvent("REC_STARTED", curRec);
848 }
849 
858 {
859  if (!curRec)
860  return;
861 
862  // Make sure the recording group is up to date
863  const QString recgrp = curRec->QueryRecordingGroup();
864  curRec->SetRecordingGroup(recgrp);
865 
866  bool is_good = true;
867  if (recq)
868  {
869  LOG((recq->IsDamaged()) ? VB_GENERAL : VB_RECORD, LOG_INFO,
870  LOC + QString("FinishedRecording(%1) %2 recq:\n%3")
871  .arg(curRec->MakeUniqueKey(),
872  (recq->IsDamaged()) ? "damaged" : "good",
873  recq->toStringXML()));
874  is_good = !recq->IsDamaged();
875  delete recq;
876  recq = nullptr;
877  }
878 
879  RecStatus::Type ors = curRec->GetRecordingStatus();
880  // Set the final recording status
881  if (curRec->GetRecordingStatus() == RecStatus::Recording)
883  else if (curRec->GetRecordingStatus() != RecStatus::Recorded)
885  curRec->SetRecordingEndTime(MythDate::current(true));
886  is_good &= (curRec->GetRecordingStatus() == RecStatus::Recorded);
887 
888  // Figure out if this was already done for this recording
889  bool was_finished = false;
890  static QMutex s_finRecLock;
891  static QHash<QString,QDateTime> s_finRecMap;
892  {
893  QMutexLocker locker(&s_finRecLock);
894  QDateTime now = MythDate::current();
895  QDateTime expired = now.addSecs(-5LL * 60);
896  QHash<QString,QDateTime>::iterator it = s_finRecMap.begin();
897  while (it != s_finRecMap.end())
898  {
899  if ((*it) < expired)
900  it = s_finRecMap.erase(it);
901  else
902  ++it;
903  }
904  QString key = curRec->MakeUniqueKey();
905  it = s_finRecMap.find(key);
906  if (it != s_finRecMap.end())
907  was_finished = true;
908  else
909  s_finRecMap[key] = now;
910  }
911 
912  // Print something informative to the log
913  LOG(VB_RECORD, LOG_INFO, LOC +
914  QString("FinishedRecording(%1) %2 quality"
915  "\n\t\t\ttitle: %3\n\t\t\t"
916  "in recgroup: %4 status: %5:%6 %7 %8")
917  .arg(curRec->MakeUniqueKey(),
918  is_good ? "Good" : "Bad",
919  curRec->GetTitle(),
920  recgrp,
923  HasFlags(kFlagDummyRecorderRunning)?"is_dummy":"not_dummy",
924  was_finished?"already_finished":"finished_now"));
925 
926  // This has already been called on this recording..
927  if (was_finished)
928  return;
929 
930  // Notify the frontend watching live tv that this file is final
931  if (m_tvChain)
932  m_tvChain->FinishedRecording(curRec);
933 
934  // if this is a dummy recorder, do no more..
936  {
937  curRec->FinishedRecording(true); // so end time is updated
938  SendMythSystemRecEvent("REC_FINISHED", curRec);
939  return;
940  }
941 
942  // Get the width and set the videoprops
943  MarkTypes aspectRatio = curRec->QueryAverageAspectRatio();
944  uint avg_height = curRec->QueryAverageHeight();
945  bool progressive = curRec->QueryAverageScanProgressive();
946 
947  uint16_t flags {VID_UNKNOWN};
948  if (avg_height > 2000)
949  flags |= VID_4K;
950  else if (avg_height > 1000)
951  flags |= VID_1080;
952  else if (avg_height > 700)
953  flags |= VID_720;
954  if (progressive)
955  flags |= VID_PROGRESSIVE;
956  if (!is_good)
957  flags |= VID_DAMAGED;
958  if ((aspectRatio == MARK_ASPECT_16_9) ||
959  (aspectRatio == MARK_ASPECT_2_21_1))
960  flags |= VID_WIDESCREEN;
961 
962  curRec->SaveVideoProperties
963  (VID_4K | VID_1080 | VID_720 | VID_DAMAGED |
964  VID_WIDESCREEN | VID_PROGRESSIVE, flags);
965 
966  // Make sure really short recordings have positive run time.
967  if (curRec->GetRecordingEndTime() <= curRec->GetRecordingStartTime())
968  {
969  curRec->SetRecordingEndTime(
970  curRec->GetRecordingStartTime().addSecs(60));
971  }
972 
973  // HACK Temporary hack, ensure we've loaded the recording file info, do it now
974  // so that it contains the final filesize information
975  if (!curRec->GetRecordingFile())
976  curRec->LoadRecordingFile();
977 
978  // Generate a preview
979  uint64_t fsize = curRec->GetFilesize();
980  if (curRec->IsLocal() && (fsize >= 1000) &&
982  {
984  }
985 
986  // store recording in recorded table
987  curRec->FinishedRecording(!is_good || (recgrp == "LiveTV"));
988 
989  // send out UPDATE_RECORDING_STATUS message
990  if (recgrp != "LiveTV")
991  {
992  LOG(VB_RECORD, LOG_INFO, LOC +
993  QString("FinishedRecording -- UPDATE_RECORDING_STATUS: %1")
994  .arg(RecStatus::toString(is_good ? curRec->GetRecordingStatus()
996  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
997  .arg(curRec->GetInputID())
998  .arg(curRec->GetChanID())
1000  .arg(is_good ? curRec->GetRecordingStatus() : RecStatus::Failed)
1001  .arg(curRec->GetRecordingEndTime(MythDate::ISODate)));
1002  gCoreContext->dispatch(me);
1003  }
1004 
1005  // send out REC_FINISHED message
1006  SendMythSystemRecEvent("REC_FINISHED", curRec);
1007 
1008  // send out DONE_RECORDING message
1009  auto secsSince = MythDate::secsInPast(curRec->GetRecordingStartTime());
1010  QString message = QString("DONE_RECORDING %1 %2 %3")
1011  .arg(m_inputId).arg(secsSince.count()).arg(GetFramesWritten());
1012  MythEvent me(message);
1013  gCoreContext->dispatch(me);
1014 
1015  // Handle JobQueue
1016  QHash<QString,int>::iterator autoJob =
1017  m_autoRunJobs.find(curRec->MakeUniqueKey());
1018  if (autoJob == m_autoRunJobs.end())
1019  {
1020  LOG(VB_GENERAL, LOG_INFO,
1021  "autoRunJobs not initialized until FinishedRecording()");
1022  AutoRunInitType t =
1023  (recgrp == "LiveTV") ? kAutoRunNone : kAutoRunProfile;
1024  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
1025  autoJob = m_autoRunJobs.find(curRec->MakeUniqueKey());
1026  }
1027  LOG(VB_JOBQUEUE, LOG_INFO, QString("AutoRunJobs 0x%1").arg(*autoJob,0,16));
1028  if ((recgrp == "LiveTV") || (fsize < 1000) ||
1029  (curRec->GetRecordingStatus() != RecStatus::Recorded) ||
1030  (curRec->GetRecordingStartTime().secsTo(
1031  MythDate::current()) < 120))
1032  {
1035  }
1036  if (*autoJob != JOB_NONE)
1037  JobQueue::QueueRecordingJobs(*curRec, *autoJob);
1038  m_autoRunJobs.erase(autoJob);
1039 }
1040 
1041 // NOLINTBEGIN(cppcoreguidelines-macro-usage)
1042 #define TRANSITION(ASTATE,BSTATE) \
1043  ((m_internalState == (ASTATE)) && (m_desiredNextState == (BSTATE)))
1044 #define SET_NEXT() do { nextState = m_desiredNextState; changed = true; } while(false)
1045 #define SET_LAST() do { nextState = m_internalState; changed = true; } while(false)
1046 // NOLINTEND(cppcoreguidelines-macro-usage)
1047 
1056 {
1057  TVState nextState = m_internalState;
1058 
1059  bool changed = false;
1060 
1061  QString transMsg = QString(" %1 to %2")
1062  .arg(StateToString(nextState), StateToString(m_desiredNextState));
1063 
1065  {
1066  LOG(VB_GENERAL, LOG_ERR, LOC +
1067  "HandleStateChange(): Null transition" + transMsg);
1068  m_changeState = false;
1069  return;
1070  }
1071 
1072  // Stop EIT scanning on this input before any tuning,
1073  // to avoid race condition with it's tuning requests.
1075  {
1076  LOG(VB_EIT, LOG_INFO, LOC + QString("Stop EIT scan on input %1").arg(GetInputId()));
1077 
1079  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1081  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1082  }
1083 
1084  // Stop EIT scanning on all conflicting inputs so that
1085  // the tuner card is available for a new tuning request.
1086  // Conflicting inputs are inputs that have independent video sources
1087  // but that share a tuner card, such as a DVB-S/S2 tuner card that
1088  // connects to multiple satellites with a DiSEqC switch.
1089  if (m_scanner && !m_eitInputs.empty())
1090  {
1091  s_inputsLock.lockForRead();
1092  s_eitLock.lock();
1093  for (auto input : m_eitInputs)
1094  {
1095  auto *tv_rec = s_inputs.value(input);
1096  if (tv_rec && tv_rec->m_scanner && tv_rec->HasFlags(kFlagEITScannerRunning))
1097  {
1098  LOG(VB_EIT, LOG_INFO, LOC +
1099  QString("Stop EIT scan active on conflicting input %1")
1100  .arg(input));
1101  tv_rec->m_scanner->StopActiveScan();
1102  tv_rec->ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1103  tv_rec->TuningShutdowns(TuningRequest(kFlagNoRec));
1105  tv_rec->m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1106  }
1107  }
1108  s_eitLock.unlock();
1109  s_inputsLock.unlock();
1110  }
1111 
1112  // Handle different state transitions
1114  {
1116  SET_NEXT();
1117  }
1119  {
1121  SET_NEXT();
1122  }
1124  {
1125  SetPseudoLiveTVRecording(nullptr);
1126 
1127  SET_NEXT();
1128  }
1130  {
1131  SetPseudoLiveTVRecording(nullptr);
1133  SET_NEXT();
1134  }
1136  {
1139  (GetFlags()&kFlagKillRec)));
1140  SET_NEXT();
1141  }
1142 
1143  QString msg = (changed) ? "Changing from" : "Unknown state transition:";
1144  LOG(VB_GENERAL, LOG_INFO, LOC + msg + transMsg);
1145 
1146  // update internal state variable
1147  m_internalState = nextState;
1148  m_changeState = false;
1149 
1151  {
1153  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1154  }
1155  else
1156  {
1157  m_eitScanStartTime = MythDate::current().addYears(1);
1158  }
1159 }
1160 #undef TRANSITION
1161 #undef SET_NEXT
1162 #undef SET_LAST
1163 
1168 {
1169  QMutexLocker lock(&m_stateChangeLock);
1170  m_desiredNextState = nextState;
1171  m_changeState = true;
1172  WakeEventLoop();
1173 }
1174 
1189 void TVRec::TeardownRecorder(uint request_flags)
1190 {
1191  LOG(VB_RECORD, LOG_INFO, LOC + QString("TeardownRecorder(%1)")
1192  .arg((request_flags & kFlagKillRec) ? "kFlagKillRec" : ""));
1193 
1194  m_pauseNotify = false;
1195  m_isPip = false;
1196 
1198  {
1201  delete m_recorderThread;
1202  m_recorderThread = nullptr;
1203  }
1205  __FILE__, __LINE__);
1206 
1207  RecordingQuality *recq = nullptr;
1208  if (m_recorder)
1209  {
1210  if (GetV4LChannel())
1211  m_channel->SetFd(-1);
1212 
1214 
1215  QMutexLocker locker(&m_stateChangeLock);
1216  delete m_recorder;
1217  m_recorder = nullptr;
1218  }
1219 
1220  if (m_buffer)
1221  {
1222  LOG(VB_FILE, LOG_INFO, LOC + "calling StopReads()");
1223  m_buffer->StopReads();
1224  }
1225 
1226  if (m_curRecording)
1227  {
1228  if (!!(request_flags & kFlagKillRec))
1230 
1232 
1234  delete m_curRecording;
1235  m_curRecording = nullptr;
1236  }
1237 
1238  m_pauseNotify = true;
1239 
1240  if (GetDTVChannel())
1242 }
1243 
1245 {
1246  return dynamic_cast<DTVRecorder*>(m_recorder);
1247 }
1248 
1250 {
1251  if (m_channel &&
1252  ((m_genOpt.m_inputType == "DVB" && m_dvbOpt.m_dvbOnDemand) ||
1253  m_genOpt.m_inputType == "FREEBOX" ||
1254  m_genOpt.m_inputType == "VBOX" ||
1255  m_genOpt.m_inputType == "HDHOMERUN" ||
1256  m_genOpt.m_inputType == "EXTERNAL" ||
1258  {
1259  m_channel->Close();
1260  }
1261 }
1262 
1264 {
1265  return dynamic_cast<DTVChannel*>(m_channel);
1266 }
1267 
1269 {
1270 #ifdef USING_V4L2
1271  return dynamic_cast<V4LChannel*>(m_channel);
1272 #else
1273  return nullptr;
1274 #endif // USING_V4L2
1275 }
1276 
1277 // Check if EIT is enabled for the video source connected to this input
1278 static bool get_use_eit(uint inputid)
1279 {
1280  MSqlQuery query(MSqlQuery::InitCon());
1281  query.prepare(
1282  "SELECT SUM(useeit) "
1283  "FROM videosource, capturecard "
1284  "WHERE videosource.sourceid = capturecard.sourceid AND"
1285  " capturecard.cardid = :INPUTID");
1286  query.bindValue(":INPUTID", inputid);
1287 
1288  if (!query.exec() || !query.isActive())
1289  {
1290  MythDB::DBError("get_use_eit", query);
1291  return false;
1292  }
1293  if (query.next())
1294  return query.value(0).toBool();
1295  return false;
1296 }
1297 
1298 static bool is_dishnet_eit(uint inputid)
1299 {
1300  MSqlQuery query(MSqlQuery::InitCon());
1301  query.prepare(
1302  "SELECT SUM(dishnet_eit) "
1303  "FROM videosource, capturecard "
1304  "WHERE videosource.sourceid = capturecard.sourceid AND"
1305  " capturecard.cardid = :INPUTID");
1306  query.bindValue(":INPUTID", inputid);
1307 
1308  if (!query.exec() || !query.isActive())
1309  {
1310  MythDB::DBError("is_dishnet_eit", query);
1311  return false;
1312  }
1313  if (query.next())
1314  return query.value(0).toBool();
1315  return false;
1316 }
1317 
1318 // Highest capturecard instance number including multirec instances
1319 static int get_highest_input(void)
1320 {
1321  MSqlQuery query(MSqlQuery::InitCon());
1322  query.prepare(
1323  "SELECT MAX(cardid) "
1324  "FROM capturecard ");
1325 
1326  if (!query.exec() || !query.isActive())
1327  {
1328  MythDB::DBError("highest_input", query);
1329  return -1;
1330  }
1331  if (query.next())
1332  return query.value(0).toInt();
1333  return -1;
1334 }
1335 
1336 static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout)
1337 {
1338  // Randomize start time a bit
1339  auto timeout = std::chrono::seconds(MythRandom(0, eitTransportTimeout.count() / 3));
1340 
1341  // Use the highest input number and the current input number
1342  // to distribute the scan start evenly over eitTransportTimeout
1343  int highest_input = get_highest_input();
1344  if (highest_input > 0)
1345  timeout += eitTransportTimeout * inputId / highest_input;
1346 
1347  return timeout;
1348 }
1349 
1351 void TVRec::run(void)
1352 {
1353  QMutexLocker lock(&m_stateChangeLock);
1354  SetFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1355  ClearFlags(kFlagExitPlayer | kFlagFinishRecording, __FILE__, __LINE__);
1356 
1357  // Check whether we should use the EITScanner in this TVRec instance
1358  if (CardUtil::IsEITCapable(m_genOpt.m_inputType) && // Card type capable of receiving EIT?
1359  (!GetDTVChannel() || GetDTVChannel()->IsMaster()) && // Card is master and not a multirec instance
1360  (m_dvbOpt.m_dvbEitScan || get_use_eit(m_inputId))) // EIT is selected for card OR EIT is selected for video source
1361  {
1364  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1365  }
1366  else
1367  {
1368  m_eitScanStartTime = MythDate::current().addYears(10);
1369  }
1370 
1371  while (HasFlags(kFlagRunMainLoop))
1372  {
1373  // If there is a state change queued up, do it...
1374  if (m_changeState)
1375  {
1378  __FILE__, __LINE__);
1379  }
1380 
1381  // Quick exit on fatal errors.
1382  if (IsErrored())
1383  {
1384  LOG(VB_GENERAL, LOG_ERR, LOC +
1385  "RunTV encountered fatal error, exiting event thread.");
1386  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1387  TeardownAll();
1388  return;
1389  }
1390 
1391  // Handle any tuning events.. Blindly grabbing the lock here
1392  // can sometimes cause a deadlock with Init() while it waits
1393  // to make sure this thread starts. Until a better solution
1394  // is found, don't run HandleTuning unless we can safely get
1395  // the lock.
1396  if (s_inputsLock.tryLockForRead())
1397  {
1398  HandleTuning();
1399  s_inputsLock.unlock();
1400  }
1401 
1402  // Tell frontends about pending recordings
1404 
1405  // If we are recording a program, check if the recording is
1406  // over or someone has asked us to finish the recording.
1407  // Add an extra 60 seconds to the recording end time if we
1408  // might want a back to back recording.
1409  QDateTime recEnd = (!m_pendingRecordings.empty()) ?
1410  m_recordEndTime.addSecs(60) : m_recordEndTime;
1411  if ((GetState() == kState_RecordingOnly) &&
1412  (MythDate::current() > recEnd ||
1414  {
1416  ClearFlags(kFlagFinishRecording, __FILE__, __LINE__);
1417  }
1418 
1419  if (m_curRecording)
1420  {
1422 
1423  if (m_recorder)
1424  {
1426 
1427  // Check for recorder errors
1428  if (m_recorder->IsErrored())
1429  {
1431 
1433  {
1434  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
1435  MythEvent me(message);
1436  gCoreContext->dispatch(me);
1437  }
1438  else
1439  {
1441  }
1442  }
1443  }
1444  }
1445 
1446  // Check for the end of the current program..
1448  {
1449  QDateTime now = MythDate::current();
1450  bool has_finish = HasFlags(kFlagFinishRecording);
1451  bool has_rec = m_pseudoLiveTVRecording;
1452  bool enable_ui = true;
1453 
1454  m_pendingRecLock.lock();
1455  bool rec_soon =
1457  m_pendingRecLock.unlock();
1458 
1459  if (has_rec && (has_finish || (now > m_recordEndTime)))
1460  {
1461  SetPseudoLiveTVRecording(nullptr);
1462  }
1463  else if (!has_rec && !rec_soon && m_curRecording &&
1464  (now >= m_curRecording->GetScheduledEndTime()))
1465  {
1466  if (!m_switchingBuffer)
1467  {
1468  LOG(VB_RECORD, LOG_INFO, LOC +
1469  "Switching Buffer (" +
1470  QString("!has_rec(%1) && ").arg(has_rec) +
1471  QString("!rec_soon(%1) && (").arg(rec_soon) +
1472  MythDate::toString(now, MythDate::ISODate) + " >= " +
1474  QString("(%1) ))")
1475  .arg(now >= m_curRecording->GetScheduledEndTime()));
1476 
1477  m_switchingBuffer = true;
1478 
1480  false, true);
1481  }
1482  else
1483  {
1484  LOG(VB_RECORD, LOG_INFO, "Waiting for ringbuffer switch");
1485  }
1486  }
1487  else
1488  {
1489  enable_ui = false;
1490  }
1491 
1492  if (enable_ui)
1493  {
1494  LOG(VB_RECORD, LOG_INFO, LOC + "Enabling Full LiveTV UI.");
1495  QString message = QString("LIVETV_WATCH %1 0").arg(m_inputId);
1496  MythEvent me(message);
1497  gCoreContext->dispatch(me);
1498  }
1499  }
1500 
1501  // Check for ExitPlayer flag, and if set change to a non-watching
1502  // state (either kState_RecordingOnly or kState_None).
1504  {
1507  else if (StateIsPlaying(m_internalState))
1509  ClearFlags(kFlagExitPlayer, __FILE__, __LINE__);
1510  }
1511 
1512  // Start active EIT scan
1513  bool conflicting_input = false;
1514  if (m_scanner && m_channel &&
1516  {
1517  if (!m_dvbOpt.m_dvbEitScan)
1518  {
1519  LOG(VB_EIT, LOG_INFO, LOC +
1520  QString("EIT scanning disabled for input %1")
1521  .arg(GetInputId()));
1522  m_eitScanStartTime = MythDate::current().addYears(10);
1523  }
1524  else if (!get_use_eit(GetInputId()))
1525  {
1526  LOG(VB_EIT, LOG_INFO, LOC +
1527  QString("EIT scanning disabled for video source %1")
1528  .arg(GetSourceID()));
1529  m_eitScanStartTime = MythDate::current().addYears(10);
1530  }
1531  else
1532  {
1533  LOG(VB_EIT, LOG_INFO, LOC +
1534  QString("EIT scanning enabled for input %1 connected to video source %2 '%3'")
1536 
1537  // Check if another card in the same input group is busy recording.
1538  // This could be either a virtual DVB-device or a second tuner on a single card.
1539  s_inputsLock.lockForRead();
1540  s_eitLock.lock();
1541  bool allow_eit = true;
1542  std::vector<uint> inputids = CardUtil::GetConflictingInputs(m_inputId);
1543  InputInfo busy_input;
1544  for (uint i = 0; i < inputids.size() && allow_eit; ++i)
1545  allow_eit = !RemoteIsBusy(inputids[i], busy_input);
1546 
1547  // Check if another card in the same input group is busy with an EIT scan.
1548  // We cannot start an EIT scan on this input if there is already an EIT scan
1549  // running on a conflicting real input.
1550  // Note that EIT scans never run on virtual inputs.
1551  if (allow_eit)
1552  {
1553  for (auto input : inputids)
1554  {
1555  auto *tv_rec = s_inputs.value(input);
1556  if (tv_rec && tv_rec->m_scanner)
1557  {
1558  conflicting_input = true;
1559  if (tv_rec->HasFlags(kFlagEITScannerRunning))
1560  {
1561  LOG(VB_EIT, LOG_INFO, LOC +
1562  QString("EIT scan on conflicting input %1").arg(input));
1563  allow_eit = false;
1564  busy_input.m_inputId = tv_rec->m_inputId;
1565  break;
1566  }
1567  }
1568  }
1569  }
1570 
1571  if (allow_eit)
1572  {
1573  LOG(VB_EIT, LOG_INFO, LOC +
1574  QString("Start EIT active scan on input %1")
1575  .arg(m_inputId));
1577  SetFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1578  m_eitScanStartTime = MythDate::current().addYears(1);
1579  if (conflicting_input)
1581  else
1582  m_eitScanStopTime = MythDate::current().addYears(1);
1583  }
1584  else
1585  {
1586  const int seconds_postpone = 300;
1587  LOG(VB_EIT, LOG_INFO, LOC +
1588  QString("Postponing EIT scan on input %1 for %2 seconds because input %3 is busy")
1589  .arg(m_inputId).arg(seconds_postpone).arg(busy_input.m_inputId));
1590  m_eitScanStartTime = m_eitScanStartTime.addSecs(seconds_postpone);
1591  }
1592  s_eitLock.unlock();
1593  s_inputsLock.unlock();
1594  }
1595  }
1596 
1597 
1598  // Stop active EIT scan and allow start of the EIT scan on one of the conflicting real inputs.
1600  {
1601  LOG(VB_EIT, LOG_INFO, LOC +
1602  QString("Stop EIT scan on input %1 to allow scan on a conflicting input")
1603  .arg(GetInputId()));
1604 
1606  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1608 
1610  secs += m_eitScanPeriod;
1611  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1612  }
1613 
1614  // We should be no more than a few thousand milliseconds,
1615  // as the end recording code does not have a trigger...
1616  // NOTE: If you change anything here, make sure that
1617  // WaitforEventThreadSleep() will still work...
1618  if (m_tuningRequests.empty() && !m_changeState)
1619  {
1620  lock.unlock(); // stateChangeLock
1621 
1622  {
1623  QMutexLocker locker(&m_triggerEventSleepLock);
1625  m_triggerEventSleepWait.wakeAll();
1626  }
1627 
1628  sched_yield();
1629 
1630  {
1631  QMutexLocker locker(&m_triggerEventLoopLock);
1632  // We check triggerEventLoopSignal because it is possible
1633  // that WakeEventLoop() was called since we
1634  // unlocked the stateChangeLock
1636  {
1638  &m_triggerEventLoopLock, 1000 /* ms */);
1639  }
1640  m_triggerEventLoopSignal = false;
1641  }
1642 
1643  lock.relock(); // stateChangeLock
1644  }
1645  }
1646 
1647  if (GetState() != kState_None)
1648  {
1651  }
1652 
1653  TeardownAll();
1654 }
1655 
1661 bool TVRec::WaitForEventThreadSleep(bool wake, std::chrono::milliseconds time)
1662 {
1663  bool ok = false;
1664  MythTimer t;
1665  t.start();
1666 
1667  while (!ok && (t.elapsed() < time))
1668  {
1669  MythTimer t2;
1670  t2.start();
1671 
1672  if (wake)
1673  WakeEventLoop();
1674 
1675  m_stateChangeLock.unlock();
1676 
1677  sched_yield();
1678 
1679  {
1680  QMutexLocker locker(&m_triggerEventSleepLock);
1683  m_triggerEventSleepSignal = false;
1684  }
1685 
1686  m_stateChangeLock.lock();
1687 
1688  // verify that we were triggered.
1689  ok = (m_tuningRequests.empty() && !m_changeState);
1690 
1691  std::chrono::milliseconds te = t2.elapsed();
1692  if (!ok && te < 10ms)
1693  std::this_thread::sleep_for(10ms - te);
1694  }
1695  return ok;
1696 }
1697 
1699 {
1700  QMutexLocker pendlock(&m_pendingRecLock);
1701 
1702  for (auto it = m_pendingRecordings.begin(); it != m_pendingRecordings.end();)
1703  {
1704  if (MythDate::current() > (*it).m_recordingStart.addSecs(30))
1705  {
1706  LOG(VB_RECORD, LOG_INFO, LOC + "Deleting stale pending recording " +
1707  QString("[%1] '%2'")
1708  .arg((*it).m_info->GetInputID())
1709  .arg((*it).m_info->GetTitle()));
1710 
1711  delete (*it).m_info;
1712  it = m_pendingRecordings.erase(it);
1713  }
1714  else
1715  {
1716  it++;
1717  }
1718  }
1719 
1720  if (m_pendingRecordings.empty())
1721  return;
1722 
1723  // Make sure EIT scan is stopped so it does't interfere
1725  {
1726  LOG(VB_CHANNEL, LOG_INFO,
1727  LOC + "Stopping active EIT scan for pending recording.");
1729  }
1730 
1731  // If we have a pending recording and AskAllowRecording
1732  // or DoNotAskAllowRecording is set and the frontend is
1733  // ready send an ASK_RECORDING query to frontend.
1734 
1735  bool has_rec = false;
1736  auto it = m_pendingRecordings.begin();
1737  if ((1 == m_pendingRecordings.size()) &&
1738  (*it).m_ask &&
1739  ((*it).m_info->GetInputID() == m_inputId) &&
1741  {
1743  has_rec = m_pseudoLiveTVRecording &&
1745  (*it).m_recordingStart);
1746  }
1747 
1748  for (it = m_pendingRecordings.begin(); it != m_pendingRecordings.end(); ++it)
1749  {
1750  if (!(*it).m_ask && !(*it).m_doNotAsk)
1751  continue;
1752 
1753  auto timeuntil = ((*it).m_doNotAsk) ?
1754  -1s: MythDate::secsInFuture((*it).m_recordingStart);
1755 
1756  if (has_rec)
1757  (*it).m_canceled = true;
1758 
1759  QString query = QString("ASK_RECORDING %1 %2 %3 %4")
1760  .arg(m_inputId)
1761  .arg(timeuntil.count())
1762  .arg(has_rec ? 1 : 0)
1763  .arg((*it).m_hasLaterShowing ? 1 : 0);
1764 
1765  LOG(VB_GENERAL, LOG_INFO, LOC + query);
1766 
1767  QStringList msg;
1768  (*it).m_info->ToStringList(msg);
1769  MythEvent me(query, msg);
1770  gCoreContext->dispatch(me);
1771 
1772  (*it).m_ask = (*it).m_doNotAsk = false;
1773  }
1774 }
1775 
1777  uint &parentid,
1778  GeneralDBOptions &gen_opts,
1779  DVBDBOptions &dvb_opts,
1780  FireWireDBOptions &firewire_opts)
1781 {
1782  int testnum = 0;
1783  QString test;
1784 
1785  MSqlQuery query(MSqlQuery::InitCon());
1786  query.prepare(
1787  "SELECT videodevice, vbidevice, audiodevice, "
1788  " audioratelimit, cardtype, "
1789  " skipbtaudio, signal_timeout, channel_timeout, "
1790  " dvb_wait_for_seqstart, "
1791  ""
1792  " dvb_on_demand, dvb_tuning_delay, dvb_eitscan,"
1793  ""
1794  " firewire_speed, firewire_model, firewire_connection, "
1795  " parentid "
1796  ""
1797  "FROM capturecard "
1798  "WHERE cardid = :INPUTID");
1799  query.bindValue(":INPUTID", inputid);
1800 
1801  if (!query.exec() || !query.isActive())
1802  {
1803  MythDB::DBError("getdevices", query);
1804  return false;
1805  }
1806 
1807  if (!query.next())
1808  return false;
1809 
1810  // General options
1811  test = query.value(0).toString();
1812  if (!test.isEmpty())
1813  gen_opts.m_videoDev = test;
1814 
1815  test = query.value(1).toString();
1816  if (!test.isEmpty())
1817  gen_opts.m_vbiDev = test;
1818 
1819  test = query.value(2).toString();
1820  if (!test.isEmpty())
1821  gen_opts.m_audioDev = test;
1822 
1823  gen_opts.m_audioSampleRate = std::max(testnum, query.value(3).toInt());
1824 
1825  test = query.value(4).toString();
1826  if (!test.isEmpty())
1827  gen_opts.m_inputType = test;
1828 
1829  gen_opts.m_skipBtAudio = query.value(5).toBool();
1830 
1831  gen_opts.m_signalTimeout = (uint) std::max(query.value(6).toInt(), 0);
1832  gen_opts.m_channelTimeout = (uint) std::max(query.value(7).toInt(), 0);
1833 
1834  // We should have at least 1000 ms to acquire tables...
1835  int table_timeout = ((int)gen_opts.m_channelTimeout -
1836  (int)gen_opts.m_signalTimeout);
1837  if (table_timeout < 1000)
1838  gen_opts.m_channelTimeout = gen_opts.m_signalTimeout + 1000;
1839 
1840  gen_opts.m_waitForSeqstart = query.value(8).toBool();
1841 
1842  // DVB options
1843  uint dvboff = 9;
1844  dvb_opts.m_dvbOnDemand = query.value(dvboff + 0).toBool();
1845  dvb_opts.m_dvbTuningDelay = std::chrono::milliseconds(query.value(dvboff + 1).toUInt());
1846  dvb_opts.m_dvbEitScan = query.value(dvboff + 2).toBool();
1847 
1848  // Firewire options
1849  uint fireoff = dvboff + 3;
1850  firewire_opts.m_speed = query.value(fireoff + 0).toUInt();
1851 
1852  test = query.value(fireoff + 1).toString();
1853  if (!test.isEmpty())
1854  firewire_opts.m_model = test;
1855 
1856  firewire_opts.m_connection = query.value(fireoff + 2).toUInt();
1857 
1858  parentid = query.value(15).toUInt();
1859 
1860  return true;
1861 }
1862 
1863 static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
1864 {
1865  if (!dtvMon->GetATSCStreamData())
1866  return;
1867 
1868  const MasterGuideTable *mgt = dtvMon->GetATSCStreamData()->GetCachedMGT();
1869  if (!mgt)
1870  return;
1871 
1872  for (uint i = 0; i < mgt->TableCount(); ++i)
1873  {
1874  pid_cache_item_t item(mgt->TablePID(i), mgt->TableType(i));
1875  pid_cache.push_back(item);
1876  }
1877  dtvMon->GetATSCStreamData()->ReturnCachedTable(mgt);
1878 }
1879 
1880 static bool ApplyCachedPids(DTVSignalMonitor *dtvMon, const DTVChannel* channel)
1881 {
1882  pid_cache_t pid_cache;
1883  channel->GetCachedPids(pid_cache);
1884  bool vctpid_cached = false;
1885  for (const auto& pid : pid_cache)
1886  {
1887  if ((pid.GetTableID() == TableID::TVCT) ||
1888  (pid.GetTableID() == TableID::CVCT))
1889  {
1890  vctpid_cached = true;
1891  if (dtvMon->GetATSCStreamData())
1892  dtvMon->GetATSCStreamData()->AddListeningPID(pid.GetPID());
1893  }
1894  }
1895  return vctpid_cached;
1896 }
1897 
1914 {
1915  LOG(VB_RECORD, LOG_INFO, LOC + "Setting up table monitoring.");
1916 
1918  DTVChannel *dtvchan = GetDTVChannel();
1919  if (!sm || !dtvchan)
1920  {
1921  LOG(VB_GENERAL, LOG_ERR, LOC + "Setting up table monitoring.");
1922  return false;
1923  }
1924 
1925  MPEGStreamData *sd = nullptr;
1926  if (GetDTVRecorder())
1927  {
1928  sd = GetDTVRecorder()->GetStreamData();
1929  sd->SetCaching(true);
1930  }
1931 
1932  QString recording_type = "all";
1936  const StandardSetting *setting = profile.byName("recordingtype");
1937  if (setting)
1938  recording_type = setting->getValue();
1939 
1940  const QString tuningmode = dtvchan->GetTuningMode();
1941 
1942  // Check if this is an ATSC Channel
1943  int major = dtvchan->GetMajorChannel();
1944  int minor = dtvchan->GetMinorChannel();
1945  if ((minor > 0) && (tuningmode == "atsc"))
1946  {
1947  QString msg = QString("ATSC channel: %1_%2").arg(major).arg(minor);
1948  LOG(VB_RECORD, LOG_INFO, LOC + msg);
1949 
1950  auto *asd = dynamic_cast<ATSCStreamData*>(sd);
1951  if (!asd)
1952  {
1953  sd = asd = new ATSCStreamData(major, minor, m_inputId);
1954  sd->SetCaching(true);
1955  if (GetDTVRecorder())
1956  GetDTVRecorder()->SetStreamData(asd);
1957  }
1958 
1959  asd->Reset();
1960  sm->SetStreamData(sd);
1961  sm->SetChannel(major, minor);
1962  sd->SetRecordingType(recording_type);
1963 
1964  // Try to get pid of VCT from cache and
1965  // require MGT if we don't have VCT pid.
1966  if (!ApplyCachedPids(sm, dtvchan))
1968 
1969  LOG(VB_RECORD, LOG_INFO, LOC +
1970  "Successfully set up ATSC table monitoring.");
1971  return true;
1972  }
1973 
1974  // Check if this is an DVB channel
1975  int progNum = dtvchan->GetProgramNumber();
1976  if ((progNum >= 0) && (tuningmode == "dvb") && CardUtil::IsChannelReusable(m_genOpt.m_inputType))
1977  {
1978  int netid = dtvchan->GetOriginalNetworkID();
1979  int tsid = dtvchan->GetTransportID();
1980 
1981  auto *dsd = dynamic_cast<DVBStreamData*>(sd);
1982  if (!dsd)
1983  {
1984  sd = dsd = new DVBStreamData(netid, tsid, progNum, m_inputId);
1985  sd->SetCaching(true);
1986  if (GetDTVRecorder())
1987  GetDTVRecorder()->SetStreamData(dsd);
1988  }
1989 
1990  LOG(VB_RECORD, LOG_INFO, LOC +
1991  QString("DVB service_id %1 on net_id %2 tsid %3")
1992  .arg(progNum).arg(netid).arg(tsid));
1993 
1995 
1996  dsd->Reset();
1997  sm->SetStreamData(sd);
1998  sm->SetDVBService(netid, tsid, progNum);
1999  sd->SetRecordingType(recording_type);
2000 
2004  sm->SetRotorTarget(1.0F);
2005 
2006  if (EITscan)
2007  {
2009  sm->IgnoreEncrypted(true);
2010  }
2011 
2012  LOG(VB_RECORD, LOG_INFO, LOC +
2013  "Successfully set up DVB table monitoring.");
2014  return true;
2015  }
2016 
2017  // Check if this is an MPEG channel
2018  if (progNum >= 0)
2019  {
2020  if (!sd)
2021  {
2022  sd = new MPEGStreamData(progNum, m_inputId, true);
2023  sd->SetCaching(true);
2024  if (GetDTVRecorder())
2026  }
2027 
2028  QString msg = QString("MPEG program number: %1").arg(progNum);
2029  LOG(VB_RECORD, LOG_INFO, LOC + msg);
2030 
2032 
2033  sd->Reset();
2034  sm->SetStreamData(sd);
2035  sm->SetProgramNumber(progNum);
2036  sd->SetRecordingType(recording_type);
2037 
2041  sm->SetRotorTarget(1.0F);
2042 
2043  if (EITscan)
2044  {
2046  sm->IgnoreEncrypted(true);
2047  }
2048 
2049  LOG(VB_RECORD, LOG_INFO, LOC +
2050  "Successfully set up MPEG table monitoring.");
2051  return true;
2052  }
2053 
2054  // If this is not an ATSC, DVB or MPEG channel then check to make sure
2055  // that we have permanent pidcache entries.
2056  bool ok = false;
2057  if (GetDTVChannel())
2058  {
2059  pid_cache_t pid_cache;
2060  GetDTVChannel()->GetCachedPids(pid_cache);
2061  for (auto item = pid_cache.cbegin(); !ok && item != pid_cache.cend(); ++item)
2062  ok |= item->IsPermanent();
2063  }
2064 
2065  if (!ok)
2066  {
2067  QString msg = "No valid DTV info, ATSC maj(%1) min(%2), MPEG pn(%3)";
2068  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(major).arg(minor).arg(progNum));
2069  }
2070  else
2071  {
2072  LOG(VB_RECORD, LOG_INFO, LOC +
2073  "Successfully set up raw pid monitoring.");
2074  }
2075 
2076  return ok;
2077 }
2078 
2093 bool TVRec::SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
2094 {
2095  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetupSignalMonitor(%1, %2)")
2096  .arg(tablemon).arg(notify));
2097 
2098  // if it already exists, there no need to initialize it
2099  if (m_signalMonitor)
2100  return true;
2101 
2102  // if there is no channel object we can't monitor it
2103  if (!m_channel)
2104  return false;
2105 
2106  // nothing to monitor here either (DummyChannel)
2107  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
2108  return true;
2109 
2110  // make sure statics are initialized
2112 
2115  m_channel, false);
2116 
2117  if (m_signalMonitor)
2118  {
2119  LOG(VB_RECORD, LOG_INFO, LOC + "Signal monitor successfully created");
2120  // If this is a monitor for Digital TV, initialize table monitors
2121  if (GetDTVSignalMonitor() && tablemon &&
2122  !SetupDTVSignalMonitor(EITscan))
2123  {
2124  LOG(VB_GENERAL, LOG_ERR, LOC +
2125  "Failed to setup digital signal monitoring");
2126 
2127  return false;
2128  }
2129 
2132  kSignalMonitoringRate * 5 :
2135 
2136  // Start the monitoring thread
2138  }
2139 
2140  return true;
2141 }
2142 
2148 {
2149  if (!m_signalMonitor)
2150  return;
2151 
2152  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- begin");
2153 
2154  // If this is a DTV signal monitor, save any pids we know about.
2156  DTVChannel *dtvChan = GetDTVChannel();
2157  if (dtvMon && dtvChan)
2158  {
2159  pid_cache_t pid_cache;
2160  GetPidsToCache(dtvMon, pid_cache);
2161  if (!pid_cache.empty())
2162  dtvChan->SaveCachedPids(pid_cache);
2163  }
2164 
2165  if (m_signalMonitor)
2166  {
2167  delete m_signalMonitor;
2168  m_signalMonitor = nullptr;
2169  }
2170 
2171  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- end");
2172 }
2173 
2185 std::chrono::milliseconds TVRec::SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend)
2186 {
2187  QString msg = "SetSignalMonitoringRate(%1, %2)";
2188  LOG(VB_RECORD, LOG_INFO, LOC +
2189  msg.arg(rate.count()).arg(notifyFrontend) + "-- start");
2190 
2191  QMutexLocker lock(&m_stateChangeLock);
2192 
2194  {
2195  LOG(VB_GENERAL, LOG_ERR, LOC +
2196  "Signal Monitoring is notsupported by your hardware.");
2197  return 0ms;
2198  }
2199 
2201  {
2202  LOG(VB_GENERAL, LOG_ERR, LOC +
2203  "Signal can only be monitored in LiveTV Mode.");
2204  return 0ms;
2205  }
2206 
2207  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
2208 
2209  TuningRequest req = (rate > 0ms) ?
2212 
2214 
2215  // Wait for RingBuffer reset
2216  while (!HasFlags(kFlagRingBufferReady))
2218  LOG(VB_RECORD, LOG_INFO, LOC +
2219  msg.arg(rate.count()).arg(notifyFrontend) + " -- end");
2220  return 1ms;
2221 }
2222 
2224 {
2225  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
2226 }
2227 
2239 bool TVRec::ShouldSwitchToAnotherInput(const QString& chanid) const
2240 {
2241  QString msg("");
2242  MSqlQuery query(MSqlQuery::InitCon());
2243 
2244  if (!query.isConnected())
2245  return false;
2246 
2247  query.prepare("SELECT channel.channum, channel.callsign "
2248  "FROM channel "
2249  "WHERE channel.chanid = :CHANID");
2250  query.bindValue(":CHANID", chanid);
2251  if (!query.exec() || !query.next())
2252  {
2253  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2254  return false;
2255  }
2256 
2257  QString channelname = query.value(0).toString();
2258  QString callsign = query.value(1).toString();
2259 
2260  query.prepare(
2261  "SELECT channel.channum "
2262  "FROM channel, capturecard "
2263  "WHERE deleted IS NULL AND "
2264  " ( channel.chanid = :CHANID OR "
2265  " ( channel.channum = :CHANNUM AND "
2266  " channel.callsign = :CALLSIGN ) "
2267  " ) AND "
2268  " channel.sourceid = capturecard.sourceid AND "
2269  " capturecard.cardid = :INPUTID");
2270  query.bindValue(":CHANID", chanid);
2271  query.bindValue(":CHANNUM", channelname);
2272  query.bindValue(":CALLSIGN", callsign);
2273  query.bindValue(":INPUTID", m_inputId);
2274 
2275  if (!query.exec() || !query.isActive())
2276  {
2277  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2278  }
2279  else if (query.size() > 0)
2280  {
2281  msg = "Found channel (%1) on current input[%2].";
2282  LOG(VB_RECORD, LOG_INFO, LOC + msg.arg(channelname).arg(m_inputId));
2283  return false;
2284  }
2285 
2286  // We didn't find it on the current input, so now we check other inputs.
2287  query.prepare(
2288  "SELECT channel.channum, capturecard.cardid "
2289  "FROM channel, capturecard "
2290  "WHERE deleted IS NULL AND "
2291  " ( channel.chanid = :CHANID OR "
2292  " ( channel.channum = :CHANNUM AND "
2293  " channel.callsign = :CALLSIGN ) "
2294  " ) AND "
2295  " channel.sourceid = capturecard.sourceid AND "
2296  " capturecard.cardid != :INPUTID");
2297  query.bindValue(":CHANID", chanid);
2298  query.bindValue(":CHANNUM", channelname);
2299  query.bindValue(":CALLSIGN", callsign);
2300  query.bindValue(":INPUTID", m_inputId);
2301 
2302  if (!query.exec() || !query.isActive())
2303  {
2304  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2305  }
2306  else if (query.next())
2307  {
2308  msg = QString("Found channel (%1) on different input(%2).")
2309  .arg(query.value(0).toString(), query.value(1).toString());
2310  LOG(VB_RECORD, LOG_INFO, LOC + msg);
2311  return true;
2312  }
2313 
2314  msg = QString("Did not find channel(%1) on any input.").arg(channelname);
2315  LOG(VB_RECORD, LOG_ERR, LOC + msg);
2316  return false;
2317 }
2318 
2329 bool TVRec::CheckChannel(const QString& name) const
2330 {
2331  if (!m_channel)
2332  return false;
2333 
2334  return m_channel->CheckChannel(name);
2335 }
2336 
2340 static QString add_spacer(const QString &channel, const QString &spacer)
2341 {
2342  QString chan = channel;
2343  if ((chan.length() >= 2) && !spacer.isEmpty())
2344  return chan.left(chan.length()-1) + spacer + chan.right(1);
2345  return chan;
2346 }
2347 
2375 bool TVRec::CheckChannelPrefix(const QString &prefix,
2376  uint &complete_valid_channel_on_rec,
2377  bool &is_extra_char_useful,
2378  QString &needed_spacer) const
2379 {
2380 #if DEBUG_CHANNEL_PREFIX
2381  LOG(VB_GENERAL, LOG_DEBUG, QString("CheckChannelPrefix(%1)").arg(prefix));
2382 #endif
2383 
2384  static const std::array<const QString,5> s_spacers = { "", "_", "-", "#", "." };
2385 
2386  MSqlQuery query(MSqlQuery::InitCon());
2387  QString basequery = QString(
2388  "SELECT channel.chanid, channel.channum, capturecard.cardid "
2389  "FROM channel, capturecard "
2390  "WHERE deleted IS NULL AND "
2391  " channel.channum LIKE '%1%' AND "
2392  " channel.sourceid = capturecard.sourceid");
2393 
2394  const std::array<const QString,2> inputquery
2395  {
2396  QString(" AND capturecard.cardid = '%1'").arg(m_inputId),
2397  QString(" AND capturecard.cardid != '%1'").arg(m_inputId),
2398  };
2399 
2400  std::vector<unsigned int> fchanid;
2401  std::vector<QString> fchannum;
2402  std::vector<unsigned int> finputid;
2403  std::vector<QString> fspacer;
2404 
2405  for (const auto & str : inputquery)
2406  {
2407  for (const auto & spacer : s_spacers)
2408  {
2409  QString qprefix = add_spacer(
2410  prefix, (spacer == "_") ? "\\_" : spacer);
2411  query.prepare(basequery.arg(qprefix) + str);
2412 
2413  if (!query.exec() || !query.isActive())
2414  {
2415  MythDB::DBError("checkchannel -- locate channum", query);
2416  }
2417  else if (query.size())
2418  {
2419  while (query.next())
2420  {
2421  fchanid.push_back(query.value(0).toUInt());
2422  fchannum.push_back(query.value(1).toString());
2423  finputid.push_back(query.value(2).toUInt());
2424  fspacer.emplace_back(spacer);
2425 #if DEBUG_CHANNEL_PREFIX
2426  LOG(VB_GENERAL, LOG_DEBUG,
2427  QString("(%1,%2) Adding %3 rec %4")
2428  .arg(i).arg(j).arg(query.value(1).toString(),6)
2429  .arg(query.value(2).toUInt()));
2430 #endif
2431  }
2432  }
2433 
2434  if (prefix.length() < 2)
2435  break;
2436  }
2437  }
2438 
2439  // Now process the lists for the info we need...
2440  is_extra_char_useful = false;
2441  complete_valid_channel_on_rec = 0;
2442  needed_spacer.clear();
2443 
2444  if (fchanid.empty())
2445  return false;
2446 
2447  if (fchanid.size() == 1) // Unique channel...
2448  {
2449  needed_spacer = fspacer[0];
2450  bool nc = (fchannum[0] != add_spacer(prefix, fspacer[0]));
2451 
2452  complete_valid_channel_on_rec = (nc) ? 0 : finputid[0];
2453  is_extra_char_useful = nc;
2454  return true;
2455  }
2456 
2457  // If we get this far there is more than one channel
2458  // sharing the prefix we were given.
2459 
2460  // Is an extra characher useful for disambiguation?
2461  is_extra_char_useful = false;
2462  for (uint i = 0; (i < fchannum.size()) && !is_extra_char_useful; i++)
2463  {
2464  is_extra_char_useful = (fchannum[i] != add_spacer(prefix, fspacer[i]));
2465 #if DEBUG_CHANNEL_PREFIX
2466  LOG(VB_GENERAL, LOG_DEBUG, QString("is_extra_char_useful(%1!=%2): %3")
2467  .arg(fchannum[i]).arg(add_spacer(prefix, fspacer[i]))
2468  .arg(is_extra_char_useful));
2469 #endif
2470  }
2471 
2472  // Are any of the channels complete w/o spacer?
2473  // If so set complete_valid_channel_on_rec,
2474  // with a preference for our inputid.
2475  for (size_t i = 0; i < fchannum.size(); i++)
2476  {
2477  if (fchannum[i] == prefix)
2478  {
2479  complete_valid_channel_on_rec = finputid[i];
2480  if (finputid[i] == m_inputId)
2481  break;
2482  }
2483  }
2484 
2485  if (complete_valid_channel_on_rec != 0)
2486  return true;
2487 
2488  // Add a spacer, if one is needed to select a valid channel.
2489  bool spacer_needed = true;
2490  for (uint i = 0; (i < fspacer.size() && spacer_needed); i++)
2491  spacer_needed = !fspacer[i].isEmpty();
2492  if (spacer_needed)
2493  needed_spacer = fspacer[0];
2494 
2495  // If it isn't useful to wait for more characters,
2496  // then try to commit to any true match immediately.
2497  for (size_t i = 0; i < ((is_extra_char_useful) ? 0 : fchanid.size()); i++)
2498  {
2499  if (fchannum[i] == add_spacer(prefix, fspacer[i]))
2500  {
2501  needed_spacer = fspacer[i];
2502  complete_valid_channel_on_rec = finputid[i];
2503  return true;
2504  }
2505  }
2506 
2507  return true;
2508 }
2509 
2511  const QString &channum)
2512 {
2513  if (!m_recorder)
2514  return false;
2515 
2516  QString videoFilters = ChannelUtil::GetVideoFilters(sourceid, channum);
2517  if (!videoFilters.isEmpty())
2518  {
2519  m_recorder->SetVideoFilters(videoFilters);
2520  return true;
2521  }
2522 
2523  return false;
2524 }
2525 
2531 {
2532  return ((m_recorder && m_recorder->IsRecording()) ||
2534 }
2535 
2541 bool TVRec::IsBusy(InputInfo *busy_input, std::chrono::seconds time_buffer) const
2542 {
2543  InputInfo dummy;
2544  if (!busy_input)
2545  busy_input = &dummy;
2546 
2547  busy_input->Clear();
2548 
2549  if (!m_channel)
2550  return false;
2551 
2552  if (!m_channel->GetInputID())
2553  return false;
2554 
2555  uint chanid = 0;
2556 
2557  if (GetState() != kState_None)
2558  {
2559  busy_input->m_inputId = m_channel->GetInputID();
2560  chanid = m_channel->GetChanID();
2561  }
2562 
2563  PendingInfo pendinfo;
2564  bool has_pending = false;
2565  {
2566  m_pendingRecLock.lock();
2567  PendingMap::const_iterator it = m_pendingRecordings.find(m_inputId);
2568  has_pending = (it != m_pendingRecordings.end());
2569  if (has_pending)
2570  pendinfo = *it;
2571  m_pendingRecLock.unlock();
2572  }
2573 
2574  if (!busy_input->m_inputId && has_pending)
2575  {
2576  auto timeLeft = MythDate::secsInFuture(pendinfo.m_recordingStart);
2577 
2578  if (timeLeft <= time_buffer)
2579  {
2580  QString channum;
2581  QString input;
2582  if (pendinfo.m_info->QueryTuningInfo(channum, input))
2583  {
2584  busy_input->m_inputId = m_channel->GetInputID();
2585  chanid = pendinfo.m_info->GetChanID();
2586  }
2587  }
2588  }
2589 
2590  if (busy_input->m_inputId)
2591  {
2592  CardUtil::GetInputInfo(*busy_input);
2593  busy_input->m_chanId = chanid;
2594  busy_input->m_mplexId = ChannelUtil::GetMplexID(busy_input->m_chanId);
2595  busy_input->m_mplexId =
2596  (32767 == busy_input->m_mplexId) ? 0 : busy_input->m_mplexId;
2597  }
2598 
2599  return busy_input->m_inputId != 0U;
2600 }
2601 
2602 
2610 {
2611  QMutexLocker lock(&m_stateChangeLock);
2612 
2613  if (m_recorder)
2614  return m_recorder->GetFrameRate();
2615  return -1.0F;
2616 }
2617 
2625 {
2626  QMutexLocker lock(&m_stateChangeLock);
2627 
2628  if (m_recorder)
2629  return m_recorder->GetFramesWritten();
2630  return -1;
2631 }
2632 
2639 long long TVRec::GetFilePosition(void)
2640 {
2641  QMutexLocker lock(&m_stateChangeLock);
2642 
2643  if (m_buffer)
2644  return m_buffer->GetWritePosition();
2645  return -1;
2646 }
2647 
2655 int64_t TVRec::GetKeyframePosition(uint64_t desired) const
2656 {
2657  QMutexLocker lock(&m_stateChangeLock);
2658 
2659  if (m_recorder)
2660  return m_recorder->GetKeyframePosition(desired);
2661  return -1;
2662 }
2663 
2673  int64_t start, int64_t end, frm_pos_map_t &map) const
2674 {
2675  QMutexLocker lock(&m_stateChangeLock);
2676 
2677  if (m_recorder)
2678  return m_recorder->GetKeyframePositions(start, end, map);
2679 
2680  return false;
2681 }
2682 
2684  int64_t start, int64_t end, frm_pos_map_t &map) const
2685 {
2686  QMutexLocker lock(&m_stateChangeLock);
2687 
2688  if (m_recorder)
2689  return m_recorder->GetKeyframeDurations(start, end, map);
2690 
2691  return false;
2692 }
2693 
2699 long long TVRec::GetMaxBitrate(void) const
2700 {
2701  long long bitrate = 0;
2702  if (m_genOpt.m_inputType == "MPEG")
2703  { // NOLINT(bugprone-branch-clone)
2704  bitrate = 10080000LL; // use DVD max bit rate
2705  }
2706  else if (m_genOpt.m_inputType == "HDPVR")
2707  {
2708  bitrate = 20200000LL; // Peak bit rate for HD-PVR
2709  }
2711  {
2712  bitrate = 22200000LL; // 1080i
2713  }
2714  else // frame grabber
2715  {
2716  bitrate = 10080000LL; // use DVD max bit rate, probably too big
2717  }
2718 
2719  return bitrate;
2720 }
2721 
2727 void TVRec::SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
2728 {
2729  QMutexLocker lock(&m_stateChangeLock);
2730 
2731  m_tvChain = newchain;
2732  m_tvChain->IncrRef(); // mark it for TVRec use
2733  m_tvChain->ReloadAll();
2734 
2735  QString hostprefix = MythCoreContext::GenMythURL(
2738 
2739  m_tvChain->SetHostPrefix(hostprefix);
2741 
2742  m_isPip = pip;
2743  m_liveTVStartChannel = std::move(startchan);
2744 
2745  // Change to WatchingLiveTV
2747  // Wait for state change to take effect
2749 
2750  // Make sure StartRecording can't steal our tuner
2751  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2752 }
2753 
2757 QString TVRec::GetChainID(void)
2758 {
2759  if (m_tvChain)
2760  return m_tvChain->GetID();
2761  return "";
2762 }
2763 
2773 {
2774  QMutexLocker lock(&m_stateChangeLock);
2775 
2777  return; // already stopped
2778 
2779  if (!m_curRecording)
2780  return;
2781 
2782  const QString recgrp = m_curRecording->QueryRecordingGroup();
2784 
2785  if (recgrp != "LiveTV" && !m_pseudoLiveTVRecording)
2786  {
2787  // User wants this recording to continue
2789  }
2790  else if (recgrp == "LiveTV" && m_pseudoLiveTVRecording)
2791  {
2792  // User wants to abandon scheduled recording
2793  SetPseudoLiveTVRecording(nullptr);
2794  }
2795 }
2796 
2807 {
2808  if (!m_channel)
2809  return;
2810 
2811  // Notify scheduler of the recording.
2812  // + set up recording so it can be resumed
2813  rec->SetInputID(m_inputId);
2815 
2816  if (rec->GetRecordingRuleType() == kNotRecording)
2817  {
2820  }
2821 
2822  // + remove any end offset which would mismatch the live session
2823  rec->GetRecordingRule()->m_endOffset = 0;
2824 
2825  // + save RecStatus::Inactive recstatus to so that a reschedule call
2826  // doesn't start recording this on another input before we
2827  // send the SCHEDULER_ADD_RECORDING message to the scheduler.
2829  rec->AddHistory(false);
2830 
2831  // + save RecordingRule so that we get a recordid
2832  // (don't allow RescheduleMatch(), avoiding unneeded reschedule)
2833  rec->GetRecordingRule()->Save(false);
2834 
2835  // + save recordid to recorded entry
2836  rec->ApplyRecordRecID();
2837 
2838  // + set proper recstatus (saved later)
2840 
2841  // + pass proginfo to scheduler and reschedule
2842  QStringList prog;
2843  rec->ToStringList(prog);
2844  MythEvent me("SCHEDULER_ADD_RECORDING", prog);
2845  gCoreContext->dispatch(me);
2846 
2847  // Allow scheduler to end this recording before post-roll,
2848  // if it has another recording for this recorder.
2849  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2850 }
2851 
2853  RecordingProfile *recpro, int line)
2854 {
2855  if (kAutoRunProfile == t)
2856  {
2858  if (!recpro)
2859  {
2860  LoadProfile(nullptr, rec, profile);
2861  recpro = &profile;
2862  }
2863  m_autoRunJobs[rec->MakeUniqueKey()] =
2864  init_jobs(rec, *recpro, m_runJobOnHostOnly,
2866  }
2867  else
2868  {
2870  }
2871  LOG(VB_JOBQUEUE, LOG_INFO,
2872  QString("InitAutoRunJobs for %1, line %2 -> 0x%3")
2873  .arg(rec->MakeUniqueKey()).arg(line)
2874  .arg(m_autoRunJobs[rec->MakeUniqueKey()],0,16));
2875 }
2876 
2888 void TVRec::SetLiveRecording([[maybe_unused]] int recording)
2889 {
2890  LOG(VB_GENERAL, LOG_INFO, LOC +
2891  QString("SetLiveRecording(%1)").arg(recording));
2892  QMutexLocker locker(&m_stateChangeLock);
2893 
2895  bool was_rec = m_pseudoLiveTVRecording;
2897  if (was_rec && !m_pseudoLiveTVRecording)
2898  {
2899  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- cancel");
2900  // cancel -- 'recording' should be 0 or -1
2901  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2902  m_curRecording->SetRecordingGroup("LiveTV");
2903  InitAutoRunJobs(m_curRecording, kAutoRunNone, nullptr, __LINE__);
2904  }
2905  else if (!was_rec && m_pseudoLiveTVRecording)
2906  {
2907  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- record");
2908  // record -- 'recording' should be 1 or -1
2909 
2910  // If the last recording was flagged for keeping
2911  // in the frontend, then add the recording rule
2912  // so that transcode, commfrag, etc can be run.
2915  recstat = m_curRecording->GetRecordingStatus();
2916  m_curRecording->SetRecordingGroup("Default");
2917  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
2918  }
2919 
2920  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
2921  .arg(m_curRecording->GetInputID())
2922  .arg(m_curRecording->GetChanID())
2924  .arg(recstat)
2926 
2927  gCoreContext->dispatch(me);
2928 }
2929 
2935 {
2936  QMutexLocker lock(&m_stateChangeLock);
2937  LOG(VB_RECORD, LOG_INFO, LOC +
2938  QString("StopLiveTV(void) curRec: 0x%1 pseudoRec: 0x%2")
2939  .arg((uint64_t)m_curRecording,0,16)
2940  .arg((uint64_t)m_pseudoLiveTVRecording,0,16));
2941 
2943  return;
2944 
2945  bool hadPseudoLiveTVRec = m_pseudoLiveTVRecording;
2947 
2948  if (!hadPseudoLiveTVRec && m_pseudoLiveTVRecording)
2950 
2951  // Figure out next state and if needed recording end time.
2952  TVState next_state = kState_None;
2954  {
2956  next_state = kState_RecordingOnly;
2957  }
2958 
2959  // Change to the appropriate state
2960  ChangeState(next_state);
2961 
2962  // Wait for state change to take effect...
2964 
2965  // We are done with the tvchain...
2966  if (m_tvChain)
2967  {
2968  m_tvChain->DecrRef();
2969  }
2970  m_tvChain = nullptr;
2971 }
2972 
2982 {
2983  QMutexLocker lock(&m_stateChangeLock);
2984 
2985  if (!m_recorder)
2986  {
2987  LOG(VB_GENERAL, LOG_ERR, LOC +
2988  "PauseRecorder() called with no recorder");
2989  return;
2990  }
2991 
2992  m_recorder->Pause();
2993 }
2994 
3001 {
3002  if (m_pauseNotify)
3003  WakeEventLoop();
3004 }
3005 
3009 void TVRec::ToggleChannelFavorite(const QString& changroupname)
3010 {
3011  QMutexLocker lock(&m_stateChangeLock);
3012 
3013  if (!m_channel)
3014  return;
3015 
3016  // Get current channel id...
3017  uint sourceid = m_channel->GetSourceID();
3018  QString channum = m_channel->GetChannelName();
3019  uint chanid = ChannelUtil::GetChanID(sourceid, channum);
3020 
3021  if (!chanid)
3022  {
3023  LOG(VB_GENERAL, LOG_ERR, LOC +
3024  QString("Channel: \'%1\' was not found in the database.\n"
3025  "\t\tMost likely, the 'starting channel' for this "
3026  "Input Connection is invalid.\n"
3027  "\t\tCould not toggle favorite.").arg(channum));
3028  return;
3029  }
3030 
3031  int changrpid = ChannelGroup::GetChannelGroupId(changroupname);
3032  if (changrpid <1)
3033  {
3034  LOG(VB_RECORD, LOG_ERR, LOC +
3035  QString("ToggleChannelFavorite: Invalid channel group name %1,")
3036  .arg(changroupname));
3037  }
3038  else
3039  {
3040  bool result = ChannelGroup::ToggleChannel(chanid, changrpid, true);
3041 
3042  if (!result)
3043  LOG(VB_RECORD, LOG_ERR, LOC + "Unable to toggle channel favorite.");
3044  else
3045  {
3046  LOG(VB_RECORD, LOG_INFO, LOC +
3047  QString("Toggled channel favorite.channum %1, chan group %2")
3048  .arg(channum, changroupname));
3049  }
3050  }
3051 }
3052 
3059 {
3060  QMutexLocker lock(&m_stateChangeLock);
3061  if (!m_channel)
3062  return -1;
3063 
3064  int ret = m_channel->GetPictureAttribute(attr);
3065 
3066  return (ret < 0) ? -1 : ret / 655;
3067 }
3068 
3077  PictureAttribute attr,
3078  bool direction)
3079 {
3080  QMutexLocker lock(&m_stateChangeLock);
3081  if (!m_channel)
3082  return -1;
3083 
3084  int ret = m_channel->ChangePictureAttribute(type, attr, direction);
3085 
3086  return (ret < 0) ? -1 : ret / 655;
3087 }
3088 
3092 QString TVRec::GetInput(void) const
3093 {
3094  if (m_channel)
3095  return m_channel->GetInputName();
3096  return {};
3097 }
3098 
3103 {
3104  if (m_channel)
3105  return m_channel->GetSourceID();
3106  return 0;
3107 }
3108 
3117 QString TVRec::SetInput(QString input)
3118 {
3119  QMutexLocker lock(&m_stateChangeLock);
3120  QString origIn = input;
3121  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + input + ") -- begin");
3122 
3123  if (!m_channel)
3124  {
3125  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput() -- end no channel class");
3126  return {};
3127  }
3128 
3129  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + origIn + ":" + input +
3130  ") -- end nothing to do");
3131  return input;
3132 }
3133 
3143 void TVRec::SetChannel(const QString& name, uint requestType)
3144 {
3145  QMutexLocker locker1(&m_setChannelLock);
3146  QMutexLocker locker2(&m_stateChangeLock);
3147 
3148  LOG(VB_CHANNEL, LOG_INFO, LOC +
3149  QString("SetChannel(%1) -- begin").arg(name));
3150 
3151  // Detect tuning request type if needed
3152  if (requestType & kFlagDetect)
3153  {
3155  requestType = m_lastTuningRequest.m_flags & (kFlagRec | kFlagNoRec);
3156  }
3157 
3158  // Clear the RingBuffer reset flag, in case we wait for a reset below
3159  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3160 
3161  // Clear out any EITScan channel change requests
3162  auto it = m_tuningRequests.begin();
3163  while (it != m_tuningRequests.end())
3164  {
3165  if ((*it).m_flags & kFlagEITScan)
3166  it = m_tuningRequests.erase(it);
3167  else
3168  ++it;
3169  }
3170 
3171  // Actually add the tuning request to the queue, and
3172  // then wait for it to start tuning
3173  m_tuningRequests.enqueue(TuningRequest(requestType, name));
3175 
3176  // If we are using a recorder, wait for a RingBuffer reset
3177  if (requestType & kFlagRec)
3178  {
3179  while (!HasFlags(kFlagRingBufferReady))
3181  }
3182  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetChannel(%1) -- end").arg(name));
3183 }
3184 
3192 bool TVRec::QueueEITChannelChange(const QString &name)
3193 {
3194  LOG(VB_CHANNEL, LOG_INFO, LOC +
3195  QString("QueueEITChannelChange(%1)").arg(name));
3196 
3197  bool ok = false;
3198  if (m_setChannelLock.tryLock())
3199  {
3200  if (m_stateChangeLock.tryLock())
3201  {
3202  if (m_tuningRequests.empty())
3203  {
3205  ok = true;
3206  }
3207  m_stateChangeLock.unlock();
3208  }
3209  m_setChannelLock.unlock();
3210  }
3211 
3212  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
3213  QString("QueueEITChannelChange(%1) %2")
3214  .arg(name, ok ? "done" : "failed"));
3215 
3216  return ok;
3217 }
3218 
3220  QString &title, QString &subtitle,
3221  QString &desc, QString &category,
3222  QString &starttime, QString &endtime,
3223  QString &callsign, QString &iconpath,
3224  QString &channum, uint &sourceChanid,
3225  QString &seriesid, QString &programid)
3226 {
3227  QString compare = "<=";
3228  QString sortorder = "desc";
3229  uint chanid = 0;
3230 
3231  if (sourceChanid)
3232  {
3233  chanid = sourceChanid;
3234 
3235  if (BROWSE_UP == direction)
3236  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_UP);
3237  else if (BROWSE_DOWN == direction)
3238  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_DOWN);
3239  else if (BROWSE_FAVORITE == direction)
3240  {
3241  chanid = m_channel->GetNextChannel(
3242  chanid, CHANNEL_DIRECTION_FAVORITE);
3243  }
3244  else if (BROWSE_LEFT == direction)
3245  {
3246  compare = "<";
3247  }
3248  else if (BROWSE_RIGHT == direction)
3249  {
3250  compare = ">";
3251  sortorder = "asc";
3252  }
3253  }
3254 
3255  if (!chanid)
3256  {
3257  if (BROWSE_SAME == direction)
3258  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3259  else if (BROWSE_UP == direction)
3260  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_UP);
3261  else if (BROWSE_DOWN == direction)
3262  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_DOWN);
3263  else if (BROWSE_FAVORITE == direction)
3264  {
3265  chanid = m_channel->GetNextChannel(channum,
3267  }
3268  else if (BROWSE_LEFT == direction)
3269  {
3270  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3271  compare = "<";
3272  }
3273  else if (BROWSE_RIGHT == direction)
3274  {
3275  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3276  compare = ">";
3277  sortorder = "asc";
3278  }
3279  }
3280 
3281  QString querystr = QString(
3282  "SELECT title, subtitle, description, category, "
3283  " starttime, endtime, callsign, icon, "
3284  " channum, seriesid, programid "
3285  "FROM program, channel "
3286  "WHERE program.chanid = channel.chanid AND "
3287  " channel.chanid = :CHANID AND "
3288  " starttime %1 :STARTTIME "
3289  "ORDER BY starttime %2 "
3290  "LIMIT 1").arg(compare, sortorder);
3291 
3292  MSqlQuery query(MSqlQuery::InitCon());
3293  query.prepare(querystr);
3294  query.bindValue(":CHANID", chanid);
3295  query.bindValue(":STARTTIME", starttime);
3296 
3297  // Clear everything now in case either query fails.
3298  title = subtitle = desc = category = "";
3299  starttime = endtime = callsign = iconpath = "";
3300  channum = seriesid = programid = "";
3301  sourceChanid = 0;
3302 
3303  // Try to get the program info
3304  if (!query.exec() && !query.isActive())
3305  {
3306  MythDB::DBError("GetNextProgram -- get program info", query);
3307  }
3308  else if (query.next())
3309  {
3310  title = query.value(0).toString();
3311  subtitle = query.value(1).toString();
3312  desc = query.value(2).toString();
3313  category = query.value(3).toString();
3314  starttime = query.value(4).toString();
3315  endtime = query.value(5).toString();
3316  callsign = query.value(6).toString();
3317  iconpath = query.value(7).toString();
3318  channum = query.value(8).toString();
3319  seriesid = query.value(9).toString();
3320  programid = query.value(10).toString();
3321  sourceChanid = chanid;
3322  return;
3323  }
3324 
3325  // Couldn't get program info, so get the channel info instead
3326  query.prepare(
3327  "SELECT channum, callsign, icon "
3328  "FROM channel "
3329  "WHERE chanid = :CHANID");
3330  query.bindValue(":CHANID", chanid);
3331 
3332  if (!query.exec() || !query.isActive())
3333  {
3334  MythDB::DBError("GetNextProgram -- get channel info", query);
3335  }
3336  else if (query.next())
3337  {
3338  sourceChanid = chanid;
3339  channum = query.value(0).toString();
3340  callsign = query.value(1).toString();
3341  iconpath = query.value(2).toString();
3342  }
3343 }
3344 
3345 bool TVRec::GetChannelInfo(uint &chanid, uint &sourceid,
3346  QString &callsign, QString &channum,
3347  QString &channame, QString &xmltvid) const
3348 {
3349  callsign.clear();
3350  channum.clear();
3351  channame.clear();
3352  xmltvid.clear();
3353 
3354  if ((!chanid || !sourceid) && !m_channel)
3355  return false;
3356 
3357  if (!chanid)
3358  chanid = (uint) std::max(m_channel->GetChanID(), 0);
3359 
3360  if (!sourceid)
3361  sourceid = m_channel->GetSourceID();
3362 
3363  MSqlQuery query(MSqlQuery::InitCon());
3364  query.prepare(
3365  "SELECT callsign, channum, name, xmltvid "
3366  "FROM channel "
3367  "WHERE chanid = :CHANID");
3368  query.bindValue(":CHANID", chanid);
3369  if (!query.exec() || !query.isActive())
3370  {
3371  MythDB::DBError("GetChannelInfo", query);
3372  return false;
3373  }
3374 
3375  if (!query.next())
3376  return false;
3377 
3378  callsign = query.value(0).toString();
3379  channum = query.value(1).toString();
3380  channame = query.value(2).toString();
3381  xmltvid = query.value(3).toString();
3382 
3383  return true;
3384 }
3385 
3386 bool TVRec::SetChannelInfo(uint chanid, uint sourceid,
3387  const QString& oldchannum,
3388  const QString& callsign, const QString& channum,
3389  const QString& channame, const QString& xmltvid)
3390 {
3391  if (!chanid || !sourceid || channum.isEmpty())
3392  return false;
3393 
3394  MSqlQuery query(MSqlQuery::InitCon());
3395  query.prepare(
3396  "UPDATE channel "
3397  "SET callsign = :CALLSIGN, "
3398  " channum = :CHANNUM, "
3399  " name = :CHANNAME, "
3400  " xmltvid = :XMLTVID "
3401  "WHERE chanid = :CHANID AND "
3402  " sourceid = :SOURCEID");
3403  query.bindValue(":CALLSIGN", callsign);
3404  query.bindValue(":CHANNUM", channum);
3405  query.bindValue(":CHANNAME", channame);
3406  query.bindValue(":XMLTVID", xmltvid);
3407  query.bindValue(":CHANID", chanid);
3408  query.bindValue(":SOURCEID", sourceid);
3409 
3410  if (!query.exec())
3411  {
3412  MythDB::DBError("SetChannelInfo", query);
3413  return false;
3414  }
3415 
3416  if (m_channel)
3417  m_channel->Renumber(sourceid, oldchannum, channum);
3418 
3419  return true;
3420 }
3421 
3426 {
3427  QMutexLocker lock(&m_stateChangeLock);
3428 
3429  MythMediaBuffer *oldbuffer = m_buffer;
3430  m_buffer = Buffer;
3431 
3432  if (oldbuffer && (oldbuffer != Buffer))
3433  {
3435  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3436  delete oldbuffer;
3437  }
3438 
3439  m_switchingBuffer = false;
3440 }
3441 
3443 {
3444  LOG(VB_GENERAL, LOG_INFO, LOC + "RingBufferChanged()");
3445 
3446  QMutexLocker lock(&m_stateChangeLock);
3447 
3448  if (pginfo)
3449  {
3450  if (m_curRecording)
3451  {
3454  delete m_curRecording;
3455  }
3457  m_curRecording = new RecordingInfo(*pginfo);
3460  }
3461 
3463 }
3464 
3466  QString &input) const
3467 {
3468  QString channum;
3469 
3470  if (request.m_program)
3471  {
3472  request.m_program->QueryTuningInfo(channum, input);
3473  return channum;
3474  }
3475 
3476  channum = request.m_channel;
3477  input = request.m_input;
3478 
3479  // If this is Live TV startup, we need a channel...
3480  if (channum.isEmpty() && (request.m_flags & kFlagLiveTV))
3481  {
3482  if (!m_liveTVStartChannel.isEmpty())
3483  channum = m_liveTVStartChannel;
3484  else
3485  {
3488  }
3489  }
3490  if (request.m_flags & kFlagLiveTV)
3491  m_channel->Init(channum, false);
3492 
3493  if (m_channel && !channum.isEmpty() && (channum.indexOf("NextChannel") >= 0))
3494  {
3495  // FIXME This is just horrible
3496  int dir = channum.right(channum.length() - 12).toInt();
3497  uint chanid = m_channel->GetNextChannel(0, static_cast<ChannelChangeDirection>(dir));
3498  channum = ChannelUtil::GetChanNum(chanid);
3499  }
3500 
3501  return channum;
3502 }
3503 
3505 {
3506  if ((request.m_flags & kFlagAntennaAdjust) || request.m_input.isEmpty() ||
3508  {
3509  return false;
3510  }
3511 
3512  uint sourceid = m_channel->GetSourceID();
3513  QString oldchannum = m_channel->GetChannelName();
3514  QString newchannum = request.m_channel;
3515 
3516  if (ChannelUtil::IsOnSameMultiplex(sourceid, newchannum, oldchannum))
3517  {
3519  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3520 
3521  if (atsc)
3522  {
3523  uint major = 0;
3524  uint minor = 0;
3525  ChannelUtil::GetATSCChannel(sourceid, newchannum, major, minor);
3526 
3527  if (minor && atsc->HasChannel(major, minor))
3528  {
3529  request.m_majorChan = major;
3530  request.m_minorChan = minor;
3531  return true;
3532  }
3533  }
3534 
3535  if (mpeg)
3536  {
3537  uint progNum = ChannelUtil::GetProgramNumber(sourceid, newchannum);
3538  if (mpeg->HasProgram(progNum))
3539  {
3540  request.m_progNum = progNum;
3541  return true;
3542  }
3543  }
3544  }
3545 
3546  return false;
3547 }
3548 
3557 {
3558  if (!m_tuningRequests.empty())
3559  {
3560  TuningRequest request = m_tuningRequests.front();
3561  LOG(VB_RECORD, LOG_INFO, LOC +
3562  "HandleTuning Request: " + request.toString());
3563 
3564  QString input;
3565  request.m_channel = TuningGetChanNum(request, input);
3566  request.m_input = input;
3567 
3568  if (TuningOnSameMultiplex(request))
3569  LOG(VB_CHANNEL, LOG_INFO, LOC + "On same multiplex");
3570 
3571  TuningShutdowns(request);
3572 
3573  // The dequeue isn't safe to do until now because we
3574  // release the stateChangeLock to teardown a recorder
3576 
3577  // Now we start new stuff
3578  if (request.m_flags & (kFlagRecording|kFlagLiveTV|
3580  {
3581  if (!m_recorder)
3582  {
3583  LOG(VB_RECORD, LOG_INFO, LOC +
3584  "No recorder yet, calling TuningFrequency");
3585  TuningFrequency(request);
3586  }
3587  else
3588  {
3589  LOG(VB_RECORD, LOG_INFO, LOC + "Waiting for recorder pause..");
3590  SetFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3591  }
3592  }
3593  m_lastTuningRequest = request;
3594  }
3595 
3597  {
3598  if (!m_recorder || !m_recorder->IsPaused())
3599  return;
3600 
3601  ClearFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3602  LOG(VB_RECORD, LOG_INFO, LOC +
3603  "Recorder paused, calling TuningFrequency");
3605  }
3606 
3607  MPEGStreamData *streamData = nullptr;
3609  {
3610  streamData = TuningSignalCheck();
3611  if (streamData == nullptr)
3612  return;
3613  }
3614 
3616  {
3617  if (m_recorder)
3619  else
3620  TuningNewRecorder(streamData);
3621 
3622  // If we got this far it is safe to set a new starting channel...
3623  if (m_channel)
3625  }
3626 }
3627 
3633 {
3634  LOG(VB_RECORD, LOG_INFO, LOC + QString("TuningShutdowns(%1)")
3635  .arg(request.toString()));
3636 
3637  if (m_scanner && !(request.m_flags & kFlagEITScan) &&
3639  {
3641  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
3643  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
3644  }
3645 
3646  if (m_scanner && !request.IsOnSameMultiplex())
3648 
3650  {
3651  MPEGStreamData *sd = nullptr;
3652  if (GetDTVSignalMonitor())
3655  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3656 
3657  // Delete StreamData if it is not in use by the recorder.
3658  MPEGStreamData *rec_sd = nullptr;
3659  if (GetDTVRecorder())
3660  rec_sd = GetDTVRecorder()->GetStreamData();
3661  if (sd && (sd != rec_sd))
3662  delete sd;
3663  }
3665  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3666 
3667  // At this point any waits are canceled.
3668 
3669  if (request.m_flags & kFlagNoRec)
3670  {
3672  {
3674  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3676  }
3677 
3679  (m_curRecording &&
3682  {
3683  m_stateChangeLock.unlock();
3684  TeardownRecorder(request.m_flags);
3685  m_stateChangeLock.lock();
3686  }
3687  // At this point the recorders are shut down
3688 
3689  CloseChannel();
3690  // At this point the channel is shut down
3691  }
3692 
3693  if (m_buffer && (request.m_flags & kFlagKillRingBuffer))
3694  {
3695  LOG(VB_RECORD, LOG_INFO, LOC + "Tearing down RingBuffer");
3696  SetRingBuffer(nullptr);
3697  // At this point the ringbuffer is shut down
3698  }
3699 
3700  // Clear pending actions from last request
3701  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
3702 }
3703 
3722 {
3723  LOG(VB_GENERAL, LOG_INFO, LOC + QString("TuningFrequency(%1)")
3724  .arg(request.toString()));
3725 
3726  DTVChannel *dtvchan = GetDTVChannel();
3727  if (dtvchan)
3728  {
3729  MPEGStreamData *mpeg = nullptr;
3730 
3731  if (GetDTVRecorder())
3733 
3734  // Tune with SI table standard (dvb, atsc, mpeg) from database, see issue #452
3736 
3737  const QString tuningmode = (HasFlags(kFlagEITScannerRunning)) ?
3738  dtvchan->GetSIStandard() :
3739  dtvchan->GetSuggestedTuningMode(
3741 
3742  dtvchan->SetTuningMode(tuningmode);
3743 
3744  if (request.m_minorChan && (tuningmode == "atsc"))
3745  {
3746  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3747  if (atsc)
3748  atsc->SetDesiredChannel(request.m_majorChan, request.m_minorChan);
3749  }
3750  else if (request.m_progNum >= 0)
3751  {
3752  if (mpeg)
3753  mpeg->SetDesiredProgram(request.m_progNum);
3754  }
3755  }
3756 
3757  if (request.IsOnSameMultiplex())
3758  {
3759  // Update the channel number for SwitchLiveTVRingBuffer (called from
3760  // TuningRestartRecorder). This ensures that the livetvchain will be
3761  // updated with the new channel number
3762  if (m_channel)
3763  {
3765  m_channel->GetChannelName(), request.m_channel );
3766  }
3767 
3768  QStringList slist;
3769  slist<<"message"<<QObject::tr("On known multiplex...");
3770  MythEvent me(QString("SIGNAL %1").arg(m_inputId), slist);
3771  gCoreContext->dispatch(me);
3772 
3773  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3774  return;
3775  }
3776 
3777  QString channum = request.m_channel;
3778 
3779  bool ok1 = true;
3780  if (m_channel)
3781  {
3782  m_channel->Open();
3783  if (!channum.isEmpty())
3784  ok1 = m_channel->SetChannelByString(channum);
3785  else
3786  ok1 = false;
3787  }
3788 
3789  if (!ok1)
3790  {
3791  if (!(request.m_flags & kFlagLiveTV) || !(request.m_flags & kFlagEITScan))
3792  {
3793  if (m_curRecording)
3795 
3796  LOG(VB_GENERAL, LOG_ERR, LOC +
3797  QString("Failed to set channel to %1. Reverting to kState_None")
3798  .arg(channum));
3801  else
3803  return;
3804  }
3805 
3806  LOG(VB_GENERAL, LOG_ERR, LOC +
3807  QString("Failed to set channel to %1.").arg(channum));
3808  }
3809 
3810  bool mpts_only = GetDTVChannel() &&
3811  GetDTVChannel()->GetFormat().compare("MPTS") == 0;
3812  if (mpts_only)
3813  {
3814  // Not using a signal monitor, so just set the status to recording
3816  if (m_curRecording)
3817  {
3819  }
3820  }
3821 
3822 
3823  bool livetv = (request.m_flags & kFlagLiveTV) != 0U;
3824  bool antadj = (request.m_flags & kFlagAntennaAdjust) != 0U;
3825  bool use_sm = !mpts_only && SignalMonitor::IsRequired(m_genOpt.m_inputType);
3826  bool use_dr = use_sm && (livetv || antadj);
3827  bool has_dummy = false;
3828 
3829  if (use_dr)
3830  {
3831  // We need there to be a ringbuffer for these modes
3832  bool ok2 = false;
3834  m_pseudoLiveTVRecording = nullptr;
3835 
3836  m_tvChain->SetInputType("DUMMY");
3837 
3838  if (!m_buffer)
3839  ok2 = CreateLiveTVRingBuffer(channum);
3840  else
3841  ok2 = SwitchLiveTVRingBuffer(channum, true, false);
3843 
3845 
3846  if (!ok2)
3847  {
3848  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 1");
3849  return;
3850  }
3851 
3852  has_dummy = true;
3853  }
3854 
3855  // Start signal monitoring for devices capable of monitoring
3856  if (use_sm)
3857  {
3858  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Signal Monitor");
3859  bool error = false;
3860  if (!SetupSignalMonitor(
3861  !antadj, (request.m_flags & kFlagEITScan) != 0U, livetv || antadj))
3862  {
3863  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to setup signal monitor");
3864  if (m_signalMonitor)
3865  {
3866  delete m_signalMonitor;
3867  m_signalMonitor = nullptr;
3868  }
3869 
3870  // pretend the signal monitor is running to prevent segfault
3871  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3872  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3873  error = true;
3874  }
3875 
3876  if (m_signalMonitor)
3877  {
3878  if (request.m_flags & kFlagEITScan)
3879  {
3881  SetVideoStreamsRequired(0);
3883  }
3884 
3885  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3886  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3887  if (!antadj)
3888  {
3889  QDateTime expire = MythDate::current();
3890 
3891  SetFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3892  if (m_curRecording)
3893  {
3895  // If startRecordingDeadline is passed, this
3896  // recording is marked as failed, so the scheduler
3897  // can try another showing.
3899  expire.addMSecs(m_genOpt.m_channelTimeout);
3901  expire.addMSecs(m_genOpt.m_channelTimeout * 2 / 3);
3902  // Keep trying to record this showing (even if it
3903  // has been marked as failed) until the scheduled
3904  // end time.
3906  m_curRecording->GetRecordingEndTime().addSecs(-10);
3907 
3908  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
3909  QString("Pre-fail start deadline: %1 "
3910  "Start recording deadline: %2 "
3911  "Good signal deadline: %3")
3912  .arg(m_preFailDeadline.toLocalTime()
3913  .toString("hh:mm:ss.zzz"),
3914  m_startRecordingDeadline.toLocalTime()
3915  .toString("hh:mm:ss.zzz"),
3916  m_signalMonitorDeadline.toLocalTime()
3917  .toString("hh:mm:ss.zzz")));
3918  }
3919  else
3920  {
3922  expire.addMSecs(m_genOpt.m_channelTimeout);
3923  }
3925 
3926  //System Event TUNING_TIMEOUT deadline
3928  m_signalEventCmdSent = false;
3929  }
3930  }
3931 
3932  if (has_dummy && m_buffer)
3933  {
3934  // Make sure recorder doesn't point to bogus ringbuffer before
3935  // it is potentially restarted without a new ringbuffer, if
3936  // the next channel won't tune and the user exits LiveTV.
3937  if (m_recorder)
3938  m_recorder->SetRingBuffer(nullptr);
3939 
3940  SetFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3941  LOG(VB_RECORD, LOG_INFO, "DummyDTVRecorder -- started");
3942  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3943  }
3944 
3945  // if we had problems starting the signal monitor,
3946  // we don't want to start the recorder...
3947  if (error)
3948  return;
3949  }
3950 
3951  // Request a recorder, if the command is a recording command
3952  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3953  if (request.m_flags & kFlagRec && !antadj)
3954  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3955 }
3956 
3965 {
3966  RecStatus::Type newRecStatus = RecStatus::Unknown;
3967  bool keep_trying = false;
3968  QDateTime current_time = MythDate::current();
3969 
3970  if ((m_signalMonitor->IsErrored() || current_time > m_signalEventCmdTimeout) &&
3972  {
3973  gCoreContext->SendSystemEvent(QString("TUNING_SIGNAL_TIMEOUT CARDID %1")
3974  .arg(m_inputId));
3975  m_signalEventCmdSent = true;
3976  }
3977 
3978  if (m_signalMonitor->IsAllGood())
3979  {
3980  LOG(VB_RECORD, LOG_INFO, LOC + "TuningSignalCheck: Good signal");
3981  if (m_curRecording && (current_time > m_startRecordingDeadline))
3982  {
3983  newRecStatus = RecStatus::Failing;
3984  m_curRecording->SaveVideoProperties(VID_DAMAGED, VID_DAMAGED);
3985 
3986  QString desc = tr("Good signal seen after %1 ms")
3987  .arg(m_genOpt.m_channelTimeout +
3988  m_startRecordingDeadline.msecsTo(current_time));
3989  QString title = m_curRecording->GetTitle();
3990  if (!m_curRecording->GetSubtitle().isEmpty())
3991  title += " - " + m_curRecording->GetSubtitle();
3992 
3994  "Recording", title,
3995  tr("See 'Tuning timeout' in mythtv-setup "
3996  "for this input."));
3997  gCoreContext->SendEvent(mn);
3998 
3999  LOG(VB_GENERAL, LOG_WARNING, LOC +
4000  QString("It took longer than %1 ms to get a signal lock. "
4001  "Keeping status of '%2'")
4003  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
4004  LOG(VB_GENERAL, LOG_WARNING, LOC +
4005  "See 'Tuning timeout' in mythtv-setup for this input");
4006  }
4007  else
4008  {
4009  newRecStatus = RecStatus::Recording;
4010  }
4011  }
4012  else if (m_signalMonitor->IsErrored() || current_time > m_signalMonitorDeadline)
4013  {
4014  LOG(VB_GENERAL, LOG_ERR, LOC + "TuningSignalCheck: SignalMonitor " +
4015  (m_signalMonitor->IsErrored() ? "failed" : "timed out"));
4016 
4017  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4018  newRecStatus = RecStatus::Failed;
4019 
4021  {
4023  }
4024  }
4025  else if (m_curRecording && !m_reachedPreFail && current_time > m_preFailDeadline)
4026  {
4027  LOG(VB_GENERAL, LOG_ERR, LOC +
4028  "TuningSignalCheck: Hit pre-fail timeout");
4029  SendMythSystemRecEvent("REC_PREFAIL", m_curRecording);
4030  m_reachedPreFail = true;
4031  return nullptr;
4032  }
4034  current_time > m_startRecordingDeadline)
4035  {
4036  newRecStatus = RecStatus::Failing;
4038  keep_trying = true;
4039 
4040  SendMythSystemRecEvent("REC_FAILING", m_curRecording);
4041 
4042  QString desc = tr("Taking more than %1 ms to get a lock.")
4043  .arg(m_genOpt.m_channelTimeout);
4044  QString title = m_curRecording->GetTitle();
4045  if (!m_curRecording->GetSubtitle().isEmpty())
4046  title += " - " + m_curRecording->GetSubtitle();
4047 
4049  "Recording", title,
4050  tr("See 'Tuning timeout' in mythtv-setup "
4051  "for this input."));
4052  mn.SetDuration(30s);
4053  gCoreContext->SendEvent(mn);
4054 
4055  LOG(VB_GENERAL, LOG_WARNING, LOC +
4056  QString("TuningSignalCheck: taking more than %1 ms to get a lock. "
4057  "marking this recording as '%2'.")
4059  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
4060  LOG(VB_GENERAL, LOG_WARNING, LOC +
4061  "See 'Tuning timeout' in mythtv-setup for this input");
4062  }
4063  else
4064  {
4065  if (m_signalMonitorCheckCnt) // Don't flood log file
4067  else
4068  {
4069  LOG(VB_RECORD, LOG_INFO, LOC +
4070  QString("TuningSignalCheck: Still waiting. Will timeout @ %1")
4071  .arg(m_signalMonitorDeadline.toLocalTime()
4072  .toString("hh:mm:ss.zzz")));
4074  }
4075  return nullptr;
4076  }
4077 
4078  SetRecordingStatus(newRecStatus, __LINE__);
4079 
4080  if (m_curRecording)
4081  {
4082  m_curRecording->SetRecordingStatus(newRecStatus);
4083  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
4084  .arg(m_curRecording->GetInputID())
4085  .arg(m_curRecording->GetChanID())
4087  .arg(newRecStatus)
4089  gCoreContext->dispatch(me);
4090  }
4091 
4092  if (keep_trying)
4093  return nullptr;
4094 
4095  // grab useful data from DTV signal monitor before we kill it...
4096  MPEGStreamData *streamData = nullptr;
4097  if (GetDTVSignalMonitor())
4098  streamData = GetDTVSignalMonitor()->GetStreamData();
4099 
4101  {
4102  // shut down signal monitoring
4104  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
4105  }
4106  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
4107 
4108  if (streamData)
4109  {
4110  auto *dsd = dynamic_cast<DVBStreamData*>(streamData);
4111  if (dsd)
4113  if (m_scanner)
4114  {
4115  if (get_use_eit(GetInputId()))
4116  {
4118  }
4119  else
4120  {
4121  LOG(VB_EIT, LOG_INFO, LOC +
4122  QString("EIT scanning disabled for video source %1")
4123  .arg(GetSourceID())); }
4124  }
4125  }
4126 
4127  return streamData;
4128 }
4129 
4131  bool on_host, bool transcode_bfr_comm, bool on_line_comm)
4132 {
4133  if (!rec)
4134  return 0; // no jobs for Live TV recordings..
4135 
4136  int jobs = 0; // start with no jobs
4137 
4138  // grab standard jobs flags from program info
4140 
4141  // disable commercial flagging on PBS, BBC, etc.
4142  if (rec->IsCommercialFree())
4144 
4145  // disable transcoding if the profile does not allow auto transcoding
4146  const StandardSetting *autoTrans = profile.byName("autotranscode");
4147  if ((!autoTrans) || (autoTrans->getValue().toInt() == 0))
4149 
4150  bool ml = JobQueue::JobIsInMask(JOB_METADATA, jobs);
4151  if (ml)
4152  {
4153  // When allowed, metadata lookup should occur at the
4154  // start of a recording to make the additional info
4155  // available immediately (and for use in future jobs).
4156  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4158  rec->GetChanID(),
4159  rec->GetRecordingStartTime(), "", "",
4160  host, JOB_LIVE_REC);
4161 
4162  // don't do regular metadata lookup, we won't need it.
4164  }
4165 
4166  // is commercial flagging enabled, and is on-line comm flagging enabled?
4167  bool rt = JobQueue::JobIsInMask(JOB_COMMFLAG, jobs) && on_line_comm;
4168  // also, we either need transcoding to be disabled or
4169  // we need to be allowed to commercial flag before transcoding?
4170  rt &= JobQueue::JobIsNotInMask(JOB_TRANSCODE, jobs) ||
4171  !transcode_bfr_comm;
4172  if (rt)
4173  {
4174  // queue up real-time (i.e. on-line) commercial flagging.
4175  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4177  rec->GetChanID(),
4178  rec->GetRecordingStartTime(), "", "",
4179  host, JOB_LIVE_REC);
4180 
4181  // don't do regular comm flagging, we won't need it.
4183  }
4184 
4185  return jobs;
4186 }
4187 
4188 QString TVRec::LoadProfile(void *tvchain, RecordingInfo *rec,
4189  RecordingProfile &profile) const
4190 {
4191  // Determine the correct recording profile.
4192  // In LiveTV mode use "Live TV" profile, otherwise use the
4193  // recording's specified profile. If the desired profile can't
4194  // be found, fall back to the "Default" profile for input type.
4195  QString profileName = "Live TV";
4196  if (!tvchain && rec)
4197  profileName = rec->GetRecordingRule()->m_recProfile;
4198 
4199  QString profileRequested = profileName;
4200 
4201  if (profile.loadByType(profileName, m_genOpt.m_inputType,
4203  {
4204  LOG(VB_RECORD, LOG_INFO, LOC +
4205  QString("Using profile '%1' to record")
4206  .arg(profileName));
4207  }
4208  else
4209  {
4210  profileName = "Default";
4211  if (profile.loadByType(profileName, m_genOpt.m_inputType, m_genOpt.m_videoDev))
4212  {
4213  LOG(VB_RECORD, LOG_INFO, LOC +
4214  QString("Profile '%1' not found, using "
4215  "fallback profile '%2' to record")
4216  .arg(profileRequested, profileName));
4217  }
4218  else
4219  {
4220  LOG(VB_RECORD, LOG_ERR, LOC +
4221  QString("Profile '%1' not found, and unable "
4222  "to load fallback profile '%2'. Results "
4223  "may be unpredicable")
4224  .arg(profileRequested, profileName));
4225  }
4226  }
4227 
4228  return profileName;
4229 }
4230 
4235 {
4236  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Recorder");
4237 
4238  bool had_dummyrec = false;
4240  {
4242  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4244  had_dummyrec = true;
4245  }
4246 
4248 
4251 
4252  if (m_tvChain)
4253  {
4254  bool ok = false;
4255  if (!m_buffer)
4256  {
4258  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4259  }
4260  else
4261  {
4263  true, !had_dummyrec && m_recorder);
4264  }
4265  if (!ok)
4266  {
4267  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 2");
4268  goto err_ret;
4269  }
4270  rec = m_curRecording; // new'd in Create/SwitchLiveTVRingBuffer()
4271  }
4272 
4274  {
4275  bool write = m_genOpt.m_inputType != "IMPORT";
4276  LOG(VB_GENERAL, LOG_INFO, LOC + QString("rec->GetPathname(): '%1'")
4277  .arg(rec->GetPathname()));
4279  if (!m_buffer->IsOpen() && write)
4280  {
4281  LOG(VB_GENERAL, LOG_ERR, LOC +
4282  QString("RingBuffer '%1' not open...")
4283  .arg(rec->GetPathname()));
4284  SetRingBuffer(nullptr);
4285  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4286  goto err_ret;
4287  }
4288  }
4289 
4290  if (!m_buffer)
4291  {
4292  LOG(VB_GENERAL, LOG_ERR, LOC +
4293  QString("Failed to start recorder! ringBuffer is NULL\n"
4294  "\t\t\t\t Tuning request was %1\n")
4295  .arg(m_lastTuningRequest.toString()));
4296 
4297  if (HasFlags(kFlagLiveTV))
4298  {
4299  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4300  MythEvent me(message);
4301  gCoreContext->dispatch(me);
4302  }
4303  goto err_ret;
4304  }
4305 
4306  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4307  m_channel->Close(); // Needed because of NVR::MJPEGInit()
4308 
4309  LOG(VB_GENERAL, LOG_INFO, LOC + "TuningNewRecorder - CreateRecorder()");
4311 
4312  if (m_recorder)
4313  {
4316  if (m_recorder->IsErrored())
4317  {
4318  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialize recorder!");
4319  delete m_recorder;
4320  m_recorder = nullptr;
4321  }
4322  }
4323 
4324  if (!m_recorder)
4325  {
4326  LOG(VB_GENERAL, LOG_ERR, LOC +
4327  QString("Failed to start recorder!\n"
4328  "\t\t\t\t Tuning request was %1\n")
4329  .arg(m_lastTuningRequest.toString()));
4330 
4331  if (HasFlags(kFlagLiveTV))
4332  {
4333  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4334  MythEvent me(message);
4335  gCoreContext->dispatch(me);
4336  }
4338  if (m_tvChain)
4339  rec = nullptr;
4340  goto err_ret;
4341  }
4342 
4343  if (rec)
4344  m_recorder->SetRecording(rec);
4345 
4346  if (GetDTVRecorder() && streamData)
4347  {
4348  const StandardSetting *setting = profile.byName("recordingtype");
4349  if (setting)
4350  streamData->SetRecordingType(setting->getValue());
4351  GetDTVRecorder()->SetStreamData(streamData);
4352  }
4353 
4354  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4355  m_channel->Open(); // Needed because of NVR::MJPEGInit()
4356 
4357  // Setup for framebuffer capture devices..
4358  if (m_channel)
4359  {
4362  }
4363 
4364  if (GetV4LChannel())
4365  {
4367  CloseChannel();
4368  }
4369 
4370  m_recorderThread = new MThread("RecThread", m_recorder);
4372 
4373  // Wait for recorder to start.
4374  m_stateChangeLock.unlock();
4375  while (!m_recorder->IsRecording() && !m_recorder->IsErrored())
4376  std::this_thread::sleep_for(5us);
4377  m_stateChangeLock.lock();
4378 
4379  if (GetV4LChannel())
4381 
4382  SetFlags(kFlagRecorderRunning | kFlagRingBufferReady, __FILE__, __LINE__);
4383 
4384  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4385 
4386  //workaround for failed import recordings, no signal monitor means we never
4387  //go to recording state and the status here seems to override the status
4388  //set in the importrecorder and backend via setrecordingstatus
4389  if (m_genOpt.m_inputType == "IMPORT")
4390  {
4392  if (m_curRecording)
4394  }
4395  return;
4396 
4397  err_ret:
4398  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
4400 
4401  if (rec)
4402  {
4403  // Make sure the scheduler knows...
4405  LOG(VB_RECORD, LOG_INFO, LOC +
4406  QString("TuningNewRecorder -- UPDATE_RECORDING_STATUS: %1")
4408  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
4409  .arg(rec->GetInputID())
4410  .arg(rec->GetChanID())
4412  .arg(RecStatus::Failed)
4414  gCoreContext->dispatch(me);
4415  }
4416 
4417  if (m_tvChain)
4418  delete rec;
4419 }
4420 
4425 {
4426  LOG(VB_RECORD, LOG_INFO, LOC + "Restarting Recorder");
4427 
4428  bool had_dummyrec = false;
4429 
4430  if (m_curRecording)
4431  {
4434  }
4435 
4437  {
4438  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4439  had_dummyrec = true;
4440  }
4441 
4442  SwitchLiveTVRingBuffer(m_channel->GetChannelName(), true, !had_dummyrec);
4443 
4444  if (had_dummyrec)
4445  {
4447  ProgramInfo *progInfo = m_tvChain->GetProgramAt(-1);
4448  RecordingInfo recinfo(*progInfo);
4449  delete progInfo;
4450  recinfo.SetInputID(m_inputId);
4451  m_recorder->SetRecording(&recinfo);
4452  }
4453  m_recorder->Reset();
4454 
4455  // Set file descriptor of channel from recorder for V4L
4456  if (GetV4LChannel())
4458 
4459  // Some recorders unpause on Reset, others do not...
4460  m_recorder->Unpause();
4461 
4463  {
4465  QString msg1 = QString("Recording: %1 %2 %3 %4")
4466  .arg(rcinfo1->GetTitle(), QString::number(rcinfo1->GetChanID()),
4469  ProgramInfo *rcinfo2 = m_tvChain->GetProgramAt(-1);
4470  QString msg2 = QString("Recording: %1 %2 %3 %4")
4471  .arg(rcinfo2->GetTitle(), QString::number(rcinfo2->GetChanID()),
4474  delete rcinfo2;
4475  LOG(VB_RECORD, LOG_INFO, LOC + "Pseudo LiveTV recording starting." +
4476  "\n\t\t\t" + msg1 + "\n\t\t\t" + msg2);
4477 
4480 
4482 
4483  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
4484  }
4485 
4486  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4487 }
4488 
4489 void TVRec::SetFlags(uint f, const QString & file, int line)
4490 {
4491  QMutexLocker lock(&m_stateChangeLock);
4492  m_stateFlags |= f;
4493  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetFlags(%1) -> %2 @ %3:%4")
4494  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4495  WakeEventLoop();
4496 }
4497 
4498 void TVRec::ClearFlags(uint f, const QString & file, int line)
4499 {
4500  QMutexLocker lock(&m_stateChangeLock);
4501  m_stateFlags &= ~f;
4502  LOG(VB_RECORD, LOG_INFO, LOC + QString("ClearFlags(%1) -> %2 @ %3:%4")
4503  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4504  WakeEventLoop();
4505 }
4506 
4508 {
4509  QString msg("");
4510 
4511  // General flags
4512  if (kFlagFrontendReady & f)
4513  msg += "FrontendReady,";
4514  if (kFlagRunMainLoop & f)
4515  msg += "RunMainLoop,";
4516  if (kFlagExitPlayer & f)
4517  msg += "ExitPlayer,";
4518  if (kFlagFinishRecording & f)
4519  msg += "FinishRecording,";
4520  if (kFlagErrored & f)
4521  msg += "Errored,";
4522  if (kFlagCancelNextRecording & f)
4523  msg += "CancelNextRecording,";
4524 
4525  // Tuning flags
4526  if ((kFlagRec & f) == kFlagRec)
4527  msg += "REC,";
4528  else
4529  {
4530  if (kFlagLiveTV & f)
4531  msg += "LiveTV,";
4532  if (kFlagRecording & f)
4533  msg += "Recording,";
4534  }
4535  if ((kFlagNoRec & f) == kFlagNoRec)
4536  msg += "NOREC,";
4537  else
4538  {
4539  if (kFlagEITScan & f)
4540  msg += "EITScan,";
4541  if (kFlagCloseRec & f)
4542  msg += "CloseRec,";
4543  if (kFlagKillRec & f)
4544  msg += "KillRec,";
4545  if (kFlagAntennaAdjust & f)
4546  msg += "AntennaAdjust,";
4547  }
4549  msg += "PENDINGACTIONS,";
4550  else
4551  {
4552  if (kFlagWaitingForRecPause & f)
4553  msg += "WaitingForRecPause,";
4554  if (kFlagWaitingForSignal & f)
4555  msg += "WaitingForSignal,";
4556  if (kFlagNeedToStartRecorder & f)
4557  msg += "NeedToStartRecorder,";
4558  if (kFlagKillRingBuffer & f)
4559  msg += "KillRingBuffer,";
4560  }
4561  if ((kFlagAnyRunning & f) == kFlagAnyRunning)
4562  msg += "ANYRUNNING,";
4563  else
4564  {
4565  if (kFlagSignalMonitorRunning & f)
4566  msg += "SignalMonitorRunning,";
4567  if (kFlagEITScannerRunning & f)
4568  msg += "EITScannerRunning,";
4570  msg += "ANYRECRUNNING,";
4571  else
4572  {
4573  if (kFlagDummyRecorderRunning & f)
4574  msg += "DummyRecorderRunning,";
4575  if (kFlagRecorderRunning & f)
4576  msg += "RecorderRunning,";
4577  }
4578  }
4579  if (kFlagRingBufferReady & f)
4580  msg += "RingBufferReady,";
4581 
4582  if (msg.isEmpty())
4583  msg = QString("0x%1").arg(f,0,16);
4584 
4585  return msg;
4586 }
4587 
4589 {
4590  QMutexLocker lock(&m_nextLiveTVDirLock);
4591 
4592  bool found = !m_nextLiveTVDir.isEmpty();
4593  if (!found && m_triggerLiveTVDir.wait(&m_nextLiveTVDirLock, 500))
4594  {
4595  found = !m_nextLiveTVDir.isEmpty();
4596  }
4597 
4598  return found;
4599 }
4600 
4601 void TVRec::SetNextLiveTVDir(QString dir)
4602 {
4603  QMutexLocker lock(&m_nextLiveTVDirLock);
4604 
4605  m_nextLiveTVDir = std::move(dir);
4606  m_triggerLiveTVDir.wakeAll();
4607 }
4608 
4611  const QString & channum)
4612 {
4613  LOG(VB_RECORD, LOG_INFO, LOC + "GetProgramRingBufferForLiveTV()");
4614  if (!m_channel || !m_tvChain || !pginfo || !Buffer)
4615  return false;
4616 
4617  m_nextLiveTVDirLock.lock();
4618  m_nextLiveTVDir.clear();
4619  m_nextLiveTVDirLock.unlock();
4620 
4621  // Dispatch this early, the response can take a while.
4622  MythEvent me(QString("QUERY_NEXT_LIVETV_DIR %1").arg(m_inputId));
4623  gCoreContext->dispatch(me);
4624 
4625  uint sourceid = m_channel->GetSourceID();
4626  int chanid = ChannelUtil::GetChanID(sourceid, channum);
4627 
4628  if (chanid < 0)
4629  {
4630  // Test setups might have zero channels
4631  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
4632  chanid = 9999;
4633  else
4634  {
4635  LOG(VB_GENERAL, LOG_ERR, LOC +
4636  QString("Channel: \'%1\' was not found in the database.\n"
4637  "\t\tMost likely, the 'starting channel' for this "
4638  "Input Connection is invalid.\n"
4639  "\t\tCould not start livetv.").arg(channum));
4640  return false;
4641  }
4642  }
4643 
4644  auto hoursMax =
4645  gCoreContext->GetDurSetting<std::chrono::hours>("MaxHoursPerLiveTVRecording", 8h);
4646  if (hoursMax <= 0h)
4647  hoursMax = 8h;
4648 
4649  RecordingInfo *prog = nullptr;
4652  else
4653  {
4654  prog = new RecordingInfo(
4655  chanid, MythDate::current(true), true, hoursMax);
4656  }
4657 
4658  prog->SetInputID(m_inputId);
4659 
4660  if (prog->GetRecordingStartTime() == prog->GetRecordingEndTime())
4661  {
4662  LOG(VB_GENERAL, LOG_ERR, LOC + "GetProgramRingBufferForLiveTV()"
4663  "\n\t\t\tProgramInfo is invalid."
4664  "\n" + prog->toString());
4665  prog->SetScheduledEndTime(prog->GetRecordingStartTime().addSecs(3600));
4667 
4668  prog->SetChanID(chanid);
4669  }
4670 
4673 
4674  prog->SetStorageGroup("LiveTV");
4675 
4676  if (WaitForNextLiveTVDir())
4677  {
4678  QMutexLocker lock(&m_nextLiveTVDirLock);
4680  }
4681  else
4682  {
4683  StorageGroup sgroup("LiveTV", gCoreContext->GetHostName());
4684  prog->SetPathname(sgroup.FindNextDirMostFree());
4685  }
4686 
4688  prog->SetRecordingGroup("LiveTV");
4689 
4690  StartedRecording(prog);
4691 
4692  *Buffer = MythMediaBuffer::Create(prog->GetPathname(), true);
4693  if (!(*Buffer) || !(*Buffer)->IsOpen())
4694  {
4695  LOG(VB_GENERAL, LOG_ERR, LOC + QString("RingBuffer '%1' not open...")
4696  .arg(prog->GetPathname()));
4697 
4698  delete *Buffer;
4699  delete prog;
4700 
4701  return false;
4702  }
4703 
4704  *pginfo = prog;
4705  return true;
4706 }
4707 
4708 bool TVRec::CreateLiveTVRingBuffer(const QString & channum)
4709 {
4710  LOG(VB_RECORD, LOG_INFO, LOC + QString("CreateLiveTVRingBuffer(%1)")
4711  .arg(channum));
4712 
4713  RecordingInfo *pginfo = nullptr;
4714  MythMediaBuffer *buffer = nullptr;
4715 
4716  if (!m_channel ||
4717  !m_channel->CheckChannel(channum))
4718  {
4720  return false;
4721  }
4722 
4723  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4724  {
4725  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4727  LOG(VB_GENERAL, LOG_ERR, LOC +
4728  QString("CreateLiveTVRingBuffer(%1) failed").arg(channum));
4729  return false;
4730  }
4731 
4732  SetRingBuffer(buffer);
4733 
4737 
4738  bool discont = (m_tvChain->TotalSize() > 0);
4740  m_channel->GetInputName(), discont);
4741 
4742  if (m_curRecording)
4743  {
4745  delete m_curRecording;
4746  }
4747 
4748  m_curRecording = pginfo;
4750 
4751  return true;
4752 }
4753 
4754 bool TVRec::SwitchLiveTVRingBuffer(const QString & channum,
4755  bool discont, bool set_rec)
4756 {
4757  QString msg;
4758  if (m_curRecording)
4759  {
4760  msg = QString(" curRec(%1) curRec.size(%2)")
4761  .arg(m_curRecording->MakeUniqueKey())
4762  .arg(m_curRecording->GetFilesize());
4763  }
4764  LOG(VB_RECORD, LOG_INFO, LOC +
4765  QString("SwitchLiveTVRingBuffer(discont %1, set_next_rec %2)")
4766  .arg(discont).arg(set_rec) + msg);
4767 
4768  RecordingInfo *pginfo = nullptr;
4769  MythMediaBuffer *buffer = nullptr;
4770 
4771  if (!m_channel ||
4772  !m_channel->CheckChannel(channum))
4773  {
4775  return false;
4776  }
4777 
4778  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4779  {
4781  return false;
4782  }
4783 
4784  QString oldinputtype = m_tvChain->GetInputType(-1);
4785 
4786  pginfo->MarkAsInUse(true, kRecorderInUseID);
4791  m_channel->GetInputName(), discont);
4792 
4793  if (set_rec && m_recorder)
4794  {
4795  m_recorder->SetNextRecording(pginfo, buffer);
4796  if (discont)
4798  delete pginfo;
4799  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4800  }
4801  else if (!set_rec)
4802  {
4803  // dummy recordings are finished before this
4804  // is called and other recordings must be finished..
4805  if (m_curRecording && oldinputtype != "DUMMY")
4806  {
4809  delete m_curRecording;
4810  }
4811  m_curRecording = pginfo;
4812  SetRingBuffer(buffer);
4813  }
4814  else
4815  {
4816  delete buffer;
4817  }
4818 
4819  return true;
4820 }
4821 
4823 {
4824  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer()");
4825 
4826  if (m_switchingBuffer)
4827  {
4828  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4829  "already switching.");
4830  return nullptr;
4831  }
4832 
4833  if (!m_recorder)
4834  {
4835  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4836  "invalid recorder.");
4837  return nullptr;
4838  }
4839 
4840  if (!m_curRecording)
4841  {
4842  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4843  "invalid recording.");
4844  return nullptr;
4845  }
4846 
4847  if (rcinfo.GetChanID() != m_curRecording->GetChanID())
4848  {
4849  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4850  "Not the same channel.");
4851  return nullptr;
4852  }
4853 
4854  auto *ri = new RecordingInfo(rcinfo);
4856 
4857  QString pn = LoadProfile(nullptr, ri, profile);
4858 
4859  if (pn != m_recProfileName)
4860  {
4861  LOG(VB_RECORD, LOG_ERR, LOC +
4862  QString("SwitchRecordingRingBuffer() -> "
4863  "cannot switch profile '%1' to '%2'")
4864  .arg(m_recProfileName, pn));
4865  return nullptr;
4866  }
4867 
4869 
4870  ri->MarkAsInUse(true, kRecorderInUseID);
4871  StartedRecording(ri);
4872 
4873  bool write = m_genOpt.m_inputType != "IMPORT";
4874  MythMediaBuffer *buffer = MythMediaBuffer::Create(ri->GetPathname(), write);
4875  if (!buffer || !buffer->IsOpen())
4876  {
4877  delete buffer;
4878  ri->SetRecordingStatus(RecStatus::Failed);
4879  FinishedRecording(ri, nullptr);
4880  ri->MarkAsInUse(false, kRecorderInUseID);
4881  delete ri;
4882  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer() -> "
4883  "Failed to create new RB.");
4884  return nullptr;
4885  }
4886 
4887  m_recorder->SetNextRecording(ri, buffer);
4888  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4890  m_switchingBuffer = true;
4891  ri->SetRecordingStatus(RecStatus::Recording);
4892  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer -> done");
4893  return ri;
4894 }
4895 
4897 {
4898  QMap<uint,TVRec*>::const_iterator it = s_inputs.constFind(inputid);
4899  if (it == s_inputs.constEnd())
4900  return nullptr;
4901  return *it;
4902 }
4903 
4904 void TVRec::EnableActiveScan(bool enable)
4905 {
4906  LOG(VB_RECORD, LOG_INFO, LOC + QString("enable:%1").arg(enable));
4907 
4908  if (m_scanner != nullptr)
4909  {
4910  if (enable)
4911  {
4913  && m_eitScanStartTime > MythDate::current().addYears(9))
4914  {
4916  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
4917  }
4918  }
4919  else
4920  {
4921  m_eitScanStartTime = MythDate::current().addYears(10);
4923  {
4925  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
4926  }
4927  }
4928  }
4929 }
4930 
4931 QString TuningRequest::toString(void) const
4932 {
4933  return QString("Program(%1) channel(%2) input(%3) flags(%4)")
4934  .arg(m_program == nullptr ? "NULL" : m_program->toString(),
4935  m_channel.isEmpty() ? "<empty>" : m_channel,
4936  m_input.isEmpty() ? "<empty>" : m_input,
4938 }
4939 
4940 #ifdef USING_DVB
4941 #include "recorders/dvbchannel.h"
4943 {
4944  // Some DVB devices munge the PMT and/or PAT so the CRC check fails.
4945  // We need to tell the stream data class to not check the CRC on
4946  // these devices. This can cause segfaults.
4947  auto * dvb = dynamic_cast<DVBChannel*>(c);
4948  if (dvb != nullptr)
4949  s->SetIgnoreCRC(dvb->HasCRCBug());
4950 }
4951 #else
4953 #endif // USING_DVB
4954 
4955 /* vim: set expandtab tabstop=4 shiftwidth=4: */
GeneralDBOptions
Definition: tv_rec.h:65
TVRec::CreateLiveTVRingBuffer
bool CreateLiveTVRingBuffer(const QString &channum)
Definition: tv_rec.cpp:4708
DTVChannel::GetMajorChannel
uint GetMajorChannel(void) const
Returns major channel, 0 if unknown.
Definition: dtvchannel.h:93
BrowseDirection
BrowseDirection
Used to request ProgramInfo for channel browsing.
Definition: tv.h:40
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:215
BROWSE_SAME
@ BROWSE_SAME
Fetch browse information on current channel and time.
Definition: tv.h:43
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
RecStatus::Type
Type
Definition: recordingstatus.h:16
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:4489
TVRec::GetKeyframeDurations
bool GetKeyframeDurations(int64_t start, int64_t end, frm_pos_map_t &map) const
Definition: tv_rec.cpp:2683
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:2530
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:340
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:93
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:312
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
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:1293
InputInfo::m_chanId
uint m_chanId
chanid restriction if applicable
Definition: inputinfo.h:51
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:61
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:365
MPEGStreamData::SetVideoStreamsRequired
void SetVideoStreamsRequired(uint num)
Definition: mpegstreamdata.h:249
DTVSignalMonitor::SetDVBService
void SetDVBService(uint network_id, uint transport_id, int service_id)
Definition: dtvsignalmonitor.cpp:229
TuningRequest
Definition: tv_rec.h:101
PictureAttribute
PictureAttribute
Definition: videoouttypes.h:103
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:1661
error
static void error(const char *str,...)
Definition: vbi.cpp:37
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:584
dtvrecorder.h
ProgramInfo::QueryMplexID
uint QueryMplexID(void) const
Queries multiplex any recording would be made on, zero if unknown.
Definition: programinfo.cpp:2655
TVRec::m_recProfileName
QString m_recProfileName
Definition: tv_rec.h:383
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:869
TVRec::ShouldSwitchToAnotherInput
bool ShouldSwitchToAnotherInput(const QString &chanid) const
Checks if named channel exists on current tuner, or another tuner.
Definition: tv_rec.cpp:2239
SourceUtil::GetSourceName
static QString GetSourceName(uint sourceid)
Definition: sourceutil.cpp:47
JOB_LIVE_REC
@ JOB_LIVE_REC
Definition: jobqueue.h:61
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:392
SignalMonitor::IsAllGood
virtual bool IsAllGood(void) const
Definition: signalmonitor.h:81
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:507
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:542
MPEGStreamData::SetCaching
void SetCaching(bool cacheTables)
Definition: mpegstreamdata.h:91
ProgramInfo::SetRecordingID
virtual void SetRecordingID(uint _recordedid)
Definition: programinfo.h:582
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:669
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
ChannelChangeDirection
ChannelChangeDirection
ChannelChangeDirection is an enumeration of possible channel changing directions.
Definition: tv.h:31
eitscanner.h
RecStatus::Tuning
@ Tuning
Definition: recordingstatus.h:22
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:2541
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:3009
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:1779
MarkTypes
MarkTypes
Definition: programtypes.h:46
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:4621
RecorderBase::Unpause
virtual void Unpause(void)
Unpause tells recorder to unpause.
Definition: recorderbase.cpp:279
TVRec::kFlagRingBufferReady
static const uint kFlagRingBufferReady
Definition: tv_rec.h:483
ProgramInfo::GetRecordingID
uint GetRecordingID(void) const
Definition: programinfo.h:450
MythMediaBuffer::GetWritePosition
long long GetWritePosition(void) const
Returns how far into a ThreadedFileWriter file we have written.
Definition: mythmediabuffer.cpp:1796
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
MARK_ASPECT_2_21_1
@ MARK_ASPECT_2_21_1
Definition: programtypes.h:67
RecStatus::Cancelled
@ Cancelled
Definition: recordingstatus.h:26
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
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:1888
TVRec::SetInput
QString SetInput(QString input)
Changes to the specified input.
Definition: tv_rec.cpp:3117
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:3102
JobQueue::QueueRecordingJobs
static bool QueueRecordingJobs(const RecordingInfo &recinfo, int jobTypes=JOB_NONE)
Definition: jobqueue.cpp:485
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:204
kNotRecording
@ kNotRecording
Definition: recordingtypes.h:21
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:370
RecStatus::TunerBusy
@ TunerBusy
Definition: recordingstatus.h:24
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:4609
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:32
apply_broken_dvb_driver_crc_hack
static void apply_broken_dvb_driver_crc_hack(ChannelBase *, MPEGStreamData *)
Definition: tv_rec.cpp:4942
TuningRequest::toString
QString toString(void) const
Definition: tv_rec.cpp:4931
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:704
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:389
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
TVRec::EnableActiveScan
void EnableActiveScan(bool enable)
Definition: tv_rec.cpp:4904
osd.h
BROWSE_UP
@ BROWSE_UP
Fetch information on previous channel.
Definition: tv.h:44
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:3351
RecStatus::Recorded
@ Recorded
Definition: recordingstatus.h:29
TVRec::StopRecording
void StopRecording(bool killFile=false)
Changes from a recording state to kState_None.
Definition: tv_rec.cpp:748
RecorderBase::GetKeyframePositions
bool GetKeyframePositions(long long start, long long end, frm_pos_map_t &map) const
Definition: recorderbase.cpp:549
MythMediaBuffer
Definition: mythmediabuffer.h:59
DTVChannel::GetFormat
QString GetFormat(void)
Definition: dtvchannel.h:46
CHANNEL_DIRECTION_FAVORITE
@ CHANNEL_DIRECTION_FAVORITE
Definition: tv.h:35
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:398
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
FireWireDBOptions::m_speed
int m_speed
Definition: tv_rec.h:96
TVRec::GetFramesWritten
long long GetFramesWritten(void)
Returns number of frames written to disk by recorder.
Definition: tv_rec.cpp:2624
TVRec::GetDevices
static bool GetDevices(uint inputid, uint &parentid, GeneralDBOptions &gen_opts, DVBDBOptions &dvb_opts, FireWireDBOptions &firewire_opts)
Definition: tv_rec.cpp:1776
channelbase.h
ProgramInfo::UpdateInUseMark
void UpdateInUseMark(bool force=false)
Definition: programinfo.cpp:4984
TVRec::GetInput
QString GetInput(void) const
Returns current input.
Definition: tv_rec.cpp:3092
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
CHANNEL_DIRECTION_SAME
@ CHANNEL_DIRECTION_SAME
Definition: tv.h:36
RecordingQuality::IsDamaged
bool IsDamaged(void) const
Definition: recordingquality.cpp:108
mythsystemevent.h
kSingleRecord
@ kSingleRecord
Definition: recordingtypes.h:22
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:1333
TVRec::GetDTVChannel
DTVChannel * GetDTVChannel(void)
Definition: tv_rec.cpp:1263
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:2375
RecorderBase::Pause
virtual void Pause(bool clear=true)
Pause tells recorder to pause, it should not block.
Definition: recorderbase.cpp:269
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:413
ChannelBase::GetPictureAttribute
virtual int GetPictureAttribute(PictureAttribute) const
Definition: channelbase.h:94
ProgramInfo::GetRecordingGroup
QString GetRecordingGroup(void) const
Definition: programinfo.h:420
TVRec::GetChainID
QString GetChainID(void)
Get the chainid of the livetv instance.
Definition: tv_rec.cpp:2757
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:571
ProgramInfo::QueryTuningInfo
bool QueryTuningInfo(QString &channum, QString &input) const
Returns the channel and input needed to record the program.
Definition: programinfo.cpp:5368
GetPidsToCache
static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
Definition: tv_rec.cpp:1863
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:15
TVRec::m_pauseNotify
bool m_pauseNotify
Definition: tv_rec.h:392
dvbchannel.h
TVRec::TuningOnSameMultiplex
bool TuningOnSameMultiplex(TuningRequest &request)
Definition: tv_rec.cpp:3504
TVRec::TeardownRecorder
void TeardownRecorder(uint request_flags)
Tears down the recorder.
Definition: tv_rec.cpp:1189
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:405
TVRec::GetFilePosition
long long GetFilePosition(void)
Returns total number of bytes written by RingBuffer.
Definition: tv_rec.cpp:2639
ProgramInfo::GetPathname
QString GetPathname(void) const
Definition: programinfo.h:344
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:633
TVRec::SwitchRecordingRingBuffer
RecordingInfo * SwitchRecordingRingBuffer(const RecordingInfo &rcinfo)
Definition: tv_rec.cpp:4822
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:375
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
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:322
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:3000
MythDate::secsInFuture
std::chrono::seconds secsInFuture(const QDateTime &future)
Definition: mythdate.cpp:217
TableID::CVCT
@ CVCT
Definition: mpegtables.h:363
TVRec::m_pendingRecordings
PendingMap m_pendingRecordings
Definition: tv_rec.h:415
TRANSITION
#define TRANSITION(ASTATE, BSTATE)
Definition: tv_rec.cpp:1042
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:5175
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:1475
BROWSE_RIGHT
@ BROWSE_RIGHT
Fetch information on current channel in the future.
Definition: tv.h:47
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:2449
ProgramInfo::SaveVideoProperties
void SaveVideoProperties(uint mask, uint video_property_flags)
Definition: programinfo.cpp:4934
ProgramInfo::SetRecordingEndTime
void SetRecordingEndTime(const QDateTime &dt)
Definition: programinfo.h:530
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
CHANNEL_DIRECTION_DOWN
@ CHANNEL_DIRECTION_DOWN
Definition: tv.h:34
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:2981
programinfo.h
TVRec::NotifySchedulerOfRecording
void NotifySchedulerOfRecording(RecordingInfo *rec)
Tell scheduler about the recording.
Definition: tv_rec.cpp:2806
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:1335
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:391
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:451
TVRec::SetRecordingStatus
void SetRecordingStatus(RecStatus::Type new_status, int line, bool have_lock=false)
Definition: tv_rec.cpp:718
ProgramInfo::QueryAverageAspectRatio
MarkTypes QueryAverageAspectRatio(void) const
Definition: programinfo.cpp:4571
is_dishnet_eit
static bool is_dishnet_eit(uint inputid)
Definition: tv_rec.cpp:1298
DVBStreamData::SetDishNetEIT
void SetDishNetEIT(bool use_dishnet_eit)
Definition: dvbstreamdata.h:165
LiveTVChain::SetHostPrefix
void SetHostPrefix(const QString &prefix)
Definition: livetvchain.cpp:47
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:764
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:528
TuningRequest::m_progNum
int m_progNum
Definition: tv_rec.h:122
ProgramInfo::SetInputID
void SetInputID(uint id)
Definition: programinfo.h:544
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:1068
TVRec::m_recorder
RecorderBase * m_recorder
Definition: tv_rec.h:336
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1552
ChannelBase::StoreInputChannels
virtual void StoreInputChannels(void)
Saves current channel as the default channel for the current input.
Definition: channelbase.cpp:653
JOB_METADATA
@ JOB_METADATA
Definition: jobqueue.h:80
TVRec::GetMaxBitrate
long long GetMaxBitrate(void) const
Returns the maximum bits per second this recorder can produce.
Definition: tv_rec.cpp:2699
MythCoreContext::SendEvent
void SendEvent(const MythEvent &event)
Definition: mythcorecontext.cpp:1538
TVRec::kFlagRunMainLoop
static const uint kFlagRunMainLoop
Definition: tv_rec.h:441
ProgramInfo::SetRecordingRuleType
void SetRecordingRuleType(RecordingType type)
Definition: programinfo.h:585
TVRec::RemoveRecording
TVState RemoveRecording(TVState state) const
If "state" is kState_RecordingOnly or kState_WatchingLiveTV, returns a kState_None,...
Definition: tv_rec.cpp:795
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:4507
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:362
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:1055
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:52
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:225
TVRec::CheckChannel
bool CheckChannel(const QString &name) const
Checks if named channel exists on current tuner.
Definition: tv_rec.cpp:2329
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:531
TVRec::SetupSignalMonitor
bool SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
This creates a SignalMonitor instance and begins signal monitoring.
Definition: tv_rec.cpp:2093
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:3465
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:2147
COMM_FLAG_COMMFREE
@ COMM_FLAG_COMMFREE
Definition: programtypes.h:123
RecorderBase::GetRecordingQuality
virtual RecordingQuality * GetRecordingQuality(const RecordingInfo *ri) const
Returns a report about the current recordings quality.
Definition: recorderbase.cpp:513
TVRec::WaitForNextLiveTVDir
bool WaitForNextLiveTVDir(void)
Definition: tv_rec.cpp:4588
RecStatus::Failing
@ Failing
Definition: recordingstatus.h:18
MARK_ASPECT_16_9
@ MARK_ASPECT_16_9
Definition: programtypes.h:66
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:510
ProgramInfo::GetSourceID
uint GetSourceID(void) const
Definition: programinfo.h:466
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:211
JobQueue::JobIsNotInMask
static bool JobIsNotInMask(int job, int mask)
Definition: jobqueue.h:199
TVRec::CloseChannel
void CloseChannel(void)
Definition: tv_rec.cpp:1249
RecordingRule::m_type
RecordingType m_type
Definition: recordingrule.h:111
RecStatus::Aborted
@ Aborted
Definition: recordingstatus.h:28
JOB_COMMFLAG
@ JOB_COMMFLAG
Definition: jobqueue.h:79
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:1167
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:1945
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:1351
MythNotification::kError
static const Type kError
Definition: mythnotification.h:35
RecStatus::Failed
@ Failed
Definition: recordingstatus.h:23
TVRec::m_triggerEventLoopSignal
bool m_triggerEventLoopSignal
Definition: tv_rec.h:400
DTVRecorder::GetStreamData
MPEGStreamData * GetStreamData(void) const
Definition: dtvrecorder.h:58
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:2340
RecorderBase::IsRecording
virtual bool IsRecording(void)
Tells whether the StartRecorder() loop is running.
Definition: recorderbase.cpp:249
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:3632
TVRec::m_liveTVStartChannel
QString m_liveTVStartChannel
Definition: tv_rec.h:422
kState_Error
@ kState_Error
Error State, if we ever try to enter this state errored is set.
Definition: tv.h:57
storagegroup.h
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:66
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:212
TVRec::m_eitScanStartTime
QDateTime m_eitScanStartTime
Definition: tv_rec.h:396
TVRec::GetPictureAttribute
int GetPictureAttribute(PictureAttribute attr)
Definition: tv_rec.cpp:3058
TVRec::TuningNewRecorder
void TuningNewRecorder(MPEGStreamData *streamData)
Creates a recorder instance.
Definition: tv_rec.cpp:4234
RecordingInfo::StartedRecording
void StartedRecording(const QString &ext)
Inserts this RecordingInfo into the database as an existing recording.
Definition: recordinginfo.cpp:986
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:2672
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:26
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:92
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
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:4601
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:2609
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:712
TVRec::QueueEITChannelChange
bool QueueEITChannelChange(const QString &name)
Queues up a channel change for the EITScanner.
Definition: tv_rec.cpp:3192
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
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:916
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:3404
ChannelBase::SetFd
virtual void SetFd(int fd)
Sets file descriptor.
Definition: channelbase.h:55
RecordingInfo::LoadRecordingFile
void LoadRecordingFile()
Definition: recordinginfo.cpp:1743
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:2727
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:388
frm_pos_map_t
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
Definition: programtypes.h:44
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
RecorderBase::StopRecording
virtual void StopRecording(void)
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: recorderbase.cpp:230
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:1044
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:3219
JOB_NONE
@ JOB_NONE
Definition: jobqueue.h:75
SignalMonitor::HasExtraSlowTuning
virtual bool HasExtraSlowTuning(void) const
Definition: signalmonitor.h:60
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:910
dvbstreamdata.h
DTVSignalMonitor::SetProgramNumber
void SetProgramNumber(int progNum)
Definition: dtvsignalmonitor.cpp:214
kState_WatchingPreRecorded
@ kState_WatchingPreRecorded
Watching Pre-recorded is a TV only state for when we are watching a pre-existing recording.
Definition: tv.h:70
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
TVRec::GetKeyframePosition
int64_t GetKeyframePosition(uint64_t desired) const
Returns byte position in RingBuffer of a keyframe according to recorder.
Definition: tv_rec.cpp:2655
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
ProgramInfo::GetInputID
uint GetInputID(void) const
Definition: programinfo.h:467
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:601
ProgramInfo::SetChanID
void SetChanID(uint _chanid)
Definition: programinfo.h:526
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
kLiveTVAutoExpire
@ kLiveTVAutoExpire
Definition: programtypes.h:196
TableID::TVCT
@ TVCT
Definition: mpegtables.h:362
LiveTVChain::GetInputType
QString GetInputType(int pos=-1) const
Definition: livetvchain.cpp:698
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:373
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:2772
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:455
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
ProgramInfo::kTitleSubtitle
@ kTitleSubtitle
Definition: programinfo.h:513
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:212
TVRec::m_reachedRecordingDeadline
bool m_reachedRecordingDeadline
Definition: tv_rec.h:347
RecStatus::Recording
@ Recording
Definition: recordingstatus.h:30
TVRec::GetChannelInfo
bool GetChannelInfo(uint &chanid, uint &sourceid, QString &callsign, QString &channum, QString &channame, QString &xmltvid) const
Definition: tv_rec.cpp:3345
RecStatus::Inactive
@ Inactive
Definition: recordingstatus.h:42
ProgramInfo::ToStringList
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
Definition: programinfo.cpp:1276
SignalMonitor::AddListener
void AddListener(SignalMonitorListener *listener)
Definition: signalmonitor.cpp:385
mythcorecontext.h
TVRec::GetV4LChannel
V4LChannel * GetV4LChannel(void)
Definition: tv_rec.cpp:1268
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:352
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:3442
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:4424
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:671
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:4548
TVRec::SetupDTVSignalMonitor
bool SetupDTVSignalMonitor(bool EITscan)
Tells DTVSignalMonitor what channel to look for.
Definition: tv_rec.cpp:1913
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:126
TVRec::SetSignalMonitoringRate
std::chrono::milliseconds SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend=1)
Sets the signal monitoring rate.
Definition: tv_rec.cpp:2185
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:888
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
CHANNEL_DIRECTION_UP
@ CHANNEL_DIRECTION_UP
Definition: tv.h:33
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:1374
TVRec::FinishedRecording
void FinishedRecording(RecordingInfo *curRec, RecordingQuality *recq)
If not a premature stop, adds program to history of recorded programs.
Definition: tv_rec.cpp:857
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
TVState
TVState
TVState is an enumeration of the states used by TV and TVRec.
Definition: tv.h:53
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:63
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:1946
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:4754
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:785
ChannelBase::GetInputID
virtual int GetInputID(void) const
Definition: channelbase.h:67
RemoteRecordPending
bool RemoteRecordPending(uint inputid, const ProgramInfo *pginfo, std::chrono::seconds secsleft, bool hasLater)
Definition: tvremoteutil.cpp:50
StorageGroup
Definition: storagegroup.h:11
JOB_TRANSCODE
@ JOB_TRANSCODE
Definition: jobqueue.h:78
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:99
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
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:87
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:831
TVRec::InitAutoRunJobs
void InitAutoRunJobs(RecordingInfo *rec, AutoRunInitType t, RecordingProfile *recpro, int line)
Definition: tv_rec.cpp:2852
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:842
recordingprofile.h
TVRec::TVRec
TVRec(int _inputid)
Performs instance initialization not requiring access to database.
Definition: tv_rec.cpp:86
uint16_t
unsigned short uint16_t
Definition: iso6937tables.h:3
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:528
SignalMonitor::IsErrored
bool IsErrored(void) const
Definition: signalmonitor.h:82
BROWSE_DOWN
@ BROWSE_DOWN
Fetch information on next channel.
Definition: tv.h:45
ProgramInfo::SetRecordingRuleID
void SetRecordingRuleID(uint id)
Definition: programinfo.h:542
TVRec::TuningSignalCheck
MPEGStreamData * TuningSignalCheck(void)
This checks if we have a channel lock.
Definition: tv_rec.cpp:3964
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:203
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:1319
BROWSE_FAVORITE
@ BROWSE_FAVORITE
Fetch information on the next favorite channel.
Definition: tv.h:48
TVRec::SetVideoFiltersForChannel
bool SetVideoFiltersForChannel(uint sourceid, const QString &channum)
Definition: tv_rec.cpp:2510
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:1244
ChannelUtil::GetChanNum
static QString GetChanNum(int chan_id)
Returns the channel-number string of the given channel.
Definition: channelutil.cpp:777
RecordingInfo::GetRecordingRule
RecordingRule * GetRecordingRule(void)
Returns the "record" field, creating it if necessary.
Definition: recordinginfo.cpp:930
ProgramInfo::GetRecordingRuleID
uint GetRecordingRuleID(void) const
Definition: programinfo.h:453
TVRec::StartRecording
RecStatus::Type StartRecording(ProgramInfo *pginfo)
Tells TVRec to Start recording the program "rcinfo" as soon as possible.
Definition: tv_rec.cpp:438
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:3386
RecordingInfo::ApplyRecordRecGroupChange
void ApplyRecordRecGroupChange(const QString &newrecgroup)
Sets the recording group, both in this RecordingInfo and in the database.
Definition: recordinginfo.cpp:659
TVRec::SetLiveRecording
void SetLiveRecording(int recording)
Tells the Scheduler about changes to the recording status of the LiveTV recording.
Definition: tv_rec.cpp:2888
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:3143
TVRec::StopLiveTV
void StopLiveTV(void)
Tells TVRec to stop a "Live TV" recorder.
Definition: tv_rec.cpp:2934
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:1278
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:357
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:2239
ProgramInfo::QueryRecordingGroup
QString QueryRecordingGroup(void) const
Query recgroup from recorded.
Definition: programinfo.cpp:5084
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:1698
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:3721
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:811
TVRec::ChangePictureAttribute
int ChangePictureAttribute(PictureAdjustType type, PictureAttribute attr, bool direction)
Returns current value [0,100] if it succeeds, -1 otherwise.
Definition: tv_rec.cpp:3076
ApplyCachedPids
static bool ApplyCachedPids(DTVSignalMonitor *dtvMon, const DTVChannel *channel)
Definition: tv_rec.cpp:1880
TVRec::StateIsRecording
static bool StateIsRecording(TVState state)
Returns true if "state" is kState_RecordingOnly, or kState_WatchingLiveTV.
Definition: tv_rec.cpp:775
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:1727
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:4130
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:1014
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:3556
ProgramInfo::IsCommercialFree
bool IsCommercialFree(void) const
Definition: programinfo.h:481
RecorderBase::IsPaused
virtual bool IsPaused(bool holding_lock=false) const
Returns true iff recorder is paused.
Definition: recorderbase.cpp:287
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:4188
EITScanner
Acts as glue between ChannelBase, EITSource and EITHelper.
Definition: eitscanner.h:28
TVRec::GetDTVSignalMonitor
DTVSignalMonitor * GetDTVSignalMonitor(void)
Definition: tv_rec.cpp:2223
ProgramInfo::SetStorageGroup
void SetStorageGroup(const QString &group)
Definition: programinfo.h:534
TVRec::SetRingBuffer
void SetRingBuffer(MythMediaBuffer *Buffer)
Sets "ringBuffer", deleting any existing RingBuffer.
Definition: tv_rec.cpp:3425
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:2182
TVRec::ClearFlags
void ClearFlags(uint f, const QString &file, int line)
Definition: tv_rec.cpp:4498
TVRec::GetTVRec
static TVRec * GetTVRec(uint inputid)
Definition: tv_rec.cpp:4896
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::kLiveTVRecGroup
@ kLiveTVRecGroup
Definition: recordinginfo.h:192
RecordingInfo::SetDesiredEndTime
void SetDesiredEndTime(const QDateTime &dt)
Definition: recordinginfo.h:244
uint
unsigned int uint
Definition: freesurround.h:24
MythMediaBuffer::IsOpen
virtual bool IsOpen(void) const =0
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:902
BROWSE_LEFT
@ BROWSE_LEFT
Fetch information on current channel in the past.
Definition: tv.h:46
MythDeque::enqueue
void enqueue(const T &d)
Adds item to the back of the list. O(1).
Definition: mythdeque.h:41
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:113
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
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:498
FireWireDBOptions::m_model
QString m_model
Definition: tv_rec.h:98
ProgramInfo::GetSubtitle
QString GetSubtitle(void) const
Definition: programinfo.h:364
PictureAdjustType
PictureAdjustType
Definition: tv.h:123
eit_start_rand
static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout)
Definition: tv_rec.cpp:1336
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:529
TVRec::m_preFailDeadline
QDateTime m_preFailDeadline
Definition: tv_rec.h:348