CPPMyth
Library to interoperate with MythTV server
Loading...
Searching...
No Matches
mythprotorecorder.cpp
1/*
2 * Copyright (C) 2014 Jean-Luc Barriere
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22#include "mythprotorecorder.h"
23#include "../private/debug.h"
24#include "../private/os/threads/latch.h"
25#include "../private/builtin.h"
26
27
28#include <limits>
29#include <cstdio>
30
31using namespace Myth;
32
33ProtoRecorder::ProtoRecorder(int num, const std::string& server, unsigned port)
34: ProtoPlayback(server, port)
35, m_num(num)
36, m_playing(false)
37, m_liveRecording(false)
38{
39 ProtoPlayback::Open();
40}
41
42ProtoRecorder::~ProtoRecorder()
43{
44 if (m_playing)
45 StopLiveTV();
46 ProtoPlayback::Close();
47}
48
49int ProtoRecorder::GetNum() const
50{
51 return m_num;
52}
53
54bool ProtoRecorder::IsPlaying() const
55{
56 /*
57 * WARNING
58 * reading this must be lock-free, to allow the dispatching of the backend
59 * messages during the spawning step
60 */
61 return m_playing;
62}
63
64bool ProtoRecorder::IsTunable(const Channel& channel)
65{
66 bool ok = false;
67 CardInputListPtr inputlist = GetFreeInputs();
68 for (CardInputList::const_iterator it = inputlist->begin(); it != inputlist->end(); ++it)
69 {
70 const CardInput *input = (*it).get();
71 if (input->sourceId != channel.sourceId)
72 {
73 DBG(DBG_DEBUG, "%s: skip input, source id differs (channel: %" PRIu32 ", input: %" PRIu32 ")\n",
74 __FUNCTION__, channel.sourceId, input->sourceId);
75 continue;
76 }
77 if (input->mplexId && input->mplexId != channel.mplexId)
78 {
79 DBG(DBG_DEBUG, "%s: skip input, multiplex id differs (channel: %" PRIu32 ", input: %" PRIu32 ")\n",
80 __FUNCTION__, channel.mplexId, input->mplexId);
81 continue;
82 }
83 DBG(DBG_DEBUG,"%s: using recorder, input is tunable: source id: %" PRIu32 ", multiplex id: %" PRIu32 ", channel: %" PRIu32 ", input: %" PRIu32 ")\n",
84 __FUNCTION__, channel.sourceId, channel.mplexId, channel.chanId, input->inputId);
85 ok = true;
86 break;
87 }
88 if (!ok)
89 {
90 DBG(DBG_INFO,"%s: recorder is not tunable\n", __FUNCTION__);
91 }
92 return ok;
93}
94
95void ProtoRecorder::DoneRecordingCallback()
96{
97 OS::WriteLock lock(*m_latch);
98 m_liveRecording = false;
99 DBG(DBG_DEBUG, "%s: completed\n", __FUNCTION__);
100}
101
102bool ProtoRecorder::SpawnLiveTV75(const std::string& chainid, const std::string& channum)
103{
104 BUILTIN_BUFFER buf;
105 std::string field;
106
107 OS::WriteLock lock(*m_latch);
108 if (!IsOpen())
109 return false;
110 std::string cmd("QUERY_RECORDER ");
111 int32_to_string((int32_t)m_num, &buf);
112 cmd.append(buf.data);
113 cmd.append(PROTO_STR_SEPARATOR);
114 cmd.append("SPAWN_LIVETV");
115 cmd.append(PROTO_STR_SEPARATOR);
116 cmd.append(chainid);
117 cmd.append(PROTO_STR_SEPARATOR).append("0").append(PROTO_STR_SEPARATOR);
118 cmd.append(channum);
119
120 DBG(DBG_DEBUG, "%s: starting ...\n", __FUNCTION__);
121 m_playing = true;
122 if (!SendCommand(cmd.c_str()))
123 {
124 m_playing = false;
125 }
126 else if (!ReadField(field) || !IsMessageOK(field))
127 {
128 m_playing = false;
129 FlushMessage();
130 }
131 DBG(DBG_DEBUG, "%s: %s\n", __FUNCTION__, (m_playing ? "succeeded" : "failed"));
132 return m_playing;
133}
134
135bool ProtoRecorder::StopLiveTV75()
136{
137 BUILTIN_BUFFER buf;
138 std::string field;
139
140 OS::WriteLock lock(*m_latch);
141 if (!IsOpen())
142 return false;
143 std::string cmd("QUERY_RECORDER ");
144 int32_to_string((int32_t)m_num, &buf);
145 cmd.append(buf.data);
146 cmd.append(PROTO_STR_SEPARATOR);
147 cmd.append("STOP_LIVETV");
148
149 if (!SendCommand(cmd.c_str()))
150 return false;
151 if (!ReadField(field) || !IsMessageOK(field))
152 {
153 FlushMessage();
154 return false;
155 }
156 m_playing = false;
157 return true;
158}
159
160bool ProtoRecorder::CheckChannel75(const std::string& channum)
161{
162 BUILTIN_BUFFER buf;
163 std::string field;
164
165 OS::WriteLock lock(*m_latch);
166 if (!IsOpen())
167 return false;
168 std::string cmd("QUERY_RECORDER ");
169 int32_to_string((int32_t)m_num, &buf);
170 cmd.append(buf.data);
171 cmd.append(PROTO_STR_SEPARATOR);
172 cmd.append("CHECK_CHANNEL");
173 cmd.append(PROTO_STR_SEPARATOR);
174 cmd.append(channum);
175
176 if (!SendCommand(cmd.c_str()))
177 return false;
178 if (!ReadField(field) || field != "1")
179 {
180 DBG(DBG_DEBUG, "%s: %s\n", __FUNCTION__, field.c_str());
181 FlushMessage();
182 return false;
183 }
184 return true;
185}
186
187ProgramPtr ProtoRecorder::GetCurrentRecording75()
188{
189 BUILTIN_BUFFER buf;
190 ProgramPtr program;
191
192 OS::WriteLock lock(*m_latch);
193 if (!IsOpen())
194 return program;
195 std::string cmd("QUERY_RECORDER ");
196 int32_to_string((int32_t)m_num, &buf);
197 cmd.append(buf.data);
198 cmd.append(PROTO_STR_SEPARATOR);
199 cmd.append("GET_CURRENT_RECORDING");
200
201 if (!SendCommand(cmd.c_str()))
202 return program;
203
204 if (!(program = RcvProgramInfo()))
205 goto out;
206 FlushMessage();
207 return program;
208out:
209 DBG(DBG_ERROR, "%s: failed\n", __FUNCTION__);
210 FlushMessage();
211 return program;
212}
213
214int64_t ProtoRecorder::GetFilePosition75()
215{
216 BUILTIN_BUFFER buf;
217 int64_t pos;
218 std::string field;
219
220 OS::WriteLock lock(*m_latch);
221 if (!IsOpen() || !IsPlaying())
222 return -1;
223 std::string cmd("QUERY_RECORDER ");
224 int32_to_string((int32_t)m_num, &buf);
225 cmd.append(buf.data);
226 cmd.append(PROTO_STR_SEPARATOR);
227 cmd.append("GET_FILE_POSITION");
228
229 if (!SendCommand(cmd.c_str()))
230 return -1;
231
232 if (!ReadField(field) || string_to_int64(field.c_str(), &pos))
233 goto out;
234
235 FlushMessage();
236 return pos;
237
238out:
239 FlushMessage();
240 return -1;
241}
242
243CardInputListPtr ProtoRecorder::GetFreeInputs75()
244{
245 CardInputListPtr list = CardInputListPtr(new CardInputList());
246 BUILTIN_BUFFER buf;
247 std::string field;
248
249 OS::WriteLock lock(*m_latch);
250 if (!IsOpen())
251 return list;
252 std::string cmd("QUERY_RECORDER ");
253 int32_to_string((int32_t)m_num, &buf);
254 cmd.append(buf.data);
255 cmd.append(PROTO_STR_SEPARATOR);
256 cmd.append("GET_FREE_INPUTS");
257
258 if (!SendCommand(cmd.c_str()))
259 return list;
260
261 while (m_msgConsumed < m_msgLength)
262 {
263 CardInputPtr input(new CardInput());
264 if (!ReadField(input->inputName))
265 break;
266 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->sourceId)))
267 break;
268 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->inputId)))
269 break;
270 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->cardId)))
271 break;
272 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->mplexId)))
273 break;
274 if (!ReadField(field) || string_to_uint8(field.c_str(), &(input->liveTVOrder)))
275 break;
276 list->push_back(input);
277 }
278 FlushMessage();
279 return list;
280}
281
282CardInputListPtr ProtoRecorder::GetFreeInputs79()
283{
284 CardInputListPtr list = CardInputListPtr(new CardInputList());
285 BUILTIN_BUFFER buf;
286 std::string field;
287
288 OS::WriteLock lock(*m_latch);
289 if (!IsOpen())
290 return list;
291 std::string cmd("QUERY_RECORDER ");
292 int32_to_string((int32_t)m_num, &buf);
293 cmd.append(buf.data);
294 cmd.append(PROTO_STR_SEPARATOR);
295 cmd.append("GET_FREE_INPUTS");
296
297 if (!SendCommand(cmd.c_str()))
298 return list;
299
300 while (m_msgConsumed < m_msgLength)
301 {
302 CardInputPtr input(new CardInput());
303 if (!ReadField(input->inputName))
304 break;
305 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->sourceId)))
306 break;
307 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->inputId)))
308 break;
309 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->cardId)))
310 break;
311 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->mplexId)))
312 break;
313 if (!ReadField(field) || string_to_uint8(field.c_str(), &(input->liveTVOrder)))
314 break;
315 if (!ReadField(field)) // displayName
316 break;
317 if (!ReadField(field)) // recPriority
318 break;
319 if (!ReadField(field)) // schedOrder
320 break;
321 if (!ReadField(field)) // quickTune
322 break;
323 list->push_back(input);
324 }
325 FlushMessage();
326 return list;
327}
328
329CardInputListPtr ProtoRecorder::GetFreeInputs81()
330{
331 CardInputListPtr list = CardInputListPtr(new CardInputList());
332 BUILTIN_BUFFER buf;
333 std::string field;
334
335 OS::WriteLock lock(*m_latch);
336 if (!IsOpen())
337 return list;
338 std::string cmd("QUERY_RECORDER ");
339 int32_to_string((int32_t)m_num, &buf);
340 cmd.append(buf.data);
341 cmd.append(PROTO_STR_SEPARATOR);
342 cmd.append("GET_FREE_INPUTS");
343
344 if (!SendCommand(cmd.c_str()))
345 return list;
346
347 while (m_msgConsumed < m_msgLength)
348 {
349 CardInputPtr input(new CardInput());
350 if (!ReadField(input->inputName))
351 break;
352 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->sourceId)))
353 break;
354 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->inputId)))
355 break;
356 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->cardId)))
357 break;
358 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->mplexId)))
359 break;
360 if (!ReadField(field) || string_to_uint8(field.c_str(), &(input->liveTVOrder)))
361 break;
362 if (!ReadField(field)) // displayName
363 break;
364 if (!ReadField(field)) // recPriority
365 break;
366 if (!ReadField(field)) // schedOrder
367 break;
368 if (!ReadField(field)) // quickTune
369 break;
370 if (!ReadField(field)) // chanid
371 break;
372 list->push_back(input);
373 }
374 FlushMessage();
375 return list;
376}
377
378CardInputListPtr ProtoRecorder::GetFreeInputs87()
379{
380 CardInputListPtr list = CardInputListPtr(new CardInputList());
381 std::string field;
382
383 OS::WriteLock lock(*m_latch);
384 if (!IsOpen())
385 return list;
386 std::string cmd("GET_FREE_INPUT_INFO 0");
387
388 if (!SendCommand(cmd.c_str()))
389 return list;
390
391 while (m_msgConsumed < m_msgLength)
392 {
393 CardInputPtr input(new CardInput());
394 if (!ReadField(input->inputName))
395 break;
396 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->sourceId)))
397 break;
398 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->inputId)))
399 break;
400 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->cardId)))
401 break;
402 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->mplexId)))
403 break;
404 if (!ReadField(field) || string_to_uint8(field.c_str(), &(input->liveTVOrder)))
405 break;
406 if (!ReadField(field)) // displayName
407 break;
408 if (!ReadField(field)) // recPriority
409 break;
410 if (!ReadField(field)) // schedOrder
411 break;
412 if (!ReadField(field)) // quickTune
413 break;
414 if (!ReadField(field)) // chanid
415 break;
416 if (input->cardId == static_cast<unsigned>(m_num))
417 list->push_back(input);
418 }
419 FlushMessage();
420 return list;
421}
422
423CardInputListPtr ProtoRecorder::GetFreeInputs89()
424{
425 CardInputListPtr list = CardInputListPtr(new CardInputList());
426 std::string field;
427
428 OS::WriteLock lock(*m_latch);
429 if (!IsOpen())
430 return list;
431 std::string cmd("GET_FREE_INPUT_INFO 0");
432
433 if (!SendCommand(cmd.c_str()))
434 return list;
435
436 while (m_msgConsumed < m_msgLength)
437 {
438 CardInputPtr input(new CardInput());
439 if (!ReadField(input->inputName))
440 break;
441 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->sourceId)))
442 break;
443 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->inputId)))
444 break;
445 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->cardId)))
446 break;
447 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->mplexId)))
448 break;
449 if (!ReadField(field) || string_to_uint8(field.c_str(), &(input->liveTVOrder)))
450 break;
451 if (!ReadField(field)) // displayName
452 break;
453 if (!ReadField(field)) // recPriority
454 break;
455 if (!ReadField(field)) // schedOrder
456 break;
457 if (!ReadField(field)) // quickTune
458 break;
459 if (!ReadField(field)) // chanid
460 break;
461 if (!ReadField(field)) // reclimit
462 break;
463 if (input->cardId == static_cast<unsigned>(m_num))
464 list->push_back(input);
465 }
466 FlushMessage();
467 return list;
468}
469
470CardInputListPtr ProtoRecorder::GetFreeInputs90()
471{
472 CardInputListPtr list = CardInputListPtr(new CardInputList());
473 std::string field;
474
475 OS::WriteLock lock(*m_latch);
476 if (!IsOpen())
477 return list;
478 std::string cmd("GET_FREE_INPUT_INFO 0");
479
480 if (!SendCommand(cmd.c_str()))
481 return list;
482
483 while (m_msgConsumed < m_msgLength)
484 {
485 CardInputPtr input(new CardInput());
486 if (!ReadField(input->inputName))
487 break;
488 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->sourceId)))
489 break;
490 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->inputId)))
491 break;
492 input->cardId = input->inputId; // @FIXME: since protocol 90
493 if (!ReadField(field)) // reccount
494 break;
495 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->mplexId)))
496 break;
497 if (!ReadField(field) || string_to_uint8(field.c_str(), &(input->liveTVOrder)))
498 break;
499 if (!ReadField(field)) // displayName
500 break;
501 if (!ReadField(field)) // recPriority
502 break;
503 if (!ReadField(field)) // schedOrder
504 break;
505 if (!ReadField(field)) // quickTune
506 break;
507 if (!ReadField(field)) // chanid
508 break;
509 if (!ReadField(field)) // reclimit
510 break;
511 if (input->cardId == static_cast<unsigned>(m_num))
512 list->push_back(input);
513 }
514 FlushMessage();
515 return list;
516}
517
518CardInputListPtr ProtoRecorder::GetFreeInputs91()
519{
520 CardInputListPtr list = CardInputListPtr(new CardInputList());
521 std::string field;
522
523 OS::WriteLock lock(*m_latch);
524 if (!IsOpen())
525 return list;
526 std::string cmd("GET_FREE_INPUT_INFO 0");
527
528 if (!SendCommand(cmd.c_str()))
529 return list;
530
531 while (m_msgConsumed < m_msgLength)
532 {
533 CardInputPtr input(new CardInput());
534 if (!ReadField(input->inputName))
535 break;
536 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->sourceId)))
537 break;
538 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->inputId)))
539 break;
540 input->cardId = input->inputId; // @FIXME: since protocol 90
541 if (!ReadField(field) || string_to_uint32(field.c_str(), &(input->mplexId)))
542 break;
543 if (!ReadField(field) || string_to_uint8(field.c_str(), &(input->liveTVOrder)))
544 break;
545 if (!ReadField(field)) // displayName
546 break;
547 if (!ReadField(field)) // recPriority
548 break;
549 if (!ReadField(field)) // schedOrder
550 break;
551 if (!ReadField(field)) // quickTune
552 break;
553 if (!ReadField(field)) // chanid
554 break;
555 if (input->cardId == static_cast<unsigned>(m_num))
556 list->push_back(input);
557 }
558 FlushMessage();
559 return list;
560}
561
562bool ProtoRecorder::IsLiveRecording()
563{
564 OS::ReadLock lock(*m_latch);
565 return m_liveRecording;
566}
567
568bool ProtoRecorder::SetLiveRecording75(bool keep)
569{
570 BUILTIN_BUFFER buf;
571 std::string field;
572
573 OS::WriteLock lock(*m_latch);
574 if (!IsOpen())
575 return false;
576 std::string cmd("QUERY_RECORDER ");
577 int32_to_string((int32_t)m_num, &buf);
578 cmd.append(buf.data);
579 cmd.append(PROTO_STR_SEPARATOR);
580 cmd.append("SET_LIVE_RECORDING").append(PROTO_STR_SEPARATOR);
581 if (keep)
582 cmd.append("1");
583 else
584 cmd.append("0");
585
586 if (!SendCommand(cmd.c_str()))
587 return false;
588
589 if (!ReadField(field) || !IsMessageOK(field))
590 goto out;
591 DBG(DBG_DEBUG, "%s: succeeded (%d)\n", __FUNCTION__, keep);
592 return true;
593out:
594 DBG(DBG_ERROR, "%s: failed\n", __FUNCTION__);
595 FlushMessage();
596 return false;
597}
598
599bool ProtoRecorder::FinishRecording75()
600{
601 BUILTIN_BUFFER buf;
602 std::string field;
603
604 OS::WriteLock lock(*m_latch);
605 if (!IsOpen())
606 return false;
607 std::string cmd("QUERY_RECORDER ");
608 int32_to_string((int32_t)m_num, &buf);
609 cmd.append(buf.data);
610 cmd.append(PROTO_STR_SEPARATOR);
611 cmd.append("FINISH_RECORDING");
612
613 if (!SendCommand(cmd.c_str()))
614 return false;
615
616 if (!ReadField(field) || !IsMessageOK(field))
617 goto out;
618 DBG(DBG_DEBUG, "%s: succeeded\n", __FUNCTION__);
619 return true;
620out:
621 DBG(DBG_ERROR, "%s: failed\n", __FUNCTION__);
622 FlushMessage();
623 return false;
624}
bool ReadField(std::string &field)
This is the main namespace that encloses all public classes.
Definition mythcontrol.h:30