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)
83  cDevice::nextParentDevice = NULL;
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)
402  return parentDevice->SetCamSlot(CamSlot);
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)
1029  Utf8Strn0Cpy(availableTracks[t].description, Description, sizeof(availableTracks[t].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
virtual int SignalQuality(void) const
Returns the "quality" of the currently received signal.
Definition: device.c:730
int sgn(T a)
Definition: tools.h:56
int cardIndex
Definition: device.h:859
void MuteAudio(bool On)
Definition: audio.c:41
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
bool Replaying(void) const
Returns true if we are currently replaying.
Definition: device.c:1279
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
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition: device.c:197
void ClearAudio(void)
Definition: audio.c:47
virtual void setScaleMode(cSpuDecoder::eScaleMode ScaleMode)=0
uchar * Get(int *Available=NULL)
Returns a pointer to the first TS packet in the buffer.
Definition: device.c:1857
int Number(void) const
Definition: channels.h:179
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
int Index(void) const
Definition: tools.c:1989
virtual const cChannel * GetCurrentlyTunedTransponder(void) const
Returns a pointer to the currently tuned transponder.
Definition: device.c:735
#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 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 bool ProvidesCa(const int *CaSystemIds)
Returns true if the CAM in this slot provides one of the given CaSystemIds.
Definition: ci.c:2089
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 NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const
Returns the number of tracks in the given range that are currently available.
Definition: device.c:1054
cSdtFilter * sdtFilter
Definition: device.h:386
cRingBufferLinear * ringBuffer
Definition: device.h:861
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
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
#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
int Spid(int i) const
Definition: channels.h:162
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
int Ca(int Index=0) const
Definition: channels.h:173
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 DeviceHooksProvidesTransponder(const cChannel *Channel) const
Definition: device.c:680
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
int Dpid(int i) const
Definition: channels.h:161
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 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
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
#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
T * Get(int Index) const
Definition: tools.h:491
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
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
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
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
#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
eTrackType GetCurrentSubtitleTrack(void) const
Definition: device.h:539
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
const char * Dlang(int i) const
Definition: channels.h:164
void DelLivePids(void)
Deletes the live viewing PIDs.
Definition: device.c:600
Definition: device.h:39
void AttachFilter(cFilter *Filter)
Attaches the given filter to this device.
Definition: device.c:658
int NumAudioTracks(void) const
Returns the number of audio tracks that are currently available.
Definition: device.c:1064
virtual bool HasIBPTrickSpeed(void)
Returns true if this device can handle all frames in 'fast forward' trick speeds. ...
Definition: device.h:700
int Count(void) const
Definition: tools.h:485
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 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
#define TS_SYNC_BYTE
Definition: remux.h:33
cTsToPes tsToPesSubtitle
Definition: device.h:597
eTrackType currentSubtitleTrack
Definition: device.h:498
virtual int GetAudioChannelDevice(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition: device.c:928
int CurrentDolby
Definition: config.h:356
bool Poll(int TimeoutMs=0)
Definition: tools.c:1443
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
const char * Alang(int i) const
Definition: channels.h:163
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
static int NextCardIndex(int n=0)
Calculates the next card index.
Definition: device.c:185
int Priority(void)
Definition: receiver.h:52
bool IsPrimaryDevice(void) const
Definition: device.h:830
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'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
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
int PesLength(const uchar *p)
Definition: remux.h:162
bool Transferring(void) const
Returns true if we are currently in Transfer Mode.
Definition: device.c:1284
cDeviceHook(void)
Creates a new device hook object.
Definition: device.c:51
virtual int SignalStrength(void) const
Returns the "strength" of the currently received signal.
Definition: device.c:725
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:745
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
virtual cString DeviceName(void) const
Returns a string identifying the name of this device.
Definition: device.c:213
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
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
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition: device.h:319
const char * Name(void) const
Definition: channels.c:122
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
Definition: device.c:715
T * Next(const T *object) const
Definition: tools.h:495
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
const int * Caids(void) const
Definition: channels.h:172
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's SPU decoder (or NULL, if this device doesn'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
#define MAXOCCUPIEDTIMEOUT
Definition: device.h:34
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 ~cDevice()
Definition: device.c:130
cTsToPes tsToPesVideo
Definition: device.h:595
virtual void CloseDvr(void)
Shuts down the DVR.
Definition: device.c:1708
virtual bool HasLock(int TimeoutMs=0) const
Returns true if the device has a lock on the requested transponder.
Definition: device.c:918
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'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
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
int SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:288
bool delivered
Definition: device.h:860
int VideoFormat
Definition: config.h:312
bool CamDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition: ci.c:2387
cSetup Setup
Definition: config.c:372
tChannelID GetChannelID(void) const
Definition: channels.h:190
Definition: ci.h:131
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
int Occupied(void) const
Returns the number of seconds this device is still occupied for.
Definition: device.c:895
eTrackType currentAudioTrack
Definition: device.h:497
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
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 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
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 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
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's output buffers are empty, i.
Definition: device.c:1348
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
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition: device.h:831
virtual cString DeviceType(void) const
Returns a string identifying the type of this device (like "DVB-S").
Definition: device.c:208
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
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 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
Definition: pat.h:19
#define MAXDPIDS
Definition: channels.h:36
void SetIoThrottle(void)
Definition: ringbuffer.c:95
T * First(void) const
Definition: tools.h:492
virtual void SetSubtitleTrackDevice(eTrackType Type)
Sets the current subtitle track to the given value.
Definition: device.c:949
virtual ~cDynamicDeviceProbe()
Definition: device.c:1908
void Del(cListObject *Object, bool DeleteObject=true)
Definition: tools.c:2046
static int useDevice
Definition: device.h:114
static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView)
Definition: status.c:38
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
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 'n'.
Definition: device.c:226
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
int Apid(int i) const
Definition: channels.h:160
#define tr(s)
Definition: i18n.h:85
unsigned char u_char
Definition: headers.h:24
bool TsIsScrambled(const uchar *p)
Definition: remux.h:86
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
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
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:696
int currentAudioTrackMissingCount
Definition: device.h:501
#define isyslog(a...)
Definition: tools.h:35
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition: device.c:740
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
const char * Slang(int i) const
Definition: channels.h:165
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 CanReplay(void) const
Returns true if this device can currently start a replay session.
Definition: device.c:1175
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
bool HasPid(int Pid) const
Returns true if this device is currently receiving the given PID.
Definition: device.c:492
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition: device.c:675
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
Definition: device.c:243
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
int Sid(void) const
Definition: channels.h:176
#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
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 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 'running' to false, so that the Action() loop can finish in an or...
Definition: thread.c:323
eTrackType GetCurrentAudioTrack(void) const
Definition: device.h:535
virtual int PlayVideo(const uchar *Data, int Length)
Plays the given data block as video.
Definition: device.c:1353
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
void SetTimeouts(int PutTimeout, int GetTimeout)
Definition: ringbuffer.c:89
int NumSubtitleTracks(void) const
Returns the number of subtitle tracks that are currently available.
Definition: device.c:1069
cDynamicDeviceProbe(void)
Definition: device.c:1903
static void SetUseDevice(int n)
Sets the 'useDevice' 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
ePlayMode playMode
Definition: player.h:20
int SlotNumber(void)
Returns the number of this CAM slot within the whole system.
Definition: ci.h:184
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
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
#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:176
uint16_t id
Definition: device.h:88
#define MAXAPIDS
Definition: channels.h:35