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 "compat.h"
13 #include "previewgeneratorqueue.h"
14 #include "dtvsignalmonitor.h"
15 #include "recordingprofile.h"
16 #include "mythcorecontext.h"
17 #include "mythsystemevent.h"
18 #include "atscstreamdata.h"
19 #include "dvbstreamdata.h"
20 #include "recordingrule.h"
21 #include "channelgroup.h"
22 #include "storagegroup.h"
23 #include "tvremoteutil.h"
24 #include "dtvrecorder.h"
25 #include "livetvchain.h"
26 #include "programinfo.h"
27 #include "mythlogging.h"
28 #include "channelbase.h"
29 #include "atsctables.h"
30 #include "dtvchannel.h"
31 #include "eitscanner.h"
32 #include "mythconfig.h"
33 #include "remoteutil.h"
34 #include "io/mythmediabuffer.h"
35 #include "v4lchannel.h"
36 #include "cardutil.h"
37 #include "jobqueue.h"
38 #include "mythdb.h"
39 #include "tv_rec.h"
40 #include "mythdate.h"
41 #include "osd.h"
42 #include "../vboxutils.h"
43 
44 #define DEBUG_CHANNEL_PREFIX 0
46 #define LOC QString("TVRec[%1]: ").arg(m_inputId)
47 #define LOC2 QString("TVRec[%1]: ").arg(inputid) // for static functions
48 
49 QReadWriteLock TVRec::s_inputsLock;
50 QMap<uint,TVRec*> TVRec::s_inputs;
51 
52 static bool is_dishnet_eit(uint inputid);
53 static int init_jobs(const RecordingInfo *rec, RecordingProfile &profile,
54  bool on_host, bool transcode_bfr_comm, bool on_line_comm);
56 static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout);
57 
82 TVRec::TVRec(int inputid)
83  // Various threads
84  : m_eventThread(new MThread("TVRecEvent", this)),
85  // Configuration variables from setup routines
86  m_inputId(inputid)
87 {
88  s_inputs[m_inputId] = this;
89 }
90 
91 bool TVRec::CreateChannel(const QString &startchannel,
92  bool enter_power_save_mode)
93 {
94  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("CreateChannel(%1)")
95  .arg(startchannel));
96  // If this recorder is a child and its parent is not in error, we
97  // do not need nor want to set the channel.
98  bool setchan = true;
99  if (m_parentId)
100  {
101  TVRec *parentTV = GetTVRec(m_parentId);
102  if (parentTV && parentTV->GetState() != kState_Error)
103  setchan = false;
104  }
106  this, m_genOpt, m_dvbOpt, m_fwOpt,
107  startchannel, enter_power_save_mode, m_rbFileExt, setchan);
108 
109  if (m_genOpt.m_inputType == "VBOX")
110  {
112  {
113  // VBOX presence failed, recorder is marked errored
114  LOG(VB_GENERAL, LOG_ERR, LOC +
115  QString("CreateChannel(%1) failed due to VBOX not responding "
116  "to network check on inputid [%2]")
117  .arg(startchannel).arg(m_inputId));
118  m_channel = nullptr;
119  }
120  }
121 
122  if (!m_channel)
123  {
124  SetFlags(kFlagErrored, __FILE__, __LINE__);
125  return false;
126  }
127 
128  return true;
129 }
130 
136 bool TVRec::Init(void)
137 {
138  QMutexLocker lock(&m_stateChangeLock);
139 
141  return false;
142 
144 
145  // configure the Channel instance
146  QString startchannel = GetStartChannel(m_inputId);
147  if (!CreateChannel(startchannel, true))
148  return false;
149 
151  gCoreContext->GetBoolSetting("AutoTranscodeBeforeAutoCommflag", false);
152  m_earlyCommFlag = gCoreContext->GetBoolSetting("AutoCommflagWhileRecording", false);
153  m_runJobOnHostOnly = gCoreContext->GetBoolSetting("JobsRunOnRecordHost", false);
154  m_eitTransportTimeout = gCoreContext->GetDurSetting<std::chrono::minutes>("EITTransportTimeout", 5min);
155  if (m_eitTransportTimeout < 6s)
157  m_eitCrawlIdleStart = gCoreContext->GetDurSetting<std::chrono::seconds>("EITCrawIdleStart", 60s);
158  m_audioSampleRateDB = gCoreContext->GetNumSetting("AudioSampleRate");
159  m_overRecordSecNrml = gCoreContext->GetDurSetting<std::chrono::seconds>("RecordOverTime");
160  m_overRecordSecCat = gCoreContext->GetDurSetting<std::chrono::minutes>("CategoryOverTime");
161  m_overRecordCategory= gCoreContext->GetSetting("OverTimeCategory");
162 
163  m_eventThread->start();
164 
166 
167  return true;
168 }
169 
175 {
176  s_inputs.remove(m_inputId);
177 
179  {
180  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
181  m_eventThread->wait();
182  delete m_eventThread;
183  m_eventThread = nullptr;
184  }
185 
186  if (m_channel)
187  {
188  delete m_channel;
189  m_channel = nullptr;
190  }
191 }
192 
194 {
195  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownAll");
196 
198 
199  if (m_scanner)
200  {
201  delete m_scanner;
202  m_scanner = nullptr;
203  }
204 
206 
207  SetRingBuffer(nullptr);
208 }
209 
211 {
212  QMutexLocker locker(&m_triggerEventLoopLock);
214  m_triggerEventLoopWait.wakeAll();
215 }
216 
224 {
225  if (m_changeState)
226  return kState_ChangingState;
227  return m_internalState;
228 }
229 
238 {
239  QMutexLocker lock(&m_stateChangeLock);
240 
241  ProgramInfo *tmppginfo = nullptr;
242 
244  {
245  tmppginfo = new ProgramInfo(*m_curRecording);
247  }
248  else
249  tmppginfo = new ProgramInfo();
250  tmppginfo->SetInputID(m_inputId);
251 
252  return tmppginfo;
253 }
254 
269 void TVRec::RecordPending(const ProgramInfo *rcinfo, std::chrono::seconds secsleft,
270  bool hasLater)
271 {
272  QMutexLocker statelock(&m_stateChangeLock);
273  QMutexLocker pendlock(&m_pendingRecLock);
274 
275  if (secsleft < 0s)
276  {
277  LOG(VB_RECORD, LOG_INFO, LOC + "Pending recording revoked on " +
278  QString("inputid [%1]").arg(rcinfo->GetInputID()));
279 
280  PendingMap::iterator it = m_pendingRecordings.find(rcinfo->GetInputID());
281  if (it != m_pendingRecordings.end())
282  {
283  (*it).m_ask = false;
284  (*it).m_doNotAsk = (*it).m_canceled = true;
285  }
286  return;
287  }
288 
289  LOG(VB_RECORD, LOG_INFO, LOC +
290  QString("RecordPending on inputid [%1]").arg(rcinfo->GetInputID()));
291 
292  PendingInfo pending;
293  pending.m_info = new ProgramInfo(*rcinfo);
294  pending.m_recordingStart = MythDate::current().addSecs(secsleft.count());
295  pending.m_hasLaterShowing = hasLater;
296  pending.m_ask = true;
297  pending.m_doNotAsk = false;
298 
299  m_pendingRecordings[rcinfo->GetInputID()] = pending;
300 
301  // If this isn't a recording for this instance to make, we are done
302  if (rcinfo->GetInputID() != m_inputId)
303  return;
304 
305  // We also need to check our input groups
306  vector<uint> inputids = CardUtil::GetConflictingInputs(
307  rcinfo->GetInputID());
308 
309  m_pendingRecordings[rcinfo->GetInputID()].m_possibleConflicts = inputids;
310 
311  pendlock.unlock();
312  statelock.unlock();
313  for (uint inputid : inputids)
314  RemoteRecordPending(inputid, rcinfo, secsleft, hasLater);
315  statelock.relock();
316  pendlock.relock();
317 }
318 
323 {
326  delete old_rec;
327 }
328 
332 QDateTime TVRec::GetRecordEndTime(const ProgramInfo *pi) const
333 {
334  bool spcat = (!m_overRecordCategory.isEmpty() &&
336  std::chrono::seconds secs = (spcat) ? m_overRecordSecCat : m_overRecordSecNrml;
337  return pi->GetRecordingEndTime().addSecs(secs.count());
338 }
339 
345 void TVRec::CancelNextRecording(bool cancel)
346 {
347  QMutexLocker pendlock(&m_pendingRecLock);
348  LOG(VB_RECORD, LOG_INFO, LOC +
349  QString("CancelNextRecording(%1) -- begin").arg(cancel));
350 
351  PendingMap::iterator it = m_pendingRecordings.find(m_inputId);
352  if (it == m_pendingRecordings.end())
353  {
354  LOG(VB_RECORD, LOG_INFO, LOC + QString("CancelNextRecording(%1) -- "
355  "error, unknown recording").arg(cancel));
356  return;
357  }
358 
359  if (cancel)
360  {
361  vector<uint> &inputids = (*it).m_possibleConflicts;
362  for (uint inputid : inputids)
363  {
364  LOG(VB_RECORD, LOG_INFO, LOC +
365  QString("CancelNextRecording -- inputid 0x%1")
366  .arg((uint64_t)inputid,0,16));
367 
368  pendlock.unlock();
369  RemoteRecordPending(inputid, (*it).m_info, -1s, false);
370  pendlock.relock();
371  }
372 
373  LOG(VB_RECORD, LOG_INFO, LOC +
374  QString("CancelNextRecording -- inputid [%1]")
375  .arg(m_inputId));
376 
377  RecordPending((*it).m_info, -1s, false);
378  }
379  else
380  {
381  (*it).m_canceled = false;
382  }
383 
384  LOG(VB_RECORD, LOG_INFO, LOC +
385  QString("CancelNextRecording(%1) -- end").arg(cancel));
386 }
387 
396 {
397  RecordingInfo ri1(*pginfo);
400  RecordingInfo *rcinfo = &ri1;
401 
402  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartRecording(%1)")
403  .arg(rcinfo->toString(ProgramInfo::kTitleSubtitle)));
404 
405  QMutexLocker lock(&m_stateChangeLock);
406 
409 
410  // Flush out any pending state changes
412 
413  // We need to do this check early so we don't cancel an overrecord
414  // that we're trying to extend.
418  {
419  int post_roll_seconds = m_curRecording->GetRecordingEndTime()
420  .secsTo(m_recordEndTime);
421 
426 
428  .addSecs(post_roll_seconds);
429 
430  QString msg = QString("updating recording: %1 %2 %3 %4")
431  .arg(m_curRecording->GetTitle(),
432  QString::number(m_curRecording->GetChanID()),
435  LOG(VB_RECORD, LOG_INFO, LOC + msg);
436 
437  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
438 
440  return RecStatus::Recording;
441  }
442 
443  bool cancelNext = false;
444  PendingInfo pendinfo;
445  PendingMap::iterator it;
446 
447  m_pendingRecLock.lock();
448  if ((it = m_pendingRecordings.find(m_inputId)) != m_pendingRecordings.end())
449  {
450  (*it).m_ask = (*it).m_doNotAsk = false;
451  cancelNext = (*it).m_canceled;
452  }
453  m_pendingRecLock.unlock();
454 
455  // Flush out events...
457 
458  // Rescan pending recordings since the event loop may have deleted
459  // a stale entry. If this happens the info pointer will not be valid
460  // since the HandlePendingRecordings loop will have deleted it.
461  m_pendingRecLock.lock();
462  it = m_pendingRecordings.find(m_inputId);
463  bool has_pending = (it != m_pendingRecordings.end());
464  if (has_pending)
465  pendinfo = *it;
466  m_pendingRecLock.unlock();
467 
468  // If the needed input is in a shared input group, and we are
469  // not canceling the recording anyway, check other recorders
470  if (!cancelNext && has_pending && !pendinfo.m_possibleConflicts.empty())
471  {
472  LOG(VB_RECORD, LOG_INFO, LOC +
473  "Checking input group recorders - begin");
474  vector<uint> &inputids = pendinfo.m_possibleConflicts;
475 
476  uint mplexid = 0;
477  uint chanid = 0;
478  uint sourceid = 0;
479  vector<uint> inputids2;
480  vector<TVState> states;
481 
482  // Stop remote recordings if needed
483  for (uint inputid : inputids)
484  {
485  InputInfo busy_input;
486  bool is_busy = RemoteIsBusy(inputid, busy_input);
487 
488  if (is_busy && !sourceid)
489  {
490  mplexid = pendinfo.m_info->QueryMplexID();
491  chanid = pendinfo.m_info->GetChanID();
492  sourceid = pendinfo.m_info->GetSourceID();
493  }
494 
495  if (is_busy &&
496  ((sourceid != busy_input.m_sourceId) ||
497  (mplexid != busy_input.m_mplexId) ||
498  ((mplexid == 0 || mplexid == 32767) &&
499  chanid != busy_input.m_chanId)))
500  {
501  states.push_back((TVState) RemoteGetState(inputid));
502  inputids2.push_back(inputid);
503  }
504  }
505 
506  bool ok = true;
507  for (uint i = 0; (i < inputids2.size()) && ok; i++)
508  {
509  LOG(VB_RECORD, LOG_INFO, LOC +
510  QString("Attempting to stop input [%1] in state %2")
511  .arg(inputids2[i]).arg(StateToString(states[i])));
512 
513  bool success = RemoteStopRecording(inputids2[i]);
514  if (success)
515  {
516  uint state = RemoteGetState(inputids2[i]);
517  LOG(VB_GENERAL, LOG_INFO, LOC + QString("a [%1]: %2")
518  .arg(inputids2[i]).arg(StateToString((TVState)state)));
519  success = (kState_None == state);
520  }
521 
522  // If we managed to stop LiveTV recording, restart playback..
523  if (success && states[i] == kState_WatchingLiveTV)
524  {
525  QString message = QString("QUIT_LIVETV %1").arg(inputids2[i]);
526  MythEvent me(message);
527  gCoreContext->dispatch(me);
528  }
529 
530  LOG(VB_RECORD, LOG_INFO, LOC +
531  QString("Stopping recording on [%1], %2") .arg(inputids2[i])
532  .arg(success ? "succeeded" : "failed"));
533 
534  ok &= success;
535  }
536 
537  // If we failed to stop the remote recordings, don't record
538  if (!ok)
539  {
540  CancelNextRecording(true);
541  cancelNext = true;
542  }
543 
544  inputids.clear();
545 
546  LOG(VB_RECORD, LOG_INFO, LOC + "Checking input group recorders - done");
547  }
548 
549  bool did_switch = false;
550  if (!cancelNext && (GetState() == kState_RecordingOnly))
551  {
553  did_switch = (nullptr != ri2);
554  if (did_switch)
555  {
556  // Make sure scheduler is allowed to end this recording
557  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
558 
560  }
561  else
562  {
563  // If in post-roll, end recording
564  m_stateChangeLock.unlock();
565  StopRecording();
566  m_stateChangeLock.lock();
567  }
568  }
569 
570  if (!cancelNext && (GetState() == kState_None))
571  {
572  if (m_tvChain)
573  {
574  QString message = QString("LIVETV_EXITED");
575  MythEvent me(message, m_tvChain->GetID());
576  gCoreContext->dispatch(me);
577  m_tvChain->DecrRef();
578  m_tvChain = nullptr;
579  }
580 
582 
583  // Tell event loop to begin recording.
584  m_curRecording = new RecordingInfo(*rcinfo);
589 
590  // Make sure scheduler is allowed to end this recording
591  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
592 
595  else
596  LOG(VB_RECORD, LOG_WARNING, LOC + "Still failing.");
598  }
599  else if (!cancelNext && (GetState() == kState_WatchingLiveTV))
600  {
604 
605  // We want the frontend to change channel for recording
606  // and disable the UI for channel change, PiP, etc.
607 
608  QString message = QString("LIVETV_WATCH %1 1").arg(m_inputId);
609  QStringList prog;
610  rcinfo->ToStringList(prog);
611  MythEvent me(message, prog);
612  gCoreContext->dispatch(me);
613  }
614  else if (!did_switch)
615  {
616  QString msg = QString("Wanted to record: %1 %2 %3 %4\n\t\t\t")
617  .arg(rcinfo->GetTitle(),
618  QString::number(rcinfo->GetChanID()),
621 
622  if (cancelNext)
623  {
624  msg += "But a user has canceled this recording";
626  }
627  else
628  {
629  msg += QString("But the current state is: %1")
632  }
633 
635  {
636  msg += QString("\n\t\t\tCurrently recording: %1 %2 %3 %4")
637  .arg(m_curRecording->GetTitle(),
638  QString::number(m_curRecording->GetChanID()),
641  }
642 
643  LOG(VB_GENERAL, LOG_INFO, LOC + msg);
644  }
645 
646  for (const auto & pend : qAsConst(m_pendingRecordings))
647  delete pend.m_info;
648  m_pendingRecordings.clear();
649 
650  if (!did_switch)
651  {
653 
654  QMutexLocker locker(&m_pendingRecLock);
655  if ((m_curRecording) &&
660  {
661  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
662  }
663  return m_recStatus;
664  }
665 
666  return GetRecordingStatus();
667 }
668 
670 {
671  QMutexLocker pendlock(&m_pendingRecLock);
672  return m_recStatus;
673 }
674 
676  RecStatus::Type new_status, int line, bool have_lock)
677 {
678  RecStatus::Type old_status { RecStatus::Unknown };
679  if (have_lock)
680  {
681  old_status = m_recStatus;
682  m_recStatus = new_status;
683  }
684  else
685  {
686  m_pendingRecLock.lock();
687  old_status = m_recStatus;
688  m_recStatus = new_status;
689  m_pendingRecLock.unlock();
690  }
691 
692  LOG(VB_RECORD, LOG_INFO, LOC +
693  QString("SetRecordingStatus(%1->%2) on line %3")
694  .arg(RecStatus::toString(old_status, kSingleRecord),
695  RecStatus::toString(new_status, kSingleRecord),
696  QString::number(line)));
697 }
698 
705 void TVRec::StopRecording(bool killFile)
706 {
707  if (StateIsRecording(GetState()))
708  {
709  QMutexLocker lock(&m_stateChangeLock);
710  if (killFile)
711  SetFlags(kFlagKillRec, __FILE__, __LINE__);
712  else if (m_curRecording)
713  {
714  QDateTime now = MythDate::current(true);
715  if (now < m_curRecording->GetDesiredEndTime())
717  }
719  // wait for state change to take effect
721  ClearFlags(kFlagCancelNextRecording|kFlagKillRec, __FILE__, __LINE__);
722 
724  }
725 }
726 
733 {
734  return (state == kState_RecordingOnly ||
735  state == kState_WatchingLiveTV);
736 }
737 
743 {
744  return (state == kState_WatchingPreRecorded);
745 }
746 
753 {
754  if (StateIsRecording(state))
755  return kState_None;
756 
757  LOG(VB_GENERAL, LOG_ERR, LOC +
758  QString("Unknown state in RemoveRecording: %1")
759  .arg(StateToString(state)));
760  return kState_Error;
761 }
762 
769 {
770  if (StateIsPlaying(state))
771  {
772  if (state == kState_WatchingPreRecorded)
773  return kState_None;
774  return kState_RecordingOnly;
775  }
776 
777  QString msg = "Unknown state in RemovePlaying: %1";
778  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(StateToString(state)));
779 
780  return kState_Error;
781 }
782 
789 {
790  if (!curRec)
791  return;
792 
793  curRec->StartedRecording(m_rbFileExt);
794  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartedRecording(%1) fn(%2)")
795  .arg(curRec->MakeUniqueKey(), curRec->GetPathname()));
796 
797  if (curRec->IsCommercialFree())
799 
800  AutoRunInitType t = (curRec->GetRecordingGroup() == "LiveTV") ?
802  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
803 
804  SendMythSystemRecEvent("REC_STARTED", curRec);
805 }
806 
815 {
816  if (!curRec)
817  return;
818 
819  // Make sure the recording group is up to date
820  const QString recgrp = curRec->QueryRecordingGroup();
821  curRec->SetRecordingGroup(recgrp);
822 
823  bool is_good = true;
824  if (recq)
825  {
826  LOG((recq->IsDamaged()) ? VB_GENERAL : VB_RECORD, LOG_INFO,
827  LOC + QString("FinishedRecording(%1) %2 recq:\n%3")
828  .arg(curRec->MakeUniqueKey(),
829  (recq->IsDamaged()) ? "damaged" : "good",
830  recq->toStringXML()));
831  is_good = !recq->IsDamaged();
832  delete recq;
833  recq = nullptr;
834  }
835 
836  RecStatus::Type ors = curRec->GetRecordingStatus();
837  // Set the final recording status
838  if (curRec->GetRecordingStatus() == RecStatus::Recording)
840  else if (curRec->GetRecordingStatus() != RecStatus::Recorded)
842  curRec->SetRecordingEndTime(MythDate::current(true));
843  is_good &= (curRec->GetRecordingStatus() == RecStatus::Recorded);
844 
845  // Figure out if this was already done for this recording
846  bool was_finished = false;
847  static QMutex s_finRecLock;
848  static QHash<QString,QDateTime> s_finRecMap;
849  {
850  QMutexLocker locker(&s_finRecLock);
851  QDateTime now = MythDate::current();
852  QDateTime expired = now.addSecs(-60*5);
853  QHash<QString,QDateTime>::iterator it = s_finRecMap.begin();
854  while (it != s_finRecMap.end())
855  {
856  if ((*it) < expired)
857  it = s_finRecMap.erase(it);
858  else
859  ++it;
860  }
861  QString key = curRec->MakeUniqueKey();
862  it = s_finRecMap.find(key);
863  if (it != s_finRecMap.end())
864  was_finished = true;
865  else
866  s_finRecMap[key] = now;
867  }
868 
869  // Print something informative to the log
870  LOG(VB_RECORD, LOG_INFO, LOC +
871  QString("FinishedRecording(%1) %2 quality"
872  "\n\t\t\ttitle: %3\n\t\t\t"
873  "in recgroup: %4 status: %5:%6 %7 %8")
874  .arg(curRec->MakeUniqueKey(),
875  is_good ? "Good" : "Bad",
876  curRec->GetTitle(),
877  recgrp,
880  HasFlags(kFlagDummyRecorderRunning)?"is_dummy":"not_dummy",
881  was_finished?"already_finished":"finished_now"));
882 
883  // This has already been called on this recording..
884  if (was_finished)
885  return;
886 
887  // Notify the frontend watching live tv that this file is final
888  if (m_tvChain)
889  m_tvChain->FinishedRecording(curRec);
890 
891  // if this is a dummy recorder, do no more..
893  {
894  curRec->FinishedRecording(true); // so end time is updated
895  SendMythSystemRecEvent("REC_FINISHED", curRec);
896  return;
897  }
898 
899  // Get the width and set the videoprops
900  MarkTypes aspectRatio = curRec->QueryAverageAspectRatio();
901  uint avg_height = curRec->QueryAverageHeight();
902  bool progressive = curRec->QueryAverageScanProgressive();
903  curRec->SaveVideoProperties
904  (VID_4K | VID_1080 | VID_720 | VID_DAMAGED |
905  VID_WIDESCREEN | VID_PROGRESSIVE,
906  ((avg_height > 2000) ? VID_4K :
907  ((avg_height > 1000) ? VID_1080 :
908  ((avg_height > 700) ? VID_720 : 0))) |
909  (progressive ? VID_PROGRESSIVE : 0) |
910  ((is_good) ? 0 : VID_DAMAGED) |
911  (((aspectRatio == MARK_ASPECT_16_9) ||
912  (aspectRatio == MARK_ASPECT_2_21_1)) ? VID_WIDESCREEN : 0));
913 
914  // Make sure really short recordings have positive run time.
915  if (curRec->GetRecordingEndTime() <= curRec->GetRecordingStartTime())
916  {
917  curRec->SetRecordingEndTime(
918  curRec->GetRecordingStartTime().addSecs(60));
919  }
920 
921  // HACK Temporary hack, ensure we've loaded the recording file info, do it now
922  // so that it contains the final filesize information
923  if (!curRec->GetRecordingFile())
924  curRec->LoadRecordingFile();
925 
926  // Generate a preview
927  uint64_t fsize = curRec->GetFilesize();
928  if (curRec->IsLocal() && (fsize >= 1000) &&
930  {
932  }
933 
934  // store recording in recorded table
935  curRec->FinishedRecording(!is_good || (recgrp == "LiveTV"));
936 
937  // send out UPDATE_RECORDING_STATUS message
938  if (recgrp != "LiveTV")
939  {
940  LOG(VB_RECORD, LOG_INFO, LOC +
941  QString("FinishedRecording -- UPDATE_RECORDING_STATUS: %1")
942  .arg(RecStatus::toString(is_good ? curRec->GetRecordingStatus()
944  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
945  .arg(curRec->GetInputID())
946  .arg(curRec->GetChanID())
948  .arg(is_good ? curRec->GetRecordingStatus() : RecStatus::Failed)
949  .arg(curRec->GetRecordingEndTime(MythDate::ISODate)));
950  gCoreContext->dispatch(me);
951  }
952 
953  // send out REC_FINISHED message
954  SendMythSystemRecEvent("REC_FINISHED", curRec);
955 
956  // send out DONE_RECORDING message
957  auto secsSince = MythDate::secsInPast(curRec->GetRecordingStartTime());
958  QString message = QString("DONE_RECORDING %1 %2 %3")
959  .arg(m_inputId).arg(secsSince.count()).arg(GetFramesWritten());
960  MythEvent me(message);
961  gCoreContext->dispatch(me);
962 
963  // Handle JobQueue
964  QHash<QString,int>::iterator autoJob =
965  m_autoRunJobs.find(curRec->MakeUniqueKey());
966  if (autoJob == m_autoRunJobs.end())
967  {
968  LOG(VB_GENERAL, LOG_INFO,
969  "autoRunJobs not initialized until FinishedRecording()");
971  (recgrp == "LiveTV") ? kAutoRunNone : kAutoRunProfile;
972  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
973  autoJob = m_autoRunJobs.find(curRec->MakeUniqueKey());
974  }
975  LOG(VB_JOBQUEUE, LOG_INFO, QString("AutoRunJobs 0x%1").arg(*autoJob,0,16));
976  if ((recgrp == "LiveTV") || (fsize < 1000) ||
977  (curRec->GetRecordingStatus() != RecStatus::Recorded) ||
978  (curRec->GetRecordingStartTime().secsTo(
979  MythDate::current()) < 120))
980  {
983  }
984  if (*autoJob != JOB_NONE)
985  JobQueue::QueueRecordingJobs(*curRec, *autoJob);
986  m_autoRunJobs.erase(autoJob);
987 }
988 
989 #define TRANSITION(ASTATE,BSTATE) \
990  ((m_internalState == (ASTATE)) && (m_desiredNextState == (BSTATE)))
991 #define SET_NEXT() do { nextState = m_desiredNextState; changed = true; } while(false)
992 #define SET_LAST() do { nextState = m_internalState; changed = true; } while(false)
993 
1002 {
1003  TVState nextState = m_internalState;
1004 
1005  bool changed = false;
1006 
1007  QString transMsg = QString(" %1 to %2")
1008  .arg(StateToString(nextState), StateToString(m_desiredNextState));
1009 
1011  {
1012  LOG(VB_GENERAL, LOG_ERR, LOC +
1013  "HandleStateChange(): Null transition" + transMsg);
1014  m_changeState = false;
1015  return;
1016  }
1017 
1018  // Make sure EIT scan is stopped before any tuning,
1019  // to avoid race condition with it's tuning requests.
1021  {
1023  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1025  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1026  }
1027 
1028  // Handle different state transitions
1030  {
1032  SET_NEXT();
1033  }
1035  {
1037  SET_NEXT();
1038  }
1040  {
1041  SetPseudoLiveTVRecording(nullptr);
1042 
1043  SET_NEXT();
1044  }
1046  {
1047  SetPseudoLiveTVRecording(nullptr);
1049  SET_NEXT();
1050  }
1052  {
1055  (GetFlags()&kFlagKillRec)));
1056  SET_NEXT();
1057  }
1058 
1059  QString msg = (changed) ? "Changing from" : "Unknown state transition:";
1060  LOG(VB_GENERAL, LOG_INFO, LOC + msg + transMsg);
1061 
1062  // update internal state variable
1063  m_internalState = nextState;
1064  m_changeState = false;
1065 
1068  {
1070  m_eitScanStartTime = m_eitScanStartTime.addSecs(secs.count());
1071  }
1072  else
1073  {
1074  m_eitScanStartTime = m_eitScanStartTime.addYears(1);
1075  }
1076 }
1077 #undef TRANSITION
1078 #undef SET_NEXT
1079 #undef SET_LAST
1080 
1085 {
1086  QMutexLocker lock(&m_stateChangeLock);
1087  m_desiredNextState = nextState;
1088  m_changeState = true;
1089  WakeEventLoop();
1090 }
1091 
1106 void TVRec::TeardownRecorder(uint request_flags)
1107 {
1108  LOG(VB_RECORD, LOG_INFO, LOC + QString("TeardownRecorder(%1)")
1109  .arg((request_flags & kFlagKillRec) ? "kFlagKillRec" : ""));
1110 
1111  m_pauseNotify = false;
1112  m_isPip = false;
1113 
1115  {
1118  delete m_recorderThread;
1119  m_recorderThread = nullptr;
1120  }
1122  __FILE__, __LINE__);
1123 
1124  RecordingQuality *recq = nullptr;
1125  if (m_recorder)
1126  {
1127  if (GetV4LChannel())
1128  m_channel->SetFd(-1);
1129 
1131 
1132  QMutexLocker locker(&m_stateChangeLock);
1133  delete m_recorder;
1134  m_recorder = nullptr;
1135  }
1136 
1137  if (m_buffer)
1138  {
1139  LOG(VB_FILE, LOG_INFO, LOC + "calling StopReads()");
1140  m_buffer->StopReads();
1141  }
1142 
1143  if (m_curRecording)
1144  {
1145  if (!!(request_flags & kFlagKillRec))
1147 
1149 
1151  delete m_curRecording;
1152  m_curRecording = nullptr;
1153  }
1154 
1155  m_pauseNotify = true;
1156 
1157  if (GetDTVChannel())
1159 }
1160 
1162 {
1163  return dynamic_cast<DTVRecorder*>(m_recorder);
1164 }
1165 
1167 {
1168  if (m_channel &&
1169  ((m_genOpt.m_inputType == "DVB" && m_dvbOpt.m_dvbOnDemand) ||
1170  m_genOpt.m_inputType == "FREEBOX" ||
1171  m_genOpt.m_inputType == "VBOX" ||
1172  m_genOpt.m_inputType == "HDHOMERUN" ||
1173  m_genOpt.m_inputType == "EXTERNAL" ||
1175  {
1176  m_channel->Close();
1177  }
1178 }
1179 
1181 {
1182  return dynamic_cast<DTVChannel*>(m_channel);
1183 }
1184 
1186 {
1187 #ifdef USING_V4L2
1188  return dynamic_cast<V4LChannel*>(m_channel);
1189 #else
1190  return nullptr;
1191 #endif // USING_V4L2
1192 }
1193 
1194 static bool get_use_eit(uint inputid)
1195 {
1196  MSqlQuery query(MSqlQuery::InitCon());
1197  query.prepare(
1198  "SELECT SUM(useeit) "
1199  "FROM videosource, capturecard "
1200  "WHERE videosource.sourceid = capturecard.sourceid AND"
1201  " capturecard.cardid = :INPUTID");
1202  query.bindValue(":INPUTID", inputid);
1203 
1204  if (!query.exec() || !query.isActive())
1205  {
1206  MythDB::DBError("get_use_eit", query);
1207  return false;
1208  }
1209  if (query.next())
1210  return query.value(0).toBool();
1211  return false;
1212 }
1213 
1214 static bool is_dishnet_eit(uint inputid)
1215 {
1216  MSqlQuery query(MSqlQuery::InitCon());
1217  query.prepare(
1218  "SELECT SUM(dishnet_eit) "
1219  "FROM videosource, capturecard "
1220  "WHERE videosource.sourceid = capturecard.sourceid AND"
1221  " capturecard.cardid = :INPUTID");
1222  query.bindValue(":INPUTID", inputid);
1223 
1224  if (!query.exec() || !query.isActive())
1225  {
1226  MythDB::DBError("is_dishnet_eit", query);
1227  return false;
1228  }
1229  if (query.next())
1230  return query.value(0).toBool();
1231  return false;
1232 }
1233 
1234 // Number of capturecard instances including multirec instances
1235 static int num_inputs(void)
1236 {
1237  MSqlQuery query(MSqlQuery::InitCon());
1238 
1239  QString str =
1240  "SELECT COUNT(cardid) "
1241  "FROM capturecard ";
1242 
1243  query.prepare(str);
1244 
1245  if (!query.exec() || !query.isActive())
1246  {
1247  MythDB::DBError("num_inputs", query);
1248  return -1;
1249  }
1250  if (query.next())
1251  return query.value(0).toInt();
1252  return -1;
1253 }
1254 
1255 static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout)
1256 {
1257  // Randomize start time a bit
1258  auto timeout = std::chrono::seconds(MythRandom()) % (eitTransportTimeout.count() / 3);
1259 
1260  // Get the number of inputs and the position of the current input
1261  // to distribute the scan start evenly over eitTransportTimeout
1262  int no_inputs = num_inputs();
1263  if (no_inputs > 0)
1264  timeout += eitTransportTimeout * inputId / no_inputs;
1265 
1266  return timeout;
1267 }
1268 
1270 void TVRec::run(void)
1271 {
1272  QMutexLocker lock(&m_stateChangeLock);
1273  SetFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1274  ClearFlags(kFlagExitPlayer | kFlagFinishRecording, __FILE__, __LINE__);
1275 
1277 
1278  // Check whether we should use the EITScanner in this TVRec instance
1279  if (CardUtil::IsEITCapable(m_genOpt.m_inputType) && // Card type capable of receiving EIT?
1280  (!GetDTVChannel() || GetDTVChannel()->IsMaster()) && // Card is master and not a multirec instance
1281  (m_dvbOpt.m_dvbEitScan || get_use_eit(m_inputId))) // EIT is selected for card OR EIT is selected for video source
1282  {
1285  m_eitScanStartTime = m_eitScanStartTime.addSecs(secs.count());
1286  }
1287  else
1288  {
1289  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1290  }
1291 
1292  while (HasFlags(kFlagRunMainLoop))
1293  {
1294  // If there is a state change queued up, do it...
1295  if (m_changeState)
1296  {
1299  __FILE__, __LINE__);
1300  }
1301 
1302  // Quick exit on fatal errors.
1303  if (IsErrored())
1304  {
1305  LOG(VB_GENERAL, LOG_ERR, LOC +
1306  "RunTV encountered fatal error, exiting event thread.");
1307  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1308  TeardownAll();
1309  return;
1310  }
1311 
1312  // Handle any tuning events.. Blindly grabbing the lock here
1313  // can sometimes cause a deadlock with Init() while it waits
1314  // to make sure this thread starts. Until a better solution
1315  // is found, don't run HandleTuning unless we can safely get
1316  // the lock.
1317  if (s_inputsLock.tryLockForRead())
1318  {
1319  HandleTuning();
1320  s_inputsLock.unlock();
1321  }
1322 
1323  // Tell frontends about pending recordings
1325 
1326  // If we are recording a program, check if the recording is
1327  // over or someone has asked us to finish the recording.
1328  // Add an extra 60 seconds to the recording end time if we
1329  // might want a back to back recording.
1330  QDateTime recEnd = (!m_pendingRecordings.empty()) ?
1331  m_recordEndTime.addSecs(60) : m_recordEndTime;
1332  if ((GetState() == kState_RecordingOnly) &&
1333  (MythDate::current() > recEnd ||
1335  {
1337  ClearFlags(kFlagFinishRecording, __FILE__, __LINE__);
1338  }
1339 
1340  if (m_curRecording)
1341  {
1343 
1344  if (m_recorder)
1345  {
1347 
1348  // Check for recorder errors
1349  if (m_recorder->IsErrored())
1350  {
1352 
1354  {
1355  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
1356  MythEvent me(message);
1357  gCoreContext->dispatch(me);
1358  }
1359  else
1361  }
1362  }
1363  }
1364 
1365  // Check for the end of the current program..
1367  {
1368  QDateTime now = MythDate::current();
1369  bool has_finish = HasFlags(kFlagFinishRecording);
1370  bool has_rec = m_pseudoLiveTVRecording;
1371  bool enable_ui = true;
1372 
1373  m_pendingRecLock.lock();
1374  bool rec_soon =
1376  m_pendingRecLock.unlock();
1377 
1378  if (has_rec && (has_finish || (now > m_recordEndTime)))
1379  {
1380  SetPseudoLiveTVRecording(nullptr);
1381  }
1382  else if (!has_rec && !rec_soon && m_curRecording &&
1383  (now >= m_curRecording->GetScheduledEndTime()))
1384  {
1385  if (!m_switchingBuffer)
1386  {
1387  LOG(VB_RECORD, LOG_INFO, LOC +
1388  "Switching Buffer (" +
1389  QString("!has_rec(%1) && ").arg(has_rec) +
1390  QString("!rec_soon(%1) && (").arg(rec_soon) +
1391  MythDate::toString(now, MythDate::ISODate) + " >= " +
1393  QString("(%1) ))")
1394  .arg(now >= m_curRecording->GetScheduledEndTime()));
1395 
1396  m_switchingBuffer = true;
1397 
1399  false, true);
1400  }
1401  else
1402  {
1403  LOG(VB_RECORD, LOG_INFO, "Waiting for ringbuffer switch");
1404  }
1405  }
1406  else
1407  enable_ui = false;
1408 
1409  if (enable_ui)
1410  {
1411  LOG(VB_RECORD, LOG_INFO, LOC + "Enabling Full LiveTV UI.");
1412  QString message = QString("LIVETV_WATCH %1 0").arg(m_inputId);
1413  MythEvent me(message);
1414  gCoreContext->dispatch(me);
1415  }
1416  }
1417 
1418  // Check for ExitPlayer flag, and if set change to a non-watching
1419  // state (either kState_RecordingOnly or kState_None).
1421  {
1424  else if (StateIsPlaying(m_internalState))
1426  ClearFlags(kFlagExitPlayer, __FILE__, __LINE__);
1427  }
1428 
1429  // Start active EIT scan
1430  if (m_scanner && m_channel &&
1432  {
1433  if (!m_dvbOpt.m_dvbEitScan)
1434  {
1435  LOG(VB_EIT, LOG_INFO, LOC +
1436  "EIT scanning disabled for this input.");
1437  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1438  }
1439  else if (!get_use_eit(GetInputId()))
1440  {
1441  LOG(VB_EIT, LOG_INFO, LOC +
1442  "EIT scanning disabled for all channels on this input.");
1443  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1444  }
1445  else
1446  {
1447  // Check if another card in the same input group is
1448  // busy. This could be either virtual DVB-devices or
1449  // a second tuner on a single card
1450  s_inputsLock.lockForRead();
1451  bool allow_eit = true;
1452  vector<uint> inputids =
1454  InputInfo busy_input;
1455  for (uint i = 0; i < inputids.size() && allow_eit; ++i)
1456  allow_eit = !RemoteIsBusy(inputids[i], busy_input);
1457  if (allow_eit)
1458  {
1460  SetFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1462  QDateTime::currentDateTime().addYears(1);
1463  }
1464  else
1465  {
1466  LOG(VB_EIT, LOG_INFO, LOC + QString(
1467  "Postponing EIT scan on input [%1] "
1468  "because input %2 is busy")
1469  .arg(m_inputId).arg(busy_input.m_inputId));
1470  m_eitScanStartTime = m_eitScanStartTime.addSecs(300);
1471  }
1472  s_inputsLock.unlock();
1473  }
1474  }
1475 
1476  // We should be no more than a few thousand milliseconds,
1477  // as the end recording code does not have a trigger...
1478  // NOTE: If you change anything here, make sure that
1479  // WaitforEventThreadSleep() will still work...
1480  if (m_tuningRequests.empty() && !m_changeState)
1481  {
1482  lock.unlock(); // stateChangeLock
1483 
1484  {
1485  QMutexLocker locker(&m_triggerEventSleepLock);
1487  m_triggerEventSleepWait.wakeAll();
1488  }
1489 
1490  sched_yield();
1491 
1492  {
1493  QMutexLocker locker(&m_triggerEventLoopLock);
1494  // We check triggerEventLoopSignal because it is possible
1495  // that WakeEventLoop() was called since we
1496  // unlocked the stateChangeLock
1498  {
1500  &m_triggerEventLoopLock, 1000 /* ms */);
1501  }
1502  m_triggerEventLoopSignal = false;
1503  }
1504 
1505  lock.relock(); // stateChangeLock
1506  }
1507  }
1508 
1509  if (GetState() != kState_None)
1510  {
1513  }
1514 
1515  TeardownAll();
1516 }
1517 
1523 bool TVRec::WaitForEventThreadSleep(bool wake, std::chrono::milliseconds time)
1524 {
1525  bool ok = false;
1526  MythTimer t;
1527  t.start();
1528 
1529  while (!ok && (t.elapsed() < time))
1530  {
1531  MythTimer t2;
1532  t2.start();
1533 
1534  if (wake)
1535  WakeEventLoop();
1536 
1537  m_stateChangeLock.unlock();
1538 
1539  sched_yield();
1540 
1541  {
1542  QMutexLocker locker(&m_triggerEventSleepLock);
1545  m_triggerEventSleepSignal = false;
1546  }
1547 
1548  m_stateChangeLock.lock();
1549 
1550  // verify that we were triggered.
1551  ok = (m_tuningRequests.empty() && !m_changeState);
1552 
1553  std::chrono::milliseconds te = t2.elapsed();
1554  if (!ok && te < 10ms)
1555  std::this_thread::sleep_for(10ms - te);
1556  }
1557  return ok;
1558 }
1559 
1561 {
1562  QMutexLocker pendlock(&m_pendingRecLock);
1563 
1564  for (auto it = m_pendingRecordings.begin(); it != m_pendingRecordings.end();)
1565  {
1566  if (MythDate::current() > (*it).m_recordingStart.addSecs(30))
1567  {
1568  LOG(VB_RECORD, LOG_INFO, LOC + "Deleting stale pending recording " +
1569  QString("[%1] '%2'")
1570  .arg((*it).m_info->GetInputID())
1571  .arg((*it).m_info->GetTitle()));
1572 
1573  delete (*it).m_info;
1574  it = m_pendingRecordings.erase(it);
1575  }
1576  else
1577  {
1578  it++;
1579  }
1580  }
1581 
1582  if (m_pendingRecordings.empty())
1583  return;
1584 
1585  // Make sure EIT scan is stopped so it does't interfere
1587  {
1588  LOG(VB_CHANNEL, LOG_INFO,
1589  LOC + "Stopping active EIT scan for pending recording.");
1591  }
1592 
1593  // If we have a pending recording and AskAllowRecording
1594  // or DoNotAskAllowRecording is set and the frontend is
1595  // ready send an ASK_RECORDING query to frontend.
1596 
1597  bool has_rec = false;
1598  auto it = m_pendingRecordings.begin();
1599  if ((1 == m_pendingRecordings.size()) &&
1600  (*it).m_ask &&
1601  ((*it).m_info->GetInputID() == m_inputId) &&
1603  {
1605  has_rec = m_pseudoLiveTVRecording &&
1607  (*it).m_recordingStart);
1608  }
1609 
1610  for (it = m_pendingRecordings.begin(); it != m_pendingRecordings.end(); ++it)
1611  {
1612  if (!(*it).m_ask && !(*it).m_doNotAsk)
1613  continue;
1614 
1615  auto timeuntil = ((*it).m_doNotAsk) ?
1616  -1s: MythDate::secsInFuture((*it).m_recordingStart);
1617 
1618  if (has_rec)
1619  (*it).m_canceled = true;
1620 
1621  QString query = QString("ASK_RECORDING %1 %2 %3 %4")
1622  .arg(m_inputId)
1623  .arg(timeuntil.count())
1624  .arg(has_rec ? 1 : 0)
1625  .arg((*it).m_hasLaterShowing ? 1 : 0);
1626 
1627  LOG(VB_GENERAL, LOG_INFO, LOC + query);
1628 
1629  QStringList msg;
1630  (*it).m_info->ToStringList(msg);
1631  MythEvent me(query, msg);
1632  gCoreContext->dispatch(me);
1633 
1634  (*it).m_ask = (*it).m_doNotAsk = false;
1635  }
1636 }
1637 
1639  uint &parentid,
1640  GeneralDBOptions &gen_opts,
1641  DVBDBOptions &dvb_opts,
1642  FireWireDBOptions &firewire_opts)
1643 {
1644  int testnum = 0;
1645  QString test;
1646 
1647  MSqlQuery query(MSqlQuery::InitCon());
1648  query.prepare(
1649  "SELECT videodevice, vbidevice, audiodevice, "
1650  " audioratelimit, cardtype, "
1651  " skipbtaudio, signal_timeout, channel_timeout, "
1652  " dvb_wait_for_seqstart, "
1653  ""
1654  " dvb_on_demand, dvb_tuning_delay, dvb_eitscan,"
1655  ""
1656  " firewire_speed, firewire_model, firewire_connection, "
1657  " parentid "
1658  ""
1659  "FROM capturecard "
1660  "WHERE cardid = :INPUTID");
1661  query.bindValue(":INPUTID", inputid);
1662 
1663  if (!query.exec() || !query.isActive())
1664  {
1665  MythDB::DBError("getdevices", query);
1666  return false;
1667  }
1668 
1669  if (!query.next())
1670  return false;
1671 
1672  // General options
1673  test = query.value(0).toString();
1674  if (!test.isEmpty())
1675  gen_opts.m_videoDev = test;
1676 
1677  test = query.value(1).toString();
1678  if (!test.isEmpty())
1679  gen_opts.m_vbiDev = test;
1680 
1681  test = query.value(2).toString();
1682  if (!test.isEmpty())
1683  gen_opts.m_audioDev = test;
1684 
1685  gen_opts.m_audioSampleRate = std::max(testnum, query.value(3).toInt());
1686 
1687  test = query.value(4).toString();
1688  if (!test.isEmpty())
1689  gen_opts.m_inputType = test;
1690 
1691  gen_opts.m_skipBtAudio = query.value(5).toBool();
1692 
1693  gen_opts.m_signalTimeout = (uint) std::max(query.value(6).toInt(), 0);
1694  gen_opts.m_channelTimeout = (uint) std::max(query.value(7).toInt(), 0);
1695 
1696  // We should have at least 1000 ms to acquire tables...
1697  int table_timeout = ((int)gen_opts.m_channelTimeout -
1698  (int)gen_opts.m_signalTimeout);
1699  if (table_timeout < 1000)
1700  gen_opts.m_channelTimeout = gen_opts.m_signalTimeout + 1000;
1701 
1702  gen_opts.m_waitForSeqstart = query.value(8).toBool();
1703 
1704  // DVB options
1705  uint dvboff = 9;
1706  dvb_opts.m_dvbOnDemand = query.value(dvboff + 0).toBool();
1707  dvb_opts.m_dvbTuningDelay = std::chrono::milliseconds(query.value(dvboff + 1).toUInt());
1708  dvb_opts.m_dvbEitScan = query.value(dvboff + 2).toBool();
1709 
1710  // Firewire options
1711  uint fireoff = dvboff + 3;
1712  firewire_opts.m_speed = query.value(fireoff + 0).toUInt();
1713 
1714  test = query.value(fireoff + 1).toString();
1715  if (!test.isEmpty())
1716  firewire_opts.m_model = test;
1717 
1718  firewire_opts.m_connection = query.value(fireoff + 2).toUInt();
1719 
1720  parentid = query.value(15).toUInt();
1721 
1722  return true;
1723 }
1724 
1726 {
1727  QString startchan;
1728 
1729  LOG(VB_RECORD, LOG_INFO, LOC2 + QString("GetStartChannel for input %1")
1730  .arg(inputid));
1731 
1732  // Get last tuned channel from database, to use as starting channel
1733  MSqlQuery query(MSqlQuery::InitCon());
1734  query.prepare(
1735  "SELECT startchan "
1736  "FROM capturecard "
1737  "WHERE capturecard.cardid = :INPUTID");
1738  query.bindValue(":INPUTID", inputid);
1739 
1740  if (!query.exec() || !query.isActive())
1741  {
1742  MythDB::DBError("getstartchan", query);
1743  }
1744  else if (query.next())
1745  {
1746  startchan = query.value(0).toString();
1747  if (!startchan.isEmpty())
1748  {
1749  LOG(VB_CHANNEL, LOG_INFO, LOC2 + QString("Start channel: %1")
1750  .arg(startchan));
1751  return startchan;
1752  }
1753  }
1754 
1755  // If we failed to get the last tuned channel,
1756  // get a valid channel on our current input.
1757  query.prepare(
1758  "SELECT channum "
1759  "FROM capturecard, channel "
1760  "WHERE deleted IS NULL AND "
1761  " channel.sourceid = capturecard.sourceid AND "
1762  " capturecard.cardid = :INPUTID");
1763  query.bindValue(":INPUTID", inputid);
1764 
1765  if (!query.exec() || !query.isActive())
1766  {
1767  MythDB::DBError("getstartchan2", query);
1768  }
1769  while (query.next())
1770  {
1771  startchan = query.value(0).toString();
1772  if (!startchan.isEmpty())
1773  {
1774  LOG(VB_GENERAL, LOG_ERR, LOC2 + QString("Start channel from DB is "
1775  "empty, setting to '%1' instead.").arg(startchan));
1776  return startchan;
1777  }
1778  }
1779 
1780  // If we failed to get a channel on our current input,
1781  // widen search to any input.
1782  query.prepare(
1783  "SELECT channum, inputname "
1784  "FROM capturecard, channel "
1785  "WHERE deleted IS NULL AND "
1786  " channel.sourceid = capturecard.sourceid AND "
1787  " capturecard.cardid = :INPUTID");
1788  query.bindValue(":INPUTID", inputid);
1789 
1790  if (!query.exec() || !query.isActive())
1791  {
1792  MythDB::DBError("getstartchan3", query);
1793  }
1794  while (query.next())
1795  {
1796  startchan = query.value(0).toString();
1797  if (!startchan.isEmpty())
1798  {
1799  LOG(VB_GENERAL, LOG_ERR, LOC2 + QString("Start channel invalid, "
1800  "setting to '%1' on input %2 instead.")
1801  .arg(startchan, query.value(1).toString()));
1802  return startchan;
1803  }
1804  }
1805 
1806  // If there are no valid channels, just use a random channel
1807  startchan = "3";
1808  LOG(VB_GENERAL, LOG_ERR, LOC2 + QString("Problem finding starting channel, "
1809  "setting to default of '%1'.").arg(startchan));
1810  return startchan;
1811 }
1812 
1813 static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
1814 {
1815  if (!dtvMon->GetATSCStreamData())
1816  return;
1817 
1818  const MasterGuideTable *mgt = dtvMon->GetATSCStreamData()->GetCachedMGT();
1819  if (!mgt)
1820  return;
1821 
1822  for (uint i = 0; i < mgt->TableCount(); ++i)
1823  {
1824  pid_cache_item_t item(mgt->TablePID(i), mgt->TableType(i));
1825  pid_cache.push_back(item);
1826  }
1827  dtvMon->GetATSCStreamData()->ReturnCachedTable(mgt);
1828 }
1829 
1830 static bool ApplyCachedPids(DTVSignalMonitor *dtvMon, const DTVChannel* channel)
1831 {
1832  pid_cache_t pid_cache;
1833  channel->GetCachedPids(pid_cache);
1834  bool vctpid_cached = false;
1835  for (auto pid : pid_cache)
1836  {
1837  if ((pid.GetTableID() == TableID::TVCT) ||
1838  (pid.GetTableID() == TableID::CVCT))
1839  {
1840  vctpid_cached = true;
1841  dtvMon->GetATSCStreamData()->AddListeningPID(pid.GetPID());
1842  }
1843  }
1844  return vctpid_cached;
1845 }
1846 
1863 {
1864  LOG(VB_RECORD, LOG_INFO, LOC + "Setting up table monitoring.");
1865 
1867  DTVChannel *dtvchan = GetDTVChannel();
1868  if (!sm || !dtvchan)
1869  {
1870  LOG(VB_GENERAL, LOG_ERR, LOC + "Setting up table monitoring.");
1871  return false;
1872  }
1873 
1874  MPEGStreamData *sd = nullptr;
1875  if (GetDTVRecorder())
1876  {
1877  sd = GetDTVRecorder()->GetStreamData();
1878  sd->SetCaching(true);
1879  }
1880 
1881  QString recording_type = "all";
1885  const StandardSetting *setting = profile.byName("recordingtype");
1886  if (setting)
1887  recording_type = setting->getValue();
1888 
1889  const QString tuningmode = dtvchan->GetTuningMode();
1890 
1891  // Check if this is an ATSC Channel
1892  int major = dtvchan->GetMajorChannel();
1893  int minor = dtvchan->GetMinorChannel();
1894  if ((minor > 0) && (tuningmode == "atsc"))
1895  {
1896  QString msg = QString("ATSC channel: %1_%2").arg(major).arg(minor);
1897  LOG(VB_RECORD, LOG_INFO, LOC + msg);
1898 
1899  auto *asd = dynamic_cast<ATSCStreamData*>(sd);
1900  if (!asd)
1901  {
1902  sd = asd = new ATSCStreamData(major, minor, m_inputId);
1903  sd->SetCaching(true);
1904  if (GetDTVRecorder())
1905  GetDTVRecorder()->SetStreamData(asd);
1906  }
1907 
1908  asd->Reset();
1909  sm->SetStreamData(sd);
1910  sm->SetChannel(major, minor);
1911  sd->SetRecordingType(recording_type);
1912 
1913  // Try to get pid of VCT from cache and
1914  // require MGT if we don't have VCT pid.
1915  if (!ApplyCachedPids(sm, dtvchan))
1917 
1918  LOG(VB_RECORD, LOG_INFO, LOC +
1919  "Successfully set up ATSC table monitoring.");
1920  return true;
1921  }
1922 
1923  // Check if this is an DVB channel
1924  int progNum = dtvchan->GetProgramNumber();
1925  if ((progNum >= 0) && (tuningmode == "dvb") && (m_genOpt.m_inputType != "VBOX"))
1926  {
1927  int netid = dtvchan->GetOriginalNetworkID();
1928  int tsid = dtvchan->GetTransportID();
1929 
1930  auto *dsd = dynamic_cast<DVBStreamData*>(sd);
1931  if (!dsd)
1932  {
1933  sd = dsd = new DVBStreamData(netid, tsid, progNum, m_inputId);
1934  sd->SetCaching(true);
1935  if (GetDTVRecorder())
1936  GetDTVRecorder()->SetStreamData(dsd);
1937  }
1938 
1939  LOG(VB_RECORD, LOG_INFO, LOC +
1940  QString("DVB service_id %1 on net_id %2 tsid %3")
1941  .arg(progNum).arg(netid).arg(tsid));
1942 
1944 
1945  dsd->Reset();
1946  sm->SetStreamData(sd);
1947  sm->SetDVBService(netid, tsid, progNum);
1948  sd->SetRecordingType(recording_type);
1949 
1953  sm->SetRotorTarget(1.0F);
1954 
1955  if (EITscan)
1956  {
1958  sm->IgnoreEncrypted(true);
1959  }
1960 
1961  LOG(VB_RECORD, LOG_INFO, LOC +
1962  "Successfully set up DVB table monitoring.");
1963  return true;
1964  }
1965 
1966  // Check if this is an MPEG channel
1967  if (progNum >= 0)
1968  {
1969  if (!sd)
1970  {
1971  sd = new MPEGStreamData(progNum, m_inputId, true);
1972  sd->SetCaching(true);
1973  if (GetDTVRecorder())
1975  }
1976 
1977  QString msg = QString("MPEG program number: %1").arg(progNum);
1978  LOG(VB_RECORD, LOG_INFO, LOC + msg);
1979 
1981 
1982  sd->Reset();
1983  sm->SetStreamData(sd);
1984  sm->SetProgramNumber(progNum);
1985  sd->SetRecordingType(recording_type);
1986 
1990  sm->SetRotorTarget(1.0F);
1991 
1992  if (EITscan)
1993  {
1995  sm->IgnoreEncrypted(true);
1996  }
1997 
1998  LOG(VB_RECORD, LOG_INFO, LOC +
1999  "Successfully set up MPEG table monitoring.");
2000  return true;
2001  }
2002 
2003  // If this is not an ATSC, DVB or MPEG channel then check to make sure
2004  // that we have permanent pidcache entries.
2005  bool ok = false;
2006  if (GetDTVChannel())
2007  {
2008  pid_cache_t pid_cache;
2009  GetDTVChannel()->GetCachedPids(pid_cache);
2010  for (auto item = pid_cache.cbegin(); !ok && item != pid_cache.cend(); ++item)
2011  ok |= item->IsPermanent();
2012  }
2013 
2014  if (!ok)
2015  {
2016  QString msg = "No valid DTV info, ATSC maj(%1) min(%2), MPEG pn(%3)";
2017  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(major).arg(minor).arg(progNum));
2018  }
2019  else
2020  {
2021  LOG(VB_RECORD, LOG_INFO, LOC +
2022  "Successfully set up raw pid monitoring.");
2023  }
2024 
2025  return ok;
2026 }
2027 
2042 bool TVRec::SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
2043 {
2044  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetupSignalMonitor(%1, %2)")
2045  .arg(tablemon).arg(notify));
2046 
2047  // if it already exists, there no need to initialize it
2048  if (m_signalMonitor)
2049  return true;
2050 
2051  // if there is no channel object we can't monitor it
2052  if (!m_channel)
2053  return false;
2054 
2055  // nothing to monitor here either (DummyChannel)
2056  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
2057  return true;
2058 
2059  // make sure statics are initialized
2061 
2064  m_channel, false);
2065 
2066  if (m_signalMonitor)
2067  {
2068  LOG(VB_RECORD, LOG_INFO, LOC + "Signal monitor successfully created");
2069  // If this is a monitor for Digital TV, initialize table monitors
2070  if (GetDTVSignalMonitor() && tablemon &&
2071  !SetupDTVSignalMonitor(EITscan))
2072  {
2073  LOG(VB_GENERAL, LOG_ERR, LOC +
2074  "Failed to setup digital signal monitoring");
2075 
2076  return false;
2077  }
2078 
2081  kSignalMonitoringRate * 5 :
2084 
2085  // Start the monitoring thread
2087  }
2088 
2089  return true;
2090 }
2091 
2097 {
2098  if (!m_signalMonitor)
2099  return;
2100 
2101  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- begin");
2102 
2103  // If this is a DTV signal monitor, save any pids we know about.
2105  DTVChannel *dtvChan = GetDTVChannel();
2106  if (dtvMon && dtvChan)
2107  {
2108  pid_cache_t pid_cache;
2109  GetPidsToCache(dtvMon, pid_cache);
2110  if (!pid_cache.empty())
2111  dtvChan->SaveCachedPids(pid_cache);
2112  }
2113 
2114  if (m_signalMonitor)
2115  {
2116  delete m_signalMonitor;
2117  m_signalMonitor = nullptr;
2118  }
2119 
2120  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- end");
2121 }
2122 
2134 std::chrono::milliseconds TVRec::SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend)
2135 {
2136  QString msg = "SetSignalMonitoringRate(%1, %2)";
2137  LOG(VB_RECORD, LOG_INFO, LOC +
2138  msg.arg(rate.count()).arg(notifyFrontend) + "-- start");
2139 
2140  QMutexLocker lock(&m_stateChangeLock);
2141 
2143  {
2144  LOG(VB_GENERAL, LOG_ERR, LOC +
2145  "Signal Monitoring is notsupported by your hardware.");
2146  return 0ms;
2147  }
2148 
2150  {
2151  LOG(VB_GENERAL, LOG_ERR, LOC +
2152  "Signal can only be monitored in LiveTV Mode.");
2153  return 0ms;
2154  }
2155 
2156  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
2157 
2158  TuningRequest req = (rate > 0ms) ?
2161 
2163 
2164  // Wait for RingBuffer reset
2165  while (!HasFlags(kFlagRingBufferReady))
2167  LOG(VB_RECORD, LOG_INFO, LOC +
2168  msg.arg(rate.count()).arg(notifyFrontend) + " -- end");
2169  return 1ms;
2170 }
2171 
2173 {
2174  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
2175 }
2176 
2188 bool TVRec::ShouldSwitchToAnotherInput(const QString& chanid) const
2189 {
2190  QString msg("");
2191  MSqlQuery query(MSqlQuery::InitCon());
2192 
2193  if (!query.isConnected())
2194  return false;
2195 
2196  query.prepare("SELECT channel.channum, channel.callsign "
2197  "FROM channel "
2198  "WHERE channel.chanid = :CHANID");
2199  query.bindValue(":CHANID", chanid);
2200  if (!query.exec() || !query.next())
2201  {
2202  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2203  return false;
2204  }
2205 
2206  QString channelname = query.value(0).toString();
2207  QString callsign = query.value(1).toString();
2208 
2209  query.prepare(
2210  "SELECT channel.channum "
2211  "FROM channel, capturecard "
2212  "WHERE deleted IS NULL AND "
2213  " ( channel.chanid = :CHANID OR "
2214  " ( channel.channum = :CHANNUM AND "
2215  " channel.callsign = :CALLSIGN ) "
2216  " ) AND "
2217  " channel.sourceid = capturecard.sourceid AND "
2218  " capturecard.cardid = :INPUTID");
2219  query.bindValue(":CHANID", chanid);
2220  query.bindValue(":CHANNUM", channelname);
2221  query.bindValue(":CALLSIGN", callsign);
2222  query.bindValue(":INPUTID", m_inputId);
2223 
2224  if (!query.exec() || !query.isActive())
2225  {
2226  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2227  }
2228  else if (query.size() > 0)
2229  {
2230  msg = "Found channel (%1) on current input[%2].";
2231  LOG(VB_RECORD, LOG_INFO, LOC + msg.arg(channelname).arg(m_inputId));
2232  return false;
2233  }
2234 
2235  // We didn't find it on the current input, so now we check other inputs.
2236  query.prepare(
2237  "SELECT channel.channum, capturecard.cardid "
2238  "FROM channel, capturecard "
2239  "WHERE deleted IS NULL AND "
2240  " ( channel.chanid = :CHANID OR "
2241  " ( channel.channum = :CHANNUM AND "
2242  " channel.callsign = :CALLSIGN ) "
2243  " ) AND "
2244  " channel.sourceid = capturecard.sourceid AND "
2245  " capturecard.cardid != :INPUTID");
2246  query.bindValue(":CHANID", chanid);
2247  query.bindValue(":CHANNUM", channelname);
2248  query.bindValue(":CALLSIGN", callsign);
2249  query.bindValue(":INPUTID", m_inputId);
2250 
2251  if (!query.exec() || !query.isActive())
2252  {
2253  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2254  }
2255  else if (query.next())
2256  {
2257  msg = QString("Found channel (%1) on different input(%2).")
2258  .arg(query.value(0).toString(), query.value(1).toString());
2259  LOG(VB_RECORD, LOG_INFO, LOC + msg);
2260  return true;
2261  }
2262 
2263  msg = QString("Did not find channel(%1) on any input.").arg(channelname);
2264  LOG(VB_RECORD, LOG_ERR, LOC + msg);
2265  return false;
2266 }
2267 
2278 bool TVRec::CheckChannel(const QString& name) const
2279 {
2280  if (!m_channel)
2281  return false;
2282 
2283  return m_channel->CheckChannel(name);
2284 }
2285 
2289 static QString add_spacer(const QString &channel, const QString &spacer)
2290 {
2291  QString chan = channel;
2292  if ((chan.length() >= 2) && !spacer.isEmpty())
2293  return chan.left(chan.length()-1) + spacer + chan.right(1);
2294  return chan;
2295 }
2296 
2324 bool TVRec::CheckChannelPrefix(const QString &prefix,
2325  uint &complete_valid_channel_on_rec,
2326  bool &is_extra_char_useful,
2327  QString &needed_spacer) const
2328 {
2329 #if DEBUG_CHANNEL_PREFIX
2330  LOG(VB_GENERAL, LOG_DEBUG, QString("CheckChannelPrefix(%1)").arg(prefix));
2331 #endif
2332 
2333  static const std::array<const QString,5> s_spacers = { "", "_", "-", "#", "." };
2334 
2335  MSqlQuery query(MSqlQuery::InitCon());
2336  QString basequery = QString(
2337  "SELECT channel.chanid, channel.channum, capturecard.cardid "
2338  "FROM channel, capturecard "
2339  "WHERE deleted IS NULL AND "
2340  " channel.channum LIKE '%1%' AND "
2341  " channel.sourceid = capturecard.sourceid");
2342 
2343  const std::array<const QString,2> inputquery
2344  {
2345  QString(" AND capturecard.cardid = '%1'").arg(m_inputId),
2346  QString(" AND capturecard.cardid != '%1'").arg(m_inputId),
2347  };
2348 
2349  vector<uint> fchanid;
2350  vector<QString> fchannum;
2351  vector<uint> finputid;
2352  vector<QString> fspacer;
2353 
2354  for (const auto & str : inputquery)
2355  {
2356  for (const auto & spacer : s_spacers)
2357  {
2358  QString qprefix = add_spacer(
2359  prefix, (spacer == "_") ? "\\_" : spacer);
2360  query.prepare(basequery.arg(qprefix) + str);
2361 
2362  if (!query.exec() || !query.isActive())
2363  {
2364  MythDB::DBError("checkchannel -- locate channum", query);
2365  }
2366  else if (query.size())
2367  {
2368  while (query.next())
2369  {
2370  fchanid.push_back(query.value(0).toUInt());
2371  fchannum.push_back(query.value(1).toString());
2372  finputid.push_back(query.value(2).toUInt());
2373  fspacer.emplace_back(spacer);
2374 #if DEBUG_CHANNEL_PREFIX
2375  LOG(VB_GENERAL, LOG_DEBUG,
2376  QString("(%1,%2) Adding %3 rec %4")
2377  .arg(i).arg(j).arg(query.value(1).toString(),6)
2378  .arg(query.value(2).toUInt()));
2379 #endif
2380  }
2381  }
2382 
2383  if (prefix.length() < 2)
2384  break;
2385  }
2386  }
2387 
2388  // Now process the lists for the info we need...
2389  is_extra_char_useful = false;
2390  complete_valid_channel_on_rec = 0;
2391  needed_spacer.clear();
2392 
2393  if (fchanid.empty())
2394  return false;
2395 
2396  if (fchanid.size() == 1) // Unique channel...
2397  {
2398  needed_spacer = fspacer[0];
2399  bool nc = (fchannum[0] != add_spacer(prefix, fspacer[0]));
2400 
2401  complete_valid_channel_on_rec = (nc) ? 0 : finputid[0];
2402  is_extra_char_useful = nc;
2403  return true;
2404  }
2405 
2406  // If we get this far there is more than one channel
2407  // sharing the prefix we were given.
2408 
2409  // Is an extra characher useful for disambiguation?
2410  is_extra_char_useful = false;
2411  for (uint i = 0; (i < fchannum.size()) && !is_extra_char_useful; i++)
2412  {
2413  is_extra_char_useful = (fchannum[i] != add_spacer(prefix, fspacer[i]));
2414 #if DEBUG_CHANNEL_PREFIX
2415  LOG(VB_GENERAL, LOG_DEBUG, QString("is_extra_char_useful(%1!=%2): %3")
2416  .arg(fchannum[i]).arg(add_spacer(prefix, fspacer[i]))
2417  .arg(is_extra_char_useful));
2418 #endif
2419  }
2420 
2421  // Are any of the channels complete w/o spacer?
2422  // If so set complete_valid_channel_on_rec,
2423  // with a preference for our inputid.
2424  for (size_t i = 0; i < fchannum.size(); i++)
2425  {
2426  if (fchannum[i] == prefix)
2427  {
2428  complete_valid_channel_on_rec = finputid[i];
2429  if (finputid[i] == m_inputId)
2430  break;
2431  }
2432  }
2433 
2434  if (complete_valid_channel_on_rec != 0)
2435  return true;
2436 
2437  // Add a spacer, if one is needed to select a valid channel.
2438  bool spacer_needed = true;
2439  for (uint i = 0; (i < fspacer.size() && spacer_needed); i++)
2440  spacer_needed = !fspacer[i].isEmpty();
2441  if (spacer_needed)
2442  needed_spacer = fspacer[0];
2443 
2444  // If it isn't useful to wait for more characters,
2445  // then try to commit to any true match immediately.
2446  for (size_t i = 0; i < ((is_extra_char_useful) ? 0 : fchanid.size()); i++)
2447  {
2448  if (fchannum[i] == add_spacer(prefix, fspacer[i]))
2449  {
2450  needed_spacer = fspacer[i];
2451  complete_valid_channel_on_rec = finputid[i];
2452  return true;
2453  }
2454  }
2455 
2456  return true;
2457 }
2458 
2460  const QString &channum)
2461 {
2462  if (!m_recorder)
2463  return false;
2464 
2465  QString videoFilters = ChannelUtil::GetVideoFilters(sourceid, channum);
2466  if (!videoFilters.isEmpty())
2467  {
2468  m_recorder->SetVideoFilters(videoFilters);
2469  return true;
2470  }
2471 
2472  return false;
2473 }
2474 
2480 {
2481  return ((m_recorder && m_recorder->IsRecording()) ||
2483 }
2484 
2490 bool TVRec::IsBusy(InputInfo *busy_input, std::chrono::seconds time_buffer) const
2491 {
2492  InputInfo dummy;
2493  if (!busy_input)
2494  busy_input = &dummy;
2495 
2496  busy_input->Clear();
2497 
2498  if (!m_channel)
2499  return false;
2500 
2501  if (!m_channel->GetInputID())
2502  return false;
2503 
2504  uint chanid = 0;
2505 
2506  if (GetState() != kState_None)
2507  {
2508  busy_input->m_inputId = m_channel->GetInputID();
2509  chanid = m_channel->GetChanID();
2510  }
2511 
2512  PendingInfo pendinfo;
2513  bool has_pending = false;
2514  {
2515  m_pendingRecLock.lock();
2516  PendingMap::const_iterator it = m_pendingRecordings.find(m_inputId);
2517  has_pending = (it != m_pendingRecordings.end());
2518  if (has_pending)
2519  pendinfo = *it;
2520  m_pendingRecLock.unlock();
2521  }
2522 
2523  if (!busy_input->m_inputId && has_pending)
2524  {
2525  auto timeLeft = MythDate::secsInFuture(pendinfo.m_recordingStart);
2526 
2527  if (timeLeft <= time_buffer)
2528  {
2529  QString channum;
2530  QString input;
2531  if (pendinfo.m_info->QueryTuningInfo(channum, input))
2532  {
2533  busy_input->m_inputId = m_channel->GetInputID();
2534  chanid = pendinfo.m_info->GetChanID();
2535  }
2536  }
2537  }
2538 
2539  if (busy_input->m_inputId)
2540  {
2541  CardUtil::GetInputInfo(*busy_input);
2542  busy_input->m_chanId = chanid;
2543  busy_input->m_mplexId = ChannelUtil::GetMplexID(busy_input->m_chanId);
2544  busy_input->m_mplexId =
2545  (32767 == busy_input->m_mplexId) ? 0 : busy_input->m_mplexId;
2546  }
2547 
2548  return busy_input->m_inputId != 0U;
2549 }
2550 
2551 
2559 {
2560  QMutexLocker lock(&m_stateChangeLock);
2561 
2562  if (m_recorder)
2563  return m_recorder->GetFrameRate();
2564  return -1.0F;
2565 }
2566 
2574 {
2575  QMutexLocker lock(&m_stateChangeLock);
2576 
2577  if (m_recorder)
2578  return m_recorder->GetFramesWritten();
2579  return -1;
2580 }
2581 
2588 long long TVRec::GetFilePosition(void)
2589 {
2590  QMutexLocker lock(&m_stateChangeLock);
2591 
2592  if (m_buffer)
2593  return m_buffer->GetWritePosition();
2594  return -1;
2595 }
2596 
2604 int64_t TVRec::GetKeyframePosition(uint64_t desired) const
2605 {
2606  QMutexLocker lock(&m_stateChangeLock);
2607 
2608  if (m_recorder)
2609  return m_recorder->GetKeyframePosition(desired);
2610  return -1;
2611 }
2612 
2622  int64_t start, int64_t end, frm_pos_map_t &map) const
2623 {
2624  QMutexLocker lock(&m_stateChangeLock);
2625 
2626  if (m_recorder)
2627  return m_recorder->GetKeyframePositions(start, end, map);
2628 
2629  return false;
2630 }
2631 
2633  int64_t start, int64_t end, frm_pos_map_t &map) const
2634 {
2635  QMutexLocker lock(&m_stateChangeLock);
2636 
2637  if (m_recorder)
2638  return m_recorder->GetKeyframeDurations(start, end, map);
2639 
2640  return false;
2641 }
2642 
2648 long long TVRec::GetMaxBitrate(void) const
2649 {
2650  long long bitrate = 0;
2651  if (m_genOpt.m_inputType == "MPEG")
2652  { // NOLINT(bugprone-branch-clone)
2653  bitrate = 10080000LL; // use DVD max bit rate
2654  }
2655  else if (m_genOpt.m_inputType == "HDPVR")
2656  {
2657  bitrate = 20200000LL; // Peak bit rate for HD-PVR
2658  }
2660  {
2661  bitrate = 22200000LL; // 1080i
2662  }
2663  else // frame grabber
2664  {
2665  bitrate = 10080000LL; // use DVD max bit rate, probably too big
2666  }
2667 
2668  return bitrate;
2669 }
2670 
2676 void TVRec::SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
2677 {
2678  QMutexLocker lock(&m_stateChangeLock);
2679 
2680  m_tvChain = newchain;
2681  m_tvChain->IncrRef(); // mark it for TVRec use
2682  m_tvChain->ReloadAll();
2683 
2684  QString hostprefix = MythCoreContext::GenMythURL(
2687 
2688  m_tvChain->SetHostPrefix(hostprefix);
2690 
2691  m_isPip = pip;
2692  m_liveTVStartChannel = std::move(startchan);
2693 
2694  // Change to WatchingLiveTV
2696  // Wait for state change to take effect
2698 
2699  // Make sure StartRecording can't steal our tuner
2700  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2701 }
2702 
2706 QString TVRec::GetChainID(void)
2707 {
2708  if (m_tvChain)
2709  return m_tvChain->GetID();
2710  return "";
2711 }
2712 
2722 {
2723  QMutexLocker lock(&m_stateChangeLock);
2724 
2726  return; // already stopped
2727 
2728  if (!m_curRecording)
2729  return;
2730 
2731  const QString recgrp = m_curRecording->QueryRecordingGroup();
2733 
2734  if (recgrp != "LiveTV" && !m_pseudoLiveTVRecording)
2735  {
2736  // User wants this recording to continue
2738  }
2739  else if (recgrp == "LiveTV" && m_pseudoLiveTVRecording)
2740  {
2741  // User wants to abandon scheduled recording
2742  SetPseudoLiveTVRecording(nullptr);
2743  }
2744 }
2745 
2756 {
2757  if (!m_channel)
2758  return;
2759 
2760  // Notify scheduler of the recording.
2761  // + set up recording so it can be resumed
2762  rec->SetInputID(m_inputId);
2764 
2765  if (rec->GetRecordingRuleType() == kNotRecording)
2766  {
2769  }
2770 
2771  // + remove any end offset which would mismatch the live session
2772  rec->GetRecordingRule()->m_endOffset = 0;
2773 
2774  // + save RecStatus::Inactive recstatus to so that a reschedule call
2775  // doesn't start recording this on another input before we
2776  // send the SCHEDULER_ADD_RECORDING message to the scheduler.
2778  rec->AddHistory(false);
2779 
2780  // + save RecordingRule so that we get a recordid
2781  // (don't allow RescheduleMatch(), avoiding unneeded reschedule)
2782  rec->GetRecordingRule()->Save(false);
2783 
2784  // + save recordid to recorded entry
2785  rec->ApplyRecordRecID();
2786 
2787  // + set proper recstatus (saved later)
2789 
2790  // + pass proginfo to scheduler and reschedule
2791  QStringList prog;
2792  rec->ToStringList(prog);
2793  MythEvent me("SCHEDULER_ADD_RECORDING", prog);
2794  gCoreContext->dispatch(me);
2795 
2796  // Allow scheduler to end this recording before post-roll,
2797  // if it has another recording for this recorder.
2798  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2799 }
2800 
2802  RecordingProfile *recpro, int line)
2803 {
2804  if (kAutoRunProfile == t)
2805  {
2807  if (!recpro)
2808  {
2809  LoadProfile(nullptr, rec, profile);
2810  recpro = &profile;
2811  }
2812  m_autoRunJobs[rec->MakeUniqueKey()] =
2813  init_jobs(rec, *recpro, m_runJobOnHostOnly,
2815  }
2816  else
2817  {
2819  }
2820  LOG(VB_JOBQUEUE, LOG_INFO,
2821  QString("InitAutoRunJobs for %1, line %2 -> 0x%3")
2822  .arg(rec->MakeUniqueKey()).arg(line)
2823  .arg(m_autoRunJobs[rec->MakeUniqueKey()],0,16));
2824 }
2825 
2837 void TVRec::SetLiveRecording(int recording)
2838 {
2839  LOG(VB_GENERAL, LOG_INFO, LOC +
2840  QString("SetLiveRecording(%1)").arg(recording));
2841  QMutexLocker locker(&m_stateChangeLock);
2842 
2843  (void) recording;
2844 
2846  bool was_rec = m_pseudoLiveTVRecording;
2848  if (was_rec && !m_pseudoLiveTVRecording)
2849  {
2850  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- cancel");
2851  // cancel -- 'recording' should be 0 or -1
2852  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2853  m_curRecording->SetRecordingGroup("LiveTV");
2854  InitAutoRunJobs(m_curRecording, kAutoRunNone, nullptr, __LINE__);
2855  }
2856  else if (!was_rec && m_pseudoLiveTVRecording)
2857  {
2858  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- record");
2859  // record -- 'recording' should be 1 or -1
2860 
2861  // If the last recording was flagged for keeping
2862  // in the frontend, then add the recording rule
2863  // so that transcode, commfrag, etc can be run.
2866  recstat = m_curRecording->GetRecordingStatus();
2867  m_curRecording->SetRecordingGroup("Default");
2868  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
2869  }
2870 
2871  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
2872  .arg(m_curRecording->GetInputID())
2873  .arg(m_curRecording->GetChanID())
2875  .arg(recstat)
2877 
2878  gCoreContext->dispatch(me);
2879 }
2880 
2886 {
2887  QMutexLocker lock(&m_stateChangeLock);
2888  LOG(VB_RECORD, LOG_INFO, LOC +
2889  QString("StopLiveTV(void) curRec: 0x%1 pseudoRec: 0x%2")
2890  .arg((uint64_t)m_curRecording,0,16)
2891  .arg((uint64_t)m_pseudoLiveTVRecording,0,16));
2892 
2894  return;
2895 
2896  bool hadPseudoLiveTVRec = m_pseudoLiveTVRecording;
2898 
2899  if (!hadPseudoLiveTVRec && m_pseudoLiveTVRecording)
2901 
2902  // Figure out next state and if needed recording end time.
2903  TVState next_state = kState_None;
2905  {
2907  next_state = kState_RecordingOnly;
2908  }
2909 
2910  // Change to the appropriate state
2911  ChangeState(next_state);
2912 
2913  // Wait for state change to take effect...
2915 
2916  // We are done with the tvchain...
2917  if (m_tvChain)
2918  {
2919  m_tvChain->DecrRef();
2920  }
2921  m_tvChain = nullptr;
2922 }
2923 
2933 {
2934  QMutexLocker lock(&m_stateChangeLock);
2935 
2936  if (!m_recorder)
2937  {
2938  LOG(VB_GENERAL, LOG_ERR, LOC +
2939  "PauseRecorder() called with no recorder");
2940  return;
2941  }
2942 
2943  m_recorder->Pause();
2944 }
2945 
2952 {
2953  if (m_pauseNotify)
2954  WakeEventLoop();
2955 }
2956 
2960 void TVRec::ToggleChannelFavorite(const QString& changroupname)
2961 {
2962  QMutexLocker lock(&m_stateChangeLock);
2963 
2964  if (!m_channel)
2965  return;
2966 
2967  // Get current channel id...
2968  uint sourceid = m_channel->GetSourceID();
2969  QString channum = m_channel->GetChannelName();
2970  uint chanid = ChannelUtil::GetChanID(sourceid, channum);
2971 
2972  if (!chanid)
2973  {
2974  LOG(VB_GENERAL, LOG_ERR, LOC +
2975  QString("Channel: \'%1\' was not found in the database.\n"
2976  "\t\tMost likely, the 'starting channel' for this "
2977  "Input Connection is invalid.\n"
2978  "\t\tCould not toggle favorite.").arg(channum));
2979  return;
2980  }
2981 
2982  int changrpid = ChannelGroup::GetChannelGroupId(changroupname);
2983  if (changrpid <1)
2984  {
2985  LOG(VB_RECORD, LOG_ERR, LOC +
2986  QString("ToggleChannelFavorite: Invalid channel group name %1,")
2987  .arg(changroupname));
2988  }
2989  else
2990  {
2991  bool result = ChannelGroup::ToggleChannel(chanid, changrpid, true);
2992 
2993  if (!result)
2994  LOG(VB_RECORD, LOG_ERR, LOC + "Unable to toggle channel favorite.");
2995  else
2996  {
2997  LOG(VB_RECORD, LOG_INFO, LOC +
2998  QString("Toggled channel favorite.channum %1, chan group %2")
2999  .arg(channum, changroupname));
3000  }
3001  }
3002 }
3003 
3010 {
3011  QMutexLocker lock(&m_stateChangeLock);
3012  if (!m_channel)
3013  return -1;
3014 
3015  int ret = m_channel->GetPictureAttribute(attr);
3016 
3017  return (ret < 0) ? -1 : ret / 655;
3018 }
3019 
3028  PictureAttribute attr,
3029  bool direction)
3030 {
3031  QMutexLocker lock(&m_stateChangeLock);
3032  if (!m_channel)
3033  return -1;
3034 
3035  int ret = m_channel->ChangePictureAttribute(type, attr, direction);
3036 
3037  return (ret < 0) ? -1 : ret / 655;
3038 }
3039 
3043 QString TVRec::GetInput(void) const
3044 {
3045  if (m_channel)
3046  return m_channel->GetInputName();
3047  return QString();
3048 }
3049 
3054 {
3055  if (m_channel)
3056  return m_channel->GetSourceID();
3057  return 0;
3058 }
3059 
3068 QString TVRec::SetInput(QString input)
3069 {
3070  QMutexLocker lock(&m_stateChangeLock);
3071  QString origIn = input;
3072  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + input + ") -- begin");
3073 
3074  if (!m_channel)
3075  {
3076  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput() -- end no channel class");
3077  return QString();
3078  }
3079 
3080  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + origIn + ":" + input +
3081  ") -- end nothing to do");
3082  return input;
3083 }
3084 
3094 void TVRec::SetChannel(const QString& name, uint requestType)
3095 {
3096  QMutexLocker locker1(&m_setChannelLock);
3097  QMutexLocker locker2(&m_stateChangeLock);
3098 
3099  LOG(VB_CHANNEL, LOG_INFO, LOC +
3100  QString("SetChannel(%1) -- begin").arg(name));
3101 
3102  // Detect tuning request type if needed
3103  if (requestType & kFlagDetect)
3104  {
3106  requestType = m_lastTuningRequest.m_flags & (kFlagRec | kFlagNoRec);
3107  }
3108 
3109  // Clear the RingBuffer reset flag, in case we wait for a reset below
3110  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3111 
3112  // Clear out any EITScan channel change requests
3113  auto it = m_tuningRequests.begin();
3114  while (it != m_tuningRequests.end())
3115  {
3116  if ((*it).m_flags & kFlagEITScan)
3117  it = m_tuningRequests.erase(it);
3118  else
3119  ++it;
3120  }
3121 
3122  // Actually add the tuning request to the queue, and
3123  // then wait for it to start tuning
3124  m_tuningRequests.enqueue(TuningRequest(requestType, name));
3126 
3127  // If we are using a recorder, wait for a RingBuffer reset
3128  if (requestType & kFlagRec)
3129  {
3130  while (!HasFlags(kFlagRingBufferReady))
3132  }
3133  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetChannel(%1) -- end").arg(name));
3134 }
3135 
3143 bool TVRec::QueueEITChannelChange(const QString &name)
3144 {
3145  LOG(VB_CHANNEL, LOG_INFO, LOC +
3146  QString("QueueEITChannelChange(%1) -- begin").arg(name));
3147 
3148  bool ok = false;
3149  if (m_setChannelLock.tryLock())
3150  {
3151  if (m_stateChangeLock.tryLock())
3152  {
3153  if (m_tuningRequests.empty())
3154  {
3156  ok = true;
3157  }
3158  m_stateChangeLock.unlock();
3159  }
3160  m_setChannelLock.unlock();
3161  }
3162 
3163  LOG(VB_CHANNEL, LOG_INFO, LOC +
3164  QString("QueueEITChannelChange(%1) -- end --> %2").arg(name).arg(ok));
3165 
3166  return ok;
3167 }
3168 
3170  QString &title, QString &subtitle,
3171  QString &desc, QString &category,
3172  QString &starttime, QString &endtime,
3173  QString &callsign, QString &iconpath,
3174  QString &channum, uint &sourceChanid,
3175  QString &seriesid, QString &programid)
3176 {
3177  QString compare = "<=";
3178  QString sortorder = "desc";
3179  uint chanid = 0;
3180 
3181  if (sourceChanid)
3182  {
3183  chanid = sourceChanid;
3184 
3185  if (BROWSE_UP == direction)
3186  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_UP);
3187  else if (BROWSE_DOWN == direction)
3188  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_DOWN);
3189  else if (BROWSE_FAVORITE == direction)
3190  {
3191  chanid = m_channel->GetNextChannel(
3192  chanid, CHANNEL_DIRECTION_FAVORITE);
3193  }
3194  else if (BROWSE_LEFT == direction)
3195  {
3196  compare = "<";
3197  }
3198  else if (BROWSE_RIGHT == direction)
3199  {
3200  compare = ">";
3201  sortorder = "asc";
3202  }
3203  }
3204 
3205  if (!chanid)
3206  {
3207  if (BROWSE_SAME == direction)
3208  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3209  else if (BROWSE_UP == direction)
3210  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_UP);
3211  else if (BROWSE_DOWN == direction)
3212  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_DOWN);
3213  else if (BROWSE_FAVORITE == direction)
3214  {
3215  chanid = m_channel->GetNextChannel(channum,
3217  }
3218  else if (BROWSE_LEFT == direction)
3219  {
3220  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3221  compare = "<";
3222  }
3223  else if (BROWSE_RIGHT == direction)
3224  {
3225  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3226  compare = ">";
3227  sortorder = "asc";
3228  }
3229  }
3230 
3231  QString querystr = QString(
3232  "SELECT title, subtitle, description, category, "
3233  " starttime, endtime, callsign, icon, "
3234  " channum, seriesid, programid "
3235  "FROM program, channel "
3236  "WHERE program.chanid = channel.chanid AND "
3237  " channel.chanid = :CHANID AND "
3238  " starttime %1 :STARTTIME "
3239  "ORDER BY starttime %2 "
3240  "LIMIT 1").arg(compare, sortorder);
3241 
3242  MSqlQuery query(MSqlQuery::InitCon());
3243  query.prepare(querystr);
3244  query.bindValue(":CHANID", chanid);
3245  query.bindValue(":STARTTIME", starttime);
3246 
3247  // Clear everything now in case either query fails.
3248  title = subtitle = desc = category = "";
3249  starttime = endtime = callsign = iconpath = "";
3250  channum = seriesid = programid = "";
3251  sourceChanid = 0;
3252 
3253  // Try to get the program info
3254  if (!query.exec() && !query.isActive())
3255  {
3256  MythDB::DBError("GetNextProgram -- get program info", query);
3257  }
3258  else if (query.next())
3259  {
3260  title = query.value(0).toString();
3261  subtitle = query.value(1).toString();
3262  desc = query.value(2).toString();
3263  category = query.value(3).toString();
3264  starttime = query.value(4).toString();
3265  endtime = query.value(5).toString();
3266  callsign = query.value(6).toString();
3267  iconpath = query.value(7).toString();
3268  channum = query.value(8).toString();
3269  seriesid = query.value(9).toString();
3270  programid = query.value(10).toString();
3271  sourceChanid = chanid;
3272  return;
3273  }
3274 
3275  // Couldn't get program info, so get the channel info instead
3276  query.prepare(
3277  "SELECT channum, callsign, icon "
3278  "FROM channel "
3279  "WHERE chanid = :CHANID");
3280  query.bindValue(":CHANID", chanid);
3281 
3282  if (!query.exec() || !query.isActive())
3283  {
3284  MythDB::DBError("GetNextProgram -- get channel info", query);
3285  }
3286  else if (query.next())
3287  {
3288  sourceChanid = chanid;
3289  channum = query.value(0).toString();
3290  callsign = query.value(1).toString();
3291  iconpath = query.value(2).toString();
3292  }
3293 }
3294 
3295 bool TVRec::GetChannelInfo(uint &chanid, uint &sourceid,
3296  QString &callsign, QString &channum,
3297  QString &channame, QString &xmltvid) const
3298 {
3299  callsign.clear();
3300  channum.clear();
3301  channame.clear();
3302  xmltvid.clear();
3303 
3304  if ((!chanid || !sourceid) && !m_channel)
3305  return false;
3306 
3307  if (!chanid)
3308  chanid = (uint) std::max(m_channel->GetChanID(), 0);
3309 
3310  if (!sourceid)
3311  sourceid = m_channel->GetSourceID();
3312 
3313  MSqlQuery query(MSqlQuery::InitCon());
3314  query.prepare(
3315  "SELECT callsign, channum, name, xmltvid "
3316  "FROM channel "
3317  "WHERE chanid = :CHANID");
3318  query.bindValue(":CHANID", chanid);
3319  if (!query.exec() || !query.isActive())
3320  {
3321  MythDB::DBError("GetChannelInfo", query);
3322  return false;
3323  }
3324 
3325  if (!query.next())
3326  return false;
3327 
3328  callsign = query.value(0).toString();
3329  channum = query.value(1).toString();
3330  channame = query.value(2).toString();
3331  xmltvid = query.value(3).toString();
3332 
3333  return true;
3334 }
3335 
3336 bool TVRec::SetChannelInfo(uint chanid, uint sourceid,
3337  const QString& oldchannum,
3338  const QString& callsign, const QString& channum,
3339  const QString& channame, const QString& xmltvid)
3340 {
3341  if (!chanid || !sourceid || channum.isEmpty())
3342  return false;
3343 
3344  MSqlQuery query(MSqlQuery::InitCon());
3345  query.prepare(
3346  "UPDATE channel "
3347  "SET callsign = :CALLSIGN, "
3348  " channum = :CHANNUM, "
3349  " name = :CHANNAME, "
3350  " xmltvid = :XMLTVID "
3351  "WHERE chanid = :CHANID AND "
3352  " sourceid = :SOURCEID");
3353  query.bindValue(":CALLSIGN", callsign);
3354  query.bindValue(":CHANNUM", channum);
3355  query.bindValue(":CHANNAME", channame);
3356  query.bindValue(":XMLTVID", xmltvid);
3357  query.bindValue(":CHANID", chanid);
3358  query.bindValue(":SOURCEID", sourceid);
3359 
3360  if (!query.exec())
3361  {
3362  MythDB::DBError("SetChannelInfo", query);
3363  return false;
3364  }
3365 
3366  if (m_channel)
3367  m_channel->Renumber(sourceid, oldchannum, channum);
3368 
3369  return true;
3370 }
3371 
3376 {
3377  QMutexLocker lock(&m_stateChangeLock);
3378 
3379  MythMediaBuffer *oldbuffer = m_buffer;
3380  m_buffer = Buffer;
3381 
3382  if (oldbuffer && (oldbuffer != Buffer))
3383  {
3385  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3386  delete oldbuffer;
3387  }
3388 
3389  m_switchingBuffer = false;
3390 }
3391 
3393 {
3394  LOG(VB_GENERAL, LOG_INFO, LOC + "RingBufferChanged()");
3395 
3396  if (pginfo)
3397  {
3398  if (m_curRecording)
3399  {
3402  delete m_curRecording;
3403  }
3405  m_curRecording = new RecordingInfo(*pginfo);
3408  }
3409 
3411 }
3412 
3414  QString &input) const
3415 {
3416  QString channum;
3417 
3418  if (request.m_program)
3419  {
3420  request.m_program->QueryTuningInfo(channum, input);
3421  return channum;
3422  }
3423 
3424  channum = request.m_channel;
3425  input = request.m_input;
3426 
3427  // If this is Live TV startup, we need a channel...
3428  if (channum.isEmpty() && (request.m_flags & kFlagLiveTV))
3429  {
3430  if (!m_liveTVStartChannel.isEmpty())
3431  channum = m_liveTVStartChannel;
3432  else
3433  {
3435  channum = GetStartChannel(m_inputId);
3436  }
3437  }
3438  if (request.m_flags & kFlagLiveTV)
3439  m_channel->Init(channum, false);
3440 
3441  if (m_channel && !channum.isEmpty() && (channum.indexOf("NextChannel") >= 0))
3442  {
3443  // FIXME This is just horrible
3444  int dir = channum.right(channum.length() - 12).toInt();
3445  uint chanid = m_channel->GetNextChannel(0, static_cast<ChannelChangeDirection>(dir));
3446  channum = ChannelUtil::GetChanNum(chanid);
3447  }
3448 
3449  return channum;
3450 }
3451 
3453 {
3454  if ((request.m_flags & kFlagAntennaAdjust) || request.m_input.isEmpty() ||
3456  {
3457  return false;
3458  }
3459 
3460  uint sourceid = m_channel->GetSourceID();
3461  QString oldchannum = m_channel->GetChannelName();
3462  QString newchannum = request.m_channel;
3463 
3464  if (ChannelUtil::IsOnSameMultiplex(sourceid, newchannum, oldchannum))
3465  {
3467  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3468 
3469  if (atsc)
3470  {
3471  uint major = 0;
3472  uint minor = 0;
3473  ChannelUtil::GetATSCChannel(sourceid, newchannum, major, minor);
3474 
3475  if (minor && atsc->HasChannel(major, minor))
3476  {
3477  request.m_majorChan = major;
3478  request.m_minorChan = minor;
3479  return true;
3480  }
3481  }
3482 
3483  if (mpeg)
3484  {
3485  uint progNum = ChannelUtil::GetProgramNumber(sourceid, newchannum);
3486  if (mpeg->HasProgram(progNum))
3487  {
3488  request.m_progNum = progNum;
3489  return true;
3490  }
3491  }
3492  }
3493 
3494  return false;
3495 }
3496 
3505 {
3506  if (!m_tuningRequests.empty())
3507  {
3508  TuningRequest request = m_tuningRequests.front();
3509  LOG(VB_RECORD, LOG_INFO, LOC +
3510  "HandleTuning Request: " + request.toString());
3511 
3512  QString input;
3513  request.m_channel = TuningGetChanNum(request, input);
3514  request.m_input = input;
3515 
3516  if (TuningOnSameMultiplex(request))
3517  LOG(VB_CHANNEL, LOG_INFO, LOC + "On same multiplex");
3518 
3519  TuningShutdowns(request);
3520 
3521  // The dequeue isn't safe to do until now because we
3522  // release the stateChangeLock to teardown a recorder
3524 
3525  // Now we start new stuff
3526  if (request.m_flags & (kFlagRecording|kFlagLiveTV|
3528  {
3529  if (!m_recorder)
3530  {
3531  LOG(VB_RECORD, LOG_INFO, LOC +
3532  "No recorder yet, calling TuningFrequency");
3533  TuningFrequency(request);
3534  }
3535  else
3536  {
3537  LOG(VB_RECORD, LOG_INFO, LOC + "Waiting for recorder pause..");
3538  SetFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3539  }
3540  }
3541  m_lastTuningRequest = request;
3542  }
3543 
3545  {
3546  if (!m_recorder->IsPaused())
3547  return;
3548 
3549  ClearFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3550  LOG(VB_RECORD, LOG_INFO, LOC +
3551  "Recorder paused, calling TuningFrequency");
3553  }
3554 
3555  MPEGStreamData *streamData = nullptr;
3556  if (HasFlags(kFlagWaitingForSignal) && !(streamData = TuningSignalCheck()))
3557  return;
3558 
3560  {
3561  if (m_recorder)
3563  else
3564  TuningNewRecorder(streamData);
3565 
3566  // If we got this far it is safe to set a new starting channel...
3567  if (m_channel)
3569  }
3570 }
3571 
3577 {
3578  LOG(VB_RECORD, LOG_INFO, LOC + QString("TuningShutdowns(%1)")
3579  .arg(request.toString()));
3580 
3581  if (m_scanner && !(request.m_flags & kFlagEITScan) &&
3583  {
3585  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
3587  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
3588  }
3589 
3590  if (m_scanner && !request.IsOnSameMultiplex())
3592 
3594  {
3595  MPEGStreamData *sd = nullptr;
3596  if (GetDTVSignalMonitor())
3599  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3600 
3601  // Delete StreamData if it is not in use by the recorder.
3602  MPEGStreamData *rec_sd = nullptr;
3603  if (GetDTVRecorder())
3604  rec_sd = GetDTVRecorder()->GetStreamData();
3605  if (sd && (sd != rec_sd))
3606  delete sd;
3607  }
3609  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3610 
3611  // At this point any waits are canceled.
3612 
3613  if (request.m_flags & kFlagNoRec)
3614  {
3616  {
3618  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3620  }
3621 
3623  (m_curRecording &&
3626  {
3627  m_stateChangeLock.unlock();
3628  TeardownRecorder(request.m_flags);
3629  m_stateChangeLock.lock();
3630  }
3631  // At this point the recorders are shut down
3632 
3633  CloseChannel();
3634  // At this point the channel is shut down
3635  }
3636 
3637  if (m_buffer && (request.m_flags & kFlagKillRingBuffer))
3638  {
3639  LOG(VB_RECORD, LOG_INFO, LOC + "Tearing down RingBuffer");
3640  SetRingBuffer(nullptr);
3641  // At this point the ringbuffer is shut down
3642  }
3643 
3644  // Clear pending actions from last request
3645  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
3646 }
3647 
3666 {
3667  LOG(VB_GENERAL, LOG_INFO, LOC + "TuningFrequency");
3668 
3669  DTVChannel *dtvchan = GetDTVChannel();
3670  if (dtvchan)
3671  {
3672  MPEGStreamData *mpeg = nullptr;
3673 
3674  if (GetDTVRecorder())
3676 
3677  const QString tuningmode = (HasFlags(kFlagEITScannerRunning)) ?
3678  dtvchan->GetSIStandard() :
3679  dtvchan->GetSuggestedTuningMode(
3681 
3682  dtvchan->SetTuningMode(tuningmode);
3683 
3684  if (request.m_minorChan && (tuningmode == "atsc"))
3685  {
3687 
3688  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3689  if (atsc)
3690  atsc->SetDesiredChannel(request.m_majorChan, request.m_minorChan);
3691  }
3692  else if (request.m_progNum >= 0)
3693  {
3695 
3696  if (mpeg)
3697  mpeg->SetDesiredProgram(request.m_progNum);
3698  }
3699  }
3700 
3701  if (request.IsOnSameMultiplex())
3702  {
3703  // Update the channel number for SwitchLiveTVRingBuffer (called from
3704  // TuningRestartRecorder). This ensures that the livetvchain will be
3705  // updated with the new channel number
3706  if (m_channel)
3707  {
3709  m_channel->GetChannelName(), request.m_channel );
3710  }
3711 
3712  QStringList slist;
3713  slist<<"message"<<QObject::tr("On known multiplex...");
3714  MythEvent me(QString("SIGNAL %1").arg(m_inputId), slist);
3715  gCoreContext->dispatch(me);
3716 
3717  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3718  return;
3719  }
3720 
3721  QString channum = request.m_channel;
3722 
3723  bool ok1 = true;
3724  if (m_channel)
3725  {
3726  m_channel->Open();
3727  if (!channum.isEmpty())
3728  ok1 = m_channel->SetChannelByString(channum);
3729  else
3730  ok1 = false;
3731  }
3732 
3733  if (!ok1)
3734  {
3735  if (!(request.m_flags & kFlagLiveTV) || !(request.m_flags & kFlagEITScan))
3736  {
3737  if (m_curRecording)
3739 
3740  LOG(VB_GENERAL, LOG_ERR, LOC +
3741  QString("Failed to set channel to %1. Reverting to kState_None")
3742  .arg(channum));
3745  else
3747  return;
3748  }
3749 
3750  LOG(VB_GENERAL, LOG_ERR, LOC +
3751  QString("Failed to set channel to %1.").arg(channum));
3752  }
3753 
3754 
3755  bool mpts_only = GetDTVChannel() &&
3756  GetDTVChannel()->GetFormat().compare("MPTS") == 0;
3757  if (mpts_only)
3758  {
3759  // Not using a signal monitor, so just set the status to recording
3761  if (m_curRecording)
3762  {
3764  }
3765  }
3766 
3767 
3768  bool livetv = (request.m_flags & kFlagLiveTV) != 0U;
3769  bool antadj = (request.m_flags & kFlagAntennaAdjust) != 0U;
3770  bool use_sm = !mpts_only && SignalMonitor::IsRequired(m_genOpt.m_inputType);
3771  bool use_dr = use_sm && (livetv || antadj);
3772  bool has_dummy = false;
3773 
3774  if (use_dr)
3775  {
3776  // We need there to be a ringbuffer for these modes
3777  bool ok2 = false;
3779  m_pseudoLiveTVRecording = nullptr;
3780 
3781  m_tvChain->SetInputType("DUMMY");
3782 
3783  if (!m_buffer)
3784  ok2 = CreateLiveTVRingBuffer(channum);
3785  else
3786  ok2 = SwitchLiveTVRingBuffer(channum, true, false);
3788 
3790 
3791  if (!ok2)
3792  {
3793  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 1");
3794  return;
3795  }
3796 
3797  has_dummy = true;
3798  }
3799 
3800  // Start signal monitoring for devices capable of monitoring
3801  if (use_sm)
3802  {
3803  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Signal Monitor");
3804  bool error = false;
3805  if (!SetupSignalMonitor(
3806  !antadj, (request.m_flags & kFlagEITScan) != 0U, livetv || antadj))
3807  {
3808  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to setup signal monitor");
3809  if (m_signalMonitor)
3810  {
3811  delete m_signalMonitor;
3812  m_signalMonitor = nullptr;
3813  }
3814 
3815  // pretend the signal monitor is running to prevent segfault
3816  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3817  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3818  error = true;
3819  }
3820 
3821  if (m_signalMonitor)
3822  {
3823  if (request.m_flags & kFlagEITScan)
3824  {
3826  SetVideoStreamsRequired(0);
3828  }
3829 
3830  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3831  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3832  if (!antadj)
3833  {
3834  QDateTime expire = MythDate::current();
3835 
3836  SetFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3837  if (m_curRecording)
3838  {
3840  // If startRecordingDeadline is passed, this
3841  // recording is marked as failed, so the scheduler
3842  // can try another showing.
3844  expire.addMSecs(m_genOpt.m_channelTimeout);
3846  expire.addMSecs(m_genOpt.m_channelTimeout * 2 / 3);
3847  // Keep trying to record this showing (even if it
3848  // has been marked as failed) until the scheduled
3849  // end time.
3851  m_curRecording->GetRecordingEndTime().addSecs(-10);
3852 
3853  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
3854  QString("Pre-fail start deadline: %1 "
3855  "Start recording deadline: %2 "
3856  "Good signal deadline: %3")
3857  .arg(m_preFailDeadline.toLocalTime()
3858  .toString("hh:mm:ss.zzz"),
3859  m_startRecordingDeadline.toLocalTime()
3860  .toString("hh:mm:ss.zzz"),
3861  m_signalMonitorDeadline.toLocalTime()
3862  .toString("hh:mm:ss.zzz")));
3863  }
3864  else
3865  {
3867  expire.addMSecs(m_genOpt.m_channelTimeout);
3868  }
3870 
3871  //System Event TUNING_TIMEOUT deadline
3873  m_signalEventCmdSent = false;
3874  }
3875  }
3876 
3877  if (has_dummy && m_buffer)
3878  {
3879  // Make sure recorder doesn't point to bogus ringbuffer before
3880  // it is potentially restarted without a new ringbuffer, if
3881  // the next channel won't tune and the user exits LiveTV.
3882  if (m_recorder)
3883  m_recorder->SetRingBuffer(nullptr);
3884 
3885  SetFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3886  LOG(VB_RECORD, LOG_INFO, "DummyDTVRecorder -- started");
3887  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3888  }
3889 
3890  // if we had problems starting the signal monitor,
3891  // we don't want to start the recorder...
3892  if (error)
3893  return;
3894  }
3895 
3896  // Request a recorder, if the command is a recording command
3897  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3898  if (request.m_flags & kFlagRec && !antadj)
3899  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3900 }
3901 
3910 {
3911  RecStatus::Type newRecStatus = RecStatus::Unknown;
3912  bool keep_trying = false;
3913  QDateTime current_time = MythDate::current();
3914 
3915  if ((m_signalMonitor->IsErrored() || current_time > m_signalEventCmdTimeout) &&
3917  {
3918  gCoreContext->SendSystemEvent(QString("TUNING_SIGNAL_TIMEOUT CARDID %1")
3919  .arg(m_inputId));
3920  m_signalEventCmdSent = true;
3921  }
3922 
3923  if (m_signalMonitor->IsAllGood())
3924  {
3925  LOG(VB_RECORD, LOG_INFO, LOC + "TuningSignalCheck: Good signal");
3926  if (m_curRecording && (current_time > m_startRecordingDeadline))
3927  {
3928  newRecStatus = RecStatus::Failing;
3929  m_curRecording->SaveVideoProperties(VID_DAMAGED, VID_DAMAGED);
3930 
3931  QString desc = tr("Good signal seen after %1 ms")
3932  .arg(m_genOpt.m_channelTimeout +
3933  m_startRecordingDeadline.msecsTo(current_time));
3934  QString title = m_curRecording->GetTitle();
3935  if (!m_curRecording->GetSubtitle().isEmpty())
3936  title += " - " + m_curRecording->GetSubtitle();
3937 
3939  "Recording", title,
3940  tr("See 'Tuning timeout' in mythtv-setup "
3941  "for this input."));
3942  gCoreContext->SendEvent(mn);
3943 
3944  LOG(VB_GENERAL, LOG_WARNING, LOC +
3945  QString("It took longer than %1 ms to get a signal lock. "
3946  "Keeping status of '%2'")
3948  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
3949  LOG(VB_GENERAL, LOG_WARNING, LOC +
3950  "See 'Tuning timeout' in mythtv-setup for this input");
3951  }
3952  else
3953  {
3954  newRecStatus = RecStatus::Recording;
3955  }
3956  }
3957  else if (m_signalMonitor->IsErrored() || current_time > m_signalMonitorDeadline)
3958  {
3959  LOG(VB_GENERAL, LOG_ERR, LOC + "TuningSignalCheck: SignalMonitor " +
3960  (m_signalMonitor->IsErrored() ? "failed" : "timed out"));
3961 
3962  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3963  newRecStatus = RecStatus::Failed;
3964 
3966  {
3968  }
3969  }
3970  else if (m_curRecording && !m_reachedPreFail && current_time > m_preFailDeadline)
3971  {
3972  LOG(VB_GENERAL, LOG_ERR, LOC +
3973  "TuningSignalCheck: Hit pre-fail timeout");
3974  SendMythSystemRecEvent("REC_PREFAIL", m_curRecording);
3975  m_reachedPreFail = true;
3976  return nullptr;
3977  }
3979  current_time > m_startRecordingDeadline)
3980  {
3981  newRecStatus = RecStatus::Failing;
3983  keep_trying = true;
3984 
3985  SendMythSystemRecEvent("REC_FAILING", m_curRecording);
3986 
3987  QString desc = tr("Taking more than %1 ms to get a lock.")
3988  .arg(m_genOpt.m_channelTimeout);
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  mn.SetDuration(30s);
3998  gCoreContext->SendEvent(mn);
3999 
4000  LOG(VB_GENERAL, LOG_WARNING, LOC +
4001  QString("TuningSignalCheck: taking more than %1 ms to get a lock. "
4002  "marking this recording as '%2'.")
4004  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
4005  LOG(VB_GENERAL, LOG_WARNING, LOC +
4006  "See 'Tuning timeout' in mythtv-setup for this input");
4007  }
4008  else
4009  {
4010  if (m_signalMonitorCheckCnt) // Don't flood log file
4012  else
4013  {
4014  LOG(VB_RECORD, LOG_INFO, LOC +
4015  QString("TuningSignalCheck: Still waiting. Will timeout @ %1")
4016  .arg(m_signalMonitorDeadline.toLocalTime()
4017  .toString("hh:mm:ss.zzz")));
4019  }
4020  return nullptr;
4021  }
4022 
4023  SetRecordingStatus(newRecStatus, __LINE__);
4024 
4025  if (m_curRecording)
4026  {
4027  m_curRecording->SetRecordingStatus(newRecStatus);
4028  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
4029  .arg(m_curRecording->GetInputID())
4030  .arg(m_curRecording->GetChanID())
4032  .arg(newRecStatus)
4034  gCoreContext->dispatch(me);
4035  }
4036 
4037  if (keep_trying)
4038  return nullptr;
4039 
4040  // grab useful data from DTV signal monitor before we kill it...
4041  MPEGStreamData *streamData = nullptr;
4042  if (GetDTVSignalMonitor())
4043  streamData = GetDTVSignalMonitor()->GetStreamData();
4044 
4046  {
4047  // shut down signal monitoring
4049  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
4050  }
4051  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
4052 
4053  if (streamData)
4054  {
4055  auto *dsd = dynamic_cast<DVBStreamData*>(streamData);
4056  if (dsd)
4058  if (!get_use_eit(GetInputId()))
4059  {
4060  LOG(VB_EIT, LOG_INFO, LOC +
4061  "EIT scanning disabled for all sources on this input.");
4062  }
4063  else if (m_scanner)
4064  m_scanner->StartPassiveScan(m_channel, streamData);
4065  }
4066 
4067  return streamData;
4068 }
4069 
4071  bool on_host, bool transcode_bfr_comm, bool on_line_comm)
4072 {
4073  if (!rec)
4074  return 0; // no jobs for Live TV recordings..
4075 
4076  int jobs = 0; // start with no jobs
4077 
4078  // grab standard jobs flags from program info
4080 
4081  // disable commercial flagging on PBS, BBC, etc.
4082  if (rec->IsCommercialFree())
4084 
4085  // disable transcoding if the profile does not allow auto transcoding
4086  const StandardSetting *autoTrans = profile.byName("autotranscode");
4087  if ((!autoTrans) || (autoTrans->getValue().toInt() == 0))
4089 
4090  bool ml = JobQueue::JobIsInMask(JOB_METADATA, jobs);
4091  if (ml)
4092  {
4093  // When allowed, metadata lookup should occur at the
4094  // start of a recording to make the additional info
4095  // available immediately (and for use in future jobs).
4096  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4098  rec->GetChanID(),
4099  rec->GetRecordingStartTime(), "", "",
4100  host, JOB_LIVE_REC);
4101 
4102  // don't do regular metadata lookup, we won't need it.
4104  }
4105 
4106  // is commercial flagging enabled, and is on-line comm flagging enabled?
4107  bool rt = JobQueue::JobIsInMask(JOB_COMMFLAG, jobs) && on_line_comm;
4108  // also, we either need transcoding to be disabled or
4109  // we need to be allowed to commercial flag before transcoding?
4110  rt &= JobQueue::JobIsNotInMask(JOB_TRANSCODE, jobs) ||
4111  !transcode_bfr_comm;
4112  if (rt)
4113  {
4114  // queue up real-time (i.e. on-line) commercial flagging.
4115  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4117  rec->GetChanID(),
4118  rec->GetRecordingStartTime(), "", "",
4119  host, JOB_LIVE_REC);
4120 
4121  // don't do regular comm flagging, we won't need it.
4123  }
4124 
4125  return jobs;
4126 }
4127 
4128 QString TVRec::LoadProfile(void *tvchain, RecordingInfo *rec,
4129  RecordingProfile &profile) const
4130 {
4131  // Determine the correct recording profile.
4132  // In LiveTV mode use "Live TV" profile, otherwise use the
4133  // recording's specified profile. If the desired profile can't
4134  // be found, fall back to the "Default" profile for input type.
4135  QString profileName = "Live TV";
4136  if (!tvchain && rec)
4137  profileName = rec->GetRecordingRule()->m_recProfile;
4138 
4139  QString profileRequested = profileName;
4140 
4141  if (profile.loadByType(profileName, m_genOpt.m_inputType,
4143  {
4144  LOG(VB_RECORD, LOG_INFO, LOC +
4145  QString("Using profile '%1' to record")
4146  .arg(profileName));
4147  }
4148  else
4149  {
4150  profileName = "Default";
4151  if (profile.loadByType(profileName, m_genOpt.m_inputType, m_genOpt.m_videoDev))
4152  {
4153  LOG(VB_RECORD, LOG_INFO, LOC +
4154  QString("Profile '%1' not found, using "
4155  "fallback profile '%2' to record")
4156  .arg(profileRequested, profileName));
4157  }
4158  else
4159  {
4160  LOG(VB_RECORD, LOG_ERR, LOC +
4161  QString("Profile '%1' not found, and unable "
4162  "to load fallback profile '%2'. Results "
4163  "may be unpredicable")
4164  .arg(profileRequested, profileName));
4165  }
4166  }
4167 
4168  return profileName;
4169 }
4170 
4175 {
4176  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Recorder");
4177 
4178  bool had_dummyrec = false;
4180  {
4182  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4184  had_dummyrec = true;
4185  }
4186 
4188 
4191 
4192  if (m_tvChain)
4193  {
4194  bool ok = false;
4195  if (!m_buffer)
4196  {
4198  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4199  }
4200  else
4202  true, !had_dummyrec && m_recorder);
4203  if (!ok)
4204  {
4205  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 2");
4206  goto err_ret;
4207  }
4208  rec = m_curRecording; // new'd in Create/SwitchLiveTVRingBuffer()
4209  }
4210 
4212  {
4213  bool write = m_genOpt.m_inputType != "IMPORT";
4214  LOG(VB_GENERAL, LOG_INFO, LOC + QString("rec->GetPathname(): '%1'")
4215  .arg(rec->GetPathname()));
4217  if (!m_buffer->IsOpen() && write)
4218  {
4219  LOG(VB_GENERAL, LOG_ERR, LOC +
4220  QString("RingBuffer '%1' not open...")
4221  .arg(rec->GetPathname()));
4222  SetRingBuffer(nullptr);
4223  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4224  goto err_ret;
4225  }
4226  }
4227 
4228  if (!m_buffer)
4229  {
4230  LOG(VB_GENERAL, LOG_ERR, LOC +
4231  QString("Failed to start recorder! ringBuffer is NULL\n"
4232  "\t\t\t\t Tuning request was %1\n")
4233  .arg(m_lastTuningRequest.toString()));
4234 
4235  if (HasFlags(kFlagLiveTV))
4236  {
4237  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4238  MythEvent me(message);
4239  gCoreContext->dispatch(me);
4240  }
4241  goto err_ret;
4242  }
4243 
4244  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4245  m_channel->Close(); // Needed because of NVR::MJPEGInit()
4246 
4247  LOG(VB_GENERAL, LOG_INFO, LOC + "TuningNewRecorder - CreateRecorder()");
4249 
4250  if (m_recorder)
4251  {
4254  if (m_recorder->IsErrored())
4255  {
4256  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialize recorder!");
4257  delete m_recorder;
4258  m_recorder = nullptr;
4259  }
4260  }
4261 
4262  if (!m_recorder)
4263  {
4264  LOG(VB_GENERAL, LOG_ERR, LOC +
4265  QString("Failed to start recorder!\n"
4266  "\t\t\t\t Tuning request was %1\n")
4267  .arg(m_lastTuningRequest.toString()));
4268 
4269  if (HasFlags(kFlagLiveTV))
4270  {
4271  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4272  MythEvent me(message);
4273  gCoreContext->dispatch(me);
4274  }
4276  goto err_ret;
4277  }
4278 
4279  if (rec)
4280  m_recorder->SetRecording(rec);
4281 
4282  if (GetDTVRecorder() && streamData)
4283  {
4284  const StandardSetting *setting = profile.byName("recordingtype");
4285  if (setting)
4286  streamData->SetRecordingType(setting->getValue());
4287  GetDTVRecorder()->SetStreamData(streamData);
4288  }
4289 
4290  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4291  m_channel->Open(); // Needed because of NVR::MJPEGInit()
4292 
4293  // Setup for framebuffer capture devices..
4294  if (m_channel)
4295  {
4298  }
4299 
4300  if (GetV4LChannel())
4301  {
4303  CloseChannel();
4304  }
4305 
4306  m_recorderThread = new MThread("RecThread", m_recorder);
4308 
4309  // Wait for recorder to start.
4310  m_stateChangeLock.unlock();
4311  while (!m_recorder->IsRecording() && !m_recorder->IsErrored())
4312  std::this_thread::sleep_for(5us);
4313  m_stateChangeLock.lock();
4314 
4315  if (GetV4LChannel())
4317 
4318  SetFlags(kFlagRecorderRunning | kFlagRingBufferReady, __FILE__, __LINE__);
4319 
4320  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4321 
4322  //workaround for failed import recordings, no signal monitor means we never
4323  //go to recording state and the status here seems to override the status
4324  //set in the importrecorder and backend via setrecordingstatus
4325  if (m_genOpt.m_inputType == "IMPORT")
4326  {
4328  if (m_curRecording)
4330  }
4331  return;
4332 
4333  err_ret:
4334  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
4336 
4337  if (rec)
4338  {
4339  // Make sure the scheduler knows...
4341  LOG(VB_RECORD, LOG_INFO, LOC +
4342  QString("TuningNewRecorder -- UPDATE_RECORDING_STATUS: %1")
4344  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
4345  .arg(rec->GetInputID())
4346  .arg(rec->GetChanID())
4348  .arg(RecStatus::Failed)
4350  gCoreContext->dispatch(me);
4351  }
4352 
4353  if (m_tvChain)
4354  delete rec;
4355 }
4356 
4361 {
4362  LOG(VB_RECORD, LOG_INFO, LOC + "Restarting Recorder");
4363 
4364  bool had_dummyrec = false;
4365 
4366  if (m_curRecording)
4367  {
4370  }
4371 
4373  {
4374  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4375  had_dummyrec = true;
4376  }
4377 
4378  SwitchLiveTVRingBuffer(m_channel->GetChannelName(), true, !had_dummyrec);
4379 
4380  if (had_dummyrec)
4381  {
4383  ProgramInfo *progInfo = m_tvChain->GetProgramAt(-1);
4384  RecordingInfo recinfo(*progInfo);
4385  delete progInfo;
4386  recinfo.SetInputID(m_inputId);
4387  m_recorder->SetRecording(&recinfo);
4388  }
4389  m_recorder->Reset();
4390 
4391  // Set file descriptor of channel from recorder for V4L
4392  if (GetV4LChannel())
4394 
4395  // Some recorders unpause on Reset, others do not...
4396  m_recorder->Unpause();
4397 
4399  {
4401  QString msg1 = QString("Recording: %1 %2 %3 %4")
4402  .arg(rcinfo1->GetTitle(), QString::number(rcinfo1->GetChanID()),
4405  ProgramInfo *rcinfo2 = m_tvChain->GetProgramAt(-1);
4406  QString msg2 = QString("Recording: %1 %2 %3 %4")
4407  .arg(rcinfo2->GetTitle(), QString::number(rcinfo2->GetChanID()),
4410  delete rcinfo2;
4411  LOG(VB_RECORD, LOG_INFO, LOC + "Pseudo LiveTV recording starting." +
4412  "\n\t\t\t" + msg1 + "\n\t\t\t" + msg2);
4413 
4416 
4418 
4419  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
4420  }
4421 
4422  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4423 }
4424 
4425 void TVRec::SetFlags(uint f, const QString & file, int line)
4426 {
4427  QMutexLocker lock(&m_stateChangeLock);
4428  m_stateFlags |= f;
4429  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetFlags(%1) -> %2 @ %3:%4")
4430  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4431  WakeEventLoop();
4432 }
4433 
4434 void TVRec::ClearFlags(uint f, const QString & file, int line)
4435 {
4436  QMutexLocker lock(&m_stateChangeLock);
4437  m_stateFlags &= ~f;
4438  LOG(VB_RECORD, LOG_INFO, LOC + QString("ClearFlags(%1) -> %2 @ %3:%4")
4439  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4440  WakeEventLoop();
4441 }
4442 
4444 {
4445  QString msg("");
4446 
4447  // General flags
4448  if (kFlagFrontendReady & f)
4449  msg += "FrontendReady,";
4450  if (kFlagRunMainLoop & f)
4451  msg += "RunMainLoop,";
4452  if (kFlagExitPlayer & f)
4453  msg += "ExitPlayer,";
4454  if (kFlagFinishRecording & f)
4455  msg += "FinishRecording,";
4456  if (kFlagErrored & f)
4457  msg += "Errored,";
4458  if (kFlagCancelNextRecording & f)
4459  msg += "CancelNextRecording,";
4460 
4461  // Tuning flags
4462  if ((kFlagRec & f) == kFlagRec)
4463  msg += "REC,";
4464  else
4465  {
4466  if (kFlagLiveTV & f)
4467  msg += "LiveTV,";
4468  if (kFlagRecording & f)
4469  msg += "Recording,";
4470  }
4471  if ((kFlagNoRec & f) == kFlagNoRec)
4472  msg += "NOREC,";
4473  else
4474  {
4475  if (kFlagEITScan & f)
4476  msg += "EITScan,";
4477  if (kFlagCloseRec & f)
4478  msg += "CloseRec,";
4479  if (kFlagKillRec & f)
4480  msg += "KillRec,";
4481  if (kFlagAntennaAdjust & f)
4482  msg += "AntennaAdjust,";
4483  }
4485  msg += "PENDINGACTIONS,";
4486  else
4487  {
4488  if (kFlagWaitingForRecPause & f)
4489  msg += "WaitingForRecPause,";
4490  if (kFlagWaitingForSignal & f)
4491  msg += "WaitingForSignal,";
4492  if (kFlagNeedToStartRecorder & f)
4493  msg += "NeedToStartRecorder,";
4494  if (kFlagKillRingBuffer & f)
4495  msg += "KillRingBuffer,";
4496  }
4497  if ((kFlagAnyRunning & f) == kFlagAnyRunning)
4498  msg += "ANYRUNNING,";
4499  else
4500  {
4501  if (kFlagSignalMonitorRunning & f)
4502  msg += "SignalMonitorRunning,";
4503  if (kFlagEITScannerRunning & f)
4504  msg += "EITScannerRunning,";
4506  msg += "ANYRECRUNNING,";
4507  else
4508  {
4509  if (kFlagDummyRecorderRunning & f)
4510  msg += "DummyRecorderRunning,";
4511  if (kFlagRecorderRunning & f)
4512  msg += "RecorderRunning,";
4513  }
4514  }
4515  if (kFlagRingBufferReady & f)
4516  msg += "RingBufferReady,";
4517 
4518  if (msg.isEmpty())
4519  msg = QString("0x%1").arg(f,0,16);
4520 
4521  return msg;
4522 }
4523 
4525 {
4526  QMutexLocker lock(&m_nextLiveTVDirLock);
4527 
4528  bool found = !m_nextLiveTVDir.isEmpty();
4529  if (!found && m_triggerLiveTVDir.wait(&m_nextLiveTVDirLock, 500))
4530  {
4531  found = !m_nextLiveTVDir.isEmpty();
4532  }
4533 
4534  return found;
4535 }
4536 
4537 void TVRec::SetNextLiveTVDir(QString dir)
4538 {
4539  QMutexLocker lock(&m_nextLiveTVDirLock);
4540 
4541  m_nextLiveTVDir = std::move(dir);
4542  m_triggerLiveTVDir.wakeAll();
4543 }
4544 
4547  const QString & channum)
4548 {
4549  LOG(VB_RECORD, LOG_INFO, LOC + "GetProgramRingBufferForLiveTV()");
4550  if (!m_channel || !m_tvChain || !pginfo || !Buffer)
4551  return false;
4552 
4553  m_nextLiveTVDirLock.lock();
4554  m_nextLiveTVDir.clear();
4555  m_nextLiveTVDirLock.unlock();
4556 
4557  // Dispatch this early, the response can take a while.
4558  MythEvent me(QString("QUERY_NEXT_LIVETV_DIR %1").arg(m_inputId));
4559  gCoreContext->dispatch(me);
4560 
4561  uint sourceid = m_channel->GetSourceID();
4562  int chanid = ChannelUtil::GetChanID(sourceid, channum);
4563 
4564  if (chanid < 0)
4565  {
4566  // Test setups might have zero channels
4567  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
4568  chanid = 9999;
4569  else
4570  {
4571  LOG(VB_GENERAL, LOG_ERR, LOC +
4572  QString("Channel: \'%1\' was not found in the database.\n"
4573  "\t\tMost likely, the 'starting channel' for this "
4574  "Input Connection is invalid.\n"
4575  "\t\tCould not start livetv.").arg(channum));
4576  return false;
4577  }
4578  }
4579 
4580  auto hoursMax =
4581  gCoreContext->GetDurSetting<std::chrono::hours>("MaxHoursPerLiveTVRecording", 8h);
4582  if (hoursMax <= 0h)
4583  hoursMax = 8h;
4584 
4585  RecordingInfo *prog = nullptr;
4588  else
4589  {
4590  prog = new RecordingInfo(
4591  chanid, MythDate::current(true), true, hoursMax);
4592  }
4593 
4594  prog->SetInputID(m_inputId);
4595 
4596  if (prog->GetRecordingStartTime() == prog->GetRecordingEndTime())
4597  {
4598  LOG(VB_GENERAL, LOG_ERR, LOC + "GetProgramRingBufferForLiveTV()"
4599  "\n\t\t\tProgramInfo is invalid."
4600  "\n" + prog->toString());
4601  prog->SetScheduledEndTime(prog->GetRecordingStartTime().addSecs(3600));
4603 
4604  prog->SetChanID(chanid);
4605  }
4606 
4609 
4610  prog->SetStorageGroup("LiveTV");
4611 
4612  if (WaitForNextLiveTVDir())
4613  {
4614  QMutexLocker lock(&m_nextLiveTVDirLock);
4616  }
4617  else
4618  {
4619  StorageGroup sgroup("LiveTV", gCoreContext->GetHostName());
4620  prog->SetPathname(sgroup.FindNextDirMostFree());
4621  }
4622 
4624  prog->SetRecordingGroup("LiveTV");
4625 
4626  StartedRecording(prog);
4627 
4628  *Buffer = MythMediaBuffer::Create(prog->GetPathname(), true);
4629  if (!(*Buffer) || !(*Buffer)->IsOpen())
4630  {
4631  LOG(VB_GENERAL, LOG_ERR, LOC + QString("RingBuffer '%1' not open...")
4632  .arg(prog->GetPathname()));
4633 
4634  delete *Buffer;
4635  delete prog;
4636 
4637  return false;
4638  }
4639 
4640  *pginfo = prog;
4641  return true;
4642 }
4643 
4644 bool TVRec::CreateLiveTVRingBuffer(const QString & channum)
4645 {
4646  LOG(VB_RECORD, LOG_INFO, LOC + QString("CreateLiveTVRingBuffer(%1)")
4647  .arg(channum));
4648 
4649  RecordingInfo *pginfo = nullptr;
4650  MythMediaBuffer *buffer = nullptr;
4651 
4652  if (!m_channel ||
4653  !m_channel->CheckChannel(channum))
4654  {
4656  return false;
4657  }
4658 
4659  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4660  {
4661  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4663  LOG(VB_GENERAL, LOG_ERR, LOC +
4664  QString("CreateLiveTVRingBuffer(%1) failed").arg(channum));
4665  return false;
4666  }
4667 
4668  SetRingBuffer(buffer);
4669 
4673 
4674  bool discont = (m_tvChain->TotalSize() > 0);
4676  m_channel->GetInputName(), discont);
4677 
4678  if (m_curRecording)
4679  {
4681  delete m_curRecording;
4682  }
4683 
4684  m_curRecording = pginfo;
4686 
4687  return true;
4688 }
4689 
4690 bool TVRec::SwitchLiveTVRingBuffer(const QString & channum,
4691  bool discont, bool set_rec)
4692 {
4693  QString msg;
4694  if (m_curRecording)
4695  {
4696  msg = QString(" curRec(%1) curRec.size(%2)")
4697  .arg(m_curRecording->MakeUniqueKey())
4698  .arg(m_curRecording->GetFilesize());
4699  }
4700  LOG(VB_RECORD, LOG_INFO, LOC +
4701  QString("SwitchLiveTVRingBuffer(discont %1, set_next_rec %2)")
4702  .arg(discont).arg(set_rec) + msg);
4703 
4704  RecordingInfo *pginfo = nullptr;
4705  MythMediaBuffer *buffer = nullptr;
4706 
4707  if (!m_channel ||
4708  !m_channel->CheckChannel(channum))
4709  {
4711  return false;
4712  }
4713 
4714  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4715  {
4717  return false;
4718  }
4719 
4720  QString oldinputtype = m_tvChain->GetInputType(-1);
4721 
4722  pginfo->MarkAsInUse(true, kRecorderInUseID);
4727  m_channel->GetInputName(), discont);
4728 
4729  if (set_rec && m_recorder)
4730  {
4731  m_recorder->SetNextRecording(pginfo, buffer);
4732  if (discont)
4734  delete pginfo;
4735  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4736  }
4737  else if (!set_rec)
4738  {
4739  // dummy recordings are finished before this
4740  // is called and other recordings must be finished..
4741  if (m_curRecording && oldinputtype != "DUMMY")
4742  {
4745  delete m_curRecording;
4746  }
4747  m_curRecording = pginfo;
4748  SetRingBuffer(buffer);
4749  }
4750  else
4751  {
4752  delete buffer;
4753  }
4754 
4755  return true;
4756 }
4757 
4759 {
4760  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer()");
4761 
4762  if (m_switchingBuffer)
4763  {
4764  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4765  "already switching.");
4766  return nullptr;
4767  }
4768 
4769  if (!m_recorder)
4770  {
4771  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4772  "invalid recorder.");
4773  return nullptr;
4774  }
4775 
4776  if (!m_curRecording)
4777  {
4778  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4779  "invalid recording.");
4780  return nullptr;
4781  }
4782 
4783  if (rcinfo.GetChanID() != m_curRecording->GetChanID())
4784  {
4785  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4786  "Not the same channel.");
4787  return nullptr;
4788  }
4789 
4790  auto *ri = new RecordingInfo(rcinfo);
4792 
4793  QString pn = LoadProfile(nullptr, ri, profile);
4794 
4795  if (pn != m_recProfileName)
4796  {
4797  LOG(VB_RECORD, LOG_ERR, LOC +
4798  QString("SwitchRecordingRingBuffer() -> "
4799  "cannot switch profile '%1' to '%2'")
4800  .arg(m_recProfileName, pn));
4801  return nullptr;
4802  }
4803 
4805 
4806  ri->MarkAsInUse(true, kRecorderInUseID);
4807  StartedRecording(ri);
4808 
4809  bool write = m_genOpt.m_inputType != "IMPORT";
4810  MythMediaBuffer *buffer = MythMediaBuffer::Create(ri->GetPathname(), write);
4811  if (!buffer || !buffer->IsOpen())
4812  {
4813  delete buffer;
4814  ri->SetRecordingStatus(RecStatus::Failed);
4815  FinishedRecording(ri, nullptr);
4816  ri->MarkAsInUse(false, kRecorderInUseID);
4817  delete ri;
4818  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer() -> "
4819  "Failed to create new RB.");
4820  return nullptr;
4821  }
4822 
4823  m_recorder->SetNextRecording(ri, buffer);
4824  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4826  m_switchingBuffer = true;
4827  ri->SetRecordingStatus(RecStatus::Recording);
4828  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer -> done");
4829  return ri;
4830 }
4831 
4833 {
4834  QMap<uint,TVRec*>::const_iterator it = s_inputs.constFind(inputid);
4835  if (it == s_inputs.constEnd())
4836  return nullptr;
4837  return *it;
4838 }
4839 
4840 QString TuningRequest::toString(void) const
4841 {
4842  return QString("Program(%1) channel(%2) input(%3) flags(%4)")
4843  .arg((m_program == nullptr) ? QString("NULL") : m_program->toString(),
4845 }
4846 
4847 #ifdef USING_DVB
4848 #include "dvbchannel.h"
4850 {
4851  // Some DVB devices munge the PMT and/or PAT so the CRC check fails.
4852  // We need to tell the stream data class to not check the CRC on
4853  // these devices. This can cause segfaults.
4854  auto * dvb = dynamic_cast<DVBChannel*>(c);
4855  if (dvb != nullptr)
4856  s->SetIgnoreCRC(dvb->HasCRCBug());
4857 }
4858 #else
4860 #endif // USING_DVB
4861 
4862 /* vim: set expandtab tabstop=4 shiftwidth=4: */
GeneralDBOptions
Definition: tv_rec.h:68
TVRec::CreateLiveTVRingBuffer
bool CreateLiveTVRingBuffer(const QString &channum)
Definition: tv_rec.cpp:4644
kLiveTVAutoExpire
@ kLiveTVAutoExpire
Definition: programtypes.h:198
DTVChannel::GetMajorChannel
uint GetMajorChannel(void) const
Returns major channel, 0 if unknown.
Definition: dtvchannel.h:94
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:212
BROWSE_LEFT
@ BROWSE_LEFT
Fetch information on current channel in the past.
Definition: tv.h:43
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:802
RecStatus::Type
Type
Definition: recStatus.h:16
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:124
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:4425
TVRec::GetKeyframeDurations
bool GetKeyframeDurations(int64_t start, int64_t end, frm_pos_map_t &map) const
Definition: tv_rec.cpp:2632
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:2479
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:338
TVRec::m_runJobOnHostOnly
bool m_runJobOnHostOnly
Definition: tv_rec.h:364
PendingInfo::m_possibleConflicts
std::vector< uint > m_possibleConflicts
Definition: tv_rec.h:141
ChannelBase::Init
virtual bool Init(QString &startchannel, bool setchan)
Definition: channelbase.cpp:57
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:80
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:211
TVRec::kFlagNoRec
static const uint kFlagNoRec
Definition: tv_rec.h:467
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:269
TVRec::kFlagErrored
static const uint kFlagErrored
Definition: tv_rec.h:447
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:286
TVRec::m_startRecordingDeadline
QDateTime m_startRecordingDeadline
Definition: tv_rec.h:348
TVRec::m_channel
ChannelBase * m_channel
Definition: tv_rec.h:341
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
MARK_ASPECT_16_9
@ MARK_ASPECT_16_9
Definition: programtypes.h:68
JobQueue::RemoveJobsFromMask
static void RemoveJobsFromMask(int jobs, int &mask)
Definition: jobqueue.h:200
TVRec::kFlagEITScannerRunning
static const uint kFlagEITScannerRunning
Definition: tv_rec.h:478
RecordingInfo::FinishedRecording
void FinishedRecording(bool allowReRecord)
If not a premature stop, adds program to history of recorded programs.
Definition: recordinginfo.cpp:1216
InputInfo::m_chanId
uint m_chanId
chanid restriction if applicable
Definition: inputinfo.h:51
BROWSE_UP
@ BROWSE_UP
Fetch information on previous channel.
Definition: tv.h:41
JobQueue::JobIsInMask
static bool JobIsInMask(int job, int mask)
Definition: jobqueue.h:196
TVRec::SetPseudoLiveTVRecording
void SetPseudoLiveTVRecording(RecordingInfo *pi)
Sets the pseudo LiveTV RecordingInfo.
Definition: tv_rec.cpp:322
MPEGStreamData::SetVideoStreamsRequired
void SetVideoStreamsRequired(uint num)
Definition: mpegstreamdata.h:248
MARK_ASPECT_2_21_1
@ MARK_ASPECT_2_21_1
Definition: programtypes.h:69
DTVSignalMonitor::SetDVBService
void SetDVBService(uint network_id, uint transport_id, int service_id)
Definition: dtvsignalmonitor.cpp:229
TuningRequest
Definition: tv_rec.h:104
TVRec::WaitForEventThreadSleep
bool WaitForEventThreadSleep(bool wake=true, std::chrono::milliseconds time=std::chrono::milliseconds::max())
Definition: tv_rec.cpp:1523
error
static void error(const char *str,...)
Definition: vbi.cpp:42
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
ProgramInfo::SetRecordingStatus
void SetRecordingStatus(RecStatus::Type status)
Definition: programinfo.h:580
CHANNEL_DIRECTION_DOWN
@ CHANNEL_DIRECTION_DOWN
Definition: tv.h:31
dtvrecorder.h
ProgramInfo::QueryMplexID
uint QueryMplexID(void) const
Queries multiplex any recording would be made on, zero if unknown.
Definition: programinfo.cpp:2650
TVRec::m_recProfileName
QString m_recProfileName
Definition: tv_rec.h:382
ChannelChangeDirection
ChannelChangeDirection
ChannelChangeDirection is an enumeration of possible channel changing directions.
Definition: tv.h:28
TVRec::m_audioSampleRateDB
int m_audioSampleRateDB
Definition: tv_rec.h:367
mythdb.h
RecorderBase::CreateRecorder
static RecorderBase * CreateRecorder(TVRec *tvrec, ChannelBase *channel, RecordingProfile &profile, const GeneralDBOptions &genOpt)
Definition: recorderbase.cpp:851
TVRec::ShouldSwitchToAnotherInput
bool ShouldSwitchToAnotherInput(const QString &chanid) const
Checks if named channel exists on current tuner, or another tuner.
Definition: tv_rec.cpp:2188
TVRec::kFlagRecording
static const uint kFlagRecording
final result desired is a timed recording
Definition: tv_rec.h:454
RecordingRule::Save
bool Save(bool sendSig=true)
Definition: recordingrule.cpp:382
SignalMonitor::IsAllGood
virtual bool IsAllGood(void) const
Definition: signalmonitor.h:85
CHANNEL_DIRECTION_UP
@ CHANNEL_DIRECTION_UP
Definition: tv.h:30
JobQueue::QueueJob
static bool QueueJob(int jobType, uint chanid, const QDateTime &recstartts, const QString &args="", const QString &comment="", QString host="", int flags=0, int status=JOB_QUEUED, QDateTime schedruntime=QDateTime())
Definition: jobqueue.cpp:523
CardUtil::GetInputName
static QString GetInputName(uint inputid)
Definition: cardutil.cpp:1701
EITScanner::StopPassiveScan
void StopPassiveScan(void)
Stops inserting Event Information Tables into DB.
Definition: eitscanner.cpp:212
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:404
ChannelBase::Open
virtual bool Open(void)=0
Opens the channel changing hardware for use.
TVRec::m_tuningRequests
TuningQueue m_tuningRequests
Definition: tv_rec.h:398
RemoteGetState
uint RemoteGetState(uint inputid)
Definition: tvremoteutil.cpp:30
ChannelBase::GetInputName
virtual QString GetInputName(void) const
Definition: channelbase.h:69
kRecorderInUseID
const QString kRecorderInUseID
Definition: programtypes.cpp:17
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:136
RecordingInfo::ApplyRecordRecID
void ApplyRecordRecID(void)
Sets recordid to match RecordingRule recordid.
Definition: recordinginfo.cpp:536
PictureAdjustType
PictureAdjustType
Definition: tv.h:120
MPEGStreamData::SetCaching
void SetCaching(bool cacheTables)
Definition: mpegstreamdata.h:90
ProgramInfo::SetRecordingID
virtual void SetRecordingID(uint _recordedid)
Definition: programinfo.h:578
TVRec::Init
bool Init(void)
Performs instance initialization, returns true on success.
Definition: tv_rec.cpp:136
SignalMonitor::IsSupported
static bool IsSupported(const QString &cardtype)
Definition: signalmonitor.h:323
MythMediaBuffer::StopReads
void StopReads(void)
Definition: mythmediabuffer.cpp:662
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:303
eitscanner.h
RecStatus::Tuning
@ Tuning
Definition: recStatus.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:2490
pid_cache_item_t
Definition: channelutil.h:24
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:2960
GeneralDBOptions::m_signalTimeout
uint m_signalTimeout
Definition: tv_rec.h:79
TVRec::m_eitTransportTimeout
std::chrono::seconds m_eitTransportTimeout
Definition: tv_rec.h:366
RecordingInfo::GetFilesize
uint64_t GetFilesize(void) const override
Definition: recordinginfo.cpp:1702
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:4455
RecorderBase::Unpause
virtual void Unpause(void)
Unpause tells recorder to unpause.
Definition: recorderbase.cpp:273
TVRec::kFlagRingBufferReady
static const uint kFlagRingBufferReady
Definition: tv_rec.h:486
ProgramInfo::GetRecordingID
uint GetRecordingID(void) const
Definition: programinfo.h:445
MythMediaBuffer::GetWritePosition
long long GetWritePosition(void) const
Returns how far into a ThreadedFileWriter file we have written.
Definition: mythmediabuffer.cpp:1786
TVRec::m_buffer
MythMediaBuffer * m_buffer
Definition: tv_rec.h:431
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:56
TVRec::m_triggerLiveTVDir
QWaitCondition m_triggerLiveTVDir
Definition: tv_rec.h:424
RecStatus::Cancelled
@ Cancelled
Definition: recStatus.h:26
TVRec::m_eventThread
MThread * m_eventThread
Event processing thread, runs TVRec::run().
Definition: tv_rec.h:357
TVRec::kFlagRecorderRunning
static const uint kFlagRecorderRunning
Definition: tv_rec.h:481
GeneralDBOptions::m_inputType
QString m_inputType
Definition: tv_rec.h:76
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
TVRec::kFlagRec
static const uint kFlagRec
Definition: tv_rec.h:457
JOB_COMMFLAG
@ JOB_COMMFLAG
Definition: jobqueue.h:77
ProgramInfo::kTitleSubtitle
@ kTitleSubtitle
Definition: programinfo.h:509
TVRec::m_recStatus
RecStatus::Type m_recStatus
Definition: tv_rec.h:408
ChannelUtil::GetATSCChannel
static bool GetATSCChannel(uint sourceid, const QString &channum, uint &major, uint &minor)
Definition: channelutil.cpp:1853
TVRec::SetInput
QString SetInput(QString input)
Changes to the specified input.
Definition: tv_rec.cpp:3068
mythburn.write
def write(text, progress=True)
Definition: mythburn.py:308
ChannelUtil::GetProgramNumber
static int GetProgramNumber(uint sourceid, const QString &channum)
Definition: channelutil.h:189
SignalMonitor::kDTVSigMon_WaitForMGT
static const uint64_t kDTVSigMon_WaitForMGT
Definition: signalmonitor.h:185
TVRec::GetSourceID
uint GetSourceID(void) const
Returns current source id.
Definition: tv_rec.cpp:3053
EITScanner::StartPassiveScan
void StartPassiveScan(ChannelBase *channel, EITSource *eitSource)
Start inserting Event Information Tables from the multiplex we happen to be tuned to into the databas...
Definition: eitscanner.cpp:180
JobQueue::QueueRecordingJobs
static bool QueueRecordingJobs(const RecordingInfo &recinfo, int jobTypes=JOB_NONE)
Definition: jobqueue.cpp:501
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:201
TVRec::m_overRecordCategory
QString m_overRecordCategory
Definition: tv_rec.h:370
PendingInfo::m_hasLaterShowing
bool m_hasLaterShowing
Definition: tv_rec.h:137
ProgramInfo::GetCategory
QString GetCategory(void) const
Definition: programinfo.h:368
RecStatus::TunerBusy
@ TunerBusy
Definition: recStatus.h:24
DTVRecorder::SetStreamData
virtual void SetStreamData(MPEGStreamData *data)
Definition: dtvrecorder.cpp:216
TVRec::GetProgramRingBufferForLiveTV
bool GetProgramRingBufferForLiveTV(RecordingInfo **pginfo, MythMediaBuffer **Buffer, const QString &channum)
Definition: tv_rec.cpp:4545
JOB_NONE
@ JOB_NONE
Definition: jobqueue.h:73
PendingInfo::m_info
ProgramInfo * m_info
Definition: tv_rec.h:135
MythNotification
Definition: mythnotification.h:29
DTVChannel::GetMinorChannel
uint GetMinorChannel(void) const
Returns minor channel, 0 if unknown.
Definition: dtvchannel.h:98
RecStatus::Unknown
@ Unknown
Definition: recStatus.h:32
apply_broken_dvb_driver_crc_hack
static void apply_broken_dvb_driver_crc_hack(ChannelBase *, MPEGStreamData *)
Definition: tv_rec.cpp:4849
TuningRequest::toString
QString toString(void) const
Definition: tv_rec.cpp:4840
RecordingRule::m_endOffset
int m_endOffset
Definition: recordingrule.h:112
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:689
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:387
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
osd.h
atscstreamdata.h
TVRec::m_curRecording
RecordingInfo * m_curRecording
Definition: tv_rec.h:411
ProgramInfo::SaveCommFlagged
void SaveCommFlagged(CommFlagStatus flag)
Set "commflagged" field in "recorded" table to "flag".
Definition: programinfo.cpp:3268
RecStatus::Recorded
@ Recorded
Definition: recStatus.h:29
TVRec::StopRecording
void StopRecording(bool killFile=false)
Changes from a recording state to kState_None.
Definition: tv_rec.cpp:705
RecorderBase::GetKeyframePositions
bool GetKeyframePositions(long long start, long long end, frm_pos_map_t &map) const
Definition: recorderbase.cpp:539
MythMediaBuffer
Definition: mythmediabuffer.h:50
DTVChannel::GetFormat
QString GetFormat(void)
Definition: dtvchannel.h:46
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
ProgramInfo::GetScheduledEndTime
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:396
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
FireWireDBOptions::m_speed
int m_speed
Definition: tv_rec.h:99
RecordingInfo::kLiveTVRecGroup
@ kLiveTVRecGroup
Definition: recordinginfo.h:192
TVRec::GetFramesWritten
long long GetFramesWritten(void)
Returns number of frames written to disk by recorder.
Definition: tv_rec.cpp:2573
TVRec::GetDevices
static bool GetDevices(uint inputid, uint &parentid, GeneralDBOptions &gen_opts, DVBDBOptions &dvb_opts, FireWireDBOptions &firewire_opts)
Definition: tv_rec.cpp:1638
channelbase.h
TableID::CVCT
@ CVCT
Definition: mpegtables.h:363
ProgramInfo::UpdateInUseMark
void UpdateInUseMark(bool force=false)
Definition: programinfo.cpp:4809
num_inputs
static int num_inputs(void)
Definition: tv_rec.cpp:1235
TVRec::GetInput
QString GetInput(void) const
Returns current input.
Definition: tv_rec.cpp:3043
ChannelUtil::GetMplexID
static uint GetMplexID(uint sourceid, const QString &channum)
Definition: channelutil.cpp:459
TVRec::kFlagDummyRecorderRunning
static const uint kFlagDummyRecorderRunning
Definition: tv_rec.h:480
ChannelBase::GetChannelName
virtual QString GetChannelName(void) const
Definition: channelbase.h:64
TVRec::m_setChannelLock
QMutex m_setChannelLock
Definition: tv_rec.h:385
RecordingQuality::IsDamaged
bool IsDamaged(void) const
Definition: recordingquality.cpp:107
mythsystemevent.h
build_compdb.file
file
Definition: build_compdb.py:55
RecordingInfo::UpdateRecordingEnd
void UpdateRecordingEnd(void)
Update information in the recorded table when the end-time of a recording is changed.
Definition: recordinginfo.cpp:1256
TVRec::GetDTVChannel
DTVChannel * GetDTVChannel(void)
Definition: tv_rec.cpp:1180
TVRec::kFlagPendingActions
static const uint kFlagPendingActions
Definition: tv_rec.h:474
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:2324
RecorderBase::Pause
virtual void Pause(bool clear=true)
Pause tells recorder to pause, it should not block.
Definition: recorderbase.cpp:262
MasterGuideTable::TableCount
uint TableCount() const
Definition: atsctables.h:117
ProgramInfo::GetRecordingEndTime
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:411
ChannelBase::GetPictureAttribute
virtual int GetPictureAttribute(PictureAttribute) const
Definition: channelbase.h:94
ProgramInfo::GetRecordingGroup
QString GetRecordingGroup(void) const
Definition: programinfo.h:418
TVRec::GetChainID
QString GetChainID(void)
Get the chainid of the livetv instance.
Definition: tv_rec.cpp:2706
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:369
RecorderBase::GetKeyframeDurations
bool GetKeyframeDurations(long long start, long long end, frm_pos_map_t &map) const
Definition: recorderbase.cpp:561
ProgramInfo::QueryTuningInfo
bool QueryTuningInfo(QString &channum, QString &input) const
Returns the channel and input needed to record the program.
Definition: programinfo.cpp:5194
GetPidsToCache
static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
Definition: tv_rec.cpp:1813
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
TVRec::m_pauseNotify
bool m_pauseNotify
Definition: tv_rec.h:396
dvbchannel.h
TVRec::TuningOnSameMultiplex
bool TuningOnSameMultiplex(TuningRequest &request)
Definition: tv_rec.cpp:3452
TVRec::TeardownRecorder
void TeardownRecorder(uint request_flags)
Tears down the recorder.
Definition: tv_rec.cpp:1106
kState_Error
@ kState_Error
Error State, if we ever try to enter this state errored is set.
Definition: tv.h:54
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:403
TVRec::GetFilePosition
long long GetFilePosition(void)
Returns total number of bytes written by RingBuffer.
Definition: tv_rec.cpp:2588
ProgramInfo::GetPathname
QString GetPathname(void) const
Definition: programinfo.h:342
TVRec::kFlagCancelNextRecording
static const uint kFlagCancelNextRecording
Definition: tv_rec.h:448
RecordingQuality::toStringXML
QString toStringXML(void) const
Definition: recordingquality.cpp:113
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:620
TVRec::SwitchRecordingRingBuffer
RecordingInfo * SwitchRecordingRingBuffer(const RecordingInfo &rcinfo)
Definition: tv_rec.cpp:4758
tmp
static guint32 * tmp
Definition: goom_core.cpp:31
TVRec::GetRecordEndTime
QDateTime GetRecordEndTime(const ProgramInfo *pi) const
Returns recording end time with proper post-roll.
Definition: tv_rec.cpp:332
TVRec::m_recordEndTime
QDateTime m_recordEndTime
Definition: tv_rec.h:412
DTVChannel::GetTuningMode
QString GetTuningMode(void) const
Returns tuning mode last set by SetTuningMode().
Definition: dtvchannel.cpp:72
kState_ChangingState
@ kState_ChangingState
This is a placeholder state which we never actually enter, but is returned by GetState() when we are ...
Definition: tv.h:89
DTVChannel::GetOriginalNetworkID
uint GetOriginalNetworkID(void) const
Returns DVB original_network_id, 0 if unknown.
Definition: dtvchannel.h:102
LiveTVChain::GetProgramAt
ProgramInfo * GetProgramAt(int at) const
Returns program at the desired location.
Definition: livetvchain.cpp:320
kState_None
@ kState_None
None State, this is the initial state in both TV and TVRec, it indicates that we are ready to change ...
Definition: tv.h:58
EITScanner::StopActiveScan
void StopActiveScan(void)
Definition: eitscanner.cpp:296
SignalMonitor::IsRequired
static bool IsRequired(const QString &cardtype)
Returns true iff the card type supports signal monitoring.
Definition: signalmonitor.h:318
TVRec::TeardownAll
void TeardownAll(void)
Definition: tv_rec.cpp:193
GeneralDBOptions::m_channelTimeout
uint m_channelTimeout
Definition: tv_rec.h:80
MPEGStreamData::SetIgnoreCRC
void SetIgnoreCRC(bool haveCRCbug)
Definition: mpegstreamdata.h:110
TVRec::m_inputId
uint m_inputId
Definition: tv_rec.h:373
GeneralDBOptions::m_vbiDev
QString m_vbiDev
Definition: tv_rec.h:74
TVRec::m_overRecordSecNrml
std::chrono::seconds m_overRecordSecNrml
Definition: tv_rec.h:368
TVRec::RecorderPaused
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2951
JOB_LIVE_REC
@ JOB_LIVE_REC
Definition: jobqueue.h:59
MythDate::secsInFuture
std::chrono::seconds secsInFuture(const QDateTime &future)
Definition: mythdate.cpp:204
TVRec::m_pendingRecordings
PendingMap m_pendingRecordings
Definition: tv_rec.h:418
TRANSITION
#define TRANSITION(ASTATE, BSTATE)
Definition: tv_rec.cpp:989
TVRec::kFlagAnyRecRunning
static const uint kFlagAnyRecRunning
Definition: tv_rec.h:482
ChannelBase::InitPictureAttributes
virtual bool InitPictureAttributes(void)
Definition: channelbase.h:93
TVRec::GetInputId
uint GetInputId(void) const
Returns the inputid.
Definition: tv_rec.h:237
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:5001
DTVChannel::GetTransportID
uint GetTransportID(void) const
Returns DVB transport_stream_id, 0 if unknown.
Definition: dtvchannel.h:106
MPEGStreamData::ReturnCachedTable
virtual void ReturnCachedTable(const PSIPTable *psip) const
Definition: mpegstreamdata.cpp:1458
mythdate.h
TVRec::kFlagWaitingForSignal
static const uint kFlagWaitingForSignal
Definition: tv_rec.h:472
TVRec::kFlagDetect
static const uint kFlagDetect
Definition: tv_rec.h:487
ProgramInfo::SetPathname
void SetPathname(const QString &pn)
Definition: programinfo.cpp:2436
ProgramInfo::SaveVideoProperties
void SaveVideoProperties(uint mask, uint video_property_flags)
Definition: programinfo.cpp:4759
ProgramInfo::SetRecordingEndTime
void SetRecordingEndTime(const QDateTime &dt)
Definition: programinfo.h:526
TVRec::CreateChannel
bool CreateChannel(const QString &startchannel, bool enter_power_save_mode)
Definition: tv_rec.cpp:91
TVRec::m_autoRunJobs
QHash< QString, int > m_autoRunJobs
Definition: tv_rec.h:414
minor
#define minor(X)
Definition: compat.h:138
RecordingInfo::GetRecordingFile
RecordingFile * GetRecordingFile() const
Definition: recordinginfo.h:280
TVRec::PauseRecorder
void PauseRecorder(void)
Tells "recorder" to pause, used for channel and input changes.
Definition: tv_rec.cpp:2932
programinfo.h
TVRec::NotifySchedulerOfRecording
void NotifySchedulerOfRecording(RecordingInfo *rec)
Tell scheduler about the recording.
Definition: tv_rec.cpp:2755
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:1308
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:389
mythlogging.h
SignalMonitor::kDVBSigMon_WaitForPos
static const uint64_t kDVBSigMon_WaitForPos
Wait for rotor to complete turning the antenna.
Definition: signalmonitor.h:202
ProgramInfo::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:446
TVRec::SetRecordingStatus
void SetRecordingStatus(RecStatus::Type new_status, int line, bool have_lock=false)
Definition: tv_rec.cpp:675
ProgramInfo::QueryAverageAspectRatio
MarkTypes QueryAverageAspectRatio(void) const
Definition: programinfo.cpp:4405
is_dishnet_eit
static bool is_dishnet_eit(uint inputid)
Definition: tv_rec.cpp:1214
DVBStreamData::SetDishNetEIT
void SetDishNetEIT(bool use_dishnet_eit)
Definition: dvbstreamdata.h:164
LiveTVChain::SetHostPrefix
void SetHostPrefix(const QString &prefix)
Definition: livetvchain.cpp:44
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:784
RemoteStopRecording
bool RemoteStopRecording(uint inputid)
Definition: tvremoteutil.cpp:97
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:74
hardwareprofile.scan.profile
profile
Definition: scan.py:99
MasterGuideTable::TablePID
uint TablePID(uint i) const
Definition: atsctables.h:131
CardUtil::IsEncoder
static bool IsEncoder(const QString &rawtype)
Definition: cardutil.h:130
RemoteIsBusy
bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
Definition: tvremoteutil.cpp:361
TVRec::kFlagKillRec
static const uint kFlagKillRec
close recorder, discard recording
Definition: tv_rec.h:465
ProgramInfo::SetScheduledEndTime
void SetScheduledEndTime(const QDateTime &dt)
Definition: programinfo.h:524
TuningRequest::m_progNum
int m_progNum
Definition: tv_rec.h:125
ProgramInfo::SetInputID
void SetInputID(uint id)
Definition: programinfo.h:540
DTVChannel::SaveCachedPids
void SaveCachedPids(const pid_cache_t &pid_cache) const
Saves MPEG PIDs to cache to database.
Definition: dtvchannel.cpp:106
MythCoreContext::GetBackendServerPort
int GetBackendServerPort(void)
Returns the locally defined backend control port.
Definition: mythcorecontext.cpp:1088
TVRec::m_recorder
RecorderBase * m_recorder
Definition: tv_rec.h:340
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1556
ChannelBase::StoreInputChannels
virtual void StoreInputChannels(void)
Saves current channel as the default channel for the current input.
Definition: channelbase.cpp:640
TVRec::GetMaxBitrate
long long GetMaxBitrate(void) const
Returns the maximum bits per second this recorder can produce.
Definition: tv_rec.cpp:2648
MythCoreContext::SendEvent
void SendEvent(const MythEvent &event)
Definition: mythcorecontext.cpp:1542
TVRec::kFlagRunMainLoop
static const uint kFlagRunMainLoop
Definition: tv_rec.h:444
ProgramInfo::SetRecordingRuleType
void SetRecordingRuleType(RecordingType type)
Definition: programinfo.h:581
TVRec::RemoveRecording
TVState RemoveRecording(TVState state) const
If "state" is kState_RecordingOnly or kState_WatchingLiveTV, returns a kState_None,...
Definition: tv_rec.cpp:752
TVRec::m_pseudoLiveTVRecording
RecordingInfo * m_pseudoLiveTVRecording
Definition: tv_rec.h:421
MPEGStreamData::SetRecordingType
void SetRecordingType(const QString &recording_type)
Definition: mpegstreamdata.cpp:101
hardwareprofile.i18n.t
t
Definition: i18n.py:36
TVRec::FlagToString
static QString FlagToString(uint f)
Definition: tv_rec.cpp:4443
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:360
compat.h
TVRec::HandleStateChange
void HandleStateChange(void)
Changes the internalState to the desiredNextState if possible.
Definition: tv_rec.cpp:1001
pid_cache_t
std::vector< pid_cache_item_t > pid_cache_t
Definition: channelutil.h:43
TVRec::kAutoRunNone
@ kAutoRunNone
Definition: tv_rec.h:329
LiveTVChain::SetInputType
void SetInputType(const QString &type)
Definition: livetvchain.cpp:49
ATSCStreamData
Encapsulates data about ATSC stream and emits events for most tables.
Definition: atscstreamdata.h:28
v4lchannel.h
TVRec::m_tvChain
LiveTVChain * m_tvChain
Definition: tv_rec.h:428
DVBDBOptions::m_dvbOnDemand
bool m_dvbOnDemand
Definition: tv_rec.h:89
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:200
TVRec::CheckChannel
bool CheckChannel(const QString &name) const
Checks if named channel exists on current tuner.
Definition: tv_rec.cpp:2278
SignalMonitor::kDTVSigMon_WaitForPMT
static const uint64_t kDTVSigMon_WaitForPMT
Definition: signalmonitor.h:184
RecorderBase::Reset
virtual void Reset(void)=0
Reset the recorder to the startup state.
TVRec::kFlagSignalMonitorRunning
static const uint kFlagSignalMonitorRunning
Definition: tv_rec.h:477
ProgramInfo::SetRecordingGroup
void SetRecordingGroup(const QString &group)
Definition: programinfo.h:527
TVRec::SetupSignalMonitor
bool SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
This creates a SignalMonitor instance and begins signal monitoring.
Definition: tv_rec.cpp:2042
SignalMonitor::kDTVSigMon_WaitForPAT
static const uint64_t kDTVSigMon_WaitForPAT
Definition: signalmonitor.h:183
MythCoreContext::GetDurSetting
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
Definition: mythcorecontext.h:170
TVRec::TuningGetChanNum
QString TuningGetChanNum(const TuningRequest &request, QString &input) const
Definition: tv_rec.cpp:3413
TVRec::kFlagEITScan
static const uint kFlagEITScan
final result desired is an EIT Scan
Definition: tv_rec.h:461
SignalMonitor::kDTVSigMon_WaitForSDT
static const uint64_t kDTVSigMon_WaitForSDT
Definition: signalmonitor.h:188
TVRec::TeardownSignalMonitor
void TeardownSignalMonitor(void)
If a SignalMonitor instance exists, the monitoring thread is stopped and the instance is deleted.
Definition: tv_rec.cpp:2096
RecorderBase::GetRecordingQuality
virtual RecordingQuality * GetRecordingQuality(const RecordingInfo *ri) const
Returns a report about the current recordings quality.
Definition: recorderbase.cpp:505
TVRec::WaitForNextLiveTVDir
bool WaitForNextLiveTVDir(void)
Definition: tv_rec.cpp:4524
RecStatus::Failing
@ Failing
Definition: recStatus.h:18
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:463
RecordingInfo::GetAutoRunJobs
int GetAutoRunJobs(void) const
Returns a bitmap of which jobs are attached to this RecordingInfo.
Definition: recordinginfo.cpp:504
ProgramInfo::GetSourceID
uint GetSourceID(void) const
Definition: programinfo.h:461
MPEGStreamData
Encapsulates data about MPEG stream and emits events for each table.
Definition: mpegstreamdata.h:84
RecordingRule::m_recProfile
QString m_recProfile
Definition: recordingrule.h:121
TVRec::m_nextLiveTVDir
QString m_nextLiveTVDir
Definition: tv_rec.h:422
TVRec::m_triggerEventSleepWait
QWaitCondition m_triggerEventSleepWait
Definition: tv_rec.h:405
RecorderBase::GetFrameRate
double GetFrameRate(void) const
Returns the latest frame rate.
Definition: recorderbase.h:233
JobQueue::JobIsNotInMask
static bool JobIsNotInMask(int job, int mask)
Definition: jobqueue.h:197
TVRec::CloseChannel
void CloseChannel(void)
Definition: tv_rec.cpp:1166
RecordingRule::m_type
RecordingType m_type
Definition: recordingrule.h:113
RecStatus::Aborted
@ Aborted
Definition: recStatus.h:28
TVRec::kFlagKillRingBuffer
static const uint kFlagKillRingBuffer
Definition: tv_rec.h:468
TVRec::ChangeState
void ChangeState(TVState nextState)
Puts a state change on the nextState queue.
Definition: tv_rec.cpp:1084
DVBStreamData
Definition: dvbstreamdata.h:32
TVRec::m_desiredNextState
TVState m_desiredNextState
Definition: tv_rec.h:394
ProgramInfo::toString
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
Definition: programinfo.cpp:1933
TVRec::m_parentId
uint m_parentId
Definition: tv_rec.h:374
TVRec::run
void run(void) override
Event handling method, contains event loop.
Definition: tv_rec.cpp:1270
RecStatus::Failed
@ Failed
Definition: recStatus.h:23
TVRec::m_triggerEventLoopSignal
bool m_triggerEventLoopSignal
Definition: tv_rec.h:403
DTVRecorder::GetStreamData
MPEGStreamData * GetStreamData(void) const
Definition: dtvrecorder.h:57
add_spacer
static QString add_spacer(const QString &channel, const QString &spacer)
Adds the spacer before the last character in chan.
Definition: tv_rec.cpp:2289
RecorderBase::IsRecording
virtual bool IsRecording(void)
Tells whether the StartRecorder() loop is running.
Definition: recorderbase.cpp:242
RecordingRule::GetAutoExpire
AutoExpireType GetAutoExpire(void) const
Definition: recordingrule.h:63
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:3576
TVRec::m_liveTVStartChannel
QString m_liveTVStartChannel
Definition: tv_rec.h:425
MythNotification::Check
static Type Check
Definition: mythnotification.h:37
storagegroup.h
TVRec::TuningRequest
friend class TuningRequest
Definition: tv_rec.h:149
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:343
TVRec::m_rbFileExt
QString m_rbFileExt
Definition: tv_rec.h:432
StandardSetting::getValue
virtual QString getValue(void) const
Definition: standardsettings.h:52
LiveTVChain::ReloadAll
void ReloadAll(const QStringList &data=QStringList())
Definition: livetvchain.cpp:209
TVRec::m_eitScanStartTime
QDateTime m_eitScanStartTime
Definition: tv_rec.h:400
TVRec::GetPictureAttribute
int GetPictureAttribute(PictureAttribute attr)
Definition: tv_rec.cpp:3009
LOC2
#define LOC2
Definition: tv_rec.cpp:47
TVRec::TuningNewRecorder
void TuningNewRecorder(MPEGStreamData *streamData)
Creates a recorder instance.
Definition: tv_rec.cpp:4174
RecordingInfo::StartedRecording
void StartedRecording(const QString &ext)
Inserts this RecordingInfo into the database as an existing recording.
Definition: recordinginfo.cpp:933
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:2621
TVRec::s_inputsLock
static QReadWriteLock s_inputsLock
Definition: tv_rec.h:435
TVRec::kFlagWaitingForRecPause
static const uint kFlagWaitingForRecPause
Definition: tv_rec.h:471
RecordingQuality
Definition: recordingquality.h:34
DTVRecorder
This is a specialization of RecorderBase used to handle MPEG-2, MPEG-4, MPEG-4 AVC,...
Definition: dtvrecorder.h:25
CHANNEL_DIRECTION_FAVORITE
@ CHANNEL_DIRECTION_FAVORITE
Definition: tv.h:32
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:134
uint
unsigned int uint
Definition: compat.h:140
TVRec::kFlagLiveTV
static const uint kFlagLiveTV
final result desired is LiveTV recording
Definition: tv_rec.h:452
TVRec::SetNextLiveTVDir
void SetNextLiveTVDir(QString dir)
Definition: tv_rec.cpp:4537
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
TVRec::GetFramerate
float GetFramerate(void)
Returns recordering frame rate from the recorder.
Definition: tv_rec.cpp:2558
TVRec::m_transcodeFirst
bool m_transcodeFirst
Definition: tv_rec.h:362
TVRec::m_signalEventCmdSent
bool m_signalEventCmdSent
Definition: tv_rec.h:346
TVRec::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: tv_rec.cpp:669
TVRec::QueueEITChannelChange
bool QueueEITChannelChange(const QString &name)
Queues up a channel change for the EITScanner.
Definition: tv_rec.cpp:3143
TVRec::m_eitCrawlIdleStart
std::chrono::seconds m_eitCrawlIdleStart
Definition: tv_rec.h:365
TuningRequest::m_minorChan
uint m_minorChan
Definition: tv_rec.h:124
DTVSignalMonitor::GetATSCStreamData
ATSCStreamData * GetATSCStreamData()
Returns the ATSC stream data if it exists.
Definition: dtvsignalmonitor.cpp:534
TVRec::m_triggerEventLoopWait
QWaitCondition m_triggerEventLoopWait
Definition: tv_rec.h:402
DTVChannel::EnterPowerSavingMode
virtual bool EnterPowerSavingMode(void)
Enters power saving mode if the card supports it.
Definition: dtvchannel.h:65
BROWSE_DOWN
@ BROWSE_DOWN
Fetch information on next channel.
Definition: tv.h:42
InputInfo::Clear
virtual void Clear(void)
Definition: inputinfo.cpp:6
CardUtil::IsV4L
static bool IsV4L(const QString &rawtype)
Definition: cardutil.h:140
TVRec::IsErrored
bool IsErrored(void) const
Returns true is "errored" is true, false otherwise.
Definition: tv_rec.h:241
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:936
RecorderBase::GetFramesWritten
virtual long long GetFramesWritten(void)=0
Returns number of frames written to disk.
states
states
Definition: mythmiscutil.cpp:1243
ProgramInfo::SaveAutoExpire
void SaveAutoExpire(AutoExpireType autoExpire, bool updateDelete=false)
Set "autoexpire" field in "recorded" table to "autoExpire".
Definition: programinfo.cpp:3321
ChannelBase::SetFd
virtual void SetFd(int fd)
Sets file descriptor.
Definition: channelbase.h:55
BROWSE_RIGHT
@ BROWSE_RIGHT
Fetch information on current channel in the future.
Definition: tv.h:44
RecordingInfo::LoadRecordingFile
void LoadRecordingFile()
Definition: recordinginfo.cpp:1666
mythmediabuffer.h
TVRec::GetRecording
ProgramInfo * GetRecording(void)
Allocates and returns a ProgramInfo for the current recording.
Definition: tv_rec.cpp:237
TVRec::SpawnLiveTV
void SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
Tells TVRec to spawn a "Live TV" recorder.
Definition: tv_rec.cpp:2676
GeneralDBOptions::m_skipBtAudio
bool m_skipBtAudio
Definition: tv_rec.h:78
CardUtil::IsVBoxPresent
static bool IsVBoxPresent(uint inputid)
Returns true if the VBox responds to a ping.
Definition: cardutil.cpp:3226
TVRec::CancelNextRecording
void CancelNextRecording(bool cancel)
Tells TVRec to cancel the upcoming recording.
Definition: tv_rec.cpp:345
frm_pos_map_t
QMap< long long, long long > frm_pos_map_t
Frame # -> File offset map.
Definition: programtypes.h:46
tvremoteutil.h
SignalMonitor::Init
static SignalMonitor * Init(const QString &cardtype, int db_cardnum, ChannelBase *channel, bool release_stream)
Definition: signalmonitor.cpp:90
InputInfo::m_inputId
uint m_inputId
unique key in DB for this input
Definition: inputinfo.h:49
PictureAttribute
PictureAttribute
Definition: videoouttypes.h:103
RecorderBase::StopRecording
virtual void StopRecording(void)
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: recorderbase.cpp:223
TVRec::m_triggerEventSleepSignal
bool m_triggerEventSleepSignal
Definition: tv_rec.h:406
ChannelUtil::GetVideoFilters
static QString GetVideoFilters(uint sourceid, const QString &channum)
Definition: channelutil.h:191
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:44
RecordingRule::m_recGroupID
uint m_recGroupID
Definition: recordingrule.h:124
SET_NEXT
#define SET_NEXT()
Definition: tv_rec.cpp:991
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:3169
SignalMonitor::HasExtraSlowTuning
virtual bool HasExtraSlowTuning(void) const
Definition: signalmonitor.h:64
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:930
dvbstreamdata.h
DTVSignalMonitor::SetProgramNumber
void SetProgramNumber(int progNum)
Definition: dtvsignalmonitor.cpp:214
MasterGuideTable
This table tells the decoder on which PIDs to find other tables, and their sizes and each table's cur...
Definition: atsctables.h:77
TVRec::m_signalMonitor
SignalMonitor * m_signalMonitor
Definition: tv_rec.h:342
BROWSE_FAVORITE
@ BROWSE_FAVORITE
Fetch information on the next favorite channel.
Definition: tv.h:45
TVRec::GetKeyframePosition
int64_t GetKeyframePosition(uint64_t desired) const
Returns byte position in RingBuffer of a keyframe according to recorder.
Definition: tv_rec.cpp:2604
ChannelGroup::ToggleChannel
static bool ToggleChannel(uint chanid, int changrpid, bool delete_chan)
Definition: channelgroup.cpp:16
TuningRequest::m_majorChan
uint m_majorChan
Definition: tv_rec.h:123
kState_WatchingPreRecorded
@ kState_WatchingPreRecorded
Watching Pre-recorded is a TV only state for when we are watching a pre-existing recording.
Definition: tv.h:67
ProgramInfo::GetInputID
uint GetInputID(void) const
Definition: programinfo.h:462
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:113
RecorderBase::SavePositionMap
void SavePositionMap(bool force=false, bool finished=false)
Save the seektable to the DB.
Definition: recorderbase.cpp:591
MythRandom
MBASE_PUBLIC uint32_t MythRandom()
Definition: mythmiscutil.h:21
ProgramInfo::SetChanID
void SetChanID(uint _chanid)
Definition: programinfo.h:522
GeneralDBOptions::m_audioSampleRate
int m_audioSampleRate
Definition: tv_rec.h:77
InputInfo::m_sourceId
uint m_sourceId
associated channel listings source
Definition: inputinfo.h:48
DVBChannel
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:30
LiveTVChain::GetInputType
QString GetInputType(int pos=-1) const
Definition: livetvchain.cpp:695
TuningRequest::m_flags
uint m_flags
Definition: tv_rec.h:119
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:371
TVRec::m_nextLiveTVDirLock
QMutex m_nextLiveTVDirLock
Definition: tv_rec.h:423
TVRec::CheckForRecGroupChange
void CheckForRecGroupChange(void)
Check if frontend changed the recording group.
Definition: tv_rec.cpp:2721
ChannelBase::SetChannelByString
virtual bool SetChannelByString(const QString &chan)=0
TVRec::m_internalState
TVState m_internalState
Definition: tv_rec.h:393
ProgramInfo::GetRecordingRuleType
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:450
livetvchain.h
DTVSignalMonitor::IgnoreEncrypted
void IgnoreEncrypted(bool ignore)
Definition: dtvsignalmonitor.h:102
TVRec::m_signalEventCmdTimeout
QDateTime m_signalEventCmdTimeout
Definition: tv_rec.h:345
Buffer
Definition: MythExternControl.h:36
DTVSignalMonitor::SetChannel
void SetChannel(int major, int minor)
Definition: dtvsignalmonitor.cpp:196
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
channelgroup.h
DVBDBOptions::m_dvbEitScan
bool m_dvbEitScan
Definition: tv_rec.h:91
MythDate::secsInPast
std::chrono::seconds secsInPast(const QDateTime &past)
Definition: mythdate.cpp:199
TVRec::m_reachedRecordingDeadline
bool m_reachedRecordingDeadline
Definition: tv_rec.h:351
RecStatus::Recording
@ Recording
Definition: recStatus.h:30
TVRec::GetChannelInfo
bool GetChannelInfo(uint &chanid, uint &sourceid, QString &callsign, QString &channum, QString &channame, QString &xmltvid) const
Definition: tv_rec.cpp:3295
TVState
TVState
TVState is an enumeration of the states used by TV and TVRec.
Definition: tv.h:50
RecStatus::Inactive
@ Inactive
Definition: recStatus.h:42
ProgramInfo::ToStringList
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
Definition: programinfo.cpp:1281
SignalMonitor::AddListener
void AddListener(SignalMonitorListener *listener)
Definition: signalmonitor.cpp:387
mythcorecontext.h
TVRec::GetV4LChannel
V4LChannel * GetV4LChannel(void)
Definition: tv_rec.cpp:1185
TVRec::m_genOpt
GeneralDBOptions m_genOpt
Definition: tv_rec.h:378
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:671
cardutil.h
ProgramInfo::IsLocal
bool IsLocal(void) const
Definition: programinfo.h:350
TVRec::m_pendingRecLock
QRecursiveMutex m_pendingRecLock
Definition: tv_rec.h:391
TVRec::RingBufferChanged
void RingBufferChanged(MythMediaBuffer *Buffer, RecordingInfo *pginfo, RecordingQuality *recq)
Definition: tv_rec.cpp:3392
JobQueue::AddJobsToMask
static void AddJobsToMask(int jobs, int &mask)
Definition: jobqueue.h:199
TVRec::TuningRestartRecorder
void TuningRestartRecorder(void)
Restarts a stopped recorder or unpauses a paused recorder.
Definition: tv_rec.cpp:4360
TVRec::kSignalMonitoringRate
static constexpr std::chrono::milliseconds kSignalMonitoringRate
How many milliseconds the signal monitor should wait between checks.
Definition: tv_rec.h:440
ChannelBase::CheckChannel
bool CheckChannel(const QString &channum) const
Definition: channelbase.cpp:658
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:4382
TVRec::SetupDTVSignalMonitor
bool SetupDTVSignalMonitor(bool EITscan)
Tells DTVSignalMonitor what channel to look for.
Definition: tv_rec.cpp:1862
ChannelGroup::GetChannelGroupId
static int GetChannelGroupId(const QString &changroupname)
Definition: channelgroup.cpp:253
TVRec::kFlagAnyRunning
static const uint kFlagAnyRunning
Definition: tv_rec.h:483
RecorderBase::SetNextRecording
void SetNextRecording(const RecordingInfo *ri, MythMediaBuffer *Buffer)
Sets next recording info, to be applied as soon as practical.
Definition: recorderbase.cpp:123
TVRec::SetSignalMonitoringRate
std::chrono::milliseconds SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend=1)
Sets the signal monitoring rate.
Definition: tv_rec.cpp:2134
kNotRecording
@ kNotRecording
Definition: recordingtypes.h:21
PreviewGeneratorQueue::GetPreviewImage
static void GetPreviewImage(const ProgramInfo &pginfo, const QString &token)
Submit a request for the generation of a preview image.
Definition: previewgeneratorqueue.h:88
TVRec::m_dvbOpt
DVBDBOptions m_dvbOpt
Definition: tv_rec.h:379
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:878
MarkTypes
MarkTypes
Definition: programtypes.h:48
JOB_METADATA
@ JOB_METADATA
Definition: jobqueue.h:78
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
DVBDBOptions
Definition: tv_rec.h:84
GeneralDBOptions::m_videoDev
QString m_videoDev
Definition: tv_rec.h:73
TVRec::kFlagFinishRecording
static const uint kFlagFinishRecording
Definition: tv_rec.h:446
DTVChannel::SetTuningMode
void SetTuningMode(const QString &tuning_mode)
Sets tuning mode: "mpeg", "dvb", "atsc", etc.
Definition: dtvchannel.cpp:86
FireWireDBOptions::m_connection
int m_connection
Definition: tv_rec.h:100
DTVSignalMonitor::SetStreamData
virtual void SetStreamData(MPEGStreamData *data)
Sets the MPEG stream data for DTVSignalMonitor to use, and connects the table signals to the monitor.
Definition: dtvsignalmonitor.cpp:258
kSingleRecord
@ kSingleRecord
Definition: recordingtypes.h:22
BROWSE_SAME
@ BROWSE_SAME
Fetch browse information on current channel and time.
Definition: tv.h:40
TVRec
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:145
FireWireDBOptions
Definition: tv_rec.h:94
RecordingInfo::AddHistory
void AddHistory(bool resched=true, bool forcedup=false, bool future=false)
Adds recording history, creating "record" it if necessary.
Definition: recordinginfo.cpp:1297
TVRec::FinishedRecording
void FinishedRecording(RecordingInfo *curRec, RecordingQuality *recq)
If not a premature stop, adds program to history of recorded programs.
Definition: tv_rec.cpp:814
TVRec::m_signalMonitorCheckCnt
uint m_signalMonitorCheckCnt
Definition: tv_rec.h:350
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:329
RecorderBase::SetVideoFilters
virtual void SetVideoFilters(QString &filters)=0
Tells recorder which filters to use.
TuningRequest::IsOnSameMultiplex
bool IsOnSameMultiplex(void) const
Definition: tv_rec.h:116
TVRec::m_stateFlags
uint m_stateFlags
Definition: tv_rec.h:397
TVRec::WakeEventLoop
void WakeEventLoop(void)
Definition: tv_rec.cpp:210
GeneralDBOptions::m_audioDev
QString m_audioDev
Definition: tv_rec.h:75
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:90
LiveTVChain::AppendNewProgram
void AppendNewProgram(ProgramInfo *pginfo, const QString &channum, const QString &inputname, bool discont)
Definition: livetvchain.cpp:60
TVRec::GetState
TVState GetState(void) const
Returns the TVState of the recorder.
Definition: tv_rec.cpp:223
MPEGStreamData::Reset
virtual void Reset(void)
Definition: mpegstreamdata.h:93
TVRec::m_signalMonitorDeadline
QDateTime m_signalMonitorDeadline
Definition: tv_rec.h:349
CardUtil::GetSourceID
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1770
DVBDBOptions::m_dvbTuningDelay
std::chrono::milliseconds m_dvbTuningDelay
Definition: tv_rec.h:90
PendingInfo::m_doNotAsk
bool m_doNotAsk
Definition: tv_rec.h:140
TVRec::SwitchLiveTVRingBuffer
bool SwitchLiveTVRingBuffer(const QString &channum, bool discont, bool set_rec)
Definition: tv_rec.cpp:4690
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:742
ChannelBase::GetInputID
virtual int GetInputID(void) const
Definition: channelbase.h:67
kState_WatchingLiveTV
@ kState_WatchingLiveTV
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
Definition: tv.h:63
RemoteRecordPending
bool RemoteRecordPending(uint inputid, const ProgramInfo *pginfo, std::chrono::seconds secsleft, bool hasLater)
Definition: tvremoteutil.cpp:49
StorageGroup
Definition: storagegroup.h:11
TableID::TVCT
@ TVCT
Definition: mpegtables.h:362
SignalMonitor::Start
virtual void Start()
Start signal monitoring thread.
Definition: signalmonitor.cpp:290
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:97
InputInfo
Definition: inputinfo.h:14
previewgeneratorqueue.h
TVRec::m_lastTuningRequest
TuningRequest m_lastTuningRequest
Definition: tv_rec.h:399
SignalMonitor::SetNotifyFrontend
void SetNotifyFrontend(bool notify)
Enables or disables frontend notification of the current signal value.
Definition: signalmonitor.h:96
TVRec::m_recorderThread
MThread * m_recorderThread
Recorder thread, runs RecorderBase::run().
Definition: tv_rec.h:359
atsctables.h
TVRec::StartedRecording
void StartedRecording(RecordingInfo *curRec)
Inserts a "curRec" into the database.
Definition: tv_rec.cpp:788
TVRec::InitAutoRunJobs
void InitAutoRunJobs(RecordingInfo *rec, AutoRunInitType t, RecordingProfile *recpro, int line)
Definition: tv_rec.cpp:2801
BrowseDirection
BrowseDirection
Used to request ProgramInfo for channel browsing.
Definition: tv.h:37
PendingInfo::m_ask