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 "libmyth/programinfo.h"
13 #include "libmyth/remoteutil.h"
14 #include "libmythbase/compat.h"
15 #include "libmythbase/mythconfig.h"
17 #include "libmythbase/mythdate.h"
18 #include "libmythbase/mythdb.h"
20 #include "libmythbase/mythrandom.h"
22 
23 #include "cardutil.h"
24 #include "channelgroup.h"
25 #include "eitscanner.h"
26 #include "io/mythmediabuffer.h"
27 #include "jobqueue.h"
28 #include "livetvchain.h"
29 #include "mpeg/atscstreamdata.h"
30 #include "mpeg/atsctables.h"
31 #include "mpeg/dvbstreamdata.h"
32 #include "mythsystemevent.h"
33 #include "osd.h"
34 #include "previewgeneratorqueue.h"
35 #include "recorders/channelbase.h"
36 #include "recorders/dtvchannel.h"
37 #include "recorders/dtvrecorder.h"
39 #include "recorders/v4lchannel.h"
40 #include "recorders/vboxutils.h"
41 #include "recordingprofile.h"
42 #include "recordingrule.h"
43 #include "tv_rec.h"
44 #include "tvremoteutil.h"
45 
46 #define DEBUG_CHANNEL_PREFIX 0
48 #define LOC QString("TVRec[%1]: ").arg(m_inputId)
49 #define LOC2 QString("TVRec[%1]: ").arg(inputid) // for static functions
50 
51 QReadWriteLock TVRec::s_inputsLock;
52 QMap<uint,TVRec*> TVRec::s_inputs;
53 
54 static bool is_dishnet_eit(uint inputid);
55 static int init_jobs(const RecordingInfo *rec, RecordingProfile &profile,
56  bool on_host, bool transcode_bfr_comm, bool on_line_comm);
58 static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout);
59 
84 TVRec::TVRec(int inputid)
85  // Various threads
86  : m_eventThread(new MThread("TVRecEvent", this)),
87  // Configuration variables from setup routines
88  m_inputId(inputid)
89 {
90  s_inputs[m_inputId] = this;
91 }
92 
93 bool TVRec::CreateChannel(const QString &startchannel,
94  bool enter_power_save_mode)
95 {
96  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("CreateChannel(%1)")
97  .arg(startchannel));
98  // If this recorder is a child and its parent is not in error, we
99  // do not need nor want to set the channel.
100  bool setchan = true;
101  if (m_parentId)
102  {
103  TVRec *parentTV = GetTVRec(m_parentId);
104  if (parentTV && parentTV->GetState() != kState_Error)
105  setchan = false;
106  }
108  this, m_genOpt, m_dvbOpt, m_fwOpt,
109  startchannel, enter_power_save_mode, m_rbFileExt, setchan);
110 
111 #ifdef USING_VBOX
112  if (m_genOpt.m_inputType == "VBOX")
113  {
114  if (!CardUtil::IsVBoxPresent(m_inputId))
115  {
116  // VBOX presence failed, recorder is marked errored
117  LOG(VB_GENERAL, LOG_ERR, LOC +
118  QString("CreateChannel(%1) failed due to VBOX not responding "
119  "to network check on inputid [%2]")
120  .arg(startchannel).arg(m_inputId));
121  m_channel = nullptr;
122  }
123  }
124 #endif
125 
126 #ifdef USING_SATIP
127  if (m_genOpt.m_inputType == "SATIP")
128  {
129  if (!CardUtil::IsSatIPPresent(m_inputId))
130  {
131  // SatIP box presence failed, recorder is marked errored
132  LOG(VB_GENERAL, LOG_ERR, LOC +
133  QString("CreateChannel(%1) failed due to SatIP box not responding "
134  "to network check on inputid [%2]")
135  .arg(startchannel).arg(m_inputId));
136  m_channel = nullptr;
137  }
138  }
139 #endif
140 
141  if (!m_channel)
142  {
143  SetFlags(kFlagErrored, __FILE__, __LINE__);
144  return false;
145  }
146 
147  return true;
148 }
149 
155 bool TVRec::Init(void)
156 {
157  QMutexLocker lock(&m_stateChangeLock);
158 
160  {
161  LOG(VB_CHANNEL, LOG_ERR, QString("[%1] Failed to GetDevices")
162  .arg(m_inputId));
163  return false;
164  }
165 
167 
168  // configure the Channel instance
169  QString startchannel = CardUtil::GetStartChannel(m_inputId);
170  if (startchannel.isEmpty())
171  return false;
172  if (!CreateChannel(startchannel, true))
173  {
174  LOG(VB_CHANNEL, LOG_ERR, QString("[%1] Failed to create channel "
175  "instance for %2")
176  .arg(m_inputId)
177  .arg(startchannel));
178  return false;
179  }
180 
182  gCoreContext->GetBoolSetting("AutoTranscodeBeforeAutoCommflag", false);
183  m_earlyCommFlag = gCoreContext->GetBoolSetting("AutoCommflagWhileRecording", false);
184  m_runJobOnHostOnly = gCoreContext->GetBoolSetting("JobsRunOnRecordHost", false);
185  m_eitTransportTimeout = gCoreContext->GetDurSetting<std::chrono::minutes>("EITTransportTimeout", 5min);
186  if (m_eitTransportTimeout < 6s)
188  m_eitCrawlIdleStart = gCoreContext->GetDurSetting<std::chrono::seconds>("EITCrawIdleStart", 60s);
189  m_audioSampleRateDB = gCoreContext->GetNumSetting("AudioSampleRate");
190  m_overRecordSecNrml = gCoreContext->GetDurSetting<std::chrono::seconds>("RecordOverTime");
191  m_overRecordSecCat = gCoreContext->GetDurSetting<std::chrono::minutes>("CategoryOverTime");
192  m_overRecordCategory= gCoreContext->GetSetting("OverTimeCategory");
193 
194  m_eventThread->start();
195 
197 
198  return true;
199 }
200 
206 {
207  s_inputs.remove(m_inputId);
208 
210  {
211  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
212  m_eventThread->wait();
213  delete m_eventThread;
214  m_eventThread = nullptr;
215  }
216 
217  if (m_channel)
218  {
219  delete m_channel;
220  m_channel = nullptr;
221  }
222 }
223 
225 {
226  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownAll");
227 
229 
230  if (m_scanner)
231  {
232  delete m_scanner;
233  m_scanner = nullptr;
234  }
235 
237 
238  SetRingBuffer(nullptr);
239 }
240 
242 {
243  QMutexLocker locker(&m_triggerEventLoopLock);
245  m_triggerEventLoopWait.wakeAll();
246 }
247 
255 {
256  if (m_changeState)
257  return kState_ChangingState;
258  return m_internalState;
259 }
260 
269 {
270  QMutexLocker lock(&m_stateChangeLock);
271 
272  ProgramInfo *tmppginfo = nullptr;
273 
275  {
276  tmppginfo = new ProgramInfo(*m_curRecording);
278  }
279  else
280  tmppginfo = new ProgramInfo();
281  tmppginfo->SetInputID(m_inputId);
282 
283  return tmppginfo;
284 }
285 
300 void TVRec::RecordPending(const ProgramInfo *rcinfo, std::chrono::seconds secsleft,
301  bool hasLater)
302 {
303  QMutexLocker statelock(&m_stateChangeLock);
304  QMutexLocker pendlock(&m_pendingRecLock);
305 
306  if (secsleft < 0s)
307  {
308  LOG(VB_RECORD, LOG_INFO, LOC + "Pending recording revoked on " +
309  QString("inputid [%1]").arg(rcinfo->GetInputID()));
310 
311  PendingMap::iterator it = m_pendingRecordings.find(rcinfo->GetInputID());
312  if (it != m_pendingRecordings.end())
313  {
314  (*it).m_ask = false;
315  (*it).m_doNotAsk = (*it).m_canceled = true;
316  }
317  return;
318  }
319 
320  LOG(VB_RECORD, LOG_INFO, LOC +
321  QString("RecordPending on inputid [%1]").arg(rcinfo->GetInputID()));
322 
323  PendingInfo pending;
324  pending.m_info = new ProgramInfo(*rcinfo);
325  pending.m_recordingStart = MythDate::current().addSecs(secsleft.count());
326  pending.m_hasLaterShowing = hasLater;
327  pending.m_ask = true;
328  pending.m_doNotAsk = false;
329 
330  m_pendingRecordings[rcinfo->GetInputID()] = pending;
331 
332  // If this isn't a recording for this instance to make, we are done
333  if (rcinfo->GetInputID() != m_inputId)
334  return;
335 
336  // We also need to check our input groups
337  std::vector<unsigned int> inputids = CardUtil::GetConflictingInputs(rcinfo->GetInputID());
338 
339  m_pendingRecordings[rcinfo->GetInputID()].m_possibleConflicts = inputids;
340 
341  pendlock.unlock();
342  statelock.unlock();
343  for (uint inputid : inputids)
344  RemoteRecordPending(inputid, rcinfo, secsleft, hasLater);
345  statelock.relock();
346  pendlock.relock();
347 }
348 
353 {
356  delete old_rec;
357 }
358 
362 QDateTime TVRec::GetRecordEndTime(const ProgramInfo *pi) const
363 {
364  bool spcat = (!m_overRecordCategory.isEmpty() &&
366  std::chrono::seconds secs = (spcat) ? m_overRecordSecCat : m_overRecordSecNrml;
367  return pi->GetRecordingEndTime().addSecs(secs.count());
368 }
369 
375 void TVRec::CancelNextRecording(bool cancel)
376 {
377  QMutexLocker pendlock(&m_pendingRecLock);
378  LOG(VB_RECORD, LOG_INFO, LOC +
379  QString("CancelNextRecording(%1) -- begin").arg(cancel));
380 
381  PendingMap::iterator it = m_pendingRecordings.find(m_inputId);
382  if (it == m_pendingRecordings.end())
383  {
384  LOG(VB_RECORD, LOG_INFO, LOC + QString("CancelNextRecording(%1) -- "
385  "error, unknown recording").arg(cancel));
386  return;
387  }
388 
389  if (cancel)
390  {
391  std::vector<unsigned int> &inputids = (*it).m_possibleConflicts;
392  for (uint inputid : inputids)
393  {
394  LOG(VB_RECORD, LOG_INFO, LOC +
395  QString("CancelNextRecording -- inputid 0x%1")
396  .arg((uint64_t)inputid,0,16));
397 
398  pendlock.unlock();
399  RemoteRecordPending(inputid, (*it).m_info, -1s, false);
400  pendlock.relock();
401  }
402 
403  LOG(VB_RECORD, LOG_INFO, LOC +
404  QString("CancelNextRecording -- inputid [%1]")
405  .arg(m_inputId));
406 
407  RecordPending((*it).m_info, -1s, false);
408  }
409  else
410  {
411  (*it).m_canceled = false;
412  }
413 
414  LOG(VB_RECORD, LOG_INFO, LOC +
415  QString("CancelNextRecording(%1) -- end").arg(cancel));
416 }
417 
426 {
427  RecordingInfo ri1(*pginfo);
430  RecordingInfo *rcinfo = &ri1;
431 
432  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartRecording(%1)")
433  .arg(rcinfo->toString(ProgramInfo::kTitleSubtitle)));
434 
435  QMutexLocker lock(&m_stateChangeLock);
436 
439 
440  // Flush out any pending state changes
442 
443  // We need to do this check early so we don't cancel an overrecord
444  // that we're trying to extend.
448  {
449  int post_roll_seconds = m_curRecording->GetRecordingEndTime()
450  .secsTo(m_recordEndTime);
451 
456 
458  .addSecs(post_roll_seconds);
459 
460  QString msg = QString("updating recording: %1 %2 %3 %4")
461  .arg(m_curRecording->GetTitle(),
462  QString::number(m_curRecording->GetChanID()),
465  LOG(VB_RECORD, LOG_INFO, LOC + msg);
466 
467  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
468 
470  return RecStatus::Recording;
471  }
472 
473  bool cancelNext = false;
474  PendingInfo pendinfo;
475  PendingMap::iterator it;
476 
477  m_pendingRecLock.lock();
478  if ((it = m_pendingRecordings.find(m_inputId)) != m_pendingRecordings.end())
479  {
480  (*it).m_ask = (*it).m_doNotAsk = false;
481  cancelNext = (*it).m_canceled;
482  }
483  m_pendingRecLock.unlock();
484 
485  // Flush out events...
487 
488  // Rescan pending recordings since the event loop may have deleted
489  // a stale entry. If this happens the info pointer will not be valid
490  // since the HandlePendingRecordings loop will have deleted it.
491  m_pendingRecLock.lock();
492  it = m_pendingRecordings.find(m_inputId);
493  bool has_pending = (it != m_pendingRecordings.end());
494  if (has_pending)
495  pendinfo = *it;
496  m_pendingRecLock.unlock();
497 
498  // If the needed input is in a shared input group, and we are
499  // not canceling the recording anyway, check other recorders
500  if (!cancelNext && has_pending && !pendinfo.m_possibleConflicts.empty())
501  {
502  LOG(VB_RECORD, LOG_INFO, LOC +
503  "Checking input group recorders - begin");
504  std::vector<unsigned int> &inputids = pendinfo.m_possibleConflicts;
505 
506  uint mplexid = 0;
507  uint chanid = 0;
508  uint sourceid = 0;
509  std::vector<unsigned int> inputids2;
510  std::vector<TVState> states;
511 
512  // Stop remote recordings if needed
513  for (uint inputid : inputids)
514  {
515  InputInfo busy_input;
516  bool is_busy = RemoteIsBusy(inputid, busy_input);
517 
518  if (is_busy && !sourceid)
519  {
520  mplexid = pendinfo.m_info->QueryMplexID();
521  chanid = pendinfo.m_info->GetChanID();
522  sourceid = pendinfo.m_info->GetSourceID();
523  }
524 
525  if (is_busy &&
526  ((sourceid != busy_input.m_sourceId) ||
527  (mplexid != busy_input.m_mplexId) ||
528  ((mplexid == 0 || mplexid == 32767) &&
529  chanid != busy_input.m_chanId)))
530  {
531  states.push_back((TVState) RemoteGetState(inputid));
532  inputids2.push_back(inputid);
533  }
534  }
535 
536  bool ok = true;
537  for (uint i = 0; (i < inputids2.size()) && ok; i++)
538  {
539  LOG(VB_RECORD, LOG_INFO, LOC +
540  QString("Attempting to stop input [%1] in state %2")
541  .arg(inputids2[i]).arg(StateToString(states[i])));
542 
543  bool success = RemoteStopRecording(inputids2[i]);
544  if (success)
545  {
546  uint state = RemoteGetState(inputids2[i]);
547  LOG(VB_GENERAL, LOG_INFO, LOC + QString("a [%1]: %2")
548  .arg(inputids2[i]).arg(StateToString((TVState)state)));
549  success = (kState_None == state);
550  }
551 
552  // If we managed to stop LiveTV recording, restart playback..
553  if (success && states[i] == kState_WatchingLiveTV)
554  {
555  QString message = QString("QUIT_LIVETV %1").arg(inputids2[i]);
556  MythEvent me(message);
557  gCoreContext->dispatch(me);
558  }
559 
560  LOG(VB_RECORD, LOG_INFO, LOC +
561  QString("Stopping recording on [%1], %2") .arg(inputids2[i])
562  .arg(success ? "succeeded" : "failed"));
563 
564  ok &= success;
565  }
566 
567  // If we failed to stop the remote recordings, don't record
568  if (!ok)
569  {
570  CancelNextRecording(true);
571  cancelNext = true;
572  }
573 
574  inputids.clear();
575 
576  LOG(VB_RECORD, LOG_INFO, LOC + "Checking input group recorders - done");
577  }
578 
579  bool did_switch = false;
580  if (!cancelNext && (GetState() == kState_RecordingOnly))
581  {
583  did_switch = (nullptr != ri2);
584  if (did_switch)
585  {
586  // Make sure scheduler is allowed to end this recording
587  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
588 
590  }
591  else
592  {
593  // If in post-roll, end recording
594  m_stateChangeLock.unlock();
595  StopRecording();
596  m_stateChangeLock.lock();
597  }
598  }
599 
600  if (!cancelNext && (GetState() == kState_None))
601  {
602  if (m_tvChain)
603  {
604  QString message = QString("LIVETV_EXITED");
605  MythEvent me(message, m_tvChain->GetID());
606  gCoreContext->dispatch(me);
607  m_tvChain->DecrRef();
608  m_tvChain = nullptr;
609  }
610 
612 
613  // Tell event loop to begin recording.
614  m_curRecording = new RecordingInfo(*rcinfo);
619 
620  // Make sure scheduler is allowed to end this recording
621  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
622 
625  else
626  LOG(VB_RECORD, LOG_WARNING, LOC + "Still failing.");
628  }
629  else if (!cancelNext && (GetState() == kState_WatchingLiveTV))
630  {
634 
635  // We want the frontend to change channel for recording
636  // and disable the UI for channel change, PiP, etc.
637 
638  QString message = QString("LIVETV_WATCH %1 1").arg(m_inputId);
639  QStringList prog;
640  rcinfo->ToStringList(prog);
641  MythEvent me(message, prog);
642  gCoreContext->dispatch(me);
643  }
644  else if (!did_switch)
645  {
646  QString msg = QString("Wanted to record: %1 %2 %3 %4\n\t\t\t")
647  .arg(rcinfo->GetTitle(),
648  QString::number(rcinfo->GetChanID()),
651 
652  if (cancelNext)
653  {
654  msg += "But a user has canceled this recording";
656  }
657  else
658  {
659  msg += QString("But the current state is: %1")
662  }
663 
665  {
666  msg += QString("\n\t\t\tCurrently recording: %1 %2 %3 %4")
667  .arg(m_curRecording->GetTitle(),
668  QString::number(m_curRecording->GetChanID()),
671  }
672 
673  LOG(VB_GENERAL, LOG_INFO, LOC + msg);
674  }
675 
676  for (const auto & pend : qAsConst(m_pendingRecordings))
677  delete pend.m_info;
678  m_pendingRecordings.clear();
679 
680  if (!did_switch)
681  {
683 
684  QMutexLocker locker(&m_pendingRecLock);
685  if ((m_curRecording) &&
690  {
691  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
692  }
693  return m_recStatus;
694  }
695 
696  return GetRecordingStatus();
697 }
698 
700 {
701  QMutexLocker pendlock(&m_pendingRecLock);
702  return m_recStatus;
703 }
704 
706  RecStatus::Type new_status, int line, bool have_lock)
707 {
708  RecStatus::Type old_status { RecStatus::Unknown };
709  if (have_lock)
710  {
711  old_status = m_recStatus;
712  m_recStatus = new_status;
713  }
714  else
715  {
716  m_pendingRecLock.lock();
717  old_status = m_recStatus;
718  m_recStatus = new_status;
719  m_pendingRecLock.unlock();
720  }
721 
722  LOG(VB_RECORD, LOG_INFO, LOC +
723  QString("SetRecordingStatus(%1->%2) on line %3")
724  .arg(RecStatus::toString(old_status, kSingleRecord),
725  RecStatus::toString(new_status, kSingleRecord),
726  QString::number(line)));
727 }
728 
735 void TVRec::StopRecording(bool killFile)
736 {
737  if (StateIsRecording(GetState()))
738  {
739  QMutexLocker lock(&m_stateChangeLock);
740  if (killFile)
741  SetFlags(kFlagKillRec, __FILE__, __LINE__);
742  else if (m_curRecording)
743  {
744  QDateTime now = MythDate::current(true);
745  if (now < m_curRecording->GetDesiredEndTime())
747  }
749  // wait for state change to take effect
751  ClearFlags(kFlagCancelNextRecording|kFlagKillRec, __FILE__, __LINE__);
752 
754  }
755 }
756 
763 {
764  return (state == kState_RecordingOnly ||
765  state == kState_WatchingLiveTV);
766 }
767 
773 {
774  return (state == kState_WatchingPreRecorded);
775 }
776 
783 {
784  if (StateIsRecording(state))
785  return kState_None;
786 
787  LOG(VB_GENERAL, LOG_ERR, LOC +
788  QString("Unknown state in RemoveRecording: %1")
789  .arg(StateToString(state)));
790  return kState_Error;
791 }
792 
799 {
800  if (StateIsPlaying(state))
801  {
802  if (state == kState_WatchingPreRecorded)
803  return kState_None;
804  return kState_RecordingOnly;
805  }
806 
807  QString msg = "Unknown state in RemovePlaying: %1";
808  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(StateToString(state)));
809 
810  return kState_Error;
811 }
812 
819 {
820  if (!curRec)
821  return;
822 
823  curRec->StartedRecording(m_rbFileExt);
824  LOG(VB_RECORD, LOG_INFO, LOC + QString("StartedRecording(%1) fn(%2)")
825  .arg(curRec->MakeUniqueKey(), curRec->GetPathname()));
826 
827  if (curRec->IsCommercialFree())
829 
830  AutoRunInitType t = (curRec->GetRecordingGroup() == "LiveTV") ?
832  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
833 
834  SendMythSystemRecEvent("REC_STARTED", curRec);
835 }
836 
845 {
846  if (!curRec)
847  return;
848 
849  // Make sure the recording group is up to date
850  const QString recgrp = curRec->QueryRecordingGroup();
851  curRec->SetRecordingGroup(recgrp);
852 
853  bool is_good = true;
854  if (recq)
855  {
856  LOG((recq->IsDamaged()) ? VB_GENERAL : VB_RECORD, LOG_INFO,
857  LOC + QString("FinishedRecording(%1) %2 recq:\n%3")
858  .arg(curRec->MakeUniqueKey(),
859  (recq->IsDamaged()) ? "damaged" : "good",
860  recq->toStringXML()));
861  is_good = !recq->IsDamaged();
862  delete recq;
863  recq = nullptr;
864  }
865 
866  RecStatus::Type ors = curRec->GetRecordingStatus();
867  // Set the final recording status
868  if (curRec->GetRecordingStatus() == RecStatus::Recording)
870  else if (curRec->GetRecordingStatus() != RecStatus::Recorded)
872  curRec->SetRecordingEndTime(MythDate::current(true));
873  is_good &= (curRec->GetRecordingStatus() == RecStatus::Recorded);
874 
875  // Figure out if this was already done for this recording
876  bool was_finished = false;
877  static QMutex s_finRecLock;
878  static QHash<QString,QDateTime> s_finRecMap;
879  {
880  QMutexLocker locker(&s_finRecLock);
881  QDateTime now = MythDate::current();
882  QDateTime expired = now.addSecs(-5LL * 60);
883  QHash<QString,QDateTime>::iterator it = s_finRecMap.begin();
884  while (it != s_finRecMap.end())
885  {
886  if ((*it) < expired)
887  it = s_finRecMap.erase(it);
888  else
889  ++it;
890  }
891  QString key = curRec->MakeUniqueKey();
892  it = s_finRecMap.find(key);
893  if (it != s_finRecMap.end())
894  was_finished = true;
895  else
896  s_finRecMap[key] = now;
897  }
898 
899  // Print something informative to the log
900  LOG(VB_RECORD, LOG_INFO, LOC +
901  QString("FinishedRecording(%1) %2 quality"
902  "\n\t\t\ttitle: %3\n\t\t\t"
903  "in recgroup: %4 status: %5:%6 %7 %8")
904  .arg(curRec->MakeUniqueKey(),
905  is_good ? "Good" : "Bad",
906  curRec->GetTitle(),
907  recgrp,
910  HasFlags(kFlagDummyRecorderRunning)?"is_dummy":"not_dummy",
911  was_finished?"already_finished":"finished_now"));
912 
913  // This has already been called on this recording..
914  if (was_finished)
915  return;
916 
917  // Notify the frontend watching live tv that this file is final
918  if (m_tvChain)
919  m_tvChain->FinishedRecording(curRec);
920 
921  // if this is a dummy recorder, do no more..
923  {
924  curRec->FinishedRecording(true); // so end time is updated
925  SendMythSystemRecEvent("REC_FINISHED", curRec);
926  return;
927  }
928 
929  // Get the width and set the videoprops
930  MarkTypes aspectRatio = curRec->QueryAverageAspectRatio();
931  uint avg_height = curRec->QueryAverageHeight();
932  bool progressive = curRec->QueryAverageScanProgressive();
933  curRec->SaveVideoProperties
934  (VID_4K | VID_1080 | VID_720 | VID_DAMAGED |
935  VID_WIDESCREEN | VID_PROGRESSIVE,
936  ((avg_height > 2000) ? VID_4K :
937  ((avg_height > 1000) ? VID_1080 :
938  ((avg_height > 700) ? VID_720 : 0))) |
939  (progressive ? VID_PROGRESSIVE : 0) |
940  ((is_good) ? 0 : VID_DAMAGED) |
941  (((aspectRatio == MARK_ASPECT_16_9) ||
942  (aspectRatio == MARK_ASPECT_2_21_1)) ? VID_WIDESCREEN : 0));
943 
944  // Make sure really short recordings have positive run time.
945  if (curRec->GetRecordingEndTime() <= curRec->GetRecordingStartTime())
946  {
947  curRec->SetRecordingEndTime(
948  curRec->GetRecordingStartTime().addSecs(60));
949  }
950 
951  // HACK Temporary hack, ensure we've loaded the recording file info, do it now
952  // so that it contains the final filesize information
953  if (!curRec->GetRecordingFile())
954  curRec->LoadRecordingFile();
955 
956  // Generate a preview
957  uint64_t fsize = curRec->GetFilesize();
958  if (curRec->IsLocal() && (fsize >= 1000) &&
960  {
962  }
963 
964  // store recording in recorded table
965  curRec->FinishedRecording(!is_good || (recgrp == "LiveTV"));
966 
967  // send out UPDATE_RECORDING_STATUS message
968  if (recgrp != "LiveTV")
969  {
970  LOG(VB_RECORD, LOG_INFO, LOC +
971  QString("FinishedRecording -- UPDATE_RECORDING_STATUS: %1")
972  .arg(RecStatus::toString(is_good ? curRec->GetRecordingStatus()
974  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
975  .arg(curRec->GetInputID())
976  .arg(curRec->GetChanID())
978  .arg(is_good ? curRec->GetRecordingStatus() : RecStatus::Failed)
979  .arg(curRec->GetRecordingEndTime(MythDate::ISODate)));
980  gCoreContext->dispatch(me);
981  }
982 
983  // send out REC_FINISHED message
984  SendMythSystemRecEvent("REC_FINISHED", curRec);
985 
986  // send out DONE_RECORDING message
987  auto secsSince = MythDate::secsInPast(curRec->GetRecordingStartTime());
988  QString message = QString("DONE_RECORDING %1 %2 %3")
989  .arg(m_inputId).arg(secsSince.count()).arg(GetFramesWritten());
990  MythEvent me(message);
991  gCoreContext->dispatch(me);
992 
993  // Handle JobQueue
994  QHash<QString,int>::iterator autoJob =
995  m_autoRunJobs.find(curRec->MakeUniqueKey());
996  if (autoJob == m_autoRunJobs.end())
997  {
998  LOG(VB_GENERAL, LOG_INFO,
999  "autoRunJobs not initialized until FinishedRecording()");
1000  AutoRunInitType t =
1001  (recgrp == "LiveTV") ? kAutoRunNone : kAutoRunProfile;
1002  InitAutoRunJobs(curRec, t, nullptr, __LINE__);
1003  autoJob = m_autoRunJobs.find(curRec->MakeUniqueKey());
1004  }
1005  LOG(VB_JOBQUEUE, LOG_INFO, QString("AutoRunJobs 0x%1").arg(*autoJob,0,16));
1006  if ((recgrp == "LiveTV") || (fsize < 1000) ||
1007  (curRec->GetRecordingStatus() != RecStatus::Recorded) ||
1008  (curRec->GetRecordingStartTime().secsTo(
1009  MythDate::current()) < 120))
1010  {
1013  }
1014  if (*autoJob != JOB_NONE)
1015  JobQueue::QueueRecordingJobs(*curRec, *autoJob);
1016  m_autoRunJobs.erase(autoJob);
1017 }
1018 
1019 // NOLINTBEGIN(cppcoreguidelines-macro-usage)
1020 #define TRANSITION(ASTATE,BSTATE) \
1021  ((m_internalState == (ASTATE)) && (m_desiredNextState == (BSTATE)))
1022 #define SET_NEXT() do { nextState = m_desiredNextState; changed = true; } while(false)
1023 #define SET_LAST() do { nextState = m_internalState; changed = true; } while(false)
1024 // NOLINTEND(cppcoreguidelines-macro-usage)
1025 
1034 {
1035  TVState nextState = m_internalState;
1036 
1037  bool changed = false;
1038 
1039  QString transMsg = QString(" %1 to %2")
1040  .arg(StateToString(nextState), StateToString(m_desiredNextState));
1041 
1043  {
1044  LOG(VB_GENERAL, LOG_ERR, LOC +
1045  "HandleStateChange(): Null transition" + transMsg);
1046  m_changeState = false;
1047  return;
1048  }
1049 
1050  // Make sure EIT scan is stopped before any tuning,
1051  // to avoid race condition with it's tuning requests.
1053  {
1054  LOG(VB_EIT, LOG_INFO, LOC + QString("Stop EIT scan on input %1").arg(GetInputId()));
1055 
1057  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1059  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
1060  }
1061 
1062  // Handle different state transitions
1064  {
1066  SET_NEXT();
1067  }
1069  {
1071  SET_NEXT();
1072  }
1074  {
1075  SetPseudoLiveTVRecording(nullptr);
1076 
1077  SET_NEXT();
1078  }
1080  {
1081  SetPseudoLiveTVRecording(nullptr);
1083  SET_NEXT();
1084  }
1086  {
1089  (GetFlags()&kFlagKillRec)));
1090  SET_NEXT();
1091  }
1092 
1093  QString msg = (changed) ? "Changing from" : "Unknown state transition:";
1094  LOG(VB_GENERAL, LOG_INFO, LOC + msg + transMsg);
1095 
1096  // update internal state variable
1097  m_internalState = nextState;
1098  m_changeState = false;
1099 
1102  {
1104  m_eitScanStartTime = m_eitScanStartTime.addSecs(secs.count());
1105  }
1106  else
1107  {
1108  m_eitScanStartTime = m_eitScanStartTime.addYears(1);
1109  }
1110 }
1111 #undef TRANSITION
1112 #undef SET_NEXT
1113 #undef SET_LAST
1114 
1119 {
1120  QMutexLocker lock(&m_stateChangeLock);
1121  m_desiredNextState = nextState;
1122  m_changeState = true;
1123  WakeEventLoop();
1124 }
1125 
1140 void TVRec::TeardownRecorder(uint request_flags)
1141 {
1142  LOG(VB_RECORD, LOG_INFO, LOC + QString("TeardownRecorder(%1)")
1143  .arg((request_flags & kFlagKillRec) ? "kFlagKillRec" : ""));
1144 
1145  m_pauseNotify = false;
1146  m_isPip = false;
1147 
1149  {
1152  delete m_recorderThread;
1153  m_recorderThread = nullptr;
1154  }
1156  __FILE__, __LINE__);
1157 
1158  RecordingQuality *recq = nullptr;
1159  if (m_recorder)
1160  {
1161  if (GetV4LChannel())
1162  m_channel->SetFd(-1);
1163 
1165 
1166  QMutexLocker locker(&m_stateChangeLock);
1167  delete m_recorder;
1168  m_recorder = nullptr;
1169  }
1170 
1171  if (m_buffer)
1172  {
1173  LOG(VB_FILE, LOG_INFO, LOC + "calling StopReads()");
1174  m_buffer->StopReads();
1175  }
1176 
1177  if (m_curRecording)
1178  {
1179  if (!!(request_flags & kFlagKillRec))
1181 
1183 
1185  delete m_curRecording;
1186  m_curRecording = nullptr;
1187  }
1188 
1189  m_pauseNotify = true;
1190 
1191  if (GetDTVChannel())
1193 }
1194 
1196 {
1197  return dynamic_cast<DTVRecorder*>(m_recorder);
1198 }
1199 
1201 {
1202  if (m_channel &&
1203  ((m_genOpt.m_inputType == "DVB" && m_dvbOpt.m_dvbOnDemand) ||
1204  m_genOpt.m_inputType == "FREEBOX" ||
1205  m_genOpt.m_inputType == "VBOX" ||
1206  m_genOpt.m_inputType == "HDHOMERUN" ||
1207  m_genOpt.m_inputType == "EXTERNAL" ||
1209  {
1210  m_channel->Close();
1211  }
1212 }
1213 
1215 {
1216  return dynamic_cast<DTVChannel*>(m_channel);
1217 }
1218 
1220 {
1221 #ifdef USING_V4L2
1222  return dynamic_cast<V4LChannel*>(m_channel);
1223 #else
1224  return nullptr;
1225 #endif // USING_V4L2
1226 }
1227 
1228 static bool get_use_eit(uint inputid)
1229 {
1230  MSqlQuery query(MSqlQuery::InitCon());
1231  query.prepare(
1232  "SELECT SUM(useeit) "
1233  "FROM videosource, capturecard "
1234  "WHERE videosource.sourceid = capturecard.sourceid AND"
1235  " capturecard.cardid = :INPUTID");
1236  query.bindValue(":INPUTID", inputid);
1237 
1238  if (!query.exec() || !query.isActive())
1239  {
1240  MythDB::DBError("get_use_eit", query);
1241  return false;
1242  }
1243  if (query.next())
1244  return query.value(0).toBool();
1245  return false;
1246 }
1247 
1248 static bool is_dishnet_eit(uint inputid)
1249 {
1250  MSqlQuery query(MSqlQuery::InitCon());
1251  query.prepare(
1252  "SELECT SUM(dishnet_eit) "
1253  "FROM videosource, capturecard "
1254  "WHERE videosource.sourceid = capturecard.sourceid AND"
1255  " capturecard.cardid = :INPUTID");
1256  query.bindValue(":INPUTID", inputid);
1257 
1258  if (!query.exec() || !query.isActive())
1259  {
1260  MythDB::DBError("is_dishnet_eit", query);
1261  return false;
1262  }
1263  if (query.next())
1264  return query.value(0).toBool();
1265  return false;
1266 }
1267 
1268 // Highest capturecard instance number including multirec instances
1269 static int get_highest_input(void)
1270 {
1271  MSqlQuery query(MSqlQuery::InitCon());
1272 
1273  QString str =
1274  "SELECT MAX(cardid) "
1275  "FROM capturecard ";
1276 
1277  query.prepare(str);
1278 
1279  if (!query.exec() || !query.isActive())
1280  {
1281  MythDB::DBError("highest_input", query);
1282  return -1;
1283  }
1284  if (query.next())
1285  return query.value(0).toInt();
1286  return -1;
1287 }
1288 
1289 static std::chrono::seconds eit_start_rand(uint inputId, std::chrono::seconds eitTransportTimeout)
1290 {
1291  // Randomize start time a bit
1292  auto timeout = std::chrono::seconds(MythRandom(0, eitTransportTimeout.count() / 3));
1293 
1294  // Use the highest input number and the current input number
1295  // to distribute the scan start evenly over eitTransportTimeout
1296  int highest_input = get_highest_input();
1297  if (highest_input > 0)
1298  timeout += eitTransportTimeout * inputId / highest_input;
1299 
1300  return timeout;
1301 }
1302 
1304 void TVRec::run(void)
1305 {
1306  QMutexLocker lock(&m_stateChangeLock);
1307  SetFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1308  ClearFlags(kFlagExitPlayer | kFlagFinishRecording, __FILE__, __LINE__);
1309 
1311 
1312  // Check whether we should use the EITScanner in this TVRec instance
1313  if (CardUtil::IsEITCapable(m_genOpt.m_inputType) && // Card type capable of receiving EIT?
1314  (!GetDTVChannel() || GetDTVChannel()->IsMaster()) && // Card is master and not a multirec instance
1315  (m_dvbOpt.m_dvbEitScan || get_use_eit(m_inputId))) // EIT is selected for card OR EIT is selected for video source
1316  {
1319  m_eitScanStartTime = m_eitScanStartTime.addSecs(secs.count());
1320  }
1321  else
1322  {
1323  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1324  }
1325 
1326  while (HasFlags(kFlagRunMainLoop))
1327  {
1328  // If there is a state change queued up, do it...
1329  if (m_changeState)
1330  {
1333  __FILE__, __LINE__);
1334  }
1335 
1336  // Quick exit on fatal errors.
1337  if (IsErrored())
1338  {
1339  LOG(VB_GENERAL, LOG_ERR, LOC +
1340  "RunTV encountered fatal error, exiting event thread.");
1341  ClearFlags(kFlagRunMainLoop, __FILE__, __LINE__);
1342  TeardownAll();
1343  return;
1344  }
1345 
1346  // Handle any tuning events.. Blindly grabbing the lock here
1347  // can sometimes cause a deadlock with Init() while it waits
1348  // to make sure this thread starts. Until a better solution
1349  // is found, don't run HandleTuning unless we can safely get
1350  // the lock.
1351  if (s_inputsLock.tryLockForRead())
1352  {
1353  HandleTuning();
1354  s_inputsLock.unlock();
1355  }
1356 
1357  // Tell frontends about pending recordings
1359 
1360  // If we are recording a program, check if the recording is
1361  // over or someone has asked us to finish the recording.
1362  // Add an extra 60 seconds to the recording end time if we
1363  // might want a back to back recording.
1364  QDateTime recEnd = (!m_pendingRecordings.empty()) ?
1365  m_recordEndTime.addSecs(60) : m_recordEndTime;
1366  if ((GetState() == kState_RecordingOnly) &&
1367  (MythDate::current() > recEnd ||
1369  {
1371  ClearFlags(kFlagFinishRecording, __FILE__, __LINE__);
1372  }
1373 
1374  if (m_curRecording)
1375  {
1377 
1378  if (m_recorder)
1379  {
1381 
1382  // Check for recorder errors
1383  if (m_recorder->IsErrored())
1384  {
1386 
1388  {
1389  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
1390  MythEvent me(message);
1391  gCoreContext->dispatch(me);
1392  }
1393  else
1395  }
1396  }
1397  }
1398 
1399  // Check for the end of the current program..
1401  {
1402  QDateTime now = MythDate::current();
1403  bool has_finish = HasFlags(kFlagFinishRecording);
1404  bool has_rec = m_pseudoLiveTVRecording;
1405  bool enable_ui = true;
1406 
1407  m_pendingRecLock.lock();
1408  bool rec_soon =
1410  m_pendingRecLock.unlock();
1411 
1412  if (has_rec && (has_finish || (now > m_recordEndTime)))
1413  {
1414  SetPseudoLiveTVRecording(nullptr);
1415  }
1416  else if (!has_rec && !rec_soon && m_curRecording &&
1417  (now >= m_curRecording->GetScheduledEndTime()))
1418  {
1419  if (!m_switchingBuffer)
1420  {
1421  LOG(VB_RECORD, LOG_INFO, LOC +
1422  "Switching Buffer (" +
1423  QString("!has_rec(%1) && ").arg(has_rec) +
1424  QString("!rec_soon(%1) && (").arg(rec_soon) +
1425  MythDate::toString(now, MythDate::ISODate) + " >= " +
1427  QString("(%1) ))")
1428  .arg(now >= m_curRecording->GetScheduledEndTime()));
1429 
1430  m_switchingBuffer = true;
1431 
1433  false, true);
1434  }
1435  else
1436  {
1437  LOG(VB_RECORD, LOG_INFO, "Waiting for ringbuffer switch");
1438  }
1439  }
1440  else
1441  enable_ui = false;
1442 
1443  if (enable_ui)
1444  {
1445  LOG(VB_RECORD, LOG_INFO, LOC + "Enabling Full LiveTV UI.");
1446  QString message = QString("LIVETV_WATCH %1 0").arg(m_inputId);
1447  MythEvent me(message);
1448  gCoreContext->dispatch(me);
1449  }
1450  }
1451 
1452  // Check for ExitPlayer flag, and if set change to a non-watching
1453  // state (either kState_RecordingOnly or kState_None).
1455  {
1458  else if (StateIsPlaying(m_internalState))
1460  ClearFlags(kFlagExitPlayer, __FILE__, __LINE__);
1461  }
1462 
1463  // Start active EIT scan
1464  if (m_scanner && m_channel &&
1466  {
1467  if (!m_dvbOpt.m_dvbEitScan)
1468  {
1469  LOG(VB_EIT, LOG_INFO, LOC +
1470  "EIT scanning disabled for this input.");
1471  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1472  }
1473  else if (!get_use_eit(GetInputId()))
1474  {
1475  LOG(VB_EIT, LOG_INFO, LOC +
1476  "EIT scanning disabled for all channels on this input.");
1477  m_eitScanStartTime = m_eitScanStartTime.addYears(10);
1478  }
1479  else
1480  {
1481  // Check if another card in the same input group is
1482  // busy. This could be either virtual DVB-devices or
1483  // a second tuner on a single card
1484  s_inputsLock.lockForRead();
1485  bool allow_eit = true;
1486  std::vector<unsigned int> inputids =
1488  InputInfo busy_input;
1489  for (uint i = 0; i < inputids.size() && allow_eit; ++i)
1490  allow_eit = !RemoteIsBusy(inputids[i], busy_input);
1491  if (allow_eit)
1492  {
1494  SetFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
1496  QDateTime::currentDateTime().addYears(1);
1497  }
1498  else
1499  {
1500  LOG(VB_EIT, LOG_INFO, LOC + QString(
1501  "Postponing EIT scan on input [%1] "
1502  "because input %2 is busy")
1503  .arg(m_inputId).arg(busy_input.m_inputId));
1504  m_eitScanStartTime = m_eitScanStartTime.addSecs(300);
1505  }
1506  s_inputsLock.unlock();
1507  }
1508  }
1509 
1510  // We should be no more than a few thousand milliseconds,
1511  // as the end recording code does not have a trigger...
1512  // NOTE: If you change anything here, make sure that
1513  // WaitforEventThreadSleep() will still work...
1514  if (m_tuningRequests.empty() && !m_changeState)
1515  {
1516  lock.unlock(); // stateChangeLock
1517 
1518  {
1519  QMutexLocker locker(&m_triggerEventSleepLock);
1521  m_triggerEventSleepWait.wakeAll();
1522  }
1523 
1524  sched_yield();
1525 
1526  {
1527  QMutexLocker locker(&m_triggerEventLoopLock);
1528  // We check triggerEventLoopSignal because it is possible
1529  // that WakeEventLoop() was called since we
1530  // unlocked the stateChangeLock
1532  {
1534  &m_triggerEventLoopLock, 1000 /* ms */);
1535  }
1536  m_triggerEventLoopSignal = false;
1537  }
1538 
1539  lock.relock(); // stateChangeLock
1540  }
1541  }
1542 
1543  if (GetState() != kState_None)
1544  {
1547  }
1548 
1549  TeardownAll();
1550 }
1551 
1557 bool TVRec::WaitForEventThreadSleep(bool wake, std::chrono::milliseconds time)
1558 {
1559  bool ok = false;
1560  MythTimer t;
1561  t.start();
1562 
1563  while (!ok && (t.elapsed() < time))
1564  {
1565  MythTimer t2;
1566  t2.start();
1567 
1568  if (wake)
1569  WakeEventLoop();
1570 
1571  m_stateChangeLock.unlock();
1572 
1573  sched_yield();
1574 
1575  {
1576  QMutexLocker locker(&m_triggerEventSleepLock);
1579  m_triggerEventSleepSignal = false;
1580  }
1581 
1582  m_stateChangeLock.lock();
1583 
1584  // verify that we were triggered.
1585  ok = (m_tuningRequests.empty() && !m_changeState);
1586 
1587  std::chrono::milliseconds te = t2.elapsed();
1588  if (!ok && te < 10ms)
1589  std::this_thread::sleep_for(10ms - te);
1590  }
1591  return ok;
1592 }
1593 
1595 {
1596  QMutexLocker pendlock(&m_pendingRecLock);
1597 
1598  for (auto it = m_pendingRecordings.begin(); it != m_pendingRecordings.end();)
1599  {
1600  if (MythDate::current() > (*it).m_recordingStart.addSecs(30))
1601  {
1602  LOG(VB_RECORD, LOG_INFO, LOC + "Deleting stale pending recording " +
1603  QString("[%1] '%2'")
1604  .arg((*it).m_info->GetInputID())
1605  .arg((*it).m_info->GetTitle()));
1606 
1607  delete (*it).m_info;
1608  it = m_pendingRecordings.erase(it);
1609  }
1610  else
1611  {
1612  it++;
1613  }
1614  }
1615 
1616  if (m_pendingRecordings.empty())
1617  return;
1618 
1619  // Make sure EIT scan is stopped so it does't interfere
1621  {
1622  LOG(VB_CHANNEL, LOG_INFO,
1623  LOC + "Stopping active EIT scan for pending recording.");
1625  }
1626 
1627  // If we have a pending recording and AskAllowRecording
1628  // or DoNotAskAllowRecording is set and the frontend is
1629  // ready send an ASK_RECORDING query to frontend.
1630 
1631  bool has_rec = false;
1632  auto it = m_pendingRecordings.begin();
1633  if ((1 == m_pendingRecordings.size()) &&
1634  (*it).m_ask &&
1635  ((*it).m_info->GetInputID() == m_inputId) &&
1637  {
1639  has_rec = m_pseudoLiveTVRecording &&
1641  (*it).m_recordingStart);
1642  }
1643 
1644  for (it = m_pendingRecordings.begin(); it != m_pendingRecordings.end(); ++it)
1645  {
1646  if (!(*it).m_ask && !(*it).m_doNotAsk)
1647  continue;
1648 
1649  auto timeuntil = ((*it).m_doNotAsk) ?
1650  -1s: MythDate::secsInFuture((*it).m_recordingStart);
1651 
1652  if (has_rec)
1653  (*it).m_canceled = true;
1654 
1655  QString query = QString("ASK_RECORDING %1 %2 %3 %4")
1656  .arg(m_inputId)
1657  .arg(timeuntil.count())
1658  .arg(has_rec ? 1 : 0)
1659  .arg((*it).m_hasLaterShowing ? 1 : 0);
1660 
1661  LOG(VB_GENERAL, LOG_INFO, LOC + query);
1662 
1663  QStringList msg;
1664  (*it).m_info->ToStringList(msg);
1665  MythEvent me(query, msg);
1666  gCoreContext->dispatch(me);
1667 
1668  (*it).m_ask = (*it).m_doNotAsk = false;
1669  }
1670 }
1671 
1673  uint &parentid,
1674  GeneralDBOptions &gen_opts,
1675  DVBDBOptions &dvb_opts,
1676  FireWireDBOptions &firewire_opts)
1677 {
1678  int testnum = 0;
1679  QString test;
1680 
1681  MSqlQuery query(MSqlQuery::InitCon());
1682  query.prepare(
1683  "SELECT videodevice, vbidevice, audiodevice, "
1684  " audioratelimit, cardtype, "
1685  " skipbtaudio, signal_timeout, channel_timeout, "
1686  " dvb_wait_for_seqstart, "
1687  ""
1688  " dvb_on_demand, dvb_tuning_delay, dvb_eitscan,"
1689  ""
1690  " firewire_speed, firewire_model, firewire_connection, "
1691  " parentid "
1692  ""
1693  "FROM capturecard "
1694  "WHERE cardid = :INPUTID");
1695  query.bindValue(":INPUTID", inputid);
1696 
1697  if (!query.exec() || !query.isActive())
1698  {
1699  MythDB::DBError("getdevices", query);
1700  return false;
1701  }
1702 
1703  if (!query.next())
1704  return false;
1705 
1706  // General options
1707  test = query.value(0).toString();
1708  if (!test.isEmpty())
1709  gen_opts.m_videoDev = test;
1710 
1711  test = query.value(1).toString();
1712  if (!test.isEmpty())
1713  gen_opts.m_vbiDev = test;
1714 
1715  test = query.value(2).toString();
1716  if (!test.isEmpty())
1717  gen_opts.m_audioDev = test;
1718 
1719  gen_opts.m_audioSampleRate = std::max(testnum, query.value(3).toInt());
1720 
1721  test = query.value(4).toString();
1722  if (!test.isEmpty())
1723  gen_opts.m_inputType = test;
1724 
1725  gen_opts.m_skipBtAudio = query.value(5).toBool();
1726 
1727  gen_opts.m_signalTimeout = (uint) std::max(query.value(6).toInt(), 0);
1728  gen_opts.m_channelTimeout = (uint) std::max(query.value(7).toInt(), 0);
1729 
1730  // We should have at least 1000 ms to acquire tables...
1731  int table_timeout = ((int)gen_opts.m_channelTimeout -
1732  (int)gen_opts.m_signalTimeout);
1733  if (table_timeout < 1000)
1734  gen_opts.m_channelTimeout = gen_opts.m_signalTimeout + 1000;
1735 
1736  gen_opts.m_waitForSeqstart = query.value(8).toBool();
1737 
1738  // DVB options
1739  uint dvboff = 9;
1740  dvb_opts.m_dvbOnDemand = query.value(dvboff + 0).toBool();
1741  dvb_opts.m_dvbTuningDelay = std::chrono::milliseconds(query.value(dvboff + 1).toUInt());
1742  dvb_opts.m_dvbEitScan = query.value(dvboff + 2).toBool();
1743 
1744  // Firewire options
1745  uint fireoff = dvboff + 3;
1746  firewire_opts.m_speed = query.value(fireoff + 0).toUInt();
1747 
1748  test = query.value(fireoff + 1).toString();
1749  if (!test.isEmpty())
1750  firewire_opts.m_model = test;
1751 
1752  firewire_opts.m_connection = query.value(fireoff + 2).toUInt();
1753 
1754  parentid = query.value(15).toUInt();
1755 
1756  return true;
1757 }
1758 
1759 static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
1760 {
1761  if (!dtvMon->GetATSCStreamData())
1762  return;
1763 
1764  const MasterGuideTable *mgt = dtvMon->GetATSCStreamData()->GetCachedMGT();
1765  if (!mgt)
1766  return;
1767 
1768  for (uint i = 0; i < mgt->TableCount(); ++i)
1769  {
1770  pid_cache_item_t item(mgt->TablePID(i), mgt->TableType(i));
1771  pid_cache.push_back(item);
1772  }
1773  dtvMon->GetATSCStreamData()->ReturnCachedTable(mgt);
1774 }
1775 
1776 static bool ApplyCachedPids(DTVSignalMonitor *dtvMon, const DTVChannel* channel)
1777 {
1778  pid_cache_t pid_cache;
1779  channel->GetCachedPids(pid_cache);
1780  bool vctpid_cached = false;
1781  for (auto pid : pid_cache)
1782  {
1783  if ((pid.GetTableID() == TableID::TVCT) ||
1784  (pid.GetTableID() == TableID::CVCT))
1785  {
1786  vctpid_cached = true;
1787  dtvMon->GetATSCStreamData()->AddListeningPID(pid.GetPID());
1788  }
1789  }
1790  return vctpid_cached;
1791 }
1792 
1809 {
1810  LOG(VB_RECORD, LOG_INFO, LOC + "Setting up table monitoring.");
1811 
1813  DTVChannel *dtvchan = GetDTVChannel();
1814  if (!sm || !dtvchan)
1815  {
1816  LOG(VB_GENERAL, LOG_ERR, LOC + "Setting up table monitoring.");
1817  return false;
1818  }
1819 
1820  MPEGStreamData *sd = nullptr;
1821  if (GetDTVRecorder())
1822  {
1823  sd = GetDTVRecorder()->GetStreamData();
1824  sd->SetCaching(true);
1825  }
1826 
1827  QString recording_type = "all";
1831  const StandardSetting *setting = profile.byName("recordingtype");
1832  if (setting)
1833  recording_type = setting->getValue();
1834 
1835  const QString tuningmode = dtvchan->GetTuningMode();
1836 
1837  // Check if this is an ATSC Channel
1838  int major = dtvchan->GetMajorChannel();
1839  int minor = dtvchan->GetMinorChannel();
1840  if ((minor > 0) && (tuningmode == "atsc"))
1841  {
1842  QString msg = QString("ATSC channel: %1_%2").arg(major).arg(minor);
1843  LOG(VB_RECORD, LOG_INFO, LOC + msg);
1844 
1845  auto *asd = dynamic_cast<ATSCStreamData*>(sd);
1846  if (!asd)
1847  {
1848  sd = asd = new ATSCStreamData(major, minor, m_inputId);
1849  sd->SetCaching(true);
1850  if (GetDTVRecorder())
1851  GetDTVRecorder()->SetStreamData(asd);
1852  }
1853 
1854  asd->Reset();
1855  sm->SetStreamData(sd);
1856  sm->SetChannel(major, minor);
1857  sd->SetRecordingType(recording_type);
1858 
1859  // Try to get pid of VCT from cache and
1860  // require MGT if we don't have VCT pid.
1861  if (!ApplyCachedPids(sm, dtvchan))
1863 
1864  LOG(VB_RECORD, LOG_INFO, LOC +
1865  "Successfully set up ATSC table monitoring.");
1866  return true;
1867  }
1868 
1869  // Check if this is an DVB channel
1870  int progNum = dtvchan->GetProgramNumber();
1871  if ((progNum >= 0) && (tuningmode == "dvb") && (m_genOpt.m_inputType != "VBOX"))
1872  {
1873  int netid = dtvchan->GetOriginalNetworkID();
1874  int tsid = dtvchan->GetTransportID();
1875 
1876  auto *dsd = dynamic_cast<DVBStreamData*>(sd);
1877  if (!dsd)
1878  {
1879  sd = dsd = new DVBStreamData(netid, tsid, progNum, m_inputId);
1880  sd->SetCaching(true);
1881  if (GetDTVRecorder())
1882  GetDTVRecorder()->SetStreamData(dsd);
1883  }
1884 
1885  LOG(VB_RECORD, LOG_INFO, LOC +
1886  QString("DVB service_id %1 on net_id %2 tsid %3")
1887  .arg(progNum).arg(netid).arg(tsid));
1888 
1890 
1891  dsd->Reset();
1892  sm->SetStreamData(sd);
1893  sm->SetDVBService(netid, tsid, progNum);
1894  sd->SetRecordingType(recording_type);
1895 
1899  sm->SetRotorTarget(1.0F);
1900 
1901  if (EITscan)
1902  {
1904  sm->IgnoreEncrypted(true);
1905  }
1906 
1907  LOG(VB_RECORD, LOG_INFO, LOC +
1908  "Successfully set up DVB table monitoring.");
1909  return true;
1910  }
1911 
1912  // Check if this is an MPEG channel
1913  if (progNum >= 0)
1914  {
1915  if (!sd)
1916  {
1917  sd = new MPEGStreamData(progNum, m_inputId, true);
1918  sd->SetCaching(true);
1919  if (GetDTVRecorder())
1921  }
1922 
1923  QString msg = QString("MPEG program number: %1").arg(progNum);
1924  LOG(VB_RECORD, LOG_INFO, LOC + msg);
1925 
1927 
1928  sd->Reset();
1929  sm->SetStreamData(sd);
1930  sm->SetProgramNumber(progNum);
1931  sd->SetRecordingType(recording_type);
1932 
1936  sm->SetRotorTarget(1.0F);
1937 
1938  if (EITscan)
1939  {
1941  sm->IgnoreEncrypted(true);
1942  }
1943 
1944  LOG(VB_RECORD, LOG_INFO, LOC +
1945  "Successfully set up MPEG table monitoring.");
1946  return true;
1947  }
1948 
1949  // If this is not an ATSC, DVB or MPEG channel then check to make sure
1950  // that we have permanent pidcache entries.
1951  bool ok = false;
1952  if (GetDTVChannel())
1953  {
1954  pid_cache_t pid_cache;
1955  GetDTVChannel()->GetCachedPids(pid_cache);
1956  for (auto item = pid_cache.cbegin(); !ok && item != pid_cache.cend(); ++item)
1957  ok |= item->IsPermanent();
1958  }
1959 
1960  if (!ok)
1961  {
1962  QString msg = "No valid DTV info, ATSC maj(%1) min(%2), MPEG pn(%3)";
1963  LOG(VB_GENERAL, LOG_ERR, LOC + msg.arg(major).arg(minor).arg(progNum));
1964  }
1965  else
1966  {
1967  LOG(VB_RECORD, LOG_INFO, LOC +
1968  "Successfully set up raw pid monitoring.");
1969  }
1970 
1971  return ok;
1972 }
1973 
1988 bool TVRec::SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
1989 {
1990  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetupSignalMonitor(%1, %2)")
1991  .arg(tablemon).arg(notify));
1992 
1993  // if it already exists, there no need to initialize it
1994  if (m_signalMonitor)
1995  return true;
1996 
1997  // if there is no channel object we can't monitor it
1998  if (!m_channel)
1999  return false;
2000 
2001  // nothing to monitor here either (DummyChannel)
2002  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
2003  return true;
2004 
2005  // make sure statics are initialized
2007 
2010  m_channel, false);
2011 
2012  if (m_signalMonitor)
2013  {
2014  LOG(VB_RECORD, LOG_INFO, LOC + "Signal monitor successfully created");
2015  // If this is a monitor for Digital TV, initialize table monitors
2016  if (GetDTVSignalMonitor() && tablemon &&
2017  !SetupDTVSignalMonitor(EITscan))
2018  {
2019  LOG(VB_GENERAL, LOG_ERR, LOC +
2020  "Failed to setup digital signal monitoring");
2021 
2022  return false;
2023  }
2024 
2027  kSignalMonitoringRate * 5 :
2030 
2031  // Start the monitoring thread
2033  }
2034 
2035  return true;
2036 }
2037 
2043 {
2044  if (!m_signalMonitor)
2045  return;
2046 
2047  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- begin");
2048 
2049  // If this is a DTV signal monitor, save any pids we know about.
2051  DTVChannel *dtvChan = GetDTVChannel();
2052  if (dtvMon && dtvChan)
2053  {
2054  pid_cache_t pid_cache;
2055  GetPidsToCache(dtvMon, pid_cache);
2056  if (!pid_cache.empty())
2057  dtvChan->SaveCachedPids(pid_cache);
2058  }
2059 
2060  if (m_signalMonitor)
2061  {
2062  delete m_signalMonitor;
2063  m_signalMonitor = nullptr;
2064  }
2065 
2066  LOG(VB_RECORD, LOG_INFO, LOC + "TeardownSignalMonitor() -- end");
2067 }
2068 
2080 std::chrono::milliseconds TVRec::SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend)
2081 {
2082  QString msg = "SetSignalMonitoringRate(%1, %2)";
2083  LOG(VB_RECORD, LOG_INFO, LOC +
2084  msg.arg(rate.count()).arg(notifyFrontend) + "-- start");
2085 
2086  QMutexLocker lock(&m_stateChangeLock);
2087 
2089  {
2090  LOG(VB_GENERAL, LOG_ERR, LOC +
2091  "Signal Monitoring is notsupported by your hardware.");
2092  return 0ms;
2093  }
2094 
2096  {
2097  LOG(VB_GENERAL, LOG_ERR, LOC +
2098  "Signal can only be monitored in LiveTV Mode.");
2099  return 0ms;
2100  }
2101 
2102  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
2103 
2104  TuningRequest req = (rate > 0ms) ?
2107 
2109 
2110  // Wait for RingBuffer reset
2111  while (!HasFlags(kFlagRingBufferReady))
2113  LOG(VB_RECORD, LOG_INFO, LOC +
2114  msg.arg(rate.count()).arg(notifyFrontend) + " -- end");
2115  return 1ms;
2116 }
2117 
2119 {
2120  return dynamic_cast<DTVSignalMonitor*>(m_signalMonitor);
2121 }
2122 
2134 bool TVRec::ShouldSwitchToAnotherInput(const QString& chanid) const
2135 {
2136  QString msg("");
2137  MSqlQuery query(MSqlQuery::InitCon());
2138 
2139  if (!query.isConnected())
2140  return false;
2141 
2142  query.prepare("SELECT channel.channum, channel.callsign "
2143  "FROM channel "
2144  "WHERE channel.chanid = :CHANID");
2145  query.bindValue(":CHANID", chanid);
2146  if (!query.exec() || !query.next())
2147  {
2148  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2149  return false;
2150  }
2151 
2152  QString channelname = query.value(0).toString();
2153  QString callsign = query.value(1).toString();
2154 
2155  query.prepare(
2156  "SELECT channel.channum "
2157  "FROM channel, capturecard "
2158  "WHERE deleted IS NULL AND "
2159  " ( channel.chanid = :CHANID OR "
2160  " ( channel.channum = :CHANNUM AND "
2161  " channel.callsign = :CALLSIGN ) "
2162  " ) AND "
2163  " channel.sourceid = capturecard.sourceid AND "
2164  " capturecard.cardid = :INPUTID");
2165  query.bindValue(":CHANID", chanid);
2166  query.bindValue(":CHANNUM", channelname);
2167  query.bindValue(":CALLSIGN", callsign);
2168  query.bindValue(":INPUTID", m_inputId);
2169 
2170  if (!query.exec() || !query.isActive())
2171  {
2172  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2173  }
2174  else if (query.size() > 0)
2175  {
2176  msg = "Found channel (%1) on current input[%2].";
2177  LOG(VB_RECORD, LOG_INFO, LOC + msg.arg(channelname).arg(m_inputId));
2178  return false;
2179  }
2180 
2181  // We didn't find it on the current input, so now we check other inputs.
2182  query.prepare(
2183  "SELECT channel.channum, capturecard.cardid "
2184  "FROM channel, capturecard "
2185  "WHERE deleted IS NULL AND "
2186  " ( channel.chanid = :CHANID OR "
2187  " ( channel.channum = :CHANNUM AND "
2188  " channel.callsign = :CALLSIGN ) "
2189  " ) AND "
2190  " channel.sourceid = capturecard.sourceid AND "
2191  " capturecard.cardid != :INPUTID");
2192  query.bindValue(":CHANID", chanid);
2193  query.bindValue(":CHANNUM", channelname);
2194  query.bindValue(":CALLSIGN", callsign);
2195  query.bindValue(":INPUTID", m_inputId);
2196 
2197  if (!query.exec() || !query.isActive())
2198  {
2199  MythDB::DBError("ShouldSwitchToAnotherInput", query);
2200  }
2201  else if (query.next())
2202  {
2203  msg = QString("Found channel (%1) on different input(%2).")
2204  .arg(query.value(0).toString(), query.value(1).toString());
2205  LOG(VB_RECORD, LOG_INFO, LOC + msg);
2206  return true;
2207  }
2208 
2209  msg = QString("Did not find channel(%1) on any input.").arg(channelname);
2210  LOG(VB_RECORD, LOG_ERR, LOC + msg);
2211  return false;
2212 }
2213 
2224 bool TVRec::CheckChannel(const QString& name) const
2225 {
2226  if (!m_channel)
2227  return false;
2228 
2229  return m_channel->CheckChannel(name);
2230 }
2231 
2235 static QString add_spacer(const QString &channel, const QString &spacer)
2236 {
2237  QString chan = channel;
2238  if ((chan.length() >= 2) && !spacer.isEmpty())
2239  return chan.left(chan.length()-1) + spacer + chan.right(1);
2240  return chan;
2241 }
2242 
2270 bool TVRec::CheckChannelPrefix(const QString &prefix,
2271  uint &complete_valid_channel_on_rec,
2272  bool &is_extra_char_useful,
2273  QString &needed_spacer) const
2274 {
2275 #if DEBUG_CHANNEL_PREFIX
2276  LOG(VB_GENERAL, LOG_DEBUG, QString("CheckChannelPrefix(%1)").arg(prefix));
2277 #endif
2278 
2279  static const std::array<const QString,5> s_spacers = { "", "_", "-", "#", "." };
2280 
2281  MSqlQuery query(MSqlQuery::InitCon());
2282  QString basequery = QString(
2283  "SELECT channel.chanid, channel.channum, capturecard.cardid "
2284  "FROM channel, capturecard "
2285  "WHERE deleted IS NULL AND "
2286  " channel.channum LIKE '%1%' AND "
2287  " channel.sourceid = capturecard.sourceid");
2288 
2289  const std::array<const QString,2> inputquery
2290  {
2291  QString(" AND capturecard.cardid = '%1'").arg(m_inputId),
2292  QString(" AND capturecard.cardid != '%1'").arg(m_inputId),
2293  };
2294 
2295  std::vector<unsigned int> fchanid;
2296  std::vector<QString> fchannum;
2297  std::vector<unsigned int> finputid;
2298  std::vector<QString> fspacer;
2299 
2300  for (const auto & str : inputquery)
2301  {
2302  for (const auto & spacer : s_spacers)
2303  {
2304  QString qprefix = add_spacer(
2305  prefix, (spacer == "_") ? "\\_" : spacer);
2306  query.prepare(basequery.arg(qprefix) + str);
2307 
2308  if (!query.exec() || !query.isActive())
2309  {
2310  MythDB::DBError("checkchannel -- locate channum", query);
2311  }
2312  else if (query.size())
2313  {
2314  while (query.next())
2315  {
2316  fchanid.push_back(query.value(0).toUInt());
2317  fchannum.push_back(query.value(1).toString());
2318  finputid.push_back(query.value(2).toUInt());
2319  fspacer.emplace_back(spacer);
2320 #if DEBUG_CHANNEL_PREFIX
2321  LOG(VB_GENERAL, LOG_DEBUG,
2322  QString("(%1,%2) Adding %3 rec %4")
2323  .arg(i).arg(j).arg(query.value(1).toString(),6)
2324  .arg(query.value(2).toUInt()));
2325 #endif
2326  }
2327  }
2328 
2329  if (prefix.length() < 2)
2330  break;
2331  }
2332  }
2333 
2334  // Now process the lists for the info we need...
2335  is_extra_char_useful = false;
2336  complete_valid_channel_on_rec = 0;
2337  needed_spacer.clear();
2338 
2339  if (fchanid.empty())
2340  return false;
2341 
2342  if (fchanid.size() == 1) // Unique channel...
2343  {
2344  needed_spacer = fspacer[0];
2345  bool nc = (fchannum[0] != add_spacer(prefix, fspacer[0]));
2346 
2347  complete_valid_channel_on_rec = (nc) ? 0 : finputid[0];
2348  is_extra_char_useful = nc;
2349  return true;
2350  }
2351 
2352  // If we get this far there is more than one channel
2353  // sharing the prefix we were given.
2354 
2355  // Is an extra characher useful for disambiguation?
2356  is_extra_char_useful = false;
2357  for (uint i = 0; (i < fchannum.size()) && !is_extra_char_useful; i++)
2358  {
2359  is_extra_char_useful = (fchannum[i] != add_spacer(prefix, fspacer[i]));
2360 #if DEBUG_CHANNEL_PREFIX
2361  LOG(VB_GENERAL, LOG_DEBUG, QString("is_extra_char_useful(%1!=%2): %3")
2362  .arg(fchannum[i]).arg(add_spacer(prefix, fspacer[i]))
2363  .arg(is_extra_char_useful));
2364 #endif
2365  }
2366 
2367  // Are any of the channels complete w/o spacer?
2368  // If so set complete_valid_channel_on_rec,
2369  // with a preference for our inputid.
2370  for (size_t i = 0; i < fchannum.size(); i++)
2371  {
2372  if (fchannum[i] == prefix)
2373  {
2374  complete_valid_channel_on_rec = finputid[i];
2375  if (finputid[i] == m_inputId)
2376  break;
2377  }
2378  }
2379 
2380  if (complete_valid_channel_on_rec != 0)
2381  return true;
2382 
2383  // Add a spacer, if one is needed to select a valid channel.
2384  bool spacer_needed = true;
2385  for (uint i = 0; (i < fspacer.size() && spacer_needed); i++)
2386  spacer_needed = !fspacer[i].isEmpty();
2387  if (spacer_needed)
2388  needed_spacer = fspacer[0];
2389 
2390  // If it isn't useful to wait for more characters,
2391  // then try to commit to any true match immediately.
2392  for (size_t i = 0; i < ((is_extra_char_useful) ? 0 : fchanid.size()); i++)
2393  {
2394  if (fchannum[i] == add_spacer(prefix, fspacer[i]))
2395  {
2396  needed_spacer = fspacer[i];
2397  complete_valid_channel_on_rec = finputid[i];
2398  return true;
2399  }
2400  }
2401 
2402  return true;
2403 }
2404 
2406  const QString &channum)
2407 {
2408  if (!m_recorder)
2409  return false;
2410 
2411  QString videoFilters = ChannelUtil::GetVideoFilters(sourceid, channum);
2412  if (!videoFilters.isEmpty())
2413  {
2414  m_recorder->SetVideoFilters(videoFilters);
2415  return true;
2416  }
2417 
2418  return false;
2419 }
2420 
2426 {
2427  return ((m_recorder && m_recorder->IsRecording()) ||
2429 }
2430 
2436 bool TVRec::IsBusy(InputInfo *busy_input, std::chrono::seconds time_buffer) const
2437 {
2438  InputInfo dummy;
2439  if (!busy_input)
2440  busy_input = &dummy;
2441 
2442  busy_input->Clear();
2443 
2444  if (!m_channel)
2445  return false;
2446 
2447  if (!m_channel->GetInputID())
2448  return false;
2449 
2450  uint chanid = 0;
2451 
2452  if (GetState() != kState_None)
2453  {
2454  busy_input->m_inputId = m_channel->GetInputID();
2455  chanid = m_channel->GetChanID();
2456  }
2457 
2458  PendingInfo pendinfo;
2459  bool has_pending = false;
2460  {
2461  m_pendingRecLock.lock();
2462  PendingMap::const_iterator it = m_pendingRecordings.find(m_inputId);
2463  has_pending = (it != m_pendingRecordings.end());
2464  if (has_pending)
2465  pendinfo = *it;
2466  m_pendingRecLock.unlock();
2467  }
2468 
2469  if (!busy_input->m_inputId && has_pending)
2470  {
2471  auto timeLeft = MythDate::secsInFuture(pendinfo.m_recordingStart);
2472 
2473  if (timeLeft <= time_buffer)
2474  {
2475  QString channum;
2476  QString input;
2477  if (pendinfo.m_info->QueryTuningInfo(channum, input))
2478  {
2479  busy_input->m_inputId = m_channel->GetInputID();
2480  chanid = pendinfo.m_info->GetChanID();
2481  }
2482  }
2483  }
2484 
2485  if (busy_input->m_inputId)
2486  {
2487  CardUtil::GetInputInfo(*busy_input);
2488  busy_input->m_chanId = chanid;
2489  busy_input->m_mplexId = ChannelUtil::GetMplexID(busy_input->m_chanId);
2490  busy_input->m_mplexId =
2491  (32767 == busy_input->m_mplexId) ? 0 : busy_input->m_mplexId;
2492  }
2493 
2494  return busy_input->m_inputId != 0U;
2495 }
2496 
2497 
2505 {
2506  QMutexLocker lock(&m_stateChangeLock);
2507 
2508  if (m_recorder)
2509  return m_recorder->GetFrameRate();
2510  return -1.0F;
2511 }
2512 
2520 {
2521  QMutexLocker lock(&m_stateChangeLock);
2522 
2523  if (m_recorder)
2524  return m_recorder->GetFramesWritten();
2525  return -1;
2526 }
2527 
2534 long long TVRec::GetFilePosition(void)
2535 {
2536  QMutexLocker lock(&m_stateChangeLock);
2537 
2538  if (m_buffer)
2539  return m_buffer->GetWritePosition();
2540  return -1;
2541 }
2542 
2550 int64_t TVRec::GetKeyframePosition(uint64_t desired) const
2551 {
2552  QMutexLocker lock(&m_stateChangeLock);
2553 
2554  if (m_recorder)
2555  return m_recorder->GetKeyframePosition(desired);
2556  return -1;
2557 }
2558 
2568  int64_t start, int64_t end, frm_pos_map_t &map) const
2569 {
2570  QMutexLocker lock(&m_stateChangeLock);
2571 
2572  if (m_recorder)
2573  return m_recorder->GetKeyframePositions(start, end, map);
2574 
2575  return false;
2576 }
2577 
2579  int64_t start, int64_t end, frm_pos_map_t &map) const
2580 {
2581  QMutexLocker lock(&m_stateChangeLock);
2582 
2583  if (m_recorder)
2584  return m_recorder->GetKeyframeDurations(start, end, map);
2585 
2586  return false;
2587 }
2588 
2594 long long TVRec::GetMaxBitrate(void) const
2595 {
2596  long long bitrate = 0;
2597  if (m_genOpt.m_inputType == "MPEG")
2598  { // NOLINT(bugprone-branch-clone)
2599  bitrate = 10080000LL; // use DVD max bit rate
2600  }
2601  else if (m_genOpt.m_inputType == "HDPVR")
2602  {
2603  bitrate = 20200000LL; // Peak bit rate for HD-PVR
2604  }
2606  {
2607  bitrate = 22200000LL; // 1080i
2608  }
2609  else // frame grabber
2610  {
2611  bitrate = 10080000LL; // use DVD max bit rate, probably too big
2612  }
2613 
2614  return bitrate;
2615 }
2616 
2622 void TVRec::SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
2623 {
2624  QMutexLocker lock(&m_stateChangeLock);
2625 
2626  m_tvChain = newchain;
2627  m_tvChain->IncrRef(); // mark it for TVRec use
2628  m_tvChain->ReloadAll();
2629 
2630  QString hostprefix = MythCoreContext::GenMythURL(
2633 
2634  m_tvChain->SetHostPrefix(hostprefix);
2636 
2637  m_isPip = pip;
2638  m_liveTVStartChannel = std::move(startchan);
2639 
2640  // Change to WatchingLiveTV
2642  // Wait for state change to take effect
2644 
2645  // Make sure StartRecording can't steal our tuner
2646  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2647 }
2648 
2652 QString TVRec::GetChainID(void)
2653 {
2654  if (m_tvChain)
2655  return m_tvChain->GetID();
2656  return "";
2657 }
2658 
2668 {
2669  QMutexLocker lock(&m_stateChangeLock);
2670 
2672  return; // already stopped
2673 
2674  if (!m_curRecording)
2675  return;
2676 
2677  const QString recgrp = m_curRecording->QueryRecordingGroup();
2679 
2680  if (recgrp != "LiveTV" && !m_pseudoLiveTVRecording)
2681  {
2682  // User wants this recording to continue
2684  }
2685  else if (recgrp == "LiveTV" && m_pseudoLiveTVRecording)
2686  {
2687  // User wants to abandon scheduled recording
2688  SetPseudoLiveTVRecording(nullptr);
2689  }
2690 }
2691 
2702 {
2703  if (!m_channel)
2704  return;
2705 
2706  // Notify scheduler of the recording.
2707  // + set up recording so it can be resumed
2708  rec->SetInputID(m_inputId);
2710 
2711  if (rec->GetRecordingRuleType() == kNotRecording)
2712  {
2715  }
2716 
2717  // + remove any end offset which would mismatch the live session
2718  rec->GetRecordingRule()->m_endOffset = 0;
2719 
2720  // + save RecStatus::Inactive recstatus to so that a reschedule call
2721  // doesn't start recording this on another input before we
2722  // send the SCHEDULER_ADD_RECORDING message to the scheduler.
2724  rec->AddHistory(false);
2725 
2726  // + save RecordingRule so that we get a recordid
2727  // (don't allow RescheduleMatch(), avoiding unneeded reschedule)
2728  rec->GetRecordingRule()->Save(false);
2729 
2730  // + save recordid to recorded entry
2731  rec->ApplyRecordRecID();
2732 
2733  // + set proper recstatus (saved later)
2735 
2736  // + pass proginfo to scheduler and reschedule
2737  QStringList prog;
2738  rec->ToStringList(prog);
2739  MythEvent me("SCHEDULER_ADD_RECORDING", prog);
2740  gCoreContext->dispatch(me);
2741 
2742  // Allow scheduler to end this recording before post-roll,
2743  // if it has another recording for this recorder.
2744  ClearFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2745 }
2746 
2748  RecordingProfile *recpro, int line)
2749 {
2750  if (kAutoRunProfile == t)
2751  {
2753  if (!recpro)
2754  {
2755  LoadProfile(nullptr, rec, profile);
2756  recpro = &profile;
2757  }
2758  m_autoRunJobs[rec->MakeUniqueKey()] =
2759  init_jobs(rec, *recpro, m_runJobOnHostOnly,
2761  }
2762  else
2763  {
2765  }
2766  LOG(VB_JOBQUEUE, LOG_INFO,
2767  QString("InitAutoRunJobs for %1, line %2 -> 0x%3")
2768  .arg(rec->MakeUniqueKey()).arg(line)
2769  .arg(m_autoRunJobs[rec->MakeUniqueKey()],0,16));
2770 }
2771 
2783 void TVRec::SetLiveRecording(int recording)
2784 {
2785  LOG(VB_GENERAL, LOG_INFO, LOC +
2786  QString("SetLiveRecording(%1)").arg(recording));
2787  QMutexLocker locker(&m_stateChangeLock);
2788 
2789  (void) recording;
2790 
2792  bool was_rec = m_pseudoLiveTVRecording;
2794  if (was_rec && !m_pseudoLiveTVRecording)
2795  {
2796  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- cancel");
2797  // cancel -- 'recording' should be 0 or -1
2798  SetFlags(kFlagCancelNextRecording, __FILE__, __LINE__);
2799  m_curRecording->SetRecordingGroup("LiveTV");
2800  InitAutoRunJobs(m_curRecording, kAutoRunNone, nullptr, __LINE__);
2801  }
2802  else if (!was_rec && m_pseudoLiveTVRecording)
2803  {
2804  LOG(VB_GENERAL, LOG_INFO, LOC + "SetLiveRecording() -- record");
2805  // record -- 'recording' should be 1 or -1
2806 
2807  // If the last recording was flagged for keeping
2808  // in the frontend, then add the recording rule
2809  // so that transcode, commfrag, etc can be run.
2812  recstat = m_curRecording->GetRecordingStatus();
2813  m_curRecording->SetRecordingGroup("Default");
2814  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
2815  }
2816 
2817  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
2818  .arg(m_curRecording->GetInputID())
2819  .arg(m_curRecording->GetChanID())
2821  .arg(recstat)
2823 
2824  gCoreContext->dispatch(me);
2825 }
2826 
2832 {
2833  QMutexLocker lock(&m_stateChangeLock);
2834  LOG(VB_RECORD, LOG_INFO, LOC +
2835  QString("StopLiveTV(void) curRec: 0x%1 pseudoRec: 0x%2")
2836  .arg((uint64_t)m_curRecording,0,16)
2837  .arg((uint64_t)m_pseudoLiveTVRecording,0,16));
2838 
2840  return;
2841 
2842  bool hadPseudoLiveTVRec = m_pseudoLiveTVRecording;
2844 
2845  if (!hadPseudoLiveTVRec && m_pseudoLiveTVRecording)
2847 
2848  // Figure out next state and if needed recording end time.
2849  TVState next_state = kState_None;
2851  {
2853  next_state = kState_RecordingOnly;
2854  }
2855 
2856  // Change to the appropriate state
2857  ChangeState(next_state);
2858 
2859  // Wait for state change to take effect...
2861 
2862  // We are done with the tvchain...
2863  if (m_tvChain)
2864  {
2865  m_tvChain->DecrRef();
2866  }
2867  m_tvChain = nullptr;
2868 }
2869 
2879 {
2880  QMutexLocker lock(&m_stateChangeLock);
2881 
2882  if (!m_recorder)
2883  {
2884  LOG(VB_GENERAL, LOG_ERR, LOC +
2885  "PauseRecorder() called with no recorder");
2886  return;
2887  }
2888 
2889  m_recorder->Pause();
2890 }
2891 
2898 {
2899  if (m_pauseNotify)
2900  WakeEventLoop();
2901 }
2902 
2906 void TVRec::ToggleChannelFavorite(const QString& changroupname)
2907 {
2908  QMutexLocker lock(&m_stateChangeLock);
2909 
2910  if (!m_channel)
2911  return;
2912 
2913  // Get current channel id...
2914  uint sourceid = m_channel->GetSourceID();
2915  QString channum = m_channel->GetChannelName();
2916  uint chanid = ChannelUtil::GetChanID(sourceid, channum);
2917 
2918  if (!chanid)
2919  {
2920  LOG(VB_GENERAL, LOG_ERR, LOC +
2921  QString("Channel: \'%1\' was not found in the database.\n"
2922  "\t\tMost likely, the 'starting channel' for this "
2923  "Input Connection is invalid.\n"
2924  "\t\tCould not toggle favorite.").arg(channum));
2925  return;
2926  }
2927 
2928  int changrpid = ChannelGroup::GetChannelGroupId(changroupname);
2929  if (changrpid <1)
2930  {
2931  LOG(VB_RECORD, LOG_ERR, LOC +
2932  QString("ToggleChannelFavorite: Invalid channel group name %1,")
2933  .arg(changroupname));
2934  }
2935  else
2936  {
2937  bool result = ChannelGroup::ToggleChannel(chanid, changrpid, true);
2938 
2939  if (!result)
2940  LOG(VB_RECORD, LOG_ERR, LOC + "Unable to toggle channel favorite.");
2941  else
2942  {
2943  LOG(VB_RECORD, LOG_INFO, LOC +
2944  QString("Toggled channel favorite.channum %1, chan group %2")
2945  .arg(channum, changroupname));
2946  }
2947  }
2948 }
2949 
2956 {
2957  QMutexLocker lock(&m_stateChangeLock);
2958  if (!m_channel)
2959  return -1;
2960 
2961  int ret = m_channel->GetPictureAttribute(attr);
2962 
2963  return (ret < 0) ? -1 : ret / 655;
2964 }
2965 
2974  PictureAttribute attr,
2975  bool direction)
2976 {
2977  QMutexLocker lock(&m_stateChangeLock);
2978  if (!m_channel)
2979  return -1;
2980 
2981  int ret = m_channel->ChangePictureAttribute(type, attr, direction);
2982 
2983  return (ret < 0) ? -1 : ret / 655;
2984 }
2985 
2989 QString TVRec::GetInput(void) const
2990 {
2991  if (m_channel)
2992  return m_channel->GetInputName();
2993  return {};
2994 }
2995 
3000 {
3001  if (m_channel)
3002  return m_channel->GetSourceID();
3003  return 0;
3004 }
3005 
3014 QString TVRec::SetInput(QString input)
3015 {
3016  QMutexLocker lock(&m_stateChangeLock);
3017  QString origIn = input;
3018  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + input + ") -- begin");
3019 
3020  if (!m_channel)
3021  {
3022  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput() -- end no channel class");
3023  return {};
3024  }
3025 
3026  LOG(VB_RECORD, LOG_INFO, LOC + "SetInput(" + origIn + ":" + input +
3027  ") -- end nothing to do");
3028  return input;
3029 }
3030 
3040 void TVRec::SetChannel(const QString& name, uint requestType)
3041 {
3042  QMutexLocker locker1(&m_setChannelLock);
3043  QMutexLocker locker2(&m_stateChangeLock);
3044 
3045  LOG(VB_CHANNEL, LOG_INFO, LOC +
3046  QString("SetChannel(%1) -- begin").arg(name));
3047 
3048  // Detect tuning request type if needed
3049  if (requestType & kFlagDetect)
3050  {
3052  requestType = m_lastTuningRequest.m_flags & (kFlagRec | kFlagNoRec);
3053  }
3054 
3055  // Clear the RingBuffer reset flag, in case we wait for a reset below
3056  ClearFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3057 
3058  // Clear out any EITScan channel change requests
3059  auto it = m_tuningRequests.begin();
3060  while (it != m_tuningRequests.end())
3061  {
3062  if ((*it).m_flags & kFlagEITScan)
3063  it = m_tuningRequests.erase(it);
3064  else
3065  ++it;
3066  }
3067 
3068  // Actually add the tuning request to the queue, and
3069  // then wait for it to start tuning
3070  m_tuningRequests.enqueue(TuningRequest(requestType, name));
3072 
3073  // If we are using a recorder, wait for a RingBuffer reset
3074  if (requestType & kFlagRec)
3075  {
3076  while (!HasFlags(kFlagRingBufferReady))
3078  }
3079  LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetChannel(%1) -- end").arg(name));
3080 }
3081 
3089 bool TVRec::QueueEITChannelChange(const QString &name)
3090 {
3091  LOG(VB_CHANNEL, LOG_INFO, LOC +
3092  QString("QueueEITChannelChange(%1) -- begin").arg(name));
3093 
3094  bool ok = false;
3095  if (m_setChannelLock.tryLock())
3096  {
3097  if (m_stateChangeLock.tryLock())
3098  {
3099  if (m_tuningRequests.empty())
3100  {
3102  ok = true;
3103  }
3104  m_stateChangeLock.unlock();
3105  }
3106  m_setChannelLock.unlock();
3107  }
3108 
3109  LOG(VB_CHANNEL, LOG_INFO, LOC +
3110  QString("QueueEITChannelChange(%1) -- end --> %2").arg(name).arg(ok));
3111 
3112  return ok;
3113 }
3114 
3116  QString &title, QString &subtitle,
3117  QString &desc, QString &category,
3118  QString &starttime, QString &endtime,
3119  QString &callsign, QString &iconpath,
3120  QString &channum, uint &sourceChanid,
3121  QString &seriesid, QString &programid)
3122 {
3123  QString compare = "<=";
3124  QString sortorder = "desc";
3125  uint chanid = 0;
3126 
3127  if (sourceChanid)
3128  {
3129  chanid = sourceChanid;
3130 
3131  if (BROWSE_UP == direction)
3132  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_UP);
3133  else if (BROWSE_DOWN == direction)
3134  chanid = m_channel->GetNextChannel(chanid, CHANNEL_DIRECTION_DOWN);
3135  else if (BROWSE_FAVORITE == direction)
3136  {
3137  chanid = m_channel->GetNextChannel(
3138  chanid, CHANNEL_DIRECTION_FAVORITE);
3139  }
3140  else if (BROWSE_LEFT == direction)
3141  {
3142  compare = "<";
3143  }
3144  else if (BROWSE_RIGHT == direction)
3145  {
3146  compare = ">";
3147  sortorder = "asc";
3148  }
3149  }
3150 
3151  if (!chanid)
3152  {
3153  if (BROWSE_SAME == direction)
3154  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3155  else if (BROWSE_UP == direction)
3156  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_UP);
3157  else if (BROWSE_DOWN == direction)
3158  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_DOWN);
3159  else if (BROWSE_FAVORITE == direction)
3160  {
3161  chanid = m_channel->GetNextChannel(channum,
3163  }
3164  else if (BROWSE_LEFT == direction)
3165  {
3166  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3167  compare = "<";
3168  }
3169  else if (BROWSE_RIGHT == direction)
3170  {
3171  chanid = m_channel->GetNextChannel(channum, CHANNEL_DIRECTION_SAME);
3172  compare = ">";
3173  sortorder = "asc";
3174  }
3175  }
3176 
3177  QString querystr = QString(
3178  "SELECT title, subtitle, description, category, "
3179  " starttime, endtime, callsign, icon, "
3180  " channum, seriesid, programid "
3181  "FROM program, channel "
3182  "WHERE program.chanid = channel.chanid AND "
3183  " channel.chanid = :CHANID AND "
3184  " starttime %1 :STARTTIME "
3185  "ORDER BY starttime %2 "
3186  "LIMIT 1").arg(compare, sortorder);
3187 
3188  MSqlQuery query(MSqlQuery::InitCon());
3189  query.prepare(querystr);
3190  query.bindValue(":CHANID", chanid);
3191  query.bindValue(":STARTTIME", starttime);
3192 
3193  // Clear everything now in case either query fails.
3194  title = subtitle = desc = category = "";
3195  starttime = endtime = callsign = iconpath = "";
3196  channum = seriesid = programid = "";
3197  sourceChanid = 0;
3198 
3199  // Try to get the program info
3200  if (!query.exec() && !query.isActive())
3201  {
3202  MythDB::DBError("GetNextProgram -- get program info", query);
3203  }
3204  else if (query.next())
3205  {
3206  title = query.value(0).toString();
3207  subtitle = query.value(1).toString();
3208  desc = query.value(2).toString();
3209  category = query.value(3).toString();
3210  starttime = query.value(4).toString();
3211  endtime = query.value(5).toString();
3212  callsign = query.value(6).toString();
3213  iconpath = query.value(7).toString();
3214  channum = query.value(8).toString();
3215  seriesid = query.value(9).toString();
3216  programid = query.value(10).toString();
3217  sourceChanid = chanid;
3218  return;
3219  }
3220 
3221  // Couldn't get program info, so get the channel info instead
3222  query.prepare(
3223  "SELECT channum, callsign, icon "
3224  "FROM channel "
3225  "WHERE chanid = :CHANID");
3226  query.bindValue(":CHANID", chanid);
3227 
3228  if (!query.exec() || !query.isActive())
3229  {
3230  MythDB::DBError("GetNextProgram -- get channel info", query);
3231  }
3232  else if (query.next())
3233  {
3234  sourceChanid = chanid;
3235  channum = query.value(0).toString();
3236  callsign = query.value(1).toString();
3237  iconpath = query.value(2).toString();
3238  }
3239 }
3240 
3241 bool TVRec::GetChannelInfo(uint &chanid, uint &sourceid,
3242  QString &callsign, QString &channum,
3243  QString &channame, QString &xmltvid) const
3244 {
3245  callsign.clear();
3246  channum.clear();
3247  channame.clear();
3248  xmltvid.clear();
3249 
3250  if ((!chanid || !sourceid) && !m_channel)
3251  return false;
3252 
3253  if (!chanid)
3254  chanid = (uint) std::max(m_channel->GetChanID(), 0);
3255 
3256  if (!sourceid)
3257  sourceid = m_channel->GetSourceID();
3258 
3259  MSqlQuery query(MSqlQuery::InitCon());
3260  query.prepare(
3261  "SELECT callsign, channum, name, xmltvid "
3262  "FROM channel "
3263  "WHERE chanid = :CHANID");
3264  query.bindValue(":CHANID", chanid);
3265  if (!query.exec() || !query.isActive())
3266  {
3267  MythDB::DBError("GetChannelInfo", query);
3268  return false;
3269  }
3270 
3271  if (!query.next())
3272  return false;
3273 
3274  callsign = query.value(0).toString();
3275  channum = query.value(1).toString();
3276  channame = query.value(2).toString();
3277  xmltvid = query.value(3).toString();
3278 
3279  return true;
3280 }
3281 
3282 bool TVRec::SetChannelInfo(uint chanid, uint sourceid,
3283  const QString& oldchannum,
3284  const QString& callsign, const QString& channum,
3285  const QString& channame, const QString& xmltvid)
3286 {
3287  if (!chanid || !sourceid || channum.isEmpty())
3288  return false;
3289 
3290  MSqlQuery query(MSqlQuery::InitCon());
3291  query.prepare(
3292  "UPDATE channel "
3293  "SET callsign = :CALLSIGN, "
3294  " channum = :CHANNUM, "
3295  " name = :CHANNAME, "
3296  " xmltvid = :XMLTVID "
3297  "WHERE chanid = :CHANID AND "
3298  " sourceid = :SOURCEID");
3299  query.bindValue(":CALLSIGN", callsign);
3300  query.bindValue(":CHANNUM", channum);
3301  query.bindValue(":CHANNAME", channame);
3302  query.bindValue(":XMLTVID", xmltvid);
3303  query.bindValue(":CHANID", chanid);
3304  query.bindValue(":SOURCEID", sourceid);
3305 
3306  if (!query.exec())
3307  {
3308  MythDB::DBError("SetChannelInfo", query);
3309  return false;
3310  }
3311 
3312  if (m_channel)
3313  m_channel->Renumber(sourceid, oldchannum, channum);
3314 
3315  return true;
3316 }
3317 
3322 {
3323  QMutexLocker lock(&m_stateChangeLock);
3324 
3325  MythMediaBuffer *oldbuffer = m_buffer;
3326  m_buffer = Buffer;
3327 
3328  if (oldbuffer && (oldbuffer != Buffer))
3329  {
3331  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3332  delete oldbuffer;
3333  }
3334 
3335  m_switchingBuffer = false;
3336 }
3337 
3339 {
3340  LOG(VB_GENERAL, LOG_INFO, LOC + "RingBufferChanged()");
3341 
3342  if (pginfo)
3343  {
3344  if (m_curRecording)
3345  {
3348  delete m_curRecording;
3349  }
3351  m_curRecording = new RecordingInfo(*pginfo);
3354  }
3355 
3357 }
3358 
3360  QString &input) const
3361 {
3362  QString channum;
3363 
3364  if (request.m_program)
3365  {
3366  request.m_program->QueryTuningInfo(channum, input);
3367  return channum;
3368  }
3369 
3370  channum = request.m_channel;
3371  input = request.m_input;
3372 
3373  // If this is Live TV startup, we need a channel...
3374  if (channum.isEmpty() && (request.m_flags & kFlagLiveTV))
3375  {
3376  if (!m_liveTVStartChannel.isEmpty())
3377  channum = m_liveTVStartChannel;
3378  else
3379  {
3382  }
3383  }
3384  if (request.m_flags & kFlagLiveTV)
3385  m_channel->Init(channum, false);
3386 
3387  if (m_channel && !channum.isEmpty() && (channum.indexOf("NextChannel") >= 0))
3388  {
3389  // FIXME This is just horrible
3390  int dir = channum.right(channum.length() - 12).toInt();
3391  uint chanid = m_channel->GetNextChannel(0, static_cast<ChannelChangeDirection>(dir));
3392  channum = ChannelUtil::GetChanNum(chanid);
3393  }
3394 
3395  return channum;
3396 }
3397 
3399 {
3400  if ((request.m_flags & kFlagAntennaAdjust) || request.m_input.isEmpty() ||
3402  {
3403  return false;
3404  }
3405 
3406  uint sourceid = m_channel->GetSourceID();
3407  QString oldchannum = m_channel->GetChannelName();
3408  QString newchannum = request.m_channel;
3409 
3410  if (ChannelUtil::IsOnSameMultiplex(sourceid, newchannum, oldchannum))
3411  {
3413  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3414 
3415  if (atsc)
3416  {
3417  uint major = 0;
3418  uint minor = 0;
3419  ChannelUtil::GetATSCChannel(sourceid, newchannum, major, minor);
3420 
3421  if (minor && atsc->HasChannel(major, minor))
3422  {
3423  request.m_majorChan = major;
3424  request.m_minorChan = minor;
3425  return true;
3426  }
3427  }
3428 
3429  if (mpeg)
3430  {
3431  uint progNum = ChannelUtil::GetProgramNumber(sourceid, newchannum);
3432  if (mpeg->HasProgram(progNum))
3433  {
3434  request.m_progNum = progNum;
3435  return true;
3436  }
3437  }
3438  }
3439 
3440  return false;
3441 }
3442 
3451 {
3452  if (!m_tuningRequests.empty())
3453  {
3454  TuningRequest request = m_tuningRequests.front();
3455  LOG(VB_RECORD, LOG_INFO, LOC +
3456  "HandleTuning Request: " + request.toString());
3457 
3458  QString input;
3459  request.m_channel = TuningGetChanNum(request, input);
3460  request.m_input = input;
3461 
3462  if (TuningOnSameMultiplex(request))
3463  LOG(VB_CHANNEL, LOG_INFO, LOC + "On same multiplex");
3464 
3465  TuningShutdowns(request);
3466 
3467  // The dequeue isn't safe to do until now because we
3468  // release the stateChangeLock to teardown a recorder
3470 
3471  // Now we start new stuff
3472  if (request.m_flags & (kFlagRecording|kFlagLiveTV|
3474  {
3475  if (!m_recorder)
3476  {
3477  LOG(VB_RECORD, LOG_INFO, LOC +
3478  "No recorder yet, calling TuningFrequency");
3479  TuningFrequency(request);
3480  }
3481  else
3482  {
3483  LOG(VB_RECORD, LOG_INFO, LOC + "Waiting for recorder pause..");
3484  SetFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3485  }
3486  }
3487  m_lastTuningRequest = request;
3488  }
3489 
3491  {
3492  if (!m_recorder || !m_recorder->IsPaused())
3493  return;
3494 
3495  ClearFlags(kFlagWaitingForRecPause, __FILE__, __LINE__);
3496  LOG(VB_RECORD, LOG_INFO, LOC +
3497  "Recorder paused, calling TuningFrequency");
3499  }
3500 
3501  MPEGStreamData *streamData = nullptr;
3502  if (HasFlags(kFlagWaitingForSignal) && !(streamData = TuningSignalCheck()))
3503  return;
3504 
3506  {
3507  if (m_recorder)
3509  else
3510  TuningNewRecorder(streamData);
3511 
3512  // If we got this far it is safe to set a new starting channel...
3513  if (m_channel)
3515  }
3516 }
3517 
3523 {
3524  LOG(VB_RECORD, LOG_INFO, LOC + QString("TuningShutdowns(%1)")
3525  .arg(request.toString()));
3526 
3527  if (m_scanner && !(request.m_flags & kFlagEITScan) &&
3529  {
3531  ClearFlags(kFlagEITScannerRunning, __FILE__, __LINE__);
3533  m_eitScanStartTime = MythDate::current().addSecs(secs.count());
3534  }
3535 
3536  if (m_scanner && !request.IsOnSameMultiplex())
3538 
3540  {
3541  MPEGStreamData *sd = nullptr;
3542  if (GetDTVSignalMonitor())
3545  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3546 
3547  // Delete StreamData if it is not in use by the recorder.
3548  MPEGStreamData *rec_sd = nullptr;
3549  if (GetDTVRecorder())
3550  rec_sd = GetDTVRecorder()->GetStreamData();
3551  if (sd && (sd != rec_sd))
3552  delete sd;
3553  }
3555  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3556 
3557  // At this point any waits are canceled.
3558 
3559  if (request.m_flags & kFlagNoRec)
3560  {
3562  {
3564  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3566  }
3567 
3569  (m_curRecording &&
3572  {
3573  m_stateChangeLock.unlock();
3574  TeardownRecorder(request.m_flags);
3575  m_stateChangeLock.lock();
3576  }
3577  // At this point the recorders are shut down
3578 
3579  CloseChannel();
3580  // At this point the channel is shut down
3581  }
3582 
3583  if (m_buffer && (request.m_flags & kFlagKillRingBuffer))
3584  {
3585  LOG(VB_RECORD, LOG_INFO, LOC + "Tearing down RingBuffer");
3586  SetRingBuffer(nullptr);
3587  // At this point the ringbuffer is shut down
3588  }
3589 
3590  // Clear pending actions from last request
3591  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
3592 }
3593 
3612 {
3613  LOG(VB_GENERAL, LOG_INFO, LOC + "TuningFrequency");
3614 
3615  DTVChannel *dtvchan = GetDTVChannel();
3616  if (dtvchan)
3617  {
3618  MPEGStreamData *mpeg = nullptr;
3619 
3620  if (GetDTVRecorder())
3622 
3623  // Tune with SI table standard (dvb, atsc, mpeg) from database, see issue #452
3625 
3626  const QString tuningmode = (HasFlags(kFlagEITScannerRunning)) ?
3627  dtvchan->GetSIStandard() :
3628  dtvchan->GetSuggestedTuningMode(
3630 
3631  dtvchan->SetTuningMode(tuningmode);
3632 
3633  if (request.m_minorChan && (tuningmode == "atsc"))
3634  {
3635  auto *atsc = dynamic_cast<ATSCStreamData*>(mpeg);
3636  if (atsc)
3637  atsc->SetDesiredChannel(request.m_majorChan, request.m_minorChan);
3638  }
3639  else if (request.m_progNum >= 0)
3640  {
3641  if (mpeg)
3642  mpeg->SetDesiredProgram(request.m_progNum);
3643  }
3644  }
3645 
3646  if (request.IsOnSameMultiplex())
3647  {
3648  // Update the channel number for SwitchLiveTVRingBuffer (called from
3649  // TuningRestartRecorder). This ensures that the livetvchain will be
3650  // updated with the new channel number
3651  if (m_channel)
3652  {
3654  m_channel->GetChannelName(), request.m_channel );
3655  }
3656 
3657  QStringList slist;
3658  slist<<"message"<<QObject::tr("On known multiplex...");
3659  MythEvent me(QString("SIGNAL %1").arg(m_inputId), slist);
3660  gCoreContext->dispatch(me);
3661 
3662  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3663  return;
3664  }
3665 
3666  QString channum = request.m_channel;
3667 
3668  bool ok1 = true;
3669  if (m_channel)
3670  {
3671  m_channel->Open();
3672  if (!channum.isEmpty())
3673  ok1 = m_channel->SetChannelByString(channum);
3674  else
3675  ok1 = false;
3676  }
3677 
3678  if (!ok1)
3679  {
3680  if (!(request.m_flags & kFlagLiveTV) || !(request.m_flags & kFlagEITScan))
3681  {
3682  if (m_curRecording)
3684 
3685  LOG(VB_GENERAL, LOG_ERR, LOC +
3686  QString("Failed to set channel to %1. Reverting to kState_None")
3687  .arg(channum));
3690  else
3692  return;
3693  }
3694 
3695  LOG(VB_GENERAL, LOG_ERR, LOC +
3696  QString("Failed to set channel to %1.").arg(channum));
3697  }
3698 
3699 
3700  bool mpts_only = GetDTVChannel() &&
3701  GetDTVChannel()->GetFormat().compare("MPTS") == 0;
3702  if (mpts_only)
3703  {
3704  // Not using a signal monitor, so just set the status to recording
3706  if (m_curRecording)
3707  {
3709  }
3710  }
3711 
3712 
3713  bool livetv = (request.m_flags & kFlagLiveTV) != 0U;
3714  bool antadj = (request.m_flags & kFlagAntennaAdjust) != 0U;
3715  bool use_sm = !mpts_only && SignalMonitor::IsRequired(m_genOpt.m_inputType);
3716  bool use_dr = use_sm && (livetv || antadj);
3717  bool has_dummy = false;
3718 
3719  if (use_dr)
3720  {
3721  // We need there to be a ringbuffer for these modes
3722  bool ok2 = false;
3724  m_pseudoLiveTVRecording = nullptr;
3725 
3726  m_tvChain->SetInputType("DUMMY");
3727 
3728  if (!m_buffer)
3729  ok2 = CreateLiveTVRingBuffer(channum);
3730  else
3731  ok2 = SwitchLiveTVRingBuffer(channum, true, false);
3733 
3735 
3736  if (!ok2)
3737  {
3738  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 1");
3739  return;
3740  }
3741 
3742  has_dummy = true;
3743  }
3744 
3745  // Start signal monitoring for devices capable of monitoring
3746  if (use_sm)
3747  {
3748  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Signal Monitor");
3749  bool error = false;
3750  if (!SetupSignalMonitor(
3751  !antadj, (request.m_flags & kFlagEITScan) != 0U, livetv || antadj))
3752  {
3753  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to setup signal monitor");
3754  if (m_signalMonitor)
3755  {
3756  delete m_signalMonitor;
3757  m_signalMonitor = nullptr;
3758  }
3759 
3760  // pretend the signal monitor is running to prevent segfault
3761  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3762  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3763  error = true;
3764  }
3765 
3766  if (m_signalMonitor)
3767  {
3768  if (request.m_flags & kFlagEITScan)
3769  {
3771  SetVideoStreamsRequired(0);
3773  }
3774 
3775  SetFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3776  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3777  if (!antadj)
3778  {
3779  QDateTime expire = MythDate::current();
3780 
3781  SetFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3782  if (m_curRecording)
3783  {
3785  // If startRecordingDeadline is passed, this
3786  // recording is marked as failed, so the scheduler
3787  // can try another showing.
3789  expire.addMSecs(m_genOpt.m_channelTimeout);
3791  expire.addMSecs(m_genOpt.m_channelTimeout * 2 / 3);
3792  // Keep trying to record this showing (even if it
3793  // has been marked as failed) until the scheduled
3794  // end time.
3796  m_curRecording->GetRecordingEndTime().addSecs(-10);
3797 
3798  LOG(VB_CHANNEL, LOG_DEBUG, LOC +
3799  QString("Pre-fail start deadline: %1 "
3800  "Start recording deadline: %2 "
3801  "Good signal deadline: %3")
3802  .arg(m_preFailDeadline.toLocalTime()
3803  .toString("hh:mm:ss.zzz"),
3804  m_startRecordingDeadline.toLocalTime()
3805  .toString("hh:mm:ss.zzz"),
3806  m_signalMonitorDeadline.toLocalTime()
3807  .toString("hh:mm:ss.zzz")));
3808  }
3809  else
3810  {
3812  expire.addMSecs(m_genOpt.m_channelTimeout);
3813  }
3815 
3816  //System Event TUNING_TIMEOUT deadline
3818  m_signalEventCmdSent = false;
3819  }
3820  }
3821 
3822  if (has_dummy && m_buffer)
3823  {
3824  // Make sure recorder doesn't point to bogus ringbuffer before
3825  // it is potentially restarted without a new ringbuffer, if
3826  // the next channel won't tune and the user exits LiveTV.
3827  if (m_recorder)
3828  m_recorder->SetRingBuffer(nullptr);
3829 
3830  SetFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
3831  LOG(VB_RECORD, LOG_INFO, "DummyDTVRecorder -- started");
3832  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
3833  }
3834 
3835  // if we had problems starting the signal monitor,
3836  // we don't want to start the recorder...
3837  if (error)
3838  return;
3839  }
3840 
3841  // Request a recorder, if the command is a recording command
3842  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3843  if (request.m_flags & kFlagRec && !antadj)
3844  SetFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3845 }
3846 
3855 {
3856  RecStatus::Type newRecStatus = RecStatus::Unknown;
3857  bool keep_trying = false;
3858  QDateTime current_time = MythDate::current();
3859 
3860  if ((m_signalMonitor->IsErrored() || current_time > m_signalEventCmdTimeout) &&
3862  {
3863  gCoreContext->SendSystemEvent(QString("TUNING_SIGNAL_TIMEOUT CARDID %1")
3864  .arg(m_inputId));
3865  m_signalEventCmdSent = true;
3866  }
3867 
3868  if (m_signalMonitor->IsAllGood())
3869  {
3870  LOG(VB_RECORD, LOG_INFO, LOC + "TuningSignalCheck: Good signal");
3871  if (m_curRecording && (current_time > m_startRecordingDeadline))
3872  {
3873  newRecStatus = RecStatus::Failing;
3874  m_curRecording->SaveVideoProperties(VID_DAMAGED, VID_DAMAGED);
3875 
3876  QString desc = tr("Good signal seen after %1 ms")
3877  .arg(m_genOpt.m_channelTimeout +
3878  m_startRecordingDeadline.msecsTo(current_time));
3879  QString title = m_curRecording->GetTitle();
3880  if (!m_curRecording->GetSubtitle().isEmpty())
3881  title += " - " + m_curRecording->GetSubtitle();
3882 
3884  "Recording", title,
3885  tr("See 'Tuning timeout' in mythtv-setup "
3886  "for this input."));
3887  gCoreContext->SendEvent(mn);
3888 
3889  LOG(VB_GENERAL, LOG_WARNING, LOC +
3890  QString("It took longer than %1 ms to get a signal lock. "
3891  "Keeping status of '%2'")
3893  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
3894  LOG(VB_GENERAL, LOG_WARNING, LOC +
3895  "See 'Tuning timeout' in mythtv-setup for this input");
3896  }
3897  else
3898  {
3899  newRecStatus = RecStatus::Recording;
3900  }
3901  }
3902  else if (m_signalMonitor->IsErrored() || current_time > m_signalMonitorDeadline)
3903  {
3904  LOG(VB_GENERAL, LOG_ERR, LOC + "TuningSignalCheck: SignalMonitor " +
3905  (m_signalMonitor->IsErrored() ? "failed" : "timed out"));
3906 
3907  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
3908  newRecStatus = RecStatus::Failed;
3909 
3911  {
3913  }
3914  }
3915  else if (m_curRecording && !m_reachedPreFail && current_time > m_preFailDeadline)
3916  {
3917  LOG(VB_GENERAL, LOG_ERR, LOC +
3918  "TuningSignalCheck: Hit pre-fail timeout");
3919  SendMythSystemRecEvent("REC_PREFAIL", m_curRecording);
3920  m_reachedPreFail = true;
3921  return nullptr;
3922  }
3924  current_time > m_startRecordingDeadline)
3925  {
3926  newRecStatus = RecStatus::Failing;
3928  keep_trying = true;
3929 
3930  SendMythSystemRecEvent("REC_FAILING", m_curRecording);
3931 
3932  QString desc = tr("Taking more than %1 ms to get a lock.")
3933  .arg(m_genOpt.m_channelTimeout);
3934  QString title = m_curRecording->GetTitle();
3935  if (!m_curRecording->GetSubtitle().isEmpty())
3936  title += " - " + m_curRecording->GetSubtitle();
3937 
3939  "Recording", title,
3940  tr("See 'Tuning timeout' in mythtv-setup "
3941  "for this input."));
3942  mn.SetDuration(30s);
3943  gCoreContext->SendEvent(mn);
3944 
3945  LOG(VB_GENERAL, LOG_WARNING, LOC +
3946  QString("TuningSignalCheck: taking more than %1 ms to get a lock. "
3947  "marking this recording as '%2'.")
3949  .arg(RecStatus::toString(newRecStatus, kSingleRecord)));
3950  LOG(VB_GENERAL, LOG_WARNING, LOC +
3951  "See 'Tuning timeout' in mythtv-setup for this input");
3952  }
3953  else
3954  {
3955  if (m_signalMonitorCheckCnt) // Don't flood log file
3957  else
3958  {
3959  LOG(VB_RECORD, LOG_INFO, LOC +
3960  QString("TuningSignalCheck: Still waiting. Will timeout @ %1")
3961  .arg(m_signalMonitorDeadline.toLocalTime()
3962  .toString("hh:mm:ss.zzz")));
3964  }
3965  return nullptr;
3966  }
3967 
3968  SetRecordingStatus(newRecStatus, __LINE__);
3969 
3970  if (m_curRecording)
3971  {
3972  m_curRecording->SetRecordingStatus(newRecStatus);
3973  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
3974  .arg(m_curRecording->GetInputID())
3975  .arg(m_curRecording->GetChanID())
3977  .arg(newRecStatus)
3979  gCoreContext->dispatch(me);
3980  }
3981 
3982  if (keep_trying)
3983  return nullptr;
3984 
3985  // grab useful data from DTV signal monitor before we kill it...
3986  MPEGStreamData *streamData = nullptr;
3987  if (GetDTVSignalMonitor())
3988  streamData = GetDTVSignalMonitor()->GetStreamData();
3989 
3991  {
3992  // shut down signal monitoring
3994  ClearFlags(kFlagSignalMonitorRunning, __FILE__, __LINE__);
3995  }
3996  ClearFlags(kFlagWaitingForSignal, __FILE__, __LINE__);
3997 
3998  if (streamData)
3999  {
4000  auto *dsd = dynamic_cast<DVBStreamData*>(streamData);
4001  if (dsd)
4003  if (!get_use_eit(GetInputId()))
4004  {
4005  LOG(VB_EIT, LOG_INFO, LOC +
4006  "EIT scanning disabled for all sources on this input.");
4007  }
4008  else if (m_scanner)
4010  }
4011 
4012  return streamData;
4013 }
4014 
4016  bool on_host, bool transcode_bfr_comm, bool on_line_comm)
4017 {
4018  if (!rec)
4019  return 0; // no jobs for Live TV recordings..
4020 
4021  int jobs = 0; // start with no jobs
4022 
4023  // grab standard jobs flags from program info
4025 
4026  // disable commercial flagging on PBS, BBC, etc.
4027  if (rec->IsCommercialFree())
4029 
4030  // disable transcoding if the profile does not allow auto transcoding
4031  const StandardSetting *autoTrans = profile.byName("autotranscode");
4032  if ((!autoTrans) || (autoTrans->getValue().toInt() == 0))
4034 
4035  bool ml = JobQueue::JobIsInMask(JOB_METADATA, jobs);
4036  if (ml)
4037  {
4038  // When allowed, metadata lookup should occur at the
4039  // start of a recording to make the additional info
4040  // available immediately (and for use in future jobs).
4041  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4043  rec->GetChanID(),
4044  rec->GetRecordingStartTime(), "", "",
4045  host, JOB_LIVE_REC);
4046 
4047  // don't do regular metadata lookup, we won't need it.
4049  }
4050 
4051  // is commercial flagging enabled, and is on-line comm flagging enabled?
4052  bool rt = JobQueue::JobIsInMask(JOB_COMMFLAG, jobs) && on_line_comm;
4053  // also, we either need transcoding to be disabled or
4054  // we need to be allowed to commercial flag before transcoding?
4055  rt &= JobQueue::JobIsNotInMask(JOB_TRANSCODE, jobs) ||
4056  !transcode_bfr_comm;
4057  if (rt)
4058  {
4059  // queue up real-time (i.e. on-line) commercial flagging.
4060  QString host = (on_host) ? gCoreContext->GetHostName() : "";
4062  rec->GetChanID(),
4063  rec->GetRecordingStartTime(), "", "",
4064  host, JOB_LIVE_REC);
4065 
4066  // don't do regular comm flagging, we won't need it.
4068  }
4069 
4070  return jobs;
4071 }
4072 
4073 QString TVRec::LoadProfile(void *tvchain, RecordingInfo *rec,
4074  RecordingProfile &profile) const
4075 {
4076  // Determine the correct recording profile.
4077  // In LiveTV mode use "Live TV" profile, otherwise use the
4078  // recording's specified profile. If the desired profile can't
4079  // be found, fall back to the "Default" profile for input type.
4080  QString profileName = "Live TV";
4081  if (!tvchain && rec)
4082  profileName = rec->GetRecordingRule()->m_recProfile;
4083 
4084  QString profileRequested = profileName;
4085 
4086  if (profile.loadByType(profileName, m_genOpt.m_inputType,
4088  {
4089  LOG(VB_RECORD, LOG_INFO, LOC +
4090  QString("Using profile '%1' to record")
4091  .arg(profileName));
4092  }
4093  else
4094  {
4095  profileName = "Default";
4096  if (profile.loadByType(profileName, m_genOpt.m_inputType, m_genOpt.m_videoDev))
4097  {
4098  LOG(VB_RECORD, LOG_INFO, LOC +
4099  QString("Profile '%1' not found, using "
4100  "fallback profile '%2' to record")
4101  .arg(profileRequested, profileName));
4102  }
4103  else
4104  {
4105  LOG(VB_RECORD, LOG_ERR, LOC +
4106  QString("Profile '%1' not found, and unable "
4107  "to load fallback profile '%2'. Results "
4108  "may be unpredicable")
4109  .arg(profileRequested, profileName));
4110  }
4111  }
4112 
4113  return profileName;
4114 }
4115 
4120 {
4121  LOG(VB_RECORD, LOG_INFO, LOC + "Starting Recorder");
4122 
4123  bool had_dummyrec = false;
4125  {
4127  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4129  had_dummyrec = true;
4130  }
4131 
4133 
4136 
4137  if (m_tvChain)
4138  {
4139  bool ok = false;
4140  if (!m_buffer)
4141  {
4143  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4144  }
4145  else
4147  true, !had_dummyrec && m_recorder);
4148  if (!ok)
4149  {
4150  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create RingBuffer 2");
4151  goto err_ret;
4152  }
4153  rec = m_curRecording; // new'd in Create/SwitchLiveTVRingBuffer()
4154  }
4155 
4157  {
4158  bool write = m_genOpt.m_inputType != "IMPORT";
4159  LOG(VB_GENERAL, LOG_INFO, LOC + QString("rec->GetPathname(): '%1'")
4160  .arg(rec->GetPathname()));
4162  if (!m_buffer->IsOpen() && write)
4163  {
4164  LOG(VB_GENERAL, LOG_ERR, LOC +
4165  QString("RingBuffer '%1' not open...")
4166  .arg(rec->GetPathname()));
4167  SetRingBuffer(nullptr);
4168  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4169  goto err_ret;
4170  }
4171  }
4172 
4173  if (!m_buffer)
4174  {
4175  LOG(VB_GENERAL, LOG_ERR, LOC +
4176  QString("Failed to start recorder! ringBuffer is NULL\n"
4177  "\t\t\t\t Tuning request was %1\n")
4178  .arg(m_lastTuningRequest.toString()));
4179 
4180  if (HasFlags(kFlagLiveTV))
4181  {
4182  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4183  MythEvent me(message);
4184  gCoreContext->dispatch(me);
4185  }
4186  goto err_ret;
4187  }
4188 
4189  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4190  m_channel->Close(); // Needed because of NVR::MJPEGInit()
4191 
4192  LOG(VB_GENERAL, LOG_INFO, LOC + "TuningNewRecorder - CreateRecorder()");
4194 
4195  if (m_recorder)
4196  {
4199  if (m_recorder->IsErrored())
4200  {
4201  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialize recorder!");
4202  delete m_recorder;
4203  m_recorder = nullptr;
4204  }
4205  }
4206 
4207  if (!m_recorder)
4208  {
4209  LOG(VB_GENERAL, LOG_ERR, LOC +
4210  QString("Failed to start recorder!\n"
4211  "\t\t\t\t Tuning request was %1\n")
4212  .arg(m_lastTuningRequest.toString()));
4213 
4214  if (HasFlags(kFlagLiveTV))
4215  {
4216  QString message = QString("QUIT_LIVETV %1").arg(m_inputId);
4217  MythEvent me(message);
4218  gCoreContext->dispatch(me);
4219  }
4221  goto err_ret;
4222  }
4223 
4224  if (rec)
4225  m_recorder->SetRecording(rec);
4226 
4227  if (GetDTVRecorder() && streamData)
4228  {
4229  const StandardSetting *setting = profile.byName("recordingtype");
4230  if (setting)
4231  streamData->SetRecordingType(setting->getValue());
4232  GetDTVRecorder()->SetStreamData(streamData);
4233  }
4234 
4235  if (m_channel && m_genOpt.m_inputType == "MJPEG")
4236  m_channel->Open(); // Needed because of NVR::MJPEGInit()
4237 
4238  // Setup for framebuffer capture devices..
4239  if (m_channel)
4240  {
4243  }
4244 
4245  if (GetV4LChannel())
4246  {
4248  CloseChannel();
4249  }
4250 
4251  m_recorderThread = new MThread("RecThread", m_recorder);
4253 
4254  // Wait for recorder to start.
4255  m_stateChangeLock.unlock();
4256  while (!m_recorder->IsRecording() && !m_recorder->IsErrored())
4257  std::this_thread::sleep_for(5us);
4258  m_stateChangeLock.lock();
4259 
4260  if (GetV4LChannel())
4262 
4263  SetFlags(kFlagRecorderRunning | kFlagRingBufferReady, __FILE__, __LINE__);
4264 
4265  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4266 
4267  //workaround for failed import recordings, no signal monitor means we never
4268  //go to recording state and the status here seems to override the status
4269  //set in the importrecorder and backend via setrecordingstatus
4270  if (m_genOpt.m_inputType == "IMPORT")
4271  {
4273  if (m_curRecording)
4275  }
4276  return;
4277 
4278  err_ret:
4279  SetRecordingStatus(RecStatus::Failed, __LINE__, true);
4281 
4282  if (rec)
4283  {
4284  // Make sure the scheduler knows...
4286  LOG(VB_RECORD, LOG_INFO, LOC +
4287  QString("TuningNewRecorder -- UPDATE_RECORDING_STATUS: %1")
4289  MythEvent me(QString("UPDATE_RECORDING_STATUS %1 %2 %3 %4 %5")
4290  .arg(rec->GetInputID())
4291  .arg(rec->GetChanID())
4293  .arg(RecStatus::Failed)
4295  gCoreContext->dispatch(me);
4296  }
4297 
4298  if (m_tvChain)
4299  delete rec;
4300 }
4301 
4306 {
4307  LOG(VB_RECORD, LOG_INFO, LOC + "Restarting Recorder");
4308 
4309  bool had_dummyrec = false;
4310 
4311  if (m_curRecording)
4312  {
4315  }
4316 
4318  {
4319  ClearFlags(kFlagDummyRecorderRunning, __FILE__, __LINE__);
4320  had_dummyrec = true;
4321  }
4322 
4323  SwitchLiveTVRingBuffer(m_channel->GetChannelName(), true, !had_dummyrec);
4324 
4325  if (had_dummyrec)
4326  {
4328  ProgramInfo *progInfo = m_tvChain->GetProgramAt(-1);
4329  RecordingInfo recinfo(*progInfo);
4330  delete progInfo;
4331  recinfo.SetInputID(m_inputId);
4332  m_recorder->SetRecording(&recinfo);
4333  }
4334  m_recorder->Reset();
4335 
4336  // Set file descriptor of channel from recorder for V4L
4337  if (GetV4LChannel())
4339 
4340  // Some recorders unpause on Reset, others do not...
4341  m_recorder->Unpause();
4342 
4344  {
4346  QString msg1 = QString("Recording: %1 %2 %3 %4")
4347  .arg(rcinfo1->GetTitle(), QString::number(rcinfo1->GetChanID()),
4350  ProgramInfo *rcinfo2 = m_tvChain->GetProgramAt(-1);
4351  QString msg2 = QString("Recording: %1 %2 %3 %4")
4352  .arg(rcinfo2->GetTitle(), QString::number(rcinfo2->GetChanID()),
4355  delete rcinfo2;
4356  LOG(VB_RECORD, LOG_INFO, LOC + "Pseudo LiveTV recording starting." +
4357  "\n\t\t\t" + msg1 + "\n\t\t\t" + msg2);
4358 
4361 
4363 
4364  InitAutoRunJobs(m_curRecording, kAutoRunProfile, nullptr, __LINE__);
4365  }
4366 
4367  ClearFlags(kFlagNeedToStartRecorder, __FILE__, __LINE__);
4368 }
4369 
4370 void TVRec::SetFlags(uint f, const QString & file, int line)
4371 {
4372  QMutexLocker lock(&m_stateChangeLock);
4373  m_stateFlags |= f;
4374  LOG(VB_RECORD, LOG_INFO, LOC + QString("SetFlags(%1) -> %2 @ %3:%4")
4375  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4376  WakeEventLoop();
4377 }
4378 
4379 void TVRec::ClearFlags(uint f, const QString & file, int line)
4380 {
4381  QMutexLocker lock(&m_stateChangeLock);
4382  m_stateFlags &= ~f;
4383  LOG(VB_RECORD, LOG_INFO, LOC + QString("ClearFlags(%1) -> %2 @ %3:%4")
4384  .arg(FlagToString(f), FlagToString(m_stateFlags), file, QString::number(line)));
4385  WakeEventLoop();
4386 }
4387 
4389 {
4390  QString msg("");
4391 
4392  // General flags
4393  if (kFlagFrontendReady & f)
4394  msg += "FrontendReady,";
4395  if (kFlagRunMainLoop & f)
4396  msg += "RunMainLoop,";
4397  if (kFlagExitPlayer & f)
4398  msg += "ExitPlayer,";
4399  if (kFlagFinishRecording & f)
4400  msg += "FinishRecording,";
4401  if (kFlagErrored & f)
4402  msg += "Errored,";
4403  if (kFlagCancelNextRecording & f)
4404  msg += "CancelNextRecording,";
4405 
4406  // Tuning flags
4407  if ((kFlagRec & f) == kFlagRec)
4408  msg += "REC,";
4409  else
4410  {
4411  if (kFlagLiveTV & f)
4412  msg += "LiveTV,";
4413  if (kFlagRecording & f)
4414  msg += "Recording,";
4415  }
4416  if ((kFlagNoRec & f) == kFlagNoRec)
4417  msg += "NOREC,";
4418  else
4419  {
4420  if (kFlagEITScan & f)
4421  msg += "EITScan,";
4422  if (kFlagCloseRec & f)
4423  msg += "CloseRec,";
4424  if (kFlagKillRec & f)
4425  msg += "KillRec,";
4426  if (kFlagAntennaAdjust & f)
4427  msg += "AntennaAdjust,";
4428  }
4430  msg += "PENDINGACTIONS,";
4431  else
4432  {
4433  if (kFlagWaitingForRecPause & f)
4434  msg += "WaitingForRecPause,";
4435  if (kFlagWaitingForSignal & f)
4436  msg += "WaitingForSignal,";
4437  if (kFlagNeedToStartRecorder & f)
4438  msg += "NeedToStartRecorder,";
4439  if (kFlagKillRingBuffer & f)
4440  msg += "KillRingBuffer,";
4441  }
4442  if ((kFlagAnyRunning & f) == kFlagAnyRunning)
4443  msg += "ANYRUNNING,";
4444  else
4445  {
4446  if (kFlagSignalMonitorRunning & f)
4447  msg += "SignalMonitorRunning,";
4448  if (kFlagEITScannerRunning & f)
4449  msg += "EITScannerRunning,";
4451  msg += "ANYRECRUNNING,";
4452  else
4453  {
4454  if (kFlagDummyRecorderRunning & f)
4455  msg += "DummyRecorderRunning,";
4456  if (kFlagRecorderRunning & f)
4457  msg += "RecorderRunning,";
4458  }
4459  }
4460  if (kFlagRingBufferReady & f)
4461  msg += "RingBufferReady,";
4462 
4463  if (msg.isEmpty())
4464  msg = QString("0x%1").arg(f,0,16);
4465 
4466  return msg;
4467 }
4468 
4470 {
4471  QMutexLocker lock(&m_nextLiveTVDirLock);
4472 
4473  bool found = !m_nextLiveTVDir.isEmpty();
4474  if (!found && m_triggerLiveTVDir.wait(&m_nextLiveTVDirLock, 500))
4475  {
4476  found = !m_nextLiveTVDir.isEmpty();
4477  }
4478 
4479  return found;
4480 }
4481 
4482 void TVRec::SetNextLiveTVDir(QString dir)
4483 {
4484  QMutexLocker lock(&m_nextLiveTVDirLock);
4485 
4486  m_nextLiveTVDir = std::move(dir);
4487  m_triggerLiveTVDir.wakeAll();
4488 }
4489 
4492  const QString & channum)
4493 {
4494  LOG(VB_RECORD, LOG_INFO, LOC + "GetProgramRingBufferForLiveTV()");
4495  if (!m_channel || !m_tvChain || !pginfo || !Buffer)
4496  return false;
4497 
4498  m_nextLiveTVDirLock.lock();
4499  m_nextLiveTVDir.clear();
4500  m_nextLiveTVDirLock.unlock();
4501 
4502  // Dispatch this early, the response can take a while.
4503  MythEvent me(QString("QUERY_NEXT_LIVETV_DIR %1").arg(m_inputId));
4504  gCoreContext->dispatch(me);
4505 
4506  uint sourceid = m_channel->GetSourceID();
4507  int chanid = ChannelUtil::GetChanID(sourceid, channum);
4508 
4509  if (chanid < 0)
4510  {
4511  // Test setups might have zero channels
4512  if (m_genOpt.m_inputType == "IMPORT" || m_genOpt.m_inputType == "DEMO")
4513  chanid = 9999;
4514  else
4515  {
4516  LOG(VB_GENERAL, LOG_ERR, LOC +
4517  QString("Channel: \'%1\' was not found in the database.\n"
4518  "\t\tMost likely, the 'starting channel' for this "
4519  "Input Connection is invalid.\n"
4520  "\t\tCould not start livetv.").arg(channum));
4521  return false;
4522  }
4523  }
4524 
4525  auto hoursMax =
4526  gCoreContext->GetDurSetting<std::chrono::hours>("MaxHoursPerLiveTVRecording", 8h);
4527  if (hoursMax <= 0h)
4528  hoursMax = 8h;
4529 
4530  RecordingInfo *prog = nullptr;
4533  else
4534  {
4535  prog = new RecordingInfo(
4536  chanid, MythDate::current(true), true, hoursMax);
4537  }
4538 
4539  prog->SetInputID(m_inputId);
4540 
4541  if (prog->GetRecordingStartTime() == prog->GetRecordingEndTime())
4542  {
4543  LOG(VB_GENERAL, LOG_ERR, LOC + "GetProgramRingBufferForLiveTV()"
4544  "\n\t\t\tProgramInfo is invalid."
4545  "\n" + prog->toString());
4546  prog->SetScheduledEndTime(prog->GetRecordingStartTime().addSecs(3600));
4548 
4549  prog->SetChanID(chanid);
4550  }
4551 
4554 
4555  prog->SetStorageGroup("LiveTV");
4556 
4557  if (WaitForNextLiveTVDir())
4558  {
4559  QMutexLocker lock(&m_nextLiveTVDirLock);
4561  }
4562  else
4563  {
4564  StorageGroup sgroup("LiveTV", gCoreContext->GetHostName());
4565  prog->SetPathname(sgroup.FindNextDirMostFree());
4566  }
4567 
4569  prog->SetRecordingGroup("LiveTV");
4570 
4571  StartedRecording(prog);
4572 
4573  *Buffer = MythMediaBuffer::Create(prog->GetPathname(), true);
4574  if (!(*Buffer) || !(*Buffer)->IsOpen())
4575  {
4576  LOG(VB_GENERAL, LOG_ERR, LOC + QString("RingBuffer '%1' not open...")
4577  .arg(prog->GetPathname()));
4578 
4579  delete *Buffer;
4580  delete prog;
4581 
4582  return false;
4583  }
4584 
4585  *pginfo = prog;
4586  return true;
4587 }
4588 
4589 bool TVRec::CreateLiveTVRingBuffer(const QString & channum)
4590 {
4591  LOG(VB_RECORD, LOG_INFO, LOC + QString("CreateLiveTVRingBuffer(%1)")
4592  .arg(channum));
4593 
4594  RecordingInfo *pginfo = nullptr;
4595  MythMediaBuffer *buffer = nullptr;
4596 
4597  if (!m_channel ||
4598  !m_channel->CheckChannel(channum))
4599  {
4601  return false;
4602  }
4603 
4604  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4605  {
4606  ClearFlags(kFlagPendingActions, __FILE__, __LINE__);
4608  LOG(VB_GENERAL, LOG_ERR, LOC +
4609  QString("CreateLiveTVRingBuffer(%1) failed").arg(channum));
4610  return false;
4611  }
4612 
4613  SetRingBuffer(buffer);
4614 
4618 
4619  bool discont = (m_tvChain->TotalSize() > 0);
4621  m_channel->GetInputName(), discont);
4622 
4623  if (m_curRecording)
4624  {
4626  delete m_curRecording;
4627  }
4628 
4629  m_curRecording = pginfo;
4631 
4632  return true;
4633 }
4634 
4635 bool TVRec::SwitchLiveTVRingBuffer(const QString & channum,
4636  bool discont, bool set_rec)
4637 {
4638  QString msg;
4639  if (m_curRecording)
4640  {
4641  msg = QString(" curRec(%1) curRec.size(%2)")
4642  .arg(m_curRecording->MakeUniqueKey())
4643  .arg(m_curRecording->GetFilesize());
4644  }
4645  LOG(VB_RECORD, LOG_INFO, LOC +
4646  QString("SwitchLiveTVRingBuffer(discont %1, set_next_rec %2)")
4647  .arg(discont).arg(set_rec) + msg);
4648 
4649  RecordingInfo *pginfo = nullptr;
4650  MythMediaBuffer *buffer = nullptr;
4651 
4652  if (!m_channel ||
4653  !m_channel->CheckChannel(channum))
4654  {
4656  return false;
4657  }
4658 
4659  if (!GetProgramRingBufferForLiveTV(&pginfo, &buffer, channum))
4660  {
4662  return false;
4663  }
4664 
4665  QString oldinputtype = m_tvChain->GetInputType(-1);
4666 
4667  pginfo->MarkAsInUse(true, kRecorderInUseID);
4672  m_channel->GetInputName(), discont);
4673 
4674  if (set_rec && m_recorder)
4675  {
4676  m_recorder->SetNextRecording(pginfo, buffer);
4677  if (discont)
4679  delete pginfo;
4680  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4681  }
4682  else if (!set_rec)
4683  {
4684  // dummy recordings are finished before this
4685  // is called and other recordings must be finished..
4686  if (m_curRecording && oldinputtype != "DUMMY")
4687  {
4690  delete m_curRecording;
4691  }
4692  m_curRecording = pginfo;
4693  SetRingBuffer(buffer);
4694  }
4695  else
4696  {
4697  delete buffer;
4698  }
4699 
4700  return true;
4701 }
4702 
4704 {
4705  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer()");
4706 
4707  if (m_switchingBuffer)
4708  {
4709  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4710  "already switching.");
4711  return nullptr;
4712  }
4713 
4714  if (!m_recorder)
4715  {
4716  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4717  "invalid recorder.");
4718  return nullptr;
4719  }
4720 
4721  if (!m_curRecording)
4722  {
4723  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4724  "invalid recording.");
4725  return nullptr;
4726  }
4727 
4728  if (rcinfo.GetChanID() != m_curRecording->GetChanID())
4729  {
4730  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer -> "
4731  "Not the same channel.");
4732  return nullptr;
4733  }
4734 
4735  auto *ri = new RecordingInfo(rcinfo);
4737 
4738  QString pn = LoadProfile(nullptr, ri, profile);
4739 
4740  if (pn != m_recProfileName)
4741  {
4742  LOG(VB_RECORD, LOG_ERR, LOC +
4743  QString("SwitchRecordingRingBuffer() -> "
4744  "cannot switch profile '%1' to '%2'")
4745  .arg(m_recProfileName, pn));
4746  return nullptr;
4747  }
4748 
4750 
4751  ri->MarkAsInUse(true, kRecorderInUseID);
4752  StartedRecording(ri);
4753 
4754  bool write = m_genOpt.m_inputType != "IMPORT";
4755  MythMediaBuffer *buffer = MythMediaBuffer::Create(ri->GetPathname(), write);
4756  if (!buffer || !buffer->IsOpen())
4757  {
4758  delete buffer;
4759  ri->SetRecordingStatus(RecStatus::Failed);
4760  FinishedRecording(ri, nullptr);
4761  ri->MarkAsInUse(false, kRecorderInUseID);
4762  delete ri;
4763  LOG(VB_RECORD, LOG_ERR, LOC + "SwitchRecordingRingBuffer() -> "
4764  "Failed to create new RB.");
4765  return nullptr;
4766  }
4767 
4768  m_recorder->SetNextRecording(ri, buffer);
4769  SetFlags(kFlagRingBufferReady, __FILE__, __LINE__);
4771  m_switchingBuffer = true;
4772  ri->SetRecordingStatus(RecStatus::Recording);
4773  LOG(VB_RECORD, LOG_INFO, LOC + "SwitchRecordingRingBuffer -> done");
4774  return ri;
4775 }
4776 
4778 {
4779  QMap<uint,TVRec*>::const_iterator it = s_inputs.constFind(inputid);
4780  if (it == s_inputs.constEnd())
4781  return nullptr;
4782  return *it;
4783 }
4784 
4785 QString TuningRequest::toString(void) const
4786 {
4787  return QString("Program(%1) channel(%2) input(%3) flags(%4)")
4788  .arg((m_program == nullptr) ? QString("NULL") : m_program->toString(),
4790 }
4791 
4792 #ifdef USING_DVB
4793 #include "recorders/dvbchannel.h"
4795 {
4796  // Some DVB devices munge the PMT and/or PAT so the CRC check fails.
4797  // We need to tell the stream data class to not check the CRC on
4798  // these devices. This can cause segfaults.
4799  auto * dvb = dynamic_cast<DVBChannel*>(c);
4800  if (dvb != nullptr)
4801  s->SetIgnoreCRC(dvb->HasCRCBug());
4802 }
4803 #else
4805 #endif // USING_DVB
4806 
4807 /* vim: set expandtab tabstop=4 shiftwidth=4: */
GeneralDBOptions
Definition: tv_rec.h:67
TVRec::CreateLiveTVRingBuffer
bool CreateLiveTVRingBuffer(const QString &channum)
Definition: tv_rec.cpp:4589
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:216
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: recordingstatus.h:16
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
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:4370
TVRec::GetKeyframeDurations
bool GetKeyframeDurations(int64_t start, int64_t end, frm_pos_map_t &map) const
Definition: tv_rec.cpp:2578
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:2425
mpeg
Definition: mythchrono.h:51
ProgramInfo::MakeUniqueKey
QString MakeUniqueKey(void) const
Creates a unique string that can be used to identify an existing recording.
Definition: programinfo.h:339
TVRec::m_runJobOnHostOnly
bool m_runJobOnHostOnly
Definition: tv_rec.h:361
PendingInfo::m_possibleConflicts
std::vector< uint > m_possibleConflicts
Definition: tv_rec.h:140
ChannelBase::Init
virtual bool Init(QString &startchannel, bool setchan)
Definition: channelbase.cpp:66
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
MSqlQuery::size
int size(void) const
Definition: mythdbcon.h:215
TVRec::kFlagNoRec
static const uint kFlagNoRec
Definition: tv_rec.h:464
TVRec::RecordPending
void RecordPending(const ProgramInfo *rcinfo, std::chrono::seconds secsleft, bool hasLater)
Tells TVRec "rcinfo" is the next pending recording.
Definition: tv_rec.cpp:300
TVRec::kFlagErrored
static const uint kFlagErrored
Definition: tv_rec.h:444
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
TVRec::m_startRecordingDeadline
QDateTime m_startRecordingDeadline
Definition: tv_rec.h:345
TVRec::m_channel
ChannelBase * m_channel
Definition: tv_rec.h:338
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:204
TVRec::kFlagEITScannerRunning
static const uint kFlagEITScannerRunning
Definition: tv_rec.h:475
RecordingInfo::FinishedRecording
void FinishedRecording(bool allowReRecord)
If not a premature stop, adds program to history of recorded programs.
Definition: recordinginfo.cpp:1271
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:200
TVRec::SetPseudoLiveTVRecording
void SetPseudoLiveTVRecording(RecordingInfo *pi)
Sets the pseudo LiveTV RecordingInfo.
Definition: tv_rec.cpp:352
MPEGStreamData::SetVideoStreamsRequired
void SetVideoStreamsRequired(uint num)
Definition: mpegstreamdata.h:249
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:103
EITScanner::StopEITEventProcessing
void StopEITEventProcessing(void)
Stops inserting Event Information Tables into DB.
Definition: eitscanner.cpp:215
TVRec::WaitForEventThreadSleep
bool WaitForEventThreadSleep(bool wake=true, std::chrono::milliseconds time=std::chrono::milliseconds::max())
Definition: tv_rec.cpp:1557
error
static void error(const char *str,...)
Definition: vbi.cpp:36
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
ProgramInfo::SetRecordingStatus
void SetRecordingStatus(RecStatus::Type status)
Definition: programinfo.h:580
CHANNEL_DIRECTION_DOWN
@ CHANNEL_DIRECTION_DOWN
Definition: tv.h:31
dtvrecorder.h
ProgramInfo::QueryMplexID
uint QueryMplexID(void) const
Queries multiplex any recording would be made on, zero if unknown.
Definition: programinfo.cpp:2652
TVRec::m_recProfileName
QString m_recProfileName
Definition: tv_rec.h:379
ChannelChangeDirection
ChannelChangeDirection
ChannelChangeDirection is an enumeration of possible channel changing directions.
Definition: tv.h:28
TVRec::m_audioSampleRateDB
int m_audioSampleRateDB
Definition: tv_rec.h:364
mythdb.h
RecorderBase::CreateRecorder
static RecorderBase * CreateRecorder(TVRec *tvrec, ChannelBase *channel, RecordingProfile &profile, const GeneralDBOptions &genOpt)
Definition: recorderbase.cpp:852
TVRec::ShouldSwitchToAnotherInput
bool ShouldSwitchToAnotherInput(const QString &chanid) const
Checks if named channel exists on current tuner, or another tuner.
Definition: tv_rec.cpp:2134
TVRec::kFlagRecording
static const uint kFlagRecording
final result desired is a timed recording
Definition: tv_rec.h:451
mythrandom.h
RecordingRule::Save
bool Save(bool sendSig=true)
Definition: recordingrule.cpp:388
SignalMonitor::IsAllGood
virtual bool IsAllGood(void) const
Definition: signalmonitor.h:83
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:513
CardUtil::GetInputName
static QString GetInputName(uint inputid)
Definition: cardutil.cpp:1732
MythTimer
A QElapsedTimer based timer to replace use of QTime as a timer.
Definition: mythtimer.h:13
TVRec::m_triggerEventSleepLock
QMutex m_triggerEventSleepLock
Definition: tv_rec.h:401
ChannelBase::Open
virtual bool Open(void)=0
Opens the channel changing hardware for use.
TVRec::m_tuningRequests
TuningQueue m_tuningRequests
Definition: tv_rec.h:395
RemoteGetState
uint RemoteGetState(uint inputid)
Definition: tvremoteutil.cpp:31
ChannelBase::GetInputName
virtual QString GetInputName(void) const
Definition: channelbase.h:69
kRecorderInUseID
const QString kRecorderInUseID
Definition: programtypes.cpp:20
MythNotification::SetDuration
void SetDuration(std::chrono::seconds Duration)
Contains a duration during which the notification will be displayed for. The duration is informative ...
Definition: mythnotification.cpp:136
RecordingInfo::ApplyRecordRecID
void ApplyRecordRecID(void)
Sets recordid to match RecordingRule recordid.
Definition: recordinginfo.cpp:538
PictureAdjustType
PictureAdjustType
Definition: tv.h:120
MPEGStreamData::SetCaching
void SetCaching(bool cacheTables)
Definition: mpegstreamdata.h:91
ProgramInfo::SetRecordingID
virtual void SetRecordingID(uint _recordedid)
Definition: programinfo.h:578
TVRec::Init
bool Init(void)
Performs instance initialization, returns true on success.
Definition: tv_rec.cpp:155
SignalMonitor::IsSupported
static bool IsSupported(const QString &cardtype)
Definition: signalmonitor.h:321
MythMediaBuffer::StopReads
void StopReads(void)
Definition: mythmediabuffer.cpp:663
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
eitscanner.h
RecStatus::Tuning
@ Tuning
Definition: recordingstatus.h: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:2436
pid_cache_item_t
Definition: channelutil.h:24
EITScanner::StartEITEventProcessing
void StartEITEventProcessing(ChannelBase *channel, EITSource *eitSource)
Start inserting Event Information Tables from the multiplex we happen to be tuned to into the databas...
Definition: eitscanner.cpp:183
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:2906
GeneralDBOptions::m_signalTimeout
uint m_signalTimeout
Definition: tv_rec.h:78
TVRec::m_eitTransportTimeout
std::chrono::seconds m_eitTransportTimeout
Definition: tv_rec.h:363
RecordingInfo::GetFilesize
uint64_t GetFilesize(void) const override
Definition: recordinginfo.cpp:1757
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:4528
RecorderBase::Unpause
virtual void Unpause(void)
Unpause tells recorder to unpause.
Definition: recorderbase.cpp:274
TVRec::kFlagRingBufferReady
static const uint kFlagRingBufferReady
Definition: tv_rec.h:483
ProgramInfo::GetRecordingID
uint GetRecordingID(void) const
Definition: programinfo.h:446
MythMediaBuffer::GetWritePosition
long long GetWritePosition(void) const
Returns how far into a ThreadedFileWriter file we have written.
Definition: mythmediabuffer.cpp:1787
TVRec::m_buffer
MythMediaBuffer * m_buffer
Definition: tv_rec.h:428
RecorderBase::IsErrored
virtual bool IsErrored(void)=0
Tells us whether an unrecoverable error has been encountered.
LiveTVChain::GetID
QString GetID(void) const
Definition: livetvchain.h:56
TVRec::m_triggerLiveTVDir
QWaitCondition m_triggerLiveTVDir
Definition: tv_rec.h:421
RecStatus::Cancelled
@ Cancelled
Definition: recordingstatus.h:26
TVRec::m_eventThread
MThread * m_eventThread
Event processing thread, runs TVRec::run().
Definition: tv_rec.h:354
TVRec::kFlagRecorderRunning
static const uint kFlagRecorderRunning
Definition: tv_rec.h:478
GeneralDBOptions::m_inputType
QString m_inputType
Definition: tv_rec.h:75
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
TVRec::kFlagRec
static const uint kFlagRec
Definition: tv_rec.h:454
JOB_COMMFLAG
@ JOB_COMMFLAG
Definition: jobqueue.h:81
ProgramInfo::kTitleSubtitle
@ kTitleSubtitle
Definition: programinfo.h:509
TVRec::m_recStatus
RecStatus::Type m_recStatus
Definition: tv_rec.h:405
ChannelUtil::GetATSCChannel
static bool GetATSCChannel(uint sourceid, const QString &channum, uint &major, uint &minor)
Definition: channelutil.cpp:1854
TVRec::SetInput
QString SetInput(QString input)
Changes to the specified input.
Definition: tv_rec.cpp:3014
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:183
TVRec::GetSourceID
uint GetSourceID(void) const
Returns current source id.
Definition: tv_rec.cpp:2999
JobQueue::QueueRecordingJobs
static bool QueueRecordingJobs(const RecordingInfo &recinfo, int jobTypes=JOB_NONE)
Definition: jobqueue.cpp:491
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:205
TVRec::m_overRecordCategory
QString m_overRecordCategory
Definition: tv_rec.h:367
PendingInfo::m_hasLaterShowing
bool m_hasLaterShowing
Definition: tv_rec.h:136
ProgramInfo::GetCategory
QString GetCategory(void) const
Definition: programinfo.h:369
RecStatus::TunerBusy
@ TunerBusy
Definition: recordingstatus.h:24
DTVRecorder::SetStreamData
virtual void SetStreamData(MPEGStreamData *data)
Definition: dtvrecorder.cpp:218
TVRec::GetProgramRingBufferForLiveTV
bool GetProgramRingBufferForLiveTV(RecordingInfo **pginfo, MythMediaBuffer **Buffer, const QString &channum)
Definition: tv_rec.cpp:4490
JOB_NONE
@ JOB_NONE
Definition: jobqueue.h:77
PendingInfo::m_info
ProgramInfo * m_info
Definition: tv_rec.h:134
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: recordingstatus.h:32
apply_broken_dvb_driver_crc_hack
static void apply_broken_dvb_driver_crc_hack(ChannelBase *, MPEGStreamData *)
Definition: tv_rec.cpp:4794
TuningRequest::toString
QString toString(void) const
Definition: tv_rec.cpp:4785
RecordingRule::m_endOffset
int m_endOffset
Definition: recordingrule.h:110
ChannelBase::CreateChannel
static ChannelBase * CreateChannel(TVRec *tvrec, const GeneralDBOptions &genOpt, const DVBDBOptions &dvbOpt, const FireWireDBOptions &fwOpt, const QString &startchannel, bool enter_power_save_mode, QString &rbFileExt, bool setchan)
Definition: channelbase.cpp:698
DTVSignalMonitor::GetStreamData
MPEGStreamData * GetStreamData()
Returns the MPEG stream data if it exists.
Definition: dtvsignalmonitor.h:59
LiveTVChain::TotalSize
int TotalSize(void) const
Definition: livetvchain.cpp:388
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:608
osd.h
atscstreamdata.h
TVRec::m_curRecording
RecordingInfo * m_curRecording
Definition: tv_rec.h:408
ProgramInfo::SaveCommFlagged
void SaveCommFlagged(CommFlagStatus flag)
Set "commflagged" field in "recorded" table to "flag".
Definition: programinfo.cpp:3341
RecStatus::Recorded
@ Recorded
Definition: recordingstatus.h:29
TVRec::StopRecording
void StopRecording(bool killFile=false)
Changes from a recording state to kState_None.
Definition: tv_rec.cpp:735
RecorderBase::GetKeyframePositions
bool GetKeyframePositions(long long start, long long end, frm_pos_map_t &map) const
Definition: recorderbase.cpp:540
MythMediaBuffer
Definition: mythmediabuffer.h:50
DTVChannel::GetFormat
QString GetFormat(void)
Definition: dtvchannel.h:46
MythTimer::start
void start(void)
starts measuring elapsed time.
Definition: mythtimer.cpp:47
ProgramInfo::GetScheduledEndTime
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:397
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
FireWireDBOptions::m_speed
int m_speed
Definition: tv_rec.h:98
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:2519
TVRec::GetDevices
static bool GetDevices(uint inputid, uint &parentid, GeneralDBOptions &gen_opts, DVBDBOptions &dvb_opts, FireWireDBOptions &firewire_opts)
Definition: tv_rec.cpp:1672
channelbase.h
TableID::CVCT
@ CVCT
Definition: mpegtables.h:363
ProgramInfo::UpdateInUseMark
void UpdateInUseMark(bool force=false)
Definition: programinfo.cpp:4882
TVRec::GetInput
QString GetInput(void) const
Returns current input.
Definition: tv_rec.cpp:2989
ChannelUtil::GetMplexID
static uint GetMplexID(uint sourceid, const QString &channum)
Definition: channelutil.cpp:460
TVRec::kFlagDummyRecorderRunning
static const uint kFlagDummyRecorderRunning
Definition: tv_rec.h:477
ChannelBase::GetChannelName
virtual QString GetChannelName(void) const
Definition: channelbase.h:64
TVRec::m_setChannelLock
QMutex m_setChannelLock
Definition: tv_rec.h:382
RecordingQuality::IsDamaged
bool IsDamaged(void) const
Definition: recordingquality.cpp:108
mythsystemevent.h
build_compdb.file
file
Definition: build_compdb.py:55
RecordingInfo::UpdateRecordingEnd
void UpdateRecordingEnd(void)
Update information in the recorded table when the end-time of a recording is changed.
Definition: recordinginfo.cpp:1311
TVRec::GetDTVChannel
DTVChannel * GetDTVChannel(void)
Definition: tv_rec.cpp:1214
TVRec::kFlagPendingActions
static const uint kFlagPendingActions
Definition: tv_rec.h:471
TVRec::CheckChannelPrefix
bool CheckChannelPrefix(const QString &prefix, uint &complete_valid_channel_on_rec, bool &is_extra_char_useful, QString &needed_spacer) const
Checks a prefix against the channels in the DB.
Definition: tv_rec.cpp:2270
RecorderBase::Pause
virtual void Pause(bool clear=true)
Pause tells recorder to pause, it should not block.
Definition: recorderbase.cpp:263
MasterGuideTable::TableCount
uint TableCount() const
Definition: atsctables.h:117
ProgramInfo::GetRecordingEndTime
QDateTime GetRecordingEndTime(void) const
Approximate time the recording should have ended, did end, or is intended to end.
Definition: programinfo.h:412
ChannelBase::GetPictureAttribute
virtual int GetPictureAttribute(PictureAttribute) const
Definition: channelbase.h:94
ProgramInfo::GetRecordingGroup
QString GetRecordingGroup(void) const
Definition: programinfo.h:419
TVRec::GetChainID
QString GetChainID(void)
Get the chainid of the livetv instance.
Definition: tv_rec.cpp:2652
remoteutil.h
hardwareprofile.distros.mythtv_data.data_mythtv.prefix
string prefix
Definition: data_mythtv.py:40
TVRec::m_overRecordSecCat
std::chrono::seconds m_overRecordSecCat
Definition: tv_rec.h:366
RecorderBase::GetKeyframeDurations
bool GetKeyframeDurations(long long start, long long end, frm_pos_map_t &map) const
Definition: recorderbase.cpp:562
ProgramInfo::QueryTuningInfo
bool QueryTuningInfo(QString &channum, QString &input) const
Returns the channel and input needed to record the program.
Definition: programinfo.cpp:5266
GetPidsToCache
static void GetPidsToCache(DTVSignalMonitor *dtvMon, pid_cache_t &pid_cache)
Definition: tv_rec.cpp:1759
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
TVRec::m_pauseNotify
bool m_pauseNotify
Definition: tv_rec.h:393
dvbchannel.h
TVRec::TuningOnSameMultiplex
bool TuningOnSameMultiplex(TuningRequest &request)
Definition: tv_rec.cpp:3398
TVRec::TeardownRecorder
void TeardownRecorder(uint request_flags)
Tears down the recorder.
Definition: tv_rec.cpp:1140
kState_Error
@ kState_Error
Error State, if we ever try to enter this state errored is set.
Definition: tv.h:54
ProgramInfo::GetRecordingStartTime
QDateTime GetRecordingStartTime(void) const
Approximate time the recording started.
Definition: programinfo.h:404
TVRec::GetFilePosition
long long GetFilePosition(void)
Returns total number of bytes written by RingBuffer.
Definition: tv_rec.cpp:2534
ProgramInfo::GetPathname
QString GetPathname(void) const
Definition: programinfo.h:343
TVRec::kFlagCancelNextRecording
static const uint kFlagCancelNextRecording
Definition: tv_rec.h:445
RecordingQuality::toStringXML
QString toStringXML(void) const
Definition: recordingquality.cpp:114
ChannelBase::Renumber
virtual void Renumber(uint sourceid, const QString &oldChanNum, const QString &newChanNum)
Changes a channum if we have it cached anywhere.
Definition: channelbase.cpp:629
TVRec::SwitchRecordingRingBuffer
RecordingInfo * SwitchRecordingRingBuffer(const RecordingInfo &rcinfo)
Definition: tv_rec.cpp:4703
tmp
static guint32 * tmp
Definition: goom_core.cpp:26
TVRec::GetRecordEndTime
QDateTime GetRecordEndTime(const ProgramInfo *pi) const
Returns recording end time with proper post-roll.
Definition: tv_rec.cpp:362
RecStatus::toString
static QString toString(RecStatus::Type recstatus, uint id)
Converts "recstatus" into a short (unreadable) string.
Definition: recordingstatus.cpp:40
TVRec::m_recordEndTime
QDateTime m_recordEndTime
Definition: tv_rec.h:409
DTVChannel::GetTuningMode
QString GetTuningMode(void) const
Returns tuning mode last set by SetTuningMode().
Definition: dtvchannel.cpp:73
kState_ChangingState
@ kState_ChangingState
This is a placeholder state which we never actually enter, but is returned by GetState() when we are ...
Definition: tv.h:89
DTVChannel::GetOriginalNetworkID
uint GetOriginalNetworkID(void) const
Returns DVB original_network_id, 0 if unknown.
Definition: dtvchannel.h:102
LiveTVChain::GetProgramAt
ProgramInfo * GetProgramAt(int at) const
Returns program at the desired location.
Definition: livetvchain.cpp:321
kState_None
@ kState_None
None State, this is the initial state in both TV and TVRec, it indicates that we are ready to change ...
Definition: tv.h:58
EITScanner::StopActiveScan
void StopActiveScan(void)
Definition: eitscanner.cpp:300
SignalMonitor::IsRequired
static bool IsRequired(const QString &cardtype)
Returns true iff the card type supports signal monitoring.
Definition: signalmonitor.h:316
TVRec::TeardownAll
void TeardownAll(void)
Definition: tv_rec.cpp:224
GeneralDBOptions::m_channelTimeout
uint m_channelTimeout
Definition: tv_rec.h:79
MPEGStreamData::SetIgnoreCRC
void SetIgnoreCRC(bool haveCRCbug)
Definition: mpegstreamdata.h:111
TVRec::m_inputId
uint m_inputId
Definition: tv_rec.h:370
GeneralDBOptions::m_vbiDev
QString m_vbiDev
Definition: tv_rec.h:73
TVRec::m_overRecordSecNrml
std::chrono::seconds m_overRecordSecNrml
Definition: tv_rec.h:365
TVRec::RecorderPaused
void RecorderPaused(void)
This is a callback, called by the "recorder" instance when it has actually paused.
Definition: tv_rec.cpp:2897
JOB_LIVE_REC
@ JOB_LIVE_REC
Definition: jobqueue.h:63
MythDate::secsInFuture
std::chrono::seconds secsInFuture(const QDateTime &future)
Definition: mythdate.cpp:208
TVRec::m_pendingRecordings
PendingMap m_pendingRecordings
Definition: tv_rec.h:415
TRANSITION
#define TRANSITION(ASTATE, BSTATE)
Definition: tv_rec.cpp:1020
TVRec::kFlagAnyRecRunning
static const uint kFlagAnyRecRunning
Definition: tv_rec.h:479
ChannelBase::InitPictureAttributes
virtual bool InitPictureAttributes(void)
Definition: channelbase.h:93
TVRec::GetInputId
uint GetInputId(void) const
Returns the inputid.
Definition: tv_rec.h:236
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:5073
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:1470
mythdate.h
TVRec::kFlagWaitingForSignal
static const uint kFlagWaitingForSignal
Definition: tv_rec.h:469
TVRec::kFlagDetect
static const uint kFlagDetect
Definition: tv_rec.h:484
ProgramInfo::SetPathname
void SetPathname(const QString &pn)
Definition: programinfo.cpp:2438
ProgramInfo::SaveVideoProperties
void SaveVideoProperties(uint mask, uint video_property_flags)
Definition: programinfo.cpp:4832
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:93
TVRec::m_autoRunJobs
QHash< QString, int > m_autoRunJobs
Definition: tv_rec.h:411
minor
#define minor(X)
Definition: compat.h:76
RecordingInfo::GetRecordingFile
RecordingFile * GetRecordingFile() const
Definition: recordinginfo.h:282
TVRec::PauseRecorder
void PauseRecorder(void)
Tells "recorder" to pause, used for channel and input changes.
Definition: tv_rec.cpp:2878
programinfo.h
TVRec::NotifySchedulerOfRecording
void NotifySchedulerOfRecording(RecordingInfo *rec)
Tell scheduler about the recording.
Definition: tv_rec.cpp:2701
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:1310
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:390
mythlogging.h
SignalMonitor::kDVBSigMon_WaitForPos
static const uint64_t kDVBSigMon_WaitForPos
Wait for rotor to complete turning the antenna.
Definition: signalmonitor.h:200
ProgramInfo::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: programinfo.h:447
TVRec::SetRecordingStatus
void SetRecordingStatus(RecStatus::Type new_status, int line, bool have_lock=false)
Definition: tv_rec.cpp:705
ProgramInfo::QueryAverageAspectRatio
MarkTypes QueryAverageAspectRatio(void) const
Definition: programinfo.cpp:4478
is_dishnet_eit
static bool is_dishnet_eit(uint inputid)
Definition: tv_rec.cpp:1248
DVBStreamData::SetDishNetEIT
void SetDishNetEIT(bool use_dishnet_eit)
Definition: dvbstreamdata.h:165
LiveTVChain::SetHostPrefix
void SetHostPrefix(const QString &prefix)
Definition: livetvchain.cpp:45
MythCoreContext::GenMythURL
static QString GenMythURL(const QString &host=QString(), int port=0, QString path=QString(), const QString &storageGroup=QString())
Definition: mythcorecontext.cpp:760
RemoteStopRecording
bool RemoteStopRecording(uint inputid)
Definition: tvremoteutil.cpp:98
ChannelBase
Abstract class providing a generic interface to tuning hardware.
Definition: channelbase.h:31
RecorderBase::SetRingBuffer
void SetRingBuffer(MythMediaBuffer *Buffer)
Tells recorder to use an externally created ringbuffer.
Definition: recorderbase.cpp:75
hardwareprofile.scan.profile
profile
Definition: scan.py:99
MasterGuideTable::TablePID
uint TablePID(uint i) const
Definition: atsctables.h:131
CardUtil::IsEncoder
static bool IsEncoder(const QString &rawtype)
Definition: cardutil.h:130
RemoteIsBusy
bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
Definition: tvremoteutil.cpp:362
TVRec::kFlagKillRec
static const uint kFlagKillRec
close recorder, discard recording
Definition: tv_rec.h:462
ProgramInfo::SetScheduledEndTime
void SetScheduledEndTime(const QDateTime &dt)
Definition: programinfo.h:524
TuningRequest::m_progNum
int m_progNum
Definition: tv_rec.h:124
ProgramInfo::SetInputID
void SetInputID(uint id)
Definition: programinfo.h:540
DTVChannel::SaveCachedPids
void SaveCachedPids(const pid_cache_t &pid_cache) const
Saves MPEG PIDs to cache to database.
Definition: dtvchannel.cpp:107
MythCoreContext::GetBackendServerPort
int GetBackendServerPort(void)
Returns the locally defined backend control port.
Definition: mythcorecontext.cpp:1064
TVRec::m_recorder
RecorderBase * m_recorder
Definition: tv_rec.h:337
MythCoreContext::SendSystemEvent
void SendSystemEvent(const QString &msg)
Definition: mythcorecontext.cpp:1544
ChannelBase::StoreInputChannels
virtual void StoreInputChannels(void)
Saves current channel as the default channel for the current input.
Definition: channelbase.cpp:649
TVRec::GetMaxBitrate
long long GetMaxBitrate(void) const
Returns the maximum bits per second this recorder can produce.
Definition: tv_rec.cpp:2594
MythCoreContext::SendEvent
void SendEvent(const MythEvent &event)
Definition: mythcorecontext.cpp:1530
TVRec::kFlagRunMainLoop
static const uint kFlagRunMainLoop
Definition: tv_rec.h:441
ProgramInfo::SetRecordingRuleType
void SetRecordingRuleType(RecordingType type)
Definition: programinfo.h:581
TVRec::RemoveRecording
TVState RemoveRecording(TVState state) const
If "state" is kState_RecordingOnly or kState_WatchingLiveTV, returns a kState_None,...
Definition: tv_rec.cpp:782
TVRec::m_pseudoLiveTVRecording
RecordingInfo * m_pseudoLiveTVRecording
Definition: tv_rec.h:418
MPEGStreamData::SetRecordingType
void SetRecordingType(const QString &recording_type)
Definition: mpegstreamdata.cpp:100
hardwareprofile.i18n.t
t
Definition: i18n.py:36
TVRec::FlagToString
static QString FlagToString(uint f)
Definition: tv_rec.cpp:4388
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:540
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:361
compat.h
TVRec::HandleStateChange
void HandleStateChange(void)
Changes the internalState to the desiredNextState if possible.
Definition: tv_rec.cpp:1033
pid_cache_t
std::vector< pid_cache_item_t > pid_cache_t
Definition: channelutil.h:43
TVRec::kAutoRunNone
@ kAutoRunNone
Definition: tv_rec.h:326
LiveTVChain::SetInputType
void SetInputType(const QString &type)
Definition: livetvchain.cpp:50
ATSCStreamData
Encapsulates data about ATSC stream and emits events for most tables.
Definition: atscstreamdata.h:29
v4lchannel.h
TVRec::m_tvChain
LiveTVChain * m_tvChain
Definition: tv_rec.h:425
DVBDBOptions::m_dvbOnDemand
bool m_dvbOnDemand
Definition: tv_rec.h:88
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:227
TVRec::CheckChannel
bool CheckChannel(const QString &name) const
Checks if named channel exists on current tuner.
Definition: tv_rec.cpp:2224
SignalMonitor::kDTVSigMon_WaitForPMT
static const uint64_t kDTVSigMon_WaitForPMT
Definition: signalmonitor.h:182
RecorderBase::Reset
virtual void Reset(void)=0
Reset the recorder to the startup state.
TVRec::kFlagSignalMonitorRunning
static const uint kFlagSignalMonitorRunning
Definition: tv_rec.h:474
ProgramInfo::SetRecordingGroup
void SetRecordingGroup(const QString &group)
Definition: programinfo.h:527
TVRec::SetupSignalMonitor
bool SetupSignalMonitor(bool tablemon, bool EITscan, bool notify)
This creates a SignalMonitor instance and begins signal monitoring.
Definition: tv_rec.cpp:1988
SignalMonitor::kDTVSigMon_WaitForPAT
static const uint64_t kDTVSigMon_WaitForPAT
Definition: signalmonitor.h:181
MythCoreContext::GetDurSetting
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
Definition: mythcorecontext.h:173
TVRec::TuningGetChanNum
QString TuningGetChanNum(const TuningRequest &request, QString &input) const
Definition: tv_rec.cpp:3359
TVRec::kFlagEITScan
static const uint kFlagEITScan
final result desired is an EIT Scan
Definition: tv_rec.h:458
SignalMonitor::kDTVSigMon_WaitForSDT
static const uint64_t kDTVSigMon_WaitForSDT
Definition: signalmonitor.h:186
TVRec::TeardownSignalMonitor
void TeardownSignalMonitor(void)
If a SignalMonitor instance exists, the monitoring thread is stopped and the instance is deleted.
Definition: tv_rec.cpp:2042
RecorderBase::GetRecordingQuality
virtual RecordingQuality * GetRecordingQuality(const RecordingInfo *ri) const
Returns a report about the current recordings quality.
Definition: recorderbase.cpp:506
TVRec::WaitForNextLiveTVDir
bool WaitForNextLiveTVDir(void)
Definition: tv_rec.cpp:4469
RecStatus::Failing
@ Failing
Definition: recordingstatus.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:460
RecordingInfo::GetAutoRunJobs
int GetAutoRunJobs(void) const
Returns a bitmap of which jobs are attached to this RecordingInfo.
Definition: recordinginfo.cpp:506
ProgramInfo::GetSourceID
uint GetSourceID(void) const
Definition: programinfo.h:462
MPEGStreamData
Encapsulates data about MPEG stream and emits events for each table.
Definition: mpegstreamdata.h:85
RecordingRule::m_recProfile
QString m_recProfile
Definition: recordingrule.h:120
TVRec::m_nextLiveTVDir
QString m_nextLiveTVDir
Definition: tv_rec.h:419
TVRec::m_triggerEventSleepWait
QWaitCondition m_triggerEventSleepWait
Definition: tv_rec.h:402
RecorderBase::GetFrameRate
double GetFrameRate(void) const
Returns the latest frame rate.
Definition: recorderbase.h:234
JobQueue::JobIsNotInMask
static bool JobIsNotInMask(int job, int mask)
Definition: jobqueue.h:201
TVRec::CloseChannel
void CloseChannel(void)
Definition: tv_rec.cpp:1200
RecordingRule::m_type
RecordingType m_type
Definition: recordingrule.h:111
RecStatus::Aborted
@ Aborted
Definition: recordingstatus.h:28
vboxutils.h
TVRec::kFlagKillRingBuffer
static const uint kFlagKillRingBuffer
Definition: tv_rec.h:465
TVRec::ChangeState
void ChangeState(TVState nextState)
Puts a state change on the nextState queue.
Definition: tv_rec.cpp:1118
DVBStreamData
Definition: dvbstreamdata.h:33
TVRec::m_desiredNextState
TVState m_desiredNextState
Definition: tv_rec.h:391
ProgramInfo::toString
QString toString(Verbosity v=kLongDescription, const QString &sep=":", const QString &grp="\"") const
Definition: programinfo.cpp:1934
TVRec::m_parentId
uint m_parentId
Definition: tv_rec.h:371
TVRec::run
void run(void) override
Event handling method, contains event loop.
Definition: tv_rec.cpp:1304
RecStatus::Failed
@ Failed
Definition: recordingstatus.h:23
TVRec::m_triggerEventLoopSignal
bool m_triggerEventLoopSignal
Definition: tv_rec.h:400
DTVRecorder::GetStreamData
MPEGStreamData * GetStreamData(void) const
Definition: dtvrecorder.h: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:2235
RecorderBase::IsRecording
virtual bool IsRecording(void)
Tells whether the StartRecorder() loop is running.
Definition: recorderbase.cpp:243
RecordingRule::GetAutoExpire
AutoExpireType GetAutoExpire(void) const
Definition: recordingrule.h:61
TVRec::TuningShutdowns
void TuningShutdowns(const TuningRequest &request)
This shuts down anything that needs to be shut down before handling the passed in tuning request.
Definition: tv_rec.cpp:3522
TVRec::m_liveTVStartChannel
QString m_liveTVStartChannel
Definition: tv_rec.h:422
MythNotification::Check
static Type Check
Definition: mythnotification.h:37
storagegroup.h
TVRec::TuningRequest
friend class TuningRequest
Definition: tv_rec.h:148
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:340
TVRec::m_rbFileExt
QString m_rbFileExt
Definition: tv_rec.h:429
StandardSetting::getValue
virtual QString getValue(void) const
Definition: standardsettings.h:52
LiveTVChain::ReloadAll
void ReloadAll(const QStringList &data=QStringList())
Definition: livetvchain.cpp:210
TVRec::m_eitScanStartTime
QDateTime m_eitScanStartTime
Definition: tv_rec.h:397
TVRec::GetPictureAttribute
int GetPictureAttribute(PictureAttribute attr)
Definition: tv_rec.cpp:2955
TVRec::TuningNewRecorder
void TuningNewRecorder(MPEGStreamData *streamData)
Creates a recorder instance.
Definition: tv_rec.cpp:4119
RecordingInfo::StartedRecording
void StartedRecording(const QString &ext)
Inserts this RecordingInfo into the database as an existing recording.
Definition: recordinginfo.cpp:984
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:2567
TVRec::s_inputsLock
static QReadWriteLock s_inputsLock
Definition: tv_rec.h:432
TVRec::kFlagWaitingForRecPause
static const uint kFlagWaitingForRecPause
Definition: tv_rec.h:468
RecordingQuality
Definition: recordingquality.h:34
DTVRecorder
This is a specialization of RecorderBase used to handle MPEG-2, MPEG-4, MPEG-4 AVC,...
Definition: dtvrecorder.h:25
CHANNEL_DIRECTION_FAVORITE
@ CHANNEL_DIRECTION_FAVORITE
Definition: tv.h:32
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:138
uint
unsigned int uint
Definition: compat.h:79
TVRec::kFlagLiveTV
static const uint kFlagLiveTV
final result desired is LiveTV recording
Definition: tv_rec.h:449
TVRec::SetNextLiveTVDir
void SetNextLiveTVDir(QString dir)
Definition: tv_rec.cpp:4482
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
TVRec::GetFramerate
float GetFramerate(void)
Returns recordering frame rate from the recorder.
Definition: tv_rec.cpp:2504
TVRec::m_transcodeFirst
bool m_transcodeFirst
Definition: tv_rec.h:359
TVRec::m_signalEventCmdSent
bool m_signalEventCmdSent
Definition: tv_rec.h:343
TVRec::GetRecordingStatus
RecStatus::Type GetRecordingStatus(void) const
Definition: tv_rec.cpp:699
TVRec::QueueEITChannelChange
bool QueueEITChannelChange(const QString &name)
Queues up a channel change for the EITScanner.
Definition: tv_rec.cpp:3089
TVRec::m_eitCrawlIdleStart
std::chrono::seconds m_eitCrawlIdleStart
Definition: tv_rec.h:362
TuningRequest::m_minorChan
uint m_minorChan
Definition: tv_rec.h:123
DTVSignalMonitor::GetATSCStreamData
ATSCStreamData * GetATSCStreamData()
Returns the ATSC stream data if it exists.
Definition: dtvsignalmonitor.cpp:561
TVRec::m_triggerEventLoopWait
QWaitCondition m_triggerEventLoopWait
Definition: tv_rec.h:399
DTVChannel::EnterPowerSavingMode
virtual bool EnterPowerSavingMode(void)
Enters power saving mode if the card supports it.
Definition: dtvchannel.h:65
BROWSE_DOWN
@ BROWSE_DOWN
Fetch information on next channel.
Definition: tv.h:42
InputInfo::Clear
virtual void Clear(void)
Definition: inputinfo.cpp:6
CardUtil::IsV4L
static bool IsV4L(const QString &rawtype)
Definition: cardutil.h:140
TVRec::IsErrored
bool IsErrored(void) const
Returns true is "errored" is true, false otherwise.
Definition: tv_rec.h:240
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:912
RecorderBase::GetFramesWritten
virtual long long GetFramesWritten(void)=0
Returns number of frames written to disk.
ProgramInfo::SaveAutoExpire
void SaveAutoExpire(AutoExpireType autoExpire, bool updateDelete=false)
Set "autoexpire" field in "recorded" table to "autoExpire".
Definition: programinfo.cpp:3394
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:1721
mythmediabuffer.h
TVRec::GetRecording
ProgramInfo * GetRecording(void)
Allocates and returns a ProgramInfo for the current recording.
Definition: tv_rec.cpp:268
TVRec::SpawnLiveTV
void SpawnLiveTV(LiveTVChain *newchain, bool pip, QString startchan)
Tells TVRec to spawn a "Live TV" recorder.
Definition: tv_rec.cpp:2622
GeneralDBOptions::m_skipBtAudio
bool m_skipBtAudio
Definition: tv_rec.h:77
TVRec::CancelNextRecording
void CancelNextRecording(bool cancel)
Tells TVRec to cancel the upcoming recording.
Definition: tv_rec.cpp:375
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:91
InputInfo::m_inputId
uint m_inputId
unique key in DB for this input
Definition: inputinfo.h:49
PictureAttribute
PictureAttribute
Definition: videoouttypes.h:103
RecorderBase::StopRecording
virtual void StopRecording(void)
StopRecording() signals to the recorder that it should stop recording and exit cleanly.
Definition: recorderbase.cpp:224
TVRec::m_triggerEventSleepSignal
bool m_triggerEventSleepSignal
Definition: tv_rec.h:403
ChannelUtil::GetVideoFilters
static QString GetVideoFilters(uint sourceid, const QString &channum)
Definition: channelutil.h: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:45
RecordingRule::m_recGroupID
uint m_recGroupID
Definition: recordingrule.h:123
SET_NEXT
#define SET_NEXT()
Definition: tv_rec.cpp:1022
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:3115
SignalMonitor::HasExtraSlowTuning
virtual bool HasExtraSlowTuning(void) const
Definition: signalmonitor.h:62
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:906
dvbstreamdata.h
DTVSignalMonitor::SetProgramNumber
void SetProgramNumber(int progNum)
Definition: dtvsignalmonitor.cpp:214
MasterGuideTable
This table tells the decoder on which PIDs to find other tables, and their sizes and each table's cur...
Definition: atsctables.h:77
TVRec::m_signalMonitor
SignalMonitor * m_signalMonitor
Definition: tv_rec.h:339
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:2550
ChannelGroup::ToggleChannel
static bool ToggleChannel(uint chanid, int changrpid, bool delete_chan)
Definition: channelgroup.cpp:19
TuningRequest::m_majorChan
uint m_majorChan
Definition: tv_rec.h:122
kState_WatchingPreRecorded
@ kState_WatchingPreRecorded
Watching Pre-recorded is a TV only state for when we are watching a pre-existing recording.
Definition: tv.h:67
ProgramInfo::GetInputID
uint GetInputID(void) const
Definition: programinfo.h:463
SignalMonitor::SetUpdateRate
void SetUpdateRate(std::chrono::milliseconds msec)
Sets the number of milliseconds between signal monitoring attempts in the signal monitoring thread.
Definition: signalmonitor.h:111
RecorderBase::SavePositionMap
void SavePositionMap(bool force=false, bool finished=false)
Save the seektable to the DB.
Definition: recorderbase.cpp:592
ProgramInfo::SetChanID
void SetChanID(uint _chanid)
Definition: programinfo.h:522
GeneralDBOptions::m_audioSampleRate
int m_audioSampleRate
Definition: tv_rec.h:76
InputInfo::m_sourceId
uint m_sourceId
associated channel listings source
Definition: inputinfo.h:48
DVBChannel
Provides interface to the tuning hardware when using DVB drivers.
Definition: dvbchannel.h:31
LiveTVChain::GetInputType
QString GetInputType(int pos=-1) const
Definition: livetvchain.cpp:696
TuningRequest::m_flags
uint m_flags
Definition: tv_rec.h:118
ProgramInfo::GetChanID
uint GetChanID(void) const
This is the unique key used in the database to locate tuning information.
Definition: programinfo.h:372
TVRec::m_nextLiveTVDirLock
QMutex m_nextLiveTVDirLock
Definition: tv_rec.h:420
TVRec::CheckForRecGroupChange
void CheckForRecGroupChange(void)
Check if frontend changed the recording group.
Definition: tv_rec.cpp:2667
ChannelBase::SetChannelByString
virtual bool SetChannelByString(const QString &chan)=0
TVRec::m_internalState
TVState m_internalState
Definition: tv_rec.h:390
ProgramInfo::GetRecordingRuleType
RecordingType GetRecordingRuleType(void) const
Definition: programinfo.h:451
livetvchain.h
DTVSignalMonitor::IgnoreEncrypted
void IgnoreEncrypted(bool ignore)
Definition: dtvsignalmonitor.h:102
TVRec::m_signalEventCmdTimeout
QDateTime m_signalEventCmdTimeout
Definition: tv_rec.h:342
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:90
MythDate::secsInPast
std::chrono::seconds secsInPast(const QDateTime &past)
Definition: mythdate.cpp:203
TVRec::m_reachedRecordingDeadline
bool m_reachedRecordingDeadline
Definition: tv_rec.h:348
RecStatus::Recording
@ Recording
Definition: recordingstatus.h:30
TVRec::GetChannelInfo
bool GetChannelInfo(uint &chanid, uint &sourceid, QString &callsign, QString &channum, QString &channame, QString &xmltvid) const
Definition: tv_rec.cpp:3241
TVState
TVState
TVState is an enumeration of the states used by TV and TVRec.
Definition: tv.h:50
RecStatus::Inactive
@ Inactive
Definition: recordingstatus.h:42
ProgramInfo::ToStringList
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
Definition: programinfo.cpp:1267
SignalMonitor::AddListener
void AddListener(SignalMonitorListener *listener)
Definition: signalmonitor.cpp:388
mythcorecontext.h
TVRec::GetV4LChannel
V4LChannel * GetV4LChannel(void)
Definition: tv_rec.cpp:1219
TVRec::m_genOpt
GeneralDBOptions m_genOpt
Definition: tv_rec.h:375
StorageGroup::FindNextDirMostFree
QString FindNextDirMostFree(void)
Definition: storagegroup.cpp:671
cardutil.h
ProgramInfo::IsLocal
bool IsLocal(void) const
Definition: programinfo.h:351
TVRec::m_pendingRecLock
QRecursiveMutex m_pendingRecLock
Definition: tv_rec.h:388
TVRec::RingBufferChanged
void RingBufferChanged(MythMediaBuffer *Buffer, RecordingInfo *pginfo, RecordingQuality *recq)
Definition: tv_rec.cpp:3338
JobQueue::AddJobsToMask
static void AddJobsToMask(int jobs, int &mask)
Definition: jobqueue.h:203
TVRec::TuningRestartRecorder
void TuningRestartRecorder(void)
Restarts a stopped recorder or unpauses a paused recorder.
Definition: tv_rec.cpp:4305
TVRec::kSignalMonitoringRate
static constexpr std::chrono::milliseconds kSignalMonitoringRate
How many milliseconds the signal monitor should wait between checks.
Definition: tv_rec.h:437
ChannelBase::CheckChannel
bool CheckChannel(const QString &channum) const
Definition: channelbase.cpp:667
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:4455
TVRec::SetupDTVSignalMonitor
bool SetupDTVSignalMonitor(bool EITscan)
Tells DTVSignalMonitor what channel to look for.
Definition: tv_rec.cpp:1808
ChannelGroup::GetChannelGroupId
static int GetChannelGroupId(const QString &changroupname)
Definition: channelgroup.cpp:396
TVRec::kFlagAnyRunning
static const uint kFlagAnyRunning
Definition: tv_rec.h:480
RecorderBase::SetNextRecording
void SetNextRecording(const RecordingInfo *ri, MythMediaBuffer *Buffer)
Sets next recording info, to be applied as soon as practical.
Definition: recorderbase.cpp:124
TVRec::SetSignalMonitoringRate
std::chrono::milliseconds SetSignalMonitoringRate(std::chrono::milliseconds rate, int notifyFrontend=1)
Sets the signal monitoring rate.
Definition: tv_rec.cpp:2080
kNotRecording
@ kNotRecording
Definition: recordingtypes.h:22
PreviewGeneratorQueue::GetPreviewImage
static void GetPreviewImage(const ProgramInfo &pginfo, const QString &token)
Submit a request for the generation of a preview image.
Definition: previewgeneratorqueue.h:89
TVRec::m_dvbOpt
DVBDBOptions m_dvbOpt
Definition: tv_rec.h:376
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:883
MarkTypes
MarkTypes
Definition: programtypes.h:48
JOB_METADATA
@ JOB_METADATA
Definition: jobqueue.h:82
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
DVBDBOptions
Definition: tv_rec.h:83
GeneralDBOptions::m_videoDev
QString m_videoDev
Definition: tv_rec.h:72
TVRec::kFlagFinishRecording
static const uint kFlagFinishRecording
Definition: tv_rec.h:443
DTVChannel::SetTuningMode
void SetTuningMode(const QString &tuning_mode)
Sets tuning mode: "mpeg", "dvb", "atsc", etc.
Definition: dtvchannel.cpp:87
FireWireDBOptions::m_connection
int m_connection
Definition: tv_rec.h:99
DTVSignalMonitor::SetStreamData
virtual void SetStreamData(MPEGStreamData *data)
Sets the MPEG stream data for DTVSignalMonitor to use, and connects the table signals to the monitor.
Definition: dtvsignalmonitor.cpp:258
kSingleRecord
@ kSingleRecord
Definition: recordingtypes.h:23
BROWSE_SAME
@ BROWSE_SAME
Fetch browse information on current channel and time.
Definition: tv.h:40
TVRec
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:144
FireWireDBOptions
Definition: tv_rec.h:93
RecordingInfo::AddHistory
void AddHistory(bool resched=true, bool forcedup=false, bool future=false)
Adds recording history, creating "record" it if necessary.
Definition: recordinginfo.cpp:1352
TVRec::FinishedRecording
void FinishedRecording(RecordingInfo *curRec, RecordingQuality *recq)
If not a premature stop, adds program to history of recorded programs.
Definition: tv_rec.cpp:844
TVRec::m_signalMonitorCheckCnt
uint m_signalMonitorCheckCnt
Definition: tv_rec.h:347
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:326
RecorderBase::SetVideoFilters
virtual void SetVideoFilters(QString &filters)=0
Tells recorder which filters to use.
TuningRequest::IsOnSameMultiplex
bool IsOnSameMultiplex(void) const
Definition: tv_rec.h:115
TVRec::m_stateFlags
uint m_stateFlags
Definition: tv_rec.h:394
TVRec::WakeEventLoop
void WakeEventLoop(void)
Definition: tv_rec.cpp:241
GeneralDBOptions::m_audioDev
QString m_audioDev
Definition: tv_rec.h:74
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:61
TVRec::GetState
TVState GetState(void) const
Returns the TVState of the recorder.
Definition: tv_rec.cpp:254
MPEGStreamData::Reset
virtual void Reset(void)
Definition: mpegstreamdata.h:94
TVRec::m_signalMonitorDeadline
QDateTime m_signalMonitorDeadline
Definition: tv_rec.h:346
CardUtil::GetSourceID
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1904
DVBDBOptions::m_dvbTuningDelay
std::chrono::milliseconds m_dvbTuningDelay
Definition: tv_rec.h:89
PendingInfo::m_doNotAsk
bool m_doNotAsk
Definition: tv_rec.h:139
TVRec::SwitchLiveTVRingBuffer
bool SwitchLiveTVRingBuffer(const QString &channum, bool discont, bool set_rec)
Definition: tv_rec.cpp:4635
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:772
ChannelBase::GetInputID
virtual int GetInputID(void) const
Definition: channelbase.h:67
kState_WatchingLiveTV
@ kState_WatchingLiveTV
Watching LiveTV is the state for when we are watching a recording and the user has control over the c...
Definition: tv.h:63
RemoteRecordPending
bool RemoteRecordPending(uint inputid, const ProgramInfo *pginfo, std::chrono::seconds secsleft, bool hasLater)
Definition: tvremoteutil.cpp:50
StorageGroup
Definition: storagegroup.h:11
TableID::TVCT
@ TVCT
Definition: mpegtables.h:362
SignalMonitor::Start
virtual void Start()
Start signal monitoring thread.
Definition: signalmonitor.cpp:291
MythMediaBuffer::Create
static MythMediaBuffer * Create(const QString &Filename, bool Write, bool UseReadAhead=true, std::chrono::milliseconds Timeout=kDefaultOpenTimeout, bool StreamOnly=false)
Creates a RingBuffer instance.
Definition: mythmediabuffer.cpp:98
InputInfo
Definition: inputinfo.h:14
previewgeneratorqueue.h
TVRec::m_lastTuningRequest
TuningRequest m_lastTuningRequest
Definition: tv_rec.h:396
SignalMonitor::SetNotifyFrontend
void SetNotifyFrontend(bool notify)
Enables or disables frontend notification of the current signal value.
Definition: signalmonitor.h:94
TVRec::m_recorderThread
MThread * m_recorderThread
Recorder thread, runs RecorderBase::run().
Definition: tv_rec.h:356
atsctables.h
TVRec::StartedRecording
void StartedRecording(RecordingInfo *curRec)
Inserts a "curRec" into the database.
Definition: tv_rec.cpp:818
TVRec::InitAutoRunJobs
void InitAutoRunJobs(RecordingInfo *rec, AutoRunInitType t, RecordingProfile *recpro, int line)
Definition: tv_rec.cpp:2747
BrowseDirection
BrowseDirection
Used to request ProgramInfo for channel browsing.
Definition: tv.h:37
PendingInfo::m_ask
bool m_ask
Definition: tv_rec.h:138
StandardSetting
Definition: standardsettings.h:29
SendMythSystemRecEvent
void SendMythSystemRecEvent(const QString &msg, const RecordingInfo *pginfo)
Definition: mythsystemevent.cpp:333
TVRec::GetFlags
uint GetFlags(void) const
Definition: tv_rec.h:247
MPEGStreamData::AddListeningPID
virtual void AddListeningPID(uint pid, PIDPriority priority=kPIDPriorityNormal)
Definition: mpegstreamdata.h:120
CardUtil::GetInputInfo
static bool GetInputInfo(InputInfo &input, std::vector< uint > *groupids=nullptr)
Definition: cardutil.cpp:1662
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:838
recordingprofile.h
TVRec::TVRec
TVRec(int _inputid)
Performs instance initialization not requiring access to database.
Definition: tv_rec.cpp:84
ChannelBase::GetSourceID
virtual uint GetSourceID(void) const
Definition: channelbase.h:71
CardUtil::IsEITCapable
static bool IsEITCapable(const QString &rawtype)
Definition: cardutil.h:165
TVRec::kFlagAntennaAdjust
static const uint kFlagAntennaAdjust
antenna adjusting mode (LiveTV without recording).
Definition: tv_rec.h:453
TVRec::kFlagExitPlayer
static const uint kFlagExitPlayer
Definition: tv_rec.h:442
StateToString
QString StateToString(TVState state)
Returns a human readable QString representing a TVState.
Definition: tv.cpp:11
DTVChannel
Class providing a generic interface to digital tuning hardware.
Definition: dtvchannel.h:33
RecorderBase::GetKeyframePosition
long long GetKeyframePosition(long long desired) const
Returns closest keyframe position before the desired frame.
Definition: recorderbase.cpp:521
SignalMonitor::IsErrored
bool IsErrored(void) const
Definition: signalmonitor.h:84
ProgramInfo::SetRecordingRuleID
void SetRecordingRuleID(uint id)
Definition: programinfo.h:538
TVRec::TuningSignalCheck
MPEGStreamData * TuningSignalCheck(void)
This checks if we have a channel lock.
Definition: tv_rec.cpp:3854
TVRec::~TVRec
~TVRec(void) override
Stops the event and scanning threads and deletes any ChannelBase, RingBuffer, and RecorderBase instan...
Definition: tv_rec.cpp:205
ChannelBase::GetNextChannel
virtual uint GetNextChannel(uint chanid, ChannelChangeDirection direction) const
Definition: channelbase.cpp:201
RecordingProfile
Definition: recordingprofile.h:41
TVRec::m_isPip
bool m_isPip
Definition: tv_rec.h:372
DTVChannel::GetCachedPids
void GetCachedPids(pid_cache_t &pid_cache) const
Returns cached MPEG PIDs for last tuned channel.
Definition: dtvchannel.cpp:97
get_highest_input
static int get_highest_input(void)
Definition: tv_rec.cpp:1269
TVRec::SetVideoFiltersForChannel
bool SetVideoFiltersForChannel(uint sourceid, const QString &channum)
Definition: tv_rec.cpp:2405
DTVChannel::GetSuggestedTuningMode
QString GetSuggestedTuningMode(bool is_live_tv) const
Returns suggested tuning mode: "mpeg", "dvb", or "atsc".
Definition: dtvchannel.cpp:57