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