mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
- Added a note about 'Id' being obsolete to the description of cDevice::PlayAudio(). - Switched to the new S2API driver API, which was decided to become the official DVB API in the kernel (based on patches from Igor M. Liplianin, Niels Wagenaar and Edgar Hucek). VDR now uses the S2API driver from http://linuxtv.org/hg/v4l-dvb. In order to correctly detect DVB-S2 capable devices, you need to apply the patch from ftp://ftp.cadsoft.de/vdr/Developer/v4l-dvb-s2api-add-s2-capability.diff to the driver source, because the S2API doesn't provide a way of telling whether a device can handle DVB-S2 transponders. - The cDvbTuner::IsTunedTo() function now also checks the symbol rate in case of DVB-S and DVB-C. - Improved handling PES video packets with zero length when converting from TS to PES. For good replay in Transfer Mode on full featured DVB cards you may want to apply the patch from ftp://ftp.cadsoft.de/vdr/Developer/av7110_v4ldvb_api5_audiobuf_test_1.diff to the driver (thanks to Oliver Endriss).
304 lines
7.7 KiB
C
304 lines
7.7 KiB
C
/*
|
|
* sky.c: A plugin for the Video Disk Recorder
|
|
*
|
|
* See the README file for copyright information and how to reach the author.
|
|
*
|
|
* $Id: sky.c 2.1 2008/09/07 11:54:07 kls Exp $
|
|
*/
|
|
|
|
#include <sys/socket.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <sys/un.h>
|
|
#include <unistd.h>
|
|
#include <vdr/device.h>
|
|
#include <vdr/plugin.h>
|
|
#include <vdr/sources.h>
|
|
|
|
static const char *VERSION = "0.3.8";
|
|
static const char *DESCRIPTION = "Sky Digibox interface";
|
|
|
|
// --- cDigiboxDevice --------------------------------------------------------
|
|
|
|
#define DUMMYAPID 80
|
|
#define DUMMYVPID 160
|
|
|
|
class cSkyChannel : public cListObject {
|
|
public:
|
|
tChannelID channelID;
|
|
int digiboxChannelNumber;
|
|
bool Parse(const char *s);
|
|
};
|
|
|
|
bool cSkyChannel::Parse(const char *s)
|
|
{
|
|
char *id = NULL;
|
|
if (2 == sscanf(s, "%a[^:]:%d", &id, &digiboxChannelNumber))
|
|
channelID = tChannelID::FromString(id);
|
|
free(id);
|
|
return digiboxChannelNumber && channelID.Valid();
|
|
}
|
|
|
|
class cSkyChannels : public cConfig<cSkyChannel> {
|
|
public:
|
|
cSkyChannel *GetSkyChannel(const cChannel *Channel);
|
|
};
|
|
|
|
cSkyChannel *cSkyChannels::GetSkyChannel(const cChannel *Channel)
|
|
{
|
|
tChannelID ChannelID = Channel->GetChannelID();
|
|
for (cSkyChannel *sc = First(); sc; sc = Next(sc)) {
|
|
if (ChannelID == sc->channelID)
|
|
return sc;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
cSkyChannels SkyChannels;
|
|
|
|
class cDigiboxDevice : public cDevice {
|
|
private:
|
|
int source;
|
|
int digiboxChannelNumber;
|
|
int fd_dvr;
|
|
int apid, vpid;
|
|
cTSBuffer *tsBuffer;
|
|
int fd_lirc;
|
|
void LircSend(const char *s);
|
|
void LircSend(int n);
|
|
protected:
|
|
virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
|
|
virtual bool OpenDvr(void);
|
|
virtual void CloseDvr(void);
|
|
virtual bool GetTSPacket(uchar *&Data);
|
|
public:
|
|
cDigiboxDevice(void);
|
|
virtual ~cDigiboxDevice();
|
|
virtual bool ProvidesSource(int Source) const;
|
|
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
|
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSetChannel = NULL) const;
|
|
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
|
};
|
|
|
|
cDigiboxDevice::cDigiboxDevice(void)
|
|
{
|
|
source = cSource::FromString("S28.2E");//XXX parameter???
|
|
digiboxChannelNumber = 0;
|
|
fd_dvr = -1;
|
|
apid = vpid = 0;
|
|
struct sockaddr_un addr;
|
|
addr.sun_family = AF_UNIX;
|
|
strn0cpy(addr.sun_path, "/dev/lircd", sizeof(addr.sun_path));//XXX parameter???
|
|
fd_lirc = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (fd_lirc >= 0) {
|
|
if (connect(fd_lirc, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
|
LOG_ERROR;
|
|
close(fd_lirc);
|
|
}
|
|
}
|
|
else
|
|
LOG_ERROR;
|
|
}
|
|
|
|
cDigiboxDevice::~cDigiboxDevice()
|
|
{
|
|
if (fd_lirc >= 0)
|
|
close(fd_lirc);
|
|
}
|
|
|
|
void cDigiboxDevice::LircSend(const char *s)
|
|
{
|
|
char buf[100];
|
|
snprintf(buf, sizeof(buf), "SEND_ONCE SKY %s\n", s);
|
|
dsyslog(buf);//XXX
|
|
if (write(fd_lirc, buf, strlen(buf)) < 0)
|
|
LOG_ERROR;//XXX _STR
|
|
cCondWait::SleepMs(200);
|
|
}
|
|
|
|
void cDigiboxDevice::LircSend(int n)
|
|
{
|
|
char buf[10];
|
|
snprintf(buf, sizeof(buf), "%d", n);
|
|
char *p = buf;
|
|
while (*p) {
|
|
char q[10];
|
|
sprintf(q, "%c", *p);
|
|
LircSend(q);
|
|
p++;
|
|
}
|
|
}
|
|
|
|
bool cDigiboxDevice::SetPid(cPidHandle *Handle, int Type, bool On)
|
|
{
|
|
//dsyslog("SetPid %d %d", Handle->pid, On);
|
|
return true;
|
|
}
|
|
|
|
bool cDigiboxDevice::OpenDvr(void)
|
|
{
|
|
CloseDvr();
|
|
fd_dvr = open("/dev/video2", O_RDONLY | O_NONBLOCK);//XXX parameter???
|
|
if (fd_dvr >= 0)
|
|
tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(2), CardIndex() + 1);
|
|
return fd_dvr >= 0;
|
|
}
|
|
|
|
void cDigiboxDevice::CloseDvr(void)
|
|
{
|
|
if (fd_dvr >= 0) {
|
|
close(fd_dvr);
|
|
fd_dvr = -1;
|
|
delete tsBuffer;
|
|
tsBuffer = NULL;
|
|
}
|
|
}
|
|
|
|
bool cDigiboxDevice::GetTSPacket(uchar *&Data)
|
|
{
|
|
if (tsBuffer) {
|
|
Data = tsBuffer->Get();
|
|
if (Data) {
|
|
// insert the actual PIDs:
|
|
int Pid = (((uint16_t)Data[1] & TS_PID_MASK_HI) << 8) | Data[2];
|
|
if (Pid == DUMMYAPID)
|
|
Pid = apid;
|
|
else if (Pid == DUMMYVPID)
|
|
Pid = vpid;
|
|
Data[1] = ((Pid >> 8) & 0xFF) | (Data[1] & ~TS_PID_MASK_HI);
|
|
Data[2] = Pid & 0xFF;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool cDigiboxDevice::ProvidesSource(int Source) const
|
|
{
|
|
return source == Source;
|
|
}
|
|
|
|
bool cDigiboxDevice::ProvidesTransponder(const cChannel *Channel) const
|
|
{
|
|
return false; // can't provide any actual transponder
|
|
}
|
|
|
|
bool cDigiboxDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
|
{
|
|
bool result = false;
|
|
bool hasPriority = Priority < 0 || Priority > this->Priority();
|
|
bool needsDetachReceivers = true;
|
|
|
|
cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel);
|
|
if (SkyChannel) {
|
|
if (Receiving(true)) {
|
|
if (digiboxChannelNumber == SkyChannel->digiboxChannelNumber) {
|
|
needsDetachReceivers = false;
|
|
result = true;
|
|
}
|
|
else
|
|
result = hasPriority;
|
|
}
|
|
else
|
|
result = hasPriority;
|
|
}
|
|
if (NeedsDetachReceivers)
|
|
*NeedsDetachReceivers = needsDetachReceivers;
|
|
return result;
|
|
}
|
|
|
|
bool cDigiboxDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|
{
|
|
if (fd_lirc >= 0 && !Receiving(true)) { // if we are receiving the channel is already set!
|
|
cSkyChannel *SkyChannel = SkyChannels.GetSkyChannel(Channel);
|
|
if (SkyChannel) {
|
|
digiboxChannelNumber = SkyChannel->digiboxChannelNumber;
|
|
apid = Channel->Apid(0);
|
|
vpid = Channel->Vpid();
|
|
//XXX only when recording??? -> faster channel switching!
|
|
LircSend("SKY"); // makes sure the Digibox is "on"
|
|
//XXX lircprint(fd_lirc, "BACKUP");
|
|
//XXX lircprint(fd_lirc, "BACKUP");
|
|
//XXX lircprint(fd_lirc, "BACKUP");
|
|
LircSend(digiboxChannelNumber);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// --- cPluginSky ------------------------------------------------------------
|
|
|
|
class cPluginSky : public cPlugin {
|
|
private:
|
|
// Add any member variables or functions you may need here.
|
|
public:
|
|
cPluginSky(void);
|
|
virtual ~cPluginSky();
|
|
virtual const char *Version(void) { return VERSION; }
|
|
virtual const char *Description(void) { return DESCRIPTION; }
|
|
virtual const char *CommandLineHelp(void);
|
|
virtual bool ProcessArgs(int argc, char *argv[]);
|
|
virtual bool Initialize(void);
|
|
virtual void Housekeeping(void);
|
|
virtual cMenuSetupPage *SetupMenu(void);
|
|
virtual bool SetupParse(const char *Name, const char *Value);
|
|
};
|
|
|
|
cPluginSky::cPluginSky(void)
|
|
{
|
|
// Initialize any member variables here.
|
|
// DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL
|
|
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
|
|
}
|
|
|
|
cPluginSky::~cPluginSky()
|
|
{
|
|
// Clean up after yourself!
|
|
}
|
|
|
|
const char *cPluginSky::CommandLineHelp(void)
|
|
{
|
|
// Return a string that describes all known command line options.
|
|
return NULL;
|
|
}
|
|
|
|
bool cPluginSky::ProcessArgs(int argc, char *argv[])
|
|
{
|
|
// Implement command line argument processing here if applicable.
|
|
return true;
|
|
}
|
|
|
|
bool cPluginSky::Initialize(void)
|
|
{
|
|
// Initialize any background activities the plugin shall perform.
|
|
const char *ConfigDir = ConfigDirectory(Name());
|
|
if (ConfigDir) {
|
|
if (SkyChannels.Load(AddDirectory(ConfigDir, "channels.conf.sky"), true)) {
|
|
new cDigiboxDevice;
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
esyslog("ERROR: can't get config directory");
|
|
return false;
|
|
}
|
|
|
|
void cPluginSky::Housekeeping(void)
|
|
{
|
|
// Perform any cleanup or other regular tasks.
|
|
}
|
|
|
|
cMenuSetupPage *cPluginSky::SetupMenu(void)
|
|
{
|
|
// Return a setup menu in case the plugin supports one.
|
|
return NULL;
|
|
}
|
|
|
|
bool cPluginSky::SetupParse(const char *Name, const char *Value)
|
|
{
|
|
// Parse your own setup parameters and store their values.
|
|
return false;
|
|
}
|
|
|
|
VDRPLUGINCREATOR(cPluginSky); // Don't touch this!
|