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