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