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