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