MythTV  master
tvremoteutil.cpp
Go to the documentation of this file.
1 #include <chrono> // for milliseconds
2 #include <thread> // for sleep_for
3 
4 #include "tvremoteutil.h"
5 #include "cardutil.h"
6 #include "inputinfo.h"
7 #include "programinfo.h"
8 #include "mythcorecontext.h"
9 #include "remoteencoder.h"
10 #include "tv_rec.h"
11 
13 {
14  if (gCoreContext->IsBackend())
15  {
16  const TVRec *rec = TVRec::GetTVRec(inputid);
17  if (rec)
18  return rec->GetFlags();
19  return 0;
20  }
21 
22  QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
23  strlist << "GET_FLAGS";
24  if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
25  return 0;
26 
27  return strlist[0].toInt();
28 }
29 
31 {
32  if (gCoreContext->IsBackend())
33  {
34  const TVRec *rec = TVRec::GetTVRec(inputid);
35  if (rec)
36  return rec->GetState();
37  return kState_ChangingState;
38  }
39 
40  QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
41  strlist << "GET_STATE";
42  if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
43  return kState_ChangingState;
44 
45  return strlist[0].toInt();
46 }
47 
48 
49 bool RemoteRecordPending(uint inputid, const ProgramInfo *pginfo,
50  int secsleft, bool hasLater)
51 {
52  if (gCoreContext->IsBackend())
53  {
54  TVRec *rec = TVRec::GetTVRec(inputid);
55  if (rec)
56  {
57  rec->RecordPending(pginfo, secsleft, hasLater);
58  return true;
59  }
60  return false;
61  }
62 
63  QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
64  strlist << "RECORD_PENDING";
65  strlist << QString::number(secsleft);
66  strlist << QString::number(static_cast<int>(hasLater));
67  pginfo->ToStringList(strlist);
68 
69  if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
70  return false;
71 
72  return strlist[0].toUpper() == "OK";
73 }
74 
75 bool RemoteStopLiveTV(uint inputid)
76 {
77  if (gCoreContext->IsBackend())
78  {
79  TVRec *rec = TVRec::GetTVRec(inputid);
80  if (rec)
81  {
82  rec->StopLiveTV();
83  return true;
84  }
85  return false;
86  }
87 
88  QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
89  strlist << "STOP_LIVETV";
90 
91  if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
92  return false;
93 
94  return strlist[0].toUpper() == "OK";
95 }
96 
98 {
99  if (gCoreContext->IsBackend())
100  {
101  TVRec *rec = TVRec::GetTVRec(inputid);
102  if (rec)
103  {
104  rec->StopRecording();
105  return true;
106  }
107  return false;
108  }
109 
110  QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
111  strlist << "STOP_RECORDING";
112 
113  if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
114  return false;
115 
116  return strlist[0].toUpper() == "OK";
117 }
118 
119 void RemoteStopRecording(const ProgramInfo *pginfo)
120 {
121  QStringList strlist(QString("STOP_RECORDING"));
122  pginfo->ToStringList(strlist);
123 
125 }
126 
127 void RemoteCancelNextRecording(uint inputid, bool cancel)
128 {
129  QStringList strlist(QString("QUERY_RECORDER %1").arg(inputid));
130  strlist << "CANCEL_NEXT_RECORDING";
131  strlist << QString::number((cancel) ? 1 : 0);
132 
134 }
135 
136 std::vector<InputInfo> RemoteRequestFreeInputInfo(uint excluded_input)
137 {
138  LOG(VB_CHANNEL, LOG_INFO,
139  QString("RemoteRequestFreeInputInfo excluding input %1")
140  .arg(excluded_input));
141 
142  std::vector<InputInfo> inputs;
143 
144  QStringList strlist(QString("GET_FREE_INPUT_INFO %1")
145  .arg(excluded_input));
146  if (!gCoreContext->SendReceiveStringList(strlist))
147  return inputs;
148 
149  QStringList::const_iterator it = strlist.cbegin();
150  while (it != strlist.cend())
151  {
152  InputInfo info;
153  if (!info.FromStringList(it, strlist.cend()))
154  break;
155  inputs.push_back(info);
156  LOG(VB_CHANNEL, LOG_INFO,
157  QString("RemoteRequestFreeInputInfo got input %1 (%2/%3)")
158  .arg(info.m_inputId).arg(info.m_chanId).arg(info.m_mplexId));
159  }
160 
161  LOG(VB_CHANNEL, LOG_INFO,
162  QString("RemoteRequestFreeInputInfo got %1 inputs")
163  .arg(inputs.size()));
164  return inputs;
165 }
166 
168 {
169  LOG(VB_CHANNEL, LOG_INFO, QString("RemoteGetFreeRecorderCount"));
170 
171  std::vector<InputInfo> inputs =
173 
174  LOG(VB_CHANNEL, LOG_INFO, QString("RemoteGetFreeRecorderCount got %1")
175  .arg(inputs.size()));
176  return inputs.size();
177 }
178 
180 {
181  LOG(VB_CHANNEL, LOG_INFO,
182  QString("RemoteRequestNextFreeRecorder after input %1)")
183  .arg(inputid));
184 
185  std::vector<InputInfo> inputs =
187 
188  if (inputs.empty())
189  {
190  LOG(VB_CHANNEL, LOG_INFO,
191  QString("RemoteRequestNextFreeRecorder got no input (after input %1)")
192  .arg(inputid));
193  return nullptr;
194  }
195 
196  size_t i = 0;
197  for ( ; i < inputs.size(); ++i)
198  if (inputs[i].m_inputId == (uint)inputid)
199  break;
200 
201  if (i >= inputs.size())
202  {
203  // We should always find the referenced input. If we don't,
204  // just return the first one.
205  i = 0;
206  }
207  else
208  {
209  // Try to find the next input with a different name. If one
210  // doesn't exist, just return the current one.
211  size_t j = i;
212  do
213  {
214  i = (i + 1) % inputs.size();
215  }
216  while (i != j && inputs[i].m_displayName == inputs[j].m_displayName);
217  }
218 
219  LOG(VB_CHANNEL, LOG_INFO,
220  QString("RemoteRequestNextFreeRecorder got input %1")
221  .arg(inputs[i].m_inputId));
222 
223  return RemoteGetExistingRecorder(inputs[i].m_inputId);
224 }
225 
226 std::vector<uint> RemoteRequestFreeRecorderList(uint excluded_input)
227 {
228  LOG(VB_CHANNEL, LOG_INFO,
229  QString("RemoteRequestFreeRecorderList excluding input %1")
230  .arg(excluded_input));
231 
232  std::vector<InputInfo> inputs =
233  RemoteRequestFreeInputInfo(excluded_input);
234 
235  std::vector<uint> inputids;
236  std::transform(inputs.cbegin(), inputs.cend(), std::back_inserter(inputids),
237  [](const auto & input){ return input.m_inputId; } );
238 
239  LOG(VB_CHANNEL, LOG_INFO,
240  QString("RemoteRequestFreeRecorderList got inputs"));
241  return inputids;
242 }
243 
244 std::vector<uint> RemoteRequestFreeInputList(uint excluded_input)
245 {
246  LOG(VB_CHANNEL, LOG_INFO,
247  QString("RemoteRequestFreeInputList excluding input %1")
248  .arg(excluded_input));
249 
250  std::vector<InputInfo> inputs =
251  RemoteRequestFreeInputInfo(excluded_input);
252 
253  std::vector<uint> inputids;
254  std::transform(inputs.cbegin(), inputs.cend(), std::back_inserter(inputids),
255  [](const auto & input){ return input.m_inputId; } );
256 
257  LOG(VB_CHANNEL, LOG_INFO,
258  QString("RemoteRequestFreeInputList got inputs"));
259  return inputids;
260 }
261 
263 (const QStringList &qualifiedRecorders, uint excluded_input)
264 {
265  LOG(VB_CHANNEL, LOG_INFO,
266  QString("RemoteRequestFreeRecorderFromList excluding input %1")
267  .arg(excluded_input));
268 
269  std::vector<InputInfo> inputs =
270  RemoteRequestFreeInputInfo(excluded_input);
271 
272  for (const auto & recorder : qAsConst(qualifiedRecorders))
273  {
274  uint inputid = recorder.toUInt();
275  auto sameinput = [inputid](const auto & input){ return input.m_inputId == inputid; };
276  if (std::any_of(inputs.cbegin(), inputs.cend(), sameinput))
277  {
278  LOG(VB_CHANNEL, LOG_INFO,
279  QString("RemoteRequestFreeRecorderFromList got input %1")
280  .arg(inputid));
281  return RemoteGetExistingRecorder(inputid);
282  }
283  }
284 
285  LOG(VB_CHANNEL, LOG_INFO,
286  QString("RemoteRequestFreeRecorderFromList got no input"));
287  return nullptr;
288 }
289 
291 {
292  LOG(VB_CHANNEL, LOG_INFO,
293  QString("RemoteRequestRecorder entered"));
294 
295  std::vector<InputInfo> inputs =
297 
298  if (inputs.empty())
299  {
300  LOG(VB_CHANNEL, LOG_INFO,
301  QString("RemoteRequestRecorder got no input"));
302  return nullptr;
303  }
304 
305  LOG(VB_CHANNEL, LOG_INFO,
306  QString("RemoteRequestRecorder got input %1")
307  .arg(inputs[0].m_inputId));
308  return RemoteGetExistingRecorder(inputs[0].m_inputId);
309 }
310 
312 {
313  LOG(VB_CHANNEL, LOG_INFO,
314  QString("RemoteGetExistingRecorder program %1")
315  .arg(pginfo->GetTitle()));
316 
317  QStringList strlist( "GET_RECORDER_NUM" );
318  pginfo->ToStringList(strlist);
319 
320  if (!gCoreContext->SendReceiveStringList(strlist))
321  {
322  LOG(VB_CHANNEL, LOG_INFO,
323  QString("RemoteGetExistingRecorder got no input"));
324  return nullptr;
325  }
326 
327  int num = strlist[0].toInt();
328  QString hostname = strlist[1];
329  int port = strlist[2].toInt();
330 
331  LOG(VB_CHANNEL, LOG_INFO,
332  QString("RemoteGetExistingRecorder got input %1").arg(num));
333  return new RemoteEncoder(num, hostname, port);
334 }
335 
337 {
338  LOG(VB_CHANNEL, LOG_INFO,
339  QString("RemoteGetExistingRecorder input %1")
340  .arg(recordernum));
341 
342  QStringList strlist( "GET_RECORDER_FROM_NUM" );
343  strlist << QString("%1").arg(recordernum);
344 
345  if (!gCoreContext->SendReceiveStringList(strlist))
346  {
347  LOG(VB_CHANNEL, LOG_INFO,
348  QString("RemoteGetExistingRecorder got no input"));
349  return nullptr;
350  }
351 
352  QString hostname = strlist[0];
353  int port = strlist[1].toInt();
354 
355  LOG(VB_CHANNEL, LOG_INFO,
356  QString("RemoteGetExistingRecorder got input %1")
357  .arg(recordernum));
358  return new RemoteEncoder(recordernum, hostname, port);
359 }
360 
361 bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
362 {
363 #if 0
364  LOG(VB_GENERAL, LOG_DEBUG, QString("RemoteIsBusy(%1) %2")
365  .arg(inputid).arg(gCoreContext->IsBackend() ? "be" : "fe"));
366 #endif
367 
368  busy_input.Clear();
369 
370  if (gCoreContext->IsBackend())
371  {
372  const TVRec *rec = TVRec::GetTVRec(inputid);
373  if (rec)
374  return rec->IsBusy(&busy_input);
375 
376  // Note this value is intentionally different than the
377  // non-backend, error value below. There is a small
378  // window when adding an input where an input can exist in
379  // the database, but not yet have a TVRec. In such cases,
380  // we don't want it to be considered busy and block other
381  // actions.
382  return false;
383  }
384 
385  QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
386  strlist << "IS_BUSY";
387  if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
388  return true;
389 
390  QStringList::const_iterator it = strlist.cbegin();
391  bool state = (*it).toInt() != 0;
392  ++it;
393  if (!busy_input.FromStringList(it, strlist.cend()))
394  state = true; // if there was an error pretend that the input is busy.
395 
396  return state;
397 }
398 
400  std::vector<TunerStatus> *tunerList, bool list_inactive)
401 {
402  bool isRecording = false;
403  std::vector<uint> inputlist = CardUtil::GetInputList();
404 
405  if (tunerList)
406  tunerList->clear();
407 
408  for (uint inputid : inputlist)
409  {
410  int state = kState_ChangingState;
411  QString channelName = "";
412  QString title = "";
413  QString subtitle = "";
414  QDateTime dtStart = QDateTime();
415  QDateTime dtEnd = QDateTime();
416  QStringList strlist;
417 
418  QString cmd = QString("QUERY_REMOTEENCODER %1").arg(inputid);
419 
420  while (state == kState_ChangingState)
421  {
422  strlist = QStringList(cmd);
423  strlist << "GET_STATE";
425 
426  if (strlist.empty())
427  break;
428 
429  state = strlist[0].toInt();
430  if (kState_ChangingState == state)
431  std::this_thread::sleep_for(std::chrono::milliseconds(5));
432  }
433 
434  if (kState_RecordingOnly == state || kState_WatchingRecording == state)
435  {
436  isRecording = true;
437 
438  if (!tunerList)
439  break;
440 
441  strlist = QStringList(QString("QUERY_RECORDER %1").arg(inputid));
442  strlist << "GET_RECORDING";
444 
445  ProgramInfo progInfo(strlist);
446 
447  title = progInfo.GetTitle();
448  subtitle = progInfo.GetSubtitle();
449  channelName = progInfo.GetChannelName();
450  dtStart = progInfo.GetScheduledStartTime();
451  dtEnd = progInfo.GetScheduledEndTime();
452  }
453  else if (!list_inactive)
454  continue;
455 
456  if (tunerList)
457  {
458  TunerStatus tuner;
459  tuner.id = inputid;
460  tuner.isRecording = ((kState_RecordingOnly == state) ||
461  (kState_WatchingRecording == state));
462  tuner.channame = channelName;
463  tuner.title = (kState_ChangingState == state) ?
464  QObject::tr("Error querying recorder state") : title;
465  tuner.subtitle = subtitle;
466  tuner.startTime = dtStart;
467  tuner.endTime = dtEnd;
468  tunerList->push_back(tuner);
469  }
470  }
471 
472  return isRecording;
473 }
474 
475 /* vim: set expandtab tabstop=4 shiftwidth=4: */
InputInfo::m_chanId
uint m_chanId
chanid restriction if applicable
Definition: inputinfo.h:51
RemoteGetExistingRecorder
RemoteEncoder * RemoteGetExistingRecorder(const ProgramInfo *pginfo)
Definition: tvremoteutil.cpp:311
RemoteRequestRecorder
RemoteEncoder * RemoteRequestRecorder(void)
Definition: tvremoteutil.cpp:290
MythCoreContext::SendReceiveStringList
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
Definition: mythcorecontext.cpp:1376
RemoteGetState
uint RemoteGetState(uint inputid)
Definition: tvremoteutil.cpp:30
TunerStatus::title
QString title
Definition: tvremoteutil.h:22
title
QString title
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:636
ProgramInfo::GetChannelName
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
Definition: programinfo.h:384
RemoteGetFreeRecorderCount
int RemoteGetFreeRecorderCount(void)
Definition: tvremoteutil.cpp:167
arg
arg(title).arg(filename).arg(doDelete))
TVRec::StopRecording
void StopRecording(bool killFile=false)
Changes from a recording state to kState_None.
Definition: tv_rec.cpp:704
TunerStatus::endTime
QDateTime endTime
Definition: tvremoteutil.h:25
ProgramInfo::GetScheduledEndTime
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:395
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
RemoteGetFlags
uint RemoteGetFlags(uint inputid)
Definition: tvremoteutil.cpp:12
isRecording
static bool isRecording()
Definition: mythtv/programs/mythshutdown/main.cpp:219
RemoteStopLiveTV
bool RemoteStopLiveTV(uint inputid)
Definition: tvremoteutil.cpp:75
TVRec::IsBusy
bool IsBusy(InputInfo *busy_input=nullptr, int time_buffer=5) const
Returns true if the recorder is busy, or will be within the next time_buffer seconds.
Definition: tv_rec.cpp:2483
RemoteEncoder
Definition: remoteencoder.h:26
TunerStatus::channame
QString channame
Definition: tvremoteutil.h:21
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
kState_WatchingRecording
@ kState_WatchingRecording
Watching Recording is the state for when we are watching an in progress recording,...
Definition: tv.h:80
TunerStatus
recording status stuff
Definition: tvremoteutil.h:17
programinfo.h
RemoteRequestFreeInputList
std::vector< uint > RemoteRequestFreeInputList(uint excluded_input)
Definition: tvremoteutil.cpp:244
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:388
CardUtil::GetInputList
static std::vector< uint > GetInputList(void)
Definition: cardutil.cpp:2644
RemoteStopRecording
bool RemoteStopRecording(uint inputid)
Definition: tvremoteutil.cpp:97
RemoteRequestFreeInputInfo
std::vector< InputInfo > RemoteRequestFreeInputInfo(uint excluded_input)
Definition: tvremoteutil.cpp:136
RemoteIsBusy
bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
Definition: tvremoteutil.cpp:361
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:359
recorder
RemoteEncoder * recorder
Definition: mythtv/programs/mythcommflag/main.cpp:80
uint
unsigned int uint
Definition: compat.h:140
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:56
InputInfo::Clear
virtual void Clear(void)
Definition: inputinfo.cpp:6
tvremoteutil.h
InputInfo::m_inputId
uint m_inputId
unique key in DB for this input
Definition: inputinfo.h:49
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:68
RemoteGetRecordingStatus
bool RemoteGetRecordingStatus(std::vector< TunerStatus > *tunerList, bool list_inactive)
Definition: tvremoteutil.cpp:399
ProgramInfo::ToStringList
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
Definition: programinfo.cpp:1270
mythcorecontext.h
MythCoreContext::IsBackend
bool IsBackend(void) const
is this process a backend process
Definition: mythcorecontext.cpp:661
cardutil.h
RemoteRequestFreeRecorderFromList
RemoteEncoder * RemoteRequestFreeRecorderFromList(const QStringList &qualifiedRecorders, uint excluded_input)
Definition: tvremoteutil.cpp:263
TVRec
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:143
TunerStatus::id
uint id
Definition: tvremoteutil.h:19
RemoteRecordPending
bool RemoteRecordPending(uint inputid, const ProgramInfo *pginfo, int secsleft, bool hasLater)
Definition: tvremoteutil.cpp:49
TVRec::GetState
TVState GetState(void) const
Returns the TVState of the recorder.
Definition: tv_rec.cpp:225
tv_rec.h
RemoteCancelNextRecording
void RemoteCancelNextRecording(uint inputid, bool cancel)
Definition: tvremoteutil.cpp:127
inputinfo.h
InputInfo
Definition: inputinfo.h:15
TunerStatus::startTime
QDateTime startTime
Definition: tvremoteutil.h:24
remoteencoder.h
TVRec::GetFlags
uint GetFlags(void) const
Definition: tv_rec.h:245
musicbrainzngs.caa.hostname
string hostname
Definition: caa.py:17
RemoteRequestFreeRecorderList
std::vector< uint > RemoteRequestFreeRecorderList(uint excluded_input)
Definition: tvremoteutil.cpp:226
TunerStatus::isRecording
bool isRecording
Definition: tvremoteutil.h:20
TVRec::StopLiveTV
void StopLiveTV(void)
Tells TVRec to stop a "Live TV" recorder.
Definition: tv_rec.cpp:2879
kState_RecordingOnly
@ kState_RecordingOnly
Recording Only is a TVRec only state for when we are recording a program, but there is no one current...
Definition: tv.h:84
TunerStatus::subtitle
QString subtitle
Definition: tvremoteutil.h:23
TVRec::GetTVRec
static TVRec * GetTVRec(uint inputid)
Definition: tv_rec.cpp:4825
InputInfo::m_mplexId
uint m_mplexId
mplexid restriction if applicable
Definition: inputinfo.h:50
TVRec::RecordPending
void RecordPending(const ProgramInfo *rcinfo, int secsleft, bool hasLater)
Tells TVRec "rcinfo" is the next pending recording.
Definition: tv_rec.cpp:271
RemoteRequestNextFreeRecorder
RemoteEncoder * RemoteRequestNextFreeRecorder(int inputid)
Definition: tvremoteutil.cpp:179
ProgramInfo::GetSubtitle
QString GetSubtitle(void) const
Definition: programinfo.h:361
InputInfo::FromStringList
virtual bool FromStringList(QStringList::const_iterator &it, const QStringList::const_iterator &end)
Definition: inputinfo.cpp:13