vdr-plugin-iptv/device.c

275 lines
7.4 KiB
C
Raw Normal View History

2007-09-12 19:28:59 +02:00
/*
* device.c: IPTV plugin for the Video Disk Recorder
*
* See the README file for copyright information and how to reach the author.
*
2007-09-24 18:08:09 +02:00
* $Id: device.c,v 1.37 2007/09/24 16:08:09 ajhseppa Exp $
2007-09-12 19:28:59 +02:00
*/
#include "common.h"
2007-09-15 17:38:38 +02:00
#include "config.h"
2007-09-12 19:28:59 +02:00
#include "device.h"
#define IPTV_MAX_DEVICES 8
cIptvDevice * IptvDevices[IPTV_MAX_DEVICES];
unsigned int cIptvDevice::deviceCount = 0;
cIptvDevice::cIptvDevice(unsigned int Index)
: deviceIndex(Index),
isPacketDelivered(false),
isOpenDvr(false),
2007-09-14 17:44:25 +02:00
mutex()
2007-09-12 19:28:59 +02:00
{
debug("cIptvDevice::cIptvDevice(%d)\n", deviceIndex);
2007-09-16 15:38:20 +02:00
tsBuffer = new cRingBufferLinear(MEGABYTE(IptvConfig.GetTsBufferSize()),
2007-09-22 12:36:30 +02:00
(TS_SIZE * IptvConfig.GetMaxBufferSize()),
false, "IPTV");
2007-09-15 19:15:37 +02:00
tsBuffer->SetTimeouts(100, 100);
2007-09-21 23:50:52 +02:00
ResetBuffering();
2007-09-14 17:44:25 +02:00
pUdpProtocol = new cIptvProtocolUdp();
2007-09-16 11:38:00 +02:00
pHttpProtocol = new cIptvProtocolHttp();
2007-09-16 14:18:15 +02:00
pFileProtocol = new cIptvProtocolFile();
2007-09-12 19:28:59 +02:00
pIptvStreamer = new cIptvStreamer(tsBuffer, &mutex);
// Initialize filter pointers
memset(&secfilters, '\0', sizeof(secfilters));
2007-09-20 23:15:08 +02:00
StartSectionHandler();
2007-09-12 19:28:59 +02:00
}
cIptvDevice::~cIptvDevice()
{
debug("cIptvDevice::~cIptvDevice(%d)\n", deviceIndex);
2007-09-14 17:44:25 +02:00
delete pIptvStreamer;
delete pUdpProtocol;
2007-09-12 19:28:59 +02:00
delete tsBuffer;
// Destroy all filters
for (int i = 0; i < eMaxFilterCount; ++i)
DeleteFilter(i);
2007-09-12 19:28:59 +02:00
}
bool cIptvDevice::Initialize(unsigned int DeviceCount)
{
debug("cIptvDevice::Initialize()\n");
if (DeviceCount > IPTV_MAX_DEVICES)
DeviceCount = IPTV_MAX_DEVICES;
for (unsigned int i = 0; i < DeviceCount; ++i)
IptvDevices[i] = new cIptvDevice(i);
return true;
}
unsigned int cIptvDevice::Count(void)
{
unsigned int count = 0;
debug("cIptvDevice::Count()\n");
for (unsigned int i = 0; i < IPTV_MAX_DEVICES; ++i) {
if (IptvDevices[i])
count++;
}
return count;
}
cIptvDevice *cIptvDevice::Get(unsigned int DeviceIndex)
{
debug("cIptvDevice::Get()\n");
if ((DeviceIndex > 0) && (DeviceIndex <= IPTV_MAX_DEVICES))
return IptvDevices[DeviceIndex - 1];
2007-09-12 19:28:59 +02:00
return NULL;
}
2007-09-14 17:44:25 +02:00
cString cIptvDevice::GetChannelSettings(const char *Param, int *IpPort, cIptvProtocolIf* *Protocol)
2007-09-12 19:28:59 +02:00
{
debug("cIptvDevice::GetChannelSettings(%d)\n", deviceIndex);
2007-09-16 15:11:19 +02:00
char *loc = NULL;
2007-09-16 15:44:09 +02:00
if (sscanf(Param, "IPTV|UDP|%a[^|]|%u", &loc, IpPort) == 2) {
2007-09-16 15:11:19 +02:00
cString addr(loc, true);
2007-09-14 17:44:25 +02:00
*Protocol = pUdpProtocol;
2007-09-16 15:11:19 +02:00
return addr;
2007-09-12 19:28:59 +02:00
}
2007-09-16 15:44:09 +02:00
else if (sscanf(Param, "IPTV|HTTP|%a[^|]|%u", &loc, IpPort) == 2) {
2007-09-16 15:11:19 +02:00
cString addr(loc, true);
2007-09-16 11:38:00 +02:00
*Protocol = pHttpProtocol;
2007-09-16 15:11:19 +02:00
return addr;
2007-09-16 11:38:00 +02:00
}
2007-09-16 15:44:09 +02:00
else if (sscanf(Param, "IPTV|FILE|%a[^|]|%u", &loc, IpPort) == 2) {
2007-09-16 15:38:20 +02:00
cString addr(loc, true);
*Protocol = pFileProtocol;
return addr;
}
2007-09-12 19:28:59 +02:00
return NULL;
}
bool cIptvDevice::ProvidesIptv(const char *Param) const
{
debug("cIptvDevice::ProvidesIptv(%d)\n", deviceIndex);
2007-09-12 19:28:59 +02:00
return (strncmp(Param, "IPTV", 4) == 0);
}
bool cIptvDevice::ProvidesSource(int Source) const
{
debug("cIptvDevice::ProvidesSource(%d)\n", deviceIndex);
return (cSource::IsPlug(Source));
2007-09-12 19:28:59 +02:00
}
bool cIptvDevice::ProvidesTransponder(const cChannel *Channel) const
{
debug("cIptvDevice::ProvidesTransponder(%d)\n", deviceIndex);
return (ProvidesSource(Channel->Source()) && ProvidesIptv(Channel->PluginParam()));
2007-09-12 19:28:59 +02:00
}
bool cIptvDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
{
bool result = false;
bool needsDetachReceivers = false;
debug("cIptvDevice::ProvidesChannel(%d)\n", deviceIndex);
2007-09-12 19:28:59 +02:00
if (ProvidesTransponder(Channel))
result = true;
if (NeedsDetachReceivers)
*NeedsDetachReceivers = needsDetachReceivers;
return result;
}
bool cIptvDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
{
2007-09-14 17:44:25 +02:00
int port;
2007-09-13 20:14:41 +02:00
cString addr;
2007-09-14 17:44:25 +02:00
cIptvProtocolIf *protocol;
2007-09-12 19:28:59 +02:00
debug("cIptvDevice::SetChannelDevice(%d)\n", deviceIndex);
addr = GetChannelSettings(Channel->PluginParam(), &port, &protocol);
if (isempty(addr)) {
error("ERROR: Unrecognized IPTV channel settings: %s", Channel->PluginParam());
return false;
}
pIptvStreamer->Set(addr, port, protocol);
2007-09-12 19:28:59 +02:00
return true;
}
bool cIptvDevice::SetPid(cPidHandle *Handle, int Type, bool On)
{
2007-09-19 20:02:38 +02:00
debug("cIptvDevice::SetPid(%d) Pid=%d Type=%d On=%d\n", deviceIndex, Handle->pid, Type, On);
2007-09-12 19:28:59 +02:00
return true;
}
bool cIptvDevice::DeleteFilter(unsigned int Index)
{
debug("cIptvDevice::DeleteFilter(%d) Index=%d\n", deviceIndex, Index);
if ((Index < eMaxFilterCount) && secfilters[Index]) {
delete secfilters[Index];
secfilters[Index] = NULL;
return true;
}
return false;
}
int cIptvDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
{
// Search the next free filter slot
2007-09-19 20:17:30 +02:00
for (unsigned int i = 0; i < eMaxFilterCount; ++i) {
if (!secfilters[i]) {
debug("cIptvDevice::OpenFilter(%d): Pid=%d Tid=%02X Mask=%02X Index=%d\n", deviceIndex, Pid, Tid, Mask, i);
secfilters[i] = new cIptvSectionFilter(i, deviceIndex, Pid, Tid,
Mask);
return secfilters[i]->GetReadDesc();
2007-09-20 23:15:08 +02:00
}
}
// No free filter slot found
return -1;
}
bool cIptvDevice::CloseFilter(int Handle)
{
debug("cIptvDevice::CloseFilter(%d): %d\n", deviceIndex, Handle);
for (unsigned int i = 0; i < eMaxFilterCount; ++i) {
2007-09-24 18:08:09 +02:00
if (secfilters[i] && Handle == secfilters[i]->GetReadDesc())
return DeleteFilter(i);
}
return false;
}
2007-09-12 19:28:59 +02:00
bool cIptvDevice::OpenDvr(void)
{
debug("cIptvDevice::OpenDvr(%d)\n", deviceIndex);
2007-09-12 19:28:59 +02:00
mutex.Lock();
isPacketDelivered = false;
tsBuffer->Clear();
mutex.Unlock();
2007-09-21 23:50:52 +02:00
ResetBuffering();
2007-09-14 17:44:25 +02:00
pIptvStreamer->Open();
2007-09-12 19:28:59 +02:00
isOpenDvr = true;
return true;
}
void cIptvDevice::CloseDvr(void)
{
debug("cIptvDevice::CloseDvr(%d)\n", deviceIndex);
2007-09-14 17:44:25 +02:00
pIptvStreamer->Close();
2007-09-12 19:28:59 +02:00
isOpenDvr = false;
}
bool cIptvDevice::HasLock(int TimeoutMs)
{
2007-09-21 23:50:52 +02:00
//debug("cIptvDevice::HasLock(%d): %d\n", deviceIndex, TimeoutMs);
return (!IsBuffering());
}
void cIptvDevice::ResetBuffering(void)
{
debug("cIptvDevice::ResetBuffering(%d)\n", deviceIndex);
// pad prefill to multiple of TS_SIZE
tsBufferPrefill = MEGABYTE(IptvConfig.GetTsBufferSize()) *
IptvConfig.GetTsBufferPrefillRatio() / 100;
tsBufferPrefill -= (tsBufferPrefill % TS_SIZE);
}
bool cIptvDevice::IsBuffering(void)
{
//debug("cIptvDevice::IsBuffering(%d): %d\n", deviceIndex);
if (tsBufferPrefill && tsBuffer->Available() < tsBufferPrefill)
2007-09-21 23:50:52 +02:00
return true;
else
tsBufferPrefill = 0;
return false;
}
2007-09-12 19:28:59 +02:00
bool cIptvDevice::GetTSPacket(uchar *&Data)
{
int Count = 0;
//debug("cIptvDevice::GetTSPacket(%d)\n", deviceIndex);
2007-09-21 23:50:52 +02:00
if (!IsBuffering()) {
if (isPacketDelivered) {
tsBuffer->Del(TS_SIZE);
isPacketDelivered = false;
2007-09-12 19:28:59 +02:00
}
2007-09-21 23:50:52 +02:00
uchar *p = tsBuffer->Get(Count);
if (p && Count >= TS_SIZE) {
if (*p != TS_SYNC_BYTE) {
for (int i = 1; i < Count; i++) {
if (p[i] == TS_SYNC_BYTE) {
Count = i;
break;
2007-09-19 20:02:38 +02:00
}
2007-09-21 23:50:52 +02:00
}
tsBuffer->Del(Count);
error("ERROR: skipped %d bytes to sync on TS packet\n", Count);
return false;
}
isPacketDelivered = true;
Data = p;
// Run the data through all filters
2007-09-21 23:50:52 +02:00
for (unsigned int i = 0; i < eMaxFilterCount; ++i) {
if (secfilters[i]) {
secfilters[i]->ProcessData(p);
2007-09-19 20:02:38 +02:00
}
}
2007-09-21 23:50:52 +02:00
return true;
}
2007-09-12 19:28:59 +02:00
}
Data = NULL;
return true;
}