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