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(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 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  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.begin();
150  while (it != strlist.end())
151  {
152  InputInfo info;
153  if (!info.FromStringList(it, strlist.end()))
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  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  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;
197  for (i = 0; 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 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  vector<InputInfo> inputs =
233  RemoteRequestFreeInputInfo(excluded_input);
234 
235  vector<uint> inputids;
236  for (size_t j = 0; j < inputs.size(); j++)
237  inputids.push_back(inputs[j].m_inputid);
238 
239  LOG(VB_CHANNEL, LOG_INFO,
240  QString("RemoteRequestFreeRecorderList got inputs"));
241  return inputids;
242 }
243 
244 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  vector<InputInfo> inputs =
251  RemoteRequestFreeInputInfo(excluded_input);
252 
253  vector<uint> inputids;
254  for (size_t j = 0; j < inputs.size(); j++)
255  inputids.push_back(inputs[j].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  vector<InputInfo> inputs =
270  RemoteRequestFreeInputInfo(excluded_input);
271 
272  for (QStringList::const_iterator recIter = qualifiedRecorders.begin();
273  recIter != qualifiedRecorders.end(); ++recIter)
274  {
275  uint inputid = (*recIter).toUInt();
276  for (size_t i = 0; i < inputs.size(); ++i)
277  {
278  if (inputs[i].m_inputid == inputid)
279  {
280  LOG(VB_CHANNEL, LOG_INFO,
281  QString("RemoteRequestFreeRecorderFromList got input %1")
282  .arg(inputid));
283  return RemoteGetExistingRecorder(inputid);
284  }
285  }
286  }
287 
288  LOG(VB_CHANNEL, LOG_INFO,
289  QString("RemoteRequestFreeRecorderFromList got no input"));
290  return nullptr;
291 }
292 
294 {
295  LOG(VB_CHANNEL, LOG_INFO,
296  QString("RemoteRequestRecorder entered"));
297 
298  vector<InputInfo> inputs =
300 
301  if (inputs.empty())
302  {
303  LOG(VB_CHANNEL, LOG_INFO,
304  QString("RemoteRequestRecorder got no input"));
305  return nullptr;
306  }
307 
308  LOG(VB_CHANNEL, LOG_INFO,
309  QString("RemoteRequestRecorder got input %1")
310  .arg(inputs[0].m_inputid));
311  return RemoteGetExistingRecorder(inputs[0].m_inputid);
312 }
313 
315 {
316  LOG(VB_CHANNEL, LOG_INFO,
317  QString("RemoteGetExistingRecorder program %1")
318  .arg(pginfo->GetTitle()));
319 
320  QStringList strlist( "GET_RECORDER_NUM" );
321  pginfo->ToStringList(strlist);
322 
323  if (!gCoreContext->SendReceiveStringList(strlist))
324  {
325  LOG(VB_CHANNEL, LOG_INFO,
326  QString("RemoteGetExistingRecorder got no input"));
327  return nullptr;
328  }
329 
330  int num = strlist[0].toInt();
331  QString hostname = strlist[1];
332  int port = strlist[2].toInt();
333 
334  LOG(VB_CHANNEL, LOG_INFO,
335  QString("RemoteGetExistingRecorder got input %1").arg(num));
336  return new RemoteEncoder(num, hostname, port);
337 }
338 
340 {
341  LOG(VB_CHANNEL, LOG_INFO,
342  QString("RemoteGetExistingRecorder input %1")
343  .arg(recordernum));
344 
345  QStringList strlist( "GET_RECORDER_FROM_NUM" );
346  strlist << QString("%1").arg(recordernum);
347 
348  if (!gCoreContext->SendReceiveStringList(strlist))
349  {
350  LOG(VB_CHANNEL, LOG_INFO,
351  QString("RemoteGetExistingRecorder got no input"));
352  return nullptr;
353  }
354 
355  QString hostname = strlist[0];
356  int port = strlist[1].toInt();
357 
358  LOG(VB_CHANNEL, LOG_INFO,
359  QString("RemoteGetExistingRecorder got input %1")
360  .arg(recordernum));
361  return new RemoteEncoder(recordernum, hostname, port);
362 }
363 
364 bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
365 {
366 #if 0
367  LOG(VB_GENERAL, LOG_DEBUG, QString("RemoteIsBusy(%1) %2")
368  .arg(inputid).arg(gCoreContext->IsBackend() ? "be" : "fe"));
369 #endif
370 
371  busy_input.Clear();
372 
373  if (gCoreContext->IsBackend())
374  {
375  const TVRec *rec = TVRec::GetTVRec(inputid);
376  if (rec)
377  return rec->IsBusy(&busy_input);
378 
379  // Note this value is intentionally different than the
380  // non-backend, error value below. There is a small
381  // window when adding an input where an input can exist in
382  // the database, but not yet have a TVRec. In such cases,
383  // we don't want it to be considered busy and block other
384  // actions.
385  return false;
386  }
387 
388  QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
389  strlist << "IS_BUSY";
390  if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
391  return true;
392 
393  QStringList::const_iterator it = strlist.begin();
394  bool state = (*it).toInt() != 0;
395  ++it;
396  if (!busy_input.FromStringList(it, strlist.end()))
397  state = true; // if there was an error pretend that the input is busy.
398 
399  return state;
400 }
401 
403  vector<TunerStatus> *tunerList, bool list_inactive)
404 {
405  bool isRecording = false;
406  vector<uint> inputlist = CardUtil::GetInputList();
407 
408  if (tunerList)
409  tunerList->clear();
410 
411  for (size_t i = 0; i < inputlist.size(); i++)
412  {
413  QString status = "";
414  uint inputid = inputlist[i];
415  int state = kState_ChangingState;
416  QString channelName = "";
417  QString title = "";
418  QString subtitle = "";
419  QDateTime dtStart = QDateTime();
420  QDateTime dtEnd = QDateTime();
421  QStringList strlist;
422 
423  QString cmd = QString("QUERY_REMOTEENCODER %1").arg(inputid);
424 
425  while (state == kState_ChangingState)
426  {
427  strlist = QStringList(cmd);
428  strlist << "GET_STATE";
430 
431  if (strlist.empty())
432  break;
433 
434  state = strlist[0].toInt();
435  if (kState_ChangingState == state)
436  std::this_thread::sleep_for(std::chrono::milliseconds(5));
437  }
438 
439  if (kState_RecordingOnly == state || kState_WatchingRecording == state)
440  {
441  isRecording = true;
442 
443  if (!tunerList)
444  break;
445 
446  strlist = QStringList(QString("QUERY_RECORDER %1").arg(inputid));
447  strlist << "GET_RECORDING";
449 
450  ProgramInfo progInfo(strlist);
451 
452  title = progInfo.GetTitle();
453  subtitle = progInfo.GetSubtitle();
454  channelName = progInfo.GetChannelName();
455  dtStart = progInfo.GetScheduledStartTime();
456  dtEnd = progInfo.GetScheduledEndTime();
457  }
458  else if (!list_inactive)
459  continue;
460 
461  if (tunerList)
462  {
463  TunerStatus tuner;
464  tuner.id = inputid;
465  tuner.isRecording = ((kState_RecordingOnly == state) ||
466  (kState_WatchingRecording == state));
467  tuner.channame = channelName;
468  tuner.title = (kState_ChangingState == state) ?
469  QObject::tr("Error querying recorder state") : title;
470  tuner.subtitle = subtitle;
471  tuner.startTime = dtStart;
472  tuner.endTime = dtEnd;
473  tunerList->push_back(tuner);
474  }
475  }
476 
477  return isRecording;
478 }
479 
480 /* vim: set expandtab tabstop=4 shiftwidth=4: */
void RemoteCancelNextRecording(uint inputid, bool cancel)
static bool isRecording()
RemoteEncoder * RemoteRequestRecorder(void)
void StopRecording(bool killFile=false)
Changes from a recording state to kState_None.
Definition: tv_rec.cpp:702
QDateTime endTime
Definition: tvremoteutil.h:26
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
Definition: programinfo.h:378
void RecordPending(const ProgramInfo *rcinfo, int secsleft, bool hasLater)
Tells TVRec "rcinfo" is the next pending recording.
Definition: tv_rec.cpp:271
bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
QString title
Definition: tvremoteutil.h:23
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
QString GetTitle(void) const
Definition: programinfo.h:353
int RemoteGetFreeRecorderCount(void)
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:2476
uint m_inputid
unique key in DB for this input
Definition: inputinfo.h:71
bool RemoteStopLiveTV(uint inputid)
Watching Recording is the state for when we are watching an in progress recording,...
Definition: tv.h:80
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
recording status stuff
Definition: tvremoteutil.h:17
uint RemoteGetFlags(uint inputid)
uint m_mplexid
mplexid restriction if applicable
Definition: inputinfo.h:72
virtual void Clear(void)
Definition: inputinfo.cpp:6
uint RemoteGetState(uint inputid)
vector< InputInfo > RemoteRequestFreeInputInfo(uint excluded_input)
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:382
Holds information on recordings and videos.
Definition: programinfo.h:66
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
Recording Only is a TVRec only state for when we are recording a program, but there is no one current...
Definition: tv.h:84
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:150
virtual bool FromStringList(QStringList::const_iterator &it, QStringList::const_iterator end)
Definition: inputinfo.cpp:13
vector< uint > RemoteRequestFreeRecorderList(uint excluded_input)
QString channame
Definition: tvremoteutil.h:22
QString GetSubtitle(void) const
Definition: programinfo.h:355
string hostname
Definition: caa.py:17
bool RemoteRecordPending(uint inputid, const ProgramInfo *pginfo, int secsleft, bool hasLater)
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:389
vector< uint > RemoteRequestFreeInputList(uint excluded_input)
TVState GetState(void) const
Returns the TVState of the recorder.
Definition: tv_rec.cpp:225
bool IsBackend(void) const
is this process a backend process
bool RemoteStopRecording(uint inputid)
static vector< uint > GetInputList(void)
uint m_chanid
chanid restriction if applicable
Definition: inputinfo.h:73
uint GetFlags(void) const
Definition: tv_rec.h:252
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool isRecording
Definition: tvremoteutil.h:21
This is a placeholder state which we never actually enter, but is returned by GetState() when we are ...
Definition: tv.h:89
RemoteEncoder * RemoteRequestFreeRecorderFromList(const QStringList &qualifiedRecorders, uint excluded_input)
QString subtitle
Definition: tvremoteutil.h:24
bool RemoteGetRecordingStatus(vector< TunerStatus > *tunerList, bool list_inactive)
static TVRec * GetTVRec(uint inputid)
Definition: tv_rec.cpp:4813
RemoteEncoder * RemoteRequestNextFreeRecorder(int inputid)
void StopLiveTV(void)
Tells TVRec to stop a "Live TV" recorder.
Definition: tv_rec.cpp:2863
QDateTime startTime
Definition: tvremoteutil.h:25
RemoteEncoder * RemoteGetExistingRecorder(const ProgramInfo *pginfo)