vdr  2.4.0
device.c
Go to the documentation of this file.
1 /*
2  * device.c: The basic device interface
3  *
4  * See the main source file 'vdr.c' for copyright information and
5  * how to reach the author.
6  *
7  * $Id: device.c 4.27 2018/03/24 09:49:14 kls Exp $
8  */
9 
10 #include "device.h"
11 #include <errno.h>
12 #include <math.h>
13 #include <sys/ioctl.h>
14 #include <sys/mman.h>
15 #include "audio.h"
16 #include "channels.h"
17 #include "i18n.h"
18 #include "player.h"
19 #include "receiver.h"
20 #include "status.h"
21 #include "transfer.h"
22 
23 // --- cLiveSubtitle ---------------------------------------------------------
24 
25 class cLiveSubtitle : public cReceiver {
26 protected:
27  virtual void Receive(const uchar *Data, int Length);
28 public:
29  cLiveSubtitle(int SPid);
30  virtual ~cLiveSubtitle();
31  };
32 
34 {
35  AddPid(SPid);
36 }
37 
39 {
41 }
42 
43 void cLiveSubtitle::Receive(const uchar *Data, int Length)
44 {
46  cDevice::PrimaryDevice()->PlayTs(Data, Length);
47 }
48 
49 // --- cDeviceHook -----------------------------------------------------------
50 
52 {
54 }
55 
56 bool cDeviceHook::DeviceProvidesTransponder(const cDevice *Device, const cChannel *Channel) const
57 {
58  return true;
59 }
60 
61 // --- cDevice ---------------------------------------------------------------
62 
63 // The minimum number of unknown PS1 packets to consider this a "pre 1.3.19 private stream":
64 #define MIN_PRE_1_3_19_PRIVATESTREAM 10
65 
66 int cDevice::numDevices = 0;
67 int cDevice::useDevice = 0;
73 
75 :patPmtParser(true)
76 {
78  dsyslog("new device number %d", CardIndex() + 1);
79 
80  SetDescription("device %d receiver", CardIndex() + 1);
81 
82  mute = false;
84 
85  sectionHandler = NULL;
86  eitFilter = NULL;
87  patFilter = NULL;
88  sdtFilter = NULL;
89  nitFilter = NULL;
90 
91  camSlot = NULL;
92 
93  occupiedTimeout = 0;
94 
95  player = NULL;
96  isPlayingVideo = false;
97  keepTracks = false; // used in ClrAvailableTracks()!
102  liveSubtitle = NULL;
103  dvbSubtitleConverter = NULL;
105 
106  for (int i = 0; i < MAXRECEIVERS; i++)
107  receiver[i] = NULL;
108 
109  if (numDevices < MAXDEVICES)
110  device[numDevices++] = this;
111  else
112  esyslog("ERROR: too many devices!");
113 }
114 
116 {
117  Detach(player);
119  delete liveSubtitle;
120  delete dvbSubtitleConverter;
121  if (this == primaryDevice)
122  primaryDevice = NULL;
123  Cancel(3);
124 }
125 
127 {
128  for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) {
129  bool ready = true;
130  for (int i = 0; i < numDevices; i++) {
131  if (device[i] && !device[i]->Ready()) {
132  ready = false;
133  cCondWait::SleepMs(100);
134  }
135  }
136  if (ready)
137  return true;
138  }
139  return false;
140 }
141 
143 {
144  if (n < MAXDEVICES)
145  useDevice |= (1 << n);
146 }
147 
149 {
150  if (n > 0) {
151  nextCardIndex += n;
152  if (nextCardIndex >= MAXDEVICES)
153  esyslog("ERROR: nextCardIndex too big (%d)", nextCardIndex);
154  }
155  else if (n < 0)
156  esyslog("ERROR: invalid value in nextCardIndex(%d)", n);
157  return nextCardIndex;
158 }
159 
160 int cDevice::DeviceNumber(void) const
161 {
162  for (int i = 0; i < numDevices; i++) {
163  if (device[i] == this)
164  return i;
165  }
166  return -1;
167 }
168 
170 {
171  return "";
172 }
173 
175 {
176  return "";
177 }
178 
180 {
181  if (!On) {
184  }
185 }
186 
188 {
189  n--;
190  if (0 <= n && n < numDevices && device[n]) {
191  isyslog("setting primary device to %d", n + 1);
192  if (primaryDevice)
194  primaryDevice = device[n];
198  Setup.PrimaryDVB = n + 1;
199  return true;
200  }
201  esyslog("ERROR: invalid primary device number: %d", n + 1);
202  return false;
203 }
204 
205 bool cDevice::HasDecoder(void) const
206 {
207  return false;
208 }
209 
211 {
212  return NULL;
213 }
214 
216 {
218  if (!d)
219  d = PrimaryDevice();
220  return d;
221 }
222 
224 {
225  return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
226 }
227 
228 static int GetClippedNumProvidedSystems(int AvailableBits, cDevice *Device)
229 {
230  int MaxNumProvidedSystems = (1 << AvailableBits) - 1;
231  int NumProvidedSystems = Device->NumProvidedSystems();
232  if (NumProvidedSystems > MaxNumProvidedSystems) {
233  esyslog("ERROR: device %d supports %d modulation systems but cDevice::GetDevice() currently only supports %d delivery systems which should be fixed", Device->CardIndex() + 1, NumProvidedSystems, MaxNumProvidedSystems);
234  NumProvidedSystems = MaxNumProvidedSystems;
235  }
236  else if (NumProvidedSystems <= 0) {
237  esyslog("ERROR: device %d reported an invalid number (%d) of supported delivery systems - assuming 1", Device->CardIndex() + 1, NumProvidedSystems);
238  NumProvidedSystems = 1;
239  }
240  return NumProvidedSystems;
241 }
242 
243 cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView, bool Query)
244 {
245  // Collect the current priorities of all CAM slots that can decrypt the channel:
246  int NumCamSlots = CamSlots.Count();
247  int SlotPriority[NumCamSlots];
248  int NumUsableSlots = 0;
249  bool InternalCamNeeded = false;
250  if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
252  SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
253  if (CamSlot->ModuleStatus() == msReady) {
254  if (CamSlot->ProvidesCa(Channel->Caids())) {
256  SlotPriority[CamSlot->Index()] = CamSlot->MtdActive() ? IDLEPRIORITY : CamSlot->Priority(); // we don't need to take the priority into account here for MTD CAM slots, because they can be used with several devices in parallel
257  NumUsableSlots++;
258  }
259  }
260  }
261  }
262  if (!NumUsableSlots)
263  InternalCamNeeded = true; // no CAM is able to decrypt this channel
264  }
265 
266  bool NeedsDetachReceivers = false;
267  cDevice *d = NULL;
268  cCamSlot *s = NULL;
269 
270  uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact
271  for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) {
272  if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY)
273  continue; // there is no CAM available in this slot
274  for (int i = 0; i < numDevices; i++) {
275  if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device[i]->CardIndex() + 1)
276  continue; // a specific card was requested, but not this one
277  bool HasInternalCam = device[i]->HasInternalCam();
278  if (InternalCamNeeded && !HasInternalCam)
279  continue; // no CAM is able to decrypt this channel and the device uses vdr handled CAMs
280  if (NumUsableSlots && !HasInternalCam && !CamSlots.Get(j)->Assign(device[i], true))
281  continue; // CAM slot can't be used with this device
282  bool ndr;
283  if (device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basically able to do the job
284  if (NumUsableSlots && !HasInternalCam) {
285  if (cCamSlot *csi = device[i]->CamSlot()) {
286  cCamSlot *csj = CamSlots.Get(j);
287  if ((csj->MtdActive() ? csi->MasterSlot() : csi) != csj)
288  ndr = true; // using a different CAM slot requires detaching receivers
289  }
290  }
291  // Put together an integer number that reflects the "impact" using
292  // this device would have on the overall system. Each condition is represented
293  // by one bit in the number (or several bits, if the condition is actually
294  // a numeric value). The sequence in which the conditions are listed corresponds
295  // to their individual severity, where the one listed first will make the most
296  // difference, because it results in the most significant bit of the result.
297  uint32_t imp = 0;
298  imp <<= 1; imp |= (LiveView && NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlots.Get(j)->MasterSlotNumber()) || ndr : 0; // prefer CAMs that are known to decrypt this channel for live viewing, if we don't need to detach existing receivers
299  imp <<= 1; imp |= LiveView ? !device[i]->IsPrimaryDevice() || ndr : 0; // prefer the primary device for live viewing if we don't need to detach existing receivers
300  imp <<= 1; imp |= !device[i]->Receiving() && (device[i] != cTransferControl::ReceiverDevice() || device[i]->IsPrimaryDevice()) || ndr; // use receiving devices if we don't need to detach existing receivers, but avoid primary device in local transfer mode
301  imp <<= 1; imp |= device[i]->Receiving(); // avoid devices that are receiving
302  imp <<= 4; imp |= GetClippedNumProvidedSystems(4, device[i]) - 1; // avoid cards which support multiple delivery systems
303  imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
304  imp <<= 8; imp |= device[i]->Priority() - IDLEPRIORITY; // use the device with the lowest priority (- IDLEPRIORITY to assure that values -100..99 can be used)
305  imp <<= 8; imp |= ((NumUsableSlots && !HasInternalCam) ? SlotPriority[j] : IDLEPRIORITY) - IDLEPRIORITY;// use the CAM slot with the lowest priority (- IDLEPRIORITY to assure that values -100..99 can be used)
306  imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers
307  imp <<= 1; imp |= (NumUsableSlots || InternalCamNeeded) ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
308  imp <<= 1; imp |= device[i]->AvoidRecording(); // avoid SD full featured cards
309  imp <<= 1; imp |= (NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlots.Get(j)->MasterSlotNumber()) : 0; // prefer CAMs that are known to decrypt this channel
310  imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device
311  if (imp < Impact) {
312  // This device has less impact than any previous one, so we take it.
313  Impact = imp;
314  d = device[i];
315  NeedsDetachReceivers = ndr;
316  if (NumUsableSlots && !HasInternalCam)
317  s = CamSlots.Get(j);
318  }
319  }
320  }
321  if (!NumUsableSlots)
322  break; // no CAM necessary, so just one loop over the devices
323  }
324  if (d) {
325  if (!Query && NeedsDetachReceivers)
326  d->DetachAllReceivers();
327  if (s) {
328  // Some of the following statements could probably be combined, but let's keep them
329  // explicit so we can clearly see every single aspect of the decisions made here.
330  if (d->CamSlot()) {
331  if (s->MtdActive()) {
332  if (s == d->CamSlot()->MasterSlot()) {
333  // device d already has a proper CAM slot, so nothing to do here
334  }
335  else {
336  // device d has a CAM slot, but it's not the right one
337  if (!Query) {
338  d->CamSlot()->Assign(NULL);
339  s = s->MtdSpawn();
340  s->Assign(d);
341  }
342  }
343  }
344  else {
345  if (s->Device()) {
346  if (s->Device() != d) {
347  // CAM slot s is currently assigned to a different device than d
348  if (Priority > s->Priority()) {
349  if (!Query) {
350  d->CamSlot()->Assign(NULL);
351  s->Assign(d);
352  }
353  }
354  else {
355  d = NULL;
356  s = NULL;
357  }
358  }
359  else {
360  // device d already has a proper CAM slot, so nothing to do here
361  }
362  }
363  else {
364  if (s != d->CamSlot()) {
365  // device d has a CAM slot, but it's not the right one
366  if (!Query) {
367  d->CamSlot()->Assign(NULL);
368  s->Assign(d);
369  }
370  }
371  else {
372  // device d already has a proper CAM slot, so nothing to do here
373  }
374  }
375  }
376  }
377  else {
378  // device d has no CAM slot, ...
379  if (s->MtdActive()) {
380  // ... so we assign s with MTD support
381  if (!Query) {
382  s = s->MtdSpawn();
383  s->Assign(d);
384  }
385  }
386  else {
387  // CAM slot s has no MTD support ...
388  if (s->Device()) {
389  // ... but it is assigned to a different device, so we reassign it to d
390  if (Priority > s->Priority()) {
391  if (!Query) {
392  s->Device()->DetachAllReceivers();
393  s->Assign(d);
394  }
395  }
396  else {
397  d = NULL;
398  s = NULL;
399  }
400  }
401  else {
402  // ... and is not assigned to any device, so we just assign it to d
403  if (!Query)
404  s->Assign(d);
405  }
406  }
407  }
408  }
409  else if (d->CamSlot() && !d->CamSlot()->IsDecrypting())
410  d->CamSlot()->Assign(NULL);
411  }
412  return d;
413 }
414 
415 cDevice *cDevice::GetDeviceForTransponder(const cChannel *Channel, int Priority)
416 {
417  cDevice *Device = NULL;
418  for (int i = 0; i < cDevice::NumDevices(); i++) {
419  if (cDevice *d = cDevice::GetDevice(i)) {
420  if (d->IsTunedToTransponder(Channel))
421  return d; // if any device is tuned to the transponder, we're done
422  if (d->ProvidesTransponder(Channel)) {
423  if (d->MaySwitchTransponder(Channel))
424  Device = d; // this device may switch to the transponder without disturbing any receiver or live view
425  else if (!d->Occupied() && d->MaySwitchTransponder(Channel)) { // MaySwitchTransponder() implicitly calls Occupied()
426  if (d->Priority() < Priority && (!Device || d->Priority() < Device->Priority()))
427  Device = d; // use this one only if no other with less impact can be found
428  }
429  }
430  }
431  }
432  return Device;
433 }
434 
435 bool cDevice::HasCi(void)
436 {
437  return false;
438 }
439 
441 {
442  LOCK_THREAD;
443  camSlot = CamSlot;
444 }
445 
447 {
448  deviceHooks.Clear();
449  for (int i = 0; i < numDevices; i++) {
450  delete device[i];
451  device[i] = NULL;
452  }
453 }
454 
455 uchar *cDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
456 {
457  return NULL;
458 }
459 
460 bool cDevice::GrabImageFile(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
461 {
462  int result = 0;
463  int fd = open(FileName, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC, DEFFILEMODE);
464  if (fd >= 0) {
465  int ImageSize;
466  uchar *Image = GrabImage(ImageSize, Jpeg, Quality, SizeX, SizeY);
467  if (Image) {
468  if (safe_write(fd, Image, ImageSize) == ImageSize)
469  isyslog("grabbed image to %s", FileName);
470  else {
471  LOG_ERROR_STR(FileName);
472  result |= 1;
473  }
474  free(Image);
475  }
476  else
477  result |= 1;
478  close(fd);
479  }
480  else {
481  LOG_ERROR_STR(FileName);
482  result |= 1;
483  }
484  return result == 0;
485 }
486 
488 {
489  cSpuDecoder *spuDecoder = GetSpuDecoder();
490  if (spuDecoder) {
491  if (Setup.VideoFormat)
493  else {
494  switch (VideoDisplayFormat) {
495  case vdfPanAndScan:
497  break;
498  case vdfLetterBox:
500  break;
501  case vdfCenterCutOut:
503  break;
504  default: esyslog("ERROR: invalid value for VideoDisplayFormat '%d'", VideoDisplayFormat);
505  }
506  }
507  }
508 }
509 
510 void cDevice::SetVideoFormat(bool VideoFormat16_9)
511 {
512 }
513 
514 void cDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect)
515 {
516  Width = 0;
517  Height = 0;
518  VideoAspect = 1.0;
519 }
520 
521 void cDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
522 {
523  Width = 720;
524  Height = 480;
525  PixelAspect = 1.0;
526 }
527 
528 //#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", CardIndex(), s); for (int i = 0; i < MAXPIDHANDLES; i++) q += sprintf(q, " %s%4d %d", i == ptOther ? "* " : "", pidHandles[i].pid, pidHandles[i].used); dsyslog("%s", b); }
529 #define PRINTPIDS(s)
530 
531 bool cDevice::HasPid(int Pid) const
532 {
533  cMutexLock MutexLock(&mutexPids);
534  for (int i = 0; i < MAXPIDHANDLES; i++) {
535  if (pidHandles[i].pid == Pid)
536  return true;
537  }
538  return false;
539 }
540 
541 bool cDevice::AddPid(int Pid, ePidType PidType, int StreamType)
542 {
543  cMutexLock MutexLock(&mutexPids);
544  if (Pid || PidType == ptPcr) {
545  int n = -1;
546  int a = -1;
547  if (PidType != ptPcr) { // PPID always has to be explicit
548  for (int i = 0; i < MAXPIDHANDLES; i++) {
549  if (i != ptPcr) {
550  if (pidHandles[i].pid == Pid)
551  n = i;
552  else if (a < 0 && i >= ptOther && !pidHandles[i].used)
553  a = i;
554  }
555  }
556  }
557  if (n >= 0) {
558  // The Pid is already in use
559  if (++pidHandles[n].used == 2 && n <= ptTeletext) {
560  // It's a special PID that may have to be switched into "tap" mode
561  PRINTPIDS("A");
562  if (!SetPid(&pidHandles[n], n, true)) {
563  esyslog("ERROR: can't set PID %d on device %d", Pid, CardIndex() + 1);
564  if (PidType <= ptTeletext)
565  DetachAll(Pid);
566  DelPid(Pid, PidType);
567  return false;
568  }
569  if (camSlot)
570  camSlot->SetPid(Pid, true);
571  }
572  PRINTPIDS("a");
573  return true;
574  }
575  else if (PidType < ptOther) {
576  // The Pid is not yet in use and it is a special one
577  n = PidType;
578  }
579  else if (a >= 0) {
580  // The Pid is not yet in use and we have a free slot
581  n = a;
582  }
583  else {
584  esyslog("ERROR: no free slot for PID %d on device %d", Pid, CardIndex() + 1);
585  return false;
586  }
587  if (n >= 0) {
588  pidHandles[n].pid = Pid;
589  pidHandles[n].streamType = StreamType;
590  pidHandles[n].used = 1;
591  PRINTPIDS("C");
592  if (!SetPid(&pidHandles[n], n, true)) {
593  esyslog("ERROR: can't set PID %d on device %d", Pid, CardIndex() + 1);
594  if (PidType <= ptTeletext)
595  DetachAll(Pid);
596  DelPid(Pid, PidType);
597  return false;
598  }
599  if (camSlot)
600  camSlot->SetPid(Pid, true);
601  }
602  }
603  return true;
604 }
605 
606 void cDevice::DelPid(int Pid, ePidType PidType)
607 {
608  cMutexLock MutexLock(&mutexPids);
609  if (Pid || PidType == ptPcr) {
610  int n = -1;
611  if (PidType == ptPcr)
612  n = PidType; // PPID always has to be explicit
613  else {
614  for (int i = 0; i < MAXPIDHANDLES; i++) {
615  if (pidHandles[i].pid == Pid) {
616  n = i;
617  break;
618  }
619  }
620  }
621  if (n >= 0 && pidHandles[n].used) {
622  PRINTPIDS("D");
623  if (--pidHandles[n].used < 2) {
624  SetPid(&pidHandles[n], n, false);
625  if (pidHandles[n].used == 0) {
626  pidHandles[n].handle = -1;
627  pidHandles[n].pid = 0;
628  if (camSlot)
629  camSlot->SetPid(Pid, false);
630  }
631  }
632  PRINTPIDS("E");
633  }
634  }
635 }
636 
637 bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
638 {
639  return false;
640 }
641 
643 {
644  cMutexLock MutexLock(&mutexPids);
645  for (int i = ptAudio; i < ptOther; i++) {
646  if (pidHandles[i].pid)
647  DelPid(pidHandles[i].pid, ePidType(i));
648  }
649 }
650 
652 {
653  if (!sectionHandler) {
654  sectionHandler = new cSectionHandler(this);
659  }
660 }
661 
663 {
664  if (sectionHandler) {
665  delete nitFilter;
666  delete sdtFilter;
667  delete patFilter;
668  delete eitFilter;
669  delete sectionHandler;
670  nitFilter = NULL;
671  sdtFilter = NULL;
672  patFilter = NULL;
673  eitFilter = NULL;
674  sectionHandler = NULL;
675  }
676 }
677 
678 int cDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
679 {
680  return -1;
681 }
682 
683 int cDevice::ReadFilter(int Handle, void *Buffer, size_t Length)
684 {
685  return safe_read(Handle, Buffer, Length);
686 }
687 
688 void cDevice::CloseFilter(int Handle)
689 {
690  close(Handle);
691 }
692 
694 {
695  if (sectionHandler)
696  sectionHandler->Attach(Filter);
697 }
698 
700 {
701  if (sectionHandler)
702  sectionHandler->Detach(Filter);
703 }
704 
705 bool cDevice::ProvidesSource(int Source) const
706 {
707  return false;
708 }
709 
711 {
712  cDeviceHook *Hook = deviceHooks.First();
713  while (Hook) {
714  if (!Hook->DeviceProvidesTransponder(this, Channel))
715  return false;
716  Hook = deviceHooks.Next(Hook);
717  }
718  return true;
719 }
720 
721 bool cDevice::ProvidesTransponder(const cChannel *Channel) const
722 {
723  return false;
724 }
725 
727 {
728  for (int i = 0; i < numDevices; i++) {
729  if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel))
730  return false;
731  }
732  return true;
733 }
734 
735 bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
736 {
737  return false;
738 }
739 
740 bool cDevice::ProvidesEIT(void) const
741 {
742  return false;
743 }
744 
746 {
747  return 0;
748 }
749 
751 {
752  return NULL;
753 }
754 
755 bool cDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
756 {
757  return false;
758 }
759 
760 int cDevice::SignalStrength(void) const
761 {
762  return -1;
763 }
764 
765 int cDevice::SignalQuality(void) const
766 {
767  return -1;
768 }
769 
771 {
772  return NULL;
773 }
774 
775 bool cDevice::IsTunedToTransponder(const cChannel *Channel) const
776 {
777  return false;
778 }
779 
780 bool cDevice::MaySwitchTransponder(const cChannel *Channel) const
781 {
782  return time(NULL) > occupiedTimeout && !Receiving() && !(pidHandles[ptAudio].pid || pidHandles[ptVideo].pid || pidHandles[ptDolby].pid);
783 }
784 
785 bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView)
786 {
787  if (LiveView) {
788  isyslog("switching to channel %d %s (%s)", Channel->Number(), *Channel->GetChannelID().ToString(), Channel->Name());
789  cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
790  // and, if decrypted, this removes the now superflous PIDs from the CAM, too
791  }
792  for (int i = 3; i--;) {
793  switch (SetChannel(Channel, LiveView)) {
794  case scrOk: return true;
795  case scrNotAvailable: Skins.Message(mtInfo, tr("Channel not available!"));
796  return false;
797  case scrNoTransfer: Skins.Message(mtError, tr("Can't start Transfer Mode!"));
798  return false;
799  case scrFailed: break; // loop will retry
800  default: esyslog("ERROR: invalid return value from SetChannel");
801  }
802  esyslog("retrying");
803  }
804  return false;
805 }
806 
807 bool cDevice::SwitchChannel(int Direction)
808 {
809  bool result = false;
810  Direction = sgn(Direction);
811  if (Direction) {
812  cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
813  // and, if decrypted, this removes the now superflous PIDs from the CAM, too
814  int n = CurrentChannel() + Direction;
815  int first = n;
817  const cChannel *Channel;
818  while ((Channel = Channels->GetByNumber(n, Direction)) != NULL) {
819  // try only channels which are currently available
820  if (GetDevice(Channel, LIVEPRIORITY, true, true))
821  break;
822  n = Channel->Number() + Direction;
823  }
824  if (Channel) {
825  int d = n - first;
826  if (abs(d) == 1)
827  dsyslog("skipped channel %d", first);
828  else if (d)
829  dsyslog("skipped channels %d..%d", first, n - sgn(d));
830  if (PrimaryDevice()->SwitchChannel(Channel, true))
831  result = true;
832  }
833  else if (n != first)
834  Skins.Message(mtError, tr("Channel not available!"));
835  }
836  return result;
837 }
838 
839 eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
840 {
841  cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme()
842  cStatus::MsgChannelSwitch(this, 0, LiveView);
843 
844  if (LiveView) {
845  StopReplay();
848  }
849 
850  cDevice *Device = (LiveView && IsPrimaryDevice()) ? GetDevice(Channel, LIVEPRIORITY, true) : this;
851 
852  bool NeedsTransferMode = LiveView && Device != PrimaryDevice();
853  // If the CAM slot wants the TS data, we need to switch to Transfer Mode:
854  if (!NeedsTransferMode && LiveView && IsPrimaryDevice() && CamSlot() && CamSlot()->WantsTsData())
855  NeedsTransferMode = true;
856 
857  eSetChannelResult Result = scrOk;
858 
859  // If this DVB card can't receive this channel, let's see if we can
860  // use the card that actually can receive it and transfer data from there:
861 
862  if (NeedsTransferMode) {
863  if (Device && PrimaryDevice()->CanReplay()) {
864  if (Device->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()!
865  cControl::Launch(new cTransferControl(Device, Channel));
866  else
867  Result = scrNoTransfer;
868  }
869  else
870  Result = scrNotAvailable;
871  }
872  else {
873  // Stop section handling:
874  if (sectionHandler) {
875  sectionHandler->SetStatus(false);
876  sectionHandler->SetChannel(NULL);
877  }
878  // Tell the camSlot about the channel switch and add all PIDs of this
879  // channel to it, for possible later decryption:
880  if (camSlot)
881  camSlot->AddChannel(Channel);
882  if (SetChannelDevice(Channel, LiveView)) {
883  // Start section handling:
884  if (sectionHandler) {
885  if (patFilter)
886  patFilter->Trigger(Channel->Sid());
887  sectionHandler->SetChannel(Channel);
888  sectionHandler->SetStatus(true);
889  }
890  // Start decrypting any PIDs that might have been set in SetChannelDevice():
891  if (camSlot)
893  }
894  else
895  Result = scrFailed;
896  }
897 
898  if (Result == scrOk) {
899  if (LiveView && IsPrimaryDevice()) {
900  currentChannel = Channel->Number();
901  // Set the available audio tracks:
903  for (int i = 0; i < MAXAPIDS; i++)
904  SetAvailableTrack(ttAudio, i, Channel->Apid(i), Channel->Alang(i));
905  if (Setup.UseDolbyDigital) {
906  for (int i = 0; i < MAXDPIDS; i++)
907  SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i));
908  }
909  for (int i = 0; i < MAXSPIDS; i++)
910  SetAvailableTrack(ttSubtitle, i, Channel->Spid(i), Channel->Slang(i));
911  if (!NeedsTransferMode)
912  EnsureAudioTrack(true);
914  }
915  cStatus::MsgChannelSwitch(this, Channel->Number(), LiveView); // only report status if channel switch successful
916  }
917 
918  return Result;
919 }
920 
922 {
925  if (const cChannel *Channel = Channels->GetByNumber(CurrentChannel()))
926  SetChannelDevice(Channel, false); // this implicitly starts Transfer Mode
927  }
928 }
929 
930 int cDevice::Occupied(void) const
931 {
932  int Seconds = occupiedTimeout - time(NULL);
933  return Seconds > 0 ? Seconds : 0;
934 }
935 
936 void cDevice::SetOccupied(int Seconds)
937 {
938  if (Seconds >= 0)
939  occupiedTimeout = time(NULL) + min(Seconds, MAXOCCUPIEDTIMEOUT);
940 }
941 
942 bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
943 {
944  return false;
945 }
946 
947 bool cDevice::HasLock(int TimeoutMs) const
948 {
949  return true;
950 }
951 
952 bool cDevice::HasProgramme(void) const
953 {
954  cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme()
956 }
957 
959 {
960  return 0;
961 }
962 
963 void cDevice::SetAudioChannelDevice(int AudioChannel)
964 {
965 }
966 
967 void cDevice::SetVolumeDevice(int Volume)
968 {
969 }
970 
972 {
973 }
974 
976 {
977 }
978 
980 {
981 }
982 
984 {
985  int OldVolume = volume;
986  mute = !mute;
987  //XXX why is it necessary to use different sequences???
988  if (mute) {
989  SetVolume(0, true);
990  Audios.MuteAudio(mute); // Mute external audio after analog audio
991  }
992  else {
993  Audios.MuteAudio(mute); // Enable external audio before analog audio
994  SetVolume(OldVolume, true);
995  }
996  volume = OldVolume;
997  return mute;
998 }
999 
1001 {
1002  int c = GetAudioChannelDevice();
1003  return (0 <= c && c <= 2) ? c : 0;
1004 }
1005 
1006 void cDevice::SetAudioChannel(int AudioChannel)
1007 {
1008  if (0 <= AudioChannel && AudioChannel <= 2)
1009  SetAudioChannelDevice(AudioChannel);
1010 }
1011 
1012 void cDevice::SetVolume(int Volume, bool Absolute)
1013 {
1014  int OldVolume = volume;
1015  double VolumeDelta = double(MAXVOLUME) / Setup.VolumeSteps;
1016  double VolumeLinearize = (Setup.VolumeLinearize >= 0) ? (Setup.VolumeLinearize / 10.0 + 1.0) : (1.0 / ((-Setup.VolumeLinearize / 10.0) + 1.0));
1017  volume = constrain(int(floor((Absolute ? Volume : volume + Volume) / VolumeDelta + 0.5) * VolumeDelta), 0, MAXVOLUME);
1018  SetVolumeDevice(MAXVOLUME - int(pow(1.0 - pow(double(volume) / MAXVOLUME, VolumeLinearize), 1.0 / VolumeLinearize) * MAXVOLUME));
1019  Absolute |= mute;
1020  cStatus::MsgSetVolume(Absolute ? volume : volume - OldVolume, Absolute);
1021  if (volume > 0) {
1022  mute = false;
1024  }
1025 }
1026 
1027 void cDevice::ClrAvailableTracks(bool DescriptionsOnly, bool IdsOnly)
1028 {
1029  if (keepTracks)
1030  return;
1031  if (DescriptionsOnly) {
1032  for (int i = ttNone; i < ttMaxTrackTypes; i++)
1033  *availableTracks[i].description = 0;
1034  }
1035  else {
1036  if (IdsOnly) {
1037  for (int i = ttNone; i < ttMaxTrackTypes; i++)
1038  availableTracks[i].id = 0;
1039  }
1040  else
1041  memset(availableTracks, 0, sizeof(availableTracks));
1043  SetAudioChannel(0); // fall back to stereo
1047  }
1048 }
1049 
1050 bool cDevice::SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language, const char *Description)
1051 {
1052  eTrackType t = eTrackType(Type + Index);
1053  if (Type == ttAudio && IS_AUDIO_TRACK(t) ||
1054  Type == ttDolby && IS_DOLBY_TRACK(t) ||
1055  Type == ttSubtitle && IS_SUBTITLE_TRACK(t)) {
1056  if (Language)
1057  strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language));
1058  if (Description)
1060  if (Id) {
1061  availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking
1062  if (Type == ttAudio || Type == ttDolby) {
1063  int numAudioTracks = NumAudioTracks();
1064  if (!availableTracks[currentAudioTrack].id && numAudioTracks && currentAudioTrackMissingCount++ > numAudioTracks * 10)
1065  EnsureAudioTrack();
1066  else if (t == currentAudioTrack)
1068  }
1069  else if (Type == ttSubtitle && autoSelectPreferredSubtitleLanguage)
1071  }
1072  return true;
1073  }
1074  else
1075  esyslog("ERROR: SetAvailableTrack called with invalid Type/Index (%d/%d)", Type, Index);
1076  return false;
1077 }
1078 
1080 {
1081  return (ttNone < Type && Type < ttMaxTrackTypes) ? &availableTracks[Type] : NULL;
1082 }
1083 
1084 int cDevice::NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const
1085 {
1086  int n = 0;
1087  for (int i = FirstTrack; i <= LastTrack; i++) {
1088  if (availableTracks[i].id)
1089  n++;
1090  }
1091  return n;
1092 }
1093 
1095 {
1097 }
1098 
1100 {
1102 }
1103 
1105 {
1106  if (ttNone < Type && Type <= ttDolbyLast) {
1107  cMutexLock MutexLock(&mutexCurrentAudioTrack);
1108  if (IS_DOLBY_TRACK(Type))
1109  SetDigitalAudioDevice(true);
1110  currentAudioTrack = Type;
1111  if (player)
1113  else
1115  if (IS_AUDIO_TRACK(Type))
1116  SetDigitalAudioDevice(false);
1117  return true;
1118  }
1119  return false;
1120 }
1121 
1123 {
1124  if (Type == ttNone || IS_SUBTITLE_TRACK(Type)) {
1125  currentSubtitleTrack = Type;
1129  if (Type == ttNone && dvbSubtitleConverter) {
1132  }
1134  if (player)
1136  else
1138  if (currentSubtitleTrack != ttNone && !Replaying() && !Transferring()) {
1139  const tTrackId *TrackId = GetTrack(currentSubtitleTrack);
1140  if (TrackId && TrackId->id) {
1141  liveSubtitle = new cLiveSubtitle(TrackId->id);
1143  }
1144  }
1145  return true;
1146  }
1147  return false;
1148 }
1149 
1151 {
1152  if (keepTracks)
1153  return;
1154  if (Force || !availableTracks[currentAudioTrack].id) {
1155  eTrackType PreferredTrack = ttAudioFirst;
1156  int PreferredAudioChannel = 0;
1157  int LanguagePreference = -1;
1158  int StartCheck = Setup.CurrentDolby ? ttDolbyFirst : ttAudioFirst;
1159  int EndCheck = ttDolbyLast;
1160  for (int i = StartCheck; i <= EndCheck; i++) {
1161  const tTrackId *TrackId = GetTrack(eTrackType(i));
1162  int pos = 0;
1163  if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.AudioLanguages, TrackId->language, LanguagePreference, &pos)) {
1164  PreferredTrack = eTrackType(i);
1165  PreferredAudioChannel = pos;
1166  }
1167  if (Setup.CurrentDolby && i == ttDolbyLast) {
1168  i = ttAudioFirst - 1;
1169  EndCheck = ttAudioLast;
1170  }
1171  }
1172  // Make sure we're set to an available audio track:
1173  const tTrackId *Track = GetTrack(GetCurrentAudioTrack());
1174  if (Force || !Track || !Track->id || PreferredTrack != GetCurrentAudioTrack()) {
1175  if (!Force) // only log this for automatic changes
1176  dsyslog("setting audio track to %d (%d)", PreferredTrack, PreferredAudioChannel);
1177  SetCurrentAudioTrack(PreferredTrack);
1178  SetAudioChannel(PreferredAudioChannel);
1179  }
1180  }
1181 }
1182 
1184 {
1185  if (keepTracks)
1186  return;
1187  if (Setup.DisplaySubtitles) {
1188  eTrackType PreferredTrack = ttNone;
1189  int LanguagePreference = INT_MAX; // higher than the maximum possible value
1190  for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
1191  const tTrackId *TrackId = GetTrack(eTrackType(i));
1192  if (TrackId && TrackId->id && (I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference) ||
1193  (i == ttSubtitleFirst + 8 && !*TrackId->language && LanguagePreference == INT_MAX))) // compatibility mode for old subtitles plugin
1194  PreferredTrack = eTrackType(i);
1195  }
1196  // Make sure we're set to an available subtitle track:
1197  const tTrackId *Track = GetTrack(GetCurrentSubtitleTrack());
1198  if (!Track || !Track->id || PreferredTrack != GetCurrentSubtitleTrack())
1199  SetCurrentSubtitleTrack(PreferredTrack);
1200  }
1201  else
1203 }
1204 
1205 bool cDevice::CanReplay(void) const
1206 {
1207  return HasDecoder();
1208 }
1209 
1211 {
1212  return false;
1213 }
1214 
1215 int64_t cDevice::GetSTC(void)
1216 {
1217  return -1;
1218 }
1219 
1220 void cDevice::TrickSpeed(int Speed, bool Forward)
1221 {
1222 }
1223 
1224 void cDevice::Clear(void)
1225 {
1226  Audios.ClearAudio();
1229 }
1230 
1231 void cDevice::Play(void)
1232 {
1235  dvbSubtitleConverter->Freeze(false);
1236 }
1237 
1239 {
1240  Audios.MuteAudio(true);
1243 }
1244 
1245 void cDevice::Mute(void)
1246 {
1247  Audios.MuteAudio(true);
1248 }
1249 
1250 void cDevice::StillPicture(const uchar *Data, int Length)
1251 {
1252  if (Data[0] == 0x47) {
1253  // TS data
1254  cTsToPes TsToPes;
1255  uchar *buf = NULL;
1256  int Size = 0;
1257  while (Length >= TS_SIZE) {
1258  int Pid = TsPid(Data);
1259  if (Pid == PATPID)
1260  patPmtParser.ParsePat(Data, TS_SIZE);
1261  else if (patPmtParser.IsPmtPid(Pid))
1262  patPmtParser.ParsePmt(Data, TS_SIZE);
1263  else if (Pid == patPmtParser.Vpid()) {
1264  if (TsPayloadStart(Data)) {
1265  int l;
1266  while (const uchar *p = TsToPes.GetPes(l)) {
1267  int Offset = Size;
1268  int NewSize = Size + l;
1269  if (uchar *NewBuffer = (uchar *)realloc(buf, NewSize)) {
1270  Size = NewSize;
1271  buf = NewBuffer;
1272  memcpy(buf + Offset, p, l);
1273  }
1274  else {
1275  LOG_ERROR_STR("out of memory");
1276  free(buf);
1277  return;
1278  }
1279  }
1280  TsToPes.Reset();
1281  }
1282  TsToPes.PutTs(Data, TS_SIZE);
1283  }
1284  Length -= TS_SIZE;
1285  Data += TS_SIZE;
1286  }
1287  int l;
1288  while (const uchar *p = TsToPes.GetPes(l)) {
1289  int Offset = Size;
1290  int NewSize = Size + l;
1291  if (uchar *NewBuffer = (uchar *)realloc(buf, NewSize)) {
1292  Size = NewSize;
1293  buf = NewBuffer;
1294  memcpy(buf + Offset, p, l);
1295  }
1296  else {
1297  esyslog("ERROR: out of memory");
1298  free(buf);
1299  return;
1300  }
1301  }
1302  if (buf) {
1303  StillPicture(buf, Size);
1304  free(buf);
1305  }
1306  }
1307 }
1308 
1309 bool cDevice::Replaying(void) const
1310 {
1311  return player != NULL;
1312 }
1313 
1314 bool cDevice::Transferring(void) const
1315 {
1316  return cTransferControl::ReceiverDevice() != NULL;
1317 }
1318 
1320 {
1321  if (CanReplay()) {
1322  if (player)
1323  Detach(player);
1326  patPmtParser.Reset();
1327  player = Player;
1328  if (!Transferring())
1329  ClrAvailableTracks(false, true);
1331  player->device = this;
1332  player->Activate(true);
1333  return true;
1334  }
1335  return false;
1336 }
1337 
1339 {
1340  if (Player && player == Player) {
1341  cPlayer *p = player;
1342  player = NULL; // avoids recursive calls to Detach()
1343  p->Activate(false);
1344  p->device = NULL;
1346  delete dvbSubtitleConverter;
1347  dvbSubtitleConverter = NULL;
1350  PlayTs(NULL, 0);
1351  patPmtParser.Reset();
1352  Audios.ClearAudio();
1353  isPlayingVideo = false;
1354  }
1355 }
1356 
1358 {
1359  if (player) {
1360  Detach(player);
1361  if (IsPrimaryDevice())
1363  }
1364 }
1365 
1366 bool cDevice::Poll(cPoller &Poller, int TimeoutMs)
1367 {
1368  return false;
1369 }
1370 
1371 bool cDevice::Flush(int TimeoutMs)
1372 {
1373  return true;
1374 }
1375 
1376 int cDevice::PlayVideo(const uchar *Data, int Length)
1377 {
1378  return -1;
1379 }
1380 
1381 int cDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
1382 {
1383  return -1;
1384 }
1385 
1386 int cDevice::PlaySubtitle(const uchar *Data, int Length)
1387 {
1388  if (!dvbSubtitleConverter)
1390  return dvbSubtitleConverter->ConvertFragments(Data, Length);
1391 }
1392 
1393 int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
1394 {
1395  bool FirstLoop = true;
1396  uchar c = Data[3];
1397  const uchar *Start = Data;
1398  const uchar *End = Start + Length;
1399  while (Start < End) {
1400  int d = End - Start;
1401  int w = d;
1402  switch (c) {
1403  case 0xBE: // padding stream, needed for MPEG1
1404  case 0xE0 ... 0xEF: // video
1405  isPlayingVideo = true;
1406  w = PlayVideo(Start, d);
1407  break;
1408  case 0xC0 ... 0xDF: // audio
1409  SetAvailableTrack(ttAudio, c - 0xC0, c);
1410  if ((!VideoOnly || HasIBPTrickSpeed()) && c == availableTracks[currentAudioTrack].id) {
1411  w = PlayAudio(Start, d, c);
1412  if (FirstLoop)
1413  Audios.PlayAudio(Data, Length, c);
1414  }
1415  break;
1416  case 0xBD: { // private stream 1
1417  int PayloadOffset = Data[8] + 9;
1418 
1419  // Compatibility mode for old subtitles plugin:
1420  if ((Data[7] & 0x01) && (Data[PayloadOffset - 3] & 0x81) == 0x01 && Data[PayloadOffset - 2] == 0x81)
1421  PayloadOffset--;
1422 
1423  uchar SubStreamId = Data[PayloadOffset];
1424  uchar SubStreamType = SubStreamId & 0xF0;
1425  uchar SubStreamIndex = SubStreamId & 0x1F;
1426 
1427  // Compatibility mode for old VDR recordings, where 0xBD was only AC3:
1428 pre_1_3_19_PrivateStreamDetected:
1430  SubStreamId = c;
1431  SubStreamType = 0x80;
1432  SubStreamIndex = 0;
1433  }
1434  else if (pre_1_3_19_PrivateStream)
1435  pre_1_3_19_PrivateStream--; // every known PS1 packet counts down towards 0 to recover from glitches...
1436  switch (SubStreamType) {
1437  case 0x20: // SPU
1438  case 0x30: // SPU
1439  SetAvailableTrack(ttSubtitle, SubStreamIndex, SubStreamId);
1440  if ((!VideoOnly || HasIBPTrickSpeed()) && currentSubtitleTrack != ttNone && SubStreamId == availableTracks[currentSubtitleTrack].id)
1441  w = PlaySubtitle(Start, d);
1442  break;
1443  case 0x80: // AC3 & DTS
1444  if (Setup.UseDolbyDigital) {
1445  SetAvailableTrack(ttDolby, SubStreamIndex, SubStreamId);
1446  if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) {
1447  w = PlayAudio(Start, d, SubStreamId);
1448  if (FirstLoop)
1449  Audios.PlayAudio(Data, Length, SubStreamId);
1450  }
1451  }
1452  break;
1453  case 0xA0: // LPCM
1454  SetAvailableTrack(ttAudio, SubStreamIndex, SubStreamId);
1455  if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) {
1456  w = PlayAudio(Start, d, SubStreamId);
1457  if (FirstLoop)
1458  Audios.PlayAudio(Data, Length, SubStreamId);
1459  }
1460  break;
1461  default:
1462  // Compatibility mode for old VDR recordings, where 0xBD was only AC3:
1464  dsyslog("unknown PS1 packet, substream id = %02X (counter is at %d)", SubStreamId, pre_1_3_19_PrivateStream);
1465  pre_1_3_19_PrivateStream += 2; // ...and every unknown PS1 packet counts up (the very first one counts twice, but that's ok)
1467  dsyslog("switching to pre 1.3.19 Dolby Digital compatibility mode - substream id = %02X", SubStreamId);
1470  goto pre_1_3_19_PrivateStreamDetected;
1471  }
1472  }
1473  }
1474  }
1475  break;
1476  default:
1477  ;//esyslog("ERROR: unexpected packet id %02X", c);
1478  }
1479  if (w > 0)
1480  Start += w;
1481  else {
1482  if (Start != Data)
1483  esyslog("ERROR: incomplete PES packet write!");
1484  return Start == Data ? w : Start - Data;
1485  }
1486  FirstLoop = false;
1487  }
1488  return Length;
1489 }
1490 
1491 int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly)
1492 {
1493  if (!Data) {
1496  return 0;
1497  }
1498  int i = 0;
1499  while (i <= Length - 6) {
1500  if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
1501  int l = PesLength(Data + i);
1502  if (i + l > Length) {
1503  esyslog("ERROR: incomplete PES packet!");
1504  return Length;
1505  }
1506  int w = PlayPesPacket(Data + i, l, VideoOnly);
1507  if (w > 0)
1508  i += l;
1509  else
1510  return i == 0 ? w : i;
1511  }
1512  else
1513  i++;
1514  }
1515  if (i < Length)
1516  esyslog("ERROR: leftover PES data!");
1517  return Length;
1518 }
1519 
1520 int cDevice::PlayTsVideo(const uchar *Data, int Length)
1521 {
1522  // Video PES has no explicit length, so we can only determine the end of
1523  // a PES packet when the next TS packet that starts a payload comes in:
1524  if (TsPayloadStart(Data)) {
1525  int l;
1526  while (const uchar *p = tsToPesVideo.GetPes(l)) {
1527  int w = PlayVideo(p, l);
1528  if (w <= 0) {
1530  return w;
1531  }
1532  }
1533  tsToPesVideo.Reset();
1534  }
1535  tsToPesVideo.PutTs(Data, Length);
1536  return Length;
1537 }
1538 
1539 int cDevice::PlayTsAudio(const uchar *Data, int Length)
1540 {
1541  // Audio PES always has an explicit length and consists of single packets:
1542  int l;
1543  if (const uchar *p = tsToPesAudio.GetPes(l)) {
1544  int w = PlayAudio(p, l, p[3]);
1545  if (w <= 0) {
1547  return w;
1548  }
1549  tsToPesAudio.Reset();
1550  }
1551  tsToPesAudio.PutTs(Data, Length);
1552  return Length;
1553 }
1554 
1555 int cDevice::PlayTsSubtitle(const uchar *Data, int Length)
1556 {
1557  if (!dvbSubtitleConverter)
1559  tsToPesSubtitle.PutTs(Data, Length);
1560  int l;
1561  if (const uchar *p = tsToPesSubtitle.GetPes(l)) {
1564  }
1565  return Length;
1566 }
1567 
1568 //TODO detect and report continuity errors?
1569 int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
1570 {
1571  int Played = 0;
1572  if (!Data) {
1573  tsToPesVideo.Reset();
1574  tsToPesAudio.Reset();
1576  }
1577  else if (Length < TS_SIZE) {
1578  esyslog("ERROR: skipped %d bytes of TS fragment", Length);
1579  return Length;
1580  }
1581  else {
1582  while (Length >= TS_SIZE) {
1583  if (int Skipped = TS_SYNC(Data, Length))
1584  return Played + Skipped;
1585  int Pid = TsPid(Data);
1586  if (TsHasPayload(Data)) { // silently ignore TS packets w/o payload
1587  int PayloadOffset = TsPayloadOffset(Data);
1588  if (PayloadOffset < TS_SIZE) {
1589  if (Pid == PATPID)
1590  patPmtParser.ParsePat(Data, TS_SIZE);
1591  else if (patPmtParser.IsPmtPid(Pid))
1592  patPmtParser.ParsePmt(Data, TS_SIZE);
1593  else if (Pid == patPmtParser.Vpid()) {
1594  isPlayingVideo = true;
1595  int w = PlayTsVideo(Data, TS_SIZE);
1596  if (w < 0)
1597  return Played ? Played : w;
1598  if (w == 0)
1599  break;
1600  }
1601  else if (Pid == availableTracks[currentAudioTrack].id) {
1602  if (!VideoOnly || HasIBPTrickSpeed()) {
1603  int w = PlayTsAudio(Data, TS_SIZE);
1604  if (w < 0)
1605  return Played ? Played : w;
1606  if (w == 0)
1607  break;
1608  Audios.PlayTsAudio(Data, TS_SIZE);
1609  }
1610  }
1611  else if (Pid == availableTracks[currentSubtitleTrack].id) {
1612  if (!VideoOnly || HasIBPTrickSpeed())
1613  PlayTsSubtitle(Data, TS_SIZE);
1614  }
1615  }
1616  }
1617  else if (Pid == patPmtParser.Ppid()) {
1618  int w = PlayTsVideo(Data, TS_SIZE);
1619  if (w < 0)
1620  return Played ? Played : w;
1621  if (w == 0)
1622  break;
1623  }
1624  Played += TS_SIZE;
1625  Length -= TS_SIZE;
1626  Data += TS_SIZE;
1627  }
1628  }
1629  return Played;
1630 }
1631 
1632 int cDevice::Priority(void) const
1633 {
1634  int priority = IDLEPRIORITY;
1635  if (IsPrimaryDevice() && !Replaying() && HasProgramme())
1636  priority = TRANSFERPRIORITY; // we use the same value here, no matter whether it's actual Transfer Mode or real live viewing
1637  cMutexLock MutexLock(&mutexReceiver);
1638  for (int i = 0; i < MAXRECEIVERS; i++) {
1639  if (receiver[i])
1640  priority = max(receiver[i]->priority, priority);
1641  }
1642  return priority;
1643 }
1644 
1645 bool cDevice::Ready(void)
1646 {
1647  return true;
1648 }
1649 
1650 bool cDevice::Receiving(bool Dummy) const
1651 {
1652  cMutexLock MutexLock(&mutexReceiver);
1653  for (int i = 0; i < MAXRECEIVERS; i++) {
1654  if (receiver[i])
1655  return true;
1656  }
1657  return false;
1658 }
1659 
1660 #define TS_SCRAMBLING_TIMEOUT 3 // seconds to wait until a TS becomes unscrambled
1661 #define TS_SCRAMBLING_TIME_OK 3 // seconds before a Channel/CAM combination is marked as known to decrypt
1662 #define EIT_INJECTION_TIME 10 // seconds for which to inject EIT event
1663 
1665 {
1666  if (Running() && OpenDvr()) {
1667  while (Running()) {
1668  // Read data from the DVR device:
1669  uchar *b = NULL;
1670  if (GetTSPacket(b)) {
1671  if (b) {
1672  // Distribute the packet to all attached receivers:
1673  Lock();
1674  cCamSlot *cs = CamSlot();
1675  if (cs)
1676  cs->TsPostProcess(b);
1677  int Pid = TsPid(b);
1678  bool IsScrambled = TsIsScrambled(b);
1679  for (int i = 0; i < MAXRECEIVERS; i++) {
1680  cMutexLock MutexLock(&mutexReceiver);
1681  cReceiver *Receiver = receiver[i];
1682  if (Receiver && Receiver->WantsPid(Pid)) {
1683  Receiver->Receive(b, TS_SIZE);
1684  // Check whether the TS packet is scrambled:
1685  if (Receiver->startScrambleDetection) {
1686  if (cs) {
1687  int CamSlotNumber = cs->MasterSlotNumber();
1688  if (Receiver->lastScrambledPacket < Receiver->startScrambleDetection)
1689  Receiver->lastScrambledPacket = Receiver->startScrambleDetection;
1690  time_t Now = time(NULL);
1691  if (IsScrambled) {
1692  Receiver->lastScrambledPacket = Now;
1693  if (Now - Receiver->startScrambleDetection > Receiver->scramblingTimeout) {
1694  if (!cs->IsActivating() || Receiver->Priority() >= LIVEPRIORITY) {
1695  if (Receiver->ChannelID().Valid()) {
1696  dsyslog("CAM %d: won't decrypt channel %s, detaching receiver", CamSlotNumber, *Receiver->ChannelID().ToString());
1697  ChannelCamRelations.SetChecked(Receiver->ChannelID(), CamSlotNumber);
1698  }
1699  Detach(Receiver);
1700  }
1701  }
1702  }
1703  else if (Now - Receiver->lastScrambledPacket > TS_SCRAMBLING_TIME_OK) {
1704  if (Receiver->ChannelID().Valid()) {
1705  dsyslog("CAM %d: decrypts channel %s", CamSlotNumber, *Receiver->ChannelID().ToString());
1706  ChannelCamRelations.SetDecrypt(Receiver->ChannelID(), CamSlotNumber);
1707  }
1708  Receiver->startScrambleDetection = 0;
1709  }
1710  }
1711  }
1712  // Inject EIT event to avoid the CAMs parental rating prompt:
1713  if (Receiver->startEitInjection) {
1714  time_t Now = time(NULL);
1715  if (cCamSlot *cs = CamSlot()) {
1716  if (Now != Receiver->lastEitInjection) { // once per second
1717  cs->InjectEit(Receiver->ChannelID().Sid());
1718  Receiver->lastEitInjection = Now;
1719  }
1720  }
1721  if (Now - Receiver->startEitInjection > EIT_INJECTION_TIME)
1722  Receiver->startEitInjection = 0;
1723  }
1724  }
1725  }
1726  Unlock();
1727  }
1728  }
1729  else
1730  break;
1731  }
1732  CloseDvr();
1733  }
1734 }
1735 
1737 {
1738  return false;
1739 }
1740 
1742 {
1743 }
1744 
1746 {
1747  return false;
1748 }
1749 
1751 {
1752  if (!Receiver)
1753  return false;
1754  if (Receiver->device == this)
1755  return true;
1756 // activate the following line if you need it - actually the driver should be fixed!
1757 //#define WAIT_FOR_TUNER_LOCK
1758 #ifdef WAIT_FOR_TUNER_LOCK
1759 #define TUNER_LOCK_TIMEOUT 5000 // ms
1760  if (!HasLock(TUNER_LOCK_TIMEOUT)) {
1761  esyslog("ERROR: device %d has no lock, can't attach receiver!", CardIndex() + 1);
1762  return false;
1763  }
1764 #endif
1765  cMutexLock MutexLock(&mutexReceiver);
1766  for (int i = 0; i < MAXRECEIVERS; i++) {
1767  if (!receiver[i]) {
1768  for (int n = 0; n < Receiver->numPids; n++) {
1769  if (!AddPid(Receiver->pids[n])) {
1770  for ( ; n-- > 0; )
1771  DelPid(Receiver->pids[n]);
1772  return false;
1773  }
1774  }
1775  Receiver->Activate(true);
1776  Receiver->device = this;
1777  receiver[i] = Receiver;
1778  if (camSlot && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
1780  if (camSlot->WantsTsData()) {
1781  Receiver->lastEitInjection = 0;
1782  Receiver->startEitInjection = time(NULL);
1783  }
1784  if (CamSlots.NumReadyMasterSlots() > 1) { // don't try different CAMs if there is only one
1785  Receiver->startScrambleDetection = time(NULL);
1787  bool KnownToDecrypt = ChannelCamRelations.CamDecrypt(Receiver->ChannelID(), camSlot->MasterSlotNumber());
1788  if (KnownToDecrypt)
1789  Receiver->scramblingTimeout *= 10; // give it time to receive ECM/EMM
1790  if (Receiver->ChannelID().Valid())
1791  dsyslog("CAM %d: %sknown to decrypt channel %s (scramblingTimeout = %ds)", camSlot->MasterSlotNumber(), KnownToDecrypt ? "" : "not ", *Receiver->ChannelID().ToString(), Receiver->scramblingTimeout);
1792  }
1793  }
1794  Start();
1795  return true;
1796  }
1797  }
1798  esyslog("ERROR: no free receiver slot!");
1799  return false;
1800 }
1801 
1803 {
1804  if (!Receiver || Receiver->device != this)
1805  return;
1806  bool receiversLeft = false;
1807  mutexReceiver.Lock();
1808  for (int i = 0; i < MAXRECEIVERS; i++) {
1809  if (receiver[i] == Receiver) {
1810  receiver[i] = NULL;
1811  Receiver->device = NULL;
1812  Receiver->Activate(false);
1813  for (int n = 0; n < Receiver->numPids; n++)
1814  DelPid(Receiver->pids[n]);
1815  }
1816  else if (receiver[i])
1817  receiversLeft = true;
1818  }
1820  if (camSlot) {
1821  if (Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
1823  if (!camSlot->IsDecrypting() && !camSlot->IsActivating())
1824  camSlot->Assign(NULL);
1825  }
1826  }
1827  if (!receiversLeft)
1828  Cancel(-1);
1829 }
1830 
1831 void cDevice::DetachAll(int Pid)
1832 {
1833  if (Pid) {
1834  cMutexLock MutexLock(&mutexReceiver);
1835  for (int i = 0; i < MAXRECEIVERS; i++) {
1836  cReceiver *Receiver = receiver[i];
1837  if (Receiver && Receiver->WantsPid(Pid))
1838  Detach(Receiver);
1839  }
1840  }
1841 }
1842 
1844 {
1845  cMutexLock MutexLock(&mutexReceiver);
1846  for (int i = 0; i < MAXRECEIVERS; i++)
1847  Detach(receiver[i]);
1848 }
1849 
1850 // --- cTSBuffer -------------------------------------------------------------
1851 
1852 cTSBuffer::cTSBuffer(int File, int Size, int CardIndex)
1853 {
1854  SetDescription("device %d TS buffer", CardIndex);
1855  f = File;
1856  cardIndex = CardIndex;
1857  delivered = 0;
1858  ringBuffer = new cRingBufferLinear(Size, TS_SIZE, true, "TS");
1859  ringBuffer->SetTimeouts(100, 100);
1861  Start();
1862 }
1863 
1865 {
1866  Cancel(3);
1867  delete ringBuffer;
1868 }
1869 
1871 {
1872  if (ringBuffer) {
1873  bool firstRead = true;
1874  cPoller Poller(f);
1875  while (Running()) {
1876  if (firstRead || Poller.Poll(100)) {
1877  firstRead = false;
1878  int r = ringBuffer->Read(f);
1879  if (r < 0 && FATALERRNO) {
1880  if (errno == EOVERFLOW)
1881  esyslog("ERROR: driver buffer overflow on device %d", cardIndex);
1882  else {
1883  LOG_ERROR;
1884  break;
1885  }
1886  }
1887  cCondWait::SleepMs(10); // avoids small chunks of data, which cause high CPU usage, esp. on ARM CPUs
1888  }
1889  }
1890  }
1891 }
1892 
1893 uchar *cTSBuffer::Get(int *Available, bool CheckAvailable)
1894 {
1895  int Count = 0;
1896  if (delivered) {
1898  delivered = 0;
1899  }
1900  if (CheckAvailable && ringBuffer->Available() < TS_SIZE)
1901  return NULL;
1902  uchar *p = ringBuffer->Get(Count);
1903  if (p && Count >= TS_SIZE) {
1904  if (*p != TS_SYNC_BYTE) {
1905  for (int i = 1; i < Count; i++) {
1906  if (p[i] == TS_SYNC_BYTE) {
1907  Count = i;
1908  break;
1909  }
1910  }
1911  ringBuffer->Del(Count);
1912  esyslog("ERROR: skipped %d bytes to sync on TS packet on device %d", Count, cardIndex);
1913  return NULL;
1914  }
1915  delivered = TS_SIZE;
1916  if (Available)
1917  *Available = Count;
1918  return p;
1919  }
1920  return NULL;
1921 }
1922 
1923 void cTSBuffer::Skip(int Count)
1924 {
1925  delivered = Count;
1926 }
static int GetClippedNumProvidedSystems(int AvailableBits, cDevice *Device)
Definition: device.c:228
cEitFilter * eitFilter
Definition: device.h:422
static int nextCardIndex
Definition: device.h:183
cPatPmtParser patPmtParser
Definition: device.h:628
int sgn(T a)
Definition: tools.h:62
int cardIndex
Definition: device.h:864
void MuteAudio(bool On)
Definition: audio.c:41
unsigned char uchar
Definition: tools.h:31
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition: remux.c:627
void ClearAudio(void)
Definition: audio.c:47
void Lock(void)
Definition: thread.c:222
int NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const
Returns the number of tracks in the given range that are currently available.
Definition: device.c:1084
virtual void setScaleMode(cSpuDecoder::eScaleMode ScaleMode)=0
virtual bool HasLock(int TimeoutMs=0) const
Returns true if the device has a lock on the requested transponder.
Definition: device.c:947
cCamSlot * MtdSpawn(void)
If this CAM slot can do MTD ("Multi Transponder Decryption"), a call to this function returns a cMtdC...
Definition: ci.c:2174
virtual bool MaySwitchTransponder(const cChannel *Channel) const
Returns true if it is ok to switch to the Channel's transponder on this device, without disturbing an...
Definition: device.c:780
void SetOccupied(int Seconds)
Sets the occupied timeout for this device to the given number of Seconds, This can be used to tune a ...
Definition: device.c:936
cNitFilter * nitFilter
Definition: device.h:425
const T * Get(int Index) const
Returns the list element at the given Index, or NULL if no such element exists.
Definition: tools.h:603
Definition: device.h:64
cPlayer * player
Definition: device.h:627
bool ToggleMute(void)
Turns the volume off or on and returns the new mute state.
Definition: device.c:983
eSetChannelResult
Definition: device.h:36
#define dsyslog(a...)
Definition: tools.h:37
int Sid(void) const
Definition: channels.h:64
#define TS_SCRAMBLING_TIMEOUT
Definition: device.c:1660
cCamSlot * CamSlot(void) const
Returns the CAM slot that is currently used with this device, or NULL if no CAM slot is in use.
Definition: device.h:469
#define CA_ENCRYPTED_MIN
Definition: channels.h:44
bool GrabImageFile(const char *FileName, bool Jpeg=true, int Quality=-1, int SizeX=-1, int SizeY=-1)
Calls GrabImage() and stores the resulting image in a file with the given name.
Definition: device.c:460
int MasterSlotNumber(void)
Returns the number of this CAM's master slot within the whole system.
Definition: ci.h:346
virtual bool ProvidesCa(const int *CaSystemIds)
Returns true if the CAM in this slot provides one of the given CaSystemIds.
Definition: ci.c:2586
const int * Caids(void) const
Definition: channels.h:170
cSdtFilter * sdtFilter
Definition: device.h:424
cRingBufferLinear * ringBuffer
Definition: device.h:866
int Dpid(int i) const
Definition: channels.h:159
static cDevice * ReceiverDevice(void)
Definition: transfer.h:38
void DetachAll(int Pid)
Detaches all receivers from this device for this pid.
Definition: device.c:1831
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
Definition: remux.c:659
void SetDescription(const char *Description,...) __attribute__((format(printf
Definition: thread.c:267
#define TRANSFERPRIORITY
Definition: config.h:46
#define LOG_ERROR
Definition: tools.h:39
friend class cLiveSubtitle
Definition: device.h:118
Definition: eit.h:23
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2152
int Convert(const uchar *Data, int Length)
Definition: dvbsubtitle.c:1416
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask)
Opens a file handle for the given filter data.
Definition: device.c:678
virtual void InjectEit(int Sid)
Injects a generated EIT with a "present event" for the given Sid into the TS data stream sent to the ...
Definition: ci.c:2748
cDevice * device
Definition: player.h:19
int f
Definition: device.h:863
virtual bool SetPlayMode(ePlayMode PlayMode)
Sets the device into the given play mode.
Definition: device.c:1210
virtual void StartDecrypting(void)
Sends all CA_PMT entries to the CAM that have been modified since the last call to this function.
Definition: ci.c:2698
bool IsPrimaryDevice(void) const
Definition: device.h:213
bool TsPayloadStart(const uchar *p)
Definition: remux.h:72
void PlayAudio(const uchar *Data, int Length, uchar Id)
Definition: audio.c:29
cReceiver * receiver[MAXRECEIVERS]
Definition: device.h:822
Definition: sdt.h:16
virtual void GetVideoSize(int &Width, int &Height, double &VideoAspect)
Returns the Width, Height and VideoAspect ratio of the currently displayed video material.
Definition: device.c:514
virtual bool HasProgramme(void) const
Returns true if the device is currently showing any programme to the user, either through replaying o...
Definition: device.c:952
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
Definition: remux.h:400
virtual bool TsPostProcess(uchar *Data)
If there is a cCiSession that needs to do additional processing on TS packets (after the CAM has done...
Definition: ci.c:2738
virtual int ReadFilter(int Handle, void *Buffer, size_t Length)
Reads data from a handle for the given filter.
Definition: device.c:683
Definition: nit.h:16
virtual bool AvoidRecording(void) const
Returns true if this device should only be used for recording if no other device is available.
Definition: device.h:229
int NumReadyMasterSlots(void)
Returns the number of master CAM slots in the system that are ready to decrypt.
Definition: ci.c:2758
void SetCamSlot(cCamSlot *CamSlot)
Sets the given CamSlot to be used with this device.
Definition: device.c:440
bool mute
Definition: device.h:595
bool TsHasPayload(const uchar *p)
Definition: remux.h:62
virtual void MakePrimaryDevice(bool On)
Informs a device that it will be the primary device.
Definition: device.c:179
virtual bool ProvidesChannel(const cChannel *Channel, int Priority=IDLEPRIORITY, bool *NeedsDetachReceivers=NULL) const
Returns true if this device can provide the given channel.
Definition: device.c:735
const char * Alang(int i) const
Definition: channels.h:161
#define MAXDEVICES
Definition: device.h:29
#define esyslog(a...)
Definition: tools.h:35
virtual void SetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat)
Sets the video display format to the given one (only useful if this device has an MPEG decoder).
Definition: device.c:487
void Detach(cFilter *Filter)
Definition: sections.c:129
void Detach(cFilter *Filter)
Detaches the given filter from this device.
Definition: device.c:699
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition: device.c:223
int cardIndex
Definition: device.h:184
int Index(void) const
Definition: tools.c:2072
Definition: ci.h:170
void DelPid(int Pid, ePidType PidType=ptOther)
Deletes a PID from the set of PIDs this device shall receive.
Definition: device.c:606
bool AttachReceiver(cReceiver *Receiver)
Attaches the given receiver to this device.
Definition: device.c:1750
static int currentChannel
Definition: device.h:256
int Ppid(void) const
Returns the PCR pid as defined by the current PMT, or 0 if no PCR pid has been detected,...
Definition: remux.h:406
bool SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language=NULL, const char *Description=NULL)
Sets the track of the given Type and Index to the given values.
Definition: device.c:1050
int volume
Definition: device.h:596
#define LOG_ERROR_STR(s)
Definition: tools.h:40
virtual void Play(void)
Sets the device into play mode (after a previous trick mode).
Definition: device.c:1231
T max(T a, T b)
Definition: tools.h:60
void SetStatus(bool On)
Definition: sections.c:146
bool autoSelectPreferredSubtitleLanguage
Definition: device.h:536
const char * Slang(int i) const
Definition: channels.h:163
#define MAXVOLUME
Definition: device.h:32
int scramblingTimeout
Definition: receiver.h:27
Definition: device.h:63
static int NumDevices(void)
Returns the total number of devices.
Definition: device.h:127
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition: device.c:1664
virtual void GetOsdSize(int &Width, int &Height, double &PixelAspect)
Returns the Width, Height and PixelAspect ratio the OSD should use to best fit the resolution of the ...
Definition: device.c:521
cDevice * device
Definition: receiver.h:20
virtual void Receive(const uchar *Data, int Length)
This function is called from the cDevice we are attached to, and delivers one TS packet from the set ...
Definition: device.c:43
virtual void Clear(void)
Clears all video and audio data from the device.
Definition: device.c:1224
#define MINPRIORITY
Definition: config.h:44
virtual int PlayTsAudio(const uchar *Data, int Length)
Plays the given data block as audio.
Definition: device.c:1539
eTrackType
Definition: device.h:63
void DelLivePids(void)
Deletes the live viewing PIDs.
Definition: device.c:642
virtual bool SignalStats(int &Valid, double *Strength=NULL, double *Cnr=NULL, double *BerPre=NULL, double *BerPost=NULL, double *Per=NULL, int *Status=NULL) const
Returns statistics about the currently received signal (if available).
Definition: device.c:755
Definition: device.h:39
virtual bool DeviceProvidesTransponder(const cDevice *Device, const cChannel *Channel) const
Returns true if the given Device can provide the given Channel's transponder.
Definition: device.c:56
void AttachFilter(cFilter *Filter)
Attaches the given filter to this device.
Definition: device.c:693
const char * Dlang(int i) const
Definition: channels.h:162
virtual bool HasIBPTrickSpeed(void)
Returns true if this device can handle all frames in 'fast forward' trick speeds.
Definition: device.h:737
virtual void SetVideoFormat(bool VideoFormat16_9)
Sets the output video format to either 16:9 or 4:3 (only useful if this device has an MPEG decoder).
Definition: device.c:510
int NumSubtitleTracks(void) const
Returns the number of subtitle tracks that are currently available.
Definition: device.c:1099
int numPids
Definition: receiver.h:24
virtual int PlayPesPacket(const uchar *Data, int Length, bool VideoOnly=false)
Plays the single PES packet in Data with the given Length.
Definition: device.c:1393
T min(T a, T b)
Definition: tools.h:59
int Ca(int Index=0) const
Definition: channels.h:171
#define TS_SYNC_BYTE
Definition: remux.h:33
cTsToPes tsToPesSubtitle
Definition: device.h:631
eTrackType currentSubtitleTrack
Definition: device.h:532
eTrackType GetCurrentAudioTrack(void) const
Definition: device.h:569
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition: device.c:705
virtual int GetAudioChannelDevice(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition: device.c:958
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
Definition: device.c:745
int CurrentDolby
Definition: config.h:362
bool Poll(int TimeoutMs=0)
Definition: tools.c:1517
int Spid(int i) const
Definition: channels.h:160
virtual eModuleStatus ModuleStatus(void)
Returns the status of the CAM in this slot.
Definition: ci.c:2392
#define EIT_INJECTION_TIME
Definition: device.c:1662
virtual void Mute(void)
Turns off audio while replaying.
Definition: device.c:1245
virtual void AddChannel(const cChannel *Channel)
Adds all PIDs of the given Channel to the current list of PIDs.
Definition: ci.c:2642
Definition: filter.h:49
cTSBuffer(int File, int Size, int CardIndex)
Definition: device.c:1852
virtual void Clear(void)
Definition: tools.c:2229
bool SetCurrentAudioTrack(eTrackType Type)
Sets the current audio track to the given Type.
Definition: device.c:1104
int TsPid(const uchar *p)
Definition: remux.h:82
virtual bool ProvidesEIT(void) const
Returns true if this device provides EIT data and thus wants to be tuned to the channels it can recei...
Definition: device.c:740
virtual cString DeviceName(void) const
Returns a string identifying the name of this device.
Definition: device.c:174
static int NextCardIndex(int n=0)
Calculates the next card index.
Definition: device.c:148
bool DeviceHooksProvidesTransponder(const cChannel *Channel) const
Definition: device.c:710
bool Receiving(bool Dummy=false) const
Returns true if we are currently receiving. The parameter has no meaning (for backwards compatibility...
Definition: device.c:1650
int Priority(void)
Definition: receiver.h:57
void SetChannel(const cChannel *Channel)
Definition: sections.c:139
virtual bool Ready(void)
Returns true if this device is ready.
Definition: device.c:1645
A steerable satellite dish generally points to the south on the northern hemisphere,...
Definition: positioner.h:31
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition: device.c:1183
time_t startScrambleDetection
Definition: receiver.h:26
virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId)
Definition: player.h:70
int PesLength(const uchar *p)
Definition: remux.h:173
cDeviceHook(void)
Creates a new device hook object.
Definition: device.c:51
tChannelID ChannelID(void)
Definition: receiver.h:80
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
Definition: device.c:1238
int pre_1_3_19_PrivateStream
Definition: device.h:538
virtual void Activate(bool On)
Definition: player.h:39
void Unlock(void)
Definition: thread.h:95
void Trigger(int Sid=-1)
Definition: pat.c:306
cPatFilter * patFilter
Definition: device.h:423
Definition: player.h:16
tTrackId availableTracks[ttMaxTrackTypes]
Definition: device.h:530
#define IDLEPRIORITY
Definition: config.h:47
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition: device.h:350
bool isPlayingVideo
Definition: device.h:632
void StartSectionHandler(void)
A derived device that provides section data must call this function (typically in its constructor) to...
Definition: device.c:651
ssize_t safe_write(int filedes, const void *buffer, size_t size)
Definition: tools.c:65
void Reset(void)
Resets the converter.
Definition: remux.c:1126
T constrain(T v, T l, T h)
Definition: tools.h:68
int Read(int FileHandle, int Max=0)
Reads at most Max bytes from FileHandle and stores them in the ring buffer.
Definition: ringbuffer.c:230
virtual void SetVolumeDevice(int Volume)
Sets the audio volume on this device (Volume = 0...255).
Definition: device.c:967
cAudios Audios
Definition: audio.c:27
void StopSectionHandler(void)
A device that has called StartSectionHandler() must call this function (typically in its destructor) ...
Definition: device.c:662
void SetVolume(int Volume, bool Absolute=false)
Sets the volume to the given value, either absolutely or relative to the current volume.
Definition: device.c:1012
virtual cSpuDecoder * GetSpuDecoder(void)
Returns a pointer to the device's SPU decoder (or NULL, if this device doesn't have an SPU decoder).
Definition: device.c:210
cMutex mutexCurrentSubtitleTrack
Definition: device.h:534
cString ToString(void) const
Definition: channels.c:40
void SetDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2937
virtual const cChannel * GetCurrentlyTunedTransponder(void) const
Returns a pointer to the currently tuned transponder.
Definition: device.c:770
#define MAXOCCUPIEDTIMEOUT
Definition: device.h:34
int Sid(void) const
Definition: channels.h:174
cDevice(void)
Definition: device.c:74
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition: device.c:785
#define TS_SCRAMBLING_TIME_OK
Definition: device.c:1661
virtual int SignalStrength(void) const
Returns the "strength" of the currently received signal.
Definition: device.c:760
#define LOCK_CHANNELS_READ
Definition: channels.h:265
virtual int SignalQuality(void) const
Returns the "quality" of the currently received signal.
Definition: device.c:765
virtual ~cDevice()
Definition: device.c:115
cTsToPes tsToPesVideo
Definition: device.h:629
virtual void CloseDvr(void)
Shuts down the DVR.
Definition: device.c:1741
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
Definition: device.c:1205
int delivered
Definition: device.h:865
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition: thread.c:72
cTsToPes tsToPesAudio
Definition: device.h:630
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
Definition: device.c:942
cCamSlot * camSlot
Definition: device.h:457
void bool Start(void)
Sets the description of this thread, which will be used when logging starting or stopping of the thre...
Definition: thread.c:304
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
Definition: remux.c:1044
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition: device.c:1027
eVideoDisplayFormat
Definition: device.h:58
#define IS_AUDIO_TRACK(t)
Definition: device.h:76
cMutex mutexPids
Definition: device.h:387
bool WantsTsData(void) const
Returns true if this CAM slot wants to receive the TS data through its Decrypt() function.
Definition: ci.h:337
Definition: skins.h:37
int SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:288
cMutex mutexChannel
Definition: device.h:253
int Occupied(void) const
Returns the number of seconds this device is still occupied for.
Definition: device.c:930
int VideoFormat
Definition: config.h:318
bool CamDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2922
cSetup Setup
Definition: config.c:372
virtual bool ProvidesTransponderExclusively(const cChannel *Channel) const
Returns true if this is the only device that is able to provide the given channel's transponder.
Definition: device.c:726
Definition: ci.h:232
virtual uchar * GrabImage(int &Size, bool Jpeg=true, int Quality=-1, int SizeX=-1, int SizeY=-1)
Grabs the currently visible screen image.
Definition: device.c:455
static cDevice * primaryDevice
Definition: device.h:125
virtual void DetachAllReceivers(void)
Detaches all receivers from this device.
Definition: device.c:1843
static int numDevices
Definition: device.h:122
char * description
Definition: thread.h:87
virtual void SetAudioChannelDevice(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
Definition: device.c:963
virtual bool SetPid(cPidHandle *Handle, int Type, bool On)
Does the actual PID setting on this device.
Definition: device.c:637
cSectionHandler * sectionHandler
Definition: device.h:421
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
Definition: thread.h:101
ePlayMode
Definition: device.h:39
eTrackType currentAudioTrack
Definition: device.h:531
int Apid(int i) const
Definition: channels.h:158
static bool WaitForAllDevicesReady(int Timeout=0)
Waits until all devices have become ready, or the given Timeout (seconds) has expired.
Definition: device.c:126
virtual int PlayPes(const uchar *Data, int Length, bool VideoOnly=false)
Plays all valid PES packets in Data with the given Length.
Definition: device.c:1491
void Skip(int Count)
If after a call to Get() more or less than TS_SIZE of the available data has been processed,...
Definition: device.c:1923
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition: device.h:214
bool AddPid(int Pid)
Adds the given Pid to the list of PIDs of this receiver.
Definition: receiver.c:42
void Del(int Count)
Deletes at most Count bytes from the ring buffer.
Definition: ringbuffer.c:371
cCamSlot * MasterSlot(void)
Returns this CAM slot's master slot, or a pointer to itself if it is a master slot.
Definition: ci.h:308
static void Launch(cControl *Control)
Definition: player.c:79
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
Definition: device.c:205
eKeys Message(eMessageType Type, const char *s, int Seconds=0)
Displays the given message, either through a currently visible display object that is capable of doin...
Definition: skins.c:250
#define IS_SUBTITLE_TRACK(t)
Definition: device.h:78
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition: tools.h:606
virtual void Action(void)
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition: device.c:1870
virtual void CloseFilter(int Handle)
Closes a file handle that has previously been opened by OpenFilter().
Definition: device.c:688
virtual bool OpenDvr(void)
Opens the DVR of this device and prepares it to deliver a Transport Stream for use in a cReceiver.
Definition: device.c:1736
virtual bool Flush(int TimeoutMs=0)
Returns true if the device's output buffers are empty, i.
Definition: device.c:1371
const char * Name(void) const
Definition: channels.c:107
virtual bool IsDecrypting(void)
Returns true if the CAM in this slot is currently used for decrypting.
Definition: ci.c:2713
int pids[MAXRECEIVEPIDS]
Definition: receiver.h:23
virtual ~cLiveSubtitle()
Definition: device.c:38
virtual int PlayTsVideo(const uchar *Data, int Length)
Plays the given data block as video.
Definition: device.c:1520
Definition: device.h:67
static cDevice * GetDeviceForTransponder(const cChannel *Channel, int Priority)
Returns a device that is not currently "occupied" and can be tuned to the transponder of the given Ch...
Definition: device.c:415
virtual int PlayAudio(const uchar *Data, int Length, uchar Id)
Plays the given data block as audio.
Definition: device.c:1381
int PrimaryDVB
Definition: config.h:262
time_t lastScrambledPacket
Definition: receiver.h:25
virtual void SetPid(int Pid, bool Active)
Sets the given Pid (which has previously been added through a call to AddPid()) to Active.
Definition: ci.c:2619
cMutex mutexReceiver
Definition: device.h:821
Definition: skins.h:37
virtual void SetSubtitleTrack(eTrackType Type, const tTrackId *TrackId)
Definition: player.h:74
virtual cString DeviceType(void) const
Returns a string identifying the type of this device (like "DVB-S").
Definition: device.c:169
virtual int PlayTs(const uchar *Data, int Length, bool VideoOnly=false)
Plays the given TS packet.
Definition: device.c:1569
#define CA_DVB_MAX
Definition: channels.h:41
void Freeze(bool Status)
Definition: dvbsubtitle.h:53
bool I18nIsPreferredLanguage(int *PreferredLanguages, const char *LanguageCode, int &OldPreference, int *Position)
Checks the given LanguageCode (which may be something like "eng" or "eng+deu") against the PreferredL...
Definition: i18n.c:269
int UseDolbyDigital
Definition: config.h:320
uchar * Get(int *Available=NULL, bool CheckAvailable=false)
Returns a pointer to the first TS packet in the buffer.
Definition: device.c:1893
int Vpid(void) const
Returns the video pid as defined by the current PMT, or 0 if no video pid has been detected,...
Definition: remux.h:403
Definition: pat.h:19
#define MAXDPIDS
Definition: channels.h:32
void SetIoThrottle(void)
Definition: ringbuffer.c:95
virtual void SetSubtitleTrackDevice(eTrackType Type)
Sets the current subtitle track to the given value.
Definition: device.c:979
static int useDevice
Definition: device.h:123
static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView)
Definition: status.c:38
virtual void Receive(const uchar *Data, int Length)=0
This function is called from the cDevice we are attached to, and delivers one TS packet from the set ...
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition: device.c:160
bool Valid(void) const
Definition: channels.h:58
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition: device.c:1150
#define PATPID
Definition: remux.h:52
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:286
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:146
tChannelID GetChannelID(void) const
Definition: channels.h:188
time_t lastEitInjection
Definition: receiver.h:29
virtual bool GetTSPacket(uchar *&Data)
Gets exactly one TS packet from the DVR of this device and returns a pointer to it in Data.
Definition: device.c:1745
#define FATALERRNO
Definition: tools.h:52
cLiveSubtitle * liveSubtitle
Definition: device.h:243
virtual ~cTSBuffer()
Definition: device.c:1864
#define MAXPRIORITY
Definition: config.h:43
eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (general setup).
Definition: device.c:839
int priority
Definition: receiver.h:22
void SetChecked(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2929
static bool SetPrimaryDevice(int n)
Sets the primary device to 'n'.
Definition: device.c:187
#define TS_SYNC(Data, Length)
Definition: remux.h:149
virtual const cPositioner * Positioner(void) const
Returns a pointer to the positioner (if any) this device has used to move the satellite dish to the r...
Definition: device.c:750
bool MtdActive(void)
Returns true if MTD is currently active.
Definition: ci.h:287
void StopReplay(void)
Stops the current replay session (if any).
Definition: device.c:1357
const tTrackId * GetTrack(eTrackType Type)
Returns a pointer to the given track id, or NULL if Type is not less than ttMaxTrackTypes.
Definition: device.c:1079
#define tr(s)
Definition: i18n.h:85
unsigned char u_char
Definition: headers.h:24
bool TsIsScrambled(const uchar *p)
Definition: remux.h:93
bool HasPid(int Pid) const
Returns true if this device is currently receiving the given PID.
Definition: device.c:531
cChannelCamRelations ChannelCamRelations
Definition: ci.c:2865
int GetAudioChannel(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition: device.c:1000
bool Transferring(void) const
Returns true if we are currently in Transfer Mode.
Definition: device.c:1314
static cList< cDeviceHook > deviceHooks
Definition: device.h:236
uchar * Get(int &Count)
Gets data from the ring buffer.
Definition: ringbuffer.c:346
void DELETENULL(T *&p)
Definition: tools.h:49
virtual bool Poll(cPoller &Poller, int TimeoutMs=0)
Returns true if the device itself or any of the file handles in Poller is ready for further action.
Definition: device.c:1366
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles.
Definition: device.c:1215
int currentAudioTrackMissingCount
Definition: device.h:535
#define isyslog(a...)
Definition: tools.h:36
bool WantsPid(int Pid)
Definition: receiver.c:114
void Attach(cFilter *Filter)
Definition: sections.c:118
bool AttachPlayer(cPlayer *Player)
Attaches the given player to this device.
Definition: device.c:1319
time_t occupiedTimeout
Definition: device.h:254
int CurrentVolume
Definition: config.h:359
static void Shutdown(void)
Closes down all devices.
Definition: device.c:446
cMutex mutexCurrentAudioTrack
Definition: device.h:533
#define MAXSPIDS
Definition: channels.h:33
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition: device.c:215
ssize_t safe_read(int filedes, void *buffer, size_t size)
Definition: tools.c:53
int Priority(void)
Returns the priority of the device this slot is currently assigned to, or IDLEPRIORITY if it is not a...
Definition: ci.c:2578
static void MsgSetVolume(int Volume, bool Absolute)
Definition: status.c:62
bool CamChecked(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2915
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition: device.c:775
char language[MAXLANGCODE2]
Definition: device.h:82
virtual void TrickSpeed(int Speed, bool Forward)
Sets the device into a mode where replay is done slower.
Definition: device.c:1220
#define TS_SIZE
Definition: remux.h:34
Definition: device.h:36
virtual int PlayTsSubtitle(const uchar *Data, int Length)
Plays the given data block as a subtitle.
Definition: device.c:1555
const uchar * GetPes(int &Length)
Gets a pointer to the complete PES packet, or NULL if the packet is not complete yet.
Definition: remux.c:1073
cLiveSubtitle(int SPid)
Definition: device.c:33
void SetAudioChannel(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
Definition: device.c:1006
virtual int PlaySubtitle(const uchar *Data, int Length)
Plays the given data block as a subtitle.
Definition: device.c:1386
#define LOCK_THREAD
Definition: thread.h:167
void ForceTransferMode(void)
Forces the device into transfermode for the current channel.
Definition: device.c:921
#define IS_DOLBY_TRACK(t)
Definition: device.h:77
int DisplaySubtitles
Definition: config.h:287
int VideoDisplayFormat
Definition: config.h:317
int VolumeLinearize
Definition: config.h:361
char * Utf8Strn0Cpy(char *Dest, const char *Src, int n)
Copies at most n character bytes from Src to Dest, making sure that the resulting copy ends with a co...
Definition: tools.c:881
#define MAXPIDHANDLES
Definition: device.h:30
#define MAXRECEIVERS
Definition: device.h:31
int TsPayloadOffset(const uchar *p)
Definition: remux.h:108
int VolumeSteps
Definition: config.h:360
bool SetCurrentSubtitleTrack(eTrackType Type, bool Manual=false)
Sets the current subtitle track to the given Type.
Definition: device.c:1122
ePidType
Definition: device.h:390
#define LIVEPRIORITY
Definition: config.h:45
void SetRepeatLast(void)
Makes the next call to GetPes() return exactly the same data as the last one (provided there was no c...
Definition: remux.c:1121
bool keepTracks
Definition: device.h:537
virtual bool Assign(cDevice *Device, bool Query=false)
Assigns this CAM slot to the given Device, if this is possible.
Definition: ci.c:2182
Definition: tools.h:393
virtual void StillPicture(const uchar *Data, int Length)
Displays the given I-frame as a still picture.
Definition: device.c:1250
virtual bool IsActivating(void)
Returns true if this CAM slot is currently activating a smart card.
Definition: ci.c:2385
cDvbSubtitleConverter * dvbSubtitleConverter
Definition: device.h:244
time_t startEitInjection
Definition: receiver.h:28
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting 'running' to false, so that the Action() loop can finish in an or...
Definition: thread.c:354
virtual int PlayVideo(const uchar *Data, int Length)
Plays the given data block as video.
Definition: device.c:1376
int Count(void) const
Definition: tools.h:590
static void Shutdown(void)
Definition: player.c:100
#define MIN_PRE_1_3_19_PRIVATESTREAM
Definition: device.c:64
void Reset(void)
Resets the parser.
Definition: remux.c:617
void Detach(void)
Definition: receiver.c:125
int ConvertFragments(const uchar *Data, int Length)
Definition: dvbsubtitle.c:1370
cPidHandle pidHandles[MAXPIDHANDLES]
Definition: device.h:399
virtual void SetDigitalAudioDevice(bool On)
Tells the output device that the current audio track is Dolby Digital.
Definition: device.c:971
bool Replaying(void) const
Returns true if we are currently replaying.
Definition: device.c:1309
void SetTimeouts(int PutTimeout, int GetTimeout)
Definition: ringbuffer.c:89
int NumAudioTracks(void) const
Returns the number of audio tracks that are currently available.
Definition: device.c:1094
static void SetUseDevice(int n)
Sets the 'useDevice' flag of the given device.
Definition: device.c:142
virtual bool HasCi(void)
Returns true if this device has a Common Interface.
Definition: device.c:435
cCamSlots CamSlots
Definition: ci.c:2756
bool AddPid(int Pid, ePidType PidType=ptOther, int StreamType=0)
Adds a PID to the set of PIDs this device shall receive.
Definition: device.c:541
virtual bool ProvidesTransponder(const cChannel *Channel) const
Returns true if this device can provide the transponder of the given Channel (which implies that it c...
Definition: device.c:721
ePlayMode playMode
Definition: player.h:20
int Priority(void) const
Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY),...
Definition: device.c:1632
void PlayTsAudio(const uchar *Data, int Length)
Definition: audio.c:35
virtual void Activate(bool On)
This function is called just before the cReceiver gets attached to (On == true) and right after it ge...
Definition: receiver.h:34
virtual bool HasInternalCam(void)
Returns true if this device handles encrypted channels itself without VDR assistance.
Definition: device.h:461
Definition: tools.h:176
int Number(void) const
Definition: channels.h:177
#define PRINTPIDS(s)
Definition: device.c:529
virtual void SetAudioTrackDevice(eTrackType Type)
Sets the current audio track to the given value.
Definition: device.c:975
static cDevice * device[MAXDEVICES]
Definition: device.h:124
void Lock(void)
Definition: thread.h:94
cSkins Skins
Definition: skins.c:219
void Unlock(void)
Definition: thread.c:228
cDevice * Device(void)
Returns the device this CAM slot is currently assigned to.
Definition: ci.h:331
virtual int Available(void)
Definition: ringbuffer.c:211
uint16_t id
Definition: device.h:81
#define MAXAPIDS
Definition: channels.h:31
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition: tools.h:613
eTrackType GetCurrentSubtitleTrack(void) const
Definition: device.h:573