diff options
author | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2002-08-04 18:00:00 +0200 |
---|---|---|
committer | Klaus Schmidinger <kls (at) cadsoft (dot) de> | 2002-08-04 18:00:00 +0200 |
commit | 527748826c8d3cfacff8a7ab3fda9551c1182590 (patch) | |
tree | 4e753aa85bc11b44e078809b643b7e5d6be5fdd9 /device.c | |
parent | a4112a96a67dbeb1cd6a63d2b4fa4b837462f467 (diff) | |
download | vdr-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.c | 691 |
1 files changed, 135 insertions, 556 deletions
@@ -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; |