MythTV master
tvremoteutil.cpp
Go to the documentation of this file.
1#include <chrono> // for milliseconds
2#include <thread> // for sleep_for
3
7
8#include "cardutil.h"
9#include "inputinfo.h"
10#include "remoteencoder.h"
11#include "tv_rec.h"
12#include "tvremoteutil.h"
13
15{
17 {
18 const TVRec *rec = TVRec::GetTVRec(inputid);
19 if (rec)
20 return rec->GetFlags();
21 return 0;
22 }
23
24 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
25 strlist << "GET_FLAGS";
26 if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
27 return 0;
28
29 return strlist[0].toInt();
30}
31
33{
35 {
36 const TVRec *rec = TVRec::GetTVRec(inputid);
37 if (rec)
38 return rec->GetState();
40 }
41
42 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
43 strlist << "GET_STATE";
44 if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
46
47 return strlist[0].toInt();
48}
49
50
51bool RemoteRecordPending(uint inputid, const ProgramInfo *pginfo,
52 std::chrono::seconds secsleft, bool hasLater)
53{
55 {
56 TVRec *rec = TVRec::GetTVRec(inputid);
57 if (rec)
58 {
59 rec->RecordPending(pginfo, secsleft, hasLater);
60 return true;
61 }
62 return false;
63 }
64
65 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
66 strlist << "RECORD_PENDING";
67 strlist << QString::number(secsleft.count());
68 strlist << QString::number(static_cast<int>(hasLater));
69 pginfo->ToStringList(strlist);
70
71 if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
72 return false;
73
74 return strlist[0].toUpper() == "OK";
75}
76
78{
80 {
81 TVRec *rec = TVRec::GetTVRec(inputid);
82 if (rec)
83 {
84 rec->StopLiveTV();
85 return true;
86 }
87 return false;
88 }
89
90 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
91 strlist << "STOP_LIVETV";
92
93 if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
94 return false;
95
96 return strlist[0].toUpper() == "OK";
97}
98
100{
101 if (gCoreContext->IsBackend())
102 {
103 TVRec *rec = TVRec::GetTVRec(inputid);
104 if (rec)
105 {
106 rec->StopRecording();
107 return true;
108 }
109 return false;
110 }
111
112 QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(inputid));
113 strlist << "STOP_RECORDING";
114
115 if (!gCoreContext->SendReceiveStringList(strlist) || strlist.empty())
116 return false;
117
118 return strlist[0].toUpper() == "OK";
119}
120
122{
123 QStringList strlist(QString("STOP_RECORDING"));
124 pginfo->ToStringList(strlist);
125
127}
128
129void RemoteCancelNextRecording(uint inputid, bool cancel)
130{
131 QStringList strlist(QString("QUERY_RECORDER %1").arg(inputid));
132 strlist << "CANCEL_NEXT_RECORDING";
133 strlist << QString::number((cancel) ? 1 : 0);
134
136}
137
138std::vector<InputInfo> RemoteRequestFreeInputInfo(uint excluded_input)
139{
140 LOG(VB_CHANNEL, LOG_INFO,
141 QString("RemoteRequestFreeInputInfo excluding input %1")
142 .arg(excluded_input));
143
144 std::vector<InputInfo> inputs;
145
146 QStringList strlist(QString("GET_FREE_INPUT_INFO %1")
147 .arg(excluded_input));
148 if (!gCoreContext->SendReceiveStringList(strlist))
149 return inputs;
150
151 QStringList::const_iterator it = strlist.cbegin();
152 while (it != strlist.cend())
153 {
155 if (!info.FromStringList(it, strlist.cend()))
156 break;
157 inputs.push_back(info);
158 LOG(VB_CHANNEL, LOG_INFO,
159 QString("RemoteRequestFreeInputInfo got input %1 (%2/%3)")
160 .arg(info.m_inputId).arg(info.m_chanId).arg(info.m_mplexId));
161 }
162
163 LOG(VB_CHANNEL, LOG_INFO,
164 QString("RemoteRequestFreeInputInfo got %1 inputs")
165 .arg(inputs.size()));
166 return inputs;
167}
168
170{
171 LOG(VB_CHANNEL, LOG_INFO, QString("RemoteGetFreeRecorderCount"));
172
173 std::vector<InputInfo> inputs =
175
176 LOG(VB_CHANNEL, LOG_INFO, QString("RemoteGetFreeRecorderCount got %1")
177 .arg(inputs.size()));
178 return inputs.size();
179}
180
182{
183 LOG(VB_CHANNEL, LOG_INFO,
184 QString("RemoteRequestNextFreeRecorder after input %1)")
185 .arg(inputid));
186
187 std::vector<InputInfo> inputs =
189
190 if (inputs.empty())
191 {
192 LOG(VB_CHANNEL, LOG_INFO,
193 QString("RemoteRequestNextFreeRecorder got no input (after input %1)")
194 .arg(inputid));
195 return nullptr;
196 }
197
198 size_t i = 0;
199 for ( ; i < inputs.size(); ++i)
200 if (inputs[i].m_inputId == (uint)inputid)
201 break;
202
203 if (i >= inputs.size())
204 {
205 // We should always find the referenced input. If we don't,
206 // just return the first one.
207 i = 0;
208 }
209 else
210 {
211 // Try to find the next input with a different name. If one
212 // doesn't exist, just return the current one.
213 size_t j = i;
214 i = (i + 1) % inputs.size();
215 while (i != j && inputs[i].m_displayName == inputs[j].m_displayName)
216 {
217 i = (i + 1) % inputs.size();
218 }
219 }
220
221 LOG(VB_CHANNEL, LOG_INFO,
222 QString("RemoteRequestNextFreeRecorder got input %1")
223 .arg(inputs[i].m_inputId));
224
225 return RemoteGetExistingRecorder(inputs[i].m_inputId);
226}
227
228std::vector<uint> RemoteRequestFreeRecorderList(uint excluded_input)
229{
230 LOG(VB_CHANNEL, LOG_INFO,
231 QString("RemoteRequestFreeRecorderList excluding input %1")
232 .arg(excluded_input));
233
234 std::vector<InputInfo> inputs =
235 RemoteRequestFreeInputInfo(excluded_input);
236
237 std::vector<uint> inputids;
238 std::transform(inputs.cbegin(), inputs.cend(), std::back_inserter(inputids),
239 [](const auto & input){ return input.m_inputId; } );
240
241 LOG(VB_CHANNEL, LOG_INFO,
242 QString("RemoteRequestFreeRecorderList got inputs"));
243 return inputids;
244}
245
246std::vector<uint> RemoteRequestFreeInputList(uint excluded_input)
247{
248 LOG(VB_CHANNEL, LOG_INFO,
249 QString("RemoteRequestFreeInputList excluding input %1")
250 .arg(excluded_input));
251
252 std::vector<InputInfo> inputs =
253 RemoteRequestFreeInputInfo(excluded_input);
254
255 std::vector<uint> inputids;
256 std::transform(inputs.cbegin(), inputs.cend(), std::back_inserter(inputids),
257 [](const auto & input){ return input.m_inputId; } );
258
259 LOG(VB_CHANNEL, LOG_INFO,
260 QString("RemoteRequestFreeInputList got inputs"));
261 return inputids;
262}
263
265(const QStringList &qualifiedRecorders, uint excluded_input)
266{
267 LOG(VB_CHANNEL, LOG_INFO,
268 QString("RemoteRequestFreeRecorderFromList excluding input %1")
269 .arg(excluded_input));
270
271 std::vector<InputInfo> inputs =
272 RemoteRequestFreeInputInfo(excluded_input);
273
274 for (const auto & recorder : std::as_const(qualifiedRecorders))
275 {
276 uint inputid = recorder.toUInt();
277 auto sameinput = [inputid](const auto & input){ return input.m_inputId == inputid; };
278 if (std::any_of(inputs.cbegin(), inputs.cend(), sameinput))
279 {
280 LOG(VB_CHANNEL, LOG_INFO,
281 QString("RemoteRequestFreeRecorderFromList got input %1")
282 .arg(inputid));
283 return RemoteGetExistingRecorder(inputid);
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 std::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
363bool 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.cbegin();
393 bool state = (*it).toInt() != 0;
394 ++it;
395 if (!busy_input.FromStringList(it, strlist.cend()))
396 state = true; // if there was an error pretend that the input is busy.
397
398 return state;
399}
400
402 std::vector<TunerStatus> *tunerList, bool list_inactive)
403{
404 bool isRecording = false;
405 std::vector<uint> inputlist = CardUtil::GetInputList();
406
407 if (tunerList)
408 tunerList->clear();
409
410 for (uint inputid : inputlist)
411 {
412 int state = kState_ChangingState;
413 QString channelName = "";
414 QString title = "";
415 QString subtitle = "";
416 QDateTime dtStart = QDateTime();
417 QDateTime dtEnd = QDateTime();
418 QStringList strlist;
419
420 QString cmd = QString("QUERY_REMOTEENCODER %1").arg(inputid);
421
422 while (state == kState_ChangingState)
423 {
424 strlist = QStringList(cmd);
425 strlist << "GET_STATE";
427
428 if (strlist.empty())
429 break;
430
431 state = strlist[0].toInt();
432 if (kState_ChangingState == state)
433 std::this_thread::sleep_for(5ms);
434 }
435
436 if (kState_RecordingOnly == state || kState_WatchingRecording == state)
437 {
438 isRecording = true;
439
440 if (!tunerList)
441 break;
442
443 strlist = QStringList(QString("QUERY_RECORDER %1").arg(inputid));
444 strlist << "GET_RECORDING";
446
447 ProgramInfo progInfo(strlist);
448
449 title = progInfo.GetTitle();
450 subtitle = progInfo.GetSubtitle();
451 channelName = progInfo.GetChannelName();
452 dtStart = progInfo.GetScheduledStartTime();
453 dtEnd = progInfo.GetScheduledEndTime();
454 }
455 else if (!list_inactive)
456 {
457 continue;
458 }
459
460 if (tunerList)
461 {
462 TunerStatus tuner;
463 tuner.id = inputid;
464 tuner.isRecording = ((kState_RecordingOnly == state) ||
465 (kState_WatchingRecording == state));
466 tuner.channame = channelName;
467 tuner.title = (kState_ChangingState == state) ?
468 QObject::tr("Error querying recorder state") : title;
469 tuner.subtitle = subtitle;
470 tuner.startTime = dtStart;
471 tuner.endTime = dtEnd;
472 tunerList->push_back(tuner);
473 }
474 }
475
476 return isRecording;
477}
478
479/* vim: set expandtab tabstop=4 shiftwidth=4: */
static std::vector< uint > GetInputList(void)
Definition: cardutil.cpp:2902
virtual bool FromStringList(QStringList::const_iterator &it, const QStringList::const_iterator &end)
Definition: inputinfo.cpp:14
virtual void Clear(void)
Definition: inputinfo.cpp:6
bool IsBackend(void) const
is this process a backend process
bool SendReceiveStringList(QStringList &strlist, bool quickTimeout=false, bool block=true)
Send a message to the backend and wait for a response.
Holds information on recordings and videos.
Definition: programinfo.h:68
QDateTime GetScheduledEndTime(void) const
The scheduled end time of the program.
Definition: programinfo.h:398
QString GetChannelName(void) const
This is the channel name in the local market, i.e.
Definition: programinfo.h:387
QString GetTitle(void) const
Definition: programinfo.h:362
QDateTime GetScheduledStartTime(void) const
The scheduled start time of program.
Definition: programinfo.h:391
void ToStringList(QStringList &list) const
Serializes ProgramInfo into a QStringList which can be passed over a socket.
QString GetSubtitle(void) const
Definition: programinfo.h:364
This is the coordinating class of the Recorder Subsystem.
Definition: tv_rec.h:143
uint GetFlags(void) const
Definition: tv_rec.h:245
void RecordPending(const ProgramInfo *rcinfo, std::chrono::seconds secsleft, bool hasLater)
Tells TVRec "rcinfo" is the next pending recording.
Definition: tv_rec.cpp:312
void StopLiveTV(void)
Tells TVRec to stop a "Live TV" recorder.
Definition: tv_rec.cpp:2930
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:2537
static TVRec * GetTVRec(uint inputid)
Definition: tv_rec.cpp:4905
TVState GetState(void) const
Returns the TVState of the recorder.
Definition: tv_rec.cpp:264
void StopRecording(bool killFile=false)
Changes from a recording state to kState_None.
Definition: tv_rec.cpp:748
recording status stuff
Definition: tvremoteutil.h:17
bool isRecording
Definition: tvremoteutil.h:20
QDateTime endTime
Definition: tvremoteutil.h:25
QString subtitle
Definition: tvremoteutil.h:23
QString channame
Definition: tvremoteutil.h:21
QString title
Definition: tvremoteutil.h:22
QDateTime startTime
Definition: tvremoteutil.h:24
unsigned int uint
Definition: freesurround.h:24
RemoteEncoder * recorder
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
static bool isRecording()
dictionary info
Definition: azlyrics.py:7
string hostname
Definition: caa.py:17
@ 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:87
@ kState_WatchingRecording
Watching Recording is the state for when we are watching an in progress recording,...
Definition: tv.h:83
@ kState_ChangingState
This is a placeholder state which we never actually enter, but is returned by GetState() when we are ...
Definition: tv.h:92
bool RemoteStopLiveTV(uint inputid)
RemoteEncoder * RemoteRequestRecorder(void)
std::vector< uint > RemoteRequestFreeInputList(uint excluded_input)
bool RemoteStopRecording(uint inputid)
bool RemoteIsBusy(uint inputid, InputInfo &busy_input)
bool RemoteRecordPending(uint inputid, const ProgramInfo *pginfo, std::chrono::seconds secsleft, bool hasLater)
RemoteEncoder * RemoteGetExistingRecorder(const ProgramInfo *pginfo)
RemoteEncoder * RemoteRequestNextFreeRecorder(int inputid)
std::vector< InputInfo > RemoteRequestFreeInputInfo(uint excluded_input)
int RemoteGetFreeRecorderCount(void)
bool RemoteGetRecordingStatus(std::vector< TunerStatus > *tunerList, bool list_inactive)
uint RemoteGetState(uint inputid)
uint RemoteGetFlags(uint inputid)
std::vector< uint > RemoteRequestFreeRecorderList(uint excluded_input)
RemoteEncoder * RemoteRequestFreeRecorderFromList(const QStringList &qualifiedRecorders, uint excluded_input)
void RemoteCancelNextRecording(uint inputid, bool cancel)