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