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 = CardUtil::GetStartChannel(m_inputId);
147  if (startchannel.isEmpty())
148  return false;
149  if (!CreateChannel(startchannel, true))
150  return false;
151 
153  gCoreContext->GetBoolSetting("AutoTranscodeBeforeAutoCommflag", false);
154  m_earlyCommFlag = gCoreContext->GetBoolSetting("AutoCommflagWhileRecording", false);
155  m_runJobOnHostOnly = gCoreContext->GetBoolSetting("JobsRunOnRecordHost", false);
156  m_eitTransportTimeout = gCoreContext->GetDurSetting<std::chrono::minutes>("EITTransportTimeout", 5min);
157  if (m_eitTransportTimeout < 6s)
159  m_eitCrawlIdleStart = gCoreContext->GetDurSetting<std::chrono::seconds>("EITCrawIdleStart", 60s);
160  m_audioSampleRateDB = gCoreContext->GetNumSetting("AudioSampleRate");
161  m_overRecordSecNrml = gCoreContext->GetDurSetting<std::chrono::seconds>("RecordOverTime");
162  m_overRecordSecCat = gCoreContext->GetDurSetting<std::chrono::minutes>("CategoryOverTime");
163  m_overRecordCategory= gCoreContext->GetSetting("OverTimeCategory");
164 
165  m_eventThread->start();
166 
168 
169  return true;
170 }
171 
177 {
178  s_inputs.remove(m_inputId);
179 
181  {
182  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
183  m_eventThread->wait();
184  delete m_eventThread;
185  m_eventThread = nullptr;
186  }
187 
188  if (m_channel)
189  {
190  delete m_channel;
191  m_channel = nullptr;
192  }
193 }
194 
196 {
197  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownAll");
198 
200 
201  if (m_scanner)
202  {
203  delete m_scanner;
204  m_scanner = nullptr;
205  }
206 
208 
209  SetRingBuffer(nullptr);
210 }
211 
213 {
214  QMutexLocker locker(&m_triggerEventLoopLock);
216  m_triggerEventLoopWait.wakeAll();
217 }
218 
226 {
227  if (m_changeState)
228  return kState_ChangingState;
229  return m_internalState;
230 }
231 
240 {
241  QMutexLocker lock(&m_stateChangeLock);
242 
243  ProgramInfo *tmppginfo = nullptr;
244 
246  {
247  tmppginfo = new ProgramInfo(*m_curRecording);
249  }
250  else
251  tmppginfo = new ProgramInfo();
252  tmppginfo->SetInputID(m_inputId);
253 
254  return tmppginfo;
255 }
256 
271 void TVRec::RecordPending(const ProgramInfo *rcinfo, std::chrono::seconds secsleft,
272  bool hasLater)
273 {
274  QMutexLocker statelock(&m_stateChangeLock);
275  QMutexLocker pendlock(&m_pendingRecLock);
276 
277  if (secsleft < 0s)
278  {
279  LOG(VB_RECORD, LOG_INFO, LOC + "Pending recording revoked on " +
280  QString("inputid [%1]").arg(rcinfo->GetInputID()));
281 
282  PendingMap::iterator it = m_pendingRecordings.find(rcinfo->GetInputID());
283  if (it != m_pendingRecordings.end())
284  {
285  (*it).m_ask = false;
286  (*it).m_doNotAsk = (*it).m_canceled = true;
287  }
288  return;
289  }
290 
291  LOG(VB_RECORD, LOG_INFO, LOC +
292  QString("RecordPending on inputid [%1]").arg(rcinfo->GetInputID()));
293 
294  PendingInfo pending;
295  pending.m_info = new ProgramInfo(*rcinfo);
296  pending.m_recordingStart = MythDate::current().addSecs(secsleft.count());
297  pending.m_hasLaterShowing = hasLater;
298  pending.m_ask = true;
299  pending.m_doNotAsk = false;
300 
301  m_pendingRecordings[rcinfo->GetInputID()] = pending;
302 
303  // If this isn't a recording for this instance to make, we are done
304  if (rcinfo->GetInputID() != m_inputId)
305  return;
306 
307  // We also need to check our input groups
308  vector<uint> inputids = CardUtil::GetConflictingInputs(
309  rcinfo->GetInputID());
310 
311  m_pendingRecordings[rcinfo->GetInputID()].m_possibleConflicts = inputids;
312 
313  pendlock.unlock();
314  statelock.unlock();
315  for (uint inputid : inputids)
316  RemoteRecordPending(inputid, rcinfo, secsleft, hasLater);
317  statelock.relock();
318  pendlock.relock();
319 }
320 
325 {
328  delete old_rec;
329 }
330 
334 QDateTime TVRec::GetRecordEndTime(const ProgramInfo *pi) const
335 {
336  bool spcat = (!m_overRecordCategory.isEmpty() &&
338  std::chrono::seconds secs = (spcat) ? m_overRecordSecCat : m_overRecordSecNrml;
339  return pi->GetRecordingEndTime().addSecs(secs.count());
340 }
341 
347 void TVRec::CancelNextRecording(bool cancel)
348 {
349  QMutexLocker pendlock(&m_pendingRecLock);
350  LOG(VB_RECORD, LOG_INFO, LOC +
351  QString("CancelNextRecording(%1) -- begin").arg(cancel));
352 
353  PendingMap::iterator it = m_pendingRecordings.find(m_inputId);
354  if (it == m_pendingRecordings.end())
355  {
356  LOG(VB_RECORD, LOG_INFO, LOC + QString("CancelNextRecording(%1) -- "
357  "error, unknown recording").arg(cancel));
358  return;
359  }
360 
361  if (cancel)
362  {
363  vector<uint> &inputids = (*it).m_possibleConflicts;
364  for (uint inputid : inputids)
365  {
366  LOG(VB_RECORD, LOG_INFO, LOC +
367  QString("CancelNextRecording -- inputid 0x%1")
368  .arg((uint64_t)inputid,0,16));
369 
370  pendlock.unlock();
371  RemoteRecordPending(inputid, (*it).m_info, -1s, false);
372  pendlock.relock();
373  }
374 
375  LOG(VB_RECORD, LOG_INFO, LOC +
376  QString("CancelNextRecording -- inputid [%1]")
377  .arg(m_inputId));
378 
379  RecordPending((*it).m_info, -1s, false);
380  }
381  else
382  {
383  (*it).m_canceled = false;
384  }
385 
386  LOG(VB_RECORD, LOG_INFO, LOC +
387  QString("CancelNextRecording(%1) -- end").arg(cancel));
388 }
389 
398 {
399  RecordingInfo ri1(*pginfo);
402  RecordingInfo *rcinfo = &ri1;
403 
404  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartRecording(%1)")
405  .arg(rcinfo->toString(ProgramInfo::kTitleSubtitle)));
406 
407  QMutexLocker lock(&m_stateChangeLock);
408 
411 
412  // Flush out any pending state changes
414 
415  // We need to do this check early so we don't cancel an overrecord
416  // that we're trying to extend.
420  {
421  int post_roll_seconds = m_curRecording->GetRecordingEndTime()
422  .secsTo(m_recordEndTime);
423 
428 
430  .addSecs(post_roll_seconds);
431 
432  QString msg = QString("updating recording: %1 %2 %3 %4")
433  .arg(m_curRecording->GetTitle(),
434  QString::number(m_curRecording->GetChanID()),
437  LOG(VB_RECORD, LOG_INFO, LOC + msg);
438 
439  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
440 
442  return RecStatus::Recording;
443  }
444 
445  bool cancelNext = false;
446  PendingInfo pendinfo;
447  PendingMap::iterator it;
448 
449  m_pendingRecLock.lock();
450  if ((it = m_pendingRecordings.find(m_inputId)) != m_pendingRecordings.end())
451  {
452  (*it).m_ask = (*it).m_doNotAsk = false;
453  cancelNext = (*it).m_canceled;
454  }
455  m_pendingRecLock.unlock();
456 
457  // Flush out events...
459 
460  // Rescan pending recordings since the event loop may have deleted
461  // a stale entry. If this happens the info pointer will not be valid
462  // since the HandlePendingRecordings loop will have deleted it.
463  m_pendingRecLock.lock();
464  it = m_pendingRecordings.find(m_inputId);
465  bool has_pending = (it != m_pendingRecordings.end());
466  if (has_pending)
467  pendinfo = *it;
468  m_pendingRecLock.unlock();
469 
470  // If the needed input is in a shared input group, and we are
471  // not canceling the recording anyway, check other recorders
472  if (!cancelNext && has_pending && !pendinfo.m_possibleConflicts.empty())
473  {
474  LOG(VB_RECORD, LOG_INFO, LOC +
475  "Checking input group recorders - begin");
476  vector<uint> &inputids = pendinfo.m_possibleConflicts;
477 
478  uint mplexid = 0;
479  uint chanid = 0;
480  uint sourceid = 0;
481  vector<uint> inputids2;
482  vector<TVState> states;
483 
484  // Stop remote recordings if needed
485  for (uint inputid : inputids)
486  {
487  InputInfo busy_input;
488  bool is_busy = RemoteIsBusy(inputid, busy_input);
489 
490  if (is_busy && !sourceid)
491  {
492  mplexid = pendinfo.m_info->QueryMplexID();
493  chanid = pendinfo.m_info->GetChanID();
494  sourceid = pendinfo.m_info->GetSourceID();
495  }
496 
497  if (is_busy &&
498  ((sourceid != busy_input.m_sourceId) ||
499  (mplexid != busy_input.m_mplexId) ||
500  ((mplexid == 0 || mplexid == 32767) &&
501  chanid != busy_input.m_chanId)))
502  {
503  states.push_back((TVState) RemoteGetState(inputid));
504  inputids2.push_back(inputid);
505  }
506  }
507 
508  bool ok = true;
509  for (uint i = 0; (i < inputids2.size()) && ok; i++)
510  {
511  LOG(VB_RECORD, LOG_INFO, LOC +
512  QString("Attempting to stop input [%1] in state %2")
513  .arg(inputids2[i]).arg(StateToString(states[i])));
514 
515  bool success = RemoteStopRecording(inputids2[i]);
516  if (success)
517  {
518  uint state = RemoteGetState(inputids2[i]);
519  LOG(VB_GENERAL, LOG_INFO, LOC + QString("a [%1]: %2")
520  .arg(inputids2[i]).arg(StateToString((TVState)state)));
521  success = (kState_None == state);
522  }
523 
524  // If we managed to stop LiveTV recording, restart playback..
525  if (success && states[i] == kState_WatchingLiveTV)
526  {
527  QString message = QString("QUIT_LIVETV %1").arg(inputids2[i]);
528  MythEvent me(message);
529  gCoreContext->dispatch(me);
530  }
531 
532  LOG(VB_RECORD, LOG_INFO, LOC +
533  QString("Stopping recording on [%1], %2") .arg(inputids2[i])
534  .arg(success ? "succeeded" : "failed"));
535 
536  ok &= success;
537  }
538 
539  // If we failed to stop the remote recordings, don't record
540  if (!ok)
541  {
542  CancelNextRecording(true);
543  cancelNext = true;
544  }
545 
546  inputids.clear();
547 
548  LOG(VB_RECORD, LOG_INFO, LOC + "Checking input group recorders - done");
549  }
550 
551  bool did_switch = false;
552  if (!cancelNext && (GetState() == kState_RecordingOnly))
553  {
555  did_switch = (nullptr != ri2);
556  if (did_switch)
557  {
558  // Make sure scheduler is allowed to end this recording
559  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
560 
562  }
563  else
564  {
565  // If in post-roll, end recording
566  m_stateChangeLock.unlock();
567  StopRecording();
568  m_stateChangeLock.lock();
569  }
570  }
571 
572  if (!cancelNext && (GetState() == kState_None))
573  {
574  if (m_tvChain)
575  {
576  QString message = QString("LIVETV_EXITED");
577  MythEvent me(message, m_tvChain->GetID());
578  gCoreContext->dispatch(me);
579  m_tvChain->DecrRef();
580  m_tvChain = nullptr;
581  }
582 
584 
585  // Tell event loop to begin recording.
586  m_curRecording = new RecordingInfo(*rcinfo);
591 
592  // Make sure scheduler is allowed to end this recording
593  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
594 
597  else
598  LOG(VB_RECORD, LOG_WARNING, LOC + "Still failing.");
600  }
601  else if (!cancelNext && (GetState() == kState_WatchingLiveTV))
602  {
606 
607  // We want the frontend to change channel for recording
608  // and disable the UI for channel change, PiP, etc.
609 
610  QString message = QString("LIVETV_WATCH %1 1").arg(m_inputId);
611  QStringList prog;
612  rcinfo->ToStringList(prog);
613  MythEvent me(message, prog);
614  gCoreContext->dispatch(me);
615  }
616  else if (!did_switch)
617  {
618  QString msg = QString("Wanted to record: %1 %2 %3 %4\n\t\t\t")
619  .arg(rcinfo->GetTitle(),
620  QString::number(rcinfo->GetChanID()),
623 
624  if (cancelNext)
625  {
626  msg += "But a user has canceled this recording";
628  }
629  else
630  {
631  msg += QString("But the current state is: %1")
634  }
635 
637  {
638  msg += QString("\n\t\t\tCurrently recording: %1 %2 %3 %4")
639  .arg(m_curRecording->GetTitle(),
640  QString::number(m_curRecording->GetChanID()),
643  }
644 
645  LOG(VB_GENERAL, LOG_INFO, LOC + msg);
646  }
647 
648  for (const auto & pend : qAsConst(m_pendingRecordings))
649  delete pend.m_info;
650  m_pendingRecordings.clear();
651 
652  if (!did_switch)
653  {
655 
656  QMutexLocker locker(&m_pendingRecLock);
657  if ((m_curRecording) &&
662  {
663  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
664  }
665  return m_recStatus;
666  }
667 
668  return GetRecordingStatus();
669 }
670 
672 {
673  QMutexLocker pendlock(&m_pendingRecLock);
674  return m_recStatus;
675 }
676 
678  RecStatus::Type new_status, int line, bool have_lock)
679 {
680  RecStatus::Type old_status { RecStatus::Unknown };
681  if (have_lock)
682  {
683  old_status = m_recStatus;
684  m_recStatus = new_status;
685  }
686  else
687  {
688  m_pendingRecLock.lock();
689  old_status = m_recStatus;
690  m_recStatus = new_status;
691  m_pendingRecLock.unlock();
692  }
693 
694  LOG(VB_RECORD, LOG_INFO, LOC +
695  QString("SetRecordingStatus(%1->%2) on line %3")
696  .arg(RecStatus::toString(old_status, kSingleRecord),
697  RecStatus::toString(new_status, kSingleRecord),
698  QString::number(line)));
699 }
700 
707 void TVRec::StopRecording(bool killFile)
708 {
709  if (StateIsRecording(GetState()))
710  {
711  QMutexLocker lock(&m_stateChangeLock);
712  if (killFile)
713  SetFlags(kFlagKillRec, __FILE__, __LINE__);
714  else if (m_curRecording)
715  {
716  QDateTime now = MythDate::current(true);
717  if (now < m_curRecording->GetDesiredEndTime())
719  }
721  // wait for state change to take effect
723  ClearFlags(kFlagCancelNextRecording|kFlagKillRec, __FILE__, __LINE__);
724 
726  }
727 }
728 
735 {
736  return (state == kState_RecordingOnly ||
737  state == kState_WatchingLiveTV);
738 }
739 
745 {
746  return (state == kState_WatchingPreRecorded);
747 }
748 
755 {
756  if (StateIsRecording(state))
757  return kState_None;
758 
759  LOG(VB_GENERAL, LOG_ERR, LOC +
760  QString("Unknown state in RemoveRecording: %1")
761  .arg(StateToString(state)));
762  return kState_Error;
763 }
764 
771 {
772  if (StateIsPlaying(state))
773  {
774  if (state == kState_WatchingPreRecorded)
775  return kState_None;
776  return kState_RecordingOnly;
777  }
778 
779  QString msg = "Unknown state in RemovePlaying: %1";
780  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(StateToString(state)));
781 
782  return kState_Error;
783 }
784 
791 {
792  if (!curRec)
793  return;
794 
795  curRec->StartedRecording(m_rbFileExt);
796  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartedRecording(%1) fn(%2)")
797  .arg(curRec->MakeUniqueKey(), curRec->GetPathname()));
798 
799  if (curRec->IsCommercialFree())
801 
802  AutoRunInitType t = (curRec->GetRecordingGroup() == "LiveTV") ?
804  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
805 
806  SendMythSystemRecEvent("REC_STARTED", curRec);
807 }
808 
817 {
818  if (!curRec)
819  return;
820 
821  // Make sure the recording group is up to date
822  const QString recgrp = curRec->QueryRecordingGroup();
823  curRec->SetRecordingGroup(recgrp);
824 
825  bool is_good = true;
826  if (recq)
827  {
828  LOG((recq->IsDamaged()) ? VB_GENERAL : VB_RECORD, LOG_INFO,
829  LOC + QString("FinishedRecording(%1) %2 recq:\n%3")
830  .arg(curRec->MakeUniqueKey(),
831  (recq->IsDamaged()) ? "damaged" : "good",
832  recq->toStringXML()));
833  is_good = !recq->IsDamaged();
834  delete recq;
835  recq = nullptr;
836  }
837 
838  RecStatus::Type ors = curRec->GetRecordingStatus();
839  // Set the final recording status
840  if (curRec->GetRecordingStatus() == RecStatus::Recording)
842  else if (curRec->GetRecordingStatus() != RecStatus::Recorded)
844  curRec->SetRecordingEndTime(MythDate::current(true));
845  is_good &= (curRec->GetRecordingStatus() == RecStatus::Recorded);
846 
847  // Figure out if this was already done for this recording
848  bool was_finished = false;
849  static QMutex s_finRecLock;
850  static QHash<QString,QDateTime> s_finRecMap;
851  {
852  QMutexLocker locker(&s_finRecLock);
853  QDateTime now = MythDate::current();
854  QDateTime expired = now.addSecs(-60*5);
855  QHash<QString,QDateTime>::iterator it = s_finRecMap.begin();
856  while (it != s_finRecMap.end())
857  {
858  if ((*it) < expired)
859  it = s_finRecMap.erase(it);
860  else
861  ++it;
862  }
863  QString key = curRec->MakeUniqueKey();
864  it = s_finRecMap.find(key);
865  if (it != s_finRecMap.end())
866  was_finished = true;
867  else
868  s_finRecMap[key] = now;
869  }
870 
871  // Print something informative to the log
872  LOG(VB_RECORD, LOG_INFO, LOC +
873  QString("FinishedRecording(%1) %2 quality"
874  "\n\t\t\ttitle: %3\n\t\t\t"
875  "in recgroup: %4 status: %5:%6 %7 %8")
876  .arg(curRec->MakeUniqueKey(),
877  is_good ? "Good" : "Bad",
878  curRec->GetTitle(),
879  recgrp,
882  HasFlags(kFlagDummyRecorderRunning)?"is_dummy":"not_dummy",
883  was_finished?"already_finished":"finished_now"));
884 
885  // This has already been called on this recording..
886  if (was_finished)
887  return;
888 
889  // Notify the frontend watching live tv that this file is final
890  if (m_tvChain)
891  m_tvChain->FinishedRecording(curRec);
892 
893  // if this is a dummy recorder, do no more..
895  {
896  curRec->FinishedRecording(true); // so end time is updated
897  SendMythSystemRecEvent("REC_FINISHED", curRec);
898  return;
899  }
900 
901  // Get the width and set the videoprops
902  MarkTypes aspectRatio = curRec->QueryAverageAspectRatio();
903  uint avg_height = curRec->QueryAverageHeight();
904  bool progressive = curRec->QueryAverageScanProgressive();
905  curRec->SaveVideoProperties
906  (VID_4K | VID_1080 | VID_720 | VID_DAMAGED |
907  VID_WIDESCREEN | VID_PROGRESSIVE,
908  ((avg_height > 2000) ? VID_4K :
909  ((avg_height > 1000) ? VID_1080 :
910  ((avg_height > 700) ? VID_720 : 0))) |
911  (progressive ? VID_PROGRESSIVE : 0) |
912  ((is_good) ? 0 : VID_DAMAGED) |
913  (((aspectRatio == MARK_ASPECT_16_9) ||
914  (aspectRatio == MARK_ASPECT_2_21_1)) ? VID_WIDESCREEN : 0));
915 
916  // Make sure really short recordings have positive run time.
917  if (curRec->GetRecordingEndTime() <= curRec->GetRecordingStartTime())
918  {
919  curRec->SetRecordingEndTime(
920  curRec->GetRecordingStartTime().addSecs(60));
921  }
922 
923  // HACK Temporary hack, ensure we've loaded the recording file info, do it now
924  // so that it contains the final filesize information
925  if (!curRec->GetRecordingFile())
926  curRec->LoadRecordingFile();
927 
928  // Generate a preview
929  uint64_t fsize = curRec->GetFilesize();
930  if (curRec->IsLocal() && (fsize >= 1000) &&
932  {
934  }
935 
936  // store recording in recorded table
937  curRec->FinishedRecording(!is_good || (recgrp == "LiveTV"));
938 
939  // send out UPDATE_RECORDING_STATUS message
940  if (recgrp != "LiveTV")
941  {
942  LOG(VB_RECORD, LOG_INFO, LOC +
943  QString("FinishedRecording -- UPDATE_RECORDING_STATUS: %1")
944  .arg(RecStatus::toString(is_good ? curRec->GetRecordingStatus()
946  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
947  .arg(curRec->GetInputID())
948  .arg(curRec->GetChanID())
950  .arg(is_good ? curRec->GetRecordingStatus() : RecStatus::Failed)
951  .arg(curRec->GetRecordingEndTime(MythDate::ISODate)));
952  gCoreContext->dispatch(me);
953  }
954 
955  // send out REC_FINISHED message
956  SendMythSystemRecEvent("REC_FINISHED", curRec);
957 
958  // send out DONE_RECORDING message
959  auto secsSince = MythDate::secsInPast(curRec->GetRecordingStartTime());
960  QString message = QString("DONE_RECORDING %1 %2 %3")
961  .arg(m_inputId).arg(secsSince.count()).arg(GetFramesWritten());
962  MythEvent me(message);
963  gCoreContext->dispatch(me);
964 
965  // Handle JobQueue
966  QHash<QString,int>::iterator autoJob =
967  m_autoRunJobs.find(curRec->MakeUniqueKey());
968  if (autoJob == m_autoRunJobs.end())
969  {
970  LOG(VB_GENERAL, LOG_INFO,
971  "autoRunJobs not initialized until FinishedRecording()");
973  (recgrp == "LiveTV") ? kAutoRunNone : kAutoRunProfile;
974  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
975  autoJob = m_autoRunJobs.find(curRec->MakeUniqueKey());
976  }
977  LOG(VB_JOBQUEUE, LOG_INFO, QString("AutoRunJobs 0x%1").arg(*autoJob,0,16));
978  if ((recgrp == "LiveTV") || (fsize < 1000) ||
979  (curRec->GetRecordingStatus() != RecStatus::Recorded) ||
980  (curRec->GetRecordingStartTime().secsTo(
981  MythDate::current()) < 120))
982  {
985  }
986  if (*autoJob != JOB_NONE)
987  JobQueue::QueueRecordingJobs(*curRec, *autoJob);
988  m_autoRunJobs.erase(autoJob);
989 }
990 
991 #define TRANSITION(ASTATE,BSTATE) \
992  ((m_internalState == (ASTATE)) && (m_desiredNextState == (BSTATE)))
993 #define SET_NEXT() do { nextState = m_desiredNextState; changed = true; } while(false)
994 #define SET_LAST() do { nextState = m_internalState; changed = true; } while(false)
995 
1004 {
1005  TVState nextState = m_internalState;
1006 
1007  bool changed = false;
1008 
1009  QString transMsg = QString(" %1 to %2")
1010  .arg(StateToString(nextState), StateToString(m_desiredNextState));
1011 
1013  {
1014  LOG(VB_GENERAL, LOG_ERR, LOC +
1015  "HandleStateChange(): Null transition" + transMsg);
1016  m_changeState = false;
1017  return;
1018  }
1019 
1020  // Make sure EIT scan is stopped before any tuning,
1021  // to avoid race condition with it's tuning requests.
1023  {
1025  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1027  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1028  }
1029 
1030  // Handle different state transitions
1032  {
1034  SET_NEXT();
1035  }
1037  {
1039  SET_NEXT();
1040  }
1042  {
1043  SetPseudoLiveTVRecording(nullptr);
1044 
1045  SET_NEXT();
1046  }
1048  {
1049  SetPseudoLiveTVRecording(nullptr);
1051  SET_NEXT();
1052  }
1054  {
1057  (GetFlags()&kFlagKillRec)));
1058  SET_NEXT();
1059  }
1060 
1061  QString msg = (changed) ? "Changing from" : "Unknown state transition:";
1062  LOG(VB_GENERAL, LOG_INFO, LOC + msg + transMsg);
1063 
1064  // update internal state variable
1065  m_internalState = nextState;
1066  m_changeState = false;
1067 
1070  {
1072  m_eitScanStartTime = m_eitScanStartTime.addSecs(secs.count());
1073  }
1074  else
1075  {
1076  m_eitScanStartTime = m_eitScanStartTime.addYears(1);
1077  }
1078 }
1079 #undef TRANSITION
1080 #undef SET_NEXT
1081 #undef SET_LAST
1082 
1087 {
1088  QMutexLocker lock(&m_stateChangeLock);
1089  m_desiredNextState = nextState;
1090  m_changeState = true;
1091  WakeEventLoop();
1092 }
1093 
1108 void TVRec::TeardownRecorder(uint request_flags)
1109 {
1110  LOG(VB_RECORD, LOG_INFO, LOC + QString("TeardownRecorder(%1)")
1111  .arg((request_flags & kFlagKillRec) ? "kFlagKillRec" : ""));
1112 
1113  m_pauseNotify = false;
1114  m_isPip = false;
1115 
1117  {
1120  delete m_recorderThread;
1121  m_recorderThread = nullptr;
1122  }
1124  __FILE__, __LINE__);
1125 
1126  RecordingQuality *recq = nullptr;
1127  if (m_recorder)
1128  {
1129  if (GetV4LChannel())
1130  m_channel->SetFd(-1);
1131 
1133 
1134  QMutexLocker locker(&m_stateChangeLock);
1135  delete m_recorder;
1136  m_recorder = nullptr;
1137  }
1138 
1139  if (m_buffer)
1140  {
1141  LOG(VB_FILE, LOG_INFO, LOC + "calling StopReads()");
1142  m_buffer->StopReads();
1143  }
1144 
1145  if (m_curRecording)
1146  {
1147  if (!!(request_flags & kFlagKillRec))
1149 
1151 
1153  delete m_curRecording;
1154  m_curRecording = nullptr;
1155  }
1156 
1157  m_pauseNotify = true;
1158 
1159  if (GetDTVChannel())
1161 }
1162 
1164 {
1165  return dynamic_cast<DTVRecorder*>(m_recorder);
1166 }
1167 
1169 {
1170  if (m_channel &&
1171  ((m_genOpt.m_inputType == "DVB" && m_dvbOpt.m_dvbOnDemand) ||
1172  m_genOpt.m_inputType == "FREEBOX" ||
1173  m_genOpt.m_inputType == "VBOX" ||
1174  m_genOpt.m_inputType == "HDHOMERUN" ||
1175  m_genOpt.m_inputType == "EXTERNAL" ||
1177  {
1178  m_channel->Close();
1179  }
1180 }
1181 
1183 {
1184  return dynamic_cast<DTVChannel*>(m_channel);
1185 }
1186 
1188 {
1189 #ifdef USING_V4L2
1190  return dynamic_cast<V4LChannel*>(m_channel);
1191 #else
1192  return nullptr;
1193 #endif // USING_V4L2
1194 }
1195 
1196 static bool get_use_eit(uint inputid)
1197 {
1198  MSqlQuery query(MSqlQuery::InitCon());
1199  query.prepare(
1200  "SELECT SUM(useeit) "
1201  "FROM videosource, capturecard "
1202  "WHERE videosource.sourceid = capturecard.sourceid AND"
1203  " capturecard.cardid = :INPUTID");
1204  query.bindValue(":INPUTID", inputid);
1205 
1206  if (!query.exec() || !query.isActive())
1207  {
1208  MythDB::DBError("get_use_eit", query);
1209  return false;
1210  }
1211  if (query.next())
1212  return query.value(0).toBool();
1213  return false;
1214 }
1215 
1216 static bool is_dishnet_eit(uint inputid)
1217 {
1218  MSqlQuery query(MSqlQuery::InitCon());
1219  query.prepare(
1220  "SELECT SUM(dishnet_eit) "
1221  "FROM videosource, capturecard "
1222  "WHERE videosource.sourceid = capturecard.sourceid AND"
1223  " capturecard.cardid = :INPUTID");
1224  query.bindValue(":INPUTID", inputid);
1225 
1226  if (!query.exec() || !query.isActive())
1227  {
1228  MythDB::DBError("is_dishnet_eit", query);
1229  return false;
1230  }
1231  if (query.next())
1232  return query.value(0).toBool();
1233  return false;
1234 }
1235 
1236 // Number of capturecard instances including multirec instances
1237 static int num_inputs(void)
1238 {
1239  MSqlQuery query(MSqlQuery::InitCon());
1240 
1241  QString str =
1242  "SELECT COUNT(cardid) "
1243  "FROM capturecard ";
1244 
1245  query.prepare(str);
1246 
1247  if (!query.exec() || !query.isActive())
1248  {
1249  MythDB::DBError("num_inputs", query);
1250  return -1;
1251  }
1252  if (query.next())
1253  return query.value(0).toInt();
1254  return -1;
1255 }
1256 
1257 static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout)
1258 {
1259  // Randomize start time a bit
1260  auto timeout = std::chrono::seconds(MythRandom()) % (eitTransportTimeout.count() / 3);
1261 
1262  // Get the number of inputs and the position of the current input
1263  // to distribute the scan start evenly over eitTransportTimeout
1264  int no_inputs = num_inputs();
1265  if (no_inputs > 0)
1266  timeout += eitTransportTimeout * inputId / no_inputs;
1267 
1268  return timeout;
1269 }
1270 
1272 void TVRec::run(void)
1273 {
1274  QMutexLocker lock(&m_stateChangeLock);
1275  SetFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1276  ClearFlags(kFlagExitPlayer | kFlagFinishRecording, __FILE__, __LINE__);
1277 
1279 
1280  // Check whether we should use the EITScanner in this TVRec instance
1281  if (CardUtil::IsEITCapable(m_genOpt.m_inputType) && // Card type capable of receiving EIT?
1282  (!GetDTVChannel() || GetDTVChannel()->IsMaster()) && // Card is master and not a multirec instance
1283  (m_dvbOpt.m_dvbEitScan || get_use_eit(m_inputId))) // EIT is selected for card OR EIT is selected for video source
1284  {
1287  m_eitScanStartTime = m_eitScanStartTime.addSecs(secs.count());
1288  }
1289  else
1290  {
1291  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1292  }
1293 
1294  while (HasFlags(kFlagRunMainLoop))
1295  {
1296  // If there is a state change queued up, do it...
1297  if (m_changeState)
1298  {
1301  __FILE__, __LINE__);
1302  }
1303 
1304  // Quick exit on fatal errors.
1305  if (IsErrored())
1306  {
1307  LOG(VB_GENERAL, LOG_ERR, LOC +
1308  "RunTV encountered fatal error, exiting event thread.");
1309  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1310  TeardownAll();
1311  return;
1312  }
1313 
1314  // Handle any tuning events.. Blindly grabbing the lock here
1315  // can sometimes cause a deadlock with Init() while it waits
1316  // to make sure this thread starts. Until a better solution
1317  // is found, don't run HandleTuning unless we can safely get
1318  // the lock.
1319  if (s_inputsLock.tryLockForRead())
1320  {
1321  HandleTuning();
1322  s_inputsLock.unlock();
1323  }
1324 
1325  // Tell frontends about pending recordings
1327 
1328  // If we are recording a program, check if the recording is
1329  // over or someone has asked us to finish the recording.
1330  // Add an extra 60 seconds to the recording end time if we
1331  // might want a back to back recording.
1332  QDateTime recEnd = (!m_pendingRecordings.empty()) ?
1333  m_recordEndTime.addSecs(60) : m_recordEndTime;
1334  if ((GetState() == kState_RecordingOnly) &&
1335  (MythDate::current() > recEnd ||
1337  {
1339  ClearFlags(kFlagFinishRecording, __FILE__, __LINE__);
1340  }
1341 
1342  if (m_curRecording)
1343  {
1345 
1346  if (m_recorder)
1347  {
1349 
1350  // Check for recorder errors
1351  if (m_recorder->IsErrored())
1352  {
1354 
1356  {
1357  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
1358  MythEvent me(message);
1359  gCoreContext->dispatch(me);
1360  }
1361  else
1363  }
1364  }
1365  }
1366 
1367  // Check for the end of the current program..
1369  {
1370  QDateTime now = MythDate::current();
1371  bool has_finish = HasFlags(kFlagFinishRecording);
1372  bool has_rec = m_pseudoLiveTVRecording;
1373  bool enable_ui = true;
1374 
1375  m_pendingRecLock.lock();
1376  bool rec_soon =
1378  m_pendingRecLock.unlock();
1379 
1380  if (has_rec && (has_finish || (now > m_recordEndTime)))
1381  {
1382  SetPseudoLiveTVRecording(nullptr);
1383  }
1384  else if (!has_rec && !rec_soon && m_curRecording &&
1385  (now >= m_curRecording->GetScheduledEndTime()))
1386  {
1387  if (!m_switchingBuffer)
1388  {
1389  LOG(VB_RECORD, LOG_INFO, LOC +
1390  "Switching Buffer (" +
1391  QString("!has_rec(%1) && ").arg(has_rec) +
1392  QString("!rec_soon(%1) && (").arg(rec_soon) +
1393  MythDate::toString(now, MythDate::ISODate) + " >= " +
1395  QString("(%1) ))")
1396  .arg(now >= m_curRecording->GetScheduledEndTime()));
1397 
1398  m_switchingBuffer = true;
1399 
1401  false, true);
1402  }
1403  else
1404  {
1405  LOG(VB_RECORD, LOG_INFO, "Waiting for ringbuffer switch");
1406  }
1407  }
1408  else
1409  enable_ui = false;
1410 
1411  if (enable_ui)
1412  {
1413  LOG(VB_RECORD, LOG_INFO, LOC + "Enabling Full LiveTV UI.");
1414  QString message = QString("LIVETV_WATCH %1 0").arg(m_inputId);
1415  MythEvent me(message);
1416  gCoreContext->dispatch(me);
1417  }
1418  }
1419 
1420  // Check for ExitPlayer flag, and if set change to a non-watching
1421  // state (either kState_RecordingOnly or kState_None).
1423  {
1426  else if (StateIsPlaying(m_internalState))
1428  ClearFlags(kFlagExitPlayer, __FILE__, __LINE__);
1429  }
1430 
1431  // Start active EIT scan
1432  if (m_scanner && m_channel &&
1434  {
1435  if (!m_dvbOpt.m_dvbEitScan)
1436  {
1437  LOG(VB_EIT, LOG_INFO, LOC +
1438  "EIT scanning disabled for this input.");
1439  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1440  }
1441  else if (!get_use_eit(GetInputId()))
1442  {
1443  LOG(VB_EIT, LOG_INFO, LOC +
1444  "EIT scanning disabled for all channels on this input.");
1445  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1446  }
1447  else
1448  {
1449  // Check if another card in the same input group is
1450  // busy. This could be either virtual DVB-devices or
1451  // a second tuner on a single card
1452  s_inputsLock.lockForRead();
1453  bool allow_eit = true;
1454  vector<uint> inputids =
1456  InputInfo busy_input;
1457  for (uint i = 0; i < inputids.size() && allow_eit; ++i)
1458  allow_eit = !RemoteIsBusy(inputids[i], busy_input);
1459  if (allow_eit)
1460  {
1462  SetFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1464  QDateTime::currentDateTime().addYears(1);
1465  }
1466  else
1467  {
1468  LOG(VB_EIT, LOG_INFO, LOC + QString(
1469  "Postponing EIT scan on input [%1] "
1470  "because input %2 is busy")
1471  .arg(m_inputId).arg(busy_input.m_inputId));
1472  m_eitScanStartTime = m_eitScanStartTime.addSecs(300);
1473  }
1474  s_inputsLock.unlock();
1475  }
1476  }
1477 
1478  // We should be no more than a few thousand milliseconds,
1479  // as the end recording code does not have a trigger...
1480  // NOTE: If you change anything here, make sure that
1481  // WaitforEventThreadSleep() will still work...
1482  if (m_tuningRequests.empty() && !m_changeState)
1483  {
1484  lock.unlock(); // stateChangeLock
1485 
1486  {
1487  QMutexLocker locker(&m_triggerEventSleepLock);
1489  m_triggerEventSleepWait.wakeAll();
1490  }
1491 
1492  sched_yield();
1493 
1494  {
1495  QMutexLocker locker(&m_triggerEventLoopLock);
1496  // We check triggerEventLoopSignal because it is possible
1497  // that WakeEventLoop() was called since we
1498  // unlocked the stateChangeLock
1500  {
1502  &m_triggerEventLoopLock, 1000 /* ms */);
1503  }
1504  m_triggerEventLoopSignal = false;
1505  }
1506 
1507  lock.relock(); // stateChangeLock
1508  }
1509  }
1510 
1511  if (GetState() != kState_None)
1512  {
1515  }
1516 
1517  TeardownAll();
1518 }
1519 
1525 bool TVRec::WaitForEventThreadSleep(bool wake, std::chrono::milliseconds time)
1526 {
1527  bool ok = false;
1528  MythTimer t;
1529  t.start();
1530 
1531  while (!ok && (t.elapsed() < time))
1532  {
1533  MythTimer t2;
1534  t2.start();
1535 
1536  if (wake)
1537  WakeEventLoop();
1538 
1539  m_stateChangeLock.unlock();
1540 
1541  sched_yield();
1542 
1543  {
1544  QMutexLocker locker(&m_triggerEventSleepLock);
1547  m_triggerEventSleepSignal = false;
1548  }
1549 
1550  m_stateChangeLock.lock();
1551 
1552  // verify that we were triggered.
1553  ok = (m_tuningRequests.empty() && !m_changeState);
1554 
1555  std::chrono::milliseconds te = t2.elapsed();
1556  if (!ok && te < 10ms)
1557  std::this_thread::sleep_for(10ms - te);
1558  }
1559  return ok;
1560 }
1561 
1563 {
1564  QMutexLocker pendlock(&m_pendingRecLock);
1565 
1566  for (auto it = m_pendingRecordings.begin(); it != m_pendingRecordings.end();)
1567  {
1568  if (MythDate::current() > (*it).m_recordingStart.addSecs(30))
1569  {
1570  LOG(VB_RECORD, LOG_INFO, LOC + "Deleting stale pending recording " +
1571  QString("[%1] '%2'")
1572  .arg((*it).m_info->GetInputID())
1573  .arg((*it).m_info->GetTitle()));
1574 
1575  delete (*it).m_info;
1576  it = m_pendingRecordings.erase(it);
1577  }
1578  else
1579  {
1580  it++;
1581  }
1582  }
1583 
1584  if (m_pendingRecordings.empty())
1585  return;
1586 
1587  // Make sure EIT scan is stopped so it does't interfere
1589  {
1590  LOG(VB_CHANNEL, LOG_INFO,
1591  LOC + "Stopping active EIT scan for pending recording.");
1593  }
1594 
1595  // If we have a pending recording and AskAllowRecording
1596  // or DoNotAskAllowRecording is set and the frontend is
1597  // ready send an ASK_RECORDING query to frontend.
1598 
1599  bool has_rec = false;
1600  auto it = m_pendingRecordings.begin();
1601  if ((1 == m_pendingRecordings.size()) &&
1602  (*it).m_ask &&
1603  ((*it).m_info->GetInputID() == m_inputId) &&
1605  {
1607  has_rec = m_pseudoLiveTVRecording &&
1609  (*it).m_recordingStart);
1610  }
1611 
1612  for (it = m_pendingRecordings.begin(); it != m_pendingRecordings.end(); ++it)
1613  {
1614  if (!(*it).m_ask && !(*it).m_doNotAsk)
1615  continue;
1616 
1617  auto timeuntil = ((*it).m_doNotAsk) ?
1618  -1s: MythDate::secsInFuture((*it).m_recordingStart);
1619 
1620  if (has_rec)
1621  (*it).m_canceled = true;
1622 
1623  QString query = QString("ASK_RECORDING %1 %2 %3 %4")
1624  .arg(m_inputId)
1625  .arg(timeuntil.count())
1626  .arg(has_rec ? 1 : 0)
1627  .arg((*it).m_hasLaterShowing ? 1 : 0);
1628 
1629  LOG(VB_GENERAL, LOG_INFO, LOC + query);
1630 
1631  QStringList msg;
1632  (*it).m_info->ToStringList(msg);
1633  MythEvent me(query, msg);
1634  gCoreContext->dispatch(me);
1635 
1636  (*it).m_ask = (*it).m_doNotAsk = false;
1637  }
1638 }
1639 
1641  uint &parentid,
1642  GeneralDBOptions &gen_opts,
1643  DVBDBOptions &dvb_opts,
1644  FireWireDBOptions &firewire_opts)
1645 {
1646  int testnum = 0;
1647  QString test;
1648 
1649  MSqlQuery query(MSqlQuery::InitCon());
1650  query.prepare(
1651  "SELECT videodevice, vbidevice, audiodevice, "
1652  " audioratelimit, cardtype, "
1653  " skipbtaudio, signal_timeout, channel_timeout, "
1654  " dvb_wait_for_seqstart, "
1655  ""
1656  " dvb_on_demand, dvb_tuning_delay, dvb_eitscan,"
1657  ""
1658  " firewire_speed, firewire_model, firewire_connection, "
1659  " parentid "
1660  ""
1661  "FROM capturecard "
1662  "WHERE cardid = :INPUTID");
1663  query.bindValue(":INPUTID", inputid);
1664 
1665  if (!query.exec() || !query.isActive())
1666  {
1667  MythDB::DBError("getdevices", query);
1668  return false;
1669  }
1670 
1671  if (!query.next())
1672  return false;
1673 
1674  // General options
1675  test = query.value(0).toString();
1676  if (!test.isEmpty())
1677  gen_opts.m_videoDev = test;
1678 
1679  test = query.value(1).toString();
1680  if (!test.isEmpty())
1681  gen_opts.m_vbiDev = test;
1682 
1683  test = query.value(2).toString();
1684  if (!test.isEmpty())
1685  gen_opts.m_audioDev = test;
1686 
1687  gen_opts.m_audioSampleRate = std::max(testnum, query.value(3).toInt());
1688 
1689  test = query.value(4).toString();
1690  if (!test.isEmpty())
1691  gen_opts.m_inputType = test;
1692 
1693  gen_opts.m_skipBtAudio = query.value(5).toBool();
1694 
1695  gen_opts.m_signalTimeout = (uint) std::max(query.value(6).toInt(), 0);
1696  gen_opts.m_channelTimeout = (uint) std::max(query.value(7).toInt(), 0);
1697 
1698  // We should have at least 1000 ms to acquire tables...
1699  int table_timeout = ((int)gen_opts.m_channelTimeout -
1700  (int)gen_opts.m_signalTimeout);
1701  if (table_timeout < 1000)
1702  gen_opts.m_channelTimeout = gen_opts.m_signalTimeout + 1000;
1703 
1704  gen_opts.m_waitForSeqstart = query.value(8).toBool();
1705 
1706  // DVB options
1707  uint dvboff = 9;
1708  dvb_opts.m_dvbOnDemand = query.value(dvboff + 0).toBool();
1709  dvb_opts.m_dvbTuningDelay = std::chrono::milliseconds(query.value(dvboff + 1).toUInt());
1710  dvb_opts.m_dvbEitScan = query.value(dvboff + 2).toBool();
1711 
1712  // Firewire options
1713  uint fireoff = dvboff + 3;
1714  firewire_opts.m_speed = query.value(fireoff + 0).toUInt();
1715 
1716  test = query.value(fireoff + 1).toString();
1717  if (!test.isEmpty())
1718  firewire_opts.m_model = test;
1719 
1720  firewire_opts.m_connection = query.value(fireoff + 2).toUInt();
1721 
1722  parentid = query.value(15).toUInt();
1723 
1724  return true;
1725 }
1726 
1727 static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
1728 {
1729  if (!dtvMon->GetATSCStreamData())
1730  return;
1731 
1732  const MasterGuideTable *mgt = dtvMon->GetATSCStreamData()->GetCachedMGT();
1733  if (!mgt)
1734  return;
1735 
1736  for (uint i = 0; i < mgt->TableCount(); ++i)
1737  {
1738  pid_cache_item_t item(mgt->TablePID(i), mgt->TableType(i));
1739  pid_cache.push_back(item);
1740  }
1741  dtvMon->GetATSCStreamData()->ReturnCachedTable(mgt);
1742 }
1743 
1744 static bool ApplyCachedPids(DTVSignalMonitor *dtvMon, const DTVChannel* channel)
1745 {
1746  pid_cache_t pid_cache;
1747  channel->GetCachedPids(pid_cache);
1748  bool vctpid_cached = false;
1749  for (auto pid : pid_cache)
1750  {
1751  if ((pid.GetTableID() == TableID::TVCT) ||
1752  (pid.GetTableID() == TableID::CVCT))
1753  {
1754  vctpid_cached = true;
1755  dtvMon->GetATSCStreamData()->AddListeningPID(pid.GetPID());
1756  }
1757  }
1758  return vctpid_cached;
1759 }
1760 
1777 {
1778  LOG(VB_RECORD, LOG_INFO, LOC + "Setting up table monitoring.");
1779 
1781  DTVChannel *dtvchan = GetDTVChannel();
1782  if (!sm || !dtvchan)
1783  {
1784  LOG(VB_GENERAL, LOG_ERR, LOC + "Setting up table monitoring.");
1785  return false;
1786  }
1787 
1788  MPEGStreamData *sd = nullptr;
1789  if (GetDTVRecorder())
1790  {
1791  sd = GetDTVRecorder()->GetStreamData();
1792  sd->SetCaching(true);
1793  }
1794 
1795  QString recording_type = "all";
1799  const StandardSetting *setting = profile.byName("recordingtype");
1800  if (setting)
1801  recording_type = setting->getValue();
1802 
1803  const QString tuningmode = dtvchan->GetTuningMode();
1804 
1805  // Check if this is an ATSC Channel
1806  int major = dtvchan->GetMajorChannel();
1807  int minor = dtvchan->GetMinorChannel();
1808  if ((minor > 0) && (tuningmode == "atsc"))
1809  {
1810  QString msg = QString("ATSC channel: %1_%2").arg(major).arg(minor);
1811  LOG(VB_RECORD, LOG_INFO, LOC + msg);
1812 
1813  auto *asd = dynamic_cast<ATSCStreamData*>(sd);
1814  if (!asd)
1815  {
1816  sd = asd = new ATSCStreamData(major, minor, m_inputId);
1817  sd->SetCaching(true);
1818  if (GetDTVRecorder())
1819  GetDTVRecorder()->SetStreamData(asd);
1820  }
1821 
1822  asd->Reset();
1823  sm->SetStreamData(sd);
1824  sm->SetChannel(major, minor);
1825  sd->SetRecordingType(recording_type);
1826 
1827  // Try to get pid of VCT from cache and
1828  // require MGT if we don't have VCT pid.
1829  if (!ApplyCachedPids(sm, dtvchan))
1831 
1832  LOG(VB_RECORD, LOG_INFO, LOC +
1833  "Successfully set up ATSC table monitoring.");
1834  return true;
1835  }
1836 
1837  // Check if this is an DVB channel
1838  int progNum = dtvchan->GetProgramNumber();
1839  if ((progNum >= 0) && (tuningmode == "dvb") && (m_genOpt.m_inputType != "VBOX"))
1840  {
1841  int netid = dtvchan->GetOriginalNetworkID();
1842  int tsid = dtvchan->GetTransportID();
1843 
1844  auto *dsd = dynamic_cast<DVBStreamData*>(sd);
1845  if (!dsd)
1846  {
1847  sd = dsd = new DVBStreamData(netid, tsid, progNum, m_inputId);
1848  sd->SetCaching(true);
1849  if (GetDTVRecorder())
1850  GetDTVRecorder()->SetStreamData(dsd);
1851  }
1852 
1853  LOG(VB_RECORD, LOG_INFO, LOC +
1854  QString("DVB service_id %1 on net_id %2 tsid %3")
1855  .arg(progNum).arg(netid).arg(tsid));
1856 
1858 
1859  dsd->Reset();
1860  sm->SetStreamData(sd);
1861  sm->SetDVBService(netid, tsid, progNum);
1862  sd->SetRecordingType(recording_type);
1863 
1867  sm->SetRotorTarget(1.0F);
1868 
1869  if (EITscan)
1870  {
1872  sm->IgnoreEncrypted(true);
1873  }
1874 
1875  LOG(VB_RECORD, LOG_INFO, LOC +
1876  "Successfully set up DVB table monitoring.");
1877  return true;
1878  }
1879 
1880  // Check if this is an MPEG channel
1881  if (progNum >= 0)
1882  {
1883  if (!sd)
1884  {
1885  sd = new MPEGStreamData(progNum, m_inputId, true);
1886  sd->SetCaching(true);
1887  if (GetDTVRecorder())
1889  }
1890 
1891  QString msg = QString("MPEG program number: %1").arg(progNum);
1892  LOG(VB_RECORD, LOG_INFO, LOC + msg);
1893 
1895 
1896  sd->Reset();
1897  sm->SetStreamData(sd);
1898  sm->SetProgramNumber(progNum);
1899  sd->SetRecordingType(recording_type);
1900 
1904  sm->SetRotorTarget(1.0F);
1905 
1906  if (EITscan)
1907  {
1909  sm->IgnoreEncrypted(true);
1910  }
1911 
1912  LOG(VB_RECORD, LOG_INFO, LOC +
1913  "Successfully set up MPEG table monitoring.");
1914  return true;
1915  }
1916 
1917  // If this is not an ATSC, DVB or MPEG channel then check to make sure
1918  // that we have permanent pidcache entries.
1919  bool ok = false;
1920  if (GetDTVChannel())
1921  {
1922  pid_cache_t pid_cache;
1923  GetDTVChannel()->GetCachedPids(pid_cache);
1924  for (auto item = pid_cache.cbegin(); !ok && item != pid_cache.cend(); ++item)
1925  ok |= item->IsPermanent();
1926  }
1927 
1928  if (!ok)
1929  {
1930  QString msg = "No valid DTV info, ATSC maj(%1) min(%2), MPEG pn(%3)";
1931  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(major).arg(minor).arg(progNum));
1932  }
1933  else
1934  {
1935  LOG(VB_RECORD, LOG_INFO, LOC +
1936  "Successfully set up raw pid monitoring.");
1937  }
1938 
1939  return ok;
1940 }
1941 
1956 bool TVRec::SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
1957 {
1958  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetupSignalMonitor(%1, %2)")
1959  .arg(tablemon).arg(notify));
1960 
1961  // if it already exists, there no need to initialize it
1962  if (m_signalMonitor)
1963  return true;
1964 
1965  // if there is no channel object we can't monitor it
1966  if (!m_channel)
1967  return false;
1968 
1969  // nothing to monitor here either (DummyChannel)
1970  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
1971  return true;
1972 
1973  // make sure statics are initialized
1975 
1978  m_channel, false);
1979 
1980  if (m_signalMonitor)
1981  {
1982  LOG(VB_RECORD, LOG_INFO, LOC + "Signal monitor successfully created");
1983  // If this is a monitor for Digital TV, initialize table monitors
1984  if (GetDTVSignalMonitor() && tablemon &&
1985  !SetupDTVSignalMonitor(EITscan))
1986  {
1987  LOG(VB_GENERAL, LOG_ERR, LOC +
1988  "Failed to setup digital signal monitoring");
1989 
1990  return false;
1991  }
1992 
1995  kSignalMonitoringRate * 5 :
1998 
1999  // Start the monitoring thread
2001  }
2002 
2003  return true;
2004 }
2005 
2011 {
2012  if (!m_signalMonitor)
2013  return;
2014 
2015  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- begin");
2016 
2017  // If this is a DTV signal monitor, save any pids we know about.
2019  DTVChannel *dtvChan = GetDTVChannel();
2020  if (dtvMon && dtvChan)
2021  {
2022  pid_cache_t pid_cache;
2023  GetPidsToCache(dtvMon, pid_cache);
2024  if (!pid_cache.empty())
2025  dtvChan->SaveCachedPids(pid_cache);
2026  }
2027 
2028  if (m_signalMonitor)
2029  {
2030  delete m_signalMonitor;
2031  m_signalMonitor = nullptr;
2032  }
2033 
2034  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- end");
2035 }
2036 
2048 std::chrono::milliseconds TVRec::SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend)
2049 {
2050  QString msg = "SetSignalMonitoringRate(%1, %2)";
2051  LOG(VB_RECORD, LOG_INFO, LOC +
2052  msg.arg(rate.count()).arg(notifyFrontend) + "-- start");
2053 
2054  QMutexLocker lock(&m_stateChangeLock);
2055 
2057  {
2058  LOG(VB_GENERAL, LOG_ERR, LOC +
2059  "Signal Monitoring is notsupported by your hardware.");
2060  return 0ms;
2061  }
2062 
2064  {
2065  LOG(VB_GENERAL, LOG_ERR, LOC +
2066  "Signal can only be monitored in LiveTV Mode.");
2067  return 0ms;
2068  }
2069 
2070  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
2071 
2072  TuningRequest req = (rate > 0ms) ?
2075 
2077 
2078  // Wait for RingBuffer reset
2079  while (!HasFlags(kFlagRingBufferReady))
2081  LOG(VB_RECORD, LOG_INFO, LOC +
2082  msg.arg(rate.count()).arg(notifyFrontend) + " -- end");
2083  return 1ms;
2084 }
2085 
2087 {
2088  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
2089 }
2090 
2102 bool TVRec::ShouldSwitchToAnotherInput(const QString& chanid) const
2103 {
2104  QString msg("");
2105  MSqlQuery query(MSqlQuery::InitCon());
2106 
2107  if (!query.isConnected())
2108  return false;
2109 
2110  query.prepare("SELECT channel.channum, channel.callsign "
2111  "FROM channel "
2112  "WHERE channel.chanid = :CHANID");
2113  query.bindValue(":CHANID", chanid);
2114  if (!query.exec() || !query.next())
2115  {
2116  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2117  return false;
2118  }
2119 
2120  QString channelname = query.value(0).toString();
2121  QString callsign = query.value(1).toString();
2122 
2123  query.prepare(
2124  "SELECT channel.channum "
2125  "FROM channel, capturecard "
2126  "WHERE deleted IS NULL AND "
2127  " ( channel.chanid = :CHANID OR "
2128  " ( channel.channum = :CHANNUM AND "
2129  " channel.callsign = :CALLSIGN ) "
2130  " ) AND "
2131  " channel.sourceid = capturecard.sourceid AND "
2132  " capturecard.cardid = :INPUTID");
2133  query.bindValue(":CHANID", chanid);
2134  query.bindValue(":CHANNUM", channelname);
2135  query.bindValue(":CALLSIGN", callsign);
2136  query.bindValue(":INPUTID", m_inputId);
2137 
2138  if (!query.exec() || !query.isActive())
2139  {
2140  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2141  }
2142  else if (query.size() > 0)
2143  {
2144  msg = "Found channel (%1) on current input[%2].";
2145  LOG(VB_RECORD, LOG_INFO, LOC + msg.arg(channelname).arg(m_inputId));
2146  return false;
2147  }
2148 
2149  // We didn't find it on the current input, so now we check other inputs.
2150  query.prepare(
2151  "SELECT channel.channum, capturecard.cardid "
2152  "FROM channel, capturecard "
2153  "WHERE deleted IS NULL AND "
2154  " ( channel.chanid = :CHANID OR "
2155  " ( channel.channum = :CHANNUM AND "
2156  " channel.callsign = :CALLSIGN ) "
2157  " ) AND "
2158  " channel.sourceid = capturecard.sourceid AND "
2159  " capturecard.cardid != :INPUTID");
2160  query.bindValue(":CHANID", chanid);
2161  query.bindValue(":CHANNUM", channelname);
2162  query.bindValue(":CALLSIGN", callsign);
2163  query.bindValue(":INPUTID", m_inputId);
2164 
2165  if (!query.exec() || !query.isActive())
2166  {
2167  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2168  }
2169  else if (query.next())
2170  {
2171  msg = QString("Found channel (%1) on different input(%2).")
2172  .arg(query.value(0).toString(), query.value(1).toString());
2173  LOG(VB_RECORD, LOG_INFO, LOC + msg);
2174  return true;
2175  }
2176 
2177  msg = QString("Did not find channel(%1) on any input.").arg(channelname);
2178  LOG(VB_RECORD, LOG_ERR, LOC + msg);
2179  return false;
2180 }
2181 
2192 bool TVRec::CheckChannel(const QString& name) const
2193 {
2194  if (!m_channel)
2195  return false;
2196 
2197  return m_channel->CheckChannel(name);
2198 }
2199 
2203 static QString add_spacer(const QString &channel, const QString &spacer)
2204 {
2205  QString chan = channel;
2206  if ((chan.length() >= 2) && !spacer.isEmpty())
2207  return chan.left(chan.length()-1) + spacer + chan.right(1);
2208  return chan;
2209 }
2210 
2238 bool TVRec::CheckChannelPrefix(const QString &prefix,
2239  uint &complete_valid_channel_on_rec,
2240  bool &is_extra_char_useful,
2241  QString &needed_spacer) const
2242 {
2243 #if DEBUG_CHANNEL_PREFIX
2244  LOG(VB_GENERAL, LOG_DEBUG, QString("CheckChannelPrefix(%1)").arg(prefix));
2245 #endif
2246 
2247  static const std::array<const QString,5> s_spacers = { "", "_", "-", "#", "." };
2248 
2249  MSqlQuery query(MSqlQuery::InitCon());
2250  QString basequery = QString(
2251  "SELECT channel.chanid, channel.channum, capturecard.cardid "
2252  "FROM channel, capturecard "
2253  "WHERE deleted IS NULL AND "
2254  " channel.channum LIKE '%1%' AND "
2255  " channel.sourceid = capturecard.sourceid");
2256 
2257  const std::array<const QString,2> inputquery
2258  {
2259  QString(" AND capturecard.cardid = '%1'").arg(m_inputId),
2260  QString(" AND capturecard.cardid != '%1'").arg(m_inputId),
2261  };
2262 
2263  vector<uint> fchanid;
2264  vector<QString> fchannum;
2265  vector<uint> finputid;
2266  vector<QString> fspacer;
2267 
2268  for (const auto & str : inputquery)
2269  {
2270  for (const auto & spacer : s_spacers)
2271  {
2272  QString qprefix = add_spacer(
2273  prefix, (spacer == "_") ? "\\_" : spacer);
2274  query.prepare(basequery.arg(qprefix) + str);
2275 
2276  if (!query.exec() || !query.isActive())
2277  {
2278  MythDB::DBError("checkchannel -- locate channum", query);
2279  }
2280  else if (query.size())
2281  {
2282  while (query.next())
2283  {
2284  fchanid.push_back(query.value(0).toUInt());
2285  fchannum.push_back(query.value(1).toString());
2286  finputid.push_back(query.value(2).toUInt());
2287  fspacer.emplace_back(spacer);
2288 #if DEBUG_CHANNEL_PREFIX
2289  LOG(VB_GENERAL, LOG_DEBUG,
2290  QString("(%1,%2) Adding %3 rec %4")
2291  .arg(i).arg(j).arg(query.value(1).toString(),6)
2292  .arg(query.value(2).toUInt()));
2293 #endif
2294  }
2295  }
2296 
2297  if (prefix.length() < 2)
2298  break;
2299  }
2300  }
2301 
2302  // Now process the lists for the info we need...
2303  is_extra_char_useful = false;
2304  complete_valid_channel_on_rec = 0;
2305  needed_spacer.clear();
2306 
2307  if (fchanid.empty())
2308  return false;
2309 
2310  if (fchanid.size() == 1) // Unique channel...
2311  {
2312  needed_spacer = fspacer[0];
2313  bool nc = (fchannum[0] != add_spacer(prefix, fspacer[0]));
2314 
2315  complete_valid_channel_on_rec = (nc) ? 0 : finputid[0];
2316  is_extra_char_useful = nc;
2317  return true;
2318  }
2319 
2320  // If we get this far there is more than one channel
2321  // sharing the prefix we were given.
2322 
2323  // Is an extra characher useful for disambiguation?
2324  is_extra_char_useful = false;
2325  for (uint i = 0; (i < fchannum.size()) && !is_extra_char_useful; i++)
2326  {
2327  is_extra_char_useful = (fchannum[i] != add_spacer(prefix, fspacer[i]));
2328 #if DEBUG_CHANNEL_PREFIX
2329  LOG(VB_GENERAL, LOG_DEBUG, QString("is_extra_char_useful(%1!=%2): %3")
2330  .arg(fchannum[i]).arg(add_spacer(prefix, fspacer[i]))
2331  .arg(is_extra_char_useful));
2332 #endif
2333  }
2334 
2335  // Are any of the channels complete w/o spacer?
2336  // If so set complete_valid_channel_on_rec,
2337  // with a preference for our inputid.
2338  for (size_t i = 0; i < fchannum.size(); i++)
2339  {
2340  if (fchannum[i] == prefix)
2341  {
2342  complete_valid_channel_on_rec = finputid[i];
2343  if (finputid[i] == m_inputId)
2344  break;
2345  }
2346  }
2347 
2348  if (complete_valid_channel_on_rec != 0)
2349  return true;
2350 
2351  // Add a spacer, if one is needed to select a valid channel.
2352  bool spacer_needed = true;
2353  for (uint i = 0; (i < fspacer.size() && spacer_needed); i++)
2354  spacer_needed = !fspacer[i].isEmpty();
2355  if (spacer_needed)
2356  needed_spacer = fspacer[0];
2357 
2358  // If it isn't useful to wait for more characters,
2359  // then try to commit to any true match immediately.
2360  for (size_t i = 0; i < ((is_extra_char_useful) ? 0 : fchanid.size()); i++)
2361  {
2362  if (fchannum[i] == add_spacer(prefix, fspacer[i]))
2363  {
2364  needed_spacer = fspacer[i];
2365  complete_valid_channel_on_rec = finputid[i];
2366  return true;
2367  }
2368  }
2369 
2370  return true;
2371 }
2372 
2374  const QString &channum)
2375 {
2376  if (!m_recorder)
2377  return false;
2378 
2379  QString videoFilters = ChannelUtil::GetVideoFilters(sourceid, channum);
2380  if (!videoFilters.isEmpty())
2381  {
2382  m_recorder->SetVideoFilters(videoFilters);
2383  return true;
2384  }
2385 
2386  return false;
2387 }
2388 
2394 {
2395  return ((m_recorder && m_recorder->IsRecording()) ||
2397 }
2398 
2404 bool TVRec::IsBusy(InputInfo *busy_input, std::chrono::seconds time_buffer) const
2405 {
2406  InputInfo dummy;
2407  if (!busy_input)
2408  busy_input = &dummy;
2409 
2410  busy_input->Clear();
2411 
2412  if (!m_channel)
2413  return false;
2414 
2415  if (!m_channel->GetInputID())
2416  return false;
2417 
2418  uint chanid = 0;
2419 
2420  if (GetState() != kState_None)
2421  {
2422  busy_input->m_inputId = m_channel->GetInputID();
2423  chanid = m_channel->GetChanID();
2424  }
2425 
2426  PendingInfo pendinfo;
2427  bool has_pending = false;
2428  {
2429  m_pendingRecLock.lock();
2430  PendingMap::const_iterator it = m_pendingRecordings.find(m_inputId);
2431  has_pending = (it != m_pendingRecordings.end());
2432  if (has_pending)
2433  pendinfo = *it;
2434  m_pendingRecLock.unlock();
2435  }
2436 
2437  if (!busy_input->m_inputId && has_pending)
2438  {
2439  auto timeLeft = MythDate::secsInFuture(pendinfo.m_recordingStart);
2440 
2441  if (timeLeft <= time_buffer)
2442  {
2443  QString channum;
2444  QString input;
2445  if (pendinfo.m_info->QueryTuningInfo(channum, input))
2446  {
2447  busy_input->m_inputId = m_channel->GetInputID();
2448  chanid = pendinfo.m_info->GetChanID();
2449  }
2450  }
2451  }
2452 
2453  if (busy_input->m_inputId)
2454  {
2455  CardUtil::GetInputInfo(*busy_input);
2456  busy_input->m_chanId = chanid;
2457  busy_input->m_mplexId = ChannelUtil::GetMplexID(busy_input->m_chanId);
2458  busy_input->m_mplexId =
2459  (32767 == busy_input->m_mplexId) ? 0 : busy_input->m_mplexId;
2460  }
2461 
2462  return busy_input->m_inputId != 0U;
2463 }
2464 
2465 
2473 {
2474  QMutexLocker lock(&m_stateChangeLock);
2475 
2476  if (m_recorder)
2477  return m_recorder->GetFrameRate();
2478  return -1.0F;
2479 }
2480 
2488 {
2489  QMutexLocker lock(&m_stateChangeLock);
2490 
2491  if (m_recorder)
2492  return m_recorder->GetFramesWritten();
2493  return -1;
2494 }
2495 
2502 long long TVRec::GetFilePosition(void)
2503 {
2504  QMutexLocker lock(&m_stateChangeLock);
2505 
2506  if (m_buffer)
2507  return m_buffer->GetWritePosition();
2508  return -1;
2509 }
2510 
2518 int64_t TVRec::GetKeyframePosition(uint64_t desired) const
2519 {
2520  QMutexLocker lock(&m_stateChangeLock);
2521 
2522  if (m_recorder)
2523  return m_recorder->GetKeyframePosition(desired);
2524  return -1;
2525 }
2526 
2536  int64_t start, int64_t end, frm_pos_map_t &map) const
2537 {
2538  QMutexLocker lock(&m_stateChangeLock);
2539 
2540  if (m_recorder)
2541  return m_recorder->GetKeyframePositions(start, end, map);
2542 
2543  return false;
2544 }
2545 
2547  int64_t start, int64_t end, frm_pos_map_t &map) const
2548 {
2549  QMutexLocker lock(&m_stateChangeLock);
2550 
2551  if (m_recorder)
2552  return m_recorder->GetKeyframeDurations(start, end, map);
2553 
2554  return false;
2555 }
2556 
2562 long long TVRec::GetMaxBitrate(void) const
2563 {
2564  long long bitrate = 0;
2565  if (m_genOpt.m_inputType == "MPEG")
2566  { // NOLINT(bugprone-branch-clone)
2567  bitrate = 10080000LL; // use DVD max bit rate
2568  }
2569  else if (m_genOpt.m_inputType == "HDPVR")
2570  {
2571  bitrate = 20200000LL; // Peak bit rate for HD-PVR
2572  }
2574  {
2575  bitrate = 22200000LL; // 1080i
2576  }
2577  else // frame grabber
2578  {
2579  bitrate = 10080000LL; // use DVD max bit rate, probably too big
2580  }
2581 
2582  return bitrate;
2583 }
2584 
2590 void TVRec::SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
2591 {
2592  QMutexLocker lock(&m_stateChangeLock);
2593 
2594  m_tvChain = newchain;
2595  m_tvChain->IncrRef(); // mark it for TVRec use
2596  m_tvChain->ReloadAll();
2597 
2598  QString hostprefix = MythCoreContext::GenMythURL(
2601 
2602  m_tvChain->SetHostPrefix(hostprefix);
2604 
2605  m_isPip = pip;
2606  m_liveTVStartChannel = std::move(startchan);
2607 
2608  // Change to WatchingLiveTV
2610  // Wait for state change to take effect
2612 
2613  // Make sure StartRecording can't steal our tuner
2614  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2615 }
2616 
2620 QString TVRec::GetChainID(void)
2621 {
2622  if (m_tvChain)
2623  return m_tvChain->GetID();
2624  return "";
2625 }
2626 
2636 {
2637  QMutexLocker lock(&m_stateChangeLock);
2638 
2640  return; // already stopped
2641 
2642  if (!m_curRecording)
2643  return;
2644 
2645  const QString recgrp = m_curRecording->QueryRecordingGroup();
2647 
2648  if (recgrp != "LiveTV" && !m_pseudoLiveTVRecording)
2649  {
2650  // User wants this recording to continue
2652  }
2653  else if (recgrp == "LiveTV" && m_pseudoLiveTVRecording)
2654  {
2655  // User wants to abandon scheduled recording
2656  SetPseudoLiveTVRecording(nullptr);
2657  }
2658 }
2659 
2670 {
2671  if (!m_channel)
2672  return;
2673 
2674  // Notify scheduler of the recording.
2675  // + set up recording so it can be resumed
2676  rec->SetInputID(m_inputId);
2678 
2679  if (rec->GetRecordingRuleType() == kNotRecording)
2680  {
2683  }
2684 
2685  // + remove any end offset which would mismatch the live session
2686  rec->GetRecordingRule()->m_endOffset = 0;
2687 
2688  // + save RecStatus::Inactive recstatus to so that a reschedule call
2689  // doesn't start recording this on another input before we
2690  // send the SCHEDULER_ADD_RECORDING message to the scheduler.
2692  rec->AddHistory(false);
2693 
2694  // + save RecordingRule so that we get a recordid
2695  // (don't allow RescheduleMatch(), avoiding unneeded reschedule)
2696  rec->GetRecordingRule()->Save(false);
2697 
2698  // + save recordid to recorded entry
2699  rec->ApplyRecordRecID();
2700 
2701  // + set proper recstatus (saved later)
2703 
2704  // + pass proginfo to scheduler and reschedule
2705  QStringList prog;
2706  rec->ToStringList(prog);
2707  MythEvent me("SCHEDULER_ADD_RECORDING", prog);
2708  gCoreContext->dispatch(me);
2709 
2710  // Allow scheduler to end this recording before post-roll,
2711  // if it has another recording for this recorder.
2712  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2713 }
2714 
2716  RecordingProfile *recpro, int line)
2717 {
2718  if (kAutoRunProfile == t)
2719  {
2721  if (!recpro)
2722  {
2723  LoadProfile(nullptr, rec, profile);
2724  recpro = &profile;
2725  }
2726  m_autoRunJobs[rec->MakeUniqueKey()] =
2727  init_jobs(rec, *recpro, m_runJobOnHostOnly,
2729  }
2730  else
2731  {
2733  }
2734  LOG(VB_JOBQUEUE, LOG_INFO,
2735  QString("InitAutoRunJobs for %1, line %2 -> 0x%3")
2736  .arg(rec->MakeUniqueKey()).arg(line)
2737  .arg(m_autoRunJobs[rec->MakeUniqueKey()],0,16));
2738 }
2739 
2751 void TVRec::SetLiveRecording(int recording)
2752 {
2753  LOG(VB_GENERAL, LOG_INFO, LOC +
2754  QString("SetLiveRecording(%1)").arg(recording));
2755  QMutexLocker locker(&m_stateChangeLock);
2756 
2757  (void) recording;
2758 
2760  bool was_rec = m_pseudoLiveTVRecording;
2762  if (was_rec && !m_pseudoLiveTVRecording)
2763  {
2764  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- cancel");
2765  // cancel -- 'recording' should be 0 or -1
2766  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2767  m_curRecording->SetRecordingGroup("LiveTV");
2768  InitAutoRunJobs(m_curRecording, kAutoRunNone, nullptr, __LINE__);
2769  }
2770  else if (!was_rec && m_pseudoLiveTVRecording)
2771  {
2772  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- record");
2773  // record -- 'recording' should be 1 or -1
2774 
2775  // If the last recording was flagged for keeping
2776  // in the frontend, then add the recording rule
2777  // so that transcode, commfrag, etc can be run.
2780  recstat = m_curRecording->GetRecordingStatus();
2781  m_curRecording->SetRecordingGroup("Default");
2782  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
2783  }
2784 
2785  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
2786  .arg(m_curRecording->GetInputID())
2787  .arg(m_curRecording->GetChanID())
2789  .arg(recstat)
2791 
2792  gCoreContext->dispatch(me);
2793 }
2794 
2800 {
2801  QMutexLocker lock(&m_stateChangeLock);
2802  LOG(VB_RECORD, LOG_INFO, LOC +
2803  QString("StopLiveTV(void) curRec: 0x%1 pseudoRec: 0x%2")
2804  .arg((uint64_t)m_curRecording,0,16)
2805  .arg((uint64_t)m_pseudoLiveTVRecording,0,16));
2806 
2808  return;
2809 
2810  bool hadPseudoLiveTVRec = m_pseudoLiveTVRecording;
2812 
2813  if (!hadPseudoLiveTVRec && m_pseudoLiveTVRecording)
2815 
2816  // Figure out next state and if needed recording end time.
2817  TVState next_state = kState_None;
2819  {
2821  next_state = kState_RecordingOnly;
2822  }
2823 
2824  // Change to the appropriate state
2825  ChangeState(next_state);
2826 
2827  // Wait for state change to take effect...
2829 
2830  // We are done with the tvchain...
2831  if (m_tvChain)
2832  {
2833  m_tvChain->DecrRef();
2834  }
2835  m_tvChain = nullptr;
2836 }
2837 
2847 {
2848  QMutexLocker lock(&m_stateChangeLock);
2849 
2850  if (!m_recorder)
2851  {
2852  LOG(VB_GENERAL, LOG_ERR, LOC +
2853  "PauseRecorder() called with no recorder");
2854  return;
2855  }
2856 
2857  m_recorder->Pause();
2858 }
2859 
2866 {
2867  if (m_pauseNotify)
2868  WakeEventLoop();
2869 }
2870 
2874 void TVRec::ToggleChannelFavorite(const QString& changroupname)
2875 {
2876  QMutexLocker lock(&m_stateChangeLock);
2877 
2878  if (!m_channel)
2879  return;
2880 
2881  // Get current channel id...
2882  uint sourceid = m_channel->GetSourceID();
2883  QString channum = m_channel->GetChannelName();
2884  uint chanid = ChannelUtil::GetChanID(sourceid, channum);
2885 
2886  if (!chanid)
2887  {
2888  LOG(VB_GENERAL, LOG_ERR, LOC +
2889  QString("Channel: \'%1\' was not found in the database.\n"
2890  "\t\tMost likely, the 'starting channel' for this "
2891  "Input Connection is invalid.\n"
2892  "\t\tCould not toggle favorite.").arg(channum));
2893  return;
2894  }
2895 
2896  int changrpid = ChannelGroup::GetChannelGroupId(changroupname);
2897  if (changrpid <1)
2898  {
2899  LOG(VB_RECORD, LOG_ERR, LOC +
2900  QString("ToggleChannelFavorite: Invalid channel group name %1,")
2901  .arg(changroupname));
2902  }
2903  else
2904  {
2905  bool result = ChannelGroup::ToggleChannel(chanid, changrpid, true);
2906 
2907  if (!result)
2908  LOG(VB_RECORD, LOG_ERR, LOC + "Unable to toggle channel favorite.");
2909  else
2910  {
2911  LOG(VB_RECORD, LOG_INFO, LOC +
2912  QString("Toggled channel favorite.channum %1, chan group %2")
2913  .arg(channum, changroupname));
2914  }
2915  }
2916 }
2917 
2924 {
2925  QMutexLocker lock(&m_stateChangeLock);
2926  if (!m_channel)
2927  return -1;
2928 
2929  int ret = m_channel->GetPictureAttribute(attr);
2930 
2931  return (ret < 0) ? -1 : ret / 655;
2932 }
2933 
2942  PictureAttribute attr,
2943  bool direction)
2944 {
2945  QMutexLocker lock(&m_stateChangeLock);
2946  if (!m_channel)
2947  return -1;
2948 
2949  int ret = m_channel->ChangePictureAttribute(type, attr, direction);
2950 
2951  return (ret < 0) ? -1 : ret / 655;
2952 }
2953 
2957 QString TVRec::GetInput(void) const
2958 {
2959  if (m_channel)
2960  return m_channel->GetInputName();
2961  return QString();
2962 }
2963 
2968 {
2969  if (m_channel)
2970  return m_channel->GetSourceID();
2971  return 0;
2972 }
2973 
2982 QString TVRec::SetInput(QString input)
2983 {
2984  QMutexLocker lock(&m_stateChangeLock);
2985  QString origIn = input;
2986  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + input + ") -- begin");
2987 
2988  if (!m_channel)
2989  {
2990  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput() -- end no channel class");
2991  return QString();
2992  }
2993 
2994  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + origIn + ":" + input +
2995  ") -- end nothing to do");
2996  return input;
2997 }
2998 
3008 void TVRec::SetChannel(const QString& name, uint requestType)
3009 {
3010  QMutexLocker locker1(&m_setChannelLock);
3011  QMutexLocker locker2(&m_stateChangeLock);
3012 
3013  LOG(VB_CHANNEL, LOG_INFO, LOC +
3014  QString("SetChannel(%1) -- begin").arg(name));
3015 
3016  // Detect tuning request type if needed
3017  if (requestType & kFlagDetect)
3018  {
3020  requestType = m_lastTuningRequest.m_flags & (kFlagRec | kFlagNoRec);
3021  }
3022 
3023  // Clear the RingBuffer reset flag, in case we wait for a reset below
3024  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3025 
3026  // Clear out any EITScan channel change requests
3027  auto it = m_tuningRequests.begin();
3028  while (it != m_tuningRequests.end())
3029  {
3030  if ((*it).m_flags & kFlagEITScan)
3031  it = m_tuningRequests.erase(it);
3032  else
3033  ++it;
3034  }
3035 
3036  // Actually add the tuning request to the queue, and
3037  // then wait for it to start tuning
3038  m_tuningRequests.enqueue(TuningRequest(requestType, name));
3040 
3041  // If we are using a recorder, wait for a RingBuffer reset
3042  if (requestType & kFlagRec)
3043  {
3044  while (!HasFlags(kFlagRingBufferReady))
3046  }
3047  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetChannel(%1) -- end").arg(name));
3048 }
3049 
3057 bool TVRec::QueueEITChannelChange(const QString &name)
3058 {
3059  LOG(VB_CHANNEL, LOG_INFO, LOC +
3060  QString("QueueEITChannelChange(%1) -- begin").arg(name));
3061 
3062  bool ok = false;
3063  if (m_setChannelLock.tryLock())
3064  {
3065  if (m_stateChangeLock.tryLock())
3066  {
3067  if (m_tuningRequests.empty())
3068  {
3070  ok = true;
3071  }
3072  m_stateChangeLock.unlock();
3073  }
3074  m_setChannelLock.unlock();
3075  }
3076 
3077  LOG(VB_CHANNEL, LOG_INFO, LOC +
3078  QString("QueueEITChannelChange(%1) -- end --> %2").arg(name).arg(ok));
3079 
3080  return ok;
3081 }
3082 
3084  QString &title, QString &subtitle,
3085  QString &desc, QString &category,
3086  QString &starttime, QString &endtime,
3087  QString &callsign, QString &iconpath,
3088  QString &channum, uint &sourceChanid,
3089  QString &seriesid, QString &programid)
3090 {
3091  QString compare = "<=";
3092  QString sortorder = "desc";
3093  uint chanid = 0;
3094 
3095  if (sourceChanid)
3096  {
3097  chanid = sourceChanid;
3098 
3099  if (BROWSE_UP == direction)
3100  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_UP);
3101  else if (BROWSE_DOWN == direction)
3102  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_DOWN);
3103  else if (BROWSE_FAVORITE == direction)
3104  {
3105  chanid = m_channel->GetNextChannel(
3106  chanid, CHANNEL_DIRECTION_FAVORITE);
3107  }
3108  else if (BROWSE_LEFT == direction)
3109  {
3110  compare = "<";
3111  }
3112  else if (BROWSE_RIGHT == direction)
3113  {
3114  compare = ">";
3115  sortorder = "asc";
3116  }
3117  }
3118 
3119  if (!chanid)
3120  {
3121  if (BROWSE_SAME == direction)
3122  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3123  else if (BROWSE_UP == direction)
3124  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_UP);
3125  else if (BROWSE_DOWN == direction)
3126  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_DOWN);
3127  else if (BROWSE_FAVORITE == direction)
3128  {
3129  chanid = m_channel->GetNextChannel(channum,
3131  }
3132  else if (BROWSE_LEFT == direction)
3133  {
3134  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3135  compare = "<";
3136  }
3137  else if (BROWSE_RIGHT == direction)
3138  {
3139  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3140  compare = ">";
3141  sortorder = "asc";
3142  }
3143  }
3144 
3145  QString querystr = QString(
3146  "SELECT title, subtitle, description, category, "
3147  " starttime, endtime, callsign, icon, "
3148  " channum, seriesid, programid "
3149  "FROM program, channel "
3150  "WHERE program.chanid = channel.chanid AND "
3151  " channel.chanid = :CHANID AND "
3152  " starttime %1 :STARTTIME "
3153  "ORDER BY starttime %2 "
3154  "LIMIT 1").arg(compare, sortorder);
3155 
3156  MSqlQuery query(MSqlQuery::InitCon());
3157  query.prepare(querystr);
3158  query.bindValue(":CHANID", chanid);
3159  query.bindValue(":STARTTIME", starttime);
3160 
3161  // Clear everything now in case either query fails.
3162  title = subtitle = desc = category = "";
3163  starttime = endtime = callsign = iconpath = "";
3164  channum = seriesid = programid = "";
3165  sourceChanid = 0;
3166 
3167  // Try to get the program info
3168  if (!query.exec() && !query.isActive())
3169  {
3170  MythDB::DBError("GetNextProgram -- get program info", query);
3171  }
3172  else if (query.next())
3173  {
3174  title = query.value(0).toString();
3175  subtitle = query.value(1).toString();
3176  desc = query.value(2).toString();
3177  category = query.value(3).toString();
3178  starttime = query.value(4).toString();
3179  endtime = query.value(5).toString();
3180  callsign = query.value(6).toString();
3181  iconpath = query.value(7).toString();
3182  channum = query.value(8).toString();
3183  seriesid = query.value(9).toString();
3184  programid = query.value(10).toString();
3185  sourceChanid = chanid;
3186  return;
3187  }
3188 
3189  // Couldn't get program info, so get the channel info instead
3190  query.prepare(
3191  "SELECT channum, callsign, icon "
3192  "FROM channel "
3193  "WHERE chanid = :CHANID");
3194  query.bindValue(":CHANID", chanid);
3195 
3196  if (!query.exec() || !query.isActive())
3197  {
3198  MythDB::DBError("GetNextProgram -- get channel info", query);
3199  }
3200  else if (query.next())
3201  {
3202  sourceChanid = chanid;
3203  channum = query.value(0).toString();
3204  callsign = query.value(1).toString();
3205  iconpath = query.value(2).toString();
3206  }
3207 }
3208 
3209 bool TVRec::GetChannelInfo(uint &chanid, uint &sourceid,
3210  QString &callsign, QString &channum,
3211  QString &channame, QString &xmltvid) const
3212 {
3213  callsign.clear();
3214  channum.clear();
3215  channame.clear();
3216  xmltvid.clear();
3217 
3218  if ((!chanid || !sourceid) && !m_channel)
3219  return false;
3220 
3221  if (!chanid)
3222  chanid = (uint) std::max(m_channel->GetChanID(), 0);
3223 
3224  if (!sourceid)
3225  sourceid = m_channel->GetSourceID();
3226 
3227  MSqlQuery query(MSqlQuery::InitCon());
3228  query.prepare(
3229  "SELECT callsign, channum, name, xmltvid "
3230  "FROM channel "
3231  "WHERE chanid = :CHANID");
3232  query.bindValue(":CHANID", chanid);
3233  if (!query.exec() || !query.isActive())
3234  {
3235  MythDB::DBError("GetChannelInfo", query);
3236  return false;
3237  }
3238 
3239  if (!query.next())
3240  return false;
3241 
3242  callsign = query.value(0).toString();
3243  channum = query.value(1).toString();
3244  channame = query.value(2).toString();
3245  xmltvid = query.value(3).toString();
3246 
3247  return true;
3248 }
3249 
3250 bool TVRec::SetChannelInfo(uint chanid, uint sourceid,
3251  const QString& oldchannum,
3252  const QString& callsign, const QString& channum,
3253  const QString& channame, const QString& xmltvid)
3254 {
3255  if (!chanid || !sourceid || channum.isEmpty())
3256  return false;
3257 
3258  MSqlQuery query(MSqlQuery::InitCon());
3259  query.prepare(
3260  "UPDATE channel "
3261  "SET callsign = :CALLSIGN, "
3262  " channum = :CHANNUM, "
3263  " name = :CHANNAME, "
3264  " xmltvid = :XMLTVID "
3265  "WHERE chanid = :CHANID AND "
3266  " sourceid = :SOURCEID");
3267  query.bindValue(":CALLSIGN", callsign);
3268  query.bindValue(":CHANNUM", channum);
3269  query.bindValue(":CHANNAME", channame);
3270  query.bindValue(":XMLTVID", xmltvid);
3271  query.bindValue(":CHANID", chanid);
3272  query.bindValue(":SOURCEID", sourceid);
3273 
3274  if (!query.exec())
3275  {
3276  MythDB::DBError("SetChannelInfo", query);
3277  return false;
3278  }
3279 
3280  if (m_channel)
3281  m_channel->Renumber(sourceid, oldchannum, channum);
3282 
3283  return true;
3284 }
3285 
3290 {
3291  QMutexLocker lock(&m_stateChangeLock);
3292 
3293  MythMediaBuffer *oldbuffer = m_buffer;
3294  m_buffer = Buffer;
3295 
3296  if (oldbuffer && (oldbuffer != Buffer))
3297  {
3299  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3300  delete oldbuffer;
3301  }
3302 
3303  m_switchingBuffer = false;
3304 }
3305 
3307 {
3308  LOG(VB_GENERAL, LOG_INFO, LOC + "RingBufferChanged()");
3309 
3310  if (pginfo)
3311  {
3312  if (m_curRecording)
3313  {
3316  delete m_curRecording;
3317  }
3319  m_curRecording = new RecordingInfo(*pginfo);
3322  }
3323 
3325 }
3326 
3328  QString &input) const
3329 {
3330  QString channum;
3331 
3332  if (request.m_program)
3333  {
3334  request.m_program->QueryTuningInfo(channum, input);
3335  return channum;
3336  }
3337 
3338  channum = request.m_channel;
3339  input = request.m_input;
3340 
3341  // If this is Live TV startup, we need a channel...
3342  if (channum.isEmpty() && (request.m_flags & kFlagLiveTV))
3343  {
3344  if (!m_liveTVStartChannel.isEmpty())
3345  channum = m_liveTVStartChannel;
3346  else
3347  {
3350  }
3351  }
3352  if (request.m_flags & kFlagLiveTV)
3353  m_channel->Init(channum, false);
3354 
3355  if (m_channel && !channum.isEmpty() && (channum.indexOf("NextChannel") >= 0))
3356  {
3357  // FIXME This is just horrible
3358  int dir = channum.right(channum.length() - 12).toInt();
3359  uint chanid = m_channel->GetNextChannel(0, static_cast<ChannelChangeDirection>(dir));
3360  channum = ChannelUtil::GetChanNum(chanid);
3361  }
3362 
3363  return channum;
3364 }
3365 
3367 {
3368  if ((request.m_flags & kFlagAntennaAdjust) || request.m_input.isEmpty() ||
3370  {
3371  return false;
3372  }
3373 
3374  uint sourceid = m_channel->GetSourceID();
3375  QString oldchannum = m_channel->GetChannelName();
3376  QString newchannum = request.m_channel;
3377 
3378  if (ChannelUtil::IsOnSameMultiplex(sourceid, newchannum, oldchannum))
3379  {
3381  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3382 
3383  if (atsc)
3384  {
3385  uint major = 0;
3386  uint minor = 0;
3387  ChannelUtil::GetATSCChannel(sourceid, newchannum, major, minor);
3388 
3389  if (minor && atsc->HasChannel(major, minor))
3390  {
3391  request.m_majorChan = major;
3392  request.m_minorChan = minor;
3393  return true;
3394  }
3395  }
3396 
3397  if (mpeg)
3398  {
3399  uint progNum = ChannelUtil::GetProgramNumber(sourceid, newchannum);
3400  if (mpeg->HasProgram(progNum))
3401  {
3402  request.m_progNum = progNum;
3403  return true;
3404  }
3405  }
3406  }
3407 
3408  return false;
3409 }
3410 
3419 {
3420  if (!m_tuningRequests.empty())
3421  {
3422  TuningRequest request = m_tuningRequests.front();
3423  LOG(VB_RECORD, LOG_INFO, LOC +
3424  "HandleTuning Request: " + request.toString());
3425 
3426  QString input;
3427  request.m_channel = TuningGetChanNum(request, input);
3428  request.m_input = input;
3429 
3430  if (TuningOnSameMultiplex(request))
3431  LOG(VB_CHANNEL, LOG_INFO, LOC + "On same multiplex");
3432 
3433  TuningShutdowns(request);
3434 
3435  // The dequeue isn't safe to do until now because we
3436  // release the stateChangeLock to teardown a recorder
3438 
3439  // Now we start new stuff
3440  if (request.m_flags & (kFlagRecording|kFlagLiveTV|
3442  {
3443  if (!m_recorder)
3444  {
3445  LOG(VB_RECORD, LOG_INFO, LOC +
3446  "No recorder yet, calling TuningFrequency");
3447  TuningFrequency(request);
3448  }
3449  else
3450  {
3451  LOG(VB_RECORD, LOG_INFO, LOC + "Waiting for recorder pause..");
3452  SetFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3453  }
3454  }
3455  m_lastTuningRequest = request;
3456  }
3457 
3459  {
3460  if (!m_recorder->IsPaused())
3461  return;
3462 
3463  ClearFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3464  LOG(VB_RECORD, LOG_INFO, LOC +
3465  "Recorder paused, calling TuningFrequency");
3467  }
3468 
3469  MPEGStreamData *streamData = nullptr;
3470  if (HasFlags(kFlagWaitingForSignal) && !(streamData = TuningSignalCheck()))
3471  return;
3472 
3474  {
3475  if (m_recorder)
3477  else
3478  TuningNewRecorder(streamData);
3479 
3480  // If we got this far it is safe to set a new starting channel...
3481  if (m_channel)
3483  }
3484 }
3485 
3491 {
3492  LOG(VB_RECORD, LOG_INFO, LOC + QString("TuningShutdowns(%1)")
3493  .arg(request.toString()));
3494 
3495  if (m_scanner && !(request.m_flags & kFlagEITScan) &&
3497  {
3499  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
3501  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
3502  }
3503 
3504  if (m_scanner && !request.IsOnSameMultiplex())
3506 
3508  {
3509  MPEGStreamData *sd = nullptr;
3510  if (GetDTVSignalMonitor())
3513  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3514 
3515  // Delete StreamData if it is not in use by the recorder.
3516  MPEGStreamData *rec_sd = nullptr;
3517  if (GetDTVRecorder())
3518  rec_sd = GetDTVRecorder()->GetStreamData();
3519  if (sd && (sd != rec_sd))
3520  delete sd;
3521  }
3523  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3524 
3525  // At this point any waits are canceled.
3526 
3527  if (request.m_flags & kFlagNoRec)
3528  {
3530  {
3532  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3534  }
3535 
3537  (m_curRecording &&
3540  {
3541  m_stateChangeLock.unlock();
3542  TeardownRecorder(request.m_flags);
3543  m_stateChangeLock.lock();
3544  }
3545  // At this point the recorders are shut down
3546 
3547  CloseChannel();
3548  // At this point the channel is shut down
3549  }
3550 
3551  if (m_buffer && (request.m_flags & kFlagKillRingBuffer))
3552  {
3553  LOG(VB_RECORD, LOG_INFO, LOC + "Tearing down RingBuffer");
3554  SetRingBuffer(nullptr);
3555  // At this point the ringbuffer is shut down
3556  }
3557 
3558  // Clear pending actions from last request
3559  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
3560 }
3561 
3580 {
3581  LOG(VB_GENERAL, LOG_INFO, LOC + "TuningFrequency");
3582 
3583  DTVChannel *dtvchan = GetDTVChannel();
3584  if (dtvchan)
3585  {
3586  MPEGStreamData *mpeg = nullptr;
3587 
3588  if (GetDTVRecorder())
3590 
3591  const QString tuningmode = (HasFlags(kFlagEITScannerRunning)) ?
3592  dtvchan->GetSIStandard() :
3593  dtvchan->GetSuggestedTuningMode(
3595 
3596  dtvchan->SetTuningMode(tuningmode);
3597 
3598  if (request.m_minorChan && (tuningmode == "atsc"))
3599  {
3601 
3602  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3603  if (atsc)
3604  atsc->SetDesiredChannel(request.m_majorChan, request.m_minorChan);
3605  }
3606  else if (request.m_progNum >= 0)
3607  {
3609 
3610  if (mpeg)
3611  mpeg->SetDesiredProgram(request.m_progNum);
3612  }
3613  }
3614 
3615  if (request.IsOnSameMultiplex())
3616  {
3617  // Update the channel number for SwitchLiveTVRingBuffer (called from
3618  // TuningRestartRecorder). This ensures that the livetvchain will be
3619  // updated with the new channel number
3620  if (m_channel)
3621  {
3623  m_channel->GetChannelName(), request.m_channel );
3624  }
3625 
3626  QStringList slist;
3627  slist<<"message"<<QObject::tr("On known multiplex...");
3628  MythEvent me(QString("SIGNAL %1").arg(m_inputId), slist);
3629  gCoreContext->dispatch(me);
3630 
3631  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3632  return;
3633  }
3634 
3635  QString channum = request.m_channel;
3636 
3637  bool ok1 = true;
3638  if (m_channel)
3639  {
3640  m_channel->Open();
3641  if (!channum.isEmpty())
3642  ok1 = m_channel->SetChannelByString(channum);
3643  else
3644  ok1 = false;
3645  }
3646 
3647  if (!ok1)
3648  {
3649  if (!(request.m_flags & kFlagLiveTV) || !(request.m_flags & kFlagEITScan))
3650  {
3651  if (m_curRecording)
3653 
3654  LOG(VB_GENERAL, LOG_ERR, LOC +
3655  QString("Failed to set channel to %1. Reverting to kState_None")
3656  .arg(channum));
3659  else
3661  return;
3662  }
3663 
3664  LOG(VB_GENERAL, LOG_ERR, LOC +
3665  QString("Failed to set channel to %1.").arg(channum));
3666  }
3667 
3668 
3669  bool mpts_only = GetDTVChannel() &&
3670  GetDTVChannel()->GetFormat().compare("MPTS") == 0;
3671  if (mpts_only)
3672  {
3673  // Not using a signal monitor, so just set the status to recording
3675  if (m_curRecording)
3676  {
3678  }
3679  }
3680 
3681 
3682  bool livetv = (request.m_flags & kFlagLiveTV) != 0U;
3683  bool antadj = (request.m_flags & kFlagAntennaAdjust) != 0U;
3684  bool use_sm = !mpts_only && SignalMonitor::IsRequired(m_genOpt.m_inputType);
3685  bool use_dr = use_sm && (livetv || antadj);
3686  bool has_dummy = false;
3687 
3688  if (use_dr)
3689  {
3690  // We need there to be a ringbuffer for these modes
3691  bool ok2 = false;
3693  m_pseudoLiveTVRecording = nullptr;
3694 
3695  m_tvChain->SetInputType("DUMMY");
3696 
3697  if (!m_buffer)
3698  ok2 = CreateLiveTVRingBuffer(channum);
3699  else
3700  ok2 = SwitchLiveTVRingBuffer(channum, true, false);
3702 
3704 
3705  if (!ok2)
3706  {
3707  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 1");
3708  return;
3709  }
3710 
3711  has_dummy = true;
3712  }
3713 
3714  // Start signal monitoring for devices capable of monitoring
3715  if (use_sm)
3716  {
3717  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Signal Monitor");
3718  bool error = false;
3719  if (!SetupSignalMonitor(
3720  !antadj, (request.m_flags & kFlagEITScan) != 0U, livetv || antadj))
3721  {
3722  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to setup signal monitor");
3723  if (m_signalMonitor)
3724  {
3725  delete m_signalMonitor;
3726  m_signalMonitor = nullptr;
3727  }
3728 
3729  // pretend the signal monitor is running to prevent segfault
3730  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3731  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3732  error = true;
3733  }
3734 
3735  if (m_signalMonitor)
3736  {
3737  if (request.m_flags & kFlagEITScan)
3738  {
3740  SetVideoStreamsRequired(0);
3742  }
3743 
3744  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3745  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3746  if (!antadj)
3747  {
3748  QDateTime expire = MythDate::current();
3749 
3750  SetFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3751  if (m_curRecording)
3752  {
3754  // If startRecordingDeadline is passed, this
3755  // recording is marked as failed, so the scheduler
3756  // can try another showing.
3758  expire.addMSecs(m_genOpt.m_channelTimeout);
3760  expire.addMSecs(m_genOpt.m_channelTimeout * 2 / 3);
3761  // Keep trying to record this showing (even if it
3762  // has been marked as failed) until the scheduled
3763  // end time.
3765  m_curRecording->GetRecordingEndTime().addSecs(-10);
3766 
3767  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
3768  QString("Pre-fail start deadline: %1 "
3769  "Start recording deadline: %2 "
3770  "Good signal deadline: %3")
3771  .arg(m_preFailDeadline.toLocalTime()
3772  .toString("hh:mm:ss.zzz"),
3773  m_startRecordingDeadline.toLocalTime()
3774  .toString("hh:mm:ss.zzz"),
3775  m_signalMonitorDeadline.toLocalTime()
3776  .toString("hh:mm:ss.zzz")));
3777  }
3778  else
3779  {
3781  expire.addMSecs(m_genOpt.m_channelTimeout);
3782  }
3784 
3785  //System Event TUNING_TIMEOUT deadline
3787  m_signalEventCmdSent = false;
3788  }
3789  }
3790 
3791  if (has_dummy && m_buffer)
3792  {
3793  // Make sure recorder doesn't point to bogus ringbuffer before
3794  // it is potentially restarted without a new ringbuffer, if
3795  // the next channel won't tune and the user exits LiveTV.
3796  if (m_recorder)
3797  m_recorder->SetRingBuffer(nullptr);
3798 
3799  SetFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3800  LOG(VB_RECORD, LOG_INFO, "DummyDTVRecorder -- started");
3801  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3802  }
3803 
3804  // if we had problems starting the signal monitor,
3805  // we don't want to start the recorder...
3806  if (error)
3807  return;
3808  }
3809 
3810  // Request a recorder, if the command is a recording command
3811  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3812  if (request.m_flags & kFlagRec && !antadj)
3813  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3814 }
3815 
3824 {
3825  RecStatus::Type newRecStatus = RecStatus::Unknown;
3826  bool keep_trying = false;
3827  QDateTime current_time = MythDate::current();
3828 
3829  if ((m_signalMonitor->IsErrored() || current_time > m_signalEventCmdTimeout) &&
3831  {
3832  gCoreContext->SendSystemEvent(QString("TUNING_SIGNAL_TIMEOUT CARDID %1")
3833  .arg(m_inputId));
3834  m_signalEventCmdSent = true;
3835  }
3836 
3837  if (m_signalMonitor->IsAllGood())
3838  {
3839  LOG(VB_RECORD, LOG_INFO, LOC + "TuningSignalCheck: Good signal");
3840  if (m_curRecording && (current_time > m_startRecordingDeadline))
3841  {
3842  newRecStatus = RecStatus::Failing;
3843  m_curRecording->SaveVideoProperties(VID_DAMAGED, VID_DAMAGED);
3844 
3845  QString desc = tr("Good signal seen after %1 ms")
3846  .arg(m_genOpt.m_channelTimeout +
3847  m_startRecordingDeadline.msecsTo(current_time));
3848  QString title = m_curRecording->GetTitle();
3849  if (!m_curRecording->GetSubtitle().isEmpty())
3850  title += " - " + m_curRecording->GetSubtitle();
3851 
3853  "Recording", title,
3854  tr("See 'Tuning timeout' in mythtv-setup "
3855  "for this input."));
3856  gCoreContext->SendEvent(mn);
3857 
3858  LOG(VB_GENERAL, LOG_WARNING, LOC +
3859  QString("It took longer than %1 ms to get a signal lock. "
3860  "Keeping status of '%2'")
3862  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
3863  LOG(VB_GENERAL, LOG_WARNING, LOC +
3864  "See 'Tuning timeout' in mythtv-setup for this input");
3865  }
3866  else
3867  {
3868  newRecStatus = RecStatus::Recording;
3869  }
3870  }
3871  else if (m_signalMonitor->IsErrored() || current_time > m_signalMonitorDeadline)
3872  {
3873  LOG(VB_GENERAL, LOG_ERR, LOC + "TuningSignalCheck: SignalMonitor " +
3874  (m_signalMonitor->IsErrored() ? "failed" : "timed out"));
3875 
3876  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3877  newRecStatus = RecStatus::Failed;
3878 
3880  {
3882  }
3883  }
3884  else if (m_curRecording && !m_reachedPreFail && current_time > m_preFailDeadline)
3885  {
3886  LOG(VB_GENERAL, LOG_ERR, LOC +
3887  "TuningSignalCheck: Hit pre-fail timeout");
3888  SendMythSystemRecEvent("REC_PREFAIL", m_curRecording);
3889  m_reachedPreFail = true;
3890  return nullptr;
3891  }
3893  current_time > m_startRecordingDeadline)
3894  {
3895  newRecStatus = RecStatus::Failing;
3897  keep_trying = true;
3898 
3899  SendMythSystemRecEvent("REC_FAILING", m_curRecording);
3900 
3901  QString desc = tr("Taking more than %1 ms to get a lock.")
3902  .arg(m_genOpt.m_channelTimeout);
3903  QString title = m_curRecording->GetTitle();
3904  if (!m_curRecording->GetSubtitle().isEmpty())
3905  title += " - " + m_curRecording->GetSubtitle();
3906 
3908  "Recording", title,
3909  tr("See 'Tuning timeout' in mythtv-setup "
3910  "for this input."));
3911  mn.SetDuration(30s);
3912  gCoreContext->SendEvent(mn);
3913 
3914  LOG(VB_GENERAL, LOG_WARNING, LOC +
3915  QString("TuningSignalCheck: taking more than %1 ms to get a lock. "
3916  "marking this recording as '%2'.")
3918  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
3919  LOG(VB_GENERAL, LOG_WARNING, LOC +
3920  "See 'Tuning timeout' in mythtv-setup for this input");
3921  }
3922  else
3923  {
3924  if (m_signalMonitorCheckCnt) // Don't flood log file
3926  else
3927  {
3928  LOG(VB_RECORD, LOG_INFO, LOC +
3929  QString("TuningSignalCheck: Still waiting. Will timeout @ %1")
3930  .arg(m_signalMonitorDeadline.toLocalTime()
3931  .toString("hh:mm:ss.zzz")));
3933  }
3934  return nullptr;
3935  }
3936 
3937  SetRecordingStatus(newRecStatus, __LINE__);
3938 
3939  if (m_curRecording)
3940  {
3941  m_curRecording->SetRecordingStatus(newRecStatus);
3942  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
3943  .arg(m_curRecording->GetInputID())
3944  .arg(m_curRecording->GetChanID())
3946  .arg(newRecStatus)
3948  gCoreContext->dispatch(me);
3949  }
3950 
3951  if (keep_trying)
3952  return nullptr;
3953 
3954  // grab useful data from DTV signal monitor before we kill it...
3955  MPEGStreamData *streamData = nullptr;
3956  if (GetDTVSignalMonitor())
3957  streamData = GetDTVSignalMonitor()->GetStreamData();
3958 
3960  {
3961  // shut down signal monitoring
3963  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3964  }
3965  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3966 
3967  if (streamData)
3968  {
3969  auto *dsd = dynamic_cast<DVBStreamData*>(streamData);
3970  if (dsd)
3972  if (!get_use_eit(GetInputId()))
3973  {
3974  LOG(VB_EIT, LOG_INFO, LOC +
3975  "EIT scanning disabled for all sources on this input.");
3976  }
3977  else if (m_scanner)
3978  m_scanner->StartPassiveScan(m_channel, streamData);
3979  }
3980 
3981  return streamData;
3982 }
3983 
3985  bool on_host, bool transcode_bfr_comm, bool on_line_comm)
3986 {
3987  if (!rec)
3988  return 0; // no jobs for Live TV recordings..
3989 
3990  int jobs = 0; // start with no jobs
3991 
3992  // grab standard jobs flags from program info
3994 
3995  // disable commercial flagging on PBS, BBC, etc.
3996  if (rec->IsCommercialFree())
3998 
3999  // disable transcoding if the profile does not allow auto transcoding
4000  const StandardSetting *autoTrans = profile.byName("autotranscode");
4001  if ((!autoTrans) || (autoTrans->getValue().toInt() == 0))
4003 
4004  bool ml = JobQueue::JobIsInMask(JOB_METADATA, jobs);
4005  if (ml)
4006  {
4007  // When allowed, metadata lookup should occur at the
4008  // start of a recording to make the additional info
4009  // available immediately (and for use in future jobs).
4010  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4012  rec->GetChanID(),
4013  rec->GetRecordingStartTime(), "", "",
4014  host, JOB_LIVE_REC);
4015 
4016  // don't do regular metadata lookup, we won't need it.
4018  }
4019 
4020  // is commercial flagging enabled, and is on-line comm flagging enabled?
4021  bool rt = JobQueue::JobIsInMask(JOB_COMMFLAG, jobs) && on_line_comm;
4022  // also, we either need transcoding to be disabled or
4023  // we need to be allowed to commercial flag before transcoding?
4024  rt &= JobQueue::JobIsNotInMask(JOB_TRANSCODE, jobs) ||
4025  !transcode_bfr_comm;
4026  if (rt)
4027  {
4028  // queue up real-time (i.e. on-line) commercial flagging.
4029  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4031  rec->GetChanID(),
4032  rec->GetRecordingStartTime(), "", "",
4033  host, JOB_LIVE_REC);
4034 
4035  // don't do regular comm flagging, we won't need it.
4037  }
4038 
4039  return jobs;
4040 }
4041 
4042 QString TVRec::LoadProfile(void *tvchain, RecordingInfo *rec,
4043  RecordingProfile &profile) const
4044 {
4045  // Determine the correct recording profile.
4046  // In LiveTV mode use "Live TV" profile, otherwise use the
4047  // recording's specified profile. If the desired profile can't
4048  // be found, fall back to the "Default" profile for input type.
4049  QString profileName = "Live TV";
4050  if (!tvchain && rec)
4051  profileName = rec->GetRecordingRule()->m_recProfile;
4052 
4053  QString profileRequested = profileName;
4054 
4055  if (profile.loadByType(profileName, m_genOpt.m_inputType,
4057  {
4058  LOG(VB_RECORD, LOG_INFO, LOC +
4059  QString("Using profile '%1' to record")
4060  .arg(profileName));
4061  }
4062  else
4063  {
4064  profileName = "Default";
4065  if (profile.loadByType(profileName, m_genOpt.m_inputType, m_genOpt.m_videoDev))
4066  {
4067  LOG(VB_RECORD, LOG_INFO, LOC +
4068  QString("Profile '%1' not found, using "
4069  "fallback profile '%2' to record")
4070  .arg(profileRequested, profileName));
4071  }
4072  else
4073  {
4074  LOG(VB_RECORD, LOG_ERR, LOC +
4075  QString("Profile '%1' not found, and unable "
4076  "to load fallback profile '%2'. Results "
4077  "may be unpredicable")
4078  .arg(profileRequested, profileName));
4079  }
4080  }
4081 
4082  return profileName;
4083 }
4084 
4089 {
4090  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Recorder");
4091 
4092  bool had_dummyrec = false;
4094  {
4096  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4098  had_dummyrec = true;
4099  }
4100 
4102 
4105 
4106  if (m_tvChain)
4107  {
4108  bool ok = false;
4109  if (!m_buffer)
4110  {
4112  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4113  }
4114  else
4116  true, !had_dummyrec && m_recorder);
4117  if (!ok)
4118  {
4119  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 2");
4120  goto err_ret;
4121  }
4122  rec = m_curRecording; // new'd in Create/SwitchLiveTVRingBuffer()
4123  }
4124 
4126  {
4127  bool write = m_genOpt.m_inputType != "IMPORT";
4128  LOG(VB_GENERAL, LOG_INFO, LOC + QString("rec->GetPathname(): '%1'")
4129  .arg(rec->GetPathname()));
4131  if (!m_buffer->IsOpen() && write)
4132  {
4133  LOG(VB_GENERAL, LOG_ERR, LOC +
4134  QString("RingBuffer '%1' not open...")
4135  .arg(rec->GetPathname()));
4136  SetRingBuffer(nullptr);
4137  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4138  goto err_ret;
4139  }
4140  }
4141 
4142  if (!m_buffer)
4143  {
4144  LOG(VB_GENERAL, LOG_ERR, LOC +
4145  QString("Failed to start recorder! ringBuffer is NULL\n"
4146  "\t\t\t\t Tuning request was %1\n")
4147  .arg(m_lastTuningRequest.toString()));
4148 
4149  if (HasFlags(kFlagLiveTV))
4150  {
4151  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4152  MythEvent me(message);
4153  gCoreContext->dispatch(me);
4154  }
4155  goto err_ret;
4156  }
4157 
4158  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4159  m_channel->Close(); // Needed because of NVR::MJPEGInit()
4160 
4161  LOG(VB_GENERAL, LOG_INFO, LOC + "TuningNewRecorder - CreateRecorder()");
4163 
4164  if (m_recorder)
4165  {
4168  if (m_recorder->IsErrored())
4169  {
4170  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialize recorder!");
4171  delete m_recorder;
4172  m_recorder = nullptr;
4173  }
4174  }
4175 
4176  if (!m_recorder)
4177  {
4178  LOG(VB_GENERAL, LOG_ERR, LOC +
4179  QString("Failed to start recorder!\n"
4180  "\t\t\t\t Tuning request was %1\n")
4181  .arg(m_lastTuningRequest.toString()));
4182 
4183  if (HasFlags(kFlagLiveTV))
4184  {
4185  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4186  MythEvent me(message);
4187  gCoreContext->dispatch(me);
4188  }
4190  goto err_ret;
4191  }
4192 
4193  if (rec)
4194  m_recorder->SetRecording(rec);
4195 
4196  if (GetDTVRecorder() && streamData)
4197  {
4198  const StandardSetting *setting = profile.byName("recordingtype");
4199  if (setting)
4200  streamData->SetRecordingType(setting->getValue());
4201  GetDTVRecorder()->SetStreamData(streamData);
4202  }
4203 
4204  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4205  m_channel->Open(); // Needed because of NVR::MJPEGInit()
4206 
4207  // Setup for framebuffer capture devices..
4208  if (m_channel)
4209  {
4212  }
4213 
4214  if (GetV4LChannel())
4215  {
4217  CloseChannel();
4218  }
4219 
4220  m_recorderThread = new MThread("RecThread", m_recorder);
4222 
4223  // Wait for recorder to start.
4224  m_stateChangeLock.unlock();
4225  while (!m_recorder->IsRecording() && !m_recorder->IsErrored())
4226  std::this_thread::sleep_for(5us);
4227  m_stateChangeLock.lock();
4228 
4229  if (GetV4LChannel())
4231 
4232  SetFlags(kFlagRecorderRunning | kFlagRingBufferReady, __FILE__, __LINE__);
4233 
4234  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4235 
4236  //workaround for failed import recordings, no signal monitor means we never
4237  //go to recording state and the status here seems to override the status
4238  //set in the importrecorder and backend via setrecordingstatus
4239  if (m_genOpt.m_inputType == "IMPORT")
4240  {
4242  if (m_curRecording)
4244  }
4245  return;
4246 
4247  err_ret:
4248  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
4250 
4251  if (rec)
4252  {
4253  // Make sure the scheduler knows...
4255  LOG(VB_RECORD, LOG_INFO, LOC +
4256  QString("TuningNewRecorder -- UPDATE_RECORDING_STATUS: %1")
4258  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
4259  .arg(rec->GetInputID())
4260  .arg(rec->GetChanID())
4262  .arg(RecStatus::Failed)
4264  gCoreContext->dispatch(me);
4265  }
4266 
4267  if (m_tvChain)
4268  delete rec;
4269 }
4270 
4275 {
4276  LOG(VB_RECORD, LOG_INFO, LOC + "Restarting Recorder");
4277 
4278  bool had_dummyrec = false;
4279 
4280  if (m_curRecording)
4281  {
4284  }
4285 
4287  {
4288  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4289  had_dummyrec = true;
4290  }
4291 
4292  SwitchLiveTVRingBuffer(m_channel->GetChannelName(), true, !had_dummyrec);
4293 
4294  if (had_dummyrec)
4295  {
4297  ProgramInfo *progInfo = m_tvChain->GetProgramAt(-1);
4298  RecordingInfo recinfo(*progInfo);
4299  delete progInfo;
4300  recinfo.SetInputID(m_inputId);
4301  m_recorder->SetRecording(&recinfo);
4302  }
4303  m_recorder->Reset();
4304 
4305  // Set file descriptor of channel from recorder for V4L
4306  if (GetV4LChannel())
4308 
4309  // Some recorders unpause on Reset, others do not...
4310  m_recorder->Unpause();
4311 
4313  {
4315  QString msg1 = QString("Recording: %1 %2 %3 %4")
4316  .arg(rcinfo1->GetTitle(), QString::number(rcinfo1->GetChanID()),
4319  ProgramInfo *rcinfo2 = m_tvChain->GetProgramAt(-1);
4320  QString msg2 = QString("Recording: %1 %2 %3 %4")
4321  .arg(rcinfo2->GetTitle(), QString::number(rcinfo2->GetChanID()),
4324  delete rcinfo2;
4325  LOG(VB_RECORD, LOG_INFO, LOC + "Pseudo LiveTV recording starting." +
4326  "\n\t\t\t" + msg1 + "\n\t\t\t" + msg2);
4327 
4330 
4332 
4333  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
4334  }
4335 
4336  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4337 }
4338 
4339 void TVRec::SetFlags(uint f, const QString & file, int line)
4340 {
4341  QMutexLocker lock(&m_stateChangeLock);
4342  m_stateFlags |= f;
4343  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetFlags(%1) -> %2 @ %3:%4")
4344  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4345  WakeEventLoop();
4346 }
4347 
4348 void TVRec::ClearFlags(uint f, const QString & file, int line)
4349 {
4350  QMutexLocker lock(&m_stateChangeLock);
4351  m_stateFlags &= ~f;
4352  LOG(VB_RECORD, LOG_INFO, LOC + QString("ClearFlags(%1) -> %2 @ %3:%4")
4353  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4354  WakeEventLoop();
4355 }
4356 
4358 {
4359  QString msg("");
4360 
4361  // General flags
4362  if (kFlagFrontendReady & f)
4363  msg += "FrontendReady,";
4364  if (kFlagRunMainLoop & f)
4365  msg += "RunMainLoop,";
4366  if (kFlagExitPlayer & f)
4367  msg += "ExitPlayer,";
4368  if (kFlagFinishRecording & f)
4369  msg += "FinishRecording,";
4370  if (kFlagErrored & f)
4371  msg += "Errored,";
4372  if (kFlagCancelNextRecording & f)
4373  msg += "CancelNextRecording,";
4374 
4375  // Tuning flags
4376  if ((kFlagRec & f) == kFlagRec)
4377  msg += "REC,";
4378  else
4379  {
4380  if (kFlagLiveTV & f)
4381  msg += "LiveTV,";
4382  if (kFlagRecording & f)
4383  msg += "Recording,";
4384  }
4385  if ((kFlagNoRec & f) == kFlagNoRec)
4386  msg += "NOREC,";
4387  else
4388  {
4389  if (kFlagEITScan & f)
4390  msg += "EITScan,";
4391  if (kFlagCloseRec & f)
4392  msg += "CloseRec,";
4393  if (kFlagKillRec & f)
4394  msg += "KillRec,";
4395  if (kFlagAntennaAdjust & f)
4396  msg += "AntennaAdjust,";
4397  }
4399  msg += "PENDINGACTIONS,";
4400  else
4401  {
4402  if (kFlagWaitingForRecPause & f)
4403  msg += "WaitingForRecPause,";
4404  if (kFlagWaitingForSignal & f)
4405  msg += "WaitingForSignal,";
4406  if (kFlagNeedToStartRecorder & f)
4407  msg += "NeedToStartRecorder,";
4408  if (kFlagKillRingBuffer & f)
4409  msg += "KillRingBuffer,";
4410  }
4411  if ((kFlagAnyRunning & f) == kFlagAnyRunning)
4412  msg += "ANYRUNNING,";
4413  else
4414  {
4415  if (kFlagSignalMonitorRunning & f)
4416  msg += "SignalMonitorRunning,";
4417  if (kFlagEITScannerRunning & f)
4418  msg += "EITScannerRunning,";
4420  msg += "ANYRECRUNNING,";
4421  else
4422  {
4423  if (kFlagDummyRecorderRunning & f)
4424  msg += "DummyRecorderRunning,";
4425  if (kFlagRecorderRunning & f)
4426  msg += "RecorderRunning,";
4427  }
4428  }
4429  if (kFlagRingBufferReady & f)
4430  msg += "RingBufferReady,";
4431 
4432  if (msg.isEmpty())
4433  msg = QString("0x%1").arg(f,0,16);
4434 
4435  return msg;
4436 }
4437 
4439 {
4440  QMutexLocker lock(&m_nextLiveTVDirLock);
4441 
4442  bool found = !m_nextLiveTVDir.isEmpty();
4443  if (!found && m_triggerLiveTVDir.wait(&m_nextLiveTVDirLock, 500))
4444  {
4445  found = !m_nextLiveTVDir.isEmpty();
4446  }
4447 
4448  return found;
4449 }
4450 
4451 void TVRec::SetNextLiveTVDir(QString dir)
4452 {
4453  QMutexLocker lock(&m_nextLiveTVDirLock);
4454 
4455  m_nextLiveTVDir = std::move(dir);
4456  m_triggerLiveTVDir.wakeAll();
4457 }
4458 
4461  const QString & channum)
4462 {
4463  LOG(VB_RECORD, LOG_INFO, LOC + "GetProgramRingBufferForLiveTV()");
4464  if (!m_channel || !m_tvChain || !pginfo || !Buffer)
4465  return false;
4466 
4467  m_nextLiveTVDirLock.lock();
4468  m_nextLiveTVDir.clear();
4469  m_nextLiveTVDirLock.unlock();
4470 
4471  // Dispatch this early, the response can take a while.
4472  MythEvent me(QString("QUERY_NEXT_LIVETV_DIR %1").arg(m_inputId));
4473  gCoreContext->dispatch(me);
4474 
4475  uint sourceid = m_channel->GetSourceID();
4476  int chanid = ChannelUtil::GetChanID(sourceid, channum);
4477 
4478  if (chanid < 0)
4479  {
4480  // Test setups might have zero channels
4481  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
4482  chanid = 9999;
4483  else
4484  {
4485  LOG(VB_GENERAL, LOG_ERR, LOC +
4486  QString("Channel: \'%1\' was not found in the database.\n"
4487  "\t\tMost likely, the 'starting channel' for this "
4488  "Input Connection is invalid.\n"
4489  "\t\tCould not start livetv.").arg(channum));
4490  return false;
4491  }
4492  }
4493 
4494  auto hoursMax =
4495  gCoreContext->GetDurSetting<std::chrono::hours>("MaxHoursPerLiveTVRecording", 8h);
4496  if (hoursMax <= 0h)
4497  hoursMax = 8h;
4498 
4499  RecordingInfo *prog = nullptr;
4502  else
4503  {
4504  prog = new RecordingInfo(
4505  chanid, MythDate::current(true), true, hoursMax);
4506  }
4507 
4508  prog->SetInputID(m_inputId);
4509 
4510  if (prog->GetRecordingStartTime() == prog->GetRecordingEndTime())
4511  {
4512  LOG(VB_GENERAL, LOG_ERR, LOC + "GetProgramRingBufferForLiveTV()"
4513  "\n\t\t\tProgramInfo is invalid."
4514  "\n" + prog->toString());
4515  prog->SetScheduledEndTime(prog->GetRecordingStartTime().addSecs(3600));
4517 
4518  prog->SetChanID(chanid);
4519  }
4520 
4523 
4524  prog->SetStorageGroup("LiveTV");
4525 
4526  if (WaitForNextLiveTVDir())
4527  {
4528  QMutexLocker lock(&m_nextLiveTVDirLock);
4530  }
4531  else
4532  {
4533  StorageGroup sgroup("LiveTV", gCoreContext->GetHostName());
4534  prog->SetPathname(sgroup.FindNextDirMostFree());
4535  }
4536 
4538  prog->SetRecordingGroup("LiveTV");
4539 
4540  StartedRecording(prog);
4541 
4542  *Buffer = MythMediaBuffer::Create(prog->GetPathname(), true);
4543  if (!(*Buffer) || !(*Buffer)->IsOpen())
4544  {
4545  LOG(VB_GENERAL, LOG_ERR, LOC + QString("RingBuffer '%1' not open...")
4546  .arg(prog->GetPathname()));
4547 
4548  delete *Buffer;
4549  delete prog;
4550 
4551  return false;
4552  }
4553 
4554  *pginfo = prog;
4555  return true;
4556 }
4557 
4558 bool TVRec::CreateLiveTVRingBuffer(const QString & channum)
4559 {
4560  LOG(VB_RECORD, LOG_INFO, LOC + QString("CreateLiveTVRingBuffer(%1)")
4561  .arg(channum));
4562 
4563  RecordingInfo *pginfo = nullptr;
4564  MythMediaBuffer *buffer = nullptr;
4565 
4566  if (!m_channel ||
4567  !m_channel->CheckChannel(channum))
4568  {
4570  return false;
4571  }
4572 
4573  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4574  {
4575  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4577  LOG(VB_GENERAL, LOG_ERR, LOC +
4578  QString("CreateLiveTVRingBuffer(%1) failed").arg(channum));
4579  return false;
4580  }
4581 
4582  SetRingBuffer(buffer);
4583 
4587 
4588  bool discont = (m_tvChain->TotalSize() > 0);
4590  m_channel->GetInputName(), discont);
4591 
4592  if (m_curRecording)
4593  {
4595  delete m_curRecording;
4596  }
4597 
4598  m_curRecording = pginfo;
4600 
4601  return true;
4602 }
4603 
4604 bool TVRec::SwitchLiveTVRingBuffer(const QString & channum,
4605  bool discont, bool set_rec)
4606 {
4607  QString msg;
4608  if (m_curRecording)
4609  {
4610  msg = QString(" curRec(%1) curRec.size(%2)")
4611  .arg(m_curRecording->MakeUniqueKey())
4612  .arg(m_curRecording->GetFilesize());
4613  }
4614  LOG(VB_RECORD, LOG_INFO, LOC +
4615  QString("SwitchLiveTVRingBuffer(discont %1, set_next_rec %2)")
4616  .arg(discont).arg(set_rec) + msg);
4617 
4618  RecordingInfo *pginfo = nullptr;
4619  MythMediaBuffer *buffer = nullptr;
4620 
4621  if (!m_channel ||
4622  !m_channel->CheckChannel(channum))
4623  {
4625  return false;
4626  }
4627 
4628  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4629  {
4631  return false;
4632  }
4633 
4634  QString oldinputtype = m_tvChain->GetInputType(-1);
4635 
4636  pginfo->MarkAsInUse(true, kRecorderInUseID);
4641  m_channel->GetInputName(), discont);
4642 
4643  if (set_rec && m_recorder)
4644  {
4645  m_recorder->SetNextRecording(pginfo, buffer);
4646  if (discont)
4648  delete pginfo;
4649  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4650  }
4651  else if (!set_rec)
4652  {
4653  // dummy recordings are finished before this
4654  // is called and other recordings must be finished..
4655  if (m_curRecording && oldinputtype != "DUMMY")
4656  {
4659  delete m_curRecording;
4660  }
4661  m_curRecording = pginfo;
4662  SetRingBuffer(buffer);
4663  }
4664  else
4665  {
4666  delete buffer;
4667  }
4668 
4669  return true;
4670 }
4671 
4673 {
4674  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer()");
4675 
4676  if (m_switchingBuffer)
4677  {
4678  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4679  "already switching.");
4680  return nullptr;
4681  }
4682 
4683  if (!m_recorder)
4684  {
4685  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4686  "invalid recorder.");
4687  return nullptr;
4688  }
4689 
4690  if (!m_curRecording)
4691  {
4692  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4693  "invalid recording.");
4694  return nullptr;
4695  }
4696 
4697  if (rcinfo.GetChanID() != m_curRecording->GetChanID())
4698  {
4699  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4700  "Not the same channel.");
4701  return nullptr;
4702  }
4703 
4704  auto *ri = new RecordingInfo(rcinfo);
4706 
4707  QString pn = LoadProfile(nullptr, ri, profile);
4708 
4709  if (pn != m_recProfileName)
4710  {
4711  LOG(VB_RECORD, LOG_ERR, LOC +
4712  QString("SwitchRecordingRingBuffer() -> "
4713  "cannot switch profile '%1' to '%2'")
4714  .arg(m_recProfileName, pn));
4715  return nullptr;
4716  }
4717 
4719 
4720  ri->MarkAsInUse(true, kRecorderInUseID);
4721  StartedRecording(ri);
4722 
4723  bool write = m_genOpt.m_inputType != "IMPORT";
4724  MythMediaBuffer *buffer = MythMediaBuffer::Create(ri->GetPathname(), write);
4725  if (!buffer || !buffer->IsOpen())
4726  {
4727  delete buffer;
4728  ri->SetRecordingStatus(RecStatus::Failed);
4729  FinishedRecording(ri, nullptr);
4730  ri->MarkAsInUse(false, kRecorderInUseID);
4731  delete ri;
4732  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer() -> "
4733  "Failed to create new RB.");
4734  return nullptr;
4735  }
4736 
4737  m_recorder->SetNextRecording(ri, buffer);
4738  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4740  m_switchingBuffer = true;
4741  ri->SetRecordingStatus(RecStatus::Recording);
4742  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer -> done");
4743  return ri;
4744 }
4745 
4747 {
4748  QMap<uint,TVRec*>::const_iterator it = s_inputs.constFind(inputid);
4749  if (it == s_inputs.constEnd())
4750  return nullptr;
4751  return *it;
4752 }
4753 
4754 QString TuningRequest::toString(void) const
4755 {
4756  return QString("Program(%1) channel(%2) input(%3) flags(%4)")
4757  .arg((m_program == nullptr) ? QString("NULL") : m_program->toString(),
4759 }
4760 
4761 #ifdef USING_DVB
4762 #include "dvbchannel.h"
4764 {
4765  // Some DVB devices munge the PMT and/or PAT so the CRC check fails.
4766  // We need to tell the stream data class to not check the CRC on
4767  // these devices. This can cause segfaults.
4768  auto * dvb = dynamic_cast<DVBChannel*>(c);
4769  if (dvb != nullptr)
4770  s->SetIgnoreCRC(dvb->HasCRCBug());
4771 }
4772 #else
4774 #endif // USING_DVB
4775 
4776 /* vim: set expandtab tabstop=4 shiftwidth=4: */
GeneralDBOptions
Definition: tv_rec.h:68
TVRec::CreateLiveTVRingBuffer
bool CreateLiveTVRingBuffer(const QString &channum)
Definition: tv_rec.cpp:4558
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:4339
TVRec::GetKeyframeDurations
bool GetKeyframeDurations(int64_t start, int64_t end, frm_pos_map_t &map) const
Definition: tv_rec.cpp:2546
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:2393
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:362
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:465
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:271
TVRec::kFlagErrored
static const uint kFlagErrored
Definition: tv_rec.h:445
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:346
TVRec::m_channel
ChannelBase * m_channel
Definition: tv_rec.h:339
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:476
RecordingInfo::FinishedRecording
void FinishedRecording(bool allowReRecord)
If not a premature stop, adds program to history of recorded programs.
Definition: recordinginfo.cpp:1222
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:324
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:1525
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:380
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:365
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:2102
TVRec::kFlagRecording
static const uint kFlagRecording
final result desired is a timed recording
Definition: tv_rec.h:452
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:402
ChannelBase::Open
virtual bool Open(void)=0
Opens the channel changing hardware for use.
TVRec::m_tuningRequests
TuningQueue m_tuningRequests
Definition: tv_rec.h:396
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:538
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:2404
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:2874
GeneralDBOptions::m_signalTimeout
uint m_signalTimeout
Definition: tv_rec.h:79
TVRec::m_eitTransportTimeout
std::chrono::seconds m_eitTransportTimeout
Definition: tv_rec.h:364
RecordingInfo::GetFilesize
uint64_t GetFilesize(void) const override
Definition: recordinginfo.cpp:1708
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:484
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:429
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:422
RecStatus::Cancelled
@ Cancelled
Definition: recStatus.h:26
TVRec::m_eventThread
MThread * m_eventThread
Event processing thread, runs TVRec::run().
Definition: tv_rec.h:355
TVRec::kFlagRecorderRunning
static const uint kFlagRecorderRunning
Definition: tv_rec.h:479
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:455
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:406
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:2982
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:2967
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:368
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:4459
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:4763
TuningRequest::toString
QString toString(void) const
Definition: tv_rec.cpp:4754
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:409
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:707
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:2487
TVRec::GetDevices
static bool GetDevices(uint inputid, uint &parentid, GeneralDBOptions &gen_opts, DVBDBOptions &dvb_opts, FireWireDBOptions &firewire_opts)
Definition: tv_rec.cpp:1640
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:1237
TVRec::GetInput
QString GetInput(void) const
Returns current input.
Definition: tv_rec.cpp:2957
ChannelUtil::GetMplexID
static uint GetMplexID(uint sourceid, const QString &channum)
Definition: channelutil.cpp:459
TVRec::kFlagDummyRecorderRunning
static const uint kFlagDummyRecorderRunning
Definition: tv_rec.h:478
ChannelBase::GetChannelName
virtual QString GetChannelName(void) const
Definition: channelbase.h:64
TVRec::m_setChannelLock
QMutex m_setChannelLock
Definition: tv_rec.h:383
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:1262
TVRec::GetDTVChannel
DTVChannel * GetDTVChannel(void)
Definition: tv_rec.cpp:1182
TVRec::kFlagPendingActions
static const uint kFlagPendingActions
Definition: tv_rec.h:472
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:2238
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:2620
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:367
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:1727
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:394
dvbchannel.h
TVRec::TuningOnSameMultiplex
bool TuningOnSameMultiplex(TuningRequest &request)
Definition: tv_rec.cpp:3366
TVRec::TeardownRecorder
void TeardownRecorder(uint request_flags)
Tears down the recorder.
Definition: tv_rec.cpp:1108
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:2502
ProgramInfo::GetPathname
QString GetPathname(void) const
Definition: programinfo.h:342
TVRec::kFlagCancelNextRecording
static const uint kFlagCancelNextRecording
Definition: tv_rec.h:446
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:4672
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:334
TVRec::m_recordEndTime
QDateTime m_recordEndTime
Definition: tv_rec.h:410
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:195
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:371
GeneralDBOptions::m_vbiDev
QString m_vbiDev
Definition: tv_rec.h:74
TVRec::m_overRecordSecNrml
std::chrono::seconds m_overRecordSecNrml
Definition: tv_rec.h:366
TVRec::RecorderPaused
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2865
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:416
TRANSITION
#define TRANSITION(ASTATE, BSTATE)
Definition: tv_rec.cpp:991
TVRec::kFlagAnyRecRunning
static const uint kFlagAnyRecRunning
Definition: tv_rec.h:480
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:470
TVRec::kFlagDetect
static const uint kFlagDetect
Definition: tv_rec.h:485
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:412
minor
#define minor(X)
Definition: compat.h:141
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:2846
programinfo.h
TVRec::NotifySchedulerOfRecording
void NotifySchedulerOfRecording(RecordingInfo *rec)
Tell scheduler about the recording.
Definition: tv_rec.cpp:2669
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:677
ProgramInfo::QueryAverageAspectRatio
MarkTypes QueryAverageAspectRatio(void) const
Definition: programinfo.cpp:4405
is_dishnet_eit
static bool is_dishnet_eit(uint inputid)
Definition: tv_rec.cpp:1216
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:463
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:338
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1568
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:2562
MythCoreContext::SendEvent
void SendEvent(const MythEvent &event)
Definition: mythcorecontext.cpp:1554
TVRec::kFlagRunMainLoop
static const uint kFlagRunMainLoop
Definition: tv_rec.h:442
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:754
TVRec::m_pseudoLiveTVRecording
RecordingInfo * m_pseudoLiveTVRecording
Definition: tv_rec.h:419
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:4357
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:1003
pid_cache_t
std::vector< pid_cache_item_t > pid_cache_t
Definition: channelutil.h:43
TVRec::kAutoRunNone
@ kAutoRunNone
Definition: tv_rec.h:327
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:426
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:2192
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:475
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:1956
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:3327
TVRec::kFlagEITScan
static const uint kFlagEITScan
final result desired is an EIT Scan
Definition: tv_rec.h:459
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:2010
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:4438
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:461
RecordingInfo::GetAutoRunJobs
int GetAutoRunJobs(void) const
Returns a bitmap of which jobs are attached to this RecordingInfo.
Definition: recordinginfo.cpp:506
ProgramInfo::GetSourceID
uint GetSourceID(void) const
Definition: programinfo.h: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:420
TVRec::m_triggerEventSleepWait
QWaitCondition m_triggerEventSleepWait
Definition: tv_rec.h:403
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:1168
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:466
TVRec::ChangeState
void ChangeState(TVState nextState)
Puts a state change on the nextState queue.
Definition: tv_rec.cpp:1086
DVBStreamData
Definition: dvbstreamdata.h:32
TVRec::m_desiredNextState
TVState m_desiredNextState
Definition: tv_rec.h:392
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:372
TVRec::run
void run(void) override
Event handling method, contains event loop.
Definition: tv_rec.cpp:1272
RecStatus::Failed
@ Failed
Definition: recStatus.h:23
TVRec::m_triggerEventLoopSignal
bool m_triggerEventLoopSignal
Definition: tv_rec.h:401
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:2203
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:3490
TVRec::m_liveTVStartChannel
QString m_liveTVStartChannel
Definition: tv_rec.h:423
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:341
TVRec::m_rbFileExt
QString m_rbFileExt
Definition: tv_rec.h:430
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:398
TVRec::GetPictureAttribute
int GetPictureAttribute(PictureAttribute attr)
Definition: tv_rec.cpp:2923
TVRec::TuningNewRecorder
void TuningNewRecorder(MPEGStreamData *streamData)
Creates a recorder instance.
Definition: tv_rec.cpp:4088
RecordingInfo::StartedRecording
void StartedRecording(const QString &ext)
Inserts this RecordingInfo into the database as an existing recording.
Definition: recordinginfo.cpp:935
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:2535
TVRec::s_inputsLock
static QReadWriteLock s_inputsLock
Definition: tv_rec.h:433
TVRec::kFlagWaitingForRecPause
static const uint kFlagWaitingForRecPause
Definition: tv_rec.h:469
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:144
TVRec::kFlagLiveTV
static const uint kFlagLiveTV
final result desired is LiveTV recording
Definition: tv_rec.h:450
TVRec::SetNextLiveTVDir
void SetNextLiveTVDir(QString dir)
Definition: tv_rec.cpp:4451
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:2472
TVRec::m_transcodeFirst
bool m_transcodeFirst
Definition: tv_rec.h:360
TVRec::m_signalEventCmdSent
bool m_signalEventCmdSent
Definition: tv_rec.h:344
TVRec::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: tv_rec.cpp:671
TVRec::QueueEITChannelChange
bool QueueEITChannelChange(const QString &name)
Queues up a channel change for the EITScanner.
Definition: tv_rec.cpp:3057
TVRec::m_eitCrawlIdleStart
std::chrono::seconds m_eitCrawlIdleStart
Definition: tv_rec.h:363
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:550
TVRec::m_triggerEventLoopWait
QWaitCondition m_triggerEventLoopWait
Definition: tv_rec.h:400
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:1246
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:1672
mythmediabuffer.h
TVRec::GetRecording
ProgramInfo * GetRecording(void)
Allocates and returns a ProgramInfo for the current recording.
Definition: tv_rec.cpp:239
TVRec::SpawnLiveTV
void SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
Tells TVRec to spawn a "Live TV" recorder.
Definition: tv_rec.cpp:2590
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:3306
TVRec::CancelNextRecording
void CancelNextRecording(bool cancel)
Tells TVRec to cancel the upcoming recording.
Definition: tv_rec.cpp:347
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:404
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:993
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:3083
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:340
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:2518
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:25
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:421
TVRec::CheckForRecGroupChange
void CheckForRecGroupChange(void)
Check if frontend changed the recording group.
Definition: tv_rec.cpp:2635
ChannelBase::SetChannelByString
virtual bool SetChannelByString(const QString &chan)=0
TVRec::m_internalState
TVState m_internalState
Definition: tv_rec.h:391
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:343
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:349
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:3209
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:1187
TVRec::m_genOpt
GeneralDBOptions m_genOpt
Definition: tv_rec.h:376
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:389
TVRec::RingBufferChanged
void RingBufferChanged(MythMediaBuffer *Buffer, RecordingInfo *pginfo, RecordingQuality *recq)
Definition: tv_rec.cpp:3306
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:4274
TVRec::kSignalMonitoringRate
static constexpr std::chrono::milliseconds kSignalMonitoringRate
How many milliseconds the signal monitor should wait between checks.
Definition: tv_rec.h:438
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:1776
ChannelGroup::GetChannelGroupId
static int GetChannelGroupId(const QString &changroupname)
Definition: channelgroup.cpp:253
TVRec::kFlagAnyRunning
static const uint kFlagAnyRunning
Definition: tv_rec.h:481
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:2048
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:377
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:444
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:1303
TVRec::FinishedRecording
void FinishedRecording(RecordingInfo *curRec, RecordingQuality *recq)
If not a premature stop, adds program to history of recorded programs.
Definition: tv_rec.cpp:816
TVRec::m_signalMonitorCheckCnt
uint m_signalMonitorCheckCnt
Definition: tv_rec.h:348
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:327
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:395
TVRec::WakeEventLoop
void WakeEventLoop(void)
Definition: tv_rec.cpp:212
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:225
MPEGStreamData::Reset
virtual void Reset(void)
Definition: mpegstreamdata.h:93
TVRec::m_signalMonitorDeadline
QDateTime m_signalMonitorDeadline
Definition: tv_rec.h:347
CardUtil::GetSourceID
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1850
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:4604
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:744
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:397
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:357
atsctables.h
TVRec::StartedRecording
void StartedRecording(RecordingInfo *curRec)
Inserts a "curRec" into the database.
Definition: tv_rec.cpp:790
TVRec::InitAutoRunJobs
void InitAutoRunJobs(RecordingInfo *rec, AutoRunInitType t, RecordingProfile *recpro, int line)
Definition: tv_rec.cpp:2715
BrowseDirection
BrowseDirection
Used to request ProgramInfo for channel browsing.
Definition: tv.h:37
PendingInfo::m_ask
bool m_ask
Definition: tv_rec.h:139
StandardSetting
Definition: standardsettings.h:29
SendMythSystemRecEvent
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
Definition: mythsystemevent.cpp:332
TVRec::GetFlags
uint GetFlags(void) const
Definition: tv_rec.h:248
MPEGStreamData::AddListeningPID
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
Definition: mpegstreamdata.h:119
CardUtil::GetInputInfo
static bool GetInputInfo(InputInfo &input, std::vector< uint > *groupids=nullptr)
Definition: cardutil.cpp:1631
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:862
recordingprofile.h
TVRec::TVRec
TVRec(int _inputid)
Performs instance initialization not requiring access to database.
Definition: tv_rec.cpp:82
ChannelBase::GetSourceID
virtual uint GetSourceID(void) const
Definition: channelbase.h:71
CardUtil::IsEITCapable
static bool IsEITCapable(const QString &rawtype)
Definition: cardutil.h:165
TVRec::kFlagAntennaAdjust
static const uint kFlagAntennaAdjust
antenna adjusting mode (LiveTV without recording).
Definition: tv_rec.h:454
TVRec::kFlagExitPlayer
static const uint kFlagExitPlayer
Definition: tv_rec.h:443
StateToString
QString StateToString(TVState state)
Returns a human readable QString representing a TVState.
Definition: tv.cpp:11
DTVChannel
Class providing a generic interface to digital tuning hardware.
Definition: dtvchannel.h:33
RecorderBase::GetKeyframePosition
long long GetKeyframePosition(long long desired) const
Returns closest keyframe position before the desired frame.
Definition: recorderbase.cpp:520
SignalMonitor::IsErrored
bool IsErrored(void) const
Definition: signalmonitor.h:86
ProgramInfo::SetRecordingRuleID
void SetRecordingRuleID(uint id)
Definition: programinfo.h:538
TVRec::TuningSignalCheck
MPEGStreamData * TuningSignalCheck(void)
This checks if we have a channel lock.
Definition: tv_rec.cpp:3823
TVRec::~TVRec
~TVRec(void) override
Stops the event and scanning threads and deletes any ChannelBase, RingBuffer, and RecorderBase instan...
Definition: tv_rec.cpp:176
ChannelBase::GetNextChannel
virtual uint GetNextChannel(uint chanid, ChannelChangeDirection direction) const
Definition: channelbase.cpp:192
RecordingProfile
Definition: recordingprofile.h:39
TVRec::m_isPip
bool m_isPip
Definition: tv_rec.h:373
DTVChannel::GetCachedPids
void GetCachedPids(pid_cache_t &pid_cache) const
Returns cached MPEG PIDs for last tuned channel.
Definition: dtvchannel.cpp:96
RecStatus::toString
static QString toString(Type recstatus, uint id)
Converts "recstatus" into a short (unreadable) string.
Definition: recStatus.cpp:39
TVRec::SetVideoFiltersForChannel
bool SetVideoFiltersForChannel(uint sourceid, const QString &channum)
Definition: tv_rec.cpp:2373
DTVChannel::GetSuggestedTuningMode
QString GetSuggestedTuningMode(bool is_live_tv) const
Returns suggested tuning mode: "mpeg", "dvb", or "atsc".
Definition: dtvchannel.cpp:56
PendingInfo::m_recordingStart
QDateTime m_recordingStart
Definition: tv_rec.h:136
TuningRequest::m_channel
QString m_channel
Definition: tv_rec.h:121
TVRec::m_fwOpt
FireWireDBOptions m_fwOpt
Definition: tv_rec.h:378
TVRec::HasFlags
bool HasFlags(uint f) const
Definition: tv_rec.h:289
TVRec::GetDTVRecorder
DTVRecorder * GetDTVRecorder(void)
Definition: tv_rec.cpp:1163
ChannelUtil::GetChanNum
static QString GetChanNum(int chan_id)
Returns the channel-number string of the given channel.
Definition: channelutil.cpp:774
MythDeque::enqueue
void enqueue(T d)
Adds item to the back of the list. O(1).
Definition: mythdeque.h:42
RecordingInfo::GetRecordingRule
RecordingRule * GetRecordingRule(void)
Returns the "record" field, creating it if necessary.
Definition: recordinginfo.cpp:879
ProgramInfo::GetRecordingRuleID
uint GetRecordingRuleID(void) const
Definition: programinfo.h:448
CHANNEL_DIRECTION_SAME
@ CHANNEL_DIRECTION_SAME
Definition: tv.h:33
TVRec::StartRecording
RecStatus::Type StartRecording(ProgramInfo *pginfo)
Tells TVRec to Start recording the program "rcinfo" as soon as possible.
Definition: tv_rec.cpp:397
TVRec::SetChannelInfo
bool SetChannelInfo(uint chanid, uint sourceid, const QString &oldchannum, const QString &callsign, const QString &channum, const QString &channame, const QString &xmltvid)