vdr 2.8.3
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 5.26 2026/09/24 20:28:19 kls Exp $
8 */
9
10#define MUTE_DEPRECATED_FLUSH
11#include "device.h"
12#include <errno.h>
13#include <math.h>
14#include <sys/ioctl.h>
15#include <sys/mman.h>
16#include "audio.h"
17#include "channels.h"
18#include "i18n.h"
19#include "player.h"
20#include "receiver.h"
21#include "status.h"
22#include "transfer.h"
23
24// --- cLiveSubtitle ---------------------------------------------------------
25
26class cLiveSubtitle : public cReceiver {
27protected:
28 virtual void Receive(const uchar *Data, int Length) override;
29public:
30 cLiveSubtitle(int SPid);
31 virtual ~cLiveSubtitle() override;
32 };
33
35{
36 AddPid(SPid);
37}
38
43
44void cLiveSubtitle::Receive(const uchar *Data, int Length)
45{
47 cDevice::PrimaryDevice()->PlayTs(Data, Length);
48}
49
50// --- cDeviceHook -----------------------------------------------------------
51
56
57bool cDeviceHook::DeviceProvidesTransponder(const cDevice *Device, const cChannel *Channel) const
58{
59 return true;
60}
61
62bool cDeviceHook::DeviceProvidesEIT(const cDevice *Device) const
63{
64 return true;
65}
66
67// --- cDevice ---------------------------------------------------------------
68
69// The minimum number of unknown PS1 packets to consider this a "pre 1.3.19 private stream":
70#define MIN_PRE_1_3_19_PRIVATESTREAM 10
71
73int cDevice::useDevice = 0;
75std::atomic<int> cDevice::currentChannel(1);
79
81:patPmtParser(true)
82{
84 dsyslog("new device number %d (card index %d)", numDevices + 1, CardIndex() + 1);
85
86 SetDescription("device %d receiver", numDevices + 1);
87
88 mute = false;
90
91 sectionHandler = NULL;
92 eitFilter = NULL;
93 patFilter = NULL;
94 sdtFilter = NULL;
95 nitFilter = NULL;
96
97 camSlot = NULL;
98
99 occupiedFrom = 0;
100 occupiedTimeout = 0;
102
103 player = NULL;
104 isPlayingVideo = false;
105 keepTracks = false; // used in ClrAvailableTracks()!
110 liveSubtitle = NULL;
113
114 for (int i = 0; i < MAXRECEIVERS; i++)
115 receiver[i] = NULL;
116
118 device[numDevices++] = this;
119 else
120 esyslog("ERROR: too many devices!");
121}
122
124{
125 Detach(player);
127 delete liveSubtitle;
129 if (this == primaryDevice)
130 primaryDevice = NULL;
131 Cancel(3);
132}
133
135{
136 for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) {
137 bool ready = true;
138 for (int i = 0; i < numDevices; i++) {
139 if (device[i] && !device[i]->Ready()) {
140 ready = false;
142 }
143 }
144 if (ready)
145 return true;
146 }
147 return false;
148}
149
151{
152 if (n < MAXDEVICES)
153 useDevice |= (1 << n);
154}
155
157{
158 if (n > 0) {
159 nextCardIndex += n;
161 esyslog("ERROR: nextCardIndex too big (%d)", nextCardIndex);
162 }
163 else if (n < 0)
164 esyslog("ERROR: invalid value in nextCardIndex(%d)", n);
165 return nextCardIndex;
166}
167
169{
170 for (int i = 0; i < numDevices; i++) {
171 if (device[i] == this)
172 return i;
173 }
174 return -1;
175}
176
178{
179 return "";
180}
181
183{
184 return "";
185}
186
188{
189 if (!On) {
190 cLiveSubtitle *ls;
191 {
193 ls = liveSubtitle; // deleted outside the mutex, see SetCurrentSubtitleTrack()
194 liveSubtitle = NULL;
196 }
197 delete ls;
198 }
199}
200
202{
203 n--;
204 if (0 <= n && n < numDevices && device[n]) {
205 isyslog("setting primary device to %d", n + 1);
206 if (primaryDevice)
212 Setup.PrimaryDVB = n + 1;
213 return true;
214 }
215 esyslog("ERROR: invalid primary device number: %d", n + 1);
216 return false;
217}
218
219bool cDevice::HasDecoder(void) const
220{
221 return false;
222}
223
225{
226 return NULL;
227}
228
230{
232 if (!d)
233 d = PrimaryDevice();
234 return d;
235}
236
238{
239 return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
240}
241
242static int GetClippedNumProvidedSystems(int AvailableBits, cDevice *Device)
243{
244 int MaxNumProvidedSystems = (1 << AvailableBits) - 1;
245 int NumProvidedSystems = Device->NumProvidedSystems();
246 if (NumProvidedSystems > MaxNumProvidedSystems) {
247 esyslog("ERROR: device %d supports %d modulation systems but cDevice::GetDevice() currently only supports %d delivery systems which should be fixed", Device->DeviceNumber() + 1, NumProvidedSystems, MaxNumProvidedSystems);
248 NumProvidedSystems = MaxNumProvidedSystems;
249 }
250 else if (NumProvidedSystems <= 0) {
251 esyslog("ERROR: device %d reported an invalid number (%d) of supported delivery systems - assuming 1", Device->DeviceNumber() + 1, NumProvidedSystems);
252 NumProvidedSystems = 1;
253 }
254 return NumProvidedSystems;
255}
256
257cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView, bool Query)
258{
259 // Collect the current priorities of all CAM slots that can decrypt the channel:
260 int NumCamSlots = CamSlots.Count();
261 int SlotPriority[NumCamSlots + 1]; // +1 to avoid a zero sized array in case there are no CAM slots
262 int NumUsableSlots = 0;
263 bool InternalCamNeeded = false;
264 if (Channel->Ca() >= CA_ENCRYPTED_MIN) {
266 SlotPriority[CamSlot->Index()] = MAXPRIORITY + 1; // assumes it can't be used
267 if (CamSlot->ModuleStatus() == msReady) {
268 if (CamSlot->ProvidesCa(Channel->Caids())) {
270 SlotPriority[CamSlot->Index()] = CamSlot->MtdActive() ? IDLEPRIORITY : CamSlot->Priority(); // we don't need to take the priority into account here for MTD CAM slots, because they can be used with several devices in parallel
271 NumUsableSlots++;
272 }
273 }
274 }
275 }
276 if (!NumUsableSlots)
277 InternalCamNeeded = true; // no CAM is able to decrypt this channel
278 }
279
280 bool NeedsDetachReceivers = false;
281 cDevice *d = NULL;
282 cCamSlot *s = NULL;
283
284 uint32_t Impact = 0xFFFFFFFF; // we're looking for a device with the least impact
285 for (int j = 0; j < NumCamSlots || !NumUsableSlots; j++) {
286 if (NumUsableSlots && SlotPriority[j] > MAXPRIORITY)
287 continue; // there is no CAM available in this slot
288 for (int i = 0; i < numDevices; i++) {
289 if (Channel->Ca() && Channel->Ca() <= CA_DVB_MAX && Channel->Ca() != device[i]->DeviceNumber() + 1)
290 continue; // a specific card was requested, but not this one
292 if (InternalCamNeeded && !HasInternalCam)
293 continue; // no CAM is able to decrypt this channel and the device uses vdr handled CAMs
294 if (NumUsableSlots && !HasInternalCam && !CamSlots.Get(j)->Assign(device[i], true))
295 continue; // CAM slot can't be used with this device
296 bool ndr = false;
297 bool TunedToTransponder = device[i]->IsTunedToTransponder(Channel);
298 if (TunedToTransponder || device[i]->ProvidesChannel(Channel, Priority, &ndr)) { // this device is basically able to do the job
299 bool OccupiedOtherTransponder = !TunedToTransponder && device[i]->Occupied();
300 if (OccupiedOtherTransponder)
301 ndr = true;
302 if (NumUsableSlots && !HasInternalCam) {
303 if (cCamSlot *csi = device[i]->CamSlot()) {
304 cCamSlot *csj = CamSlots.Get(j);
305 if ((csj->MtdActive() ? csi->MasterSlot() : csi) != csj)
306 ndr = true; // using a different CAM slot requires detaching receivers
307 }
308 }
309 // Put together an integer number that reflects the "impact" using
310 // this device would have on the overall system. Each condition is represented
311 // by one bit in the number (or several bits, if the condition is actually
312 // a numeric value). The sequence in which the conditions are listed corresponds
313 // to their individual severity, where the one listed first will make the most
314 // difference, because it results in the most significant bit of the result.
315 uint32_t imp = 0;
316 imp <<= 1; imp |= (LiveView && NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlots.Get(j)->MasterSlotNumber()) || ndr : 0; // prefer CAMs that are known to decrypt this channel for live viewing, if we don't need to detach existing receivers
317 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
318 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
319 imp <<= 1; imp |= device[i]->Receiving() || OccupiedOtherTransponder; // avoid devices that are receiving
320 imp <<= 5; imp |= GetClippedNumProvidedSystems(5, device[i]) - 1; // avoid cards which support multiple delivery systems
321 imp <<= 8; imp |= device[i]->Priority() - IDLEPRIORITY; // use the device with the lowest priority (- IDLEPRIORITY to assure that values -100..99 can be used)
322 imp <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
323 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)
324 imp <<= 1; imp |= ndr; // avoid devices if we need to detach existing receivers
325 imp <<= 1; imp |= (NumUsableSlots || InternalCamNeeded) ? 0 : device[i]->HasCi(); // avoid cards with Common Interface for FTA channels
326 imp <<= 1; imp |= device[i]->AvoidRecording(); // avoid SD full featured cards
327 imp <<= 1; imp |= (NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlots.Get(j)->MasterSlotNumber()) : 0; // prefer CAMs that are known to decrypt this channel
328 imp <<= 1; imp |= device[i]->IsPrimaryDevice(); // avoid the primary device
329 if (imp < Impact) {
330 // This device has less impact than any previous one, so we take it.
331 Impact = imp;
332 d = device[i];
333 NeedsDetachReceivers = ndr;
334 if (NumUsableSlots && !HasInternalCam)
335 s = CamSlots.Get(j);
336 }
337 //dsyslog("device %d provides channel %d prio %d ndr %d imp %.8X", device[i]->DeviceNumber() + 1, Channel->Number(), Priority, ndr, imp);
338 }
339 }
340 if (!NumUsableSlots)
341 break; // no CAM necessary, so just one loop over the devices
342 }
343 if (d) {
344 if (!Query && NeedsDetachReceivers)
346 if (s) {
347 // Some of the following statements could probably be combined, but let's keep them
348 // explicit so we can clearly see every single aspect of the decisions made here.
349 if (d->CamSlot()) {
350 if (s->MtdActive()) {
351 if (s == d->CamSlot()->MasterSlot()) {
352 // device d already has a proper CAM slot, so nothing to do here
353 }
354 else {
355 // device d has a CAM slot, but it's not the right one
356 if (!Query) {
357 d->CamSlot()->Assign(NULL);
358 s = s->MtdSpawn();
359 s->Assign(d);
360 }
361 }
362 }
363 else {
364 if (s->Device()) {
365 if (s->Device() != d) {
366 // CAM slot s is currently assigned to a different device than d
367 if (Priority > s->Priority()) {
368 if (!Query) {
369 d->CamSlot()->Assign(NULL);
370 s->Assign(d);
371 }
372 }
373 else {
374 d = NULL;
375 s = NULL;
376 }
377 }
378 else {
379 // device d already has a proper CAM slot, so nothing to do here
380 }
381 }
382 else {
383 if (s != d->CamSlot()) {
384 // device d has a CAM slot, but it's not the right one
385 if (!Query) {
386 d->CamSlot()->Assign(NULL);
387 s->Assign(d);
388 }
389 }
390 else {
391 // device d already has a proper CAM slot, so nothing to do here
392 }
393 }
394 }
395 }
396 else {
397 // device d has no CAM slot, ...
398 if (s->MtdActive()) {
399 // ... so we assign s with MTD support
400 if (!Query) {
401 s = s->MtdSpawn();
402 s->Assign(d);
403 }
404 }
405 else {
406 // CAM slot s has no MTD support ...
407 if (s->Device()) {
408 // ... but it is assigned to a different device, so we reassign it to d
409 if (Priority > s->Priority()) {
410 if (!Query) {
412 s->Assign(d);
413 }
414 }
415 else {
416 d = NULL;
417 s = NULL;
418 }
419 }
420 else {
421 // ... and is not assigned to any device, so we just assign it to d
422 if (!Query)
423 s->Assign(d);
424 }
425 }
426 }
427 }
428 else if (d->CamSlot() && !d->CamSlot()->IsDecrypting())
429 d->CamSlot()->Assign(NULL);
430 }
431 return d;
432}
433
435{
436 cDevice *Device = NULL;
437 for (int i = 0; i < cDevice::NumDevices(); i++) {
438 if (cDevice *d = cDevice::GetDevice(i)) {
439 if (d->IsTunedToTransponder(Channel))
440 return d; // if any device is tuned to the transponder, we're done
441 if (d->ProvidesTransponder(Channel)) {
442 if (d->MaySwitchTransponder(Channel))
443 return d; // this device may switch to the transponder without disturbing any receiver or live view
444 else if (!d->Occupied(Priority) && !d->IsBonded() && d->Priority(true) < LIVEPRIORITY) { // MaySwitchTransponder() implicitly calls Occupied()
445 // we select only devices with priority < LIVEPRIORITY, so device can be switched without impact on recordings or live viewing
446 if (d->Priority() < Priority && (!Device || d->Priority() < Device->Priority()))
447 Device = d; // use this one only if no other with less impact can be found
448 }
449 }
450 }
451 }
452 return Device;
453}
454
456{
457 if (cCamSlot *cs = camSlot) {
458 if (!cs->IsDecrypting() && !cs->IsActivating())
459 cs->Assign(NULL);
460 }
461}
462
464{
465 return false;
466}
467
473
475{
477 for (int i = 0; i < numDevices; i++) {
478 delete device[i];
479 device[i] = NULL;
480 }
481}
482
483uchar *cDevice::GrabImage(int &Size, bool Jpeg, int Quality, int SizeX, int SizeY)
484{
485 return NULL;
486}
487
488bool cDevice::GrabImageFile(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
489{
490 int result = 0;
491 int fd = open(FileName, O_WRONLY | O_CREAT | O_NOFOLLOW | O_TRUNC, DEFFILEMODE);
492 if (fd >= 0) {
493 int ImageSize;
494 uchar *Image = GrabImage(ImageSize, Jpeg, Quality, SizeX, SizeY);
495 if (Image) {
496 if (safe_write(fd, Image, ImageSize) == ImageSize)
497 isyslog("grabbed image to %s", FileName);
498 else {
499 LOG_ERROR_STR(FileName);
500 result |= 1;
501 }
502 free(Image);
503 }
504 else
505 result |= 1;
506 close(fd);
507 }
508 else {
509 LOG_ERROR_STR(FileName);
510 result |= 1;
511 }
512 return result == 0;
513}
514
516{
517 cSpuDecoder *spuDecoder = GetSpuDecoder();
518 if (spuDecoder) {
519 if (Setup.VideoFormat)
521 else {
522 switch (VideoDisplayFormat) {
523 case vdfPanAndScan:
525 break;
526 case vdfLetterBox:
528 break;
529 case vdfCenterCutOut:
531 break;
532 default: esyslog("ERROR: invalid value for VideoDisplayFormat '%d'", VideoDisplayFormat);
533 }
534 }
535 }
536}
537
538void cDevice::SetVideoFormat(bool VideoFormat16_9)
539{
540}
541
542void cDevice::GetVideoSize(int &Width, int &Height, double &VideoAspect)
543{
544 Width = 0;
545 Height = 0;
546 VideoAspect = 1.0;
547}
548
549void cDevice::GetOsdSize(int &Width, int &Height, double &PixelAspect)
550{
551 Width = 720;
552 Height = 480;
553 PixelAspect = 1.0;
554}
555
556//#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", DeviceNumber() + 1, 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); }
557#define PRINTPIDS(s)
558
559bool cDevice::HasPid(int Pid) const
560{
561 cMutexLock MutexLock(&mutexPids);
562 for (int i = 0; i < MAXPIDHANDLES; i++) {
563 if (pidHandles[i].pid == Pid)
564 return true;
565 }
566 return false;
567}
568
569bool cDevice::AddPid(int Pid, ePidType PidType, int StreamType)
570{
571 // cCamSlot::SetPid() and DetachAll() are called after releasing mutexPids:
572 // the locks they take are held while calling AddPid() elsewhere (the CAM
573 // slot's and cCaPidReceiver's mutexes when adding ECM/EMM PIDs, mutexReceiver
574 // in AttachReceiver()):
575 cCamSlot *NotifySlot = NULL;
576 bool Failed = false;
577 {
578 cMutexLock MutexLock(&mutexPids);
579 if (Pid || PidType == ptPcr) {
580 int n = -1;
581 int a = -1;
582 if (PidType != ptPcr) { // PPID always has to be explicit
583 for (int i = 0; i < MAXPIDHANDLES; i++) {
584 if (i != ptPcr) {
585 if (pidHandles[i].pid == Pid)
586 n = i;
587 else if (a < 0 && i >= ptOther && !pidHandles[i].used)
588 a = i;
589 }
590 }
591 }
592 if (n >= 0) {
593 // The Pid is already in use
594 if (++pidHandles[n].used == 2 && n <= ptTeletext) {
595 // It's a special PID that may have to be switched into "tap" mode
596 PRINTPIDS("A");
597 if (!SetPid(&pidHandles[n], n, true)) {
598 esyslog("ERROR: can't set PID %d on device %d", Pid, DeviceNumber() + 1);
599 Failed = true;
600 }
601 else
602 NotifySlot = camSlot;
603 }
604 PRINTPIDS("a");
605 }
606 else {
607 if (PidType < ptOther) {
608 // The Pid is not yet in use and it is a special one
609 n = PidType;
610 }
611 else if (a >= 0) {
612 // The Pid is not yet in use and we have a free slot
613 n = a;
614 }
615 else {
616 esyslog("ERROR: no free slot for PID %d on device %d", Pid, DeviceNumber() + 1);
617 return false;
618 }
619 pidHandles[n].pid = Pid;
620 pidHandles[n].streamType = StreamType;
621 pidHandles[n].used = 1;
622 PRINTPIDS("C");
623 if (!SetPid(&pidHandles[n], n, true)) {
624 esyslog("ERROR: can't set PID %d on device %d", Pid, DeviceNumber() + 1);
625 Failed = true;
626 }
627 else
628 NotifySlot = camSlot;
629 }
630 }
631 }
632 if (Failed) {
633 if (PidType <= ptTeletext)
634 DetachAll(Pid);
635 DelPid(Pid, PidType);
636 return false;
637 }
638 if (NotifySlot)
639 NotifySlot->SetPid(Pid, true);
640 return true;
641}
642
643void cDevice::DelPid(int Pid, ePidType PidType)
644{
645 cCamSlot *NotifySlot = NULL; // notified after releasing mutexPids, see AddPid()
646 {
647 cMutexLock MutexLock(&mutexPids);
648 if (Pid || PidType == ptPcr) {
649 int n = -1;
650 if (PidType == ptPcr)
651 n = PidType; // PPID always has to be explicit
652 else {
653 for (int i = 0; i < MAXPIDHANDLES; i++) {
654 if (pidHandles[i].pid == Pid) {
655 n = i;
656 break;
657 }
658 }
659 }
660 if (n >= 0 && pidHandles[n].used) {
661 PRINTPIDS("D");
662 if (--pidHandles[n].used < 2) {
663 SetPid(&pidHandles[n], n, false);
664 if (pidHandles[n].used == 0) {
665 pidHandles[n].handle = -1;
666 pidHandles[n].pid = 0;
667 NotifySlot = camSlot;
668 }
669 }
670 PRINTPIDS("E");
671 }
672 }
673 }
674 if (NotifySlot)
675 NotifySlot->SetPid(Pid, false);
676}
677
678bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
679{
680 return false;
681}
682
684{
685 cMutexLock MutexLock(&mutexPids);
686 for (int i = ptAudio; i < ptOther; i++) {
687 if (pidHandles[i].pid)
688 DelPid(pidHandles[i].pid, ePidType(i));
689 }
690}
691
702
704{
705 if (sectionHandler) {
706 delete sectionHandler; // automatically detaches filters
707 delete nitFilter;
708 delete sdtFilter;
709 delete patFilter;
710 delete eitFilter;
711 nitFilter = NULL;
712 sdtFilter = NULL;
713 patFilter = NULL;
714 eitFilter = NULL;
715 sectionHandler = NULL;
716 }
717}
718
719int cDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
720{
721 return -1;
722}
723
724int cDevice::ReadFilter(int Handle, void *Buffer, size_t Length)
725{
726 return safe_read(Handle, Buffer, Length);
727}
728
729void cDevice::CloseFilter(int Handle)
730{
731 close(Handle);
732}
733
735{
736 if (sectionHandler)
737 sectionHandler->Attach(Filter);
738}
739
741{
742 if (sectionHandler)
743 sectionHandler->Detach(Filter);
744}
745
746bool cDevice::ProvidesSource(int Source) const
747{
748 return false;
749}
750
752{
753 cDeviceHook *Hook = deviceHooks.First();
754 while (Hook) {
755 if (!Hook->DeviceProvidesTransponder(this, Channel))
756 return false;
757 Hook = deviceHooks.Next(Hook);
758 }
759 return true;
760}
761
763{
764 cDeviceHook *Hook = deviceHooks.First();
765 while (Hook) {
766 if (!Hook->DeviceProvidesEIT(this))
767 return false;
768 Hook = deviceHooks.Next(Hook);
769 }
770 return true;
771}
772
773bool cDevice::ProvidesTransponder(const cChannel *Channel) const
774{
775 return false;
776}
777
779{
780 for (int i = 0; i < numDevices; i++) {
781 if (device[i] && device[i] != this && device[i]->ProvidesTransponder(Channel))
782 return false;
783 }
784 return true;
785}
786
787bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
788{
789 return false;
790}
791
792bool cDevice::ProvidesEIT(void) const
793{
794 return false;
795}
796
798{
799 return 0;
800}
801
803{
804 return NULL;
805}
806
807bool cDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
808{
809 return false;
810}
811
813{
814 return -1;
815}
816
818{
819 return -1;
820}
821
823{
824 return NULL;
825}
826
827bool cDevice::IsTunedToTransponder(const cChannel *Channel) const
828{
829 return false;
830}
831
832bool cDevice::MaySwitchTransponder(const cChannel *Channel) const
833{
835}
836
838{
839}
840
842{
843 if (!Occupied() && !Receiving() && !(pidHandles[ptAudio].pid || pidHandles[ptVideo].pid || pidHandles[ptDolby].pid))
844 SetPowerSaveMode(true);
845}
846
847bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView)
848{
849 if (LiveView) {
850 isyslog("switching to channel %d %s (%s)", Channel->Number(), *Channel->GetChannelID().ToString(), Channel->Name());
851 cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
852 // and, if decrypted, this removes the now superfluous PIDs from the CAM, too
853 }
854 for (int i = 3; i--;) {
855 switch (SetChannel(Channel, LiveView)) {
856 case scrOk: return true;
857 case scrNotAvailable: Skins.QueueMessage(mtInfo, tr("Channel not available!"));
858 return false;
859 case scrNoTransfer: Skins.QueueMessage(mtError, tr("Can't start Transfer Mode!"));
860 return false;
861 case scrFailed: break; // loop will retry
862 default: esyslog("ERROR: invalid return value from SetChannel");
863 }
864 esyslog("retrying");
865 }
866 return false;
867}
868
869bool cDevice::SwitchChannel(int Direction)
870{
871 bool result = false;
872 Direction = sgn(Direction);
873 if (Direction) {
874 cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
875 // and, if decrypted, this removes the now superfluous PIDs from the CAM, too
876 int n = CurrentChannel() + Direction;
877 int first = n;
879 const cChannel *Channel;
880 while ((Channel = Channels->GetByNumber(n, Direction)) != NULL) {
881 // try only channels which are currently available
882 if (GetDevice(Channel, LIVEPRIORITY, true, true))
883 break;
884 n = Channel->Number() + Direction;
885 }
886 if (Channel) {
887 int d = n - first;
888 if (abs(d) == 1)
889 dsyslog("skipped channel %d", first);
890 else if (d)
891 dsyslog("skipped channels %d..%d", first, n - sgn(d));
892 if (PrimaryDevice()->SwitchChannel(Channel, true))
893 result = true;
894 }
895 else if (n != first)
896 Skins.QueueMessage(mtError, tr("Channel not available!"));
897 }
898 return result;
899}
900
901eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
902{
903 cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme()
904 cStatus::MsgChannelSwitch(this, 0, LiveView);
905
906 if (LiveView) {
907 if (IsPrimaryDevice() && !Replaying() && !Transferring()) { // this is only for FF DVB cards!
909 if (const cChannel *ch = Channels->GetByNumber(currentChannel)) {
910 if (patFilter)
911 patFilter->Release(ch->Sid());
912 }
913 }
914 StopReplay();
915 cLiveSubtitle *ls;
916 {
918 ls = liveSubtitle; // deleted outside the mutex, see SetCurrentSubtitleTrack()
919 liveSubtitle = NULL;
921 }
922 delete ls;
923 }
924
925 cDevice *Device = (LiveView && IsPrimaryDevice(false)) ? GetDevice(Channel, LIVEPRIORITY, true) : this;
926
927 bool NeedsTransferMode = LiveView && Device != PrimaryDevice();
928 // If the CAM slot wants the TS data, we need to switch to Transfer Mode:
929 cCamSlot *PrimaryCamSlot = CamSlot();
930 if (!NeedsTransferMode && LiveView && IsPrimaryDevice() && PrimaryCamSlot && PrimaryCamSlot->WantsTsData())
931 NeedsTransferMode = true;
932
933 eSetChannelResult Result = scrOk;
934
935 // If this DVB card can't receive this channel, let's see if we can
936 // use the card that actually can receive it and transfer data from there:
937
938 if (NeedsTransferMode) {
939 if (Device && PrimaryDevice()->CanReplay()) {
940 if (Device->SetChannel(Channel, false) != scrOk) // calling SetChannel() directly, not SwitchChannel()!
941 Result = scrNoTransfer;
942 }
943 else
944 Result = scrNotAvailable;
945 }
946 else {
947 // Stop section handling:
948 if (sectionHandler) {
951 }
952 // Tell the camSlot about the channel switch and add all PIDs of this
953 // channel to it, for possible later decryption:
954 if (cCamSlot *cs = camSlot)
955 cs->AddChannel(Channel);
956 SetPowerSaveMode(false);
957 if (SetChannelDevice(Channel, LiveView)) {
958 // Start section handling:
959 if (sectionHandler) {
960 sectionHandler->SetChannel(Channel);
962 }
963 // Start decrypting any PIDs that might have been set in SetChannelDevice():
964 if (cCamSlot *cs = camSlot)
965 cs->StartDecrypting();
966 }
967 else
968 Result = scrFailed;
969 }
970
971 if (Result == scrOk) {
972 if (LiveView) {
973 if (IsPrimaryDevice(false))
974 currentChannel = Channel->Number();
975 if (IsPrimaryDevice()) {
976 if (patFilter) // this is only for FF DVB cards!
977 patFilter->Request(Channel->Sid());
978 // Set the available audio tracks:
980 for (int i = 0; i < MAXAPIDS; i++)
981 SetAvailableTrack(ttAudio, i, Channel->Apid(i), Channel->Alang(i));
982 for (int i = 0; i < MAXDPIDS; i++)
983 SetAvailableTrack(ttDolby, i, Channel->Dpid(i), Channel->Dlang(i));
984 for (int i = 0; i < MAXSPIDS; i++)
985 SetAvailableTrack(ttSubtitle, i, Channel->Spid(i), Channel->Slang(i));
986 if (!NeedsTransferMode)
987 EnsureAudioTrack(true);
989 }
990 }
991 // Launch the transfer control only after the channel switch is complete.
992 // Launch() makes the control visible to the main loop, which attaches it and
993 // starts feeding TS data into the primary device - if that happens while this
994 // function is still setting up the track state above, the two threads race
995 // on availableTracks et al. (SwitchChannel() may run in the SVDRP thread):
996 if (NeedsTransferMode)
997 cControl::Launch(new cTransferControl(Device, Channel));
998 cStatus::MsgChannelSwitch(this, Channel->Number(), LiveView); // only report status if channel switch successful
999 }
1000
1001 return Result;
1002}
1003
1005{
1008 if (const cChannel *Channel = Channels->GetByNumber(CurrentChannel())) {
1009 SetPowerSaveMode(false);
1010 SetChannelDevice(Channel, false); // this implicitly starts Transfer Mode
1011 }
1012 }
1013}
1014
1016{
1018 return 0;
1019 int Seconds = occupiedTimeout - time(NULL);
1020 return Seconds > 0 ? Seconds : 0;
1021}
1022
1023void cDevice::SetOccupied(int Seconds, int Priority, time_t From)
1024{
1025 if (Seconds < 0)
1026 return;
1027 if (From == 0)
1028 From = time(NULL);
1029 if (From == occupiedFrom)
1031 else {
1033 occupiedFrom = From;
1034 }
1035 occupiedTimeout = From + min(Seconds, MAXOCCUPIEDTIMEOUT);
1036}
1037
1038bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
1039{
1040 return false;
1041}
1042
1043bool cDevice::HasLock(int TimeoutMs) const
1044{
1045 return true;
1046}
1047
1049{
1050 cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme()
1052}
1053
1055{
1056 return 0;
1057}
1058
1060{
1061}
1062
1064{
1065}
1066
1068{
1069}
1070
1074
1078
1080{
1081 int OldVolume = volume;
1082 mute = !mute;
1083 //XXX why is it necessary to use different sequences???
1084 if (mute) {
1085 SetVolume(0, true);
1086 Audios.MuteAudio(mute); // Mute external audio after analog audio
1087 }
1088 else {
1089 Audios.MuteAudio(mute); // Enable external audio before analog audio
1090 SetVolume(OldVolume, true);
1091 }
1092 volume = OldVolume;
1093 return mute;
1094}
1095
1097{
1098 int c = GetAudioChannelDevice();
1099 return (0 <= c && c <= 2) ? c : 0;
1100}
1101
1102void cDevice::SetAudioChannel(int AudioChannel)
1103{
1104 if (0 <= AudioChannel && AudioChannel <= 2)
1105 SetAudioChannelDevice(AudioChannel);
1106}
1107
1108void cDevice::SetVolume(int Volume, bool Absolute)
1109{
1110 int OldVolume = volume;
1111 double VolumeDelta = double(MAXVOLUME) / Setup.VolumeSteps;
1112 double VolumeLinearize = (Setup.VolumeLinearize >= 0) ? (Setup.VolumeLinearize / 10.0 + 1.0) : (1.0 / ((-Setup.VolumeLinearize / 10.0) + 1.0));
1113 volume = constrain(int(floor((Absolute ? Volume : volume + Volume) / VolumeDelta + 0.5) * VolumeDelta), 0, MAXVOLUME);
1114 SetVolumeDevice(MAXVOLUME - int(pow(1.0 - pow(double(volume) / MAXVOLUME, VolumeLinearize), 1.0 / VolumeLinearize) * MAXVOLUME));
1115 Absolute |= mute;
1116 cStatus::MsgSetVolume(Absolute ? volume : volume - OldVolume, Absolute);
1117 if (volume > 0) {
1118 mute = false;
1120 }
1121}
1122
1123void cDevice::ClrAvailableTracks(bool DescriptionsOnly, bool IdsOnly)
1124{
1125 if (keepTracks)
1126 return;
1128 if (DescriptionsOnly) {
1129 for (int i = ttNone; i < ttMaxTrackTypes; i++)
1131 }
1132 else {
1133 if (IdsOnly) {
1134 for (int i = ttNone; i < ttMaxTrackTypes; i++)
1135 availableTracks[i].id = 0;
1136 }
1137 else
1138 memset(availableTracks, 0, sizeof(availableTracks));
1140 SetAudioChannel(0); // fall back to stereo
1144 }
1145}
1146
1147bool cDevice::SetAvailableTrack(eTrackType Type, int Index, uint16_t Id, const char *Language, const char *Description)
1148{
1150 eTrackType t = eTrackType(Type + Index);
1151 if (Type == ttAudio && IS_AUDIO_TRACK(t) ||
1152 Type == ttDolby && IS_DOLBY_TRACK(t) ||
1153 Type == ttSubtitle && IS_SUBTITLE_TRACK(t)) {
1154 if (Language)
1155 strn0cpy(availableTracks[t].language, Language, sizeof(availableTracks[t].language));
1156 if (Description)
1158 if (Id) {
1159 availableTracks[t].id = Id; // setting 'id' last to avoid the need for extensive locking
1160 if (Type == ttAudio || Type == ttDolby) {
1161 int numAudioTracks = NumAudioTracks();
1162 if (!availableTracks[currentAudioTrack].id && numAudioTracks && currentAudioTrackMissingCount++ > numAudioTracks * 10)
1164 else if (t == currentAudioTrack)
1166 }
1169 }
1170 return true;
1171 }
1172 else
1173 esyslog("ERROR: SetAvailableTrack called with invalid Type/Index (%d/%d)", Type, Index);
1174 return false;
1175}
1176
1178{
1179 return (ttNone < Type && Type < ttMaxTrackTypes) ? &availableTracks[Type] : NULL;
1180}
1181
1183{
1185 if (const tTrackId *Track = GetTrack(Type)) {
1186 TrackId = *Track;
1187 return true;
1188 }
1189 return false;
1190}
1191
1192int cDevice::NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const
1193{
1194 int n = 0;
1195 for (int i = FirstTrack; i <= LastTrack; i++) {
1196 if (availableTracks[i].id)
1197 n++;
1198 }
1199 return n;
1200}
1201
1203{
1205}
1206
1208{
1210}
1211
1213{
1214 if (ttNone < Type && Type <= ttDolbyLast) {
1216 if (IS_DOLBY_TRACK(Type))
1218 currentAudioTrack = Type;
1219 if (cPlayer *p = player)
1220 p->SetAudioTrack(currentAudioTrack, GetTrack(currentAudioTrack));
1221 else
1223 if (IS_AUDIO_TRACK(Type))
1224 SetDigitalAudioDevice(false);
1225 return true;
1226 }
1227 return false;
1228}
1229
1231{
1232 if (Type == ttNone || IS_SUBTITLE_TRACK(Type)) {
1233 currentSubtitleTrack = Type;
1235 cLiveSubtitle *ls;
1236 {
1237 // mutexCurrentSubtitleTrack guards dvbSubtitleConverter and liveSubtitle
1238 // against the play/receiver thread and other control paths. liveSubtitle
1239 // is only unlinked under the mutex and deleted after releasing it:
1240 // ~cLiveSubtitle() detaches the receiver, which takes mutexReceiver - and
1241 // the receiver thread holds mutexReceiver while it delivers data through
1242 // cLiveSubtitle::Receive() -> PlayTs() -> PlayTsSubtitle(), where it
1243 // waits for mutexCurrentSubtitleTrack. Deleting under the mutex would
1244 // deadlock the two:
1248 if (Type == ttNone) {
1251 else
1253 }
1254 else if (Replaying() && !Transferring() && Setup.DisplaySubtitles == SUBTITLES_REWIND && Manual)
1256 }
1257 ls = liveSubtitle;
1258 liveSubtitle = NULL;
1259 }
1260 delete ls;
1261 if (cPlayer *p = player)
1262 p->SetSubtitleTrack(currentSubtitleTrack, GetTrack(currentSubtitleTrack));
1263 else
1266 const tTrackId *TrackId = GetTrack(currentSubtitleTrack);
1267 if (TrackId && TrackId->id) {
1268 liveSubtitle = new cLiveSubtitle(TrackId->id);
1270 }
1271 }
1272 return true;
1273 }
1274 return false;
1275}
1276
1283
1285{
1286 if (keepTracks)
1287 return;
1288 if (Force || !availableTracks[currentAudioTrack].id) {
1289 eTrackType PreferredTrack = ttAudioFirst;
1290 int PreferredAudioChannel = 0;
1291 int LanguagePreference = -1;
1292 int StartCheck = Setup.CurrentDolby ? ttDolbyFirst : ttAudioFirst;
1293 int EndCheck = ttDolbyLast;
1294 for (int i = StartCheck; i <= EndCheck; i++) {
1295 const tTrackId *TrackId = GetTrack(eTrackType(i));
1296 int pos = 0;
1297 if (TrackId && TrackId->id && I18nIsPreferredLanguage(Setup.AudioLanguages, TrackId->language, LanguagePreference, &pos)) {
1298 PreferredTrack = eTrackType(i);
1299 PreferredAudioChannel = pos;
1300 }
1301 if (Setup.CurrentDolby && i == ttDolbyLast) {
1302 i = ttAudioFirst - 1;
1303 EndCheck = ttAudioLast;
1304 }
1305 }
1306 // Make sure we're set to an available audio track:
1307 const tTrackId *Track = GetTrack(GetCurrentAudioTrack());
1308 if (Force || !Track || !Track->id || PreferredTrack != GetCurrentAudioTrack()) {
1309 if (!Force) // only log this for automatic changes
1310 dsyslog("setting audio track to %d (%d)", PreferredTrack, PreferredAudioChannel);
1311 SetCurrentAudioTrack(PreferredTrack);
1312 SetAudioChannel(PreferredAudioChannel);
1313 }
1314 }
1315}
1316
1318{
1319 if (keepTracks)
1320 return;
1322 eTrackType PreferredTrack = ttNone;
1323 int LanguagePreference = INT_MAX; // higher than the maximum possible value
1324 for (int i = ttSubtitleFirst; i <= ttSubtitleLast; i++) {
1325 const tTrackId *TrackId = GetTrack(eTrackType(i));
1326 if (TrackId && TrackId->id && (I18nIsPreferredLanguage(Setup.SubtitleLanguages, TrackId->language, LanguagePreference) ||
1327 (i == ttSubtitleFirst + 8 && !*TrackId->language && LanguagePreference == INT_MAX))) // compatibility mode for old subtitles plugin
1328 PreferredTrack = eTrackType(i);
1329 }
1330 // Make sure we're set to an available subtitle track:
1331 const tTrackId *Track = GetTrack(GetCurrentSubtitleTrack());
1332 if (!Track || !Track->id || PreferredTrack != GetCurrentSubtitleTrack())
1333 SetCurrentSubtitleTrack(PreferredTrack);
1334 }
1335 else
1337}
1338
1339bool cDevice::CanReplay(void) const
1340{
1341 return HasDecoder();
1342}
1343
1345{
1346 return false;
1347}
1348
1349int64_t cDevice::GetSTC(void)
1350{
1351 return -1;
1352}
1353
1354void cDevice::TrickSpeed(int Speed, bool Forward)
1355{
1356}
1357
1365
1367{
1372}
1373
1375{
1376 Audios.MuteAudio(true);
1380}
1381
1383{
1384 Audios.MuteAudio(true);
1385}
1386
1387void cDevice::StillPicture(const uchar *Data, int Length)
1388{
1389 if (Data[0] == 0x47) {
1390 // TS data
1391 cTsToPes TsToPes;
1392 uchar *buf = NULL;
1393 int Size = 0;
1394 while (Length >= TS_SIZE) {
1395 int Pid = TsPid(Data);
1396 if (Pid == PATPID)
1398 else if (patPmtParser.IsPmtPid(Pid))
1400 else if (Pid == patPmtParser.Vpid()) {
1401 if (TsPayloadStart(Data)) {
1402 int l;
1403 while (const uchar *p = TsToPes.GetPes(l)) {
1404 int Offset = Size;
1405 int NewSize = Size + l;
1406 if (uchar *NewBuffer = (uchar *)realloc(buf, NewSize)) {
1407 Size = NewSize;
1408 buf = NewBuffer;
1409 memcpy(buf + Offset, p, l);
1410 }
1411 else {
1412 LOG_ERROR_STR("out of memory");
1413 free(buf);
1414 return;
1415 }
1416 }
1417 TsToPes.Reset();
1418 }
1419 TsToPes.PutTs(Data, TS_SIZE);
1420 }
1421 Length -= TS_SIZE;
1422 Data += TS_SIZE;
1423 }
1424 int l;
1425 while (const uchar *p = TsToPes.GetPes(l)) {
1426 int Offset = Size;
1427 int NewSize = Size + l;
1428 if (uchar *NewBuffer = (uchar *)realloc(buf, NewSize)) {
1429 Size = NewSize;
1430 buf = NewBuffer;
1431 memcpy(buf + Offset, p, l);
1432 }
1433 else {
1434 esyslog("ERROR: out of memory");
1435 free(buf);
1436 return;
1437 }
1438 }
1439 if (buf) {
1440 StillPicture(buf, Size);
1441 free(buf);
1442 }
1443 }
1444}
1445
1446bool cDevice::Replaying(void) const
1447{
1448 return player != NULL;
1449}
1450
1452{
1453 return cTransferControl::ReceiverDevice() != NULL;
1454}
1455
1457{
1458 if (CanReplay()) {
1459 if (player)
1460 Detach(player);
1461 cLiveSubtitle *ls;
1462 {
1464 ls = liveSubtitle; // deleted outside the mutex, see SetCurrentSubtitleTrack()
1465 liveSubtitle = NULL;
1467 }
1468 delete ls;
1470 player = Player;
1471 if (!Transferring())
1472 ClrAvailableTracks(false, true);
1473 SetPlayMode(Player->playMode);
1474 Player->device = this;
1475 Player->Activate(true);
1476 return true;
1477 }
1478 return false;
1479}
1480
1482{
1483 if (Player && player == Player) {
1484 cPlayer *p = player;
1485 player = NULL; // avoids recursive calls to Detach()
1486 p->Activate(false);
1487 p->device = NULL;
1492 PlayTs(NULL, 0);
1495 isPlayingVideo = false;
1496 }
1497}
1498
1500{
1501 if (player) {
1502 Detach(player);
1503 if (IsPrimaryDevice())
1505 }
1506}
1507
1508bool cDevice::Poll(cPoller &Poller, int TimeoutMs)
1509{
1510 return false;
1511}
1512
1513bool cDevice::Flush(int TimeoutMs)
1514{
1515 return false;
1516}
1517
1519{
1520 // At the end of a stream no further TS packet comes that could complete the
1521 // PES packets the converters still hold, so they are played out here. The
1522 // cDevice implementations are called explicitly, because a device that
1523 // overrides them buffers on its own and plays that data out in DrainDevice():
1524 if (cDevice::PlayTsVideo(NULL, 0) <= 0 || cDevice::PlayTsAudio(NULL, 0) <= 0 || cDevice::PlayTsSubtitle(NULL, 0) <= 0)
1525 return false; // backpressure, the player will call again
1526 return DrainDevice();
1527}
1528
1530{
1531 return Flush(10);
1532}
1533
1534int cDevice::PlayVideo(const uchar *Data, int Length)
1535{
1536 return -1;
1537}
1538
1539int cDevice::PlayAudio(const uchar *Data, int Length, uchar Id)
1540{
1541 return -1;
1542}
1543
1554
1555int cDevice::PlayPesPacket(const uchar *Data, int Length, bool VideoOnly)
1556{
1557 bool FirstLoop = true;
1558 uchar c = Data[3];
1559 const uchar *Start = Data;
1560 const uchar *End = Start + Length;
1561 while (Start < End) {
1562 int d = End - Start;
1563 int w = d;
1564 switch (c) {
1565 case 0xBE: // padding stream, needed for MPEG1
1566 case 0xE0 ... 0xEF: // video
1567 isPlayingVideo = true;
1568 w = PlayVideo(Start, d);
1569 break;
1570 case 0xC0 ... 0xDF: // audio
1571 SetAvailableTrack(ttAudio, c - 0xC0, c);
1572 if ((!VideoOnly || HasIBPTrickSpeed()) && c == availableTracks[currentAudioTrack].id) {
1573 w = PlayAudio(Start, d, c);
1574 if (FirstLoop)
1575 Audios.PlayAudio(Data, Length, c);
1576 }
1577 break;
1578 case 0xBD: { // private stream 1
1579 int PayloadOffset = Data[8] + 9;
1580
1581 // Compatibility mode for old subtitles plugin:
1582 if ((Data[7] & 0x01) && (Data[PayloadOffset - 3] & 0x81) == 0x01 && Data[PayloadOffset - 2] == 0x81)
1583 PayloadOffset--;
1584
1585 uchar SubStreamId = Data[PayloadOffset];
1586 uchar SubStreamType = SubStreamId & 0xF0;
1587 uchar SubStreamIndex = SubStreamId & 0x1F;
1588
1589 // Compatibility mode for old VDR recordings, where 0xBD was only AC3:
1590pre_1_3_19_PrivateStreamDetected:
1592 SubStreamId = c;
1593 SubStreamType = 0x80;
1594 SubStreamIndex = 0;
1595 }
1596 else if (pre_1_3_19_PrivateStream)
1597 pre_1_3_19_PrivateStream--; // every known PS1 packet counts down towards 0 to recover from glitches...
1598 switch (SubStreamType) {
1599 case 0x20: // SPU
1600 case 0x30: // SPU
1601 SetAvailableTrack(ttSubtitle, SubStreamIndex, SubStreamId);
1602 if ((!VideoOnly || HasIBPTrickSpeed()) && currentSubtitleTrack != ttNone && SubStreamId == availableTracks[currentSubtitleTrack].id)
1603 w = PlaySubtitle(Start, d);
1604 break;
1605 case 0x80: // AC3 & DTS
1606 SetAvailableTrack(ttDolby, SubStreamIndex, SubStreamId);
1607 if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) {
1608 w = PlayAudio(Start, d, SubStreamId);
1609 if (FirstLoop)
1610 Audios.PlayAudio(Data, Length, SubStreamId);
1611 }
1612 break;
1613 case 0xA0: // LPCM
1614 SetAvailableTrack(ttAudio, SubStreamIndex, SubStreamId);
1615 if ((!VideoOnly || HasIBPTrickSpeed()) && SubStreamId == availableTracks[currentAudioTrack].id) {
1616 w = PlayAudio(Start, d, SubStreamId);
1617 if (FirstLoop)
1618 Audios.PlayAudio(Data, Length, SubStreamId);
1619 }
1620 break;
1621 default:
1622 // Compatibility mode for old VDR recordings, where 0xBD was only AC3:
1624 dsyslog("unknown PS1 packet, substream id = %02X (counter is at %d)", SubStreamId, pre_1_3_19_PrivateStream);
1625 pre_1_3_19_PrivateStream += 2; // ...and every unknown PS1 packet counts up (the very first one counts twice, but that's ok)
1627 dsyslog("switching to pre 1.3.19 Dolby Digital compatibility mode - substream id = %02X", SubStreamId);
1630 goto pre_1_3_19_PrivateStreamDetected;
1631 }
1632 }
1633 }
1634 }
1635 break;
1636 default:
1637 ;//esyslog("ERROR: unexpected packet id %02X", c);
1638 }
1639 if (w > 0)
1640 Start += w;
1641 else {
1642 if (Start != Data)
1643 esyslog("ERROR: incomplete PES packet write!");
1644 return Start == Data ? w : Start - Data;
1645 }
1646 FirstLoop = false;
1647 }
1648 return Length;
1649}
1650
1651int cDevice::PlayPes(const uchar *Data, int Length, bool VideoOnly)
1652{
1653 if (!Data) {
1657 return 0;
1658 }
1659 int i = 0;
1660 while (i <= Length - 6) {
1661 if (Data[i] == 0x00 && Data[i + 1] == 0x00 && Data[i + 2] == 0x01) {
1662 int l = PesLength(Data + i);
1663 if (i + l > Length) {
1664 esyslog("ERROR: incomplete PES packet!");
1665 return Length;
1666 }
1667 int w = PlayPesPacket(Data + i, l, VideoOnly);
1668 if (w > 0)
1669 i += l;
1670 else
1671 return i == 0 ? w : i;
1672 }
1673 else
1674 i++;
1675 }
1676 if (i < Length)
1677 esyslog("ERROR: leftover PES data!");
1678 return Length;
1679}
1680
1681int cDevice::PlayTsVideo(const uchar *Data, int Length)
1682{
1683 // Video PES has no explicit length, so we can only determine the end of
1684 // a PES packet when the next TS packet that starts a payload comes in
1685 // (Data == NULL means that no such packet will come any more):
1686 if (!Data || TsPayloadStart(Data)) {
1687 int l;
1688 while (const uchar *p = tsToPesVideo.GetPes(l)) {
1689 int w = PlayVideo(p, l);
1690 if (w <= 0) {
1692 return w;
1693 }
1694 }
1696 }
1697 if (!Data)
1698 return 1; // nothing taken, but the converter is empty now
1699 tsToPesVideo.PutTs(Data, Length);
1700 return Length;
1701}
1702
1703int cDevice::PlayTsAudio(const uchar *Data, int Length)
1704{
1705 // Audio PES always has an explicit length and consists of single packets:
1706 int l;
1707 if (const uchar *p = tsToPesAudio.GetPes(l)) {
1708 int w = PlayAudio(p, l, p[3]);
1709 if (w <= 0) {
1711 return w;
1712 }
1714 }
1715 if (!Data)
1716 return 1; // nothing taken, but the converter is empty now
1717 tsToPesAudio.PutTs(Data, Length);
1718 return Length;
1719}
1720
1721int cDevice::PlayTsSubtitle(const uchar *Data, int Length)
1722{
1723 // The converter is created here in the play/receiver thread but reset and
1724 // deleted from control paths in other threads; mutexCurrentSubtitleTrack
1725 // (which already guarded two of the delete sites) now guards all access:
1727 if (!Data && !dvbSubtitleConverter)
1728 return 1; // no subtitles have been played, so there is nothing to play out
1729 if (!dvbSubtitleConverter) {
1731 if (Replaying() && !Transferring())
1733 }
1734 if (Data)
1735 tsToPesSubtitle.PutTs(Data, Length);
1736 int l;
1737 if (const uchar *p = tsToPesSubtitle.GetPes(l)) {
1740 }
1741 return Data ? Length : 1; // nothing taken if Data is NULL, but the converter is empty now
1742}
1743
1744int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly)
1745{
1746 int Played = 0;
1747 if (!Data) {
1751 }
1752 else if (Length < TS_SIZE) {
1753 esyslog("ERROR: skipped %d bytes of TS fragment", Length);
1754 return Length;
1755 }
1756 else {
1757 while (Length >= TS_SIZE) {
1758 if (int Skipped = TS_SYNC(Data, Length))
1759 return Played + Skipped;
1760 int Pid = TsPid(Data);
1761 if (TsHasPayload(Data)) { // silently ignore TS packets w/o payload
1762 int PayloadOffset = TsPayloadOffset(Data);
1763 if (PayloadOffset < TS_SIZE) {
1764 if (Pid == PATPID)
1766 else if (patPmtParser.IsPmtPid(Pid))
1768 else if (Pid == patPmtParser.Vpid()) {
1769 isPlayingVideo = true;
1770 int w = PlayTsVideo(Data, TS_SIZE);
1771 if (w < 0)
1772 return Played ? Played : w;
1773 if (w == 0)
1774 break;
1775 }
1776 else if (Pid == availableTracks[currentAudioTrack].id) {
1777 if (!VideoOnly || HasIBPTrickSpeed()) {
1778 int w = PlayTsAudio(Data, TS_SIZE);
1779 if (w < 0)
1780 return Played ? Played : w;
1781 if (w == 0)
1782 break;
1783 Audios.PlayTsAudio(Data, TS_SIZE);
1784 }
1785 }
1786 else if (Pid == availableTracks[currentSubtitleTrack].id) {
1787 if (!VideoOnly || HasIBPTrickSpeed())
1788 PlayTsSubtitle(Data, TS_SIZE);
1789 }
1790 }
1791 }
1792 else if (Pid == patPmtParser.Ppid()) {
1793 int w = PlayTsVideo(Data, TS_SIZE);
1794 if (w < 0)
1795 return Played ? Played : w;
1796 if (w == 0)
1797 break;
1798 }
1799 Played += TS_SIZE;
1800 Length -= TS_SIZE;
1801 Data += TS_SIZE;
1802 }
1803 }
1804 return Played;
1805}
1806
1807int cDevice::Priority(bool IgnoreOccupied) const
1808{
1809 int priority = IDLEPRIORITY;
1810 if (IsPrimaryDevice() && !Replaying() && HasProgramme())
1811 priority = TRANSFERPRIORITY; // we use the same value here, no matter whether it's actual Transfer Mode or real live viewing
1812 if (!IgnoreOccupied && time(NULL) <= occupiedTimeout && occupiedPriority > priority)
1813 priority = occupiedPriority - 1; // so timers with occupiedPriority can start
1814 cMutexLock MutexLock(&mutexReceiver);
1815 for (int i = 0; i < MAXRECEIVERS; i++) {
1816 if (receiver[i])
1817 priority = max(receiver[i]->priority, priority);
1818 }
1819 return priority;
1820}
1821
1823{
1824 return true;
1825}
1826
1827bool cDevice::Receiving(bool Dummy) const
1828{
1829 cMutexLock MutexLock(&mutexReceiver);
1830 for (int i = 0; i < MAXRECEIVERS; i++) {
1831 if (receiver[i])
1832 return true;
1833 }
1834 return false;
1835}
1836
1837#define TS_SCRAMBLING_TIMEOUT 3 // seconds to wait until a TS becomes unscrambled
1838#define TS_SCRAMBLING_TIME_OK 3 // seconds before a Channel/CAM combination is marked as known to decrypt
1839#define EIT_INJECTION_TIME 10 // seconds for which to inject EIT event
1840
1842{
1843 if (Running() && OpenDvr()) {
1844 while (Running()) {
1845 // Read data from the DVR device:
1846 uchar *b = NULL;
1847 if (GetTSPacket(b)) {
1848 if (b) {
1849 // Distribute the packet to all attached receivers:
1850 Lock();
1851 cCamSlot *cs = CamSlot();
1852 if (cs)
1853 cs->TsPostProcess(b);
1854 int Pid = TsPid(b);
1855 bool IsScrambled = TsIsScrambled(b);
1856 cMutexLock MutexLock(&mutexReceiver);
1857 for (int i = 0; i < MAXRECEIVERS; i++) {
1858 cReceiver *Receiver = receiver[i];
1859 if (Receiver && Receiver->WantsPid(Pid)) {
1860 Receiver->Receive(b, TS_SIZE);
1861 // Check whether the TS packet is scrambled:
1862 if (Receiver->startScrambleDetection) {
1863 if (cs) {
1864 int CamSlotNumber = cs->MasterSlotNumber();
1865 if (Receiver->lastScrambledPacket < Receiver->startScrambleDetection)
1866 Receiver->lastScrambledPacket = Receiver->startScrambleDetection;
1867 time_t Now = time(NULL);
1868 if (IsScrambled) {
1869 Receiver->lastScrambledPacket = Now;
1870 if (Now - Receiver->startScrambleDetection > Receiver->scramblingTimeout) {
1871 if (!cs->IsActivating() || Receiver->Priority() >= LIVEPRIORITY) {
1872 if (Receiver->ChannelID().Valid()) {
1873 dsyslog("CAM %d: won't decrypt channel %s, detaching receiver", CamSlotNumber, *Receiver->ChannelID().ToString());
1874 ChannelCamRelations.SetChecked(Receiver->ChannelID(), CamSlotNumber);
1875 }
1876 Detach(Receiver);
1877 }
1878 }
1879 }
1880 else if (Now - Receiver->lastScrambledPacket > TS_SCRAMBLING_TIME_OK) {
1881 if (Receiver->ChannelID().Valid()) {
1882 dsyslog("CAM %d: decrypts channel %s", CamSlotNumber, *Receiver->ChannelID().ToString());
1883 ChannelCamRelations.SetDecrypt(Receiver->ChannelID(), CamSlotNumber);
1884 }
1885 Receiver->startScrambleDetection = 0;
1886 }
1887 }
1888 }
1889 // Inject EIT event to avoid the CAMs parental rating prompt:
1890 if (Receiver->startEitInjection) {
1891 time_t Now = time(NULL);
1892 if (cCamSlot *cs = CamSlot()) {
1893 if (Now != Receiver->lastEitInjection) { // once per second
1894 cs->InjectEit(Receiver->ChannelID().Sid());
1895 Receiver->lastEitInjection = Now;
1896 }
1897 }
1898 if (Now - Receiver->startEitInjection > EIT_INJECTION_TIME)
1899 Receiver->startEitInjection = 0;
1900 }
1901 }
1902 }
1903 Unlock();
1904 }
1905 }
1906 else
1907 break;
1908 }
1909 CloseDvr();
1910 }
1911}
1912
1914{
1915 return false;
1916}
1917
1919{
1920}
1921
1923{
1924 return false;
1925}
1926
1928{
1929 if (!Receiver)
1930 return false;
1931 if (Receiver->device == this)
1932 return true;
1933// activate the following line if you need it - actually the driver should be fixed!
1934//#define WAIT_FOR_TUNER_LOCK
1935#ifdef WAIT_FOR_TUNER_LOCK
1936#define TUNER_LOCK_TIMEOUT 5000 // ms
1937 if (!HasLock(TUNER_LOCK_TIMEOUT)) {
1938 esyslog("ERROR: device %d has no lock, can't attach receiver!", DeviceNumber() + 1);
1939 return false;
1940 }
1941#endif
1942 cMutexLock MutexLock(&mutexReceiver);
1943 for (int i = 0; i < MAXRECEIVERS; i++) {
1944 if (!receiver[i]) {
1945 for (int n = 0; n < Receiver->numPids; n++) {
1946 if (!AddPid(Receiver->pids[n])) {
1947 for ( ; n-- > 0; )
1948 DelPid(Receiver->pids[n]);
1949 return false;
1950 }
1951 }
1952 Receiver->Activate(true);
1953 Receiver->device = this;
1954 receiver[i] = Receiver;
1955 cCamSlot *cs = camSlot;
1956 if (cs && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
1957 cs->StartDecrypting();
1958 if (cs->WantsTsData()) {
1959 Receiver->lastEitInjection = 0;
1960 Receiver->startEitInjection = time(NULL);
1961 }
1962 if (CamSlots.NumReadyMasterSlots() > 1) { // don't try different CAMs if there is only one
1963 Receiver->startScrambleDetection = time(NULL);
1965 bool KnownToDecrypt = ChannelCamRelations.CamDecrypt(Receiver->ChannelID(), cs->MasterSlotNumber());
1966 if (KnownToDecrypt)
1967 Receiver->scramblingTimeout *= 9; // give it time to receive ECM/EMM (must be less than MAXBROKENTIMEOUT in recorder.c!)
1968 if (Receiver->ChannelID().Valid())
1969 dsyslog("CAM %d: %sknown to decrypt channel %s (scramblingTimeout = %ds)", cs->MasterSlotNumber(), KnownToDecrypt ? "" : "not ", *Receiver->ChannelID().ToString(), Receiver->scramblingTimeout);
1970 }
1971 }
1972 if (patFilter && Receiver->ChannelID().Valid())
1973 patFilter->Request(Receiver->ChannelID().Sid());
1974 Start();
1975 return true;
1976 }
1977 }
1978 esyslog("ERROR: no free receiver slot!");
1979 return false;
1980}
1981
1982void cDevice::Detach(cReceiver *Receiver, bool ReleaseCam)
1983{
1984 if (!Receiver || Receiver->device != this)
1985 return;
1986 bool receiversLeft = false;
1988 for (int i = 0; i < MAXRECEIVERS; i++) {
1989 if (receiver[i] == Receiver)
1990 receiver[i] = NULL;
1991 else if (receiver[i])
1992 receiversLeft = true;
1993 }
1994 if (patFilter && Receiver->ChannelID().Valid())
1995 patFilter->Release(Receiver->ChannelID().Sid());
1997 Receiver->device = NULL;
1998 Receiver->Activate(false);
1999 for (int n = 0; n < Receiver->numPids; n++)
2000 DelPid(Receiver->pids[n]);
2001 if (cCamSlot *cs = camSlot) {
2002 if (Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
2003 cs->StartDecrypting();
2004 if (ReleaseCam)
2006 }
2007 }
2008 if (!receiversLeft)
2009 Cancel(-1);
2010}
2011
2013{
2014 if (Pid) {
2015 {
2016 cMutexLock MutexLock(&mutexReceiver);
2017 for (int i = 0; i < MAXRECEIVERS; i++) {
2018 cReceiver *Receiver = receiver[i];
2019 if (Receiver && Receiver->WantsPid(Pid))
2020 Detach(Receiver, false);
2021 }
2022 }
2023 // Outside of mutexReceiver - see DetachAllReceivers():
2025 }
2026}
2027
2029{
2030 {
2031 cMutexLock MutexLock(&mutexReceiver);
2032 for (int i = 0; i < MAXRECEIVERS; i++)
2033 Detach(receiver[i], false);
2034 }
2035 // Outside of mutexReceiver: ReleaseCamSlot() -> cCamSlot::Assign() takes the
2036 // CAM assign mutex, under which Assign() calls AttachReceiver() and
2037 // SetCamSlot() (mutexReceiver, thread lock) - holding mutexReceiver here
2038 // inverts that order:
2040}
2041
2042// --- cTSBuffer -------------------------------------------------------------
2043
2044cTSBuffer::cTSBuffer(int File, int Size, int DeviceNumber)
2045{
2046 SetDescription("device %d TS buffer", DeviceNumber);
2047 f = File;
2048 deviceNumber = DeviceNumber;
2049 delivered = 0;
2050 ringBuffer = new cRingBufferLinear(Size, TS_SIZE, true, "TS");
2051 ringBuffer->SetTimeouts(100, 10); // the ring signals Get() only above 10% fill, too late for live TV
2053 Start();
2054}
2055
2057{
2058 Cancel(3);
2059 delete ringBuffer;
2060}
2061
2063{
2064 if (ringBuffer) {
2065 bool firstRead = true;
2066 cPoller Poller(f);
2067 while (Running()) {
2068 if (firstRead || Poller.Poll(100)) {
2069 firstRead = false;
2070 int r = ringBuffer->Read(f);
2071 if (r < 0 && FATALERRNO) {
2072 if (errno == EOVERFLOW)
2073 esyslog("ERROR: driver buffer overflow on device %d", deviceNumber);
2074 else {
2075 LOG_ERROR;
2076 break;
2077 }
2078 }
2079 cCondWait::SleepMs(10); // avoids small chunks of data, which cause high CPU usage, esp. on ARM CPUs
2080 }
2081 }
2082 }
2083}
2084
2085uchar *cTSBuffer::Get(int *Available, bool CheckAvailable)
2086{
2087 int Count = 0;
2088 if (delivered) {
2090 delivered = 0;
2091 }
2092 if (CheckAvailable && ringBuffer->Available() < TS_SIZE)
2093 return NULL;
2094 uchar *p = ringBuffer->Get(Count);
2095 if (p && Count >= TS_SIZE) {
2096 if (*p != TS_SYNC_BYTE) {
2097 for (int i = 1; i < Count; i++) {
2098 if (p[i] == TS_SYNC_BYTE) {
2099 Count = i;
2100 break;
2101 }
2102 }
2103 ringBuffer->Del(Count);
2104 esyslog("ERROR: skipped %d bytes to sync on TS packet on device %d", Count, deviceNumber);
2105 return NULL;
2106 }
2108 if (Available)
2109 *Available = Count;
2110 return p;
2111 }
2112 return NULL;
2113}
2114
2115void cTSBuffer::Skip(int Count)
2116{
2117 delivered = Count;
2118}
cAudios Audios
Definition audio.c:27
#define CA_ENCRYPTED_MIN
Definition channels.h:44
#define MAXDPIDS
Definition channels.h:32
#define MAXAPIDS
Definition channels.h:31
#define MAXSPIDS
Definition channels.h:33
#define CA_DVB_MAX
Definition channels.h:41
#define LOCK_CHANNELS_READ
Definition channels.h:277
cChannelCamRelations ChannelCamRelations
Definition ci.c:2960
cCamSlots CamSlots
Definition ci.c:2851
@ msReady
Definition ci.h:171
void PlayAudio(const uchar *Data, int Length, uchar Id)
Definition audio.c:29
void PlayTsAudio(const uchar *Data, int Length)
Definition audio.c:35
void ClearAudio(void)
Definition audio.c:47
void MuteAudio(bool On)
Definition audio.c:41
Definition ci.h:233
bool MtdActive(void)
Returns true if MTD is currently active.
Definition ci.h:290
virtual bool IsDecrypting(void)
Returns true if the CAM in this slot is currently used for decrypting.
Definition ci.c:2808
virtual void InjectEit(int Sid)
Injects a generated EIT with a "present event" for the given Sid into the TS data stream sent to the ...
Definition ci.c:2843
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:2669
cCamSlot * MasterSlot(void)
Returns this CAM slot's master slot, or a pointer to itself if it is a master slot.
Definition ci.h:311
int MasterSlotNumber(void)
Returns the number of this CAM's master slot within the whole system.
Definition ci.h:349
virtual eModuleStatus ModuleStatus(void)
Returns the status of the CAM in this slot.
Definition ci.c:2444
bool WantsTsData(void) const
Returns true if this CAM slot wants to receive the TS data through its Decrypt() function.
Definition ci.h:340
virtual bool Assign(cDevice *Device, bool Query=false)
Assigns this CAM slot to the given Device, if this is possible.
Definition ci.c:2221
cDevice * Device(void)
Returns the device this CAM slot is currently assigned to.
Definition ci.h:334
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:2710
virtual void StartDecrypting(void)
Sends all CA_PMT entries to the CAM that have been modified since the last call to this function.
Definition ci.c:2789
virtual bool IsActivating(void)
Returns true if this CAM slot is currently activating a smart card.
Definition ci.c:2437
virtual bool TsPostProcess(uchar *Data)
If there is a cCiSession that needs to do additional processing on TS packets (after the CAM has done...
Definition ci.c:2833
cCamSlot * MtdSpawn(void)
If this CAM slot can do MTD ("Multi Transponder Decryption"), a call to this function returns a cMtdC...
Definition ci.c:2213
virtual bool ProvidesCa(const int *CaSystemIds)
Returns true if the CAM in this slot provides one of the given CaSystemIds.
Definition ci.c:2677
int NumReadyMasterSlots(void)
Returns the number of master CAM slots in the system that are ready to decrypt.
Definition ci.c:2853
void SetChecked(tChannelID ChannelID, int CamSlotNumber)
Definition ci.c:3024
bool CamDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition ci.c:3017
bool CamChecked(tChannelID ChannelID, int CamSlotNumber)
Definition ci.c:3010
void SetDecrypt(tChannelID ChannelID, int CamSlotNumber)
Definition ci.c:3032
const char * Slang(int i) const
Definition channels.h:168
int Number(void) const
Definition channels.h:187
const char * Name(void) const
Definition channels.c:121
int Dpid(int i) const
Definition channels.h:161
int Apid(int i) const
Definition channels.h:160
tChannelID GetChannelID(void) const
Definition channels.h:199
int Ca(int Index=0) const
Definition channels.h:181
const char * Dlang(int i) const
Definition channels.h:167
const int * Caids(void) const
Definition channels.h:180
int Spid(int i) const
Definition channels.h:162
const char * Alang(int i) const
Definition channels.h:166
int Sid(void) const
Definition channels.h:184
static void SleepMs(int TimeoutMs)
Creates a cCondWait object and uses it to sleep for TimeoutMs milliseconds, immediately giving up the...
Definition thread.c:73
static void Shutdown(void)
Definition player.c:111
static void Launch(cControl *Control)
Definition player.c:91
virtual bool DeviceProvidesEIT(const cDevice *Device) const
Returns true if the given Device can provide EIT data.
Definition device.c:62
cDeviceHook(void)
Creates a new device hook object.
Definition device.c:52
virtual bool DeviceProvidesTransponder(const cDevice *Device, const cChannel *Channel) const
Returns true if the given Device can provide the given Channel's transponder.
Definition device.c:57
friend class cReceiver
Definition device.h:122
friend class cDeviceHook
Definition device.h:121
std::atomic< eTrackType > currentAudioTrack
Definition device.h:556
static int NextCardIndex(int n=0)
Calculates the next card index.
Definition device.c:156
int Occupied(int Priority=MINPRIORITY) const
Returns the number of seconds this device is still occupied for with a priority >= Priority.
Definition device.c:1015
virtual cString DeviceName(void) const
Returns a string identifying the name of this device.
Definition device.c:182
static cList< cDeviceHook > deviceHooks
Definition device.h:246
bool Replaying(void) const
Returns true if we are currently replaying.
Definition device.c:1446
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:1508
int currentAudioTrackMissingCount
Definition device.h:560
void StopSectionHandler(void)
A device that has called StartSectionHandler() must call this function (typically in its destructor) ...
Definition device.c:703
int Priority(bool IgnoreOccupied=false) const
Returns the priority of the current receiving session (-MAXPRIORITY..MAXPRIORITY),...
Definition device.c:1807
virtual bool SignalStats(int &Valid, double *Strength=NULL, double *Cnr=NULL, double *BerPre=NULL, double *BerPost=NULL, double *Per=NULL, int *Status=NULL) const
Returns statistics about the currently received signal (if available).
Definition device.c:807
virtual void SetSubtitleTrackDevice(eTrackType Type)
Sets the current subtitle track to the given value.
Definition device.c:1075
virtual int GetAudioChannelDevice(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition device.c:1054
virtual int PlayVideo(const uchar *Data, int Length)
Plays the given data block as video.
Definition device.c:1534
cSectionHandler * sectionHandler
Definition device.h:441
bool SetCurrentSubtitleTrack(eTrackType Type, bool Manual=false)
Sets the current subtitle track to the given Type.
Definition device.c:1230
virtual bool HasInternalCam(void)
Returns true if this device handles encrypted channels itself without VDR assistance.
Definition device.h:485
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:483
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:542
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:488
eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (general setup).
Definition device.c:901
bool mute
Definition device.h:627
virtual bool HasLock(int TimeoutMs=0) const
Returns true if the device has a lock on the requested transponder.
Definition device.c:1043
void StartSectionHandler(void)
A derived device that provides section data must call this function (typically in its constructor) to...
Definition device.c:692
@ ptTeletext
Definition device.h:410
@ ptPcr
Definition device.h:410
@ ptOther
Definition device.h:410
@ ptDolby
Definition device.h:410
@ ptAudio
Definition device.h:410
@ ptVideo
Definition device.h:410
cMutex mutexCurrentAudioTrack
Definition device.h:558
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:802
bool GetTrackId(eTrackType Type, tTrackId &TrackId)
Copies the given track id into TrackId and returns true, or returns false if Type is not a valid trac...
Definition device.c:1182
virtual int NumProvidedSystems(void) const
Returns the number of individual "delivery systems" this device provides.
Definition device.c:797
int NumSubtitleTracks(void) const
Returns the number of subtitle tracks that are currently available.
Definition device.c:1207
bool keepTracks
Definition device.h:562
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:1651
cMutex mutexReceiver
Definition device.h:883
virtual bool ProvidesSource(int Source) const
Returns true if this device can provide the given source.
Definition device.c:746
void ReleaseCamSlot(void)
Releases the CAM slot if it is currently not used.
Definition device.c:455
static int useDevice
Definition device.h:125
virtual void Action(void) override
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition device.c:1841
cDvbSubtitleConverter * dvbSubtitleConverter
Definition device.h:255
bool HasPid(int Pid) const
Returns true if this device is currently receiving the given PID.
Definition device.c:559
virtual void SetAudioTrackDevice(eTrackType Type)
Sets the current audio track to the given value.
Definition device.c:1071
virtual bool SetPid(cPidHandle *Handle, int Type, bool On)
Does the actual PID setting on this device.
Definition device.c:678
static int nextCardIndex
Definition device.h:188
cTsToPes tsToPesAudio
Definition device.h:662
cNitFilter * nitFilter
Definition device.h:445
bool autoSelectPreferredSubtitleLanguage
Definition device.h:561
static bool WaitForAllDevicesReady(int Timeout=0)
Waits until all devices have become ready, or the given Timeout (seconds) has expired.
Definition device.c:134
void SetCamSlot(cCamSlot *CamSlot)
Sets the given CamSlot to be used with this device.
Definition device.c:468
static cDevice * ActualDevice(void)
Returns the actual receiving device in case of Transfer Mode, or the primary device otherwise.
Definition device.c:229
static cDevice * PrimaryDevice(void)
Returns the primary device.
Definition device.h:148
static void SetUseDevice(int n)
Sets the 'useDevice' flag of the given device.
Definition device.c:150
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:832
eTrackType GetCurrentSubtitleTrack(void) const
Definition device.h:603
static cDevice * GetDevice(int Index)
Gets the device with the given Index.
Definition device.c:237
static void Shutdown(void)
Closes down all devices.
Definition device.c:474
cPatFilter * patFilter
Definition device.h:443
eTrackType GetCurrentAudioTrack(void) const
Definition device.h:599
cDevice(void)
Definition device.c:80
bool DeviceHooksProvidesEIT(void) const
Definition device.c:762
bool SwitchChannel(const cChannel *Channel, bool LiveView)
Switches the device to the given Channel, initiating transfer mode if necessary.
Definition device.c:847
virtual int PlayTsVideo(const uchar *Data, int Length)
Plays the given data block as video.
Definition device.c:1681
int DeviceNumber(void) const
Returns the number of this device (0 ... numDevices - 1).
Definition device.c:168
virtual void SetPowerSaveMode(bool On)
Puts the device into power save mode, if applicable.
Definition device.c:837
virtual bool DrainDevice(void)
Tells the device to play out all data it still holds in its buffers and decoders (data may be held ba...
Definition device.c:1529
cEitFilter * eitFilter
Definition device.h:442
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:792
virtual void SetAudioChannelDevice(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
Definition device.c:1059
cReceiver * receiver[MAXRECEIVERS]
Definition device.h:884
void DelPid(int Pid, ePidType PidType=ptOther)
Deletes a PID from the set of PIDs this device shall receive.
Definition device.c:643
bool AttachReceiver(cReceiver *Receiver)
Attaches the given receiver to this device.
Definition device.c:1927
static int CurrentChannel(void)
Returns the number of the current channel on the primary device.
Definition device.h:371
bool IsPrimaryDevice(bool CheckDecoder=true) const
Definition device.h:223
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:239
static cDevice * primaryDevice
Definition device.h:127
static bool SetPrimaryDevice(int n)
Sets the primary device to 'n'.
Definition device.c:201
bool Receiving(bool Dummy=false) const
Returns true if we are currently receiving. The parameter has no meaning (for backwards compatibility...
Definition device.c:1827
bool Transferring(void) const
Returns true if we are currently in Transfer Mode.
Definition device.c:1451
virtual int PlayTsAudio(const uchar *Data, int Length)
Plays the given data block as audio.
Definition device.c:1703
time_t occupiedTimeout
Definition device.h:266
void StopReplay(void)
Stops the current replay session (if any).
Definition device.c:1499
virtual void MakePrimaryDevice(bool On)
Informs a device that it will be the primary device.
Definition device.c:187
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:778
void DetachAll(int Pid)
Detaches all receivers from this device for this pid.
Definition device.c:2012
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:787
int cardIndex
Definition device.h:189
virtual int SignalQuality(void) const
Returns the "quality" of the currently received signal.
Definition device.c:817
virtual int SignalStrength(void) const
Returns the "strength" of the currently received signal.
Definition device.c:812
virtual void Play(void)
Sets the device into play mode (after a previous trick mode).
Definition device.c:1366
int GetAudioChannel(void)
Gets the current audio channel, which is stereo (0), mono left (1) or mono right (2).
Definition device.c:1096
cPidHandle pidHandles[MAXPIDHANDLES]
Definition device.h:419
void EnsureAudioTrack(bool Force=false)
Makes sure an audio track is selected that is actually available.
Definition device.c:1284
void Detach(cFilter *Filter)
Detaches the given filter from this device.
Definition device.c:740
cTsToPes tsToPesVideo
Definition device.h:661
virtual bool SetPlayMode(ePlayMode PlayMode)
Sets the device into the given play mode.
Definition device.c:1344
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:1913
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:1177
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:1108
virtual void TrickSpeed(int Speed, bool Forward)
Sets the device into a mode where replay is done slower.
Definition device.c:1354
cLiveSubtitle * liveSubtitle
Definition device.h:254
virtual void Mute(void)
Turns off audio while replaying.
Definition device.c:1382
virtual bool HasCi(void)
Returns true if this device has a Common Interface.
Definition device.c:463
virtual cString DeviceType(void) const
Returns a string identifying the type of this device (like "DVB-S").
Definition device.c:177
virtual const cChannel * GetCurrentlyTunedTransponder(void) const
Returns a pointer to the currently tuned transponder.
Definition device.c:822
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
Definition device.c:1374
void SetAudioChannel(int AudioChannel)
Sets the audio channel to stereo (0), mono left (1) or mono right (2).
Definition device.c:1102
static int NumDevices(void)
Returns the total number of devices.
Definition device.h:129
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles.
Definition device.c:1349
time_t occupiedFrom
Definition device.h:265
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:515
bool isPlayingVideo
Definition device.h:664
virtual bool Flush(int TimeoutMs=0)
Definition device.c:1513
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
Definition device.c:219
virtual int PlayTsSubtitle(const uchar *Data, int Length)
Plays the given data block as a subtitle.
Definition device.c:1721
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:538
virtual void CloseDvr(void)
Shuts down the DVR.
Definition device.c:1918
virtual void CloseFilter(int Handle)
Closes a file handle that has previously been opened by OpenFilter().
Definition device.c:729
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView)
Sets the device to the given channel (actual physical setup).
Definition device.c:1038
bool AttachPlayer(cPlayer *Player)
Attaches the given player to this device.
Definition device.c:1456
void ClrAvailableTracks(bool DescriptionsOnly=false, bool IdsOnly=false)
Clears the list of currently available tracks.
Definition device.c:1123
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:1048
friend class cLiveSubtitle
Definition device.h:120
int volume
Definition device.h:628
void EnsureSubtitleTrack(void)
Makes sure one of the preferred language subtitle tracks is selected.
Definition device.c:1317
virtual void DetachAllReceivers(void)
Detaches all receivers from this device.
Definition device.c:2028
virtual bool IsTunedToTransponder(const cChannel *Channel) const
Returns true if this device is currently tuned to the given Channel's transponder.
Definition device.c:827
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
Definition device.c:1339
int NumTracks(eTrackType FirstTrack, eTrackType LastTrack) const
Returns the number of tracks in the given range that are currently available.
Definition device.c:1192
void AttachFilter(cFilter *Filter)
Attaches the given filter to this device.
Definition device.c:734
std::atomic< cPlayer * > player
Definition device.h:659
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:224
virtual bool HasIBPTrickSpeed(void)
Returns true if this device can handle all frames in 'fast forward' trick speeds.
Definition device.h:793
virtual bool Ready(void)
Returns true if this device is ready.
Definition device.c:1822
cMutex mutexChannel
Definition device.h:264
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:434
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:549
tTrackId availableTracks[ttMaxTrackTypes]
Definition device.h:554
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:1922
virtual void Clear(void)
Clears all video and audio data from the device.
Definition device.c:1358
cTsToPes tsToPesSubtitle
Definition device.h:663
int CardIndex(void) const
Returns the card index of this device (0 ... MAXDEVICES - 1).
Definition device.h:224
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:493
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:1147
void SetOccupied(int Seconds, int Priority=MINPRIORITY, time_t From=0)
Sets the occupied timeout for this device to the given number of Seconds, This can be used to tune a ...
Definition device.c:1023
std::atomic< eTrackType > currentSubtitleTrack
Definition device.h:557
static int numDevices
Definition device.h:124
bool Drain(void)
Tells the device that the last data of the current stream has been delivered and no more will follow,...
Definition device.c:1518
int NumAudioTracks(void) const
Returns the number of audio tracks that are currently available.
Definition device.c:1202
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:1555
bool ToggleMute(void)
Turns the volume off or on and returns the new mute state.
Definition device.c:1079
void SetPowerSaveIfUnused(void)
Sets this device into a power save mode if it is not currently used and has implemented SetPowerSaveM...
Definition device.c:841
void DelLivePids(void)
Deletes the live viewing PIDs.
Definition device.c:683
virtual int PlayTs(const uchar *Data, int Length, bool VideoOnly=false)
Plays the given TS packet.
Definition device.c:1744
cPatPmtParser patPmtParser
Definition device.h:660
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:569
virtual ~cDevice() override
Definition device.c:123
cMutex mutexCurrentSubtitleTrack
Definition device.h:559
int pre_1_3_19_PrivateStream
Definition device.h:563
bool DeviceHooksProvidesTransponder(const cChannel *Channel) const
Definition device.c:751
virtual int ReadFilter(int Handle, void *Buffer, size_t Length)
Reads data from a handle for the given filter.
Definition device.c:724
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask)
Opens a file handle for the given filter data.
Definition device.c:719
cSdtFilter * sdtFilter
Definition device.h:444
static cDevice * device[MAXDEVICES]
Definition device.h:76
int occupiedPriority
Definition device.h:267
std::atomic< cCamSlot * > camSlot
Definition device.h:479
void ForceTransferMode(void)
Forces the device into transfermode for the current channel.
Definition device.c:1004
virtual int PlayAudio(const uchar *Data, int Length, uchar Id)
Plays the given data block as audio.
Definition device.c:1539
cMutex mutexPids
Definition device.h:407
bool SetCurrentAudioTrack(eTrackType Type)
Sets the current audio track to the given Type.
Definition device.c:1212
void SetTempSubtitles(void)
Temporarily turn on subtitles after a fast rewind during reply.
Definition device.c:1277
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:773
virtual void SetDigitalAudioDevice(bool On)
Tells the output device that the current audio track is Dolby Digital.
Definition device.c:1067
static std::atomic< int > currentChannel
Definition device.h:269
virtual void StillPicture(const uchar *Data, int Length)
Displays the given I-frame as a still picture.
Definition device.c:1387
virtual int PlaySubtitle(const uchar *Data, int Length)
Plays the given data block as a subtitle.
Definition device.c:1544
virtual void SetVolumeDevice(int Volume)
Sets the audio volume on this device (Volume = 0...255).
Definition device.c:1063
int Convert(const uchar *Data, int Length)
void Freeze(bool Status)
Definition dvbsubtitle.h:60
void SetVisible(bool Visible)
int ConvertFragments(const uchar *Data, int Length)
virtual void Clear(void)
Definition tools.c:2305
int Count(void) const
Definition tools.h:646
void Add(cListObject *Object, cListObject *After=NULL)
Definition tools.c:2228
int Index(void) const
Definition tools.c:2148
Definition tools.h:650
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
Definition tools.h:662
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
Definition tools.h:669
const T * Get(int Index) const
Returns the list element at the given Index, or NULL if no such element exists.
Definition tools.h:659
virtual ~cLiveSubtitle() override
Definition device.c:39
cLiveSubtitle(int SPid)
Definition device.c:34
virtual void Receive(const uchar *Data, int Length) override
This function is called from the cDevice we are attached to, and delivers one TS packet from the set ...
Definition device.c:44
bool Lock(int TimeoutMs=0, bool *TimedOut=NULL)
Returns true if the mutex was successfully locked.
Definition thread.c:228
void Unlock(void)
Definition thread.c:252
cNitFilter(cSdtFilter *SdtFilter)
Definition nit.c:29
void Request(int Sid)
Definition pat.c:408
void Release(int Sid)
Definition pat.c:431
void Reset(void)
Resets the parser.
Definition remux.c:638
void ParsePat(const uchar *Data, int Length)
Parses the PAT data from the single TS packet in Data.
Definition remux.c:648
void ParsePmt(const uchar *Data, int Length)
Parses the PMT data from the single TS packet in Data.
Definition remux.c:680
bool IsPmtPid(int Pid) const
Returns true if Pid the one of the PMT pids as defined by the current PAT.
Definition remux.h:404
int Ppid(void) const
Returns the PCR pid as defined by the current PMT, or 0 if no PCR pid has been detected,...
Definition remux.h:410
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:407
std::atomic< cDevice * > device
Definition player.h:19
ePlayMode playMode
Definition player.h:20
virtual void Activate(bool On)
Definition player.h:42
bool Poll(int TimeoutMs=0)
Definition tools.c:1632
A steerable satellite dish generally points to the south on the northern hemisphere,...
Definition positioner.h:31
time_t lastEitInjection
Definition receiver.h:31
int Priority(void)
Definition receiver.h:59
bool WantsPid(int Pid)
Definition receiver.c:114
std::atomic< int > pids[MAXRECEIVEPIDS]
Definition receiver.h:25
time_t startEitInjection
Definition receiver.h:30
tChannelID ChannelID(void)
Definition receiver.h:82
std::atomic< cDevice * > device
Definition receiver.h:21
void Detach(void)
Definition receiver.c:125
int priority
Definition receiver.h:23
virtual void Receive(const uchar *Data, int Length)=0
This function is called from the cDevice we are attached to, and delivers one TS packet from the set ...
bool AddPid(int Pid)
Adds the given Pid to the list of PIDs of this receiver.
Definition receiver.c:42
std::atomic< int > numPids
Definition receiver.h:26
time_t startScrambleDetection
Definition receiver.h:28
time_t lastScrambledPacket
Definition receiver.h:27
int scramblingTimeout
Definition receiver.h:29
cReceiver(const cChannel *Channel=NULL, int Priority=MINPRIORITY)
Creates a new receiver for the given Channel with the given Priority.
Definition receiver.c:14
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:36
cRingBufferLinear(int Size, int Margin=0, bool Statistics=false, const char *Description=NULL)
Creates a linear ring buffer.
Definition ringbuffer.c:170
void Del(int Count)
Deletes at most Count bytes from the ring buffer.
Definition ringbuffer.c:371
uchar * Get(int &Count)
Gets data from the ring buffer.
Definition ringbuffer.c:346
int Read(int FileHandle, int Max=0)
Reads at most Max bytes from FileHandle and stores them in the ring buffer.
Definition ringbuffer.c:230
virtual int Available(void) override
Definition ringbuffer.c:211
void SetTimeouts(int PutTimeout, int GetTimeout)
Definition ringbuffer.c:89
void SetIoThrottle(void)
Definition ringbuffer.c:95
cSdtFilter(cPatFilter *PatFilter)
Definition sdt.c:23
void SetChannel(const cChannel *Channel)
Definition sections.c:140
cSectionHandler(cDevice *Device)
Definition sections.c:42
void SetStatus(bool On)
Definition sections.c:147
void Attach(cFilter *Filter)
Definition sections.c:119
void Detach(cFilter *Filter)
Definition sections.c:130
int VolumeSteps
Definition config.h:377
int VideoDisplayFormat
Definition config.h:331
int CurrentVolume
Definition config.h:376
int SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:299
int DisplaySubtitles
Definition config.h:298
int VolumeLinearize
Definition config.h:378
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition config.h:297
int VideoFormat
Definition config.h:332
int PrimaryDVB
Definition config.h:273
int CurrentDolby
Definition config.h:379
int QueueMessage(eMessageType Type, const char *s, int Seconds=0, int Timeout=0)
Like Message(), but this function may be called from a background thread.
Definition skins.c:334
@ eSpuPanAndScan
Definition spu.h:21
@ eSpuNormal
Definition spu.h:21
@ eSpuLetterBox
Definition spu.h:21
virtual void setScaleMode(cSpuDecoder::eScaleMode ScaleMode)=0
static void MsgSetVolume(int Volume, bool Absolute)
Definition status.c:69
static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView)
Definition status.c:45
cTSBuffer(int File, int Size, int DeviceNumber)
Definition device.c:2044
int delivered
Definition device.h:931
uchar * Get(int *Available=NULL, bool CheckAvailable=false)
Returns a pointer to the first TS packet in the buffer.
Definition device.c:2085
virtual ~cTSBuffer() override
Definition device.c:2056
cRingBufferLinear * ringBuffer
Definition device.h:932
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:2115
int deviceNumber
Definition device.h:930
int f
Definition device.h:929
virtual void Action(void) override
A derived cThread class must implement the code it wants to execute as a separate thread in this func...
Definition device.c:2062
void Unlock(void)
Definition thread.h:104
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:330
void SetDescription(const char *Description,...) __attribute__((format(printf
Definition thread.c:293
bool Running(void)
Returns false if a derived cThread object shall leave its Action() function.
Definition thread.h:110
void Lock(void)
Definition thread.h:103
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:380
char * description
Definition thread.h:96
static cDevice * ReceiverDevice(void)
Definition transfer.h:40
cTransferControl(cDevice *ReceiverDevice, const cChannel *Channel)
Definition transfer.c:76
void PutTs(const uchar *Data, int Length)
Puts the payload data of the single TS packet at Data into the converter.
Definition remux.c:1067
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:1144
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:1096
void Reset(void)
Resets the converter.
Definition remux.c:1149
cSetup Setup
Definition config.c:373
#define MINPRIORITY
Definition config.h:42
#define TRANSFERPRIORITY
Definition config.h:44
#define MAXPRIORITY
Definition config.h:41
#define SUBTITLES_ALWAYS
Definition config.h:83
#define IDLEPRIORITY
Definition config.h:45
#define SUBTITLES_REWIND
Definition config.h:84
#define LIVEPRIORITY
Definition config.h:43
#define EIT_INJECTION_TIME
Definition device.c:1839
static int GetClippedNumProvidedSystems(int AvailableBits, cDevice *Device)
Definition device.c:242
#define PRINTPIDS(s)
Definition device.c:557
#define TS_SCRAMBLING_TIMEOUT
Definition device.c:1837
#define MIN_PRE_1_3_19_PRIVATESTREAM
Definition device.c:70
#define TS_SCRAMBLING_TIME_OK
Definition device.c:1838
#define MAXVOLUME
Definition device.h:32
#define MAXPIDHANDLES
Definition device.h:30
eVideoDisplayFormat
Definition device.h:58
@ vdfLetterBox
Definition device.h:59
@ vdfCenterCutOut
Definition device.h:60
@ vdfPanAndScan
Definition device.h:58
ePlayMode
Definition device.h:39
@ pmNone
Definition device.h:39
#define MAXDEVICES
Definition device.h:29
#define MAXOCCUPIEDTIMEOUT
Definition device.h:34
#define IS_AUDIO_TRACK(t)
Definition device.h:76
eTrackType
Definition device.h:63
@ ttSubtitle
Definition device.h:70
@ ttMaxTrackTypes
Definition device.h:73
@ ttDolbyLast
Definition device.h:69
@ ttAudioLast
Definition device.h:66
@ ttDolby
Definition device.h:67
@ ttAudioFirst
Definition device.h:65
@ ttSubtitleLast
Definition device.h:72
@ ttDolbyFirst
Definition device.h:68
@ ttSubtitleFirst
Definition device.h:71
@ ttAudio
Definition device.h:64
@ ttNone
Definition device.h:63
#define MAXRECEIVERS
Definition device.h:31
#define IS_SUBTITLE_TRACK(t)
Definition device.h:78
#define IS_DOLBY_TRACK(t)
Definition device.h:77
eSetChannelResult
Definition device.h:36
@ scrOk
Definition device.h:36
@ scrNotAvailable
Definition device.h:36
@ scrFailed
Definition device.h:36
@ scrNoTransfer
Definition device.h:36
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:331
#define tr(s)
Definition i18n.h:85
int TsPid(const uchar *p)
Definition remux.h:82
bool TsHasPayload(const uchar *p)
Definition remux.h:62
#define PATPID
Definition remux.h:52
bool TsIsScrambled(const uchar *p)
Definition remux.h:93
#define TS_SIZE
Definition remux.h:34
bool TsPayloadStart(const uchar *p)
Definition remux.h:72
#define TS_SYNC(Data, Length)
Definition remux.h:149
int TsPayloadOffset(const uchar *p)
Definition remux.h:108
#define TS_SYNC_BYTE
Definition remux.h:33
int PesLength(const uchar *p)
Definition remux.h:173
cSkins Skins
Definition skins.c:257
@ mtInfo
Definition skins.h:37
@ mtError
Definition skins.h:37
int Sid(void) const
Definition channels.h:64
bool Valid(void) const
Definition channels.h:58
cString ToString(void) const
Definition channels.c:40
char language[MAXLANGCODE2]
Definition device.h:82
uint16_t id
Definition device.h:81
#define LOCK_THREAD
Definition thread.h:181
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:962
ssize_t safe_read(int filedes, void *buffer, size_t size)
Definition tools.c:50
ssize_t safe_write(int filedes, const void *buffer, size_t size)
Definition tools.c:62
char * strn0cpy(char *dest, const char *src, size_t n)
Definition tools.c:128
#define FATALERRNO
Definition tools.h:52
T constrain(T v, T l, T h)
Definition tools.h:70
#define LOG_ERROR_STR(s)
Definition tools.h:40
unsigned char uchar
Definition tools.h:31
#define dsyslog(a...)
Definition tools.h:37
int sgn(T a)
Definition tools.h:68
void DELETENULL(T *&p)
Definition tools.h:49
T min(T a, T b)
Definition tools.h:63
T max(T a, T b)
Definition tools.h:64
#define esyslog(a...)
Definition tools.h:35
#define LOG_ERROR
Definition tools.h:39
#define isyslog(a...)
Definition tools.h:36