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