vdr 2.6.1
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.5 2022/01/24 16:53:45 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];
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 <<= 1; imp |= device[i] == cTransferControl::ReceiverDevice(); // avoid the Transfer Mode receiver device
309 imp <<= 8; imp |= device[i]->Priority() - IDLEPRIORITY; // use the device with the lowest priority (- IDLEPRIORITY to assure that values -100..99 can be used)
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
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
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
static cDevice * device[MAXDEVICES]
Definition: device.h:126
virtual int PlayVideo(const uchar *Data, int Length)
Plays the given data block as video.
Definition: device.c:1405
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
static cList< cDeviceHook > deviceHooks
Definition: device.h:243
ePidType
Definition: device.h:398
@ ptVideo
Definition: device.h:398
@ ptAudio
Definition: device.h:398
@ ptPcr
Definition: device.h:398
@ ptDolby
Definition: device.h:398
@ ptTeletext
Definition: device.h:398
@ ptOther
Definition: device.h:398
cPlayer * player
Definition: device.h:639
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
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
cTsToPes tsToPesAudio
Definition: device.h:642
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
cSdtFilter * sdtFilter
Definition: device.h:432
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
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
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
cPatFilter * patFilter
Definition: device.h:431
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
cCamSlot * camSlot
Definition: device.h:467
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 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
friend class cLiveSubtitle
Definition: device.h:120
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
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
cSectionHandler * sectionHandler
Definition: device.h:429
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
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
cDvbSubtitleConverter * dvbSubtitleConverter
Definition: device.h:252
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
static int nextCardIndex
Definition: device.h:185
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
cEitFilter * eitFilter
Definition: device.h:430
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
int volume
Definition: device.h:608
static int numDevices
Definition: device.h:124
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
cReceiver * receiver[MAXRECEIVERS]
Definition: device.h:834
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
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
tTrackId availableTracks[ttMaxTrackTypes]
Definition: device.h:542
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 useDevice
Definition: device.h:125
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
static cDevice * primaryDevice
Definition: device.h:127
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
cPidHandle pidHandles[MAXPIDHANDLES]
Definition: device.h:407
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
cLiveSubtitle * liveSubtitle
Definition: device.h:251
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
cNitFilter * nitFilter
Definition: device.h:433
int Convert(const uchar *Data, int Length)
Definition: dvbsubtitle.c:1450
void Freeze(bool Status)
Definition: dvbsubtitle.h:53
int ConvertFragments(const uchar *Data, int Length)
Definition: dvbsubtitle.c:1404
Definition: eit.h:48
Definition: filter.h:80
virtual void Clear(void)
Definition: tools.c:2261
int Count(void) const
void Add(cListObject *Object, cListObject *After=NULL)
Definition: tools.c:2184
int Index(void) const
Definition: tools.c:2104
const T * First(void) const
Returns the first element in this list, or NULL if the list is empty.
const T * Next(const T *Object) const
< Returns the element immediately before Object in this list, or NULL if Object is the first element ...
const T * Get(int Index) const
Returns the list element at the given Index, or NULL if no such element exists.
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.
int Ppid(void) const
Returns the PCR pid as defined by the current PMT, or 0 if no PCR pid has been detected,...
int Vpid(void) const
Returns the video pid as defined by the current PMT, or 0 if no video pid has been detected,...
virtual void SetAudioTrack(eTrackType Type, const tTrackId *TrackId)
cDevice * device
ePlayMode playMode
virtual void Activate(bool On)
virtual void SetSubtitleTrack(eTrackType Type, const tTrackId *TrackId)
bool Poll(int TimeoutMs=0)
Definition: tools.c:1539
A steerable satellite dish generally points to the south on the northern hemisphere,...
time_t lastEitInjection
int Priority(void)
bool WantsPid(int Pid)
Definition: receiver.c:114
cDevice * device
time_t startEitInjection
tChannelID ChannelID(void)
void Detach(void)
Definition: receiver.c:125
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 pids[MAXRECEIVEPIDS]
bool AddPid(int Pid)
Adds the given Pid to the list of PIDs of this receiver.
Definition: receiver.c:42
time_t startScrambleDetection
time_t lastScrambledPacket
virtual void Activate(bool On)
This function is called just before the cReceiver gets attached to (On == true) and right after it ge...
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 SubtitleLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:294
int VolumeSteps
Definition: config.h:366
int VideoDisplayFormat
Definition: config.h:323
int CurrentVolume
Definition: config.h:365
int AudioLanguages[I18N_MAX_LANGUAGES+1]
Definition: config.h:292
int DisplaySubtitles
Definition: config.h:293
int VolumeLinearize
Definition: config.h:367
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
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
cRingBufferLinear * ringBuffer
Definition: device.h:881
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
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
char * description
void Unlock(void)
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.
void Lock(void)
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
static cDevice * ReceiverDevice(void)
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:316
#define tr(s)
Definition: i18n.h:85
int TsPid(const uchar *p)
bool TsHasPayload(const uchar *p)
#define PATPID
bool TsIsScrambled(const uchar *p)
#define TS_SIZE
bool TsPayloadStart(const uchar *p)
#define TS_SYNC(Data, Length)
int TsPayloadOffset(const uchar *p)
#define TS_SYNC_BYTE
int PesLength(const uchar *p)
cSkins Skins
Definition: skins.c:219
@ mtInfo
@ mtError
#define LOCK_THREAD
#define FATALERRNO
T constrain(T v, T l, T h)
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
#define LOG_ERROR_STR(s)
unsigned char uchar
#define dsyslog(a...)
int sgn(T a)
ssize_t safe_read(int filedes, void *buffer, size_t size)
Definition: tools.c:53
void DELETENULL(T *&p)
ssize_t safe_write(int filedes, const void *buffer, size_t size)
Definition: tools.c:65
T min(T a, T b)
T max(T a, T b)
#define esyslog(a...)
#define LOG_ERROR
char * strn0cpy(char *dest, const char *src, size_t n)
Definition: tools.c:131
#define isyslog(a...)
unsigned char u_char
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