summaryrefslogtreecommitdiff
path: root/device.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2002-08-04 18:00:00 +0200
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2002-08-04 18:00:00 +0200
commit527748826c8d3cfacff8a7ab3fda9551c1182590 (patch)
tree4e753aa85bc11b44e078809b643b7e5d6be5fdd9 /device.c
parenta4112a96a67dbeb1cd6a63d2b4fa4b837462f467 (diff)
downloadvdr-patch-lnbsharing-527748826c8d3cfacff8a7ab3fda9551c1182590.tar.gz
vdr-patch-lnbsharing-527748826c8d3cfacff8a7ab3fda9551c1182590.tar.bz2
Version 1.1.6vdr-1.1.6
- Re-visited the race condition fix in the cDvbPlayer (thanks again to Andreas Schultz). - Changed the VFAT handling to allow users who normally use it but have forgotten to set it when compiling a new version of VDR to at least see their recordings made with VFAT enabled (thanks to Christian Rienecker). - Added some missing teletext PIDs (thanks to Joerg Riechardt). - Fixed PID handling for cReceiver. - Added a missing #include to ringbuffer.c (thanks to Martin Hammerschmid). - Now using CC, CFLAGS, CXX and CXXFLAGS in Makefile. - Changed the cDevice class to allow plugins to implement their own devices (see PLUGINS.html for details).
Diffstat (limited to 'device.c')
-rw-r--r--device.c691
1 files changed, 135 insertions, 556 deletions
diff --git a/device.c b/device.c
index c85cd45..f70ca04 100644
--- a/device.c
+++ b/device.c
@@ -4,108 +4,42 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 1.5 2002/06/23 12:51:24 kls Exp $
+ * $Id: device.c 1.8 2002/08/04 15:18:05 kls Exp $
*/
#include "device.h"
#include <errno.h>
-extern "C" {
-#define HAVE_BOOLEAN
-#include <jpeglib.h>
-}
-#include <linux/videodev.h>
-#include <ost/sec.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include "eit.h"
#include "player.h"
#include "receiver.h"
#include "status.h"
#include "transfer.h"
-#define DEV_VIDEO "/dev/video"
-#define DEV_OST_OSD "/dev/ost/osd"
-#define DEV_OST_FRONTEND "/dev/ost/frontend"
-#define DEV_OST_SEC "/dev/ost/sec"
-#define DEV_OST_DVR "/dev/ost/dvr"
-#define DEV_OST_DEMUX "/dev/ost/demux"
-#define DEV_OST_VIDEO "/dev/ost/video"
-#define DEV_OST_AUDIO "/dev/ost/audio"
-
-// The default priority for non-primary DVB cards:
+// The default priority for non-primary devices:
#define DEFAULTPRIORITY -2
-#define TS_SIZE 188
-#define TS_SYNC_BYTE 0x47
-#define PID_MASK_HI 0x1F
-
// The maximum time we wait before assuming that a recorded video data stream
// is broken:
#define MAXBROKENTIMEOUT 30 // seconds
-static const char *OstName(const char *Name, int n)
-{
- static char buffer[_POSIX_PATH_MAX];
- snprintf(buffer, sizeof(buffer), "%s%d", Name, n);
- return buffer;
-}
-
-static int OstOpen(const char *Name, int n, int Mode, bool ReportError = false)
-{
- const char *FileName = OstName(Name, n);
- int fd = open(FileName, Mode);
- if (fd < 0 && ReportError)
- LOG_ERROR_STR(FileName);
- return fd;
-}
-
int cDevice::numDevices = 0;
int cDevice::useDevice = 0;
+int cDevice::nextCardIndex = 0;
cDevice *cDevice::device[MAXDEVICES] = { NULL };
cDevice *cDevice::primaryDevice = NULL;
-cDevice::cDevice(int n)
+cDevice::cDevice(void)
{
- frontendType = FrontendType(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
- siProcessor = NULL;
- cardIndex = n;
-
- // Devices that are present on all card types:
+ cardIndex = nextCardIndex++;
- fd_frontend = OstOpen(DEV_OST_FRONTEND, n, O_RDWR);
-
- // Devices that are only present on DVB-S cards:
-
- fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR);
-
- // Devices that are only present on cards with decoders:
-
- fd_osd = OstOpen(DEV_OST_OSD, n, O_RDWR);
- fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK);
- fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK);
-
- // Video format:
-
- SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
-
- // We only check the devices that must be present - the others will be checked before accessing them://XXX
-
- if (fd_frontend >= 0) {
- siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n));
- FrontendInfo feinfo;
- if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0)
- frontendType = feinfo.type;
- else
- LOG_ERROR;
- }
- else
- esyslog("ERROR: can't open video device %d", n);
+ SetVideoFormat(Setup.VideoFormat);
- dvrFileName = strdup(OstName(DEV_OST_DVR, CardIndex()));
active = false;
currentChannel = 0;
- frequency = 0;
mute = false;
volume = Setup.CurrentVolume;
@@ -115,17 +49,20 @@ cDevice::cDevice(int n)
for (int i = 0; i < MAXRECEIVERS; i++)
receiver[i] = NULL;
ca = -1;
+
+ if (numDevices < MAXDEVICES) {
+ device[numDevices++] = this;
+ SetCaCaps(cardIndex);
+ }
+ else
+ esyslog("ERROR: too many devices!");
}
cDevice::~cDevice()
{
- delete dvrFileName;
- delete siProcessor;
Detach(player);
for (int i = 0; i < MAXRECEIVERS; i++)
Detach(receiver[i]);
- // We're not explicitly closing any device files here, since this sometimes
- // caused segfaults. Besides, the program is about to terminate anyway...
}
void cDevice::SetUseDevice(int n)
@@ -134,15 +71,44 @@ void cDevice::SetUseDevice(int n)
useDevice |= (1 << n);
}
+int cDevice::NextCardIndex(int n)
+{
+ if (n > 0) {
+ nextCardIndex += n;
+ if (nextCardIndex >= MAXDEVICES)
+ esyslog("ERROR: nextCardIndex too big (%d)", nextCardIndex);
+ }
+ else if (n < 0)
+ esyslog("ERROR: illegal value in IncCardIndex(%d)", n);
+ return nextCardIndex;
+}
+
+void cDevice::MakePrimaryDevice(bool On)
+{
+}
+
bool cDevice::SetPrimaryDevice(int n)
{
n--;
if (0 <= n && n < numDevices && device[n]) {
isyslog("setting primary device to %d", n + 1);
+ if (primaryDevice)
+ primaryDevice->MakePrimaryDevice(false);
primaryDevice = device[n];
+ primaryDevice->MakePrimaryDevice(true);
return true;
}
- esyslog("invalid devive number: %d", n + 1);
+ esyslog("invalid device number: %d", n + 1);
+ return false;
+}
+
+bool cDevice::CanBeReUsed(int Frequency, int Vpid)
+{
+ return false;
+}
+
+bool cDevice::HasDecoder(void) const
+{
return false;
}
@@ -156,20 +122,7 @@ cDevice *cDevice::GetDevice(int Ca, int Priority, int Frequency, int Vpid, bool
for (int i = 0; i < numDevices; i++) {
if ((Provides[i] = device[i]->ProvidesCa(Ca)) != 0) { // this device is basicly able to do the job
//XXX+ dsyslog("GetDevice: %d %d %d %5d %5d", i, device[i]->HasDecoder(), device[i]->Receiving(), Frequency, device[i]->frequency);//XXX
- if ( (!device[i]->HasDecoder() // it's a "budget card" which can receive multiple channels...
- && device[i]->frequency == Frequency // ...and it is tuned to the requested frequency...
- && device[i]->Receiving() // ...and is already receiving
- // need not check priority - if a budget card is already receiving on the requested
- // frequency, we can attach another receiver regardless of priority
- )
- || (device[i]->HasDecoder() // it's a "full featured card" which can receive only one channel...
- && device[i]->frequency == Frequency // ...and it is tuned to the requested frequency...
- && device[i]->pidHandles[ptVideo].pid == Vpid // ...and the requested video PID...
- && device[i]->Receiving() // ...and is already receiving
- // need not check priority - if a full featured card is already receiving the requested
- // frequency and video PID, we can attach another receiver regardless of priority
- )
- ) {
+ if (device[i]->CanBeReUsed(Frequency, Vpid)) {
d = device[i];
if (ReUse)
*ReUse = true;
@@ -204,50 +157,14 @@ cDevice *cDevice::GetDevice(int Ca, int Priority, int Frequency, int Vpid, bool
return d;
}
-void cDevice::SetCaCaps(void)
+void cDevice::SetCaCaps(int Index)
{
for (int d = 0; d < numDevices; d++) {
- for (int i = 0; i < MAXCACAPS; i++)
- device[d]->caCaps[i] = Setup.CaCaps[device[d]->CardIndex()][i];
- }
-}
-
-bool cDevice::Probe(const char *FileName)
-{
- if (access(FileName, F_OK) == 0) {
- dsyslog("probing %s", FileName);
- int f = open(FileName, O_RDONLY);
- if (f >= 0) {
- close(f);
- return true;
- }
- else if (errno != ENODEV && errno != EINVAL)
- LOG_ERROR_STR(FileName);
- }
- else if (errno != ENOENT)
- LOG_ERROR_STR(FileName);
- return false;
-}
-
-bool cDevice::Initialize(void)
-{
- numDevices = 0;
- for (int i = 0; i < MAXDEVICES; i++) {
- if (useDevice == 0 || (useDevice & (1 << i)) != 0) {
- if (Probe(OstName(DEV_OST_FRONTEND, i)))
- device[numDevices++] = new cDevice(i);
- else
- break;
+ if (Index < 0 || Index == device[d]->CardIndex()) {
+ for (int i = 0; i < MAXCACAPS; i++)
+ device[d]->caCaps[i] = Setup.CaCaps[device[d]->CardIndex()][i];
}
}
- primaryDevice = device[0];
- if (numDevices > 0) {
- isyslog("found %d video device%s", numDevices, numDevices > 1 ? "s" : "");
- SetCaCaps();
- }
- else
- esyslog("ERROR: no video device found, giving up!");
- return numDevices > 0;
}
void cDevice::Shutdown(void)
@@ -261,106 +178,13 @@ void cDevice::Shutdown(void)
bool cDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
{
- int videoDev = OstOpen(DEV_VIDEO, CardIndex(), O_RDWR, true);
- if (videoDev >= 0) {
- int result = 0;
- struct video_mbuf mbuf;
- result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf);
- if (result == 0) {
- int msize = mbuf.size;
- unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
- if (mem && mem != (unsigned char *)-1) {
- // set up the size and RGB
- struct video_capability vc;
- result |= ioctl(videoDev, VIDIOCGCAP, &vc);
- struct video_mmap vm;
- vm.frame = 0;
- if ((SizeX > 0) && (SizeX <= vc.maxwidth) &&
- (SizeY > 0) && (SizeY <= vc.maxheight)) {
- vm.width = SizeX;
- vm.height = SizeY;
- }
- else {
- vm.width = vc.maxwidth;
- vm.height = vc.maxheight;
- }
- vm.format = VIDEO_PALETTE_RGB24;
- result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm);
- result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame);
- // make RGB out of BGR:
- int memsize = vm.width * vm.height;
- unsigned char *mem1 = mem;
- for (int i = 0; i < memsize; i++) {
- unsigned char tmp = mem1[2];
- mem1[2] = mem1[0];
- mem1[0] = tmp;
- mem1 += 3;
- }
-
- if (Quality < 0)
- Quality = 255; //XXX is this 'best'???
-
- isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
- FILE *f = fopen(FileName, "wb");
- if (f) {
- if (Jpeg) {
- // write JPEG file:
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_compress(&cinfo);
- jpeg_stdio_dest(&cinfo, f);
- cinfo.image_width = vm.width;
- cinfo.image_height = vm.height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
-
- jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo, Quality, true);
- jpeg_start_compress(&cinfo, true);
-
- int rs = vm.width * 3;
- JSAMPROW rp[vm.height];
- for (int k = 0; k < vm.height; k++)
- rp[k] = &mem[rs * k];
- jpeg_write_scanlines(&cinfo, rp, vm.height);
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
- }
- else {
- // write PNM file:
- if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 ||
- fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) {
- LOG_ERROR_STR(FileName);
- result |= 1;
- }
- }
- fclose(f);
- }
- else {
- LOG_ERROR_STR(FileName);
- result |= 1;
- }
- munmap(mem, msize);
- }
- else
- result |= 1;
- }
- close(videoDev);
- return result == 0;
- }
return false;
}
-void cDevice::SetVideoFormat(videoFormat_t Format)
+void cDevice::SetVideoFormat(bool VideoFormat16_9)
{
- if (HasDecoder())
- CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, Format));
}
-// ptVideo ptAudio ptTeletext ptDolby ptOther
-dmxPesType_t PesTypes[] = { DMX_PES_VIDEO, DMX_PES_AUDIO, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER };
-
//#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", CardIndex(), s); for (int i = 0; i < MAXPIDHANDLES; i++) q += sprintf(q, " %s%4d %d", i == ptOther ? "* " : "", pidHandles[i].pid, pidHandles[i].used); dsyslog(b); } //XXX+
#define PRINTPIDS(s)
@@ -375,13 +199,12 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
else if (a < 0 && i >= ptOther && !pidHandles[i].used)
a = i;
}
- dmxPesType_t PesType = PesTypes[ptOther];
if (n >= 0) {
// The Pid is already in use
if (++pidHandles[n].used == 2 && n <= ptTeletext) {
- // It's a special PID that has to be switched into "tap" mode
+ // It's a special PID that may have to be switched into "tap" mode
PRINTPIDS("A");//XXX+
- return SetPid(pidHandles[n].fd, PesTypes[n], Pid, DMX_OUT_TS_TAP);
+ return SetPid(&pidHandles[n], n, true);
}
PRINTPIDS("a");//XXX+
return true;
@@ -389,8 +212,6 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
else if (PidType < ptOther) {
// The Pid is not yet in use and it is a special one
n = PidType;
- PesType = PesTypes[PidType];
- PRINTPIDS("B");//XXX+
}
else if (a >= 0) {
// The Pid is not yet in use and we have a free slot
@@ -400,217 +221,51 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
esyslog("ERROR: no free slot for PID %d", Pid);
if (n >= 0) {
pidHandles[n].pid = Pid;
- pidHandles[n].fd = OstOpen(DEV_OST_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true);
pidHandles[n].used = 1;
PRINTPIDS("C");//XXX+
- return SetPid(pidHandles[n].fd, PesType, Pid, PidType <= ptTeletext ? DMX_OUT_DECODER : DMX_OUT_TS_TAP);
+ return SetPid(&pidHandles[n], n, true);
}
}
return true;
}
-bool cDevice::DelPid(int Pid)
+void cDevice::DelPid(int Pid)
{
if (Pid) {
for (int i = 0; i < MAXPIDHANDLES; i++) {
if (pidHandles[i].pid == Pid) {
- switch (--pidHandles[i].used) {
- case 0: CHECK(ioctl(pidHandles[i].fd, DMX_STOP));//XXX+ is this necessary???
- close(pidHandles[i].fd);
- pidHandles[i].fd = -1;
- pidHandles[i].pid = 0;
- break;
- case 1: if (i <= ptTeletext)
- SetPid(pidHandles[i].fd, PesTypes[i], Pid, DMX_OUT_DECODER);
- break;
- }
+ if (--pidHandles[i].used < 2) {
+ SetPid(&pidHandles[i], i, false);
+ if (pidHandles[i].used == 0) {
+ pidHandles[i].handle = -1;
+ pidHandles[i].pid = 0;
+ }
+ }
PRINTPIDS("D");//XXX+
- return pidHandles[i].used;
}
}
}
- return false;
}
-bool cDevice::SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output)
+bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
{
- if (Pid) {
- CHECK(ioctl(fd, DMX_STOP));
- if (Pid != 0x1FFF) {
- dmxPesFilterParams pesFilterParams;
- pesFilterParams.pid = Pid;
- pesFilterParams.input = DMX_IN_FRONTEND;
- pesFilterParams.output = Output;
- pesFilterParams.pesType = PesType;
- pesFilterParams.flags = DMX_IMMEDIATE_START;
- //XXX+ pesFilterParams.flags = DMX_CHECK_CRC;//XXX
- if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
- LOG_ERROR;
- return false;
- }
- //XXX+ CHECK(ioctl(fd, DMX_SET_BUFFER_SIZE, KILOBYTE(32)));//XXX
- //XXX+ CHECK(ioctl(fd, DMX_START));//XXX
- }
- }
- return true;
+ return false;
}
-eSetChannelResult cDevice::SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr)
+eSetChannelResult cDevice::SetChannel(const cChannel *Channel)
{
- StopReplay();
-
cStatus::MsgChannelSwitch(this, 0);
+ StopReplay();
+
// Must set this anyway to avoid getting stuck when switching through
// channels with 'Up' and 'Down' keys:
- currentChannel = ChannelNumber;
-
- // Avoid noise while switching:
-
- if (HasDecoder()) {
- CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
- CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
- CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
- CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
- }
-
- // Stop setting system time:
-
- if (siProcessor)
- siProcessor->SetCurrentTransponder(0);
+ currentChannel = Channel->number;
// If this card can't receive this channel, we must not actually switch
// the channel here, because that would irritate the driver when we
// start replaying in Transfer Mode immediately after switching the channel:
- bool NeedsTransferMode = (IsPrimaryDevice() && !ProvidesCa(Ca));
-
- if (!NeedsTransferMode) {
-
- // Turn off current PIDs:
-
- if (HasDecoder()) {
- DelPid(pidHandles[ptVideo].pid);
- DelPid(pidHandles[ptAudio].pid);
- DelPid(pidHandles[ptTeletext].pid);
- DelPid(pidHandles[ptDolby].pid);
- }
-
- FrontendParameters Frontend;
-
- switch (frontendType) {
- case FE_QPSK: { // DVB-S
-
- // Frequency offsets:
-
- unsigned int freq = Frequency;
- int tone = SEC_TONE_OFF;
-
- if (freq < (unsigned int)Setup.LnbSLOF) {
- freq -= Setup.LnbFrequLo;
- tone = SEC_TONE_OFF;
- }
- else {
- freq -= Setup.LnbFrequHi;
- tone = SEC_TONE_ON;
- }
-
- Frontend.Frequency = freq * 1000UL;
- Frontend.Inversion = INVERSION_AUTO;
- Frontend.u.qpsk.SymbolRate = Srate * 1000UL;
- Frontend.u.qpsk.FEC_inner = FEC_AUTO;
-
- int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
-
- // DiseqC:
-
- secCommand scmd;
- scmd.type = 0;
- scmd.u.diseqc.addr = 0x10;
- scmd.u.diseqc.cmd = 0x38;
- scmd.u.diseqc.numParams = 1;
- scmd.u.diseqc.params[0] = 0xF0 | ((Diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0);
-
- secCmdSequence scmds;
- scmds.voltage = volt;
- scmds.miniCommand = SEC_MINI_NONE;
- scmds.continuousTone = tone;
- scmds.numCommands = Setup.DiSEqC ? 1 : 0;
- scmds.commands = &scmd;
-
- CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds));
- }
- break;
- case FE_QAM: { // DVB-C
-
- // Frequency and symbol rate:
-
- Frontend.Frequency = Frequency * 1000000UL;
- Frontend.Inversion = INVERSION_AUTO;
- Frontend.u.qam.SymbolRate = Srate * 1000UL;
- Frontend.u.qam.FEC_inner = FEC_AUTO;
- Frontend.u.qam.QAM = QAM_64;
- }
- break;
- case FE_OFDM: { // DVB-T
-
- // Frequency and OFDM paramaters:
-
- Frontend.Frequency = Frequency * 1000UL;
- Frontend.Inversion = INVERSION_AUTO;
- Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ;
- Frontend.u.ofdm.HP_CodeRate=FEC_2_3;
- Frontend.u.ofdm.LP_CodeRate=FEC_1_2;
- Frontend.u.ofdm.Constellation=QAM_64;
- Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K;
- Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32;
- Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE;
- }
- break;
- default:
- esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
- return scrFailed;
- }
-
- // Tuning:
-
- CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
-
- // Wait for channel sync:
-
- if (cFile::FileReady(fd_frontend, 5000)) {
- FrontendEvent event;
- int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
- if (res >= 0) {
- if (event.type != FE_COMPLETION_EV) {
- esyslog("ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1);
- if (IsPrimaryDevice())
- cThread::RaisePanic();
- return scrFailed;
- }
- }
- else
- esyslog("ERROR %d in frontend get event (channel %d, card %d)", res, ChannelNumber, CardIndex() + 1);
- }
- else
- esyslog("ERROR: timeout while tuning");
-
- frequency = Frequency;
-
- // PID settings:
-
- if (HasDecoder()) {
- if (!(AddPid(Vpid, ptVideo) && AddPid(Apid, ptAudio))) {//XXX+ dolby Dpid1!!! (if audio plugins are attached)
- esyslog("ERROR: failed to set PIDs for channel %d", ChannelNumber);
- return scrFailed;
- }
- if (IsPrimaryDevice())
- AddPid(Tpid, ptTeletext);
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
- }
- }
-
- if (IsPrimaryDevice() && siProcessor)
- siProcessor->SetCurrentServiceID(Pnr);
+ bool NeedsTransferMode = (IsPrimaryDevice() && !ProvidesCa(Channel->ca));
eSetChannelResult Result = scrOk;
@@ -618,28 +273,30 @@ eSetChannelResult cDevice::SetChannel(int ChannelNumber, int Frequency, char Pol
// use the card that actually can receive it and transfer data from there:
if (NeedsTransferMode) {
- cDevice *CaDevice = GetDevice(Ca, 0);
- if (CaDevice && !CaDevice->Receiving()) {
- if ((Result = CaDevice->SetChannel(ChannelNumber, Frequency, Polarization, Diseqc, Srate, Vpid, Apid, Tpid, Ca, Pnr)) == scrOk)
- cControl::Launch(new cTransferControl(CaDevice, Vpid, Apid, 0, 0, 0));//XXX+
- }
+ cDevice *CaDevice = GetDevice(Channel->ca, 0);
+ if (CaDevice && !CaDevice->Receiving() && CaDevice->SetChannel(Channel) == scrOk)
+ cControl::Launch(new cTransferControl(CaDevice, Channel->vpid, Channel->apid1, 0, 0, 0));//XXX+
else
Result = scrNoTransfer;
}
+ else if (!SetChannelDevice(Channel))
+ Result = scrFailed;
- if (HasDecoder()) {
- CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
- CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
- }
+ if (IsPrimaryDevice())
+ cSIProcessor::SetCurrentServiceID(Channel->pnr);
- // Start setting system time:
+ cStatus::MsgChannelSwitch(this, Channel->number);
- if (Result == scrOk && siProcessor)
- siProcessor->SetCurrentTransponder(Frequency);
+ return Result;
+}
- cStatus::MsgChannelSwitch(this, ChannelNumber);
+bool cDevice::SetChannelDevice(const cChannel *Channel)
+{
+ return false;
+}
- return Result;
+void cDevice::SetVolumeDevice(int Volume)
+{
}
bool cDevice::ToggleMute(void)
@@ -653,78 +310,40 @@ bool cDevice::ToggleMute(void)
void cDevice::SetVolume(int Volume, bool Absolute)
{
- if (HasDecoder()) {
- volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME);
- audioMixer_t am;
- am.volume_left = am.volume_right = volume;
- CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am));
- cStatus::MsgSetVolume(volume, Absolute);
- if (volume > 0)
- mute = false;
- }
+ volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME);
+ SetVolumeDevice(volume);
+ cStatus::MsgSetVolume(volume, Absolute);
+ if (volume > 0)
+ mute = false;
+}
+
+int cDevice::SetPlayMode(bool On)
+{
+ return -1;
}
void cDevice::TrickSpeed(int Speed)
{
- if (fd_video >= 0)
- CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed));
}
void cDevice::Clear(void)
{
- if (fd_video >= 0)
- CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
- if (fd_audio >= 0)
- CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
}
void cDevice::Play(void)
{
- if (fd_audio >= 0)
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
- if (fd_video >= 0)
- CHECK(ioctl(fd_video, VIDEO_CONTINUE));
}
void cDevice::Freeze(void)
{
- if (fd_audio >= 0)
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
- if (fd_video >= 0)
- CHECK(ioctl(fd_video, VIDEO_FREEZE));
}
void cDevice::Mute(void)
{
- if (fd_audio >= 0) {
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
- CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
- }
}
void cDevice::StillPicture(const uchar *Data, int Length)
{
- Mute();
-/* Using the VIDEO_STILLPICTURE ioctl call would be the
- correct way to display a still frame, but unfortunately this
- doesn't work with frames from VDR. So let's do pretty much the
- same here as in DVB/driver/dvb.c's play_iframe() - I have absolutely
- no idea why it works this way, but doesn't work with VIDEO_STILLPICTURE.
- If anybody ever finds out what could be changed so that VIDEO_STILLPICTURE
- could be used, please let me know!
- kls 2002-03-23
-*/
-//#define VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES
-#ifdef VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES
- videoDisplayStillPicture sp = { (char *)Data, Length };
- CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
-#else
-#define MIN_IFRAME 400000
- for (int i = MIN_IFRAME / Length + 1; i > 0; i--) {
- safe_write(fd_video, Data, Length);
- usleep(1); // allows the buffer to be displayed in case the progress display is active
- }
-#endif
}
bool cDevice::Replaying(void)
@@ -741,19 +360,9 @@ bool cDevice::AttachPlayer(cPlayer *Player)
if (HasDecoder()) {
if (player)
Detach(player);
-
- if (siProcessor)
- siProcessor->SetStatus(false);
- CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
- CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY));
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
- CHECK(ioctl(fd_audio, AUDIO_PLAY));
- CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
- CHECK(ioctl(fd_video, VIDEO_PLAY));
-
player = Player;
player->device = this;
- player->deviceFileHandle = fd_video;
+ player->deviceFileHandle = SetPlayMode(true);
player->Activate(true);
return true;
}
@@ -767,17 +376,7 @@ void cDevice::Detach(cPlayer *Player)
player->deviceFileHandle = -1;
player->device = NULL;
player = NULL;
-
- CHECK(ioctl(fd_video, VIDEO_STOP, true));
- CHECK(ioctl(fd_audio, AUDIO_STOP, true));
- CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
- CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
- CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX));
- CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX));
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
- CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
- if (siProcessor)
- siProcessor->SetStatus(true);
+ SetPlayMode(false);
}
}
@@ -802,14 +401,11 @@ void cDevice::StopReplay(void)
int cDevice::PlayVideo(const uchar *Data, int Length)
{
- if (fd_video >= 0)
- return write(fd_video, Data, Length);
return -1;
}
int cDevice::PlayAudio(const uchar *Data, int Length)
{
- //XXX+
return -1;
}
@@ -828,7 +424,7 @@ int cDevice::Priority(void)
int cDevice::CanShift(int Ca, int Priority, int UsedCards)
{
return -1;//XXX+ too complex with multiple recordings per device
- // Test whether a receiving on this DVB device can be shifted to another one
+ // Test whether a receiver on this device can be shifted to another one
// in order to perform a new receiving with the given Ca and Priority on this device:
int ShiftLevel = -1; // default means this device can't be shifted
if (UsedCards & (1 << CardIndex()) != 0)
@@ -882,7 +478,7 @@ int cDevice::ProvidesCa(int Ca)
bool cDevice::Receiving(void)
{
for (int i = 0; i < MAXRECEIVERS; i++) {
- if (receiver[i])
+ if (receiver[i] && receiver[i]->priority >= 0) // cReceiver with priority < 0 doesn't count
return true;
}
return false;
@@ -892,51 +488,31 @@ void cDevice::Action(void)
{
dsyslog("receiver thread started on device %d (pid=%d)", CardIndex() + 1, getpid());
- int fd_dvr = open(dvrFileName, O_RDONLY | O_NONBLOCK);
- if (fd_dvr >= 0) {
- pollfd pfd;
- pfd.fd = fd_dvr;
- pfd.events = pfd.revents = POLLIN;
+ if (OpenDvr()) {
uchar b[TS_SIZE];
time_t t = time(NULL);
active = true;
for (; active;) {
-
// Read data from the DVR device:
-
- if (pfd.revents & POLLIN != 0) {
- int r = read(fd_dvr, b, sizeof(b));
- if (r == TS_SIZE) {
- if (*b == TS_SYNC_BYTE) {
- // We're locked on to a TS packet
- int Pid = (((uint16_t)b[1] & PID_MASK_HI) << 8) | b[2];
- // Distribute the packet to all attached receivers:
- Lock();
- for (int i = 0; i < MAXRECEIVERS; i++) {
- if (receiver[i] && receiver[i]->WantsPid(Pid))
- receiver[i]->Receive(b, TS_SIZE);
- }
- Unlock();
- }
- t = time(NULL);
- }
- else if (r > 0)
- esyslog("ERROR: got incomplete TS packet (%d bytes)", r);//XXX+ TODO do we have to read the rest???
- else if (r < 0) {
- if (FATALERRNO) {
- if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library
- esyslog("ERROR: DVB driver buffer overflow on device %d", CardIndex() + 1);
- else {
- LOG_ERROR;
- break;
- }
- }
+ int r = GetTSPacket(b);
+ if (r == TS_SIZE) {
+ if (*b == TS_SYNC_BYTE) {
+ // We're locked on to a TS packet
+ int Pid = (((uint16_t)b[1] & PID_MASK_HI) << 8) | b[2];
+ // Distribute the packet to all attached receivers:
+ Lock();
+ for (int i = 0; i < MAXRECEIVERS; i++) {
+ if (receiver[i] && receiver[i]->WantsPid(Pid))
+ receiver[i]->Receive(b, TS_SIZE);
+ }
+ Unlock();
}
+ t = time(NULL);
}
-
- // Wait for more data to become available:
-
- poll(&pfd, 1, 100);
+ else if (r > 0)
+ esyslog("ERROR: got incomplete TS packet (%d bytes) on device %d", r, CardIndex() + 1);//XXX+ TODO do we have to read the rest???
+ else if (r < 0)
+ break;
//XXX+ put this into the recorder??? or give the receiver a flag whether it wants this?
if (time(NULL) - t > MAXBROKENTIMEOUT) {
@@ -945,14 +521,26 @@ void cDevice::Action(void)
t = time(NULL);
}
}
- close(fd_dvr);
+ CloseDvr();
}
- else
- LOG_ERROR_STR(dvrFileName);
dsyslog("receiver thread ended on device %d (pid=%d)", CardIndex() + 1, getpid());
}
+bool cDevice::OpenDvr(void)
+{
+ return false;
+}
+
+void cDevice::CloseDvr(void)
+{
+}
+
+int cDevice::GetTSPacket(uchar *Data)
+{
+ return -1;
+}
+
bool cDevice::AttachReceiver(cReceiver *Receiver)
{
//XXX+ check for same transponder???
@@ -963,13 +551,8 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
StopReplay();
for (int i = 0; i < MAXRECEIVERS; i++) {
if (!receiver[i]) {
- //siProcessor->SetStatus(false);//XXX+
- for (int n = 0; n < MAXRECEIVEPIDS; n++) {
- if (Receiver->pids[n])
- AddPid(Receiver->pids[n]);//XXX+ retval!
- else
- break;
- }
+ for (int n = 0; n < MAXRECEIVEPIDS; n++)
+ AddPid(Receiver->pids[n]);//XXX+ retval!
Receiver->Activate(true);
Lock();
Receiver->device = this;
@@ -995,12 +578,8 @@ void cDevice::Detach(cReceiver *Receiver)
receiver[i] = NULL;
Receiver->device = NULL;
Unlock();
- for (int n = 0; n < MAXRECEIVEPIDS; n++) {
- if (Receiver->pids[n])
- DelPid(Receiver->pids[n]);
- else
- break;
- }
+ for (int n = 0; n < MAXRECEIVEPIDS; n++)
+ DelPid(Receiver->pids[n]);
}
else if (receiver[i])
receiversLeft = true;