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 
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 
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);
1764  ringBuffer->SetIoThrottle();
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) {
1800  ringBuffer->Del(TS_SIZE);
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
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
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 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
cDevice * Device(void)
Definition: receiver.h:27
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 &#39;fast forward&#39; 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&#39;re located directly on the equator, in which case the general direction is "up").
Definition: positioner.h:31
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition: device.c: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&#39;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&#39;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
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&#39;s SPU decoder (or NULL, if this device doesn&#39;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
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
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&#39;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
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 &#39;n&#39;.
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
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&#39;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&#39;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 &#39;running&#39; 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
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 &#39;useDevice&#39; 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