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