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  }
791  for (int i = 3; i--;) {
792  switch (SetChannel(Channel, LiveView)) {
793  case scrOk: return true;
794  case scrNotAvailable: Skins.Message(mtInfo, tr("Channel not available!"));
795  return false;
796  case scrNoTransfer: Skins.Message(mtError, tr("Can't start Transfer Mode!"));
797  return false;
798  case scrFailed: break; // loop will retry
799  default: esyslog("ERROR: invalid return value from SetChannel");
800  }
801  esyslog("retrying");
802  }
803  return false;
804 }
805 
806 bool cDevice::SwitchChannel(int Direction)
807 {
808  bool result = false;
809  Direction = sgn(Direction);
810  if (Direction) {
811  cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
812  int n = CurrentChannel() + Direction;
813  int first = n;
815  const cChannel *Channel;
816  while ((Channel = Channels->GetByNumber(n, Direction)) != NULL) {
817  // try only channels which are currently available
818  if (GetDevice(Channel, LIVEPRIORITY, true, true))
819  break;
820  n = Channel->Number() + Direction;
821  }
822  if (Channel) {
823  int d = n - first;
824  if (abs(d) == 1)
825  dsyslog("skipped channel %d", first);
826  else if (d)
827  dsyslog("skipped channels %d..%d", first, n - sgn(d));
828  if (PrimaryDevice()->SwitchChannel(Channel, true))
829  result = true;
830  }
831  else if (n != first)
832  Skins.Message(mtError, tr("Channel not available!"));
833  }
834  return result;
835 }
836 
837 eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
838 {
839  cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme()
840  cStatus::MsgChannelSwitch(this, 0, LiveView);
841 
842  if (LiveView) {
843  StopReplay();
846  }
847 
848  cDevice *Device = (LiveView && IsPrimaryDevice()) ? GetDevice(Channel, LIVEPRIORITY, true) : this;
849 
850  bool NeedsTransferMode = LiveView && Device != PrimaryDevice();
851  // If the CAM slot wants the TS data, we need to switch to Transfer Mode:
852  if (!NeedsTransferMode && LiveView && IsPrimaryDevice() && CamSlot() && CamSlot()->WantsTsData())
853  NeedsTransferMode = true;
854 
855  eSetChannelResult Result = scrOk;
856 
857  // If this DVB card can't receive this channel, let's see if we can
858  // use the card that actually can receive it and transfer data from there:
859 
860  if (NeedsTransferMode) {
861  if (Device && PrimaryDevice()->CanReplay()) {
862  if (Device->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()!
863  cControl::Launch(new cTransferControl(Device, Channel));
864  else
865  Result = scrNoTransfer;
866  }
867  else
868  Result = scrNotAvailable;
869  }
870  else {
871  // Stop section handling:
872  if (sectionHandler) {
873  sectionHandler->SetStatus(false);
874  sectionHandler->SetChannel(NULL);
875  }
876  // Tell the camSlot about the channel switch and add all PIDs of this
877  // channel to it, for possible later decryption:
878  if (camSlot)
879  camSlot->AddChannel(Channel);
880  if (SetChannelDevice(Channel, LiveView)) {
881  // Start section handling:
882  if (sectionHandler) {
883  if (patFilter)
884  patFilter->Trigger(Channel->Sid());
885  sectionHandler->SetChannel(Channel);
886  sectionHandler->SetStatus(true);
887  }
888  // Start decrypting any PIDs that might have been set in SetChannelDevice():
889  if (camSlot)
891  }
892  else
893  Result = scrFailed;
894  }
895 
896  if (Result == scrOk) {
897  if (LiveView && IsPrimaryDevice()) {
898  currentChannel = Channel->Number();
899  // Set the available audio tracks:
901  for (int i = 0; i < MAXAPIDS; i++)
902  SetAvailableTrack(ttAudio, i, Channel->Apid(i), Channel->Alang(i));
903  if (Setup.UseDolbyDigital) {
904  for (int i = 0; i < MAXDPIDS; i++)
905  SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i));
906  }
907  for (int i = 0; i < MAXSPIDS; i++)
908  SetAvailableTrack(ttSubtitle, i, Channel->Spid(i), Channel->Slang(i));
909  if (!NeedsTransferMode)
910  EnsureAudioTrack(true);
912  }
913  cStatus::MsgChannelSwitch(this, Channel->Number(), LiveView); // only report status if channel switch successful
914  }
915 
916  return Result;
917 }
918 
920 {
923  if (const cChannel *Channel = Channels->GetByNumber(CurrentChannel()))
924  SetChannelDevice(Channel, false); // this implicitly starts Transfer Mode
925  }
926 }
927 
928 int cDevice::Occupied(void) const
929 {
930  int Seconds = occupiedTimeout - time(NULL);
931  return Seconds > 0 ? Seconds : 0;
932 }
933 
934 void cDevice::SetOccupied(int Seconds)
935 {
936  if (Seconds >= 0)
937  occupiedTimeout = time(NULL) + min(Seconds, MAXOCCUPIEDTIMEOUT);
938 }
939 
940 bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
941 {
942  return false;
943 }
944 
945 bool cDevice::HasLock(int TimeoutMs) const
946 {
947  return true;
948 }
949 
950 bool cDevice::HasProgramme(void) const
951 {
952  cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme()
954 }
955 
957 {
958  return 0;
959 }
960 
961 void cDevice::SetAudioChannelDevice(int AudioChannel)
962 {
963 }
964 
965 void cDevice::SetVolumeDevice(int Volume)
966 {
967 }
968 
970 {
971 }
972 
974 {
975 }
976 
978 {
979 }
980 
982 {
983  int OldVolume = volume;
984  mute = !mute;
985  //XXX why is it necessary to use different sequences???
986  if (mute) {
987  SetVolume(0, true);
988  Audios.MuteAudio(mute); // Mute external audio after analog audio
989  }
990  else {
991  Audios.MuteAudio(mute); // Enable external audio before analog audio
992  SetVolume(OldVolume, true);
993  }
994  volume = OldVolume;
995  return mute;
996 }
997 
999 {
1000  int c = GetAudioChannelDevice();
1001  return (0 <= c && c <= 2) ? c : 0;
1002 }
1003 
1004 void cDevice::SetAudioChannel(int AudioChannel)
1005 {
1006  if (0 <= AudioChannel && AudioChannel <= 2)
1007  SetAudioChannelDevice(AudioChannel);
1008 }
1009 
1010 void cDevice::SetVolume(int Volume, bool Absolute)
1011 {
1012  int OldVolume = volume;
1013  double VolumeDelta = double(MAXVOLUME) / Setup.VolumeSteps;
1014  double VolumeLinearize = (Setup.VolumeLinearize >= 0) ? (Setup.VolumeLinearize / 10.0 + 1.0) : (1.0 / ((-Setup.VolumeLinearize / 10.0) + 1.0));
1015  volume = constrain(int(floor((Absolute ? Volume : volume + Volume) / VolumeDelta + 0.5) * VolumeDelta), 0, MAXVOLUME);
1016  SetVolumeDevice(MAXVOLUME - int(pow(1.0 - pow(double(volume) / MAXVOLUME, VolumeLinearize), 1.0 / VolumeLinearize) * MAXVOLUME));
1017  Absolute |= mute;
1018  cStatus::MsgSetVolume(Absolute ? volume : volume - OldVolume, Absolute);
1019  if (volume > 0) {
1020  mute = false;
1022  }
1023 }
1024 
1025 void cDevice::ClrAvailableTracks(bool DescriptionsOnly, bool IdsOnly)
1026 {
1027  if (keepTracks)
1028  return;
1029  if (DescriptionsOnly) {
1030  for (int i = ttNone; i < ttMaxTrackTypes; i++)
1031  *availableTracks[i].description = 0;
1032  }
1033  else {
1034  if (IdsOnly) {
1035  for (int i = ttNone; i < ttMaxTrackTypes; i++)
1036  availableTracks[i].id = 0;
1037  }
1038  else
1039  memset(availableTracks, 0, sizeof(availableTracks));
1041  SetAudioChannel(0); // fall back to stereo
1045  }
1046 }
1047 
1048 bool cDevice::SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language, const char *Description)
1049 {
1050  eTrackType t = eTrackType(Type + Index);
1051  if (Type == ttAudio && IS_AUDIO_TRACK(t) ||
1052  Type == ttDolby && IS_DOLBY_TRACK(t) ||
1053  Type == ttSubtitle && IS_SUBTITLE_TRACK(t)) {
1054  if (Language)
1055  strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language));
1056  if (Description)
1058  if (Id) {
1059  availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking
1060  if (Type == ttAudio || Type == ttDolby) {
1061  int numAudioTracks = NumAudioTracks();
1062  if (!availableTracks[currentAudioTrack].id && numAudioTracks && currentAudioTrackMissingCount++ > numAudioTracks * 10)
1063  EnsureAudioTrack();
1064  else if (t == currentAudioTrack)
1066  }
1067  else if (Type == ttSubtitle && autoSelectPreferredSubtitleLanguage)
1069  }
1070  return true;
1071  }
1072  else
1073  esyslog("ERROR: SetAvailableTrack called with invalid Type/Index (%d/%d)", Type, Index);
1074  return false;
1075 }
1076 
1078 {
1079  return (ttNone < Type && Type < ttMaxTrackTypes) ? &availableTracks[Type] : NULL;
1080 }
1081 
1082 int cDevice::NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const
1083 {
1084  int n = 0;
1085  for (int i = FirstTrack; i <= LastTrack; i++) {
1086  if (availableTracks[i].id)
1087  n++;
1088  }
1089  return n;
1090 }
1091 
1093 {
1095 }
1096 
1098 {
1100 }
1101 
1103 {
1104  if (ttNone < Type && Type <= ttDolbyLast) {
1105  cMutexLock MutexLock(&mutexCurrentAudioTrack);
1106  if (IS_DOLBY_TRACK(Type))
1107  SetDigitalAudioDevice(true);
1108  currentAudioTrack = Type;
1109  if (player)
1111  else
1113  if (IS_AUDIO_TRACK(Type))
1114  SetDigitalAudioDevice(false);
1115  return true;
1116  }
1117  return false;
1118 }
1119 
1121 {
1122  if (Type == ttNone || IS_SUBTITLE_TRACK(Type)) {
1123  currentSubtitleTrack = Type;
1127  if (Type == ttNone && dvbSubtitleConverter) {
1130  }
1132  if (player)
1134  else
1136  if (currentSubtitleTrack != ttNone && !Replaying() && !Transferring()) {
1137  const tTrackId *TrackId = GetTrack(currentSubtitleTrack);
1138  if (TrackId && TrackId->id) {
1139  liveSubtitle = new cLiveSubtitle(TrackId->id);
1141  }
1142  }
1143  return true;
1144  }
1145  return false;
1146 }
1147 
1149 {
1150  if (keepTracks)
1151  return;
1152  if (Force || !availableTracks[currentAudioTrack].id) {
1153  eTrackType PreferredTrack = ttAudioFirst;
1154  int PreferredAudioChannel = 0;
1155  int LanguagePreference = -1;
1156  int StartCheck = Setup.CurrentDolby ? ttDolbyFirst : ttAudioFirst;
1157  int EndCheck = ttDolbyLast;
1158  for (int i = StartCheck; i <= EndCheck; i++) {
1159  const tTrackId *TrackId = GetTrack(eTrackType(i));
1160  int pos = 0;
1161  if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.AudioLanguages, TrackId->language, LanguagePreference, &pos)) {
1162  PreferredTrack = eTrackType(i);
1163  PreferredAudioChannel = pos;
1164  }
1165  if (Setup.CurrentDolby && i == ttDolbyLast) {
1166  i = ttAudioFirst - 1;
1167  EndCheck = ttAudioLast;
1168  }
1169  }
1170  // Make sure we're set to an available audio track:
1171  const tTrackId *Track = GetTrack(GetCurrentAudioTrack());
1172  if (Force || !Track || !Track->id || PreferredTrack != GetCurrentAudioTrack()) {
1173  if (!Force) // only log this for automatic changes
1174  dsyslog("setting audio track to %d (%d)", PreferredTrack, PreferredAudioChannel);
1175  SetCurrentAudioTrack(PreferredTrack);
1176  SetAudioChannel(PreferredAudioChannel);
1177  }
1178  }
1179 }
1180 
1182 {
1183  if (keepTracks)
1184  return;
1185  if (Setup.DisplaySubtitles) {
1186  eTrackType PreferredTrack = ttNone;
1187  int LanguagePreference = INT_MAX; // higher than the maximum possible value
1188  for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
1189  const tTrackId *TrackId = GetTrack(eTrackType(i));
1190  if (TrackId && TrackId->id && (I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference) ||
1191  (i == ttSubtitleFirst + 8 && !*TrackId->language && LanguagePreference == INT_MAX))) // compatibility mode for old subtitles plugin
1192  PreferredTrack = eTrackType(i);
1193  }
1194  // Make sure we're set to an available subtitle track:
1195  const tTrackId *Track = GetTrack(GetCurrentSubtitleTrack());
1196  if (!Track || !Track->id || PreferredTrack != GetCurrentSubtitleTrack())
1197  SetCurrentSubtitleTrack(PreferredTrack);
1198  }
1199  else
1201 }
1202 
1203 bool cDevice::CanReplay(void) const
1204 {
1205  return HasDecoder();
1206 }
1207 
1209 {
1210  return false;
1211 }
1212 
1213 int64_t cDevice::GetSTC(void)
1214 {
1215  return -1;
1216 }
1217 
1218 void cDevice::TrickSpeed(int Speed, bool Forward)
1219 {
1220 }
1221 
1222 void cDevice::Clear(void)
1223 {
1224  Audios.ClearAudio();
1227 }
1228 
1229 void cDevice::Play(void)
1230 {
1233  dvbSubtitleConverter->Freeze(false);
1234 }
1235 
1237 {
1238  Audios.MuteAudio(true);
1241 }
1242 
1243 void cDevice::Mute(void)
1244 {
1245  Audios.MuteAudio(true);
1246 }
1247 
1248 void cDevice::StillPicture(const uchar *Data, int Length)
1249 {
1250  if (Data[0] == 0x47) {
1251  // TS data
1252  cTsToPes TsToPes;
1253  uchar *buf = NULL;
1254  int Size = 0;
1255  while (Length >= TS_SIZE) {
1256  int Pid = TsPid(Data);
1257  if (Pid == PATPID)
1258  patPmtParser.ParsePat(Data, TS_SIZE);
1259  else if (patPmtParser.IsPmtPid(Pid))
1260  patPmtParser.ParsePmt(Data, TS_SIZE);
1261  else if (Pid == patPmtParser.Vpid()) {
1262  if (TsPayloadStart(Data)) {
1263  int l;
1264  while (const uchar *p = TsToPes.GetPes(l)) {
1265  int Offset = Size;
1266  int NewSize = Size + l;
1267  if (uchar *NewBuffer = (uchar *)realloc(buf, NewSize)) {
1268  Size = NewSize;
1269  buf = NewBuffer;
1270  memcpy(buf + Offset, p, l);
1271  }
1272  else {
1273  LOG_ERROR_STR("out of memory");
1274  free(buf);
1275  return;
1276  }
1277  }
1278  TsToPes.Reset();
1279  }
1280  TsToPes.PutTs(Data, TS_SIZE);
1281  }
1282  Length -= TS_SIZE;
1283  Data += TS_SIZE;
1284  }
1285  int l;
1286  while (const uchar *p = TsToPes.GetPes(l)) {
1287  int Offset = Size;
1288  int NewSize = Size + l;
1289  if (uchar *NewBuffer = (uchar *)realloc(buf, NewSize)) {
1290  Size = NewSize;
1291  buf = NewBuffer;
1292  memcpy(buf + Offset, p, l);
1293  }
1294  else {
1295  esyslog("ERROR: out of memory");
1296  free(buf);
1297  return;
1298  }
1299  }
1300  if (buf) {
1301  StillPicture(buf, Size);
1302  free(buf);
1303  }
1304  }
1305 }
1306 
1307 bool cDevice::Replaying(void) const
1308 {
1309  return player != NULL;
1310 }
1311 
1312 bool cDevice::Transferring(void) const
1313 {
1314  return cTransferControl::ReceiverDevice() != NULL;
1315 }
1316 
1318 {
1319  if (CanReplay()) {
1320  if (player)
1321  Detach(player);
1324  patPmtParser.Reset();
1325  player = Player;
1326  if (!Transferring())
1327  ClrAvailableTracks(false, true);
1329  player->device = this;
1330  player->Activate(true);
1331  return true;
1332  }
1333  return false;
1334 }
1335 
1337 {
1338  if (Player && player == Player) {
1339  cPlayer *p = player;
1340  player = NULL; // avoids recursive calls to Detach()
1341  p->Activate(false);
1342  p->device = NULL;
1344  delete dvbSubtitleConverter;
1345  dvbSubtitleConverter = NULL;
1348  PlayTs(NULL, 0);
1349  patPmtParser.Reset();
1350  Audios.ClearAudio();
1351  isPlayingVideo = false;
1352  }
1353 }
1354 
1356 {
1357  if (player) {
1358  Detach(player);
1359  if (IsPrimaryDevice())
1361  }
1362 }
1363 
1364 bool cDevice::Poll(cPoller &Poller, int TimeoutMs)
1365 {
1366  return false;
1367 }
1368 
1369 bool cDevice::Flush(int TimeoutMs)
1370 {
1371  return true;
1372 }
1373 
1374 int cDevice::PlayVideo(const uchar *Data, int Length)
1375 {
1376  return -1;
1377 }
1378 
1379 int cDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
1380 {
1381  return -1;
1382 }
1383 
1384 int cDevice::PlaySubtitle(const uchar *Data, int Length)
1385 {
1386  if (!dvbSubtitleConverter)
1388  return dvbSubtitleConverter->ConvertFragments(Data, Length);
1389 }
1390 
1391 int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
1392 {
1393  bool FirstLoop = true;
1394  uchar c = Data[3];
1395  const uchar *Start = Data;
1396  const uchar *End = Start + Length;
1397  while (Start < End) {
1398  int d = End - Start;
1399  int w = d;
1400  switch (c) {
1401  case 0xBE: // padding stream, needed for MPEG1
1402  case 0xE0 ... 0xEF: // video
1403  isPlayingVideo = true;
1404  w = PlayVideo(Start, d);
1405  break;
1406  case 0xC0 ... 0xDF: // audio
1407  SetAvailableTrack(ttAudio, c - 0xC0, c);
1408  if ((!VideoOnly || HasIBPTrickSpeed()) && c == availableTracks[currentAudioTrack].id) {
1409  w = PlayAudio(Start, d, c);
1410  if (FirstLoop)
1411  Audios.PlayAudio(Data, Length, c);
1412  }
1413  break;
1414  case 0xBD: { // private stream 1
1415  int PayloadOffset = Data[8] + 9;
1416 
1417  // Compatibility mode for old subtitles plugin:
1418  if ((Data[7] & 0x01) && (Data[PayloadOffset - 3] & 0x81) == 0x01 && Data[PayloadOffset - 2] == 0x81)
1419  PayloadOffset--;
1420 
1421  uchar SubStreamId = Data[PayloadOffset];
1422  uchar SubStreamType = SubStreamId & 0xF0;
1423  uchar SubStreamIndex = SubStreamId & 0x1F;
1424 
1425  // Compatibility mode for old VDR recordings, where 0xBD was only AC3:
1426 pre_1_3_19_PrivateStreamDetected:
1428  SubStreamId = c;
1429  SubStreamType = 0x80;
1430  SubStreamIndex = 0;
1431  }
1432  else if (pre_1_3_19_PrivateStream)
1433  pre_1_3_19_PrivateStream--; // every known PS1 packet counts down towards 0 to recover from glitches...
1434  switch (SubStreamType) {
1435  case 0x20: // SPU
1436  case 0x30: // SPU
1437  SetAvailableTrack(ttSubtitle, SubStreamIndex, SubStreamId);
1438  if ((!VideoOnly || HasIBPTrickSpeed()) && currentSubtitleTrack != ttNone && SubStreamId == availableTracks[currentSubtitleTrack].id)
1439  w = PlaySubtitle(Start, d);
1440  break;
1441  case 0x80: // AC3 & DTS
1442  if (Setup.UseDolbyDigital) {
1443  SetAvailableTrack(ttDolby, SubStreamIndex, SubStreamId);
1444  if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) {
1445  w = PlayAudio(Start, d, SubStreamId);
1446  if (FirstLoop)
1447  Audios.PlayAudio(Data, Length, SubStreamId);
1448  }
1449  }
1450  break;
1451  case 0xA0: // LPCM
1452  SetAvailableTrack(ttAudio, SubStreamIndex, SubStreamId);
1453  if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) {
1454  w = PlayAudio(Start, d, SubStreamId);
1455  if (FirstLoop)
1456  Audios.PlayAudio(Data, Length, SubStreamId);
1457  }
1458  break;
1459  default:
1460  // Compatibility mode for old VDR recordings, where 0xBD was only AC3:
1462  dsyslog("unknown PS1 packet, substream id = %02X (counter is at %d)", SubStreamId, pre_1_3_19_PrivateStream);
1463  pre_1_3_19_PrivateStream += 2; // ...and every unknown PS1 packet counts up (the very first one counts twice, but that's ok)
1465  dsyslog("switching to pre 1.3.19 Dolby Digital compatibility mode - substream id = %02X", SubStreamId);
1468  goto pre_1_3_19_PrivateStreamDetected;
1469  }
1470  }
1471  }
1472  }
1473  break;
1474  default:
1475  ;//esyslog("ERROR: unexpected packet id %02X", c);
1476  }
1477  if (w > 0)
1478  Start += w;
1479  else {
1480  if (Start != Data)
1481  esyslog("ERROR: incomplete PES packet write!");
1482  return Start == Data ? w : Start - Data;
1483  }
1484  FirstLoop = false;
1485  }
1486  return Length;
1487 }
1488 
1489 int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly)
1490 {
1491  if (!Data) {
1494  return 0;
1495  }
1496  int i = 0;
1497  while (i <= Length - 6) {
1498  if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
1499  int l = PesLength(Data + i);
1500  if (i + l > Length) {
1501  esyslog("ERROR: incomplete PES packet!");
1502  return Length;
1503  }
1504  int w = PlayPesPacket(Data + i, l, VideoOnly);
1505  if (w > 0)
1506  i += l;
1507  else
1508  return i == 0 ? w : i;
1509  }
1510  else
1511  i++;
1512  }
1513  if (i < Length)
1514  esyslog("ERROR: leftover PES data!");
1515  return Length;
1516 }
1517 
1518 int cDevice::PlayTsVideo(const uchar *Data, int Length)
1519 {
1520  // Video PES has no explicit length, so we can only determine the end of
1521  // a PES packet when the next TS packet that starts a payload comes in:
1522  if (TsPayloadStart(Data)) {
1523  int l;
1524  while (const uchar *p = tsToPesVideo.GetPes(l)) {
1525  int w = PlayVideo(p, l);
1526  if (w <= 0) {
1528  return w;
1529  }
1530  }
1531  tsToPesVideo.Reset();
1532  }
1533  tsToPesVideo.PutTs(Data, Length);
1534  return Length;
1535 }
1536 
1537 int cDevice::PlayTsAudio(const uchar *Data, int Length)
1538 {
1539  // Audio PES always has an explicit length and consists of single packets:
1540  int l;
1541  if (const uchar *p = tsToPesAudio.GetPes(l)) {
1542  int w = PlayAudio(p, l, p[3]);
1543  if (w <= 0) {
1545  return w;
1546  }
1547  tsToPesAudio.Reset();
1548  }
1549  tsToPesAudio.PutTs(Data, Length);
1550  return Length;
1551 }
1552 
1553 int cDevice::PlayTsSubtitle(const uchar *Data, int Length)
1554 {
1555  if (!dvbSubtitleConverter)
1557  tsToPesSubtitle.PutTs(Data, Length);
1558  int l;
1559  if (const uchar *p = tsToPesSubtitle.GetPes(l)) {
1562  }
1563  return Length;
1564 }
1565 
1566 //TODO detect and report continuity errors?
1567 int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
1568 {
1569  int Played = 0;
1570  if (!Data) {
1571  tsToPesVideo.Reset();
1572  tsToPesAudio.Reset();
1574  }
1575  else if (Length < TS_SIZE) {
1576  esyslog("ERROR: skipped %d bytes of TS fragment", Length);
1577  return Length;
1578  }
1579  else {
1580  while (Length >= TS_SIZE) {
1581  if (int Skipped = TS_SYNC(Data, Length))
1582  return Played + Skipped;
1583  int Pid = TsPid(Data);
1584  if (TsHasPayload(Data)) { // silently ignore TS packets w/o payload
1585  int PayloadOffset = TsPayloadOffset(Data);
1586  if (PayloadOffset < TS_SIZE) {
1587  if (Pid == PATPID)
1588  patPmtParser.ParsePat(Data, TS_SIZE);
1589  else if (patPmtParser.IsPmtPid(Pid))
1590  patPmtParser.ParsePmt(Data, TS_SIZE);
1591  else if (Pid == patPmtParser.Vpid()) {
1592  isPlayingVideo = true;
1593  int w = PlayTsVideo(Data, TS_SIZE);
1594  if (w < 0)
1595  return Played ? Played : w;
1596  if (w == 0)
1597  break;
1598  }
1599  else if (Pid == availableTracks[currentAudioTrack].id) {
1600  if (!VideoOnly || HasIBPTrickSpeed()) {
1601  int w = PlayTsAudio(Data, TS_SIZE);
1602  if (w < 0)
1603  return Played ? Played : w;
1604  if (w == 0)
1605  break;
1606  Audios.PlayTsAudio(Data, TS_SIZE);
1607  }
1608  }
1609  else if (Pid == availableTracks[currentSubtitleTrack].id) {
1610  if (!VideoOnly || HasIBPTrickSpeed())
1611  PlayTsSubtitle(Data, TS_SIZE);
1612  }
1613  }
1614  }
1615  else if (Pid == patPmtParser.Ppid()) {
1616  int w = PlayTsVideo(Data, TS_SIZE);
1617  if (w < 0)
1618  return Played ? Played : w;
1619  if (w == 0)
1620  break;
1621  }
1622  Played += TS_SIZE;
1623  Length -= TS_SIZE;
1624  Data += TS_SIZE;
1625  }
1626  }
1627  return Played;
1628 }
1629 
1630 int cDevice::Priority(void) const
1631 {
1632  int priority = IDLEPRIORITY;
1633  if (IsPrimaryDevice() && !Replaying() && HasProgramme())
1634  priority = TRANSFERPRIORITY; // we use the same value here, no matter whether it's actual Transfer Mode or real live viewing
1635  cMutexLock MutexLock(&mutexReceiver);
1636  for (int i = 0; i < MAXRECEIVERS; i++) {
1637  if (receiver[i])
1638  priority = max(receiver[i]->priority, priority);
1639  }
1640  return priority;
1641 }
1642 
1643 bool cDevice::Ready(void)
1644 {
1645  return true;
1646 }
1647 
1648 bool cDevice::Receiving(bool Dummy) const
1649 {
1650  cMutexLock MutexLock(&mutexReceiver);
1651  for (int i = 0; i < MAXRECEIVERS; i++) {
1652  if (receiver[i])
1653  return true;
1654  }
1655  return false;
1656 }
1657 
1658 #define TS_SCRAMBLING_TIMEOUT 3 // seconds to wait until a TS becomes unscrambled
1659 #define TS_SCRAMBLING_TIME_OK 3 // seconds before a Channel/CAM combination is marked as known to decrypt
1660 #define EIT_INJECTION_TIME 10 // seconds for which to inject EIT event
1661 
1663 {
1664  if (Running() && OpenDvr()) {
1665  while (Running()) {
1666  // Read data from the DVR device:
1667  uchar *b = NULL;
1668  if (GetTSPacket(b)) {
1669  if (b) {
1670  // Distribute the packet to all attached receivers:
1671  Lock();
1672  cCamSlot *cs = CamSlot();
1673  if (cs)
1674  cs->TsPostProcess(b);
1675  int Pid = TsPid(b);
1676  bool IsScrambled = TsIsScrambled(b);
1677  for (int i = 0; i < MAXRECEIVERS; i++) {
1678  cMutexLock MutexLock(&mutexReceiver);
1679  cReceiver *Receiver = receiver[i];
1680  if (Receiver && Receiver->WantsPid(Pid)) {
1681  Receiver->Receive(b, TS_SIZE);
1682  // Check whether the TS packet is scrambled:
1683  if (Receiver->startScrambleDetection) {
1684  if (cs) {
1685  int CamSlotNumber = cs->MasterSlotNumber();
1686  if (Receiver->lastScrambledPacket < Receiver->startScrambleDetection)
1687  Receiver->lastScrambledPacket = Receiver->startScrambleDetection;
1688  time_t Now = time(NULL);
1689  if (IsScrambled) {
1690  Receiver->lastScrambledPacket = Now;
1691  if (Now - Receiver->startScrambleDetection > Receiver->scramblingTimeout) {
1692  if (!cs->IsActivating() || Receiver->Priority() >= LIVEPRIORITY) {
1693  if (Receiver->ChannelID().Valid()) {
1694  dsyslog("CAM %d: won't decrypt channel %s, detaching receiver", CamSlotNumber, *Receiver->ChannelID().ToString());
1695  ChannelCamRelations.SetChecked(Receiver->ChannelID(), CamSlotNumber);
1696  }
1697  Detach(Receiver);
1698  }
1699  }
1700  }
1701  else if (Now - Receiver->lastScrambledPacket > TS_SCRAMBLING_TIME_OK) {
1702  if (Receiver->ChannelID().Valid()) {
1703  dsyslog("CAM %d: decrypts channel %s", CamSlotNumber, *Receiver->ChannelID().ToString());
1704  ChannelCamRelations.SetDecrypt(Receiver->ChannelID(), CamSlotNumber);
1705  }
1706  Receiver->startScrambleDetection = 0;
1707  }
1708  }
1709  }
1710  // Inject EIT event to avoid the CAMs parental rating prompt:
1711  if (Receiver->startEitInjection) {
1712  time_t Now = time(NULL);
1713  if (cCamSlot *cs = CamSlot()) {
1714  if (Now != Receiver->lastEitInjection) { // once per second
1715  cs->InjectEit(Receiver->ChannelID().Sid());
1716  Receiver->lastEitInjection = Now;
1717  }
1718  }
1719  if (Now - Receiver->startEitInjection > EIT_INJECTION_TIME)
1720  Receiver->startEitInjection = 0;
1721  }
1722  }
1723  }
1724  Unlock();
1725  }
1726  }
1727  else
1728  break;
1729  }
1730  CloseDvr();
1731  }
1732 }
1733 
1735 {
1736  return false;
1737 }
1738 
1740 {
1741 }
1742 
1744 {
1745  return false;
1746 }
1747 
1749 {
1750  if (!Receiver)
1751  return false;
1752  if (Receiver->device == this)
1753  return true;
1754 // activate the following line if you need it - actually the driver should be fixed!
1755 //#define WAIT_FOR_TUNER_LOCK
1756 #ifdef WAIT_FOR_TUNER_LOCK
1757 #define TUNER_LOCK_TIMEOUT 5000 // ms
1758  if (!HasLock(TUNER_LOCK_TIMEOUT)) {
1759  esyslog("ERROR: device %d has no lock, can't attach receiver!", CardIndex() + 1);
1760  return false;
1761  }
1762 #endif
1763  cMutexLock MutexLock(&mutexReceiver);
1764  for (int i = 0; i < MAXRECEIVERS; i++) {
1765  if (!receiver[i]) {
1766  for (int n = 0; n < Receiver->numPids; n++) {
1767  if (!AddPid(Receiver->pids[n])) {
1768  for ( ; n-- > 0; )
1769  DelPid(Receiver->pids[n]);
1770  return false;
1771  }
1772  }
1773  Receiver->Activate(true);
1774  Receiver->device = this;
1775  receiver[i] = Receiver;
1776  if (camSlot && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
1778  if (camSlot->WantsTsData()) {
1779  Receiver->lastEitInjection = 0;
1780  Receiver->startEitInjection = time(NULL);
1781  }
1782  if (CamSlots.NumReadyMasterSlots() > 1) { // don't try different CAMs if there is only one
1783  Receiver->startScrambleDetection = time(NULL);
1785  bool KnownToDecrypt = ChannelCamRelations.CamDecrypt(Receiver->ChannelID(), camSlot->MasterSlotNumber());
1786  if (KnownToDecrypt)
1787  Receiver->scramblingTimeout *= 10; // give it time to receive ECM/EMM
1788  if (Receiver->ChannelID().Valid())
1789  dsyslog("CAM %d: %sknown to decrypt channel %s (scramblingTimeout = %ds)", camSlot->MasterSlotNumber(), KnownToDecrypt ? "" : "not ", *Receiver->ChannelID().ToString(), Receiver->scramblingTimeout);
1790  }
1791  }
1792  Start();
1793  return true;
1794  }
1795  }
1796  esyslog("ERROR: no free receiver slot!");
1797  return false;
1798 }
1799 
1801 {
1802  if (!Receiver || Receiver->device != this)
1803  return;
1804  bool receiversLeft = false;
1805  mutexReceiver.Lock();
1806  for (int i = 0; i < MAXRECEIVERS; i++) {
1807  if (receiver[i] == Receiver) {
1808  receiver[i] = NULL;
1809  Receiver->device = NULL;
1810  Receiver->Activate(false);
1811  for (int n = 0; n < Receiver->numPids; n++)
1812  DelPid(Receiver->pids[n]);
1813  }
1814  else if (receiver[i])
1815  receiversLeft = true;
1816  }
1818  if (camSlot) {
1819  if (Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
1821  if (!camSlot->IsDecrypting() && !camSlot->IsActivating())
1822  camSlot->Assign(NULL);
1823  }
1824  }
1825  if (!receiversLeft)
1826  Cancel(-1);
1827 }
1828 
1829 void cDevice::DetachAll(int Pid)
1830 {
1831  if (Pid) {
1832  cMutexLock MutexLock(&mutexReceiver);
1833  for (int i = 0; i < MAXRECEIVERS; i++) {
1834  cReceiver *Receiver = receiver[i];
1835  if (Receiver && Receiver->WantsPid(Pid))
1836  Detach(Receiver);
1837  }
1838  }
1839 }
1840 
1842 {
1843  cMutexLock MutexLock(&mutexReceiver);
1844  for (int i = 0; i < MAXRECEIVERS; i++)
1845  Detach(receiver[i]);
1846 }
1847 
1848 // --- cTSBuffer -------------------------------------------------------------
1849 
1850 cTSBuffer::cTSBuffer(int File, int Size, int CardIndex)
1851 {
1852  SetDescription("device %d TS buffer", CardIndex);
1853  f = File;
1854  cardIndex = CardIndex;
1855  delivered = 0;
1856  ringBuffer = new cRingBufferLinear(Size, TS_SIZE, true, "TS");
1857  ringBuffer->SetTimeouts(100, 100);
1859  Start();
1860 }
1861 
1863 {
1864  Cancel(3);
1865  delete ringBuffer;
1866 }
1867 
1869 {
1870  if (ringBuffer) {
1871  bool firstRead = true;
1872  cPoller Poller(f);
1873  while (Running()) {
1874  if (firstRead || Poller.Poll(100)) {
1875  firstRead = false;
1876  int r = ringBuffer->Read(f);
1877  if (r < 0 && FATALERRNO) {
1878  if (errno == EOVERFLOW)
1879  esyslog("ERROR: driver buffer overflow on device %d", cardIndex);
1880  else {
1881  LOG_ERROR;
1882  break;
1883  }
1884  }
1885  cCondWait::SleepMs(10); // avoids small chunks of data, which cause high CPU usage, esp. on ARM CPUs
1886  }
1887  }
1888  }
1889 }
1890 
1891 uchar *cTSBuffer::Get(int *Available, bool CheckAvailable)
1892 {
1893  int Count = 0;
1894  if (delivered) {
1896  delivered = 0;
1897  }
1898  if (CheckAvailable && ringBuffer->Available() < TS_SIZE)
1899  return NULL;
1900  uchar *p = ringBuffer->Get(Count);
1901  if (p && Count >= TS_SIZE) {
1902  if (*p != TS_SYNC_BYTE) {
1903  for (int i = 1; i < Count; i++) {
1904  if (p[i] == TS_SYNC_BYTE) {
1905  Count = i;
1906  break;
1907  }
1908  }
1909  ringBuffer->Del(Count);
1910  esyslog("ERROR: skipped %d bytes to sync on TS packet on device %d", Count, cardIndex);
1911  return NULL;
1912  }
1913  delivered = TS_SIZE;
1914  if (Available)
1915  *Available = Count;
1916  return p;
1917  }
1918  return NULL;
1919 }
1920 
1921 void cTSBuffer::Skip(int Count)
1922 {
1923  delivered = Count;
1924 }
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:663
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:1082
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:945
cCamSlot * MtdSpawn(void)
If this CAM slot can do MTD ("Multi Transponder Decryption"), a call to this function returns a cMtdC...
Definition: ci.c:2173
virtual bool MaySwitchTransponder(const cChannel *Channel) const
Returns true if it is ok to switch to the Channel&#39;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:934
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:981
eSetChannelResult
Definition: device.h:36
#define dsyslog(a...)
Definition: tools.h:37
int Sid(void) const
Definition: channels.h:66
#define TS_SCRAMBLING_TIMEOUT
Definition: device.c:1658
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&#39;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:2585
const int * Caids(void) const
Definition: channels.h:172
cSdtFilter * sdtFilter
Definition: device.h:424
cRingBufferLinear * ringBuffer
Definition: device.h:866
int Dpid(int i) const
Definition: channels.h:161
static cDevice * ReceiverDevice(void)
Definition: transfer.h:38
void DetachAll(int Pid)
Detaches all receivers from this device for this pid.
Definition: device.c:1829
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
Definition: remux.c:695
void SetDescription(const char *Description,...) __attribute__((format(printf
Definition: thread.c:267
#define TRANSFERPRIORITY
Definition: config.h:42
#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:2747
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:1208
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:2697
bool IsPrimaryDevice(void) const
Definition: device.h:213
bool TsPayloadStart(const uchar *p)
Definition: remux.h:77
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:950
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
Definition: remux.h:406
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:2737
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:2757
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:163
#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:1748
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, yet.
Definition: remux.h:412
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:1048
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:1229
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:165
#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:1662
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:1222
#define MINPRIORITY
Definition: config.h:40
virtual int PlayTsAudio(const uchar *Data, int Length)
Plays the given data block as audio.
Definition: device.c:1537
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&#39;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:164
virtual bool HasIBPTrickSpeed(void)
Returns true if this device can handle all frames in &#39;fast forward&#39; 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:1097
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:1391
T min(T a, T b)
Definition: tools.h:59
int Ca(int Index=0) const
Definition: channels.h:173
#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:956
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:162
virtual eModuleStatus ModuleStatus(void)
Returns the status of the CAM in this slot.
Definition: ci.c:2391
#define EIT_INJECTION_TIME
Definition: device.c:1660
virtual void Mute(void)
Turns off audio while replaying.
Definition: device.c:1243
virtual void AddChannel(const cChannel *Channel)
Adds all PIDs of the given Channel to the current list of PIDs.
Definition: ci.c:2641
Definition: filter.h:49
cTSBuffer(int File, int Size, int CardIndex)
Definition: device.c:1850
virtual void Clear(void)
Definition: tools.c:2229
bool SetCurrentAudioTrack(eTrackType Type)
Sets the current audio track to the given Type.
Definition: device.c:1102
int TsPid(const uchar *p)
Definition: remux.h:87
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:1648
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:1643
A steerable satellite dish generally points to the south on the northern hemisphere, and to the north on the southern hemisphere (unless you&#39;re located directly on the equator, in which case the general direction is "up").
Definition: positioner.h:31
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition: device.c:1181
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:179
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:1236
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:43
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:1162
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:965
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:1010
virtual cSpuDecoder * GetSpuDecoder(void)
Returns a pointer to the device&#39;s SPU decoder (or NULL, if this device doesn&#39;t have an SPU decoder)...
Definition: device.c:210
cMutex mutexCurrentSubtitleTrack
Definition: device.h:534
cString ToString(void) const
Definition: channels.c:41
void SetDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2936
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:176
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:1659
virtual int SignalStrength(void) const
Returns the "strength" of the currently received signal.
Definition: device.c:760
#define LOCK_CHANNELS_READ
Definition: channels.h:267
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:1739
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
Definition: device.c:1203
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:940
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:1080
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition: device.c:1025
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:287
cMutex mutexChannel
Definition: device.h:253
int Occupied(void) const
Returns the number of seconds this device is still occupied for.
Definition: device.c:928
int VideoFormat
Definition: config.h:317
bool CamDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2921
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&#39;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:1841
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:961
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:160
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:1489
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:1921
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&#39;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:1868
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:1734
virtual bool Flush(int TimeoutMs=0)
Returns true if the device&#39;s output buffers are empty, i.
Definition: device.c:1369
const char * Name(void) const
Definition: channels.c:108
virtual bool IsDecrypting(void)
Returns true if the CAM in this slot is currently used for decrypting.
Definition: ci.c:2712
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:1518
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:1379
int PrimaryDVB
Definition: config.h:261
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:2618
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:1567
#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:319
uchar * Get(int *Available=NULL, bool CheckAvailable=false)
Returns a pointer to the first TS packet in the buffer.
Definition: device.c:1891
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:409
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:977
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:60
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition: device.c:1148
#define PATPID
Definition: remux.h:52
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:285
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition: device.h:146
tChannelID GetChannelID(void) const
Definition: channels.h:190
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:1743
#define FATALERRNO
Definition: tools.h:52
cLiveSubtitle * liveSubtitle
Definition: device.h:243
virtual ~cTSBuffer()
Definition: device.c:1862
#define MAXPRIORITY
Definition: config.h:39
eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (general setup).
Definition: device.c:837
int priority
Definition: receiver.h:22
void SetChecked(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2928
static bool SetPrimaryDevice(int n)
Sets the primary device to &#39;n&#39;.
Definition: device.c:187
#define TS_SYNC(Data, Length)
Definition: remux.h:154
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:1355
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:1077
#define tr(s)
Definition: i18n.h:85
unsigned char u_char
Definition: headers.h:24
bool TsIsScrambled(const uchar *p)
Definition: remux.h:98
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:2864
int GetAudioChannel(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition: device.c:998
bool Transferring(void) const
Returns true if we are currently in Transfer Mode.
Definition: device.c:1312
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:1364
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles...
Definition: device.c:1213
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:1317
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:2577
static void MsgSetVolume(int Volume, bool Absolute)
Definition: status.c:62
bool CamChecked(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2914
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel&#39;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:1218
#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:1553
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:1109
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:1004
virtual int PlaySubtitle(const uchar *Data, int Length)
Plays the given data block as a subtitle.
Definition: device.c:1384
#define LOCK_THREAD
Definition: thread.h:167
void ForceTransferMode(void)
Forces the device into transfermode for the current channel.
Definition: device.c:919
#define IS_DOLBY_TRACK(t)
Definition: device.h:77
int DisplaySubtitles
Definition: config.h:286
int VideoDisplayFormat
Definition: config.h:316
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:113
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:1120
ePidType
Definition: device.h:390
#define LIVEPRIORITY
Definition: config.h:41
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:1157
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:2181
Definition: tools.h:393
virtual void StillPicture(const uchar *Data, int Length)
Displays the given I-frame as a still picture.
Definition: device.c:1248
virtual bool IsActivating(void)
Returns true if this CAM slot is currently activating a smart card.
Definition: ci.c:2384
cDvbSubtitleConverter * dvbSubtitleConverter
Definition: device.h:244
time_t startEitInjection
Definition: receiver.h:28
void Cancel(int WaitSeconds=0)
Cancels the thread by first setting &#39;running&#39; 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:1374
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:653
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:969
bool Replaying(void) const
Returns true if we are currently replaying.
Definition: device.c:1307
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:1092
static void SetUseDevice(int n)
Sets the &#39;useDevice&#39; 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:2755
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), or IDLEPRIORITY if no receiver is currently active.
Definition: device.c:1630
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:179
#define PRINTPIDS(s)
Definition: device.c:529
virtual void SetAudioTrackDevice(eTrackType Type)
Sets the current audio track to the given value.
Definition: device.c:973
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