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