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 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 = 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 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 (auto & input : inputs)
237  inputids.push_back(input.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 (auto & input : inputs)
255  inputids.push_back(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  vector<InputInfo> inputs =
270  RemoteRequestFreeInputInfo(excluded_input);
271 
272  for (const auto & recorder : qAsConst(qualifiedRecorders))
273  {
274  uint inputid = recorder.toUInt();
275  for (auto & input : inputs)
276  {
277  if (input.m_inputId == inputid)
278  {
279  LOG(VB_CHANNEL, LOG_INFO,
280  QString("RemoteRequestFreeRecorderFromList got input %1")
281  .arg(inputid));
282  return RemoteGetExistingRecorder(inputid);
283  }
284  }
285  }
286 
287  LOG(VB_CHANNEL, LOG_INFO,
288  QString("RemoteRequestFreeRecorderFromList got no input"));
289  return nullptr;
290 }
291 
293 {
294  LOG(VB_CHANNEL, LOG_INFO,
295  QString("RemoteRequestRecorder entered"));
296 
297  vector<InputInfo> inputs =
299 
300  if (inputs.empty())
301  {
302  LOG(VB_CHANNEL, LOG_INFO,
303  QString("RemoteRequestRecorder got no input"));
304  return nullptr;
305  }
306 
307  LOG(VB_CHANNEL, LOG_INFO,
308  QString("RemoteRequestRecorder got input %1")
309  .arg(inputs[0].m_inputId));
310  return RemoteGetExistingRecorder(inputs[0].m_inputId);
311 }
312 
314 {
315  LOG(VB_CHANNEL, LOG_INFO,
316  QString("RemoteGetExistingRecorder program %1")
317  .arg(pginfo->GetTitle()));
318 
319  QStringList strlist( "GET_RECORDER_NUM" );
320  pginfo->ToStringList(strlist);
321 
322  if (!gCoreContext->SendReceiveStringList(strlist))
323  {
324  LOG(VB_CHANNEL, LOG_INFO,
325  QString("RemoteGetExistingRecorder got no input"));
326  return nullptr;
327  }
328 
329  int num = strlist[0].toInt();
330  QString hostname = strlist[1];
331  int port = strlist[2].toInt();
332 
333  LOG(VB_CHANNEL, LOG_INFO,
334  QString("RemoteGetExistingRecorder got input %1").arg(num));
335  return new RemoteEncoder(num, hostname, port);
336 }
337 
339 {
340  LOG(VB_CHANNEL, LOG_INFO,
341  QString("RemoteGetExistingRecorder input %1")
342  .arg(recordernum));
343 
344  QStringList strlist( "GET_RECORDER_FROM_NUM" );
345  strlist << QString("%1").arg(recordernum);
346 
347  if (!gCoreContext->SendReceiveStringList(strlist))
348  {
349  LOG(VB_CHANNEL, LOG_INFO,
350  QString("RemoteGetExistingRecorder got no input"));
351  return nullptr;
352  }
353 
354  QString hostname = strlist[0];
355  int port = strlist[1].toInt();
356 
357  LOG(VB_CHANNEL, LOG_INFO,
358  QString("RemoteGetExistingRecorder got input %1")
359  .arg(recordernum));
360  return new RemoteEncoder(recordernum, hostname, port);
361 }
362 
363 bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
364 {
365 #if 0
366  LOG(VB_GENERAL, LOG_DEBUG, QString("RemoteIsBusy(%1) %2")
367  .arg(inputid).arg(gCoreContext->IsBackend() ? "be" : "fe"));
368 #endif
369 
370  busy_input.Clear();
371 
372  if (gCoreContext->IsBackend())
373  {
374  const TVRec *rec = TVRec::GetTVRec(inputid);
375  if (rec)
376  return rec->IsBusy(&busy_input);
377 
378  // Note this value is intentionally different than the
379  // non-backend, error value below. There is a small
380  // window when adding an input where an input can exist in
381  // the database, but not yet have a TVRec. In such cases,
382  // we don't want it to be considered busy and block other
383  // actions.
384  return false;
385  }
386 
387  QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
388  strlist << "IS_BUSY";
389  if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
390  return true;
391 
392  QStringList::const_iterator it = strlist.begin();
393  bool state = (*it).toInt() != 0;
394  ++it;
395  if (!busy_input.FromStringList(it, strlist.end()))
396  state = true; // if there was an error pretend that the input is busy.
397 
398  return state;
399 }
400 
402  vector<TunerStatus> *tunerList, bool list_inactive)
403 {
404  bool isRecording = false;
405  vector<uint> inputlist = CardUtil::GetInputList();
406 
407  if (tunerList)
408  tunerList->clear();
409 
410  for (uint inputid : inputlist)
411  {
412  QString status = "";
413  int state = kState_ChangingState;
414  QString channelName = "";
415  QString title = "";
416  QString subtitle = "";
417  QDateTime dtStart = QDateTime();
418  QDateTime dtEnd = QDateTime();
419  QStringList strlist;
420 
421  QString cmd = QString("QUERY_REMOTEENCODER %1").arg(inputid);
422 
423  while (state == kState_ChangingState)
424  {
425  strlist = QStringList(cmd);
426  strlist << "GET_STATE";
428 
429  if (strlist.empty())
430  break;
431 
432  state = strlist[0].toInt();
433  if (kState_ChangingState == state)
434  std::this_thread::sleep_for(std::chrono::milliseconds(5));
435  }
436 
437  if (kState_RecordingOnly == state || kState_WatchingRecording == state)
438  {
439  isRecording = true;
440 
441  if (!tunerList)
442  break;
443 
444  strlist = QStringList(QString("QUERY_RECORDER %1").arg(inputid));
445  strlist << "GET_RECORDING";
447 
448  ProgramInfo progInfo(strlist);
449 
450  title = progInfo.GetTitle();
451  subtitle = progInfo.GetSubtitle();
452  channelName = progInfo.GetChannelName();
453  dtStart = progInfo.GetScheduledStartTime();
454  dtEnd = progInfo.GetScheduledEndTime();
455  }
456  else if (!list_inactive)
457  continue;
458 
459  if (tunerList)
460  {
461  TunerStatus tuner;
462  tuner.id = inputid;
463  tuner.isRecording = ((kState_RecordingOnly == state) ||
464  (kState_WatchingRecording == state));
465  tuner.channame = channelName;
466  tuner.title = (kState_ChangingState == state) ?
467  QObject::tr("Error querying recorder state") : title;
468  tuner.subtitle = subtitle;
469  tuner.startTime = dtStart;
470  tuner.endTime = dtEnd;
471  tunerList->push_back(tuner);
472  }
473  }
474 
475  return isRecording;
476 }
477 
478 /* 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:313
RemoteRequestRecorder
RemoteEncoder * RemoteRequestRecorder(void)
Definition: tvremoteutil.cpp:292
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:1352
RemoteGetState
uint RemoteGetState(uint inputid)
Definition: tvremoteutil.cpp:30
TunerStatus::title
QString title
Definition: tvremoteutil.h:23
title
QString title
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:633
ProgramInfo::GetChannelName
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
Definition: programinfo.h:381
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:705
TunerStatus::endTime
QDateTime endTime
Definition: tvremoteutil.h:26
ProgramInfo::GetScheduledEndTime
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:392
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:220
RemoteStopLiveTV
bool RemoteStopLiveTV(uint inputid)
Definition: tvremoteutil.cpp:75
RemoteRequestFreeInputInfo
vector< InputInfo > RemoteRequestFreeInputInfo(uint excluded_input)
Definition: tvremoteutil.cpp:136
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:2484
RemoteEncoder
Definition: remoteencoder.h:25
TunerStatus::channame
QString channame
Definition: tvremoteutil.h:22
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
ProgramInfo::GetScheduledStartTime
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:385
RemoteStopRecording
bool RemoteStopRecording(uint inputid)
Definition: tvremoteutil.cpp:97
RemoteIsBusy
bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
Definition: tvremoteutil.cpp:363
ProgramInfo::GetTitle
QString GetTitle(void) const
Definition: programinfo.h:356
RemoteRequestFreeInputList
vector< uint > RemoteRequestFreeInputList(uint excluded_input)
Definition: tvremoteutil.cpp:244
recorder
RemoteEncoder * recorder
Definition: mythtv/programs/mythcommflag/main.cpp:74
uint
unsigned int uint
Definition: compat.h:140
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:57
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
RemoteRequestFreeRecorderList
vector< uint > RemoteRequestFreeRecorderList(uint excluded_input)
Definition: tvremoteutil.cpp:226
ProgramInfo
Holds information on recordings and videos.
Definition: programinfo.h:67
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:647
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:142
TunerStatus::id
uint id
Definition: tvremoteutil.h:20
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:14
TunerStatus::startTime
QDateTime startTime
Definition: tvremoteutil.h:25
remoteencoder.h
RemoteGetRecordingStatus
bool RemoteGetRecordingStatus(vector< TunerStatus > *tunerList, bool list_inactive)
Definition: tvremoteutil.cpp:401
CardUtil::GetInputList
static vector< uint > GetInputList(void)
TVRec::GetFlags
uint GetFlags(void) const
Definition: tv_rec.h:245
musicbrainzngs.caa.hostname
string hostname
Definition: caa.py:17
TunerStatus::isRecording
bool isRecording
Definition: tvremoteutil.h:21
TVRec::StopLiveTV
void StopLiveTV(void)
Tells TVRec to stop a "Live TV" recorder.
Definition: tv_rec.cpp:2880
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:24
TVRec::GetTVRec
static TVRec * GetTVRec(uint inputid)
Definition: tv_rec.cpp:4831
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:358
InputInfo::FromStringList
virtual bool FromStringList(QStringList::const_iterator &it, const QStringList::const_iterator &end)
Definition: inputinfo.cpp:13