[SCM] vdr-plugin-vnsiserver/master: New upstream version 1.5.1
tiber-guest at users.alioth.debian.org
tiber-guest at users.alioth.debian.org
Fri Nov 4 23:55:56 UTC 2016
The following commit has been merged in the master branch:
commit e52a261265a5b511f284320b885d14501a10855f
Author: Tobias Grimm <etobi at debian.org>
Date: Fri Nov 4 20:48:19 2016 +0100
New upstream version 1.5.1
diff --git a/HISTORY b/HISTORY
index 1df333c..ac60789 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,5 +1,19 @@
VDR Plugin 'vnsiserver' Revision History
----------------------------------------
+2016-09-25: Version 1.5.1
+
+- see github history for fixes
+- added new setup parameter DisableCamBlacklist:
+ avoids a VDR hard-coded 15 seconds timeout if tuning failed due to hard-coded scramble timeout
+
+2016-08-01: Version 1.5.0
+
+- support for vdr 2.3.1
+- add epg search timers
+- support for h265 (hevc)
+- fix PID change
+- fixes and improvements for handling of CAMs
+- see github history for other fixes
2015-09-18: Version 1.3.0
diff --git a/Makefile b/Makefile
index 8f1cb05..660df05 100644
--- a/Makefile
+++ b/Makefile
@@ -36,32 +36,9 @@ APIVERSION = $(shell grep 'define APIVERSION ' $(VDRDIR)/config.h | awk '{ print
NOCONFIG := 1
endif
-# backwards compatibility version < 1.7.34
-API1733 := $(shell if [ "$(APIVERSION)" \< "1.7.34" ]; then echo true; fi; )
-
-ifdef API1733
-
-VDRSRC = $(VDRDIR)
-VDRSRC ?= ../../..
-ifeq ($(strip $(LIBDIR)),)
-LIBDIR = $(VDRSRC)/PLUGINS/lib
-endif
-
-ifndef NOCONFIG
-CXXFLAGS = $(call PKGCFG,cflags)
-CXXFLAGS += -fPIC
-else
--include $(VDRSRC)/Make.global
--include $(VDRSRC)/Make.config
-endif
-
-export CXXFLAGS
-else
-
### Allow user defined options to overwrite defaults:
-include $(PLGCFG)
-endif
### The name of the distribution archive:
@@ -79,6 +56,8 @@ INCLUDES += -I$(VDRSRC)/include
endif
DEFINES += -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' -DVNSI_SERVER_VERSION='"$(VERSION)"'
+CXXFLAGS += -std=c++11
+export CXXFLAGS
ifeq ($(DEBUG),1)
DEFINES += -DDEBUG
@@ -87,10 +66,10 @@ endif
### The object files (add further files here):
OBJS = vnsi.o bitstream.o vnsiclient.o channelscancontrol.o config.o cxsocket.o parser.o parser_AAC.o \
- parser_AC3.o parser_DTS.o parser_h264.o parser_MPEGAudio.o parser_MPEGVideo.o \
+ parser_AC3.o parser_DTS.o parser_h264.o parser_hevc.o parser_MPEGAudio.o parser_MPEGVideo.o \
parser_Subtitle.o parser_Teletext.o streamer.o recplayer.o requestpacket.o responsepacket.o \
vnsiserver.o hash.o recordingscache.o setup.o vnsiosd.o demuxer.o videobuffer.o \
- videoinput.o channelfilter.o status.o
+ videoinput.o channelfilter.o status.o vnsitimer.o
### The main target:
diff --git a/bitstream.c b/bitstream.c
index d0c06f3..60ee244 100644
--- a/bitstream.c
+++ b/bitstream.c
@@ -22,37 +22,62 @@
*
*/
-#include <stdio.h>
-#include <inttypes.h>
#include "bitstream.h"
-cBitstream::cBitstream(uint8_t *data, int bits)
+void cBitstream::skipBits(unsigned int num)
{
- m_data = data;
- m_offset = 0;
- m_len = bits;
- m_error = false;
-}
+ if (m_doEP3)
+ {
+ register unsigned int tmp;
-void cBitstream::setBitstream(uint8_t *data, int bits)
-{
- m_data = data;
- m_offset = 0;
- m_len = bits;
- m_error = false;
-}
+ while (num)
+ {
+ tmp = m_offset >> 3;
+ if (!(m_offset & 7) && (m_data[tmp--] == 3) && (m_data[tmp--] == 0) && (m_data[tmp] == 0))
+ m_offset += 8; // skip EP3 byte
+
+ if (!(m_offset & 7) && (num >= 8)) // byte boundary, speed up things a little bit
+ {
+ m_offset += 8;
+ num -= 8;
+ }
+ else if ((tmp = 8-(m_offset & 7)) <= num) // jump to byte boundary
+ {
+ m_offset += tmp;
+ num -= tmp;
+ }
+ else
+ {
+ m_offset += num;
+ num = 0;
+ }
+
+ if (m_offset >= m_len)
+ {
+ m_error = true;
+ break;
+ }
+ }
+
+ return;
+ }
-void cBitstream::skipBits(int num)
-{
m_offset += num;
}
unsigned int cBitstream::readBits(int num)
{
- int r = 0;
+ unsigned int r = 0;
while(num > 0)
{
+ if (m_doEP3)
+ {
+ size_t tmp = m_offset >> 3;
+ if (!(m_offset & 7) && (m_data[tmp--] == 3) && (m_data[tmp--] == 0) && (m_data[tmp] == 0))
+ m_offset += 8; // skip EP3 byte
+ }
+
if(m_offset >= m_len)
{
m_error = true;
@@ -71,8 +96,8 @@ unsigned int cBitstream::readBits(int num)
unsigned int cBitstream::showBits(int num)
{
- int r = 0;
- int offs = m_offset;
+ unsigned int r = 0;
+ size_t offs = m_offset;
while(num > 0)
{
@@ -118,30 +143,3 @@ signed int cBitstream::readGolombSE()
v = (v + 1) >> 1;
return pos ? v : -v;
}
-
-
-unsigned int cBitstream::remainingBits()
-{
- return m_len - m_offset;
-}
-
-
-void cBitstream::putBits(int val, int num)
-{
- while(num > 0) {
- if(m_offset >= m_len)
- {
- m_error = true;
- return;
- }
-
- num--;
-
- if(val & (1 << num))
- m_data[m_offset / 8] |= 1 << (7 - (m_offset & 7));
- else
- m_data[m_offset / 8] &= ~(1 << (7 - (m_offset & 7)));
-
- m_offset++;
- }
-}
diff --git a/bitstream.h b/bitstream.h
index 4d236b5..c589654 100644
--- a/bitstream.h
+++ b/bitstream.h
@@ -25,28 +25,43 @@
#ifndef VNSI_BITSTREAM_H
#define VNSI_BITSTREAM_H
+#include <stdint.h>
+#include <stddef.h>
+
class cBitstream
{
private:
- uint8_t *m_data;
- int m_offset;
- int m_len;
- bool m_error;
+ uint8_t *const m_data;
+ size_t m_offset = 0;
+ const size_t m_len;
+ bool m_error = false;
+ const bool m_doEP3 = false;
public:
- cBitstream(uint8_t *data, int bits);
+ constexpr cBitstream(uint8_t *data, size_t bits)
+ :m_data(data), m_len(bits)
+ {
+ }
+
+ // this is a bitstream that has embedded emulation_prevention_three_byte
+ // sequences that need to be removed as used in HECV.
+ // Data must start at byte 2
+ constexpr cBitstream(uint8_t *data, size_t bits, bool doEP3)
+ :m_data(data),
+ m_offset(16), // skip header and use as sentinel for EP3 detection
+ m_len(bits),
+ m_doEP3(true)
+ {
+ }
- void setBitstream(uint8_t *data, int bits);
- void skipBits(int num);
+ void skipBits(unsigned int num);
unsigned int readBits(int num);
unsigned int showBits(int num);
unsigned int readBits1() { return readBits(1); }
unsigned int readGolombUE(int maxbits = 32);
- signed int readGolombSE();
- unsigned int remainingBits();
- void putBits(int val, int num);
- int length() { return m_len; }
- bool isError() { return m_error; }
+ signed int readGolombSE();
+ constexpr size_t length() const { return m_len; }
+ constexpr bool isError() const { return m_error; }
};
#endif // VNSI_BITSTREAM_H
diff --git a/channelfilter.c b/channelfilter.c
index a497a40..847bdeb 100644
--- a/channelfilter.c
+++ b/channelfilter.c
@@ -32,7 +32,7 @@
#include <vdr/tools.h>
cVNSIProvider::cVNSIProvider()
- :m_name(""), m_caid(0)
+ :m_caid(0)
{
}
@@ -42,10 +42,12 @@ cVNSIProvider::cVNSIProvider(std::string name, int caid)
{
};
-bool cVNSIProvider::operator==(const cVNSIProvider &rhs)
+bool cVNSIProvider::operator==(const cVNSIProvider &rhs) const
{
if (rhs.m_caid != m_caid)
return false;
+ if (m_name.empty())
+ return false;
if (rhs.m_name.compare(m_name) != 0)
return false;
return true;
@@ -73,8 +75,6 @@ void cVNSIChannelFilter::Load()
cString filename;
std::string line;
std::ifstream rfile;
- cVNSIProvider provider;
- std::vector<cVNSIProvider>::iterator p_it;
filename = cString::sprintf("%s/videowhitelist.vnsi", *VNSIServerConfig.ConfigDirectory);
m_providersVideo.clear();
@@ -83,23 +83,21 @@ void cVNSIChannelFilter::Load()
{
while(std::getline(rfile,line))
{
+ cVNSIProvider provider;
size_t pos = line.find("|");
if(pos == line.npos)
{
provider.m_name = line;
- provider.m_caid = 0;
}
else
{
- provider.m_name = line.substr(0, pos);
- std::string tmp = line.substr(pos+1);
- char *pend;
- provider.m_caid = strtol(tmp.c_str(), &pend, 10);
+ provider.m_name.assign(line, 0, pos);
+ provider.m_caid = strtol(line.c_str() + pos + 1, nullptr, 10);
}
- p_it = std::find(m_providersVideo.begin(), m_providersVideo.end(), provider);
+ auto p_it = std::find(m_providersVideo.begin(), m_providersVideo.end(), provider);
if(p_it == m_providersVideo.end())
{
- m_providersVideo.push_back(provider);
+ m_providersVideo.emplace_back(std::move(provider));
}
}
rfile.close();
@@ -112,23 +110,21 @@ void cVNSIChannelFilter::Load()
{
while(std::getline(rfile,line))
{
- unsigned int pos = line.find("|");
+ cVNSIProvider provider;
+ auto pos = line.find("|");
if(pos == line.npos)
{
provider.m_name = line;
- provider.m_caid = 0;
}
else
{
- provider.m_name = line.substr(0, pos);
- std::string tmp = line.substr(pos+1);
- char *pend;
- provider.m_caid = strtol(tmp.c_str(), &pend, 10);
+ provider.m_name.assign(line, 0, pos);
+ provider.m_caid = strtol(line.c_str() + pos + 1, nullptr, 10);
}
- p_it = std::find(m_providersRadio.begin(), m_providersRadio.end(), provider);
+ auto p_it = std::find(m_providersRadio.begin(), m_providersRadio.end(), provider);
if(p_it == m_providersRadio.end())
{
- m_providersRadio.push_back(provider);
+ m_providersRadio.emplace_back(std::move(provider));
}
}
rfile.close();
@@ -141,9 +137,8 @@ void cVNSIChannelFilter::Load()
{
while(getline(rfile,line))
{
- char *pend;
- int id = strtol(line.c_str(), &pend, 10);
- m_channelsVideo.push_back(id);
+ int id = strtol(line.c_str(), nullptr, 10);
+ m_channelsVideo.insert(id);
}
rfile.close();
}
@@ -155,9 +150,8 @@ void cVNSIChannelFilter::Load()
{
while(getline(rfile,line))
{
- char *pend;
- int id = strtol(line.c_str(), &pend, 10);
- m_channelsRadio.push_back(id);
+ int id = strtol(line.c_str(), nullptr, 10);
+ m_channelsRadio.insert(id);
}
rfile.close();
}
@@ -169,8 +163,6 @@ void cVNSIChannelFilter::StoreWhitelist(bool radio)
cString filename;
std::ofstream wfile;
- cVNSIProvider provider;
- std::vector<cVNSIProvider>::iterator p_it;
std::vector<cVNSIProvider> *whitelist;
if (radio)
@@ -187,15 +179,9 @@ void cVNSIChannelFilter::StoreWhitelist(bool radio)
wfile.open(filename);
if(wfile.is_open())
{
- std::string tmp;
- char buf[16];
- for(p_it=whitelist->begin(); p_it!=whitelist->end(); ++p_it)
+ for (const auto i : *whitelist)
{
- tmp = p_it->m_name;
- tmp += "|";
- sprintf(buf, "%d\n", p_it->m_caid);
- tmp += buf;
- wfile << tmp;
+ wfile << i.m_name << '|' << i.m_caid << '\n';
}
wfile.close();
}
@@ -209,9 +195,7 @@ void cVNSIChannelFilter::StoreBlacklist(bool radio)
cString filename;
std::ofstream wfile;
- cVNSIProvider provider;
- std::vector<int>::iterator it;
- std::vector<int> *blacklist;
+ std::set<int> *blacklist;
if (radio)
{
@@ -227,13 +211,9 @@ void cVNSIChannelFilter::StoreBlacklist(bool radio)
wfile.open(filename);
if(wfile.is_open())
{
- std::string tmp;
- char buf[16];
- for(it=blacklist->begin(); it!=blacklist->end(); ++it)
+ for (const auto i : *blacklist)
{
- sprintf(buf, "%d\n", *it);
- tmp = buf;
- wfile << tmp;
+ wfile << i << '\n';
}
wfile.close();
}
@@ -244,7 +224,6 @@ void cVNSIChannelFilter::StoreBlacklist(bool radio)
bool cVNSIChannelFilter::IsWhitelist(const cChannel &channel)
{
cVNSIProvider provider;
- std::vector<cVNSIProvider>::iterator p_it;
std::vector<cVNSIProvider> *providers;
provider.m_name = channel.Provider();
@@ -259,7 +238,7 @@ bool cVNSIChannelFilter::IsWhitelist(const cChannel &channel)
if (channel.Ca(0) == 0)
{
provider.m_caid = 0;
- p_it = std::find(providers->begin(), providers->end(), provider);
+ auto p_it = std::find(providers->begin(), providers->end(), provider);
if(p_it!=providers->end())
return true;
else
@@ -271,7 +250,7 @@ bool cVNSIChannelFilter::IsWhitelist(const cChannel &channel)
while((caid = channel.Ca(idx)) != 0)
{
provider.m_caid = caid;
- p_it = std::find(providers->begin(), providers->end(), provider);
+ auto p_it = std::find(providers->begin(), providers->end(), provider);
if(p_it!=providers->end())
return true;
@@ -290,16 +269,15 @@ bool cVNSIChannelFilter::PassFilter(const cChannel &channel)
if (!IsWhitelist(channel))
return false;
- std::vector<int>::iterator it;
if (IsRadio(&channel))
{
- it = std::find(m_channelsRadio.begin(), m_channelsRadio.end(), CreateChannelUID(&channel));
+ auto it = std::find(m_channelsRadio.begin(), m_channelsRadio.end(), CreateChannelUID(&channel));
if(it!=m_channelsRadio.end())
return false;
}
else
{
- it = std::find(m_channelsVideo.begin(), m_channelsVideo.end(), CreateChannelUID(&channel));
+ auto it = std::find(m_channelsVideo.begin(), m_channelsVideo.end(), CreateChannelUID(&channel));
if(it!=m_channelsVideo.end())
return false;
}
@@ -309,18 +287,30 @@ bool cVNSIChannelFilter::PassFilter(const cChannel &channel)
void cVNSIChannelFilter::SortChannels()
{
+#if VDRVERSNUM >= 20301
+ LOCK_CHANNELS_WRITE;
+ for (cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel))
+#else
Channels.IncBeingEdited();
Channels.Lock(true);
-
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
+#endif
{
if(!PassFilter(*channel))
{
+#if VDRVERSNUM >= 20301
+ for (cChannel *whitechan = Channels->Next(channel); whitechan; whitechan = Channels->Next(whitechan))
+#else
for (cChannel *whitechan = Channels.Next(channel); whitechan; whitechan = Channels.Next(whitechan))
+#endif
{
if(PassFilter(*whitechan))
{
+#if VDRVERSNUM >= 20301
+ Channels->Move(whitechan, channel);
+#else
Channels.Move(whitechan, channel);
+#endif
channel = whitechan;
break;
}
@@ -328,9 +318,13 @@ void cVNSIChannelFilter::SortChannels()
}
}
+#if VDRVERSNUM >= 20301
+ Channels->SetModifiedByUser();
+#else
Channels.SetModified(true);
Channels.Unlock();
Channels.DecBeingEdited();
+#endif
}
cVNSIChannelFilter VNSIChannelFilter;
diff --git a/channelfilter.h b/channelfilter.h
index 58dc659..8b9554b 100644
--- a/channelfilter.h
+++ b/channelfilter.h
@@ -26,6 +26,7 @@
#include <string>
#include <vector>
+#include <set>
#include <vdr/thread.h>
#include <vdr/channels.h>
@@ -34,7 +35,7 @@ class cVNSIProvider
public:
cVNSIProvider();
cVNSIProvider(std::string name, int caid);
- bool operator==(const cVNSIProvider &rhs);
+ bool operator==(const cVNSIProvider &rhs) const;
std::string m_name;
int m_caid;
};
@@ -51,8 +52,8 @@ public:
static bool IsRadio(const cChannel* channel);
std::vector<cVNSIProvider> m_providersVideo;
std::vector<cVNSIProvider> m_providersRadio;
- std::vector<int> m_channelsVideo;
- std::vector<int> m_channelsRadio;
+ std::set<int> m_channelsVideo;
+ std::set<int> m_channelsRadio;
cMutex m_Mutex;
};
diff --git a/channelscancontrol.c b/channelscancontrol.c
index eac2eef..7ca2d4c 100644
--- a/channelscancontrol.c
+++ b/channelscancontrol.c
@@ -22,12 +22,12 @@
*
*/
-#include <vdr/menu.h>
-#include <vdr/status.h>
-
#include "channelscancontrol.h"
#include "vnsiclient.h"
+#include <vdr/menu.h>
+#include <vdr/status.h>
+
using namespace WIRBELSCAN_SERVICE;
/*!
@@ -54,8 +54,6 @@ using namespace WIRBELSCAN_SERVICE;
#define SCANDONE 2
#define CHECKVERSION(a,b,c) p=strchr((char *) m_scanInformation->a,'#') + 1; sscanf(p,"%d ",&version); if (version < b) c = true;
#define CHECKLIMITS(a,v,_min,_max,_def) a=v; if ((a<_min) || (a>_max)) a=_def;
-#define freeAndNull(p) if(p) { free(p); p=NULL; }
-#define deleteAndNull(p) if(p) { delete(p); p=NULL; }
CScanControl::CScanControl(cVNSIClient *client)
: m_client(client),
@@ -71,10 +69,9 @@ CScanControl::CScanControl(cVNSIClient *client)
CScanControl::~CScanControl()
{
- if (m_scanInformation)
- delete m_scanInformation;
- freeAndNull(m_cbuf);
- freeAndNull(m_sbuf);
+ delete m_scanInformation;
+ free(m_cbuf);
+ free(m_sbuf);
}
bool CScanControl::IsSupported()
@@ -198,7 +195,14 @@ bool CScanControl::StartScan(sScanServiceData &data)
m_setup.scanflags |= data.scan_fta ? SCAN_FTA : 0;
m_setup.scanflags |= data.scan_hd ? SCAN_HD : 0;
+#if VDRVERSNUM >= 20301
+ {
+ LOCK_CHANNELS_READ;
+ m_lastChannelCount = Channels->Count();
+ }
+#else
m_lastChannelCount = Channels.Count();
+#endif
char *s;
if (asprintf(&s, "%sSet%s", SPlugin, SSetup) < 0)
@@ -291,12 +295,36 @@ void CScanControl::Action(void)
m_client->processSCAN_SetDeviceInfo(m_scanStatus.curr_device);
m_client->processSCAN_SetTransponder(m_scanStatus.transponder);
- for (int i = 0; i < Channels.Count()-m_lastChannelCount; i++)
+
+ int noOfChannels;
+#if VDRVERSNUM >= 20301
+ {
+ LOCK_CHANNELS_READ;
+ noOfChannels = Channels->Count();
+ }
+#else
+ noOfChannels = Channels.Count();
+#endif
+
+ for (int i = 0; i < noOfChannels-m_lastChannelCount; i++)
{
+#if VDRVERSNUM >= 20301
+ LOCK_CHANNELS_READ;
+ const cChannel *channel = Channels->GetByNumber(Channels->Count()-i);
+#else
cChannel *channel = Channels.GetByNumber(Channels.Count()-i);
+#endif
m_client->processSCAN_NewChannel(channel->Name(), channel->Vpid() == 0, channel->Ca() > 0, channel->Vtype() > 2);
}
- m_lastChannelCount = Channels.Count();
+
+#if VDRVERSNUM >= 20301
+ {
+ LOCK_CHANNELS_READ;
+ m_lastChannelCount = Channels->Count();
+ }
+#else
+ m_lastChannelCount = Channels.Count();
+#endif
if (m_scanStatus.status == StatusStopped)
{
diff --git a/config.h b/config.h
index 933bf96..fa02c4e 100644
--- a/config.h
+++ b/config.h
@@ -34,19 +34,13 @@
// log output configuration
#ifdef CONSOLEDEBUG
-#define DEBUGLOG(x...) printf("VNSI: "x)
-#elif defined DEBUG
-#define DEBUGLOG(x...) dsyslog("VNSI: "x)
+#define INFOLOG(x...) printf("VNSI: " x)
+#define ERRORLOG(x...) printf("VNSI-Error: " x)
+#define DEBUGLOG(x...) printf("VNSI-Debug: " x)
#else
-#define DEBUGLOG(x...)
-#endif
-
-#ifdef CONSOLEDEBUG
-#define INFOLOG(x...) printf("VNSI: "x)
-#define ERRORLOG(x...) printf("VNSI-Error: "x)
-#else
-#define INFOLOG(x...) isyslog("VNSI: "x)
-#define ERRORLOG(x...) esyslog("VNSI-Error: "x)
+#define INFOLOG(x...) isyslog("VNSI: " x)
+#define ERRORLOG(x...) esyslog("VNSI-Error: " x)
+#define DEBUGLOG(x...) (SysLogLevel > 3) ? dsyslog("VNSI-Debug: " x) : void()
#endif
// default settings
@@ -69,6 +63,7 @@
#define ERROR_PES_SCRAMBLE 0x02
#define ERROR_PES_STARTCODE 0x04
#define ERROR_DEMUX_NODATA 0x10
+#define ERROR_CAM_ERROR 0x20
class cVNSIServerConfig
{
diff --git a/cxsocket.c b/cxsocket.c
index e50bfab..e9b5cad 100644
--- a/cxsocket.c
+++ b/cxsocket.c
@@ -31,6 +31,9 @@
*
*/
+#include "cxsocket.h"
+#include "config.h"
+
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
@@ -46,33 +49,25 @@
#include <vdr/config.h>
#include <vdr/tools.h>
-#include "config.h"
-#include "cxsocket.h"
-
#ifndef MSG_MORE
#define MSG_MORE 0
#endif
-cxSocket::~cxSocket()
+cxSocket::cxSocket(int h)
+ :m_fd(h),
+ m_pollerRead(m_fd),
+ m_pollerWrite(m_fd, true)
{
- close();
- delete m_pollerRead;
- delete m_pollerWrite;
}
-void cxSocket::close() {
- if(m_fd >= 0) {
- ::close(m_fd);
- m_fd=-1;
- }
+cxSocket::~cxSocket()
+{
+ close(m_fd);
}
void cxSocket::Shutdown()
{
- if(m_fd >= 0)
- {
- ::shutdown(m_fd, SHUT_RD);
- }
+ ::shutdown(m_fd, SHUT_RD);
}
void cxSocket::LockWrite()
@@ -89,17 +84,14 @@ ssize_t cxSocket::write(const void *buffer, size_t size, int timeout_ms, bool mo
{
cMutexLock CmdLock(&m_MutexWrite);
- if(m_fd == -1)
- return -1;
-
ssize_t written = (ssize_t)size;
const unsigned char *ptr = (const unsigned char *)buffer;
while (size > 0)
{
- if(!m_pollerWrite->Poll(timeout_ms))
+ if(!m_pollerWrite.Poll(timeout_ms))
{
- ERRORLOG("cxSocket::write: poll() failed");
+ ERRORLOG("cxSocket::write(fd=%d): poll() failed", m_fd);
return written-size;
}
@@ -109,11 +101,11 @@ ssize_t cxSocket::write(const void *buffer, size_t size, int timeout_ms, bool mo
{
if (errno == EINTR || errno == EAGAIN)
{
- DEBUGLOG("cxSocket::write: EINTR during write(), retrying");
+ DEBUGLOG("cxSocket::write(fd=%d): EINTR during write(), retrying", m_fd);
continue;
}
else if (errno != EPIPE)
- ERRORLOG("cxSocket::write: write() error");
+ ERRORLOG("cxSocket::write(fd=%d): write() error", m_fd);
return p;
}
@@ -128,17 +120,14 @@ ssize_t cxSocket::read(void *buffer, size_t size, int timeout_ms)
{
int retryCounter = 0;
- if(m_fd == -1)
- return -1;
-
ssize_t missing = (ssize_t)size;
unsigned char *ptr = (unsigned char *)buffer;
while (missing > 0)
{
- if(!m_pollerRead->Poll(timeout_ms))
+ if(!m_pollerRead.Poll(timeout_ms))
{
- ERRORLOG("cxSocket::read: poll() failed at %d/%d", (int)(size-missing), (int)size);
+ ERRORLOG("cxSocket::read(fd=%d): poll() failed at %d/%d", m_fd, (int)(size-missing), (int)size);
return size-missing;
}
@@ -148,16 +137,16 @@ ssize_t cxSocket::read(void *buffer, size_t size, int timeout_ms)
{
if (retryCounter < 10 && (errno == EINTR || errno == EAGAIN))
{
- DEBUGLOG("cxSocket::read: EINTR/EAGAIN during read(), retrying");
+ DEBUGLOG("cxSocket::read(fd=%d): EINTR/EAGAIN during read(), retrying", m_fd);
retryCounter++;
continue;
}
- ERRORLOG("cxSocket::read: read() error at %d/%d", (int)(size-missing), (int)size);
+ ERRORLOG("cxSocket::read(fd=%d): read() error at %d/%d", m_fd, (int)(size-missing), (int)size);
return 0;
}
else if (p == 0)
{
- INFOLOG("cxSocket::read: eof, connection closed");
+ INFOLOG("cxSocket::read(fd=%d): eof, connection closed", m_fd);
return 0;
}
@@ -169,17 +158,6 @@ ssize_t cxSocket::read(void *buffer, size_t size, int timeout_ms)
return size;
}
-void cxSocket::SetHandle(int h) {
- if(h != m_fd) {
- close();
- m_fd = h;
- delete m_pollerRead;
- delete m_pollerWrite;
- m_pollerRead = new cPoller(m_fd);
- m_pollerWrite = new cPoller(m_fd, true);
- }
-}
-
char *cxSocket::ip2txt(uint32_t ip, unsigned int port, char *str)
{
// inet_ntoa is not thread-safe (?)
diff --git a/cxsocket.h b/cxsocket.h
index d144411..d8f7eab 100644
--- a/cxsocket.h
+++ b/cxsocket.h
@@ -39,17 +39,18 @@
class cxSocket
{
- private:
- int m_fd;
+ const int m_fd;
cMutex m_MutexWrite;
- cPoller *m_pollerRead;
- cPoller *m_pollerWrite;
+ cPoller m_pollerRead;
+ cPoller m_pollerWrite;
public:
- cxSocket() : m_fd(-1), m_pollerRead(NULL), m_pollerWrite(NULL) {}
+ cxSocket(int h);
~cxSocket();
- void SetHandle(int h);
- void close(void);
+
+ cxSocket(const cxSocket &) = delete;
+ cxSocket &operator=(const cxSocket &) = delete;
+
void Shutdown(void);
void LockWrite();
void UnlockWrite();
diff --git a/demuxer.c b/demuxer.c
index 94859ec..3521656 100644
--- a/demuxer.c
+++ b/demuxer.c
@@ -31,10 +31,34 @@
#include <vdr/channels.h>
#include <libsi/si.h>
+cStreamInfo::cStreamInfo()
+{
+
+}
+
+cStreamInfo::cStreamInfo(const cStreamInfo& info)
+{
+ pID = info.pID;
+ type = info.type;
+ content = info.content;
+ subtitlingType = info.subtitlingType;
+ compositionPageId = info.compositionPageId;
+ ancillaryPageId = info.ancillaryPageId;
+ handleRDS = info.handleRDS;
+ SetLanguage(info.language);
+}
+
+void cStreamInfo::SetLanguage(const char* lang)
+{
+ language[0] = lang[0];
+ language[1] = lang[1];
+ language[2] = lang[2];
+ language[3] = 0;
+}
+
cVNSIDemuxer::cVNSIDemuxer(bool bAllowRDS)
: m_bAllowRDS(bAllowRDS)
{
- m_OldPmtVersion = -1;
}
cVNSIDemuxer::~cVNSIDemuxer()
@@ -48,7 +72,6 @@ void cVNSIDemuxer::Open(const cChannel &channel, cVideoBuffer *videoBuffer)
m_CurrentChannel = channel;
m_VideoBuffer = videoBuffer;
- m_OldPmtVersion = -1;
if (m_CurrentChannel.Vpid())
m_WaitIFrame = true;
@@ -61,16 +84,17 @@ void cVNSIDemuxer::Open(const cChannel &channel, cVideoBuffer *videoBuffer)
m_MuxPacketSerial = 0;
m_Error = ERROR_DEMUX_NODATA;
m_SetRefTime = true;
+ m_seenFirstPacket = false;
}
void cVNSIDemuxer::Close()
{
cMutexLock lock(&m_Mutex);
- for (std::list<cTSStream*>::iterator it = m_Streams.begin(); it != m_Streams.end(); ++it)
+ for (auto *i : m_Streams)
{
- DEBUGLOG("Deleting stream parser for pid=%i and type=%i", (*it)->GetPID(), (*it)->Type());
- delete (*it);
+ DEBUGLOG("Deleting stream parser for pid=%i and type=%i", i->GetPID(), i->Type());
+ delete i;
}
m_Streams.clear();
m_StreamInfos.clear();
@@ -84,6 +108,9 @@ int cVNSIDemuxer::Read(sStreamPacket *packet, sStreamPacket *packet_side_data)
cMutexLock lock(&m_Mutex);
+ if (!m_CurrentChannel.Vpid())
+ m_WaitIFrame = false;
+
// clear packet
if (!packet)
return -1;
@@ -118,18 +145,14 @@ int cVNSIDemuxer::Read(sStreamPacket *packet, sStreamPacket *packet_side_data)
m_PatPmtParser.ParsePmt(buf, TS_SIZE);
if (m_PatPmtParser.GetVersions(patVersion, pmtVersion))
{
- if (pmtVersion != m_OldPmtVersion)
+ cChannel pmtChannel(m_CurrentChannel);
+ SetChannelPids(&pmtChannel, &m_PatPmtParser);
+ SetChannelStreamInfos(&pmtChannel);
+ m_PatPmtParser.Reset();
+ if (EnsureParsers())
{
- cChannel pmtChannel(m_CurrentChannel);
- SetChannelPids(&pmtChannel, &m_PatPmtParser);
- SetChannelStreams(&pmtChannel);
- m_PatPmtParser.Reset();
- m_OldPmtVersion = pmtVersion;
- if (EnsureParsers())
- {
- packet->pmtChange = true;
- return 1;
- }
+ packet->pmtChange = true;
+ return 1;
}
}
}
@@ -139,6 +162,7 @@ int cVNSIDemuxer::Read(sStreamPacket *packet, sStreamPacket *packet_side_data)
if (error == 0)
{
m_WaitIFrame = false;
+ m_seenFirstPacket = true;
packet->serial = m_MuxPacketSerial;
if (m_SetRefTime)
@@ -152,6 +176,15 @@ int cVNSIDemuxer::Read(sStreamPacket *packet, sStreamPacket *packet_side_data)
else if (error < 0)
{
m_Error |= abs(error);
+ if (m_Error & ERROR_PES_SCRAMBLE)
+ {
+ if (m_seenFirstPacket)
+ {
+ ResetParsers();
+ m_Error |= ERROR_CAM_ERROR;
+ m_WaitIFrame = true;
+ }
+ }
}
}
@@ -362,107 +395,107 @@ cTSStream *cVNSIDemuxer::GetNextStream()
cTSStream *cVNSIDemuxer::FindStream(int Pid)
{
- for (std::list<cTSStream*>::iterator it = m_Streams.begin(); it != m_Streams.end(); ++it)
+ for (auto *i : m_Streams)
{
- if (Pid == (*it)->GetPID())
- return *it;
+ if (Pid == i->GetPID())
+ return i;
}
return NULL;
}
void cVNSIDemuxer::ResetParsers()
{
- for (std::list<cTSStream*>::iterator it = m_Streams.begin(); it != m_Streams.end(); ++it)
+ for (auto *i : m_Streams)
{
- (*it)->ResetParser();
+ i->ResetParser();
}
+ m_seenFirstPacket = false;
}
-void cVNSIDemuxer::AddStreamInfo(sStreamInfo &stream)
+static bool Contains(const std::list<cStreamInfo> &list, int pID, eStreamType type)
{
- m_StreamInfos.push_back(stream);
+ for (const auto &i : list)
+ if (i.pID == pID && i.type == type)
+ return true;
+
+ return false;
}
bool cVNSIDemuxer::EnsureParsers()
{
bool streamChange = false;
- std::list<cTSStream*>::iterator it = m_Streams.begin();
+ auto it = m_Streams.begin();
while (it != m_Streams.end())
{
- std::list<sStreamInfo>::iterator its;
- for (its = m_StreamInfos.begin(); its != m_StreamInfos.end(); ++its)
- {
- if ((its->pID == (*it)->GetPID()) && (its->type == (*it)->Type()))
- {
- break;
- }
- }
- if (its == m_StreamInfos.end())
+ if (!Contains(m_StreamInfos, (*it)->GetPID(), (*it)->Type()))
{
INFOLOG("Deleting stream for pid=%i and type=%i", (*it)->GetPID(), (*it)->Type());
- m_Streams.erase(it);
- it = m_Streams.begin();
+ it = m_Streams.erase(it);
streamChange = true;
}
else
++it;
}
- for (std::list<sStreamInfo>::iterator it = m_StreamInfos.begin(); it != m_StreamInfos.end(); ++it)
+ for (const auto &i : m_StreamInfos)
{
- cTSStream *stream = FindStream(it->pID);
+ cTSStream *stream = FindStream(i.pID);
if (stream)
{
// TODO: check for change in lang
- stream->SetLanguage(it->language);
+ stream->SetLanguage(i.language);
continue;
}
- if (it->type == stH264)
+ if (i.type == stH264)
+ {
+ stream = new cTSStream(stH264, i.pID, &m_PtsWrap);
+ }
+ else if (i.type == stHEVC)
{
- stream = new cTSStream(stH264, it->pID, &m_PtsWrap);
+ stream = new cTSStream(stHEVC, i.pID, &m_PtsWrap);
}
- else if (it->type == stMPEG2VIDEO)
+ else if (i.type == stMPEG2VIDEO)
{
- stream = new cTSStream(stMPEG2VIDEO, it->pID, &m_PtsWrap);
+ stream = new cTSStream(stMPEG2VIDEO, i.pID, &m_PtsWrap);
}
- else if (it->type == stMPEG2AUDIO)
+ else if (i.type == stMPEG2AUDIO)
{
- stream = new cTSStream(stMPEG2AUDIO, it->pID, &m_PtsWrap, it->handleRDS);
- stream->SetLanguage(it->language);
+ stream = new cTSStream(stMPEG2AUDIO, i.pID, &m_PtsWrap, i.handleRDS);
+ stream->SetLanguage(i.language);
}
- else if (it->type == stAACADTS)
+ else if (i.type == stAACADTS)
{
- stream = new cTSStream(stAACADTS, it->pID, &m_PtsWrap);
- stream->SetLanguage(it->language);
+ stream = new cTSStream(stAACADTS, i.pID, &m_PtsWrap);
+ stream->SetLanguage(i.language);
}
- else if (it->type == stAACLATM)
+ else if (i.type == stAACLATM)
{
- stream = new cTSStream(stAACLATM, it->pID, &m_PtsWrap);
- stream->SetLanguage(it->language);
+ stream = new cTSStream(stAACLATM, i.pID, &m_PtsWrap);
+ stream->SetLanguage(i.language);
}
- else if (it->type == stAC3)
+ else if (i.type == stAC3)
{
- stream = new cTSStream(stAC3, it->pID, &m_PtsWrap);
- stream->SetLanguage(it->language);
+ stream = new cTSStream(stAC3, i.pID, &m_PtsWrap);
+ stream->SetLanguage(i.language);
}
- else if (it->type == stEAC3)
+ else if (i.type == stEAC3)
{
- stream = new cTSStream(stEAC3, it->pID, &m_PtsWrap);
- stream->SetLanguage(it->language);
+ stream = new cTSStream(stEAC3, i.pID, &m_PtsWrap);
+ stream->SetLanguage(i.language);
}
- else if (it->type == stDVBSUB)
+ else if (i.type == stDVBSUB)
{
- stream = new cTSStream(stDVBSUB, it->pID, &m_PtsWrap);
- stream->SetLanguage(it->language);
+ stream = new cTSStream(stDVBSUB, i.pID, &m_PtsWrap);
+ stream->SetLanguage(i.language);
#if APIVERSNUM >= 10709
- stream->SetSubtitlingDescriptor(it->subtitlingType, it->compositionPageId, it->ancillaryPageId);
+ stream->SetSubtitlingDescriptor(i.subtitlingType, i.compositionPageId, i.ancillaryPageId);
#endif
}
- else if (it->type == stTELETEXT)
+ else if (i.type == stTELETEXT)
{
- stream = new cTSStream(stTELETEXT, it->pID, &m_PtsWrap);
+ stream = new cTSStream(stTELETEXT, i.pID, &m_PtsWrap);
}
else
continue;
@@ -476,9 +509,11 @@ bool cVNSIDemuxer::EnsureParsers()
return streamChange;
}
-void cVNSIDemuxer::SetChannelStreams(const cChannel *channel)
+void cVNSIDemuxer::SetChannelStreamInfos(const cChannel *channel)
{
- sStreamInfo newStream;
+ m_StreamInfos.clear();
+
+ cStreamInfo newStream;
bool containsVideo = false;
int index = 0;
if (channel->Vpid())
@@ -487,11 +522,13 @@ void cVNSIDemuxer::SetChannelStreams(const cChannel *channel)
#if APIVERSNUM >= 10701
if (channel->Vtype() == 0x1B)
newStream.type = stH264;
+ else if (channel->Vtype() == 0x24)
+ newStream.type = stHEVC;
else
#endif
newStream.type = stMPEG2VIDEO;
- AddStreamInfo(newStream);
+ m_StreamInfos.push_back(newStream);
containsVideo = true;
}
@@ -499,17 +536,12 @@ void cVNSIDemuxer::SetChannelStreams(const cChannel *channel)
index = 0;
for ( ; *DPids; DPids++)
{
- if (!FindStream(*DPids))
- {
- newStream.pID = *DPids;
- newStream.type = stAC3;
-#if APIVERSNUM >= 10715
- if (channel->Dtype(index) == SI::EnhancedAC3DescriptorTag)
- newStream.type = stEAC3;
-#endif
- newStream.SetLanguage(channel->Dlang(index));
- AddStreamInfo(newStream);
- }
+ newStream.pID = *DPids;
+ newStream.type = stAC3;
+ if (channel->Dtype(index) == SI::EnhancedAC3DescriptorTag)
+ newStream.type = stEAC3;
+ newStream.SetLanguage(channel->Dlang(index));
+ m_StreamInfos.push_back(newStream);
index++;
}
@@ -517,20 +549,15 @@ void cVNSIDemuxer::SetChannelStreams(const cChannel *channel)
index = 0;
for ( ; *APids; APids++)
{
- if (!FindStream(*APids))
- {
- newStream.pID = *APids;
- newStream.type = stMPEG2AUDIO;
-#if APIVERSNUM >= 10715
- if (channel->Atype(index) == 0x0F)
- newStream.type = stAACADTS;
- else if (channel->Atype(index) == 0x11)
- newStream.type = stAACLATM;
-#endif
- newStream.handleRDS = m_bAllowRDS && newStream.type == stMPEG2AUDIO && !containsVideo ? true : false; // Relevant for RDS, if present only on mpeg 2 audio, use only if RDS is allowed
- newStream.SetLanguage(channel->Alang(index));
- AddStreamInfo(newStream);
- }
+ newStream.pID = *APids;
+ newStream.type = stMPEG2AUDIO;
+ if (channel->Atype(index) == 0x0F)
+ newStream.type = stAACADTS;
+ else if (channel->Atype(index) == 0x11)
+ newStream.type = stAACLATM;
+ newStream.handleRDS = m_bAllowRDS && newStream.type == stMPEG2AUDIO && !containsVideo ? true : false; // Relevant for RDS, if present only on mpeg 2 audio, use only if RDS is allowed
+ newStream.SetLanguage(channel->Alang(index));
+ m_StreamInfos.push_back(newStream);
index++;
}
@@ -540,27 +567,22 @@ void cVNSIDemuxer::SetChannelStreams(const cChannel *channel)
index = 0;
for ( ; *SPids; SPids++)
{
- if (!FindStream(*SPids))
- {
- newStream.pID = *SPids;
- newStream.type = stDVBSUB;
- newStream.SetLanguage(channel->Slang(index));
-#if APIVERSNUM >= 10709
- newStream.subtitlingType = channel->SubtitlingType(index);
- newStream.compositionPageId = channel->CompositionPageId(index);
- newStream.ancillaryPageId = channel->AncillaryPageId(index);
-#endif
- AddStreamInfo(newStream);
- }
- index++;
+ newStream.pID = *SPids;
+ newStream.type = stDVBSUB;
+ newStream.SetLanguage(channel->Slang(index));
+ newStream.subtitlingType = channel->SubtitlingType(index);
+ newStream.compositionPageId = channel->CompositionPageId(index);
+ newStream.ancillaryPageId = channel->AncillaryPageId(index);
+ m_StreamInfos.push_back(newStream);
}
+ index++;
}
if (channel->Tpid())
{
newStream.pID = channel->Tpid();
newStream.type = stTELETEXT;
- AddStreamInfo(newStream);
+ m_StreamInfos.push_back(newStream);
}
}
@@ -571,9 +593,9 @@ void cVNSIDemuxer::SetChannelPids(cChannel *channel, cPatPmtParser *patPmtParser
int Dpids[MAXDPIDS + 1] = { 0 };
int Dtypes[MAXDPIDS + 1] = { 0 };
int Spids[MAXSPIDS + 1] = { 0 };
- char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
- char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
- char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
+ char ALangs[MAXAPIDS][MAXLANGCODE2] = { 0 };
+ char DLangs[MAXDPIDS][MAXLANGCODE2] = { 0 };
+ char SLangs[MAXSPIDS][MAXLANGCODE2] = { 0 };
int index = 0;
const int *aPids = patPmtParser->Apids();
@@ -625,7 +647,7 @@ bool cVNSIDemuxer::GetTimeAtPos(off_t *pos, int64_t *time)
m_VideoBuffer->SetPos(*pos);
ResetParsers();
- while (len = m_VideoBuffer->Read(&buf, TS_SIZE, m_endTime, m_wrapTime) == TS_SIZE)
+ while ((len = m_VideoBuffer->Read(&buf, TS_SIZE, m_endTime, m_wrapTime)) == TS_SIZE)
{
ts_pid = TsPid(buf);
if (stream = FindStream(ts_pid))
diff --git a/demuxer.h b/demuxer.h
index fe83f02..73be2bd 100644
--- a/demuxer.h
+++ b/demuxer.h
@@ -33,23 +33,22 @@ class cChannel;
class cPatPmtParser;
class cVideoBuffer;
-struct sStreamInfo
+class cStreamInfo
{
- int pID;
- eStreamType type;
+public:
+ cStreamInfo();
+ cStreamInfo(const cStreamInfo& info);
+ cStreamInfo& operator=(const cStreamInfo& info) = delete;
+ void SetLanguage(const char* lang);
+
+ int pID = 0;
+ eStreamType type = eStreamType::stNone;
eStreamContent content;
- char language[MAXLANGCODE2];
+ char language[MAXLANGCODE2] = { 0 };
int subtitlingType;
int compositionPageId;
int ancillaryPageId;
- bool handleRDS;
- void SetLanguage(const char* lang)
- {
- language[0] = lang[0];
- language[1] = lang[1];
- language[2] = lang[2];
- language[3] = 0;
- }
+ bool handleRDS = false;
};
class cVNSIDemuxer
@@ -57,6 +56,10 @@ class cVNSIDemuxer
public:
cVNSIDemuxer(bool bAllowRDS);
virtual ~cVNSIDemuxer();
+
+ cVNSIDemuxer(const cVNSIDemuxer &) = delete;
+ cVNSIDemuxer &operator=(const cVNSIDemuxer &) = delete;
+
int Read(sStreamPacket *packet, sStreamPacket *packet_side_data);
cTSStream *GetFirstStream();
cTSStream *GetNextStream();
@@ -71,17 +74,15 @@ public:
protected:
bool EnsureParsers();
void ResetParsers();
- void SetChannelStreams(const cChannel *channel);
+ void SetChannelStreamInfos(const cChannel *channel);
void SetChannelPids(cChannel *channel, cPatPmtParser *patPmtParser);
cTSStream *FindStream(int Pid);
- void AddStreamInfo(sStreamInfo &stream);
bool GetTimeAtPos(off_t *pos, int64_t *time);
std::list<cTSStream*> m_Streams;
std::list<cTSStream*>::iterator m_StreamsIterator;
- std::list<sStreamInfo> m_StreamInfos;
+ std::list<cStreamInfo> m_StreamInfos;
cChannel m_CurrentChannel;
cPatPmtParser m_PatPmtParser;
- int m_OldPmtVersion;
bool m_WaitIFrame;
cVideoBuffer *m_VideoBuffer;
cMutex m_Mutex;
@@ -91,4 +92,5 @@ protected:
bool m_SetRefTime;
time_t m_refTime, m_endTime, m_wrapTime;
bool m_bAllowRDS;
+ bool m_seenFirstPacket;
};
diff --git a/hash.c b/hash.c
index f4dee4e..5c6ca21 100644
--- a/hash.c
+++ b/hash.c
@@ -23,11 +23,11 @@
*
*/
+#include "hash.h"
+
#include <vdr/tools.h>
#include <vdr/channels.h>
-#include "hash.h"
-
static uint32_t crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
@@ -98,9 +98,21 @@ uint32_t CreateChannelUID(const cChannel* channel) {
}
const cChannel* FindChannelByUID(uint32_t channelUID) {
- cChannel* result = NULL;
+ const cChannel* result = NULL;
+#if VDRVERSNUM >= 20301
+ LOCK_CHANNELS_READ;
+ // maybe we need to use a lookup table
+ for (const cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel)) {
+ cString channelid = channel->GetChannelID().ToString();
+ if(channelUID == CreateStringHash(channelid)) {
+ result = channel;
+ break;
+ }
+ }
+#else
// maybe we need to use a lookup table
+ Channels.Lock(false);
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel)) {
cString channelid = channel->GetChannelID().ToString();
if(channelUID == CreateStringHash(channelid)) {
@@ -108,6 +120,8 @@ const cChannel* FindChannelByUID(uint32_t channelUID) {
break;
}
}
+ Channels.Unlock();
+#endif
return result;
}
diff --git a/parser.c b/parser.c
index ab8dadf..7740e0f 100644
--- a/parser.c
+++ b/parser.c
@@ -32,6 +32,7 @@
#include "parser_AC3.h"
#include "parser_DTS.h"
#include "parser_h264.h"
+#include "parser_hevc.h"
#include "parser_MPEGAudio.h"
#include "parser_MPEGVideo.h"
#include "parser_Subtitle.h"
@@ -58,8 +59,7 @@ cParser::cParser(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsW
cParser::~cParser()
{
- if (m_PesBuffer)
- free(m_PesBuffer);
+ free(m_PesBuffer);
}
void cParser::Reset()
@@ -370,13 +370,15 @@ bool cParser::AddPESPacket(uint8_t *data, int size)
return false;
}
m_PesBufferSize += m_PesBufferInitialSize / 10;
- m_PesBuffer = (uint8_t*)realloc(m_PesBuffer, m_PesBufferSize);
- if (m_PesBuffer == NULL)
+ uint8_t *new_buffer = (uint8_t*)realloc(m_PesBuffer, m_PesBufferSize);
+ if (new_buffer == NULL)
{
ERRORLOG("cParser::AddPESPacket - realloc failed");
Reset();
return false;
}
+
+ m_PesBuffer = new_buffer;
}
// copy first packet of new frame to front
@@ -401,7 +403,7 @@ inline bool cParser::IsValidStartCode(uint8_t *buf, int size)
return false;
uint32_t startcode = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
- if (m_Stream->Type() == stH264 || m_Stream->Type() == stMPEG2VIDEO)
+ if (m_Stream->Type() == stH264 || m_Stream->Type() == stHEVC ||m_Stream->Type() == stMPEG2VIDEO)
{
if (startcode >= 0x000001e0 && startcode <= 0x000001ef)
return true;
@@ -469,6 +471,11 @@ cTSStream::cTSStream(eStreamType type, int pid, sPtsWrap *ptsWrap, bool handleSi
m_pesParser = new cParserH264(m_pID, this, ptsWrap, true);
m_streamContent = scVIDEO;
}
+ else if (m_streamType == stHEVC)
+ {
+ m_pesParser = new cParserHEVC(m_pID, this, ptsWrap, true);
+ m_streamContent = scVIDEO;
+ }
else if (m_streamType == stMPEG2AUDIO)
{
m_pesParser = new cParserMPEG2Audio(m_pID, this, ptsWrap, true, handleSideData);
@@ -694,7 +701,10 @@ bool cTSStream::SetVideoInformation(int FpsScale, int FpsRate, int Height, int W
(m_Height != Height) ||
(m_Width != Width) ||
(m_Aspect != Aspect))
+ {
+ INFOLOG("Video stream change, pid: %d, width: %d, height: %d, aspect: %f", m_pID, Width, Height, Aspect);
m_IsStreamChange = true;
+ }
m_FpsScale = FpsScale;
m_FpsRate = FpsRate;
@@ -723,7 +733,10 @@ bool cTSStream::SetAudioInformation(int Channels, int SampleRate, int BitRate, i
(m_BlockAlign != BlockAlign) ||
(m_BitRate != BitRate) ||
(m_BitsPerSample != BitsPerSample))
+ {
+ INFOLOG("Audio stream change, pid: %d, channels: %d, samplerate: %d", m_pID, Channels, SampleRate);
m_IsStreamChange = true;
+ }
m_Channels = Channels;
m_SampleRate = SampleRate;
diff --git a/parser.h b/parser.h
index f15bd2e..b9455b0 100644
--- a/parser.h
+++ b/parser.h
@@ -104,6 +104,7 @@ enum eStreamType
stDTS,
stMPEG2VIDEO,
stH264,
+ stHEVC,
stDVBSUB,
stTEXTSUB,
stTELETEXT,
@@ -149,6 +150,9 @@ public:
cParser(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
virtual ~cParser();
+ cParser(const cParser &) = delete;
+ cParser &operator=(const cParser &) = delete;
+
bool AddPESPacket(uint8_t *data, int size);
virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data) = 0;
// void ClearFrame() {m_PesBufferPtr = 0;}
@@ -227,19 +231,22 @@ public:
cTSStream(eStreamType type, int pid, sPtsWrap *ptsWrap, bool handleSideData = false);
virtual ~cTSStream();
+ cTSStream(const cTSStream &) = delete;
+ cTSStream &operator=(const cTSStream &) = delete;
+
int ProcessTSPacket(uint8_t *data, sStreamPacket *pkt, sStreamPacket *pkt_side_data, bool iframe);
bool ReadTime(uint8_t *data, int64_t *dts);
void ResetParser();
void SetLanguage(const char *language);
const char *GetLanguage() { return m_language; }
- const eStreamContent Content() const { return m_streamContent; }
- const eStreamType Type() const { return m_streamType; }
+ eStreamContent Content() const { return m_streamContent; }
+ eStreamType Type() const { return m_streamType; }
void SetType(eStreamType type) { m_streamType = type; }
- const int GetPID() const { return m_pID; }
+ int GetPID() const { return m_pID; }
uint32_t AddSideDataType(eStreamContent content);
- const std::vector< std::pair<uint32_t, eStreamContent> > *GetSideDataTypes() const { return &m_SideDataTypes; }
+ const std::vector< std::pair<uint32_t, eStreamContent> > &GetSideDataTypes() const { return m_SideDataTypes; }
/* Video Stream Information */
bool SetVideoInformation(int FpsScale, int FpsRate, int Height, int Width, float Aspect);
diff --git a/parser_AAC.c b/parser_AAC.c
index 5dab502..9fec5ce 100644
--- a/parser_AAC.c
+++ b/parser_AAC.c
@@ -22,11 +22,11 @@
*
*/
-#include <stdlib.h>
-#include <assert.h>
+#include "parser_AAC.h"
#include "config.h"
-#include "parser_AAC.h"
+#include <stdlib.h>
+#include <assert.h>
static int aac_sample_rates[16] =
{
@@ -154,6 +154,9 @@ int cParserAAC::FindHeaders(uint8_t *buf, int buf_size)
m_FrameSize = bs.readBits(13);
m_SampleRate = aac_sample_rates[SampleRateIndex & 0x0E];
+ if (!m_SampleRate)
+ m_SampleRate = aac_sample_rates[4];
+
m_FoundFrame = true;
m_DTS = m_curPTS;
m_PTS = m_curPTS;
diff --git a/parser_AC3.c b/parser_AC3.c
index f401953..9ca7124 100644
--- a/parser_AC3.c
+++ b/parser_AC3.c
@@ -22,12 +22,12 @@
*
*/
-#include <stdlib.h>
-#include <assert.h>
-#include "config.h"
-
#include "parser_AC3.h"
#include "bitstream.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
#define AC3_HEADER_SIZE 7
diff --git a/parser_DTS.c b/parser_DTS.c
index f464892..5395c3b 100644
--- a/parser_DTS.c
+++ b/parser_DTS.c
@@ -22,12 +22,12 @@
*
*/
-#include <stdlib.h>
-#include <assert.h>
-#include "config.h"
-
#include "parser_DTS.h"
#include "bitstream.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
cParserDTS::cParserDTS(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
: cParser(pID, stream, ptsWrap, observePtsWraps)
diff --git a/parser_MPEGAudio.c b/parser_MPEGAudio.c
index fbbb0d0..2b1ec67 100644
--- a/parser_MPEGAudio.c
+++ b/parser_MPEGAudio.c
@@ -22,12 +22,12 @@
*
*/
-#include <stdlib.h>
-#include <assert.h>
-#include "config.h"
-
#include "parser_MPEGAudio.h"
#include "bitstream.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
#define MAX_RDS_BUFFER_SIZE 100000
@@ -65,11 +65,7 @@ cParserMPEG2Audio::cParserMPEG2Audio(int pID, cTSStream *stream, sPtsWrap *ptsWr
cParserMPEG2Audio::~cParserMPEG2Audio()
{
- if (m_RDSBuffer)
- {
- delete m_RDSBuffer;
- m_RDSBuffer = NULL;
- }
+ free(m_RDSBuffer);
}
void cParserMPEG2Audio::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
@@ -140,14 +136,16 @@ void cParserMPEG2Audio::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
return;
}
m_RDSBufferSize += m_RDSBufferInitialSize / 10;
- m_RDSBuffer = (uint8_t*)realloc(m_RDSBuffer, m_RDSBufferSize);
- if (m_RDSBuffer == NULL)
+ uint8_t *new_buffer = (uint8_t *)realloc(m_RDSBuffer, m_RDSBufferSize);
+ if (new_buffer == NULL)
{
ERRORLOG("PVR Parser MPEG2-Audio - %s - realloc for RDS data failed", __FUNCTION__);
m_RDSEnabled = false;
return;
}
- }
+
+ m_RDSBuffer = new_buffer;
+ }
int pes_buffer_ptr = 0;
for (int i = m_FrameSize-3; i > m_FrameSize-3-rdsl; i--) // <-- data reverse, from end to start
diff --git a/parser_MPEGVideo.c b/parser_MPEGVideo.c
index 663d09d..b27dd1b 100644
--- a/parser_MPEGVideo.c
+++ b/parser_MPEGVideo.c
@@ -22,12 +22,12 @@
*
*/
-#include <stdlib.h>
-#include <assert.h>
-#include "config.h"
+#include "parser_MPEGVideo.h"
#include "bitstream.h"
+#include "config.h"
-#include "parser_MPEGVideo.h"
+#include <stdlib.h>
+#include <assert.h>
using namespace std;
diff --git a/parser_Subtitle.c b/parser_Subtitle.c
index bd8e19f..032ec88 100644
--- a/parser_Subtitle.c
+++ b/parser_Subtitle.c
@@ -22,11 +22,11 @@
*
*/
-#include <stdlib.h>
-#include <assert.h>
+#include "parser_Subtitle.h"
#include "config.h"
-#include "parser_Subtitle.h"
+#include <stdlib.h>
+#include <assert.h>
cParserSubtitle::cParserSubtitle(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
: cParser(pID, stream, ptsWrap, observePtsWraps)
diff --git a/parser_Teletext.c b/parser_Teletext.c
index a5c65a6..8e32dce 100644
--- a/parser_Teletext.c
+++ b/parser_Teletext.c
@@ -22,10 +22,10 @@
*
*/
-#include <stdlib.h>
+#include "parser_Teletext.h"
#include "config.h"
-#include "parser_Teletext.h"
+#include <stdlib.h>
cParserTeletext::cParserTeletext(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
: cParser(pID, stream, ptsWrap, observePtsWraps)
diff --git a/parser_h264.c b/parser_h264.c
index c7f8dde..ced5d88 100644
--- a/parser_h264.c
+++ b/parser_h264.c
@@ -22,12 +22,12 @@
*
*/
-#include <stdlib.h>
-#include <assert.h>
-#include "config.h"
+#include "parser_h264.h"
#include "bitstream.h"
+#include "config.h"
-#include "parser_h264.h"
+#include <stdlib.h>
+#include <assert.h>
static const int h264_lev2cpbsize[][2] =
{
diff --git a/parser_hevc.c b/parser_hevc.c
new file mode 100644
index 0000000..34b5901
--- /dev/null
+++ b/parser_hevc.c
@@ -0,0 +1,323 @@
+/*
+ * vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ * Copyright (C) 2005-2012 Team XBMC
+ * Copyright (C) 2015 Team KODI
+ *
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KODI; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+// Warning: This is an unfinished port from H.264 to HEVC in alpha state
+// Tested with German DVB-T2 HD channels
+
+#include "parser_hevc.h"
+#include "bitstream.h"
+#include "config.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+
+cParserHEVC::cParserHEVC(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps)
+ : cParser(pID, stream, ptsWrap, observePtsWraps)
+{
+ m_Height = 0;
+ m_Width = 0;
+ m_FpsScale = 0;
+ m_PixelAspect.den = 1;
+ m_PixelAspect.num = 0;
+ memset(&m_streamData, 0, sizeof(m_streamData));
+ m_PesBufferInitialSize = 240000;
+
+ m_IsVideo = true;
+ Reset();
+}
+
+cParserHEVC::~cParserHEVC()
+{
+}
+
+void cParserHEVC::Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data)
+{
+ if (m_PesBufferPtr < 10) // 2*startcode + header + trail bits
+ return;
+
+ int p = m_PesParserPtr;
+ uint32_t startcode = m_StartCode;
+ bool frameComplete = false;
+
+ while (m_PesBufferPtr - p)
+ {
+ startcode = startcode << 8 | m_PesBuffer[p++];
+ if ((startcode & 0x00ffffff) == 0x00000001)
+ {
+ if (m_LastStartPos != -1)
+ Parse_HEVC(m_LastStartPos, p-m_LastStartPos, &frameComplete);
+ m_LastStartPos = p;
+ if (frameComplete)
+ break;
+ }
+ }
+ m_PesParserPtr = p;
+ m_StartCode = startcode;
+
+ if (frameComplete)
+ {
+ if (!m_NeedSPS && m_FrameValid)
+ {
+ double PAR = (double)m_PixelAspect.num/(double)m_PixelAspect.den;
+ double DAR = (PAR * m_Width) / m_Height;
+ DEBUGLOG("HEVC SPS: PAR %i:%i", m_PixelAspect.num, m_PixelAspect.den);
+ DEBUGLOG("HEVC SPS: DAR %.2f", DAR);
+
+ int duration;
+ if (m_curDTS != DVD_NOPTS_VALUE && m_prevDTS != DVD_NOPTS_VALUE && m_curDTS > m_prevDTS)
+ duration = m_curDTS - m_prevDTS;
+ else
+ duration = m_Stream->Rescale(20000, 90000, DVD_TIME_BASE);
+
+ if (m_FpsScale == 0)
+ m_FpsScale = m_Stream->Rescale(duration, DVD_TIME_BASE, 90000);
+
+ bool streamChange = m_Stream->SetVideoInformation(m_FpsScale, DVD_TIME_BASE, m_Height, m_Width, DAR);
+
+ pkt->id = m_pID;
+ pkt->size = m_PesNextFramePtr;
+ pkt->data = m_PesBuffer;
+ pkt->dts = m_DTS;
+ pkt->pts = m_PTS;
+ pkt->duration = duration;
+ pkt->streamChange = streamChange;
+
+ }
+ m_StartCode = 0xffffffff;
+ m_LastStartPos = -1;
+ m_PesParserPtr = 0;
+ m_FoundFrame = false;
+ m_FrameValid = true;
+ }
+}
+
+void cParserHEVC::Reset()
+{
+ cParser::Reset();
+ m_StartCode = 0xffffffff;
+ m_LastStartPos = -1;
+ m_NeedSPS = true;
+ m_NeedPPS = true;
+ memset(&m_streamData, 0, sizeof(m_streamData));
+}
+
+
+void cParserHEVC::Parse_HEVC(int buf_ptr, unsigned int NumBytesInNalUnit, bool *complete)
+{
+ uint8_t *buf = m_PesBuffer + buf_ptr;
+ uint16_t header;
+ HDR_NAL hdr;
+
+ // nal_unit_header
+ header = (buf[0] << 8) | buf[1];
+ if (header & 0x8000) // ignore forbidden_bit == 1
+ return;
+ hdr.nal_unit_type = (header & 0x7e00) >> 9;
+ hdr.nuh_layer_id = (header & 0x1f8) >> 3;
+ hdr.nuh_temporal_id = (header & 0x7) - 1;
+
+ switch (hdr.nal_unit_type)
+ {
+ case NAL_TRAIL_N ... NAL_RASL_R:
+ case NAL_BLA_W_LP ... NAL_CRA_NUT:
+ {
+ if (m_NeedSPS || m_NeedPPS)
+ {
+ m_FoundFrame = true;
+ return;
+ }
+ hevc_private::VCL_NAL vcl;
+ memset(&vcl, 0, sizeof(hevc_private::VCL_NAL));
+ Parse_SLH(buf, NumBytesInNalUnit, hdr, vcl);
+
+ // check for the beginning of a new access unit
+ if (m_FoundFrame && IsFirstVclNal(vcl))
+ {
+ *complete = true;
+ m_PesNextFramePtr = buf_ptr - 3;
+ return;
+ }
+
+ if (!m_FoundFrame)
+ {
+ if (buf_ptr - 3 >= m_PesTimePos)
+ {
+ m_DTS = m_curDTS;
+ m_PTS = m_curPTS;
+ }
+ else
+ {
+ m_DTS = m_prevDTS;
+ m_PTS = m_prevPTS;
+ }
+ }
+
+ m_streamData.vcl_nal = vcl;
+ m_FoundFrame = true;
+ break;
+ }
+
+ case NAL_PFX_SEI_NUT:
+ if (m_FoundFrame)
+ {
+ *complete = true;
+ m_PesNextFramePtr = buf_ptr - 3;
+ }
+ break;
+
+ case NAL_VPS_NUT:
+ break;
+
+ case NAL_SPS_NUT:
+ {
+ if (m_FoundFrame)
+ {
+ *complete = true;
+ m_PesNextFramePtr = buf_ptr - 3;
+ return;
+ }
+ Parse_SPS(buf, NumBytesInNalUnit, hdr);
+ m_NeedSPS = false;
+ break;
+ }
+
+ case NAL_PPS_NUT:
+ {
+ if (m_FoundFrame)
+ {
+ *complete = true;
+ m_PesNextFramePtr = buf_ptr - 3;
+ return;
+ }
+ Parse_PPS(buf, NumBytesInNalUnit);
+ m_NeedPPS = false;
+ break;
+ }
+
+ case NAL_AUD_NUT:
+ if (m_FoundFrame && (m_prevPTS != DVD_NOPTS_VALUE))
+ {
+ *complete = true;
+ m_PesNextFramePtr = buf_ptr - 3;
+ }
+ break;
+
+ case NAL_EOS_NUT:
+ if (m_FoundFrame)
+ {
+ *complete = true;
+ m_PesNextFramePtr = buf_ptr + 2;
+ }
+ break;
+
+ case NAL_FD_NUT:
+ case NAL_SFX_SEI_NUT:
+ break;
+
+ default:
+ INFOLOG("HEVC fixme: nal unknown %i", hdr.nal_unit_type);
+ break;
+ }
+}
+
+void cParserHEVC::Parse_PPS(uint8_t *buf, int len)
+{
+ cBitstream bs(buf, len*8, true);
+
+ int pps_id = bs.readGolombUE();
+ int sps_id = bs.readGolombUE();
+ m_streamData.pps[pps_id].sps = sps_id;
+ m_streamData.pps[pps_id].dependent_slice_segments_enabled_flag = bs.readBits(1);
+}
+
+void cParserHEVC::Parse_SLH(uint8_t *buf, int len, HDR_NAL hdr, hevc_private::VCL_NAL &vcl)
+{
+ cBitstream bs(buf, len*8, true);
+
+ vcl.nal_unit_type = hdr.nal_unit_type;
+
+ vcl.first_slice_segment_in_pic_flag = bs.readBits(1);
+
+ if ((hdr.nal_unit_type >= NAL_BLA_W_LP) && (hdr.nal_unit_type <= NAL_RSV_IRAP_VCL23))
+ bs.skipBits(1); // no_output_of_prior_pics_flag
+
+ vcl.pic_parameter_set_id = bs.readGolombUE();
+}
+
+// 7.3.2.2.1 General sequence parameter set RBSP syntax
+void cParserHEVC::Parse_SPS(uint8_t *buf, int len, HDR_NAL hdr)
+{
+ cBitstream bs(buf, len*8, true);
+ unsigned int i;
+ int sub_layer_profile_present_flag[8], sub_layer_level_present_flag[8];
+
+ bs.skipBits(4); // sps_video_parameter_set_id
+
+ unsigned int sps_max_sub_layers_minus1 = bs.readBits(3);
+ bs.skipBits(1); // sps_temporal_id_nesting_flag
+
+ // skip over profile_tier_level
+ bs.skipBits(8 + 32 + 4 + 43 + 1 +8);
+ for (i=0; i<sps_max_sub_layers_minus1; i++)
+ {
+ sub_layer_profile_present_flag[i] = bs.readBits(1);
+ sub_layer_level_present_flag[i] = bs.readBits(1);
+ }
+ if (sps_max_sub_layers_minus1 > 0)
+ {
+ for (i=sps_max_sub_layers_minus1; i<8; i++)
+ bs.skipBits(2);
+ }
+ for (i=0; i<sps_max_sub_layers_minus1; i++)
+ {
+ if (sub_layer_profile_present_flag[i])
+ bs.skipBits(8 + 32 + 4 + 43 + 1);
+ if (sub_layer_level_present_flag[i])
+ bs.skipBits(8);
+ }
+ // end skip over profile_tier_level
+
+ bs.readGolombUE(); // sps_seq_parameter_set_id
+ unsigned int chroma_format_idc = bs.readGolombUE();
+
+ if (chroma_format_idc == 3)
+ bs.skipBits(1); // separate_colour_plane_flag
+
+ m_Width = bs.readGolombUE();
+ m_Height = bs.readGolombUE();
+ m_PixelAspect.num = 1;
+}
+
+bool cParserHEVC::IsFirstVclNal(hevc_private::VCL_NAL &vcl)
+{
+ if (m_streamData.vcl_nal.pic_parameter_set_id != vcl.pic_parameter_set_id)
+ return true;
+
+ if (vcl.first_slice_segment_in_pic_flag)
+ return true;
+
+ return false;
+}
+
diff --git a/parser_hevc.h b/parser_hevc.h
new file mode 100644
index 0000000..e29b775
--- /dev/null
+++ b/parser_hevc.h
@@ -0,0 +1,123 @@
+/*
+ * vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ * Copyright (C) 2005-2012 Team XBMC
+ * Copyright (C) 2015 Team KODI
+ *
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KODI; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VNSI_DEMUXER_HEVC_H
+#define VNSI_DEMUXER_HEVC_H
+
+#include "parser.h"
+
+class cBitstream;
+
+// --- cParserHEVC -------------------------------------------------
+
+class cParserHEVC : public cParser
+{
+private:
+ typedef struct hevc_private
+ {
+ struct PPS
+ {
+ int sps;
+ int dependent_slice_segments_enabled_flag;
+ } pps[64];
+
+ struct VCL_NAL
+ {
+ int pic_parameter_set_id; // slice
+ unsigned int first_slice_segment_in_pic_flag;
+ unsigned int nal_unit_type;
+ } vcl_nal;
+
+ } hevc_private_t;
+
+ typedef struct HDR_NAL_t
+ {
+ uint nal_unit_type;
+ uint nuh_layer_id;
+ uint nuh_temporal_id;
+ } HDR_NAL;
+
+ typedef struct mpeg_rational_s {
+ int num;
+ int den;
+ } mpeg_rational_t;
+
+ enum
+ {
+ NAL_TRAIL_N = 0x00, // Coded slice segment of trailing picture
+ NAL_TRAIL_R = 0x01, // Coded slice segment of trailing picture
+ NAL_TSA_N = 0x02, // Coded slice segment of TSA picture
+ NAL_TSA_R = 0x03, // Coded slice segment of TSA picture
+ NAL_STSA_N = 0x04, // Coded slice segment of STSA picture
+ NAL_STSA_R = 0x05, // Coded slice segment of STSA picture
+ NAL_RADL_N = 0x06, // Coded slice segment of RADL picture
+ NAL_RADL_R = 0x07, // Coded slice segment of RADL picture
+ NAL_RASL_N = 0x08, // Coded slice segment of RASL picture
+ NAL_RASL_R = 0x09, // Coded slice segment of RASL picture
+
+ NAL_BLA_W_LP = 0x10, // Coded slice segment of a BLA picture
+ NAL_CRA_NUT = 0x15, // Coded slice segment of a CRA picture
+ NAL_RSV_IRAP_VCL22 = 0x16, // Reserved IRAP VCL NAL unit types
+ NAL_RSV_IRAP_VCL23 = 0x17, // Reserved IRAP VCL NAL unit types
+
+ NAL_VPS_NUT = 0x20, // Video Parameter SET
+ NAL_SPS_NUT = 0x21, // Sequence Parameter Set
+ NAL_PPS_NUT = 0x22, // Picture Parameter Set
+ NAL_AUD_NUT = 0x23, // Access Unit Delimiter
+ NAL_EOS_NUT = 0x24, // End of Sequence
+ NAL_EOB_NUT = 0x25, // End of Bitstream
+ NAL_FD_NUT = 0x26, // Filler Data
+ NAL_PFX_SEI_NUT = 0x27, // Supplemental Enhancement Information
+ NAL_SFX_SEI_NUT = 0x28, // Supplemental Enhancement Information
+
+ };
+
+ uint32_t m_StartCode;
+ int m_LastStartPos;
+ bool m_NeedSPS;
+ bool m_NeedPPS;
+ int m_Width;
+ int m_Height;
+ int m_FpsScale;
+ mpeg_rational_t m_PixelAspect;
+ hevc_private m_streamData;
+ int64_t m_DTS;
+ int64_t m_PTS;
+
+ void Parse_HEVC(int buf_ptr, unsigned int NumBytesInNalUnit, bool *complete);
+ void Parse_PPS(uint8_t *buf, int len);
+ void Parse_SLH(uint8_t *buf, int len, HDR_NAL hdr, hevc_private::VCL_NAL &vcl);
+ void Parse_SPS(uint8_t *buf, int len, HDR_NAL hdr);
+ bool IsFirstVclNal(hevc_private::VCL_NAL &vcl);
+
+public:
+ cParserHEVC(int pID, cTSStream *stream, sPtsWrap *ptsWrap, bool observePtsWraps);
+ virtual ~cParserHEVC();
+
+ virtual void Parse(sStreamPacket *pkt, sStreamPacket *pkt_side_data);
+ virtual void Reset();
+};
+
+
+#endif // VNSI_DEMUXER_HEVC_H
diff --git a/po/de_DE.po b/po/de_DE.po
index 0edfa03..00d9411 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VNSI-Server 1.0.0\n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2015-04-04 14:32+0200\n"
+"POT-Creation-Date: 2016-04-23 09:08+0200\n"
"PO-Revision-Date: 2015-01-23 21:46+0100\n"
"Last-Translator: Alwin Esch\n"
"Language-Team: German\n"
@@ -21,9 +21,6 @@ msgstr ""
msgid "Your scanner version is to old - Please upgrade."
msgstr ""
-msgid "PMT Timeout (0-10)"
-msgstr "PMT Auszeit (0-10)"
-
msgid "Off"
msgstr "Aus"
@@ -51,6 +48,9 @@ msgstr "Wiedergeben als Aufzeichnung statt Live"
msgid "Avoid EPG scan while streaming"
msgstr "Keine EPG suche während der Wiedergabe durchführen"
+msgid "Disable scramble timeout"
+msgstr ""
+
msgid "Recording with the same name exists"
msgstr "Aufnahme mit der selben größe existiert"
@@ -65,3 +65,6 @@ msgstr "Fehler beim Zugriff der Indexdatei"
msgid "Deleted recording vanished"
msgstr "Gelöschte Aufnahme verschwunden"
+
+#~ msgid "PMT Timeout (0-10)"
+#~ msgstr "PMT Auszeit (0-10)"
diff --git a/po/lt_LT.po b/po/lt_LT.po
index a3c985d..2f979df 100644
--- a/po/lt_LT.po
+++ b/po/lt_LT.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: VNSI-Server 1.0.0\n"
"Report-Msgid-Bugs-To: <see README>\n"
-"POT-Creation-Date: 2015-04-04 14:32+0200\n"
+"POT-Creation-Date: 2016-04-23 09:08+0200\n"
"PO-Revision-Date: 2015-02-11 22:30+0200\n"
"Last-Translator: Valdemaras Pipiras\n"
"Language-Team: Lithuanian\n"
@@ -21,9 +21,6 @@ msgstr ""
msgid "Your scanner version is to old - Please upgrade."
msgstr ""
-msgid "PMT Timeout (0-10)"
-msgstr "PMT (0-10)"
-
msgid "Off"
msgstr "Išjungta"
@@ -51,6 +48,9 @@ msgstr "Groti įrašą vietoj gyvos transliacijos"
msgid "Avoid EPG scan while streaming"
msgstr "Vengti EPG skanavimo kol vyksta transliacija"
+msgid "Disable scramble timeout"
+msgstr ""
+
msgid "Recording with the same name exists"
msgstr "Jau yra įrašų tokiu pat pavadinimu"
@@ -65,3 +65,6 @@ msgstr "Klaida bandant atidaryti index failą"
msgid "Deleted recording vanished"
msgstr "Ištrintas įrašas galutinai išvalytas"
+
+#~ msgid "PMT Timeout (0-10)"
+#~ msgstr "PMT (0-10)"
diff --git a/recordingscache.c b/recordingscache.c
index b2892d8..1c4ff6e 100644
--- a/recordingscache.c
+++ b/recordingscache.c
@@ -22,8 +22,8 @@
*
*/
-#include "config.h"
#include "recordingscache.h"
+#include "config.h"
#include "vnsiclient.h"
#include "hash.h"
@@ -38,7 +38,7 @@ cRecordingsCache& cRecordingsCache::GetInstance() {
return singleton;
}
-uint32_t cRecordingsCache::Register(cRecording* recording, bool deleted) {
+uint32_t cRecordingsCache::Register(const cRecording* recording, bool deleted) {
cString filename = recording->FileName();
uint32_t uid = CreateStringHash(filename);
@@ -54,7 +54,7 @@ uint32_t cRecordingsCache::Register(cRecording* recording, bool deleted) {
return uid;
}
-cRecording* cRecordingsCache::Lookup(uint32_t uid) {
+const cRecording* cRecordingsCache::Lookup(uint32_t uid) {
DEBUGLOG("%s - lookup uid: %08x", __FUNCTION__, uid);
if(m_recordings.find(uid) == m_recordings.end()) {
@@ -66,11 +66,65 @@ cRecording* cRecordingsCache::Lookup(uint32_t uid) {
cString filename = m_recordings[uid].filename;
DEBUGLOG("%s - filename: %s", __FUNCTION__, (const char*)filename);
+ const cRecording* r;
+ if (!m_recordings[uid].isDeleted)
+ {
+#if VDRVERSNUM >= 20301
+ LOCK_RECORDINGS_READ;
+ r = Recordings->GetByName(filename);
+#else
+ r = Recordings.GetByName(filename);
+#endif
+ }
+ else
+ {
+#if VDRVERSNUM >= 20301
+ LOCK_DELETEDRECORDINGS_READ;
+ r = DeletedRecordings->GetByName(filename);
+#else
+ r = DeletedRecordings.GetByName(filename);
+#endif
+ }
+
+ DEBUGLOG("%s - recording %s", __FUNCTION__, (r == NULL) ? "not found !" : "found");
+ m_mutex.Unlock();
+
+ return r;
+}
+
+cRecording* cRecordingsCache::LookupWrite(uint32_t uid)
+{
+ DEBUGLOG("%s - lookup uid: %08x", __FUNCTION__, uid);
+
+ if(m_recordings.find(uid) == m_recordings.end())
+ {
+ DEBUGLOG("%s - not found !", __FUNCTION__);
+ return NULL;
+ }
+
+ m_mutex.Lock();
+ cString filename = m_recordings[uid].filename;
+ DEBUGLOG("%s - filename: %s", __FUNCTION__, (const char*)filename);
+
cRecording* r;
if (!m_recordings[uid].isDeleted)
+ {
+#if VDRVERSNUM >= 20301
+ LOCK_RECORDINGS_WRITE;
+ r = Recordings->GetByName(filename);
+#else
r = Recordings.GetByName(filename);
+#endif
+ }
else
+ {
+#if VDRVERSNUM >= 20301
+ LOCK_DELETEDRECORDINGS_WRITE;
+ r = DeletedRecordings->GetByName(filename);
+#else
r = DeletedRecordings.GetByName(filename);
+#endif
+ }
DEBUGLOG("%s - recording %s", __FUNCTION__, (r == NULL) ? "not found !" : "found");
m_mutex.Unlock();
diff --git a/recordingscache.h b/recordingscache.h
index 7fb9180..2dac71d 100644
--- a/recordingscache.h
+++ b/recordingscache.h
@@ -43,9 +43,10 @@ public:
static cRecordingsCache& GetInstance();
- uint32_t Register(cRecording* recording, bool deleted = false);
+ uint32_t Register(const cRecording* recording, bool deleted = false);
- cRecording* Lookup(uint32_t uid);
+ const cRecording* Lookup(uint32_t uid);
+ cRecording* LookupWrite(uint32_t uid);
private:
struct RecordingsInfo
diff --git a/recplayer.c b/recplayer.c
index 870d388..710b2c5 100644
--- a/recplayer.c
+++ b/recplayer.c
@@ -38,31 +38,23 @@
#define O_NOATIME 0
#endif
-cRecPlayer::cRecPlayer(cRecording* rec, bool inProgress)
+cRecPlayer::cRecPlayer(const cRecording* rec, bool inProgress)
+ :m_inProgress(inProgress),
+ m_recordingFilename(rec->FileName()),
+ m_pesrecording(rec->IsPesRecording()),
+ m_indexFile(m_recordingFilename.c_str(), false, m_pesrecording),
+ m_file(-1), m_fileOpen(-1)
{
- m_file = -1;
- m_fileOpen = -1;
- m_recordingFilename = strdup(rec->FileName());
- m_inProgress = inProgress;
-
// FIXME find out max file path / name lengths
-#if VDRVERSNUM < 10703
- m_pesrecording = true;
- m_indexFile = new cIndexFile(m_recordingFilename, false);
-#else
- m_pesrecording = rec->IsPesRecording();
- if(m_pesrecording) INFOLOG("recording '%s' is a PES recording", m_recordingFilename);
- m_indexFile = new cIndexFile(m_recordingFilename, false, m_pesrecording);
-#endif
+
+ if(m_pesrecording)
+ INFOLOG("recording '%s' is a PES recording", m_recordingFilename.c_str());
scan();
}
void cRecPlayer::cleanup() {
- for(int i = 0; i != m_segments.Size(); i++) {
- delete m_segments[i];
- }
- m_segments.Clear();
+ m_segments.clear();
}
void cRecPlayer::scan()
@@ -85,17 +77,17 @@ void cRecPlayer::scan()
break;
}
- cSegment* segment = new cSegment();
- segment->start = m_totalLength;
- segment->end = segment->start + s.st_size;
+ cSegment segment;
+ segment.start = m_totalLength;
+ segment.end = segment.start + s.st_size;
- m_segments.Append(segment);
+ m_segments.push_back(segment);
m_totalLength += s.st_size;
INFOLOG("File %i found, size: %lu, totalLength now %lu", i, s.st_size, m_totalLength);
}
- m_totalFrames = m_indexFile->Last();
+ m_totalFrames = m_indexFile.Last();
INFOLOG("total frames: %u", m_totalFrames);
}
@@ -105,7 +97,7 @@ void cRecPlayer::reScan()
m_totalLength = 0;
- for(int i = 0; ; i++) // i think we only need one possible loop
+ for(size_t i = 0; ; i++) // i think we only need one possible loop
{
fileNameFromIndex(i);
@@ -114,21 +106,21 @@ void cRecPlayer::reScan()
}
cSegment* segment;
- if (m_segments.Size() < i+1)
+ if (m_segments.size() < i+1)
{
- segment = new cSegment();
- m_segments.Append(segment);
+ m_segments.push_back(cSegment());
+ segment = &m_segments.back();
segment->start = m_totalLength;
}
else
- segment = m_segments[i];
+ segment = &m_segments[i];
segment->end = segment->start + s.st_size;
m_totalLength += s.st_size;
}
- m_totalFrames = m_indexFile->Last();
+ m_totalFrames = m_indexFile.Last();
}
@@ -136,14 +128,13 @@ cRecPlayer::~cRecPlayer()
{
cleanup();
closeFile();
- free(m_recordingFilename);
}
char* cRecPlayer::fileNameFromIndex(int index) {
if (m_pesrecording)
- snprintf(m_fileName, sizeof(m_fileName), "%s/%03i.vdr", m_recordingFilename, index+1);
+ snprintf(m_fileName, sizeof(m_fileName), "%s/%03i.vdr", m_recordingFilename.c_str(), index+1);
else
- snprintf(m_fileName, sizeof(m_fileName), "%s/%05i.ts", m_recordingFilename, index+1);
+ snprintf(m_fileName, sizeof(m_fileName), "%s/%05i.ts", m_recordingFilename.c_str(), index+1);
return m_fileName;
}
@@ -212,25 +203,25 @@ int cRecPlayer::getBlock(unsigned char* buffer, uint64_t position, int amount)
amount = m_totalLength - position;
// work out what block "position" is in
- int segmentNumber = -1;
- for(int i = 0; i < m_segments.Size(); i++)
- {
- if ((position >= m_segments[i]->start) && (position < m_segments[i]->end)) {
- segmentNumber = i;
+ std::vector<cSegment>::iterator begin = m_segments.begin(),
+ end = m_segments.end(), segmentIterator = end;
+ for (std::vector<cSegment>::iterator i = begin; i != end; ++i) {
+ if ((position >= i->start) && (position < i->end)) {
+ segmentIterator = i;
break;
}
}
// segment not found / invalid position
- if (segmentNumber == -1)
+ if (segmentIterator == end)
return 0;
// open file (if not already open)
- if (!openFile(segmentNumber))
+ if (!openFile(std::distance(begin, segmentIterator)))
return 0;
// work out position in current file
- uint64_t filePosition = position - m_segments[segmentNumber]->start;
+ uint64_t filePosition = position - segmentIterator->start;
// seek to position
if(lseek(m_file, filePosition, SEEK_SET) == -1)
@@ -264,55 +255,44 @@ int cRecPlayer::getBlock(unsigned char* buffer, uint64_t position, int amount)
uint64_t cRecPlayer::positionFromFrameNumber(uint32_t frameNumber)
{
- if (!m_indexFile)
- return 0;
-#if VDRVERSNUM < 10703
- unsigned char retFileNumber;
- int retFileOffset;
- unsigned char retPicType;
-#else
uint16_t retFileNumber;
off_t retFileOffset;
bool retPicType;
-#endif
int retLength;
-
- if (!m_indexFile->Get((int)frameNumber, &retFileNumber, &retFileOffset, &retPicType, &retLength))
+ if (!m_indexFile.Get((int)frameNumber, &retFileNumber, &retFileOffset, &retPicType, &retLength))
return 0;
- if (retFileNumber >= m_segments.Size())
+ if (retFileNumber >= m_segments.size())
return 0;
- uint64_t position = m_segments[retFileNumber]->start + retFileOffset;
+ uint64_t position = m_segments[retFileNumber].start + retFileOffset;
return position;
}
uint32_t cRecPlayer::frameNumberFromPosition(uint64_t position)
{
- if (!m_indexFile) return 0;
-
if (position >= m_totalLength)
{
DEBUGLOG("Client asked for data starting past end of recording!");
return m_totalFrames;
}
- int segmentNumber = -1;
- for(int i = 0; i < m_segments.Size(); i++)
- {
- if ((position >= m_segments[i]->start) && (position < m_segments[i]->end)) {
- segmentNumber = i;
+ std::vector<cSegment>::iterator begin = m_segments.begin(),
+ end = m_segments.end(), segmentIterator = end;
+ for (std::vector<cSegment>::iterator i = begin; i != end; ++i) {
+ if ((position >= i->start) && (position < i->end)) {
+ segmentIterator = i;
break;
}
}
- if(segmentNumber == -1) {
+ if (segmentIterator == end)
return m_totalFrames;
- }
- uint32_t askposition = position - m_segments[segmentNumber]->start;
- return m_indexFile->Get((int)segmentNumber, askposition);
+ uint32_t askposition = position - segmentIterator->start;
+ int segmentNumber = std::distance(begin, segmentIterator);
+ return m_indexFile.Get((int)segmentNumber, askposition);
}
@@ -321,20 +301,13 @@ bool cRecPlayer::getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_
// 0 = backwards
// 1 = forwards
- if (!m_indexFile) return false;
-
-#if VDRVERSNUM < 10703
- unsigned char waste1;
- int waste2;
-#else
uint16_t waste1;
off_t waste2;
-#endif
int iframeLength;
int indexReturnFrameNumber;
- indexReturnFrameNumber = (uint32_t)m_indexFile->GetNextIFrame(frameNumber, (direction==1 ? true : false), &waste1, &waste2, &iframeLength);
+ indexReturnFrameNumber = (uint32_t)m_indexFile.GetNextIFrame(frameNumber, (direction==1 ? true : false), &waste1, &waste2, &iframeLength);
DEBUGLOG("GNIF input framenumber:%u, direction=%u, output:framenumber=%i, framelength=%i", frameNumber, direction, indexReturnFrameNumber, iframeLength);
if (indexReturnFrameNumber == -1) return false;
diff --git a/recplayer.h b/recplayer.h
index 3d7b520..ce04cf6 100644
--- a/recplayer.h
+++ b/recplayer.h
@@ -33,10 +33,12 @@
#include <stdio.h>
#include <vdr/recording.h>
-#include <vdr/tools.h>
#include "config.h"
+#include <vector>
+#include <string>
+
class cSegment
{
public:
@@ -47,7 +49,7 @@ class cSegment
class cRecPlayer
{
public:
- cRecPlayer(cRecording* rec, bool inProgress = false);
+ cRecPlayer(const cRecording* rec, bool inProgress = false);
~cRecPlayer();
uint64_t getLengthBytes();
uint32_t getLengthFrames();
@@ -67,16 +69,16 @@ private:
char* fileNameFromIndex(int index);
void checkBufferSize(int s);
- char m_fileName[512];
- cIndexFile *m_indexFile;
- int m_file;
- int m_fileOpen;
- cVector<cSegment*> m_segments;
- uint64_t m_totalLength;
- uint32_t m_totalFrames;
- char *m_recordingFilename;
- bool m_pesrecording;
- bool m_inProgress;
+ const bool m_inProgress;
+ const std::string m_recordingFilename;
+ const bool m_pesrecording;
+ cIndexFile m_indexFile;
+ int m_file;
+ int m_fileOpen;
+ char m_fileName[512];
+ std::vector<cSegment> m_segments;
+ uint64_t m_totalLength;
+ uint32_t m_totalFrames;
};
#endif // VNSI_RECPLAYER_H
diff --git a/requestpacket.c b/requestpacket.c
index 4ab2b30..86fec04 100644
--- a/requestpacket.c
+++ b/requestpacket.c
@@ -24,8 +24,11 @@
*
*/
+#include "requestpacket.h"
+#include "vnsicommand.h"
+#include "config.h"
+
#include <stdlib.h>
-#include <stdint.h>
#include <string.h>
#ifndef __FreeBSD__
@@ -36,15 +39,10 @@
#define __cpu_to_be64 htobe64
#endif
-#include "config.h"
-#include "requestpacket.h"
-#include "vnsicommand.h"
-
-cRequestPacket::cRequestPacket(uint32_t requestID, uint32_t opcode, uint8_t* data, uint32_t dataLength)
+cRequestPacket::cRequestPacket(uint32_t requestID, uint32_t opcode, uint8_t* data, size_t dataLength)
: userData(data), userDataLength(dataLength), opCode(opcode), requestID(requestID)
{
packetPos = 0;
- ownBlock = true;
channelID = 0;
streamID = 0;
flag = 0;
@@ -52,37 +50,31 @@ cRequestPacket::cRequestPacket(uint32_t requestID, uint32_t opcode, uint8_t* dat
cRequestPacket::~cRequestPacket()
{
- if (!ownBlock) return; // don't free if it's a getblock
-
- if (userData) free(userData);
+ delete[] userData;
}
-bool cRequestPacket::end()
+bool cRequestPacket::end() const
{
return (packetPos >= userDataLength);
}
-int cRequestPacket::serverError()
-{
- if ((packetPos == 0) && (userDataLength == 4) && !ntohl(*(uint32_t*)userData)) return 1;
- else return 0;
-}
-
char* cRequestPacket::extract_String()
{
- if (serverError()) return NULL;
+ char *p = (char *)&userData[packetPos];
+ const char *end = (const char *)memchr(p, '\0', userDataLength - packetPos);
+ if (end == NULL)
+ /* string is not terminated - fail */
+ throw MalformedVNSIPacket();
- int length = strlen((char*)&userData[packetPos]);
- if ((packetPos + length) > userDataLength) return NULL;
- char* str = new char[length + 1];
- strcpy(str, (char*)&userData[packetPos]);
+ int length = end - p;
packetPos += length + 1;
- return str;
+ return p;
}
uint8_t cRequestPacket::extract_U8()
{
- if ((packetPos + sizeof(uint8_t)) > userDataLength) return 0;
+ if ((packetPos + sizeof(uint8_t)) > userDataLength)
+ throw MalformedVNSIPacket();
uint8_t uc = userData[packetPos];
packetPos += sizeof(uint8_t);
return uc;
@@ -90,7 +82,8 @@ uint8_t cRequestPacket::extract_U8()
uint32_t cRequestPacket::extract_U32()
{
- if ((packetPos + sizeof(uint32_t)) > userDataLength) return 0;
+ if ((packetPos + sizeof(uint32_t)) > userDataLength)
+ throw MalformedVNSIPacket();
uint32_t ul;
memcpy(&ul, &userData[packetPos], sizeof(uint32_t));
ul = ntohl(ul);
@@ -100,7 +93,8 @@ uint32_t cRequestPacket::extract_U32()
uint64_t cRequestPacket::extract_U64()
{
- if ((packetPos + sizeof(uint64_t)) > userDataLength) return 0;
+ if ((packetPos + sizeof(uint64_t)) > userDataLength)
+ throw MalformedVNSIPacket();
uint64_t ull;
memcpy(&ull, &userData[packetPos], sizeof(uint64_t));
ull = __be64_to_cpu(ull);
@@ -110,7 +104,8 @@ uint64_t cRequestPacket::extract_U64()
int64_t cRequestPacket::extract_S64()
{
- if ((packetPos + sizeof(int64_t)) > userDataLength) return 0;
+ if ((packetPos + sizeof(int64_t)) > userDataLength)
+ throw MalformedVNSIPacket();
int64_t ll;
memcpy(&ll, &userData[packetPos], sizeof(int64_t));
ll = __be64_to_cpu(ll);
@@ -120,7 +115,8 @@ int64_t cRequestPacket::extract_S64()
double cRequestPacket::extract_Double()
{
- if ((packetPos + sizeof(uint64_t)) > userDataLength) return 0;
+ if ((packetPos + sizeof(uint64_t)) > userDataLength)
+ throw MalformedVNSIPacket();
uint64_t ull;
memcpy(&ull, &userData[packetPos], sizeof(uint64_t));
ull = __be64_to_cpu(ull);
@@ -132,7 +128,8 @@ double cRequestPacket::extract_Double()
int32_t cRequestPacket::extract_S32()
{
- if ((packetPos + sizeof(int32_t)) > userDataLength) return 0;
+ if ((packetPos + sizeof(int32_t)) > userDataLength)
+ throw MalformedVNSIPacket();
int32_t l;
memcpy(&l, &userData[packetPos], sizeof(int32_t));
l = ntohl(l);
@@ -142,6 +139,5 @@ int32_t cRequestPacket::extract_S32()
uint8_t* cRequestPacket::getData()
{
- ownBlock = false;
return userData;
}
diff --git a/requestpacket.h b/requestpacket.h
index 368f971..65d0f66 100644
--- a/requestpacket.h
+++ b/requestpacket.h
@@ -27,20 +27,29 @@
#ifndef VNSI_REQUESTPACKET_H
#define VNSI_REQUESTPACKET_H
+#include <stddef.h>
+#include <stdint.h>
+
+#include <stdexcept>
+
+class MalformedVNSIPacket : public std::runtime_error {
+public:
+ MalformedVNSIPacket()
+ :std::runtime_error("Malformed VNSI packet") {}
+};
+
class cRequestPacket
{
public:
- cRequestPacket(uint32_t requestID, uint32_t opcode, uint8_t* data, uint32_t dataLength);
+ cRequestPacket(uint32_t requestID, uint32_t opcode, uint8_t* data, size_t dataLength);
~cRequestPacket();
- int serverError();
-
- uint32_t getDataLength() { return userDataLength; }
- uint32_t getChannelID() { return channelID; }
- uint32_t getRequestID() { return requestID; }
- uint32_t getStreamID() { return streamID; }
- uint32_t getFlag() { return flag; }
- uint32_t getOpCode() { return opCode; }
+ size_t getDataLength() const { return userDataLength; }
+ uint32_t getChannelID() const { return channelID; }
+ uint32_t getRequestID() const { return requestID; }
+ uint32_t getStreamID() const { return streamID; }
+ uint32_t getFlag() const { return flag; }
+ uint32_t getOpCode() const { return opCode; }
char* extract_String();
uint8_t extract_U8();
@@ -50,15 +59,15 @@ public:
int32_t extract_S32();
double extract_Double();
- bool end();
+ bool end() const;
// If you call this, the memory becomes yours. Free with free()
uint8_t* getData();
private:
uint8_t* userData;
- uint32_t userDataLength;
- uint32_t packetPos;
+ size_t userDataLength;
+ size_t packetPos;
uint32_t opCode;
uint32_t channelID;
@@ -67,8 +76,6 @@ private:
uint32_t streamID;
uint32_t flag; // stream only
-
- bool ownBlock;
};
#endif // VNSI_REQUESTPACKET_H
diff --git a/responsepacket.c b/responsepacket.c
index 92ad9ae..8e944f1 100644
--- a/responsepacket.c
+++ b/responsepacket.c
@@ -28,10 +28,13 @@
* This code is taken from VOMP for VDR plugin.
*/
+#include "responsepacket.h"
+#include "vnsicommand.h"
+#include "config.h"
+
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
-#include <inttypes.h>
#ifndef __FreeBSD__
#include <asm/byteorder.h>
@@ -41,10 +44,6 @@
#define __cpu_to_be64 htobe64
#endif
-#include "responsepacket.h"
-#include "vnsicommand.h"
-#include "config.h"
-
/* Packet format for an RR channel response:
4 bytes = channel ID = 1 (request/response channel)
@@ -73,7 +72,7 @@ void cResponsePacket::initBuffers()
}
}
-bool cResponsePacket::init(uint32_t requestID)
+void cResponsePacket::init(uint32_t requestID)
{
initBuffers();
@@ -87,11 +86,9 @@ bool cResponsePacket::init(uint32_t requestID)
memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
bufUsed = headerLength;
-
- return true;
}
-bool cResponsePacket::initScan(uint32_t opCode)
+void cResponsePacket::initScan(uint32_t opCode)
{
initBuffers();
@@ -105,11 +102,9 @@ bool cResponsePacket::initScan(uint32_t opCode)
memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
bufUsed = headerLength;
-
- return true;
}
-bool cResponsePacket::initStatus(uint32_t opCode)
+void cResponsePacket::initStatus(uint32_t opCode)
{
initBuffers();
@@ -123,11 +118,9 @@ bool cResponsePacket::initStatus(uint32_t opCode)
memcpy(&buffer[userDataLenPos], &ul, sizeof(uint32_t));
bufUsed = headerLength;
-
- return true;
}
-bool cResponsePacket::initStream(uint32_t opCode, uint32_t streamID, uint32_t duration, int64_t pts, int64_t dts, uint32_t serial)
+void cResponsePacket::initStream(uint32_t opCode, uint32_t streamID, uint32_t duration, int64_t pts, int64_t dts, uint32_t serial)
{
initBuffers();
@@ -152,11 +145,9 @@ bool cResponsePacket::initStream(uint32_t opCode, uint32_t streamID, uint32_t du
memcpy(&buffer[userDataLenPosStream], &ul, sizeof(uint32_t));
bufUsed = headerLengthStream;
-
- return true;
}
-bool cResponsePacket::initOsd(uint32_t opCode, int32_t wnd, int32_t color, int32_t x0, int32_t y0, int32_t x1, int32_t y1)
+void cResponsePacket::initOsd(uint32_t opCode, int32_t wnd, int32_t color, int32_t x0, int32_t y0, int32_t x1, int32_t y1)
{
initBuffers();
@@ -183,8 +174,6 @@ bool cResponsePacket::initOsd(uint32_t opCode, int32_t wnd, int32_t color, int32
memcpy(&buffer[userDataLenPosOSD], &ul, sizeof(uint32_t));
bufUsed = headerLengthOSD;
-
- return true;
}
void cResponsePacket::finalise()
diff --git a/responsepacket.h b/responsepacket.h
index 256a70a..6d7af8f 100644
--- a/responsepacket.h
+++ b/responsepacket.h
@@ -31,17 +31,19 @@
#ifndef VNSI_RESPONSEPACKET_H
#define VNSI_RESPONSEPACKET_H
+#include <stdint.h>
+
class cResponsePacket
{
public:
cResponsePacket();
~cResponsePacket();
- bool init(uint32_t requestID);
- bool initScan(uint32_t opCode);
- bool initStatus(uint32_t opCode);
- bool initStream(uint32_t opCode, uint32_t streamID, uint32_t duration, int64_t pts, int64_t dts, uint32_t serial);
- bool initOsd(uint32_t opCode, int32_t wnd, int32_t color, int32_t x0, int32_t y0, int32_t x1, int32_t y1);
+ void init(uint32_t requestID);
+ void initScan(uint32_t opCode);
+ void initStatus(uint32_t opCode);
+ void initStream(uint32_t opCode, uint32_t streamID, uint32_t duration, int64_t pts, int64_t dts, uint32_t serial);
+ void initOsd(uint32_t opCode, int32_t wnd, int32_t color, int32_t x0, int32_t y0, int32_t x1, int32_t y1);
void finalise();
void finaliseStream();
void finaliseOSD();
diff --git a/setup.c b/setup.c
index acc0aa3..008122d 100644
--- a/setup.c
+++ b/setup.c
@@ -32,12 +32,11 @@ int TimeshiftBufferFileSize = 6;
char TimeshiftBufferDir[PATH_MAX] = "\0";
int PlayRecording = 0;
int AvoidEPGScan = 1;
+int DisableScrambleTimeout = 0;
+int DisableCamBlacklist = 0;
cMenuSetupVNSI::cMenuSetupVNSI(void)
{
- newPmtTimeout = PmtTimeout;
- Add(new cMenuEditIntItem( tr("PMT Timeout (0-10)"), &newPmtTimeout));
-
timeshiftModesTexts[0] = tr("Off");
timeshiftModesTexts[1] = tr("RAM");
timeshiftModesTexts[2] = tr("File");
@@ -58,6 +57,12 @@ cMenuSetupVNSI::cMenuSetupVNSI(void)
newAvoidEPGScan = AvoidEPGScan;
Add(new cMenuEditBoolItem( tr("Avoid EPG scan while streaming"), &newAvoidEPGScan));
+
+ newDisableScrambleTimeout = DisableScrambleTimeout;
+ Add(new cMenuEditBoolItem( tr("Disable scramble timeout"), &newDisableScrambleTimeout));
+
+ newDisableCamBlacklist = DisableCamBlacklist;
+ Add(new cMenuEditBoolItem( tr("Disable cam blacklist"), &newDisableCamBlacklist));
}
void cMenuSetupVNSI::Store(void)
@@ -80,9 +85,18 @@ void cMenuSetupVNSI::Store(void)
newTimeshiftBufferFileSize = 1;
SetupStore(CONFNAME_TIMESHIFTBUFFERFILESIZE, TimeshiftBufferFileSize = newTimeshiftBufferFileSize);
- SetupStore(CONFNAME_TIMESHIFTBUFFERDIR, strn0cpy(TimeshiftBufferDir, newTimeshiftBufferDir, sizeof(TimeshiftBufferDir)));
+ strn0cpy(TimeshiftBufferDir, newTimeshiftBufferDir, sizeof(TimeshiftBufferDir));
+ if (*TimeshiftBufferDir && TimeshiftBufferDir[strlen(TimeshiftBufferDir)-1] == '/')
+ /* strip trailing slash */
+ TimeshiftBufferDir[strlen(TimeshiftBufferDir)-1] = 0;
+
+ SetupStore(CONFNAME_TIMESHIFTBUFFERDIR, TimeshiftBufferDir);
SetupStore(CONFNAME_PLAYRECORDING, PlayRecording = newPlayRecording);
SetupStore(CONFNAME_AVOIDEPGSCAN, AvoidEPGScan = newAvoidEPGScan);
+
+ SetupStore(CONFNAME_DISABLESCRAMBLETIMEOUT, DisableScrambleTimeout = newDisableScrambleTimeout);
+
+ SetupStore(CONFNAME_DISABLECAMBLACKLIST, DisableCamBlacklist = newDisableCamBlacklist);
}
diff --git a/setup.h b/setup.h
index cd4f0dc..e37ad10 100644
--- a/setup.h
+++ b/setup.h
@@ -38,6 +38,8 @@ private:
char newTimeshiftBufferDir[PATH_MAX];
int newPlayRecording;
int newAvoidEPGScan;
+ int newDisableScrambleTimeout;
+ int newDisableCamBlacklist;
protected:
virtual void Store(void);
public:
diff --git a/status.c b/status.c
index b8f41e1..3c28934 100644
--- a/status.c
+++ b/status.c
@@ -22,70 +22,137 @@
*
*/
-#include "vnsi.h"
#include "status.h"
-#include "vnsiclient.h"
+#include "vnsi.h"
+
#include <vdr/tools.h>
#include <vdr/recording.h>
#include <vdr/videodir.h>
#include <vdr/shutdown.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+cVNSIStatus::cVNSIStatus() : cThread("VNSIStatus")
+{
+}
+
cVNSIStatus::~cVNSIStatus()
{
Shutdown();
}
+void cVNSIStatus::Init(CVNSITimers *timers)
+{
+ m_vnsiTimers = timers;
+ Start();
+}
+
void cVNSIStatus::Shutdown()
{
Cancel(5);
cMutexLock lock(&m_mutex);
- for (ClientList::iterator i = m_clients.begin(); i != m_clients.end(); i++)
- {
- delete (*i);
- }
- m_clients.erase(m_clients.begin(), m_clients.end());
+ m_clients.clear();
}
-void cVNSIStatus::AddClient(cVNSIClient* client)
+static bool CheckFileSuffix(const char *name,
+ const char *suffix, size_t suffix_length)
{
- cMutexLock lock(&m_mutex);
- m_clients.push_back(client);
+ size_t name_length = strlen(name);
+ return name_length > suffix_length &&
+ memcmp(name + name_length - suffix_length, suffix, suffix_length) == 0;
+}
+
+static void DeleteFiles(const char *directory_path, const char *suffix)
+{
+ const size_t suffix_length = strlen(suffix);
+
+ DIR *dir = opendir(directory_path);
+ if (dir == nullptr)
+ return;
+
+ std::string path(directory_path);
+ path.push_back('/');
+ const size_t start = path.size();
+
+ while (auto *e = readdir(dir))
+ {
+ if (CheckFileSuffix(e->d_name, suffix, suffix_length))
+ {
+ path.replace(start, path.size(), e->d_name);
+
+ if (unlink(path.c_str()) < 0)
+ {
+ ERRORLOG("Failed to delete %s: %s", path.c_str(), strerror(errno));
+ }
+ }
+ }
+
+ closedir(dir);
}
void cVNSIStatus::Action(void)
{
cTimeMs chanTimer(0);
+ cTimeMs epgTimer(0);
// get initial state of the recordings
+#if VDRVERSNUM >= 20301
+ cStateKey chanState;
+ const cChannels *channels = cChannels::GetChannelsRead(chanState);
+ chanState.Remove(false);
+#endif
+
+ // get initial state of the recordings
+#if VDRVERSNUM >= 20301
+ cStateKey recState;
+ const cRecordings *recordings = cRecordings::GetRecordingsRead(recState);
+ recState.Remove(false);
+#else
int recState = -1;
Recordings.StateChanged(recState);
+#endif
// get initial state of the timers
+#if VDRVERSNUM >= 20301
+ cStateKey timerState;
+ const cTimers *timers = cTimers::GetTimersRead(timerState);
+ timerState.Remove(false);
+#else
int timerState = -1;
Timers.Modified(timerState);
+#endif
+
+ // vnsitimer
+ int vnsitimerState;
+ m_vnsiTimers->StateChange(vnsitimerState);
// last update of epg
+#if VDRVERSNUM >= 20301
+ cStateKey epgState;
+ const cSchedules *epg = cSchedules::GetSchedulesRead(epgState);
+ epgState.Remove(false);
+#else
time_t epgUpdate = cSchedules::Modified();
+#endif
// delete old timeshift file
- cString cmd;
struct stat sb;
if ((*TimeshiftBufferDir) && stat(TimeshiftBufferDir, &sb) == 0 && S_ISDIR(sb.st_mode))
{
- if (TimeshiftBufferDir[strlen(TimeshiftBufferDir)-1] == '/')
- cmd = cString::sprintf("rm -f %s*.vnsi", TimeshiftBufferDir);
- else
- cmd = cString::sprintf("rm -f %s/*.vnsi", TimeshiftBufferDir);
+ DeleteFiles(TimeshiftBufferDir, ".vnsi");
}
else
{
#if VDRVERSNUM >= 20102
- cmd = cString::sprintf("rm -f %s/*.vnsi", cVideoDirectory::Name());
+ DeleteFiles(cVideoDirectory::Name(), ".vnsi");
#else
- cmd = cString::sprintf("rm -f %s/*.vnsi", VideoDirectory);
+ DeleteFiles(VideoDirectory, ".vnsi");
#endif
}
- int ret = system(cmd);
// set thread priority
SetPriority(1);
@@ -97,10 +164,9 @@ void cVNSIStatus::Action(void)
// remove disconnected clients
for (ClientList::iterator i = m_clients.begin(); i != m_clients.end();)
{
- if (!(*i)->Active())
+ if (!i->Active())
{
- INFOLOG("Client with ID %u seems to be disconnected, removing from client list", (*i)->GetID());
- delete (*i);
+ INFOLOG("Client with ID %u seems to be disconnected, removing from client list", i->GetID());
i = m_clients.erase(i);
}
else {
@@ -114,33 +180,99 @@ void cVNSIStatus::Action(void)
*/
if (!cVNSIClient::InhibidDataUpdates())
{
+ // reset inactivity timeout as long as there are clients connected
+ if (!m_clients.empty())
+ {
+ ShutdownHandler.SetUserInactiveTimeout();
+ }
+
// trigger clients to reload the modified channel list
- if(m_clients.size() > 0 && chanTimer.TimedOut())
+ if(chanTimer.TimedOut())
{
+#if VDRVERSNUM >= 20301
+ if (channels->Lock(chanState))
+ {
+ chanState.Remove(false);
+ INFOLOG("Requesting clients to reload channel list");
+ for (auto &i : m_clients)
+ i.ChannelsChange();
+ chanTimer.Set(5000);
+ }
+#else
int modified = Channels.Modified();
if (modified)
{
Channels.SetModified((modified == CHANNELSMOD_USER) ? true : false);
INFOLOG("Requesting clients to reload channel list");
- for (ClientList::iterator i = m_clients.begin(); i != m_clients.end(); i++)
- (*i)->ChannelsChange();
+ for (auto &i : m_clients)
+ i.ChannelsChange();
}
chanTimer.Set(5000);
+#endif
}
- // reset inactivity timeout as long as there are clients connected
- if(m_clients.size() > 0)
+
+#if VDRVERSNUM >= 20301
+ if (recordings->Lock(recState))
{
- ShutdownHandler.SetUserInactiveTimeout();
+ recState.Remove();
+ INFOLOG("Requesting clients to reload recordings list");
+ for (auto &i : m_clients)
+ {
+ i.RecordingsChange();
+ }
}
+ if (timers->Lock(timerState))
+ {
+ timerState.Remove(false);
+ INFOLOG("Requesting clients to reload timers");
+ for (auto &i : m_clients)
+ {
+ i.SignalTimerChange();
+ }
+ }
+
+ if (m_vnsiTimers->StateChange(vnsitimerState))
+ {
+ INFOLOG("Requesting clients to reload vnsi-timers");
+ for (auto &i : m_clients)
+ {
+ i.SignalTimerChange();
+ }
+ }
+
+ if (epgTimer.TimedOut())
+ {
+ if (epg->Lock(epgState))
+ {
+ epgState.Remove(false);
+ INFOLOG("Requesting clients to load epg");
+ bool callAgain = false;
+ for (auto &i : m_clients)
+ {
+ callAgain |= i.EpgChange();
+ }
+ if (callAgain)
+ {
+ epgTimer.Set(100);
+ epgState.Reset();
+ }
+ else
+ {
+ epgTimer.Set(5000);
+ m_vnsiTimers->Scan();
+ }
+ }
+ }
+#else
// update recordings
if(Recordings.StateChanged(recState))
{
INFOLOG("Recordings state changed (%i)", recState);
INFOLOG("Requesting clients to reload recordings list");
- for (ClientList::iterator i = m_clients.begin(); i != m_clients.end(); i++)
- (*i)->RecordingsChange();
+ for (auto &i : m_clients)
+ i.RecordingsChange();
}
// update timers
@@ -148,21 +280,22 @@ void cVNSIStatus::Action(void)
{
INFOLOG("Timers state changed (%i)", timerState);
INFOLOG("Requesting clients to reload timers");
- for (ClientList::iterator i = m_clients.begin(); i != m_clients.end(); i++)
+ for (auto &i : m_clients)
{
- (*i)->TimerChange();
+ i.SignalTimerChange();
}
}
// update epg
if((cSchedules::Modified() > epgUpdate + 10) || time(NULL) > epgUpdate + 300)
{
- for (ClientList::iterator i = m_clients.begin(); i != m_clients.end(); i++)
+ for (auto &i : m_clients)
{
- (*i)->EpgChange();
+ i.EpgChange();
}
epgUpdate = time(NULL);
}
+#endif
}
m_mutex.Unlock();
diff --git a/status.h b/status.h
index 94015a2..aaea7f5 100644
--- a/status.h
+++ b/status.h
@@ -26,21 +26,35 @@
#include <vdr/thread.h>
#include <list>
+#include "vnsitimer.h"
+#include "vnsiclient.h"
class cVNSIClient;
-typedef std::list<cVNSIClient*> ClientList;
+typedef std::list<cVNSIClient> ClientList;
class cVNSIStatus : public cThread
{
public:
+ cVNSIStatus();
virtual ~cVNSIStatus();
+
+ cVNSIStatus(const cVNSIStatus &) = delete;
+ cVNSIStatus &operator=(const cVNSIStatus &) = delete;
+
+ void Init(CVNSITimers *timers);
void Shutdown();
- void AddClient(cVNSIClient* client);
+
+ template<typename... Args>
+ void AddClient(Args&&... args) {
+ cMutexLock lock(&m_mutex);
+ m_clients.emplace_back(std::forward<Args>(args)...);
+ }
protected:
virtual void Action(void);
ClientList m_clients;
cMutex m_mutex;
+ CVNSITimers *m_vnsiTimers;
};
diff --git a/streamer.c b/streamer.c
index 782bfb6..3a35212 100644
--- a/streamer.c
+++ b/streamer.c
@@ -46,19 +46,9 @@ cLiveStreamer::cLiveStreamer(int clientID, bool bAllowRDS, uint8_t timeshift, ui
, m_ClientID(clientID)
, m_scanTimeout(timeout)
, m_Demuxer(bAllowRDS)
- , m_VideoInput(m_Event, m_Mutex, m_IsRetune)
+ , m_VideoInput(m_Event)
{
- m_Channel = NULL;
- m_Socket = NULL;
- m_Frontend = -1;
- m_IsAudioOnly = false;
- m_IsMPEGPS = false;
- m_startup = true;
- m_SignalLost = false;
- m_IFrameSeen = false;
- m_VideoBuffer = NULL;
m_Timeshift = timeshift;
- m_IsRetune = false;
memset(&m_FrontendInfo, 0, sizeof(m_FrontendInfo));
@@ -97,12 +87,30 @@ bool cLiveStreamer::Open(int serial)
}
else if (PlayRecording && serial == -1)
{
+#if VDRVERSNUM >= 20301
+ LOCK_TIMERS_READ;
+ for (const cTimer *timer = Timers->First(); timer; timer = Timers->Next(timer))
+#else
for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer))
+#endif
{
if (timer &&
timer->Recording() &&
timer->Channel() == m_Channel)
{
+#if VDRVERSNUM >= 20301
+ LOCK_RECORDINGS_READ;
+ cTimer t(*timer);
+ cRecording matchRec(&t, t.Event());
+ const cRecording *rec;
+ {
+ rec = Recordings->GetByName(matchRec.FileName());
+ if (!rec)
+ {
+ return false;
+ }
+ }
+#else
Recordings.Load();
cRecording matchRec(timer, timer->Event());
cRecording *rec;
@@ -114,6 +122,7 @@ bool cLiveStreamer::Open(int serial)
return false;
}
}
+#endif
m_VideoBuffer = cVideoBuffer::Create(rec);
recording = true;
break;
@@ -133,7 +142,6 @@ bool cLiveStreamer::Open(int serial)
if (m_Channel && ((m_Channel->Source() >> 24) == 'V'))
m_IsMPEGPS = true;
- m_IsRetune = false;
if (!m_VideoInput.Open(m_Channel, m_Priority, m_VideoBuffer))
{
ERRORLOG("Can't switch to channel %i - %s", m_Channel->Number(), m_Channel->Name());
@@ -177,13 +185,17 @@ void cLiveStreamer::Action(void)
bool requestStreamChangeSideData = false;
cTimeMs last_info(1000);
cTimeMs bufferStatsTimer(1000);
+ int openFailCount = 0;
while (Running())
{
- if (m_IsRetune)
+ auto retune = m_VideoInput.ReceivingStatus();
+ if (retune == cVideoInput::RETUNE)
+ // allow timeshift playback when retune == cVideoInput::CLOSE
ret = -1;
else
ret = m_Demuxer.Read(&pkt_data, &pkt_side_data);
+
if (ret > 0)
{
if (pkt_data.pmtChange)
@@ -241,29 +253,39 @@ void cLiveStreamer::Action(void)
else if (ret == -1)
{
// no data
+ if (retune == cVideoInput::CLOSE)
{
- bool retune = false;
- {
- cMutexLock lock(&m_Mutex);
- retune = m_IsRetune;
- if (!retune)
- m_Event.TimedWait(m_Mutex, 10);
- }
- if (retune)
+ m_Socket->Shutdown();
+ break;
+ }
+ if (m_Demuxer.GetError() & ERROR_CAM_ERROR)
+ {
+ INFOLOG("CAM error, try reset");
+ cCamSlot *cs = m_Device->CamSlot();
+ if (cs)
+ cs->StopDecrypting();
+ retune = cVideoInput::RETUNE;
+ }
+ if (retune == cVideoInput::RETUNE)
+ {
+ INFOLOG("re-tuning...");
+ m_VideoInput.Close();
+ if (!m_VideoInput.Open(m_Channel, m_Priority, m_VideoBuffer))
{
- m_VideoInput.Close();
- if (m_VideoInput.Open(m_Channel, m_Priority, m_VideoBuffer))
+ if (++openFailCount == 3)
{
- cMutexLock lock(&m_Mutex);
- m_IsRetune = false;
+ openFailCount = 0;
+ cCondWait::SleepMs(2000);
}
else
- {
- cMutexLock lock(&m_Mutex);
- m_Event.TimedWait(m_Mutex, 100);
- }
+ cCondWait::SleepMs(100);
}
+ else
+ openFailCount = 0;
}
+ else
+ m_Event.Wait(10);
+
if(m_last_tick.Elapsed() >= (uint64_t)(m_scanTimeout*1000))
{
sendStreamStatus();
@@ -295,6 +317,9 @@ bool cLiveStreamer::StreamChannel(const cChannel *channel, int priority, cxSocke
m_Priority = priority;
m_Socket = Socket;
+ if (m_Priority < 0)
+ m_Priority = 0;
+
if (!Open())
return false;
@@ -331,11 +356,7 @@ void cLiveStreamer::sendStreamPacket(sStreamPacket *pkt)
if(pkt->size == 0)
return;
- if (!m_streamHeader.initStream(VNSI_STREAM_MUXPKT, pkt->id, pkt->duration, pkt->pts, pkt->dts, pkt->serial))
- {
- ERRORLOG("stream response packet init fail");
- return;
- }
+ m_streamHeader.initStream(VNSI_STREAM_MUXPKT, pkt->id, pkt->duration, pkt->pts, pkt->dts, pkt->serial);
m_streamHeader.setLen(m_streamHeader.getStreamHeaderLength() + pkt->size);
m_streamHeader.finaliseStream();
@@ -350,136 +371,140 @@ void cLiveStreamer::sendStreamPacket(sStreamPacket *pkt)
void cLiveStreamer::sendStreamChange()
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStream(VNSI_STREAM_CHANGE, 0, 0, 0, 0, 0))
- {
- ERRORLOG("stream response packet init fail");
- delete resp;
- return;
- }
+ cResponsePacket resp;
+ resp.initStream(VNSI_STREAM_CHANGE, 0, 0, 0, 0, 0);
uint32_t FpsScale, FpsRate, Height, Width;
double Aspect;
uint32_t Channels, SampleRate, BitRate, BitsPerSample, BlockAlign;
for (cTSStream* stream = m_Demuxer.GetFirstStream(); stream; stream = m_Demuxer.GetNextStream())
{
- resp->add_U32(stream->GetPID());
+ resp.add_U32(stream->GetPID());
if (stream->Type() == stMPEG2AUDIO)
{
stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
- resp->add_String("MPEG2AUDIO");
- resp->add_String(stream->GetLanguage());
- resp->add_U32(Channels);
- resp->add_U32(SampleRate);
- resp->add_U32(BlockAlign);
- resp->add_U32(BitRate);
- resp->add_U32(BitsPerSample);
-
- for (unsigned int i = 0; i < stream->GetSideDataTypes()->size(); i++)
+ resp.add_String("MPEG2AUDIO");
+ resp.add_String(stream->GetLanguage());
+ resp.add_U32(Channels);
+ resp.add_U32(SampleRate);
+ resp.add_U32(BlockAlign);
+ resp.add_U32(BitRate);
+ resp.add_U32(BitsPerSample);
+
+ for (const auto &i : stream->GetSideDataTypes())
{
- resp->add_U32(stream->GetSideDataTypes()->at(i).first);
- if (stream->GetSideDataTypes()->at(i).second == scRDS)
+ resp.add_U32(i.first);
+ if (i.second == scRDS)
{
- resp->add_String("RDS");
- resp->add_String(stream->GetLanguage());
- resp->add_U32(stream->GetPID());
+ resp.add_String("RDS");
+ resp.add_String(stream->GetLanguage());
+ resp.add_U32(stream->GetPID());
}
}
}
else if (stream->Type() == stMPEG2VIDEO)
{
stream->GetVideoInformation(FpsScale, FpsRate, Height, Width, Aspect);
- resp->add_String("MPEG2VIDEO");
- resp->add_U32(FpsScale);
- resp->add_U32(FpsRate);
- resp->add_U32(Height);
- resp->add_U32(Width);
- resp->add_double(Aspect);
+ resp.add_String("MPEG2VIDEO");
+ resp.add_U32(FpsScale);
+ resp.add_U32(FpsRate);
+ resp.add_U32(Height);
+ resp.add_U32(Width);
+ resp.add_double(Aspect);
}
else if (stream->Type() == stAC3)
{
stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
- resp->add_String("AC3");
- resp->add_String(stream->GetLanguage());
- resp->add_U32(Channels);
- resp->add_U32(SampleRate);
- resp->add_U32(BlockAlign);
- resp->add_U32(BitRate);
- resp->add_U32(BitsPerSample);
+ resp.add_String("AC3");
+ resp.add_String(stream->GetLanguage());
+ resp.add_U32(Channels);
+ resp.add_U32(SampleRate);
+ resp.add_U32(BlockAlign);
+ resp.add_U32(BitRate);
+ resp.add_U32(BitsPerSample);
}
else if (stream->Type() == stH264)
{
stream->GetVideoInformation(FpsScale, FpsRate, Height, Width, Aspect);
- resp->add_String("H264");
- resp->add_U32(FpsScale);
- resp->add_U32(FpsRate);
- resp->add_U32(Height);
- resp->add_U32(Width);
- resp->add_double(Aspect);
+ resp.add_String("H264");
+ resp.add_U32(FpsScale);
+ resp.add_U32(FpsRate);
+ resp.add_U32(Height);
+ resp.add_U32(Width);
+ resp.add_double(Aspect);
+ }
+ else if (stream->Type() == stHEVC)
+ {
+ stream->GetVideoInformation(FpsScale, FpsRate, Height, Width, Aspect);
+ resp.add_String("HEVC");
+ resp.add_U32(FpsScale);
+ resp.add_U32(FpsRate);
+ resp.add_U32(Height);
+ resp.add_U32(Width);
+ resp.add_double(Aspect);
}
else if (stream->Type() == stDVBSUB)
{
- resp->add_String("DVBSUB");
- resp->add_String(stream->GetLanguage());
- resp->add_U32(stream->CompositionPageId());
- resp->add_U32(stream->AncillaryPageId());
+ resp.add_String("DVBSUB");
+ resp.add_String(stream->GetLanguage());
+ resp.add_U32(stream->CompositionPageId());
+ resp.add_U32(stream->AncillaryPageId());
}
else if (stream->Type() == stTELETEXT)
{
- resp->add_String("TELETEXT");
- resp->add_String(stream->GetLanguage());
- resp->add_U32(stream->CompositionPageId());
- resp->add_U32(stream->AncillaryPageId());
+ resp.add_String("TELETEXT");
+ resp.add_String(stream->GetLanguage());
+ resp.add_U32(stream->CompositionPageId());
+ resp.add_U32(stream->AncillaryPageId());
}
else if (stream->Type() == stAACADTS)
{
stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
- resp->add_String("AAC");
- resp->add_String(stream->GetLanguage());
- resp->add_U32(Channels);
- resp->add_U32(SampleRate);
- resp->add_U32(BlockAlign);
- resp->add_U32(BitRate);
- resp->add_U32(BitsPerSample);
+ resp.add_String("AAC");
+ resp.add_String(stream->GetLanguage());
+ resp.add_U32(Channels);
+ resp.add_U32(SampleRate);
+ resp.add_U32(BlockAlign);
+ resp.add_U32(BitRate);
+ resp.add_U32(BitsPerSample);
}
else if (stream->Type() == stAACLATM)
{
stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
- resp->add_String("AAC_LATM");
- resp->add_String(stream->GetLanguage());
- resp->add_U32(Channels);
- resp->add_U32(SampleRate);
- resp->add_U32(BlockAlign);
- resp->add_U32(BitRate);
- resp->add_U32(BitsPerSample);
+ resp.add_String("AAC_LATM");
+ resp.add_String(stream->GetLanguage());
+ resp.add_U32(Channels);
+ resp.add_U32(SampleRate);
+ resp.add_U32(BlockAlign);
+ resp.add_U32(BitRate);
+ resp.add_U32(BitsPerSample);
}
else if (stream->Type() == stEAC3)
{
stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
- resp->add_String("EAC3");
- resp->add_String(stream->GetLanguage());
- resp->add_U32(Channels);
- resp->add_U32(SampleRate);
- resp->add_U32(BlockAlign);
- resp->add_U32(BitRate);
- resp->add_U32(BitsPerSample);
+ resp.add_String("EAC3");
+ resp.add_String(stream->GetLanguage());
+ resp.add_U32(Channels);
+ resp.add_U32(SampleRate);
+ resp.add_U32(BlockAlign);
+ resp.add_U32(BitRate);
+ resp.add_U32(BitsPerSample);
}
else if (stream->Type() == stDTS)
{
stream->GetAudioInformation(Channels, SampleRate, BitRate, BitsPerSample, BlockAlign);
- resp->add_String("DTS");
- resp->add_String(stream->GetLanguage());
- resp->add_U32(Channels);
- resp->add_U32(SampleRate);
- resp->add_U32(BlockAlign);
- resp->add_U32(BitRate);
- resp->add_U32(BitsPerSample);
+ resp.add_String("DTS");
+ resp.add_String(stream->GetLanguage());
+ resp.add_U32(Channels);
+ resp.add_U32(SampleRate);
+ resp.add_U32(BlockAlign);
+ resp.add_U32(BitRate);
+ resp.add_U32(BitsPerSample);
}
}
- resp->finaliseStream();
- m_Socket->write(resp->getPtr(), resp->getLen());
- delete resp;
+ resp.finaliseStream();
+ m_Socket->write(resp.getPtr(), resp.getLen());
}
void cLiveStreamer::sendSignalInfo()
@@ -488,24 +513,17 @@ void cLiveStreamer::sendSignalInfo()
return a empty signalinfo package */
if (m_Frontend == -2)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStream(VNSI_STREAM_SIGNALINFO, 0, 0, 0, 0, 0))
- {
- ERRORLOG("stream response packet init fail");
- delete resp;
- return;
- }
-
- resp->add_String(*cString::sprintf("Unknown"));
- resp->add_String(*cString::sprintf("Unknown"));
- resp->add_U32(0);
- resp->add_U32(0);
- resp->add_U32(0);
- resp->add_U32(0);
-
- resp->finaliseStream();
- m_Socket->write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initStream(VNSI_STREAM_SIGNALINFO, 0, 0, 0, 0, 0);
+ resp.add_String(*cString::sprintf("Unknown"));
+ resp.add_String(*cString::sprintf("Unknown"));
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_U32(0);
+
+ resp.finaliseStream();
+ m_Socket->write(resp.getPtr(), resp.getLen());
return;
}
@@ -536,23 +554,17 @@ void cLiveStreamer::sendSignalInfo()
if (m_Frontend >= 0)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStream(VNSI_STREAM_SIGNALINFO, 0, 0, 0, 0, 0))
- {
- ERRORLOG("stream response packet init fail");
- delete resp;
- return;
- }
- resp->add_String(*cString::sprintf("Analog #%s - %s (%s)", *m_DeviceString, (char *) m_vcap.card, m_vcap.driver));
- resp->add_String("");
- resp->add_U32(0);
- resp->add_U32(0);
- resp->add_U32(0);
- resp->add_U32(0);
-
- resp->finaliseStream();
- m_Socket->write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initStream(VNSI_STREAM_SIGNALINFO, 0, 0, 0, 0, 0);
+ resp.add_String(*cString::sprintf("Analog #%s - %s (%s)", *m_DeviceString, (char *) m_vcap.card, m_vcap.driver));
+ resp.add_String("");
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_U32(0);
+
+ resp.finaliseStream();
+ m_Socket->write(resp.getPtr(), resp.getLen());
}
}
else
@@ -576,13 +588,8 @@ void cLiveStreamer::sendSignalInfo()
if (m_Frontend >= 0)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStream(VNSI_STREAM_SIGNALINFO, 0, 0, 0, 0, 0))
- {
- ERRORLOG("stream response packet init fail");
- delete resp;
- return;
- }
+ cResponsePacket resp;
+ resp.initStream(VNSI_STREAM_SIGNALINFO, 0, 0, 0, 0, 0);
fe_status_t status;
uint16_t fe_snr;
@@ -605,82 +612,75 @@ void cLiveStreamer::sendSignalInfo()
switch (m_Channel->Source() & cSource::st_Mask)
{
case cSource::stSat:
- resp->add_String(*cString::sprintf("DVB-S%s #%d - %s", (m_FrontendInfo.caps & 0x10000000) ? "2" : "", cDevice::ActualDevice()->CardIndex(), m_FrontendInfo.name));
+ resp.add_String(*cString::sprintf("DVB-S%s #%d - %s", (m_FrontendInfo.caps & 0x10000000) ? "2" : "", cDevice::ActualDevice()->CardIndex(), m_FrontendInfo.name));
break;
case cSource::stCable:
- resp->add_String(*cString::sprintf("DVB-C #%d - %s", cDevice::ActualDevice()->CardIndex(), m_FrontendInfo.name));
+ resp.add_String(*cString::sprintf("DVB-C #%d - %s", cDevice::ActualDevice()->CardIndex(), m_FrontendInfo.name));
break;
case cSource::stTerr:
- resp->add_String(*cString::sprintf("DVB-T #%d - %s", cDevice::ActualDevice()->CardIndex(), m_FrontendInfo.name));
+ resp.add_String(*cString::sprintf("DVB-T #%d - %s", cDevice::ActualDevice()->CardIndex(), m_FrontendInfo.name));
+ break;
+ case cSource::stAtsc:
+ resp.add_String(*cString::sprintf("ATSC #%d - %s", cDevice::ActualDevice()->CardIndex(), m_FrontendInfo.name));
+ break;
+ default:
+ resp.add_U8(0);
break;
}
- resp->add_String(*cString::sprintf("%s:%s:%s:%s:%s", (status & FE_HAS_LOCK) ? "LOCKED" : "-", (status & FE_HAS_SIGNAL) ? "SIGNAL" : "-", (status & FE_HAS_CARRIER) ? "CARRIER" : "-", (status & FE_HAS_VITERBI) ? "VITERBI" : "-", (status & FE_HAS_SYNC) ? "SYNC" : "-"));
- resp->add_U32(fe_snr);
- resp->add_U32(fe_signal);
- resp->add_U32(fe_ber);
- resp->add_U32(fe_unc);
-
- resp->finaliseStream();
- m_Socket->write(resp->getPtr(), resp->getLen());
- delete resp;
+ resp.add_String(*cString::sprintf("%s:%s:%s:%s:%s", (status & FE_HAS_LOCK) ? "LOCKED" : "-", (status & FE_HAS_SIGNAL) ? "SIGNAL" : "-", (status & FE_HAS_CARRIER) ? "CARRIER" : "-", (status & FE_HAS_VITERBI) ? "VITERBI" : "-", (status & FE_HAS_SYNC) ? "SYNC" : "-"));
+ resp.add_U32(fe_snr);
+ resp.add_U32(fe_signal);
+ resp.add_U32(fe_ber);
+ resp.add_U32(fe_unc);
+
+ resp.finaliseStream();
+ m_Socket->write(resp.getPtr(), resp.getLen());
}
}
}
void cLiveStreamer::sendStreamStatus()
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStream(VNSI_STREAM_STATUS, 0, 0, 0, 0, 0))
- {
- ERRORLOG("stream response packet init fail");
- delete resp;
- return;
- }
+ cResponsePacket resp;
+ resp.initStream(VNSI_STREAM_STATUS, 0, 0, 0, 0, 0);
uint16_t error = m_Demuxer.GetError();
if (error & ERROR_PES_SCRAMBLE)
{
INFOLOG("Channel: scrambled %d", error);
- resp->add_String(cString::sprintf("Channel: scrambled (%d)", error));
+ resp.add_String(cString::sprintf("Channel: scrambled (%d)", error));
}
else if (error & ERROR_PES_STARTCODE)
{
INFOLOG("Channel: startcode %d", error);
- resp->add_String(cString::sprintf("Channel: encrypted? (%d)", error));
+ resp.add_String(cString::sprintf("Channel: encrypted? (%d)", error));
}
else if (error & ERROR_DEMUX_NODATA)
{
INFOLOG("Channel: no data %d", error);
- resp->add_String(cString::sprintf("Channel: no data"));
+ resp.add_String(cString::sprintf("Channel: no data"));
}
else
{
INFOLOG("Channel: unknown error %d", error);
- resp->add_String(cString::sprintf("Channel: unknown error (%d)", error));
+ resp.add_String(cString::sprintf("Channel: unknown error (%d)", error));
}
- resp->finaliseStream();
- m_Socket->write(resp->getPtr(), resp->getLen());
- delete resp;
+ resp.finaliseStream();
+ m_Socket->write(resp.getPtr(), resp.getLen());
}
void cLiveStreamer::sendBufferStatus()
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStream(VNSI_STREAM_BUFFERSTATS, 0, 0, 0, 0, 0))
- {
- ERRORLOG("stream response packet init fail");
- delete resp;
- return;
- }
+ cResponsePacket resp;
+ resp.initStream(VNSI_STREAM_BUFFERSTATS, 0, 0, 0, 0, 0);
uint32_t start, end;
bool timeshift;
m_Demuxer.BufferStatus(timeshift, start, end);
- resp->add_U8(timeshift);
- resp->add_U32(start);
- resp->add_U32(end);
- resp->finaliseStream();
- m_Socket->write(resp->getPtr(), resp->getLen());
- delete resp;
+ resp.add_U8(timeshift);
+ resp.add_U32(start);
+ resp.add_U32(end);
+ resp.finaliseStream();
+ m_Socket->write(resp.getPtr(), resp.getLen());
}
void cLiveStreamer::sendRefTime(sStreamPacket *pkt)
@@ -688,19 +688,12 @@ void cLiveStreamer::sendRefTime(sStreamPacket *pkt)
if(pkt == NULL)
return;
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStream(VNSI_STREAM_REFTIME, 0, 0, 0, 0, 0))
- {
- ERRORLOG("stream response packet init fail");
- delete resp;
- return;
- }
-
- resp->add_U32(pkt->reftime);
- resp->add_U64(pkt->pts);
- resp->finaliseStream();
- m_Socket->write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initStream(VNSI_STREAM_REFTIME, 0, 0, 0, 0, 0);
+ resp.add_U32(pkt->reftime);
+ resp.add_U64(pkt->pts);
+ resp.finaliseStream();
+ m_Socket->write(resp.getPtr(), resp.getLen());
}
bool cLiveStreamer::SeekTime(int64_t time, uint32_t &serial)
@@ -716,7 +709,5 @@ void cLiveStreamer::RetuneChannel(const cChannel *channel)
return;
INFOLOG("re-tune to channel %s", m_Channel->Name());
- cMutexLock lock(&m_Mutex);
- m_IsRetune = true;
- m_Event.Broadcast();
+ m_VideoInput.RequestRetune();
}
diff --git a/streamer.h b/streamer.h
index 078e144..9445c28 100644
--- a/streamer.h
+++ b/streamer.h
@@ -32,7 +32,6 @@
#include <vdr/device.h>
#include <vdr/receiver.h>
#include <vdr/thread.h>
-#include <list>
#include "parser.h"
#include "responsepacket.h"
@@ -48,10 +47,7 @@ class cVideoInput;
class cLiveStreamer : public cThread
{
-private:
friend class cParser;
- friend class cLivePatFilter;
- friend class cLiveReceiver;
void sendStreamPacket(sStreamPacket *pkt);
void sendStreamChange();
@@ -60,30 +56,28 @@ private:
void sendBufferStatus();
void sendRefTime(sStreamPacket *pkt);
- int m_ClientID;
- const cChannel *m_Channel; /*!> Channel to stream */
+ const int m_ClientID;
+ const cChannel *m_Channel = nullptr; /*!> Channel to stream */
cDevice *m_Device;
- cxSocket *m_Socket; /*!> The socket class to communicate with client */
- int m_Frontend; /*!> File descriptor to access used receiving device */
+ cxSocket *m_Socket = nullptr; /*!> The socket class to communicate with client */
+ int m_Frontend = -1; /*!> File descriptor to access used receiving device */
dvb_frontend_info m_FrontendInfo; /*!> DVB Information about the receiving device (DVB only) */
v4l2_capability m_vcap; /*!> PVR Information about the receiving device (pvrinput only) */
cString m_DeviceString; /*!> The name of the receiving device */
- bool m_startup;
- bool m_IsAudioOnly; /*!> Set to true if streams contains only audio */
- bool m_IsMPEGPS; /*!> TS Stream contains MPEG PS data like from pvrinput */
+ bool m_startup = true;
+ bool m_IsAudioOnly = false; /*!> Set to true if streams contains only audio */
+ bool m_IsMPEGPS = false; /*!> TS Stream contains MPEG PS data like from pvrinput */
uint32_t m_scanTimeout; /*!> Channel scanning timeout (in seconds) */
cTimeMs m_last_tick;
- bool m_SignalLost;
- bool m_IFrameSeen;
+ bool m_SignalLost = false;
+ bool m_IFrameSeen = false;
cResponsePacket m_streamHeader;
cVNSIDemuxer m_Demuxer;
- cVideoBuffer *m_VideoBuffer;
+ cVideoBuffer *m_VideoBuffer = nullptr;
cVideoInput m_VideoInput;
int m_Priority;
uint8_t m_Timeshift;
- cCondVar m_Event;
- cMutex m_Mutex;
- bool m_IsRetune;
+ cCondWait m_Event;
protected:
virtual void Action(void);
@@ -94,6 +88,9 @@ public:
cLiveStreamer(int clientID, bool bAllowRDS, uint8_t timeshift, uint32_t timeout = 0);
virtual ~cLiveStreamer();
+ cLiveStreamer(const cLiveStreamer &) = delete;
+ cLiveStreamer &operator=(const cLiveStreamer &) = delete;
+
void Activate(bool On);
bool StreamChannel(const cChannel *channel, int priority, cxSocket *Socket, cResponsePacket* resp);
diff --git a/videobuffer.c b/videobuffer.c
index 131c252..c85a06e 100644
--- a/videobuffer.c
+++ b/videobuffer.c
@@ -40,32 +40,25 @@ class cVideoBufferSimple : public cVideoBuffer
{
friend class cVideoBuffer;
public:
- virtual void Put(uint8_t *buf, unsigned int size);
+ virtual void Put(const uint8_t *buf, unsigned int size);
virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime);
protected:
cVideoBufferSimple();
- virtual ~cVideoBufferSimple();
- cRingBufferLinear *m_Buffer;
+ cRingBufferLinear m_Buffer;
int m_BytesConsumed;
};
cVideoBufferSimple::cVideoBufferSimple()
+ :m_Buffer(MEGABYTE(5), TS_SIZE * 2, false)
{
- m_Buffer = new cRingBufferLinear(MEGABYTE(3), TS_SIZE * 2, false);
- m_Buffer->SetTimeouts(0, 100);
+ m_Buffer.SetTimeouts(0, 100);
m_BytesConsumed = 0;
}
-cVideoBufferSimple::~cVideoBufferSimple()
+void cVideoBufferSimple::Put(const uint8_t *buf, unsigned int size)
{
- if (m_Buffer)
- delete m_Buffer;
-}
-
-void cVideoBufferSimple::Put(uint8_t *buf, unsigned int size)
-{
- m_Buffer->Put(buf, size);
+ m_Buffer.Put(buf, size);
}
int cVideoBufferSimple::ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime)
@@ -73,10 +66,10 @@ int cVideoBufferSimple::ReadBlock(uint8_t **buf, unsigned int size, time_t &endT
int readBytes;
if (m_BytesConsumed)
{
- m_Buffer->Del(m_BytesConsumed);
+ m_Buffer.Del(m_BytesConsumed);
}
m_BytesConsumed = 0;
- *buf = m_Buffer->Get(readBytes);
+ *buf = m_Buffer.Get(readBytes);
if (!(*buf) || readBytes < TS_SIZE)
{
usleep(100);
@@ -94,7 +87,7 @@ int cVideoBufferSimple::ReadBlock(uint8_t **buf, unsigned int size, time_t &endT
if ((*buf)[0] != TS_SYNC_BYTE)
{
- m_Buffer->Del(m_BytesConsumed);
+ m_Buffer.Del(m_BytesConsumed);
m_BytesConsumed = 0;
return 0;
}
@@ -198,7 +191,7 @@ class cVideoBufferRAM : public cVideoBufferTimeshift
{
friend class cVideoBuffer;
public:
- virtual void Put(uint8_t *buf, unsigned int size);
+ virtual void Put(const uint8_t *buf, unsigned int size);
virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime);
virtual void SetPos(off_t pos);
@@ -217,8 +210,7 @@ cVideoBufferRAM::cVideoBufferRAM()
cVideoBufferRAM::~cVideoBufferRAM()
{
- if (m_Buffer)
- free(m_Buffer);
+ free(m_Buffer);
}
bool cVideoBufferRAM::Init()
@@ -243,7 +235,7 @@ void cVideoBufferRAM::SetPos(off_t pos)
m_BytesConsumed = 0;
}
-void cVideoBufferRAM::Put(uint8_t *buf, unsigned int size)
+void cVideoBufferRAM::Put(const uint8_t *buf, unsigned int size)
{
if (Available() + MARGIN >= m_BufferSize)
{
@@ -303,7 +295,7 @@ int cVideoBufferRAM::ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime
if (m_ReadPtr > (m_BufferSize - m_Margin))
{
int bytesToCopy = m_BufferSize - m_ReadPtr;
- memmove(m_Buffer + (m_Margin - bytesToCopy), m_Buffer + m_ReadPtr, bytesToCopy);
+ memmove(m_Buffer + (m_Margin - bytesToCopy), m_BufferPtr + m_ReadPtr, bytesToCopy);
*buf = m_Buffer + (m_Margin - bytesToCopy);
}
else
@@ -335,7 +327,7 @@ class cVideoBufferFile : public cVideoBufferTimeshift
friend class cVideoBuffer;
public:
virtual off_t GetPosMax();
- virtual void Put(uint8_t *buf, unsigned int size);
+ virtual void Put(const uint8_t *buf, unsigned int size);
virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime);
virtual void SetPos(off_t pos);
@@ -393,10 +385,7 @@ bool cVideoBufferFile::Init()
struct stat sb;
if ((*TimeshiftBufferDir) && stat(TimeshiftBufferDir, &sb) == 0 && S_ISDIR(sb.st_mode))
{
- if (TimeshiftBufferDir[strlen(TimeshiftBufferDir)-1] == '/')
- m_Filename = cString::sprintf("%sTimeshift-%d.vnsi", TimeshiftBufferDir, m_ClientID);
- else
- m_Filename = cString::sprintf("%s/Timeshift-%d.vnsi", TimeshiftBufferDir, m_ClientID);
+ m_Filename = cString::sprintf("%s/Timeshift-%d.vnsi", TimeshiftBufferDir, m_ClientID);
}
else
#if VDRVERSNUM >= 20102
@@ -451,7 +440,7 @@ off_t cVideoBufferFile::GetPosMax()
return posMax;
}
-void cVideoBufferFile::Put(uint8_t *buf, unsigned int size)
+void cVideoBufferFile::Put(const uint8_t *buf, unsigned int size)
{
if (Available() + MARGIN >= m_BufferSize)
{
@@ -626,22 +615,22 @@ class cVideoBufferRecording : public cVideoBufferFile
friend class cVideoBuffer;
public:
virtual off_t GetPosMax();
- virtual void Put(uint8_t *buf, unsigned int size);
+ virtual void Put(const uint8_t *buf, unsigned int size);
virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime);
virtual time_t GetRefTime();
protected:
- cVideoBufferRecording(cRecording *rec);
+ cVideoBufferRecording(const cRecording *rec);
virtual ~cVideoBufferRecording();
virtual bool Init();
virtual off_t Available();
off_t GetPosEnd();
cRecPlayer *m_RecPlayer;
- cRecording *m_Recording;
+ const cRecording *m_Recording;
cTimeMs m_ScanTimer;
};
-cVideoBufferRecording::cVideoBufferRecording(cRecording *rec)
+cVideoBufferRecording::cVideoBufferRecording(const cRecording *rec)
{
m_Recording = rec;
m_ReadCacheSize = 0;
@@ -662,7 +651,7 @@ off_t cVideoBufferRecording::GetPosMax()
return cVideoBufferFile::GetPosMax();
}
-void cVideoBufferRecording::Put(uint8_t *buf, unsigned int size)
+void cVideoBufferRecording::Put(const uint8_t *buf, unsigned int size)
{
}
@@ -778,7 +767,7 @@ class cVideoBufferTest : public cVideoBufferFile
friend class cVideoBuffer;
public:
virtual off_t GetPosMax();
- virtual void Put(uint8_t *buf, unsigned int size);
+ virtual void Put(const uint8_t *buf, unsigned int size);
protected:
cVideoBufferTest(cString filename);
@@ -818,7 +807,7 @@ off_t cVideoBufferTest::GetPosEnd()
return end;
}
-void cVideoBufferTest::Put(uint8_t *buf, unsigned int size)
+void cVideoBufferTest::Put(const uint8_t *buf, unsigned int size)
{
}
@@ -915,7 +904,7 @@ cVideoBuffer* cVideoBuffer::Create(cString filename)
return buffer;
}
-cVideoBuffer* cVideoBuffer::Create(cRecording *rec)
+cVideoBuffer* cVideoBuffer::Create(const cRecording *rec)
{
INFOLOG("Open recording: %s", rec->FileName());
cVideoBufferRecording *buffer = new cVideoBufferRecording(rec);
diff --git a/videobuffer.h b/videobuffer.h
index 2df8f57..493d377 100644
--- a/videobuffer.h
+++ b/videobuffer.h
@@ -36,8 +36,8 @@ public:
virtual ~cVideoBuffer();
static cVideoBuffer* Create(int clientID, uint8_t timeshift);
static cVideoBuffer* Create(cString filename);
- static cVideoBuffer* Create(cRecording *rec);
- virtual void Put(uint8_t *buf, unsigned int size) = 0;
+ static cVideoBuffer* Create(const cRecording *rec);
+ virtual void Put(const uint8_t *buf, unsigned int size) = 0;
virtual int ReadBlock(uint8_t **buf, unsigned int size, time_t &endTime, time_t &wrapTime) = 0;
virtual off_t GetPosMin() { return 0; };
virtual off_t GetPosMax() { return 0; };
diff --git a/videoinput.c b/videoinput.c
index 98378b1..2947f14 100644
--- a/videoinput.c
+++ b/videoinput.c
@@ -29,13 +29,15 @@
#include "vnsi.h"
#include <vdr/remux.h>
-#include <vdr/channels.h>
#include <vdr/device.h>
#include <vdr/receiver.h>
#include <vdr/ci.h>
#include <vdr/config.h>
#include <libsi/section.h>
#include <libsi/descriptor.h>
+#include <memory>
+#include <vector>
+#include <algorithm>
// --- cLiveReceiver -------------------------------------------------
@@ -44,11 +46,14 @@ class cLiveReceiver: public cReceiver
public:
cLiveReceiver(cVideoInput *VideoInput, const cChannel *Channel, int Priority);
virtual ~cLiveReceiver();
- cChannel m_PmtChannel;
protected:
virtual void Activate(bool On);
+#if VDRVERSNUM >= 20301
+ virtual void Receive(const uchar *Data, int Length);
+#else
virtual void Receive(uchar *Data, int Length);
+#endif
cVideoInput *m_VideoInput;
};
@@ -66,18 +71,20 @@ cLiveReceiver::~cLiveReceiver()
}
//void cLiveReceiver
+#if VDRVERSNUM >= 20301
+void cLiveReceiver::Receive(const uchar *Data, int Length)
+#else
void cLiveReceiver::Receive(uchar *Data, int Length)
+#endif
{
m_VideoInput->Receive(Data, Length);
}
-inline void cLiveReceiver::Activate(bool On)
+void cLiveReceiver::Activate(bool On)
{
- DEBUGLOG("activate live receiver: %d", On);
+ INFOLOG("activate live receiver: %d, pmt change: %d", On, static_cast<bool>(m_VideoInput->m_PmtChange));
if (!On && !m_VideoInput->m_PmtChange)
- {
- m_VideoInput->Retune();
- }
+ m_VideoInput->RequestRetune();
}
// --- cLivePatFilter ----------------------------------------------------
@@ -110,6 +117,7 @@ cLivePatFilter::cLivePatFilter(cVideoInput *VideoInput, const cChannel *Channel)
void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
+#if VDRVERSNUM < 20104
if (Pid == 0x00)
{
if (Tid == 0x00)
@@ -122,7 +130,12 @@ void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Le
{
if (!assoc.isNITPid())
{
+#if VDRVERSNUM >= 20301
+ LOCK_CHANNELS_READ;
+ const cChannel *Channel = Channels->GetByServiceID(Source(), Transponder(), assoc.getServiceId());
+#else
const cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
+#endif
if (Channel && (Channel == m_Channel))
{
int prevPmtPid = m_pmtPid;
@@ -160,7 +173,12 @@ void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Le
}
m_pmtVersion = pmt.getVersionNumber();
+#if VDRVERSNUM >= 20301
+ LOCK_CHANNELS_READ;
+ const cChannel *Channel = Channels->GetByServiceID(Source(), Transponder(), pmt.getServiceId());
+#else
cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), pmt.getServiceId());
+#endif
if (Channel) {
// Scan the stream-specific loop:
SI::PMT::Stream stream;
@@ -389,23 +407,90 @@ void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Le
pmtChannel->Modification();
pmtChannel->SetPids(Vpid, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid);
pmtChannel->SetSubtitlingDescriptors(SubtitlingTypes, CompositionPageIds, AncillaryPageIds);
- m_VideoInput->PmtChange(pmtChannel->Modification(CHANNELMOD_PIDS));
+ if (pmtChannel->Modification(CHANNELMOD_PIDS))
+ m_VideoInput->RequestRetune();
}
}
+#endif
+}
+
+// --- cDummyReceiver ----------------------------------------------------
+
+// This dummy receiver is used to detect if a recording/streaming task
+// with a higher priority has acquired the device and detached *all*
+// receivers from it.
+class cDummyReceiver : public cReceiver
+{
+public:
+ // Return a new or existing dummy receiver attached to the device.
+ static std::shared_ptr<cDummyReceiver> Create(cDevice *device);
+ virtual ~cDummyReceiver() {Detach();}
+ bool BeenDetached() {return m_BeenDetached;}
+protected:
+#if VDRVERSNUM >= 20301
+ virtual void Receive(const uchar *Data, int Length) {}
+#else
+ virtual void Receive(uchar *Data, int Length) {}
+#endif
+ virtual void Activate(bool On);
+private:
+ static std::vector<std::weak_ptr<cDummyReceiver>> s_Pool;
+ static cMutex s_PoolMutex;
+ std::atomic<bool> m_BeenDetached;
+ cDummyReceiver() : cReceiver(NULL, MINPRIORITY), m_BeenDetached(false) {}
+};
+
+std::vector<std::weak_ptr<cDummyReceiver>> cDummyReceiver::s_Pool;
+cMutex cDummyReceiver::s_PoolMutex;
+
+void cDummyReceiver::Activate(bool On)
+{
+ INFOLOG("Dummy receiver (%p) %s", this, (On)? "activated" : "deactivated");
+ if (!On)
+ m_BeenDetached = true;
+}
+
+std::shared_ptr<cDummyReceiver> cDummyReceiver::Create(cDevice *device)
+{
+ if (!device)
+ return nullptr;
+
+ cMutexLock MutexLock(&s_PoolMutex);
+ // cleanup
+ s_Pool.erase(std::remove_if(s_Pool.begin(), s_Pool.end(),
+ [](const std::weak_ptr<cDummyReceiver> &p) -> bool
+ {return !p.lock();}), s_Pool.end());
+
+ // find an active receiver for the device
+ for (auto p : s_Pool)
+ {
+ auto recv = p.lock();
+ if (!recv->BeenDetached() && recv->Device() == device)
+ return recv;
+ }
+ auto recv = std::shared_ptr<cDummyReceiver>(new cDummyReceiver);
+ if (device->AttachReceiver(recv.get()))
+ {
+ s_Pool.push_back(recv);
+ return recv;
+ }
+ return nullptr;
}
// ----------------------------------------------------------------------------
-cVideoInput::cVideoInput(cCondVar &condVar, cMutex &mutex, bool &retune) :
- m_Event(condVar), m_Mutex(mutex), m_IsRetune(retune)
+cVideoInput::cVideoInput(cCondWait &event)
+ : m_PmtChange(false)
+ , m_Event(event)
+ , m_RetuneRequested(false)
{
- m_Device = NULL;;
+ m_Device = NULL;
+ m_camSlot = nullptr;
m_PatFilter = NULL;
m_Receiver = NULL;;
m_Channel = NULL;
m_VideoBuffer = NULL;
m_Priority = 0;
- m_PmtChange = false;
}
cVideoInput::~cVideoInput()
@@ -418,27 +503,58 @@ bool cVideoInput::Open(const cChannel *channel, int priority, cVideoBuffer *vide
m_VideoBuffer = videoBuffer;
m_Channel = channel;
m_Priority = priority;
+ m_RetuneRequested = false;
+ m_PmtChange = false;
m_Device = cDevice::GetDevice(m_Channel, m_Priority, false);
+ m_camSlot = nullptr;
if (m_Device != NULL)
{
- INFOLOG("Successfully found following device: %p (%d) for receiving", m_Device, m_Device ? m_Device->CardIndex() + 1 : 0);
+ INFOLOG("Successfully found following device: %p (%d) for receiving, priority=%d", m_Device, m_Device ? m_Device->CardIndex() + 1 : 0, m_Priority);
if (m_Device->SwitchChannel(m_Channel, false))
{
- DEBUGLOG("Creating new live Receiver");
- //m_Device->SetCurrentChannel(m_Channel);
- m_SeenPmt = false;
+
+ m_Device->SetCurrentChannel(m_Channel);
+
+#if VDRVERSNUM < 20104
m_PatFilter = new cLivePatFilter(this, m_Channel);
- m_Receiver0 = new cLiveReceiver(this, m_Channel, m_Priority);
- m_Receiver = new cLiveReceiver(this, m_Channel, m_Priority);
- m_Device->AttachReceiver(m_Receiver0);
m_Device->AttachFilter(m_PatFilter);
- cCamSlot *cs = m_Device->CamSlot();
- if (m_Priority <= MINPRIORITY && cs)
- cs->StartDecrypting();
+#endif
+
+ m_PmtChannel = *m_Channel;
+ m_PmtChange = true;
+
+ m_Receiver = new cLiveReceiver(this, m_Channel, m_Priority);
+ m_Receiver->SetPids(NULL);
+ m_Receiver->SetPids(&m_PmtChannel);
+ m_Receiver->AddPid(m_PmtChannel.Tpid());
+
+ m_DummyReceiver = cDummyReceiver::Create(m_Device);
+ if (!m_DummyReceiver)
+ return false;
+
+ m_camSlot = m_Device->CamSlot();
+
+#if VDRVERSNUM >= 20107
+ if (DisableScrambleTimeout && m_camSlot)
+ {
+ // HACK cDevice::AttachReceiver() doesn't start scrambling
+ // timer if priority == MINPRIORITY
+ m_Receiver->SetPriority(MINPRIORITY);
+ if (!m_Device->AttachReceiver(m_Receiver))
+ return false;
+ if (m_camSlot)
+ m_camSlot->StartDecrypting();
+ m_Receiver->SetPriority(m_Priority);
+ }
+ else
+#endif
+ {
+ if (!m_Device->AttachReceiver(m_Receiver))
+ return false;
+ }
m_VideoBuffer->AttachInput(true);
- Start();
return true;
}
}
@@ -448,24 +564,25 @@ bool cVideoInput::Open(const cChannel *channel, int priority, cVideoBuffer *vide
void cVideoInput::Close()
{
INFOLOG("close video input ...");
- Cancel(5);
if (m_Device)
{
- if (m_Receiver)
+ if (DisableCamBlacklist)
{
- DEBUGLOG("Detaching Live Receiver");
- m_Device->Detach(m_Receiver);
- }
- else
- {
- DEBUGLOG("No live receiver present");
+ // HACK Undo ChannelCamRelations.SetChecked() - see cDevice::Action().
+ // Note: m_Device->CamSlot() returns NULL after SetChecked() is called.
+ // Use m_camSlot here.
+ if (m_Receiver && m_camSlot)
+ {
+ ChannelCamRelations.ClrChecked(m_Receiver->ChannelID(),
+ m_camSlot->SlotNumber());
+ }
}
- if (m_Receiver0)
+ if (m_Receiver)
{
- DEBUGLOG("Detaching Live Receiver0");
- m_Device->Detach(m_Receiver0);
+ DEBUGLOG("Detaching Live Receiver");
+ m_Device->Detach(m_Receiver);
}
else
{
@@ -482,32 +599,19 @@ void cVideoInput::Close()
DEBUGLOG("No live filter present");
}
+ m_DummyReceiver.reset();
+
if (m_Receiver)
{
DEBUGLOG("Deleting Live Receiver");
DELETENULL(m_Receiver);
}
- if (m_Receiver0)
- {
- DEBUGLOG("Deleting Live Receiver0");
- DELETENULL(m_Receiver0);
- }
-
if (m_PatFilter)
{
DEBUGLOG("Deleting Live Filter");
DELETENULL(m_PatFilter);
}
-
- //m_Device->SetCurrentChannel(NULL);
- cCamSlot *cs = m_Device->CamSlot();
- if (m_Priority <= MINPRIORITY && cs)
- {
- cs->StartDecrypting();
- if (!cs->IsDecrypting())
- cs->Assign(NULL);
- }
}
m_Channel = NULL;
m_Device = NULL;
@@ -528,33 +632,15 @@ bool cVideoInput::IsOpen()
cChannel *cVideoInput::PmtChannel()
{
- return &m_Receiver->m_PmtChannel;
+ return &m_PmtChannel;
}
-void cVideoInput::PmtChange(int pidChange)
-{
- if (pidChange)
- {
- INFOLOG("Video Input - new pmt, attaching receiver");
- m_PmtChange = true;
- m_Device->Detach(m_Receiver);
- m_Receiver->SetPids(NULL);
- m_Receiver->SetPids(&m_Receiver->m_PmtChannel);
- m_Receiver->AddPid(m_Receiver->m_PmtChannel.Tpid());
- m_Device->AttachReceiver(m_Receiver);
- cCamSlot *cs = m_Device->CamSlot();
- if (m_Priority <= MINPRIORITY && cs)
- cs->StartDecrypting();
- m_SeenPmt = true;
- }
-}
-
-inline void cVideoInput::Receive(uchar *data, int length)
+inline void cVideoInput::Receive(const uchar *data, int length)
{
if (m_PmtChange)
{
// generate pat/pmt so we can configure parsers later
- cPatPmtGenerator patPmtGenerator(&m_Receiver->m_PmtChannel);
+ cPatPmtGenerator patPmtGenerator(&m_PmtChannel);
m_VideoBuffer->Put(patPmtGenerator.GetPat(), TS_SIZE);
int Index = 0;
while (uchar *pmt = patPmtGenerator.GetPmt(Index))
@@ -564,29 +650,23 @@ inline void cVideoInput::Receive(uchar *data, int length)
m_VideoBuffer->Put(data, length);
}
-void cVideoInput::Retune()
+void cVideoInput::RequestRetune()
{
- INFOLOG("call retune ...");
- cMutexLock lock(&m_Mutex);
- m_IsRetune = true;
- m_Event.Broadcast();
+ m_RetuneRequested = true;
+ m_Event.Signal();
}
-void cVideoInput::Action()
+cVideoInput::eReceivingStatus cVideoInput::ReceivingStatus()
{
- cTimeMs starttime;
-
- while (Running())
+ if (!m_Device || !m_DummyReceiver)
+ return RETUNE;
+ if (m_RetuneRequested)
{
- if (starttime.Elapsed() > (unsigned int)PmtTimeout*1000)
- {
- INFOLOG("VideoInput: no pat/pmt within timeout, falling back to channel pids");
- m_Receiver->m_PmtChannel = *m_Channel;
- PmtChange(true);
- }
- if (m_SeenPmt)
- break;
-
- usleep(1000);
+ (void)m_Device->Receiving(); // wait for the receivers mutex
+ if (m_DummyReceiver->BeenDetached()) // DetachAllReceivers() was called
+ return CLOSE;
+ else
+ return RETUNE;
}
+ return NORMAL;
}
diff --git a/videoinput.h b/videoinput.h
index d1ebb51..3ad8749 100644
--- a/videoinput.h
+++ b/videoinput.h
@@ -24,41 +24,44 @@
#pragma once
+#include <memory>
+#include <atomic>
+#include <vdr/channels.h>
#include <vdr/thread.h>
class cLivePatFilter;
class cLiveReceiver;
class cVideoBuffer;
-class cChannel;
class cDevice;
+class cDummyReceiver;
+class cCamSlot;
-class cVideoInput : public cThread
+class cVideoInput
{
friend class cLivePatFilter;
friend class cLiveReceiver;
public:
- cVideoInput(cCondVar &condVar, cMutex &mutex, bool &retune);
+ cVideoInput(cCondWait &event);
virtual ~cVideoInput();
bool Open(const cChannel *channel, int priority, cVideoBuffer *videoBuffer);
void Close();
bool IsOpen();
-
+ void RequestRetune();
+ enum eReceivingStatus {NORMAL, RETUNE, CLOSE};
+ eReceivingStatus ReceivingStatus();
protected:
- virtual void Action(void);
- void PmtChange(int pidChange);
cChannel *PmtChannel();
- void Receive(uchar *data, int length);
- void Retune();
+ void Receive(const uchar *data, int length);
cDevice *m_Device;
+ cCamSlot *m_camSlot;
cLivePatFilter *m_PatFilter;
cLiveReceiver *m_Receiver;
- cLiveReceiver *m_Receiver0;
const cChannel *m_Channel;
cVideoBuffer *m_VideoBuffer;
int m_Priority;
- bool m_PmtChange;
- bool m_SeenPmt;
- cCondVar &m_Event;
- cMutex &m_Mutex;
- bool &m_IsRetune;
+ std::atomic<bool> m_PmtChange;
+ cChannel m_PmtChannel;
+ cCondWait &m_Event;
+ std::shared_ptr<cDummyReceiver> m_DummyReceiver;
+ std::atomic<bool> m_RetuneRequested;
};
diff --git a/vnsi.c b/vnsi.c
index 5078eb6..e3541ee 100644
--- a/vnsi.c
+++ b/vnsi.c
@@ -23,25 +23,19 @@
*
*/
-#include <getopt.h>
-#include <vdr/plugin.h>
#include "vnsi.h"
#include "vnsicommand.h"
#include "setup.h"
+#include <getopt.h>
+#include <vdr/plugin.h>
+
cPluginVNSIServer* cPluginVNSIServer::VNSIServer = NULL;
cPluginVNSIServer::cPluginVNSIServer(void)
{
Server = NULL;
VNSIServer = NULL;
- probe = new cDvbVsniDeviceProbe();
-}
-
-cPluginVNSIServer::~cPluginVNSIServer()
-{
- // Clean up after yourself!
- delete probe;
}
const char *cPluginVNSIServer::CommandLineHelp(void)
@@ -155,11 +149,19 @@ bool cPluginVNSIServer::SetupParse(const char *Name, const char *Value)
else if (!strcasecmp(Name, CONFNAME_TIMESHIFTBUFFERFILESIZE))
TimeshiftBufferFileSize = atoi(Value);
else if (!strcasecmp(Name, CONFNAME_TIMESHIFTBUFFERDIR))
+ {
strn0cpy(TimeshiftBufferDir, Value, sizeof(TimeshiftBufferDir));
- else if (!strcasecmp(Name, CONFNAME_PLAYRECORDING))
+ if (*TimeshiftBufferDir && TimeshiftBufferDir[strlen(TimeshiftBufferDir)-1] == '/')
+ /* strip trailing slash */
+ TimeshiftBufferDir[strlen(TimeshiftBufferDir)-1] = 0;
+ } else if (!strcasecmp(Name, CONFNAME_PLAYRECORDING))
PlayRecording = atoi(Value);
else if (!strcasecmp(Name, CONFNAME_AVOIDEPGSCAN))
AvoidEPGScan = atoi(Value);
+ else if (!strcasecmp(Name, CONFNAME_DISABLESCRAMBLETIMEOUT))
+ DisableScrambleTimeout = atoi(Value);
+ else if (!strcasecmp(Name, CONFNAME_DISABLECAMBLACKLIST))
+ DisableCamBlacklist = atoi(Value);
else
return false;
return true;
diff --git a/vnsi.h b/vnsi.h
index 957700e..ade3376 100644
--- a/vnsi.h
+++ b/vnsi.h
@@ -28,7 +28,7 @@
#include <vdr/thread.h>
#include "vnsiserver.h"
-static const char *VERSION = "1.3.1";
+static const char *VERSION = "1.5.1";
static const char *DESCRIPTION = "VDR-Network-Streaming-Interface (VNSI) Server";
extern int PmtTimeout;
@@ -38,18 +38,23 @@ extern int TimeshiftBufferFileSize;
extern char TimeshiftBufferDir[PATH_MAX];
extern int PlayRecording;
extern int AvoidEPGScan;
+extern int DisableScrambleTimeout;
+extern int DisableCamBlacklist;
-class cDvbVsniDeviceProbe;
+class cDvbVsniDeviceProbe : public cDvbDeviceProbe
+{
+public:
+ virtual bool Probe(int Adapter, int Frontend);
+};
class cPluginVNSIServer : public cPlugin {
private:
cVNSIServer *Server;
static cPluginVNSIServer *VNSIServer;
- cDvbVsniDeviceProbe *probe;
+ cDvbVsniDeviceProbe probe;
public:
cPluginVNSIServer(void);
- virtual ~cPluginVNSIServer();
virtual const char *Version(void) { return VERSION; }
virtual const char *Description(void) { return DESCRIPTION; }
virtual const char *CommandLineHelp(void);
@@ -72,12 +77,6 @@ public:
static void StoreSetup(const char *Name, int Value);
};
-class cDvbVsniDeviceProbe : public cDvbDeviceProbe
-{
-public:
- virtual bool Probe(int Adapter, int Frontend);
-};
-
class cDvbVnsiDevice : public cDvbDevice
{
public:
diff --git a/vnsiclient.c b/vnsiclient.c
index 56d3e9a..bee2bb2 100644
--- a/vnsiclient.c
+++ b/vnsiclient.c
@@ -23,23 +23,11 @@
*
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <map>
-
-#include <vdr/recording.h>
-#include <vdr/channels.h>
-#include <vdr/videodir.h>
-#include <vdr/plugin.h>
-#include <vdr/timers.h>
-#include <vdr/menu.h>
-#include <vdr/device.h>
-
+#include "vnsiclient.h"
#include "vnsi.h"
#include "config.h"
#include "vnsicommand.h"
#include "recordingscache.h"
-#include "vnsiclient.h"
#include "streamer.h"
#include "vnsiserver.h"
#include "recplayer.h"
@@ -50,24 +38,30 @@
#include "channelfilter.h"
#include "channelscancontrol.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <map>
+#include <memory>
+
+#include <vdr/recording.h>
+#include <vdr/channels.h>
+#include <vdr/videodir.h>
+#include <vdr/plugin.h>
+#include <vdr/timers.h>
+#include <vdr/menu.h>
+#include <vdr/device.h>
+
cMutex cVNSIClient::m_timerLock;
bool cVNSIClient::m_inhibidDataUpdates = false;
-cVNSIClient::cVNSIClient(int fd, unsigned int id, const char *ClientAdr)
+cVNSIClient::cVNSIClient(int fd, unsigned int id, const char *ClientAdr, CVNSITimers &timers)
: m_Id(id),
- m_loggedIn(false),
- m_StatusInterfaceEnabled(false),
- m_Streamer(NULL),
- m_isStreaming(false),
- m_bSupportRDS(false),
+ m_socket(fd),
m_ClientAddress(ClientAdr),
- m_RecPlayer(NULL),
- m_req(NULL),
- m_resp(NULL),
- m_Osd(NULL),
- m_ChannelScanControl(this)
+ m_ChannelScanControl(this),
+ m_vnsiTimers(timers)
{
- m_socket.SetHandle(fd);
+ SetDescription("VNSI Client %u->%s", id, ClientAdr);
Start();
}
@@ -77,7 +71,7 @@ cVNSIClient::~cVNSIClient()
DEBUGLOG("%s", __FUNCTION__);
StopChannelStreaming();
m_ChannelScanControl.StopScan();
- m_socket.close(); // force closing connection
+ m_socket.Shutdown();
Cancel(10);
DEBUGLOG("done");
}
@@ -113,9 +107,9 @@ void cVNSIClient::Action(void)
if (dataLength)
{
- data = (uint8_t*)malloc(dataLength);
- if (!data)
- {
+ try {
+ data = new uint8_t[dataLength];
+ } catch (const std::bad_alloc &) {
ERRORLOG("Extra data buffer malloc error");
break;
}
@@ -141,9 +135,13 @@ void cVNSIClient::Action(void)
break;
}
- cRequestPacket* req = new cRequestPacket(requestID, opcode, data, dataLength);
-
- processRequest(req);
+ try {
+ cRequestPacket req(requestID, opcode, data, dataLength);
+ processRequest(req);
+ } catch (const std::exception &e) {
+ ERRORLOG("%s", e.what());
+ break;
+ }
}
else
{
@@ -158,51 +156,35 @@ void cVNSIClient::Action(void)
m_ChannelScanControl.StopScan();
// Shutdown OSD
- if (m_Osd)
- {
- delete m_Osd;
- m_Osd = NULL;
- }
+ delete m_Osd;
+ m_Osd = NULL;
}
-bool cVNSIClient::StartChannelStreaming(const cChannel *channel, int32_t priority, uint8_t timeshift, uint32_t timeout)
+bool cVNSIClient::StartChannelStreaming(cResponsePacket &resp, const cChannel *channel, int32_t priority, uint8_t timeshift, uint32_t timeout)
{
+ delete m_Streamer;
m_Streamer = new cLiveStreamer(m_Id, m_bSupportRDS, timeshift, timeout);
- m_isStreaming = m_Streamer->StreamChannel(channel, priority, &m_socket, m_resp);
+ m_isStreaming = m_Streamer->StreamChannel(channel, priority, &m_socket, &resp);
return m_isStreaming;
}
void cVNSIClient::StopChannelStreaming()
{
m_isStreaming = false;
- if (m_Streamer)
- {
- delete m_Streamer;
- m_Streamer = NULL;
- }
+ delete m_Streamer;
+ m_Streamer = NULL;
}
-void cVNSIClient::TimerChange(const cTimer *Timer, eTimerChange Change)
-{
- TimerChange();
-}
-
-void cVNSIClient::TimerChange()
+void cVNSIClient::SignalTimerChange()
{
cMutexLock lock(&m_msgLock);
if (m_StatusInterfaceEnabled)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStatus(VNSI_STATUS_TIMERCHANGE))
- {
- delete resp;
- return;
- }
-
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initStatus(VNSI_STATUS_TIMERCHANGE);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
}
@@ -213,16 +195,10 @@ void cVNSIClient::ChannelsChange()
if (!m_StatusInterfaceEnabled)
return;
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStatus(VNSI_STATUS_CHANNELCHANGE))
- {
- delete resp;
- return;
- }
-
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initStatus(VNSI_STATUS_CHANNELCHANGE);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
void cVNSIClient::RecordingsChange()
@@ -232,40 +208,49 @@ void cVNSIClient::RecordingsChange()
if (!m_StatusInterfaceEnabled)
return;
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStatus(VNSI_STATUS_RECORDINGSCHANGE))
- {
- delete resp;
- return;
- }
-
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initStatus(VNSI_STATUS_RECORDINGSCHANGE);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
-void cVNSIClient::EpgChange()
+bool cVNSIClient::EpgChange()
{
+ bool callAgain = false;
+
cMutexLock lock(&m_msgLock);
if (!m_StatusInterfaceEnabled)
- return;
+ return callAgain;
+#if VDRVERSNUM >= 20301
+ cStateKey SchedulesStateKey(true);
+ const cSchedules *schedules = cSchedules::GetSchedulesRead(SchedulesStateKey);
+ if (!schedules)
+ {
+ return callAgain;
+ }
+#else
cSchedulesLock MutexLock;
const cSchedules *schedules = cSchedules::Schedules(MutexLock);
if (!schedules)
- return;
+ return callAgain;
+#endif
- std::map<int, sEpgUpdate>::iterator it;
for (const cSchedule *schedule = schedules->First(); schedule; schedule = schedules->Next(schedule))
{
- cEvent *lastEvent = schedule->Events()->Last();
+ const cEvent *lastEvent = schedule->Events()->Last();
if (!lastEvent)
continue;
+#if VDRVERSNUM >= 20301
+ LOCK_CHANNELS_READ;
+ const cChannel *channel = Channels->GetByChannelID(schedule->ChannelID());
+#else
Channels.Lock(false);
const cChannel *channel = Channels.GetByChannelID(schedule->ChannelID());
Channels.Unlock();
+#endif
if (!channel)
continue;
@@ -274,31 +259,40 @@ void cVNSIClient::EpgChange()
continue;
uint32_t channelId = CreateStringHash(schedule->ChannelID().ToString());
- it = m_epgUpdate.find(channelId);
- if (it != m_epgUpdate.end() && it->second.lastEvent >= lastEvent->StartTime())
+ auto it = m_epgUpdate.find(channelId);
+ if (it == m_epgUpdate.end() || it->second.attempts > 3 ||
+ it->second.lastEvent >= lastEvent->StartTime())
{
continue;
}
- if (it->second.attempts > 3)
+ time_t now = time(nullptr);
+ if ((now - it->second.lastTrigger) < 5)
{
+ callAgain = true;
continue;
}
+
it->second.attempts++;
+ it->second.lastTrigger = now;
- INFOLOG("Trigger EPG update for channel %s, id: %d", channel->Name(), channelId);
+ DEBUGLOG("Trigger EPG update for channel %s, id: %d", channel->Name(), channelId);
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStatus(VNSI_STATUS_EPGCHANGE))
- {
- delete resp;
- return;
- }
- resp->add_U32(channelId);
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initStatus(VNSI_STATUS_EPGCHANGE);
+ resp.add_U32(channelId);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+
+ callAgain = true;
+ break;
}
+
+#if VDRVERSNUM >= 20301
+ SchedulesStateKey.Remove();
+#endif
+
+ return callAgain;
}
void cVNSIClient::Recording(const cDevice *Device, const char *Name, const char *FileName, bool On)
@@ -307,28 +301,22 @@ void cVNSIClient::Recording(const cDevice *Device, const char *Name, const char
if (m_StatusInterfaceEnabled)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStatus(VNSI_STATUS_RECORDING))
- {
- delete resp;
- return;
- }
-
- resp->add_U32(Device->CardIndex());
- resp->add_U32(On);
+ cResponsePacket resp;
+ resp.initStatus(VNSI_STATUS_RECORDING);
+ resp.add_U32(Device->CardIndex());
+ resp.add_U32(On);
if (Name)
- resp->add_String(Name);
+ resp.add_String(Name);
else
- resp->add_String("");
+ resp.add_String("");
if (FileName)
- resp->add_String(FileName);
+ resp.add_String(FileName);
else
- resp->add_String("");
+ resp.add_String("");
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
}
@@ -354,27 +342,24 @@ void cVNSIClient::OsdStatusMessage(const char *Message)
else if (strcasecmp(Message, trVDR("Delete marks information?")) == 0) return;
else if (strcasecmp(Message, trVDR("Delete resume information?")) == 0) return;
else if (strcasecmp(Message, trVDR("CAM is in use - really reset?")) == 0) return;
+ else if (strcasecmp(Message, trVDR("CAM activated!")) == 0) return;
else if (strcasecmp(Message, trVDR("Really restart?")) == 0) return;
else if (strcasecmp(Message, trVDR("Stop recording?")) == 0) return;
else if (strcasecmp(Message, trVDR("Cancel editing?")) == 0) return;
else if (strcasecmp(Message, trVDR("Cutter already running - Add to cutting queue?")) == 0) return;
else if (strcasecmp(Message, trVDR("No index-file found. Creating may take minutes. Create one?")) == 0) return;
+ else if (strncmp(Message, trVDR("VDR will shut down in"), 21) == 0) return;
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initStatus(VNSI_STATUS_MESSAGE))
- {
- delete resp;
- return;
- }
-
- resp->add_U32(0);
- resp->add_String(Message);
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initStatus(VNSI_STATUS_MESSAGE);
+ resp.add_U32(0);
+ resp.add_String(Message);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
}
+#if VDRVERSNUM >= 20104
void cVNSIClient::ChannelChange(const cChannel *Channel)
{
cMutexLock lock(&m_msgLock);
@@ -383,221 +368,213 @@ void cVNSIClient::ChannelChange(const cChannel *Channel)
m_Streamer->RetuneChannel(Channel);
}
}
+#endif
-bool cVNSIClient::processRequest(cRequestPacket* req)
+bool cVNSIClient::processRequest(cRequestPacket &req)
{
cMutexLock lock(&m_msgLock);
- m_req = req;
- m_resp = new cResponsePacket();
- if (!m_resp->init(m_req->getRequestID()))
- {
- ERRORLOG("Response packet init fail");
- delete m_resp;
- delete m_req;
- m_resp = NULL;
- m_req = NULL;
- return false;
- }
-
bool result = false;
- switch(m_req->getOpCode())
+ switch(req.getOpCode())
{
/** OPCODE 1 - 19: VNSI network functions for general purpose */
case VNSI_LOGIN:
- result = process_Login();
+ result = process_Login(req);
break;
case VNSI_GETTIME:
- result = process_GetTime();
+ result = process_GetTime(req);
break;
case VNSI_ENABLESTATUSINTERFACE:
- result = process_EnableStatusInterface();
+ result = process_EnableStatusInterface(req);
break;
case VNSI_PING:
- result = process_Ping();
+ result = process_Ping(req);
break;
case VNSI_GETSETUP:
- result = process_GetSetup();
+ result = process_GetSetup(req);
break;
case VNSI_STORESETUP:
- result = process_StoreSetup();
+ result = process_StoreSetup(req);
break;
/** OPCODE 20 - 39: VNSI network functions for live streaming */
case VNSI_CHANNELSTREAM_OPEN:
- result = processChannelStream_Open();
+ result = processChannelStream_Open(req);
break;
case VNSI_CHANNELSTREAM_CLOSE:
- result = processChannelStream_Close();
+ result = processChannelStream_Close(req);
break;
case VNSI_CHANNELSTREAM_SEEK:
- result = processChannelStream_Seek();
+ result = processChannelStream_Seek(req);
break;
/** OPCODE 40 - 59: VNSI network functions for recording streaming */
case VNSI_RECSTREAM_OPEN:
- result = processRecStream_Open();
+ result = processRecStream_Open(req);
break;
case VNSI_RECSTREAM_CLOSE:
- result = processRecStream_Close();
+ result = processRecStream_Close(req);
break;
case VNSI_RECSTREAM_GETBLOCK:
- result = processRecStream_GetBlock();
+ result = processRecStream_GetBlock(req);
break;
case VNSI_RECSTREAM_POSTOFRAME:
- result = processRecStream_PositionFromFrameNumber();
+ result = processRecStream_PositionFromFrameNumber(req);
break;
case VNSI_RECSTREAM_FRAMETOPOS:
- result = processRecStream_FrameNumberFromPosition();
+ result = processRecStream_FrameNumberFromPosition(req);
break;
case VNSI_RECSTREAM_GETIFRAME:
- result = processRecStream_GetIFrame();
+ result = processRecStream_GetIFrame(req);
break;
case VNSI_RECSTREAM_GETLENGTH:
- result = processRecStream_GetLength();
+ result = processRecStream_GetLength(req);
break;
/** OPCODE 60 - 79: VNSI network functions for channel access */
case VNSI_CHANNELS_GETCOUNT:
- result = processCHANNELS_ChannelsCount();
+ result = processCHANNELS_ChannelsCount(req);
break;
case VNSI_CHANNELS_GETCHANNELS:
- result = processCHANNELS_GetChannels();
+ result = processCHANNELS_GetChannels(req);
break;
case VNSI_CHANNELGROUP_GETCOUNT:
- result = processCHANNELS_GroupsCount();
+ result = processCHANNELS_GroupsCount(req);
break;
case VNSI_CHANNELGROUP_LIST:
- result = processCHANNELS_GroupList();
+ result = processCHANNELS_GroupList(req);
break;
case VNSI_CHANNELGROUP_MEMBERS:
- result = processCHANNELS_GetGroupMembers();
+ result = processCHANNELS_GetGroupMembers(req);
break;
case VNSI_CHANNELS_GETCAIDS:
- result = processCHANNELS_GetCaids();
+ result = processCHANNELS_GetCaids(req);
break;
case VNSI_CHANNELS_GETWHITELIST:
- result = processCHANNELS_GetWhitelist();
+ result = processCHANNELS_GetWhitelist(req);
break;
case VNSI_CHANNELS_GETBLACKLIST:
- result = processCHANNELS_GetBlacklist();
+ result = processCHANNELS_GetBlacklist(req);
break;
case VNSI_CHANNELS_SETWHITELIST:
- result = processCHANNELS_SetWhitelist();
+ result = processCHANNELS_SetWhitelist(req);
break;
case VNSI_CHANNELS_SETBLACKLIST:
- result = processCHANNELS_SetBlacklist();
+ result = processCHANNELS_SetBlacklist(req);
break;
/** OPCODE 80 - 99: VNSI network functions for timer access */
case VNSI_TIMER_GETCOUNT:
- result = processTIMER_GetCount();
+ result = processTIMER_GetCount(req);
break;
case VNSI_TIMER_GET:
- result = processTIMER_Get();
+ result = processTIMER_Get(req);
break;
case VNSI_TIMER_GETLIST:
- result = processTIMER_GetList();
+ result = processTIMER_GetList(req);
break;
case VNSI_TIMER_ADD:
- result = processTIMER_Add();
+ result = processTIMER_Add(req);
break;
case VNSI_TIMER_DELETE:
- result = processTIMER_Delete();
+ result = processTIMER_Delete(req);
break;
case VNSI_TIMER_UPDATE:
- result = processTIMER_Update();
+ result = processTIMER_Update(req);
break;
+ case VNSI_TIMER_GETTYPES:
+ result = processTIMER_GetTypes(req);
+ break;
/** OPCODE 100 - 119: VNSI network functions for recording access */
case VNSI_RECORDINGS_DISKSIZE:
- result = processRECORDINGS_GetDiskSpace();
+ result = processRECORDINGS_GetDiskSpace(req);
break;
case VNSI_RECORDINGS_GETCOUNT:
- result = processRECORDINGS_GetCount();
+ result = processRECORDINGS_GetCount(req);
break;
case VNSI_RECORDINGS_GETLIST:
- result = processRECORDINGS_GetList();
+ result = processRECORDINGS_GetList(req);
break;
case VNSI_RECORDINGS_RENAME:
- result = processRECORDINGS_Rename();
+ result = processRECORDINGS_Rename(req);
break;
case VNSI_RECORDINGS_DELETE:
- result = processRECORDINGS_Delete();
+ result = processRECORDINGS_Delete(req);
break;
case VNSI_RECORDINGS_GETEDL:
- result = processRECORDINGS_GetEdl();
+ result = processRECORDINGS_GetEdl(req);
break;
/** OPCODE 120 - 139: VNSI network functions for epg access and manipulating */
case VNSI_EPG_GETFORCHANNEL:
- result = processEPG_GetForChannel();
+ result = processEPG_GetForChannel(req);
break;
/** OPCODE 140 - 159: VNSI network functions for channel scanning */
case VNSI_SCAN_SUPPORTED:
- result = processSCAN_ScanSupported();
+ result = processSCAN_ScanSupported(req);
break;
case VNSI_SCAN_GETCOUNTRIES:
- result = processSCAN_GetCountries();
+ result = processSCAN_GetCountries(req);
break;
case VNSI_SCAN_GETSATELLITES:
- result = processSCAN_GetSatellites();
+ result = processSCAN_GetSatellites(req);
break;
case VNSI_SCAN_START:
- result = processSCAN_Start();
+ result = processSCAN_Start(req);
break;
case VNSI_SCAN_STOP:
- result = processSCAN_Stop();
+ result = processSCAN_Stop(req);
break;
case VNSI_SCAN_SUPPORTED_TYPES:
- result = processSCAN_GetSupportedTypes();
+ result = processSCAN_GetSupportedTypes(req);
break;
/** OPCODE 160 - 179: VNSI network functions for OSD */
case VNSI_OSD_CONNECT:
- result = processOSD_Connect();
+ result = processOSD_Connect(req);
break;
case VNSI_OSD_DISCONNECT:
@@ -605,55 +582,49 @@ bool cVNSIClient::processRequest(cRequestPacket* req)
break;
case VNSI_OSD_HITKEY:
- result = processOSD_Hitkey();
+ result = processOSD_Hitkey(req);
break;
/** OPCODE 180 - 189: VNSI network functions for deleted recording access */
case VNSI_RECORDINGS_DELETED_ACCESS_SUPPORTED:
- result = processRECORDINGS_DELETED_Supported();
+ result = processRECORDINGS_DELETED_Supported(req);
break;
case VNSI_RECORDINGS_DELETED_GETCOUNT:
- result = processRECORDINGS_DELETED_GetCount();
+ result = processRECORDINGS_DELETED_GetCount(req);
break;
case VNSI_RECORDINGS_DELETED_GETLIST:
- result = processRECORDINGS_DELETED_GetList();
+ result = processRECORDINGS_DELETED_GetList(req);
break;
case VNSI_RECORDINGS_DELETED_DELETE:
- result = processRECORDINGS_DELETED_Delete();
+ result = processRECORDINGS_DELETED_Delete(req);
break;
case VNSI_RECORDINGS_DELETED_UNDELETE:
- result = processRECORDINGS_DELETED_Undelete();
+ result = processRECORDINGS_DELETED_Undelete(req);
break;
case VNSI_RECORDINGS_DELETED_DELETE_ALL:
- result = processRECORDINGS_DELETED_DeleteAll();
+ result = processRECORDINGS_DELETED_DeleteAll(req);
break;
}
- delete m_resp;
- m_resp = NULL;
-
- delete m_req;
- m_req = NULL;
-
return result;
}
/** OPCODE 1 - 19: VNSI network functions for general purpose */
-bool cVNSIClient::process_Login() /* OPCODE 1 */
+bool cVNSIClient::process_Login(cRequestPacket &req) /* OPCODE 1 */
{
- if (m_req->getDataLength() <= 4) return false;
+ if (req.getDataLength() <= 4) return false;
- m_protocolVersion = m_req->extract_U32();
- m_req->extract_U8();
- const char *clientName = m_req->extract_String();
+ m_protocolVersion = req.extract_U32();
+ req.extract_U8();
+ const char *clientName = req.extract_String();
INFOLOG("Welcome client '%s' with protocol version '%u'", clientName, m_protocolVersion);
@@ -662,12 +633,14 @@ bool cVNSIClient::process_Login() /* OPCODE 1 */
struct tm* timeStruct = localtime(&timeNow);
int timeOffset = timeStruct->tm_gmtoff;
- m_resp->add_U32(VNSI_PROTOCOLVERSION);
- m_resp->add_U32(timeNow);
- m_resp->add_S32(timeOffset);
- m_resp->add_String("VDR-Network-Streaming-Interface (VNSI) Server");
- m_resp->add_String(VNSI_SERVER_VERSION);
- m_resp->finalise();
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(VNSI_PROTOCOLVERSION);
+ resp.add_U32(timeNow);
+ resp.add_S32(timeOffset);
+ resp.add_String("VDR-Network-Streaming-Interface (VNSI) Server");
+ resp.add_String(VNSI_SERVER_VERSION);
+ resp.finalise();
if (m_protocolVersion < VNSI_MIN_PROTOCOLVERSION)
ERRORLOG("Client '%s' have a not allowed protocol version '%u', terminating client", clientName, m_protocolVersion);
@@ -684,133 +657,145 @@ bool cVNSIClient::process_Login() /* OPCODE 1 */
m_bSupportRDS = true;
}
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
-
- delete[] clientName;
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::process_GetTime() /* OPCODE 2 */
+bool cVNSIClient::process_GetTime(cRequestPacket &req) /* OPCODE 2 */
{
time_t timeNow = time(NULL);
struct tm* timeStruct = localtime(&timeNow);
int timeOffset = timeStruct->tm_gmtoff;
- m_resp->add_U32(timeNow);
- m_resp->add_S32(timeOffset);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(timeNow);
+ resp.add_S32(timeOffset);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::process_EnableStatusInterface()
+bool cVNSIClient::process_EnableStatusInterface(cRequestPacket &req)
{
- bool enabled = m_req->extract_U8();
+ bool enabled = req.extract_U8();
SetStatusInterface(enabled);
SetPriority(1);
- m_resp->add_U32(VNSI_RET_OK);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(VNSI_RET_OK);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::process_Ping() /* OPCODE 7 */
+bool cVNSIClient::process_Ping(cRequestPacket &req) /* OPCODE 7 */
{
- m_resp->add_U32(1);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(1);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::process_GetSetup() /* OPCODE 8 */
+bool cVNSIClient::process_GetSetup(cRequestPacket &req) /* OPCODE 8 */
{
- char* name = m_req->extract_String();
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ char* name = req.extract_String();
if (!strcasecmp(name, CONFNAME_PMTTIMEOUT))
- m_resp->add_U32(PmtTimeout);
+ resp.add_U32(PmtTimeout);
else if (!strcasecmp(name, CONFNAME_TIMESHIFT))
- m_resp->add_U32(TimeshiftMode);
+ resp.add_U32(TimeshiftMode);
else if (!strcasecmp(name, CONFNAME_TIMESHIFTBUFFERSIZE))
- m_resp->add_U32(TimeshiftBufferSize);
+ resp.add_U32(TimeshiftBufferSize);
else if (!strcasecmp(name, CONFNAME_TIMESHIFTBUFFERFILESIZE))
- m_resp->add_U32(TimeshiftBufferFileSize);
+ resp.add_U32(TimeshiftBufferFileSize);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::process_StoreSetup() /* OPCODE 9 */
+bool cVNSIClient::process_StoreSetup(cRequestPacket &req) /* OPCODE 9 */
{
- char* name = m_req->extract_String();
+ char* name = req.extract_String();
if (!strcasecmp(name, CONFNAME_PMTTIMEOUT))
{
- int value = m_req->extract_U32();
+ int value = req.extract_U32();
cPluginVNSIServer::StoreSetup(CONFNAME_PMTTIMEOUT, value);
}
else if (!strcasecmp(name, CONFNAME_TIMESHIFT))
{
- int value = m_req->extract_U32();
+ int value = req.extract_U32();
cPluginVNSIServer::StoreSetup(CONFNAME_TIMESHIFT, value);
}
else if (!strcasecmp(name, CONFNAME_TIMESHIFTBUFFERSIZE))
{
- int value = m_req->extract_U32();
+ int value = req.extract_U32();
cPluginVNSIServer::StoreSetup(CONFNAME_TIMESHIFTBUFFERSIZE, value);
}
else if (!strcasecmp(name, CONFNAME_TIMESHIFTBUFFERFILESIZE))
{
- int value = m_req->extract_U32();
+ int value = req.extract_U32();
cPluginVNSIServer::StoreSetup(CONFNAME_TIMESHIFTBUFFERFILESIZE, value);
}
else if (!strcasecmp(name, CONFNAME_PLAYRECORDING))
{
- int value = m_req->extract_U32();
+ int value = req.extract_U32();
cPluginVNSIServer::StoreSetup(CONFNAME_PLAYRECORDING, value);
}
- m_resp->add_U32(VNSI_RET_OK);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(VNSI_RET_OK);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
/** OPCODE 20 - 39: VNSI network functions for live streaming */
-bool cVNSIClient::processChannelStream_Open() /* OPCODE 20 */
+bool cVNSIClient::processChannelStream_Open(cRequestPacket &req) /* OPCODE 20 */
{
- uint32_t uid = m_req->extract_U32();
- int32_t priority = m_req->extract_S32();
- uint8_t timeshift = m_req->extract_U8();
- uint32_t timeout = m_req->extract_U32();
-
- if(timeout == 0)
- timeout = VNSIServerConfig.stream_timeout;
+ uint32_t uid = req.extract_U32();
+ int32_t priority = req.extract_S32();
+ uint8_t timeshift = req.extract_U8();
+ uint32_t timeout = req.end()
+ ? VNSIServerConfig.stream_timeout
+ : req.extract_U32();
if (m_isStreaming)
StopChannelStreaming();
- Channels.Lock(false);
- const cChannel *channel = NULL;
-
- // try to find channel by uid first
- channel = FindChannelByUID(uid);
- Channels.Unlock();
+ const cChannel *channel = FindChannelByUID(uid);
// try channelnumber
if (channel == NULL)
+ {
+#if VDRVERSNUM >= 20301
+ LOCK_CHANNELS_READ;
+ channel = Channels->GetByNumber(uid);
+#else
channel = Channels.GetByNumber(uid);
+#endif
+ }
+
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
if (channel == NULL) {
ERRORLOG("Can't find channel %08x", uid);
- m_resp->add_U32(VNSI_RET_DATAINVALID);
+ resp.add_U32(VNSI_RET_DATAINVALID);
}
else
{
- if (StartChannelStreaming(channel, priority, timeshift, timeout))
+ if (StartChannelStreaming(resp, channel, priority, timeshift, timeout))
{
INFOLOG("Started streaming of channel %s (timeout %i seconds)", channel->Name(), timeout);
// return here without sending the response
@@ -819,93 +804,98 @@ bool cVNSIClient::processChannelStream_Open() /* OPCODE 20 */
}
DEBUGLOG("Can't stream channel %s", channel->Name());
- m_resp->add_U32(VNSI_RET_DATALOCKED);
+ resp.add_U32(VNSI_RET_DATALOCKED);
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return false;
}
-bool cVNSIClient::processChannelStream_Close() /* OPCODE 21 */
+bool cVNSIClient::processChannelStream_Close(cRequestPacket &req) /* OPCODE 21 */
{
if (m_isStreaming)
StopChannelStreaming();
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+
return true;
}
-bool cVNSIClient::processChannelStream_Seek() /* OPCODE 22 */
+bool cVNSIClient::processChannelStream_Seek(cRequestPacket &req) /* OPCODE 22 */
{
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
uint32_t serial = 0;
if (m_isStreaming && m_Streamer)
{
- int64_t time = m_req->extract_S64();
+ int64_t time = req.extract_S64();
if (m_Streamer->SeekTime(time, serial))
- m_resp->add_U32(VNSI_RET_OK);
+ resp.add_U32(VNSI_RET_OK);
else
- m_resp->add_U32(VNSI_RET_ERROR);
+ resp.add_U32(VNSI_RET_ERROR);
}
else
- m_resp->add_U32(VNSI_RET_ERROR);
+ resp.add_U32(VNSI_RET_ERROR);
- m_resp->add_U32(serial);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.add_U32(serial);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
/** OPCODE 40 - 59: VNSI network functions for recording streaming */
-bool cVNSIClient::processRecStream_Open() /* OPCODE 40 */
+bool cVNSIClient::processRecStream_Open(cRequestPacket &req) /* OPCODE 40 */
{
- cRecording *recording = NULL;
+ const cRecording *recording = NULL;
- uint32_t uid = m_req->extract_U32();
+ uint32_t uid = req.extract_U32();
recording = cRecordingsCache::GetInstance().Lookup(uid);
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
if (recording && m_RecPlayer == NULL)
{
m_RecPlayer = new cRecPlayer(recording);
- m_resp->add_U32(VNSI_RET_OK);
- m_resp->add_U32(m_RecPlayer->getLengthFrames());
- m_resp->add_U64(m_RecPlayer->getLengthBytes());
-
-#if VDRVERSNUM < 10703
- m_resp->add_U8(true);//added for TS
-#else
- m_resp->add_U8(recording->IsPesRecording());//added for TS
-#endif
+ resp.add_U32(VNSI_RET_OK);
+ resp.add_U32(m_RecPlayer->getLengthFrames());
+ resp.add_U64(m_RecPlayer->getLengthBytes());
+ resp.add_U8(recording->IsPesRecording());//added for TS
}
else
{
- m_resp->add_U32(VNSI_RET_DATAUNKNOWN);
+ resp.add_U32(VNSI_RET_DATAUNKNOWN);
ERRORLOG("%s - unable to start recording !", __FUNCTION__);
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRecStream_Close() /* OPCODE 41 */
+bool cVNSIClient::processRecStream_Close(cRequestPacket &req) /* OPCODE 41 */
{
- if (m_RecPlayer)
- {
- delete m_RecPlayer;
- m_RecPlayer = NULL;
- }
+ delete m_RecPlayer;
+ m_RecPlayer = NULL;
- m_resp->add_U32(VNSI_RET_OK);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(VNSI_RET_OK);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRecStream_GetBlock() /* OPCODE 42 */
+bool cVNSIClient::processRecStream_GetBlock(cRequestPacket &req) /* OPCODE 42 */
{
if (m_isStreaming)
{
@@ -919,62 +909,69 @@ bool cVNSIClient::processRecStream_GetBlock() /* OPCODE 42 */
return false;
}
- uint64_t position = m_req->extract_U64();
- uint32_t amount = m_req->extract_U32();
+ uint64_t position = req.extract_U64();
+ uint32_t amount = req.extract_U32();
+
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
- uint8_t* p = m_resp->reserve(amount);
+ uint8_t* p = resp.reserve(amount);
uint32_t amountReceived = m_RecPlayer->getBlock(p, position, amount);
- if(amount > amountReceived) m_resp->unreserve(amount - amountReceived);
+ if(amount > amountReceived) resp.unreserve(amount - amountReceived);
if (!amountReceived)
{
- m_resp->add_U32(0);
+ resp.add_U32(0);
DEBUGLOG("written 4(0) as getblock got 0");
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRecStream_PositionFromFrameNumber() /* OPCODE 43 */
+bool cVNSIClient::processRecStream_PositionFromFrameNumber(cRequestPacket &req) /* OPCODE 43 */
{
uint64_t retval = 0;
- uint32_t frameNumber = m_req->extract_U32();
+ uint32_t frameNumber = req.extract_U32();
if (m_RecPlayer)
retval = m_RecPlayer->positionFromFrameNumber(frameNumber);
- m_resp->add_U64(retval);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U64(retval);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
DEBUGLOG("Wrote posFromFrameNum reply to client");
return true;
}
-bool cVNSIClient::processRecStream_FrameNumberFromPosition() /* OPCODE 44 */
+bool cVNSIClient::processRecStream_FrameNumberFromPosition(cRequestPacket &req) /* OPCODE 44 */
{
uint32_t retval = 0;
- uint64_t position = m_req->extract_U64();
+ uint64_t position = req.extract_U64();
if (m_RecPlayer)
retval = m_RecPlayer->frameNumberFromPosition(position);
- m_resp->add_U32(retval);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(retval);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
DEBUGLOG("Wrote frameNumFromPos reply to client");
return true;
}
-bool cVNSIClient::processRecStream_GetIFrame() /* OPCODE 45 */
+bool cVNSIClient::processRecStream_GetIFrame(cRequestPacket &req) /* OPCODE 45 */
{
bool success = false;
- uint32_t frameNumber = m_req->extract_U32();
- uint32_t direction = m_req->extract_U32();
+ uint32_t frameNumber = req.extract_U32();
+ uint32_t direction = req.extract_U32();
uint64_t rfilePosition = 0;
uint32_t rframeNumber = 0;
uint32_t rframeLength = 0;
@@ -982,26 +979,29 @@ bool cVNSIClient::processRecStream_GetIFrame() /* OPCODE 45 */
if (m_RecPlayer)
success = m_RecPlayer->getNextIFrame(frameNumber, direction, &rfilePosition, &rframeNumber, &rframeLength);
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
// returns file position, frame number, length
if (success)
{
- m_resp->add_U64(rfilePosition);
- m_resp->add_U32(rframeNumber);
- m_resp->add_U32(rframeLength);
+ resp.add_U64(rfilePosition);
+ resp.add_U32(rframeNumber);
+ resp.add_U32(rframeLength);
}
else
{
- m_resp->add_U32(0);
+ resp.add_U32(0);
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
DEBUGLOG("Wrote GNIF reply to client %lu %u %u", rfilePosition, rframeNumber, rframeLength);
return true;
}
-bool cVNSIClient::processRecStream_GetLength() /* OPCODE 46 */
+bool cVNSIClient::processRecStream_GetLength(cRequestPacket &req) /* OPCODE 46 */
{
uint64_t length = 0;
@@ -1011,42 +1011,66 @@ bool cVNSIClient::processRecStream_GetLength() /* OPCODE 46 */
length = m_RecPlayer->getLengthBytes();
}
- m_resp->add_U64(length);
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U64(length);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
/** OPCODE 60 - 79: VNSI network functions for channel access */
-bool cVNSIClient::processCHANNELS_ChannelsCount() /* OPCODE 61 */
+bool cVNSIClient::processCHANNELS_ChannelsCount(cRequestPacket &req) /* OPCODE 61 */
{
+ int count = 0;
+#if VDRVERSNUM >= 20301
+ {
+ LOCK_CHANNELS_READ;
+ count = Channels->MaxNumber();
+ }
+#else
Channels.Lock(false);
- int count = Channels.MaxNumber();
+ count = Channels.MaxNumber();
Channels.Unlock();
+#endif
- m_resp->add_U32(count);
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(count);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processCHANNELS_GetChannels() /* OPCODE 63 */
+bool cVNSIClient::processCHANNELS_GetChannels(cRequestPacket &req) /* OPCODE 63 */
{
- if (m_req->getDataLength() != 5) return false;
+ if (req.getDataLength() != 5) return false;
- bool radio = m_req->extract_U32();
- bool filter = m_req->extract_U8();
+ bool radio = req.extract_U32();
+ bool filter = req.extract_U8();
+#if VDRVERSNUM >= 20301
+ cStateKey ChannelsKey(true);
+ const cChannels *Channels = cChannels::GetChannelsRead(ChannelsKey);
+#else
Channels.Lock(false);
+#endif
+
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
cString caids;
int caid;
int caid_idx;
+#if VDRVERSNUM >= 20301
+ for (const cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel))
+#else
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
+#endif
{
if (radio != cVNSIChannelFilter::IsRadio(channel))
continue;
@@ -1060,11 +1084,11 @@ bool cVNSIClient::processCHANNELS_GetChannels() /* OPCODE 63 */
continue;
uint32_t uuid = CreateChannelUID(channel);
- m_resp->add_U32(channel->Number());
- m_resp->add_String(m_toUTF8.Convert(channel->Name()));
- m_resp->add_String(m_toUTF8.Convert(channel->Provider()));
- m_resp->add_U32(uuid);
- m_resp->add_U32(channel->Ca(0));
+ resp.add_U32(channel->Number());
+ resp.add_String(m_toUTF8.Convert(channel->Name()));
+ resp.add_String(m_toUTF8.Convert(channel->Provider()));
+ resp.add_U32(uuid);
+ resp.add_U32(channel->Ca(0));
caid_idx = 0;
caids = "caids:";
while((caid = channel->Ca(caid_idx)) != 0)
@@ -1072,35 +1096,31 @@ bool cVNSIClient::processCHANNELS_GetChannels() /* OPCODE 63 */
caids = cString::sprintf("%s%d;", (const char*)caids, caid);
caid_idx++;
}
- m_resp->add_String((const char*)caids);
+ resp.add_String((const char*)caids);
if (m_protocolVersion >= 6)
{
- m_resp->add_String(CreatePiconRef(channel));
+ resp.add_String(CreatePiconRef(channel));
}
// create entry in EPG map on first query
- std::map<int, sEpgUpdate>::iterator it;
- it = m_epgUpdate.find(uuid);
- if (it == m_epgUpdate.end())
- {
- m_epgUpdate[uuid].lastEvent = 0;
- m_epgUpdate[uuid].attempts = 0;
- }
+ m_epgUpdate.insert(std::make_pair(uuid, sEpgUpdate()));
}
+#if VDRVERSNUM >= 20301
+ ChannelsKey.Remove();
+#else
Channels.Unlock();
+#endif
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processCHANNELS_GroupsCount()
+bool cVNSIClient::processCHANNELS_GroupsCount(cRequestPacket &req)
{
- uint32_t type = m_req->extract_U32();
-
- Channels.Lock(false);
+ uint32_t type = req.extract_U32();
m_channelgroups[0].clear();
m_channelgroups[1].clear();
@@ -1118,54 +1138,63 @@ bool cVNSIClient::processCHANNELS_GroupsCount()
break;
}
- Channels.Unlock();
-
uint32_t count = m_channelgroups[0].size() + m_channelgroups[1].size();
- m_resp->add_U32(count);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(count);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processCHANNELS_GroupList()
+bool cVNSIClient::processCHANNELS_GroupList(cRequestPacket &req)
{
- uint32_t radio = m_req->extract_U8();
- std::map<std::string, ChannelGroup>::iterator i;
+ uint32_t radio = req.extract_U8();
- for(i = m_channelgroups[radio].begin(); i != m_channelgroups[radio].end(); i++)
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
+ for (const auto &i : m_channelgroups[radio])
{
- m_resp->add_String(i->second.name.c_str());
- m_resp->add_U8(i->second.radio);
+ resp.add_String(i.second.name.c_str());
+ resp.add_U8(i.second.radio);
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processCHANNELS_GetGroupMembers()
+bool cVNSIClient::processCHANNELS_GetGroupMembers(cRequestPacket &req)
{
- char* groupname = m_req->extract_String();
- uint32_t radio = m_req->extract_U8();
- bool filter = m_req->extract_U8();
+ char* groupname = req.extract_String();
+ uint32_t radio = req.extract_U8();
+ bool filter = req.extract_U8();
int index = 0;
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
// unknown group
if(m_channelgroups[radio].find(groupname) == m_channelgroups[radio].end())
{
- delete[] groupname;
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
bool automatic = m_channelgroups[radio][groupname].automatic;
std::string name;
+#if VDRVERSNUM >= 20301
+ cStateKey ChannelsKey(true);
+ const cChannels *Channels = cChannels::GetChannelsRead(ChannelsKey);
+ for (const cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel))
+#else
Channels.Lock(false);
-
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
+#endif
{
if(automatic && !channel->GroupSep())
@@ -1191,27 +1220,30 @@ bool cVNSIClient::processCHANNELS_GetGroupMembers()
if(name == groupname)
{
- m_resp->add_U32(CreateChannelUID(channel));
- m_resp->add_U32(++index);
+ resp.add_U32(CreateChannelUID(channel));
+ resp.add_U32(++index);
}
}
+#if VDRVERSNUM >= 20301
+ ChannelsKey.Remove();
+#else
Channels.Unlock();
+#endif
- delete[] groupname;
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processCHANNELS_GetCaids()
+bool cVNSIClient::processCHANNELS_GetCaids(cRequestPacket &req)
{
- uint32_t uid = m_req->extract_U32();
+ uint32_t uid = req.extract_U32();
- Channels.Lock(false);
- const cChannel *channel = NULL;
- channel = FindChannelByUID(uid);
- Channels.Unlock();
+ const cChannel *channel = FindChannelByUID(uid);
+
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
if (channel != NULL)
{
@@ -1219,20 +1251,20 @@ bool cVNSIClient::processCHANNELS_GetCaids()
int idx = 0;
while((caid = channel->Ca(idx)) != 0)
{
- m_resp->add_U32(caid);
+ resp.add_U32(caid);
idx++;
}
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processCHANNELS_GetWhitelist()
+bool cVNSIClient::processCHANNELS_GetWhitelist(cRequestPacket &req)
{
- bool radio = m_req->extract_U8();
+ bool radio = req.extract_U8();
std::vector<cVNSIProvider> *providers;
if(radio)
@@ -1240,44 +1272,50 @@ bool cVNSIClient::processCHANNELS_GetWhitelist()
else
providers = &VNSIChannelFilter.m_providersVideo;
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
VNSIChannelFilter.m_Mutex.Lock();
- for(unsigned int i=0; i<providers->size(); i++)
+ for (const auto &i : *providers)
{
- m_resp->add_String((*providers)[i].m_name.c_str());
- m_resp->add_U32((*providers)[i].m_caid);
+ resp.add_String(i.m_name.c_str());
+ resp.add_U32(i.m_caid);
}
VNSIChannelFilter.m_Mutex.Unlock();
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processCHANNELS_GetBlacklist()
+bool cVNSIClient::processCHANNELS_GetBlacklist(cRequestPacket &req)
{
- bool radio = m_req->extract_U8();
- std::vector<int> *channels;
+ bool radio = req.extract_U8();
+ const std::set<int> *channels;
if(radio)
channels = &VNSIChannelFilter.m_channelsRadio;
else
channels = &VNSIChannelFilter.m_channelsVideo;
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
VNSIChannelFilter.m_Mutex.Lock();
- for(unsigned int i=0; i<channels->size(); i++)
+ for (auto i : *channels)
{
- m_resp->add_U32((*channels)[i]);
+ resp.add_U32(i);
}
VNSIChannelFilter.m_Mutex.Unlock();
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processCHANNELS_SetWhitelist()
+bool cVNSIClient::processCHANNELS_SetWhitelist(cRequestPacket &req)
{
- bool radio = m_req->extract_U8();
+ bool radio = req.extract_U8();
cVNSIProvider provider;
std::vector<cVNSIProvider> *providers;
@@ -1289,27 +1327,28 @@ bool cVNSIClient::processCHANNELS_SetWhitelist()
VNSIChannelFilter.m_Mutex.Lock();
providers->clear();
- while(!m_req->end())
+ while(!req.end())
{
- char *str = m_req->extract_String();
+ char *str = req.extract_String();
provider.m_name = str;
- provider.m_caid = m_req->extract_U32();
- delete [] str;
+ provider.m_caid = req.extract_U32();
providers->push_back(provider);
}
VNSIChannelFilter.StoreWhitelist(radio);
VNSIChannelFilter.m_Mutex.Unlock();
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processCHANNELS_SetBlacklist()
+bool cVNSIClient::processCHANNELS_SetBlacklist(cRequestPacket &req)
{
- bool radio = m_req->extract_U8();
+ bool radio = req.extract_U8();
cVNSIProvider provider;
- std::vector<int> *channels;
+ std::set<int> *channels;
if(radio)
channels = &VNSIChannelFilter.m_channelsRadio;
@@ -1320,16 +1359,18 @@ bool cVNSIClient::processCHANNELS_SetBlacklist()
channels->clear();
int id;
- while(!m_req->end())
+ while(!req.end())
{
- id = m_req->extract_U32();
- channels->push_back(id);
+ id = req.extract_U32();
+ channels->insert(id);
}
VNSIChannelFilter.StoreBlacklist(radio);
VNSIChannelFilter.m_Mutex.Unlock();
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
@@ -1337,7 +1378,13 @@ void cVNSIClient::CreateChannelGroups(bool automatic)
{
std::string groupname;
+#if VDRVERSNUM >= 20301
+ LOCK_CHANNELS_READ;
+ for (const cChannel *channel = Channels->First(); channel; channel = Channels->Next(channel))
+#else
+ Channels.Lock(false);
for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
+#endif
{
bool isRadio = cVNSIChannelFilter::IsRadio(channel);
@@ -1358,111 +1405,229 @@ void cVNSIClient::CreateChannelGroups(bool automatic)
m_channelgroups[isRadio][groupname] = group;
}
}
+
+#if VDRVERSNUM < 20301
+ Channels.Unlock();
+#endif
}
/** OPCODE 80 - 99: VNSI network functions for timer access */
-bool cVNSIClient::processTIMER_GetCount() /* OPCODE 80 */
+bool cVNSIClient::processTIMER_GetCount(cRequestPacket &req) /* OPCODE 80 */
{
cMutexLock lock(&m_timerLock);
+#if VDRVERSNUM >= 20301
+ LOCK_TIMERS_READ;
+ int count = Timers->Count() + m_vnsiTimers.GetTimersCount();
+#else
int count = Timers.Count();
+#endif
- m_resp->add_U32(count);
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(count);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processTIMER_Get() /* OPCODE 81 */
+bool cVNSIClient::processTIMER_Get(cRequestPacket &req) /* OPCODE 81 */
{
cMutexLock lock(&m_timerLock);
- uint32_t number = m_req->extract_U32();
+ uint32_t number = req.extract_U32();
- int numTimers = Timers.Count();
- if (numTimers > 0)
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
+ if (number & m_vnsiTimers.INDEX_MASK)
{
- cTimer *timer = Timers.Get(number-1);
- if (timer)
+ CVNSITimer timer;
+ if (m_vnsiTimers.GetTimer(number, timer))
{
- m_resp->add_U32(VNSI_RET_OK);
-
- m_resp->add_U32(timer->Index()+1);
- m_resp->add_U32(timer->HasFlags(tfActive));
- m_resp->add_U32(timer->Recording());
- m_resp->add_U32(timer->Pending());
- m_resp->add_U32(timer->Priority());
- m_resp->add_U32(timer->Lifetime());
- m_resp->add_U32(timer->Channel()->Number());
- m_resp->add_U32(CreateChannelUID(timer->Channel()));
- m_resp->add_U32(timer->StartTime());
- m_resp->add_U32(timer->StopTime());
- m_resp->add_U32(timer->Day());
- m_resp->add_U32(timer->WeekDays());
- m_resp->add_String(m_toUTF8.Convert(timer->File()));
+ resp.add_U32(VNSI_RET_OK);
+
+ resp.add_U32(VNSI_TIMER_TYPE_EPG_SEARCH);
+ resp.add_U32(number);
+ resp.add_U32(timer.m_enabled);
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_U32(timer.m_priority);
+ resp.add_U32(timer.m_lifetime);
+ resp.add_U32(0);
+ resp.add_U32(timer.m_channelUID);
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_String(timer.m_name.c_str());
+ resp.add_String(timer.m_search.c_str());
}
else
- m_resp->add_U32(VNSI_RET_DATAUNKNOWN);
+ {
+ resp.add_U32(VNSI_RET_DATAUNKNOWN);
+ }
}
else
- m_resp->add_U32(VNSI_RET_DATAUNKNOWN);
+ {
+#if VDRVERSNUM >= 20301
+ LOCK_TIMERS_READ;
+ int numTimers = Timers->Count();
+ if (numTimers > 0)
+ {
+ const cTimer *timer = Timers->Get(number-1);
+#else
+ int numTimers = Timers.Count();
+ if (numTimers > 0)
+ {
+ cTimer *timer = Timers.Get(number-1);
+#endif
+ if (timer)
+ {
+ resp.add_U32(VNSI_RET_OK);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ if (m_protocolVersion >= 9)
+ {
+ uint32_t type;
+ if (timer->HasFlags(tfVps))
+ type = VNSI_TIMER_TYPE_VPS;
+ else
+ type = VNSI_TIMER_TYPE_MAN;
+ resp.add_U32(type);
+ }
+ resp.add_U32(timer->Index()+1);
+ resp.add_U32(timer->HasFlags(tfActive));
+ resp.add_U32(timer->Recording());
+ resp.add_U32(timer->Pending());
+ resp.add_U32(timer->Priority());
+ resp.add_U32(timer->Lifetime());
+ resp.add_U32(timer->Channel()->Number());
+ resp.add_U32(CreateChannelUID(timer->Channel()));
+ resp.add_U32(timer->StartTime());
+ resp.add_U32(timer->StopTime());
+ resp.add_U32(timer->Day());
+ resp.add_U32(timer->WeekDays());
+ resp.add_String(m_toUTF8.Convert(timer->File()));
+ if (m_protocolVersion >= 9)
+ {
+ resp.add_String("");
+ }
+ }
+ else
+ resp.add_U32(VNSI_RET_DATAUNKNOWN);
+ }
+ else
+ resp.add_U32(VNSI_RET_DATAUNKNOWN);
+ }
+
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processTIMER_GetList() /* OPCODE 82 */
+bool cVNSIClient::processTIMER_GetList(cRequestPacket &req) /* OPCODE 82 */
{
- cMutexLock lock(&m_timerLock);
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
- cTimer *timer;
- int numTimers = Timers.Count();
-
- m_resp->add_U32(numTimers);
+ cMutexLock lock(&m_timerLock);
+#if VDRVERSNUM >= 20301
+ LOCK_TIMERS_READ;
+ int numVdrTimers = Timers->Count();
+ int numTimers = numVdrTimers + m_vnsiTimers.GetTimersCount();
+ resp.add_U32(numTimers);
+ for (int i = 0; i < numVdrTimers; i++)
+ {
+ const cTimer *timer = Timers->Get(i);
+#else
+ int numTimers = Timers.Count() + m_vnsiTimers.GetTimersCount();
+ resp.add_U32(numTimers);
for (int i = 0; i < numTimers; i++)
{
- timer = Timers.Get(i);
+ cTimer *timer = Timers.Get(i);
+#endif
if (!timer)
continue;
- m_resp->add_U32(timer->Index()+1);
- m_resp->add_U32(timer->HasFlags(tfActive));
- m_resp->add_U32(timer->Recording());
- m_resp->add_U32(timer->Pending());
- m_resp->add_U32(timer->Priority());
- m_resp->add_U32(timer->Lifetime());
- m_resp->add_U32(timer->Channel()->Number());
- m_resp->add_U32(CreateChannelUID(timer->Channel()));
- m_resp->add_U32(timer->StartTime());
- m_resp->add_U32(timer->StopTime());
- m_resp->add_U32(timer->Day());
- m_resp->add_U32(timer->WeekDays());
- m_resp->add_String(m_toUTF8.Convert(timer->File()));
- }
-
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ if (m_protocolVersion >= 9)
+ {
+ uint32_t type;
+ if (timer->HasFlags(tfVps))
+ type = VNSI_TIMER_TYPE_VPS;
+ else
+ type = VNSI_TIMER_TYPE_MAN;
+ resp.add_U32(type);
+ }
+ resp.add_U32(timer->Index()+1);
+ resp.add_U32(timer->HasFlags(tfActive));
+ resp.add_U32(timer->Recording());
+ resp.add_U32(timer->Pending());
+ resp.add_U32(timer->Priority());
+ resp.add_U32(timer->Lifetime());
+ resp.add_U32(timer->Channel()->Number());
+ resp.add_U32(CreateChannelUID(timer->Channel()));
+ resp.add_U32(timer->StartTime());
+ resp.add_U32(timer->StopTime());
+ resp.add_U32(timer->Day());
+ resp.add_U32(timer->WeekDays());
+ resp.add_String(m_toUTF8.Convert(timer->File()));
+ if (m_protocolVersion >= 9)
+ {
+ resp.add_String("");
+ }
+ }
+
+ std::vector<CVNSITimer> vnsitimers = m_vnsiTimers.GetTimers();
+ int idx = m_vnsiTimers.INDEX_MASK;
+ for (auto &vnsitimer : vnsitimers)
+ {
+ resp.add_U32(VNSI_TIMER_TYPE_EPG_SEARCH);
+ resp.add_U32(idx);
+ resp.add_U32(vnsitimer.m_enabled);
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_U32(vnsitimer.m_priority);
+ resp.add_U32(vnsitimer.m_lifetime);
+ resp.add_U32(0);
+ resp.add_U32(vnsitimer.m_channelUID);
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_U32(0);
+ resp.add_String(vnsitimer.m_name.c_str());
+ resp.add_String(vnsitimer.m_search.c_str());
+ idx++;
+ }
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processTIMER_Add() /* OPCODE 83 */
+bool cVNSIClient::processTIMER_Add(cRequestPacket &req) /* OPCODE 83 */
{
cMutexLock lock(&m_timerLock);
- uint32_t flags = m_req->extract_U32() > 0 ? tfActive : tfNone;
- uint32_t priority = m_req->extract_U32();
- uint32_t lifetime = m_req->extract_U32();
- uint32_t channelid = m_req->extract_U32();
- time_t startTime = m_req->extract_U32();
- time_t stopTime = m_req->extract_U32();
- time_t day = m_req->extract_U32();
- uint32_t weekdays = m_req->extract_U32();
- const char *file = m_req->extract_String();
- const char *aux = m_req->extract_String();
+ uint32_t type = 0;
+ std::string epgsearch;
+ if (m_protocolVersion >= 9)
+ {
+ type = req.extract_U32();
+ }
+ uint32_t flags = req.extract_U32() > 0 ? tfActive : tfNone;
+ uint32_t priority = req.extract_U32();
+ uint32_t lifetime = req.extract_U32();
+ uint32_t channelid = req.extract_U32();
+ time_t startTime = req.extract_U32();
+ time_t stopTime = req.extract_U32();
+ time_t day = req.extract_U32();
+ uint32_t weekdays = req.extract_U32();
+ const char *file = req.extract_String();
+ const char *aux = req.extract_String();
+ if (m_protocolVersion >= 9)
+ epgsearch = req.extract_String();
// handle instant timers
if(startTime == -1 || startTime == 0)
@@ -1478,6 +1643,9 @@ bool cVNSIClient::processTIMER_Add() /* OPCODE 83 */
time = localtime_r(&stopTime, &tm_r);
int stop = time->tm_hour * 100 + time->tm_min;
+ if (type == VNSI_TIMER_TYPE_VPS)
+ flags |= tfVps;
+
cString buffer;
const cChannel* channel = FindChannelByUID(channelid);
if(channel != NULL)
@@ -1485,138 +1653,254 @@ bool cVNSIClient::processTIMER_Add() /* OPCODE 83 */
buffer = cString::sprintf("%u:%s:%s:%04d:%04d:%d:%d:%s:%s\n", flags, (const char*)channel->GetChannelID().ToString(), *cTimer::PrintDay(day, weekdays, true), start, stop, priority, lifetime, file, aux);
}
- delete[] file;
- delete[] aux;
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
- cTimer *timer = new cTimer;
- if (timer->Parse(buffer))
+ if (type == VNSI_TIMER_TYPE_EPG_SEARCH)
{
- cTimer *t = Timers.GetTimer(timer);
- if (!t)
+ CVNSITimer vnsitimer;
+ vnsitimer.m_name = aux;
+ vnsitimer.m_channelUID = channelid;
+ vnsitimer.m_search = epgsearch;
+ vnsitimer.m_enabled = flags;
+ vnsitimer.m_lifetime = lifetime;
+ m_vnsiTimers.Add(std::move(vnsitimer));
+ resp.add_U32(VNSI_RET_OK);
+ }
+ else
+ {
+ std::unique_ptr<cTimer> timer(new cTimer);
+ if (timer->Parse(buffer))
{
- Timers.Add(timer);
- Timers.SetModified();
- INFOLOG("Timer %s added", *timer->ToDescr());
- m_resp->add_U32(VNSI_RET_OK);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
- return true;
+#if VDRVERSNUM >= 20301
+ LOCK_TIMERS_WRITE;
+ const cTimer *t = Timers->GetTimer(timer.get());
+ if (!t)
+ {
+ INFOLOG("Timer %s added", *timer->ToDescr());
+ Timers->Add(timer.release());
+ Timers->SetModified();
+ resp.add_U32(VNSI_RET_OK);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+ return true;
+ }
+#else
+ cTimer *t = Timers.GetTimer(timer.get());
+ if (!t)
+ {
+ INFOLOG("Timer %s added", *timer->ToDescr());
+ Timers.Add(timer.release());
+ Timers.SetModified();
+ resp.add_U32(VNSI_RET_OK);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+ return true;
+ }
+#endif
+ else
+ {
+ ERRORLOG("Timer already defined: %d %s", t->Index() + 1, *t->ToText());
+ resp.add_U32(VNSI_RET_DATALOCKED);
+ }
}
else
{
- ERRORLOG("Timer already defined: %d %s", t->Index() + 1, *t->ToText());
- m_resp->add_U32(VNSI_RET_DATALOCKED);
+ ERRORLOG("Error in timer settings");
+ resp.add_U32(VNSI_RET_DATAINVALID);
}
}
- else
- {
- ERRORLOG("Error in timer settings");
- m_resp->add_U32(VNSI_RET_DATAINVALID);
- }
-
- delete timer;
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processTIMER_Delete() /* OPCODE 84 */
+bool cVNSIClient::processTIMER_Delete(cRequestPacket &req) /* OPCODE 84 */
{
cMutexLock lock(&m_timerLock);
- uint32_t number = m_req->extract_U32();
- bool force = m_req->extract_U32();
+ uint32_t number = req.extract_U32();
+ bool force = req.extract_U32();
+
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
- if (number <= 0 || number > (uint32_t)Timers.Count())
+ if (number & m_vnsiTimers.INDEX_MASK)
{
- ERRORLOG("Unable to delete timer - invalid timer identifier");
- m_resp->add_U32(VNSI_RET_DATAINVALID);
+ if (m_vnsiTimers.DeleteTimer(number))
+ {
+ INFOLOG("Deleting vnsitimer %d", number);
+ resp.add_U32(VNSI_RET_OK);
+ }
+ else
+ {
+ ERRORLOG("Unable to delete timer - invalid timer identifier");
+ resp.add_U32(VNSI_RET_DATAINVALID);
+ }
}
else
{
- cTimer *timer = Timers.Get(number-1);
- if (timer)
+#if VDRVERSNUM >= 20301
+ LOCK_TIMERS_WRITE;
+ int timersCount = Timers->Count();
+#else
+ int timersCount = Timers.Count();
+#endif
+
+ if (number <= 0 || number > (uint32_t)timersCount)
{
- if (!Timers.BeingEdited())
+ ERRORLOG("Unable to delete timer - invalid timer identifier");
+ resp.add_U32(VNSI_RET_DATAINVALID);
+ }
+ else
+ {
+#if VDRVERSNUM >= 20301
+ cTimer *timer = Timers->Get(number-1);
+ if (timer)
{
- if (timer->Recording())
+ Timers->SetExplicitModify();
{
- if (force)
+ if (timer->Recording())
{
- timer->Skip();
- cRecordControls::Process(time(NULL));
+ if (force)
+ {
+ timer->Skip();
+ cRecordControls::Process(Timers, time(NULL));
+ }
+ else
+ {
+ ERRORLOG("Timer \"%i\" is recording and can be deleted (use force=1 to stop it)", number);
+ resp.add_U32(VNSI_RET_RECRUNNING);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+ return true;
+ }
}
- else
+ INFOLOG("Deleting timer %s", *timer->ToDescr());
+ Timers->Del(timer);
+ Timers->SetModified();
+ resp.add_U32(VNSI_RET_OK);
+ }
+#else
+ cTimer *timer = Timers.Get(number-1);
+ if (timer)
+ {
+ if (!Timers.BeingEdited())
+ {
+ if (timer->Recording())
{
- ERRORLOG("Timer \"%i\" is recording and can be deleted (use force=1 to stop it)", number);
- m_resp->add_U32(VNSI_RET_RECRUNNING);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
- return true;
+ if (force)
+ {
+ timer->Skip();
+ cRecordControls::Process(time(NULL));
+ }
+ else
+ {
+ ERRORLOG("Timer \"%i\" is recording and can be deleted (use force=1 to stop it)", number);
+ resp.add_U32(VNSI_RET_RECRUNNING);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+ return true;
+ }
}
+ INFOLOG("Deleting timer %s", *timer->ToDescr());
+ Timers.Del(timer);
+ Timers.SetModified();
+ resp.add_U32(VNSI_RET_OK);
}
- INFOLOG("Deleting timer %s", *timer->ToDescr());
- Timers.Del(timer);
- Timers.SetModified();
- m_resp->add_U32(VNSI_RET_OK);
+ else
+ {
+ ERRORLOG("Unable to delete timer - timers being edited at VDR");
+ resp.add_U32(VNSI_RET_DATALOCKED);
+ }
+#endif
}
else
{
- ERRORLOG("Unable to delete timer - timers being edited at VDR");
- m_resp->add_U32(VNSI_RET_DATALOCKED);
+ ERRORLOG("Unable to delete timer - invalid timer identifier");
+ resp.add_U32(VNSI_RET_DATAINVALID);
}
}
- else
- {
- ERRORLOG("Unable to delete timer - invalid timer identifier");
- m_resp->add_U32(VNSI_RET_DATAINVALID);
- }
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processTIMER_Update() /* OPCODE 85 */
+bool cVNSIClient::processTIMER_Update(cRequestPacket &req) /* OPCODE 85 */
{
cMutexLock lock(&m_timerLock);
- int length = m_req->getDataLength();
- uint32_t index = m_req->extract_U32();
- bool active = m_req->extract_U32();
-
- cTimer *timer = Timers.Get(index - 1);
- if (!timer)
- {
- ERRORLOG("Timer \"%u\" not defined", index);
- m_resp->add_U32(VNSI_RET_DATAUNKNOWN);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
- return true;
- }
-
- cTimer t = *timer;
-
- if (length == 8)
- {
- if (active)
- t.SetFlags(tfActive);
- else
- t.ClrFlags(tfActive);
+ bool active;
+ uint32_t priority, lifetime, channelid, weekdays;
+ uint32_t type = 0;
+ time_t startTime, stopTime, day;
+ const char *file;
+ const char *aux;
+ std::string epgsearch;
+
+ uint32_t index = req.extract_U32();
+
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
+ type = m_protocolVersion >= 9
+ ? req.extract_U32()
+ : VNSI_TIMER_TYPE_MAN;
+
+ active = req.extract_U32();
+ priority = req.extract_U32();
+ lifetime = req.extract_U32();
+ channelid = req.extract_U32();
+ startTime = req.extract_U32();
+ stopTime = req.extract_U32();
+ day = req.extract_U32();
+ weekdays = req.extract_U32();
+ file = req.extract_String();
+ aux = req.extract_String();
+ if (m_protocolVersion >= 9)
+ {
+ epgsearch = req.extract_String();
+ }
+
+ if (index & m_vnsiTimers.INDEX_MASK)
+ {
+ CVNSITimer vnsitimer;
+ vnsitimer.m_name = aux;
+ vnsitimer.m_channelUID = channelid;
+ vnsitimer.m_search = epgsearch;
+ vnsitimer.m_enabled = active;
+ vnsitimer.m_priority = priority;
+ vnsitimer.m_lifetime = lifetime;
+ if (!m_vnsiTimers.UpdateTimer(index, vnsitimer))
+ {
+ ERRORLOG("Timer \"%u\" not defined", index);
+ resp.add_U32(VNSI_RET_DATAUNKNOWN);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+ return true;
+ }
}
else
{
- uint32_t flags = active ? tfActive : tfNone;
- uint32_t priority = m_req->extract_U32();
- uint32_t lifetime = m_req->extract_U32();
- uint32_t channelid = m_req->extract_U32();
- time_t startTime = m_req->extract_U32();
- time_t stopTime = m_req->extract_U32();
- time_t day = m_req->extract_U32();
- uint32_t weekdays = m_req->extract_U32();
- const char *file = m_req->extract_String();
- const char *aux = m_req->extract_String();
+#if VDRVERSNUM >= 20301
+ LOCK_TIMERS_WRITE;
+ cTimer *timer = Timers->Get(index - 1);
+#else
+ cTimer *timer = Timers.Get(index - 1);
+#endif
+
+ if (!timer)
+ {
+ ERRORLOG("Timer \"%u\" not defined", index);
+ resp.add_U32(VNSI_RET_DATAUNKNOWN);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+ return true;
+ }
+
+ cTimer t = *timer;
struct tm tm_r;
struct tm *time = localtime_r(&startTime, &tm_r);
@@ -1626,6 +1910,10 @@ bool cVNSIClient::processTIMER_Update() /* OPCODE 85 */
time = localtime_r(&stopTime, &tm_r);
int stop = time->tm_hour * 100 + time->tm_min;
+ uint32_t flags = active > 0 ? tfActive : tfNone;
+ if (type == VNSI_TIMER_TYPE_VPS)
+ flags |= tfVps;
+
cString buffer;
const cChannel* channel = FindChannelByUID(channelid);
if(channel != NULL)
@@ -1633,32 +1921,47 @@ bool cVNSIClient::processTIMER_Update() /* OPCODE 85 */
buffer = cString::sprintf("%u:%s:%s:%04d:%04d:%d:%d:%s:%s\n", flags, (const char*)channel->GetChannelID().ToString(), *cTimer::PrintDay(day, weekdays, true), start, stop, priority, lifetime, file, aux);
}
- delete[] file;
- delete[] aux;
-
if (!t.Parse(buffer))
{
ERRORLOG("Error in timer settings");
- m_resp->add_U32(VNSI_RET_DATAINVALID);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.add_U32(VNSI_RET_DATAINVALID);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
- }
- *timer = t;
- Timers.SetModified();
+ *timer = t;
+#if VDRVERSNUM >= 20301
+ Timers->SetModified();
+#else
+ Timers.SetModified();
+#endif
+
+ }
- m_resp->add_U32(VNSI_RET_OK);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.add_U32(VNSI_RET_OK);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
+bool cVNSIClient::processTIMER_GetTypes(cRequestPacket &req) /* OPCODE 80 */
+{
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+#if VDRVERSNUM >= 20301
+ resp.add_U32(VNSI_TIMER_TYPE_EPG_SEARCH);
+#else
+ resp.add_U32(0);
+#endif
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+ return true;
+}
/** OPCODE 100 - 119: VNSI network functions for recording access */
-bool cVNSIClient::processRECORDINGS_GetDiskSpace() /* OPCODE 100 */
+bool cVNSIClient::processRECORDINGS_GetDiskSpace(cRequestPacket &req) /* OPCODE 100 */
{
int FreeMB;
int UsedMB;
@@ -1669,30 +1972,52 @@ bool cVNSIClient::processRECORDINGS_GetDiskSpace() /* OPCODE 100 */
#endif
int Total = FreeMB + UsedMB;
- m_resp->add_U32(Total);
- m_resp->add_U32(FreeMB);
- m_resp->add_U32(Percent);
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.add_U32(Total);
+ resp.add_U32(FreeMB);
+ resp.add_U32(Percent);
+
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRECORDINGS_GetCount() /* OPCODE 101 */
+bool cVNSIClient::processRECORDINGS_GetCount(cRequestPacket &req) /* OPCODE 101 */
{
- m_resp->add_U32(Recordings.Count());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
+#if VDRVERSNUM >= 20301
+ LOCK_RECORDINGS_READ;
+ resp.add_U32(Recordings->Count());
+#else
+ resp.add_U32(Recordings.Count());
+#endif
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRECORDINGS_GetList() /* OPCODE 102 */
+bool cVNSIClient::processRECORDINGS_GetList(cRequestPacket &req) /* OPCODE 102 */
{
cMutexLock lock(&m_timerLock);
+#if VDRVERSNUM >= 20301
+ LOCK_RECORDINGS_READ;
+#else
cThreadLock RecordingsLock(&Recordings);
+#endif
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
+#if VDRVERSNUM >= 20301
+ for (const cRecording *recording = Recordings->First(); recording; recording = Recordings->Next(recording))
+#else
for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording))
+#endif
{
#if APIVERSNUM >= 10705
const cEvent *event = recording->Info()->GetEvent();
@@ -1727,58 +2052,83 @@ bool cVNSIClient::processRECORDINGS_GetList() /* OPCODE 102 */
DEBUGLOG("GRI: RC: recordingStart=%lu recordingDuration=%i", recordingStart, recordingDuration);
// recording_time
- m_resp->add_U32(recordingStart);
+ resp.add_U32(recordingStart);
// duration
- m_resp->add_U32(recordingDuration);
+ resp.add_U32(recordingDuration);
// priority
#if APIVERSNUM >= 10727
- m_resp->add_U32(recording->Priority());
+ resp.add_U32(recording->Priority());
#else
- m_resp->add_U32(recording->priority);
+ resp.add_U32(recording->priority);
#endif
// lifetime
#if APIVERSNUM >= 10727
- m_resp->add_U32(recording->Lifetime());
+ resp.add_U32(recording->Lifetime());
#else
- m_resp->add_U32(recording->lifetime);
+ resp.add_U32(recording->lifetime);
#endif
// channel_name
- m_resp->add_String(recording->Info()->ChannelName() ? m_toUTF8.Convert(recording->Info()->ChannelName()) : "");
+ resp.add_String(recording->Info()->ChannelName() ? m_toUTF8.Convert(recording->Info()->ChannelName()) : "");
+ if (m_protocolVersion >= 9)
+ {
+ // channel uuid
+#if VDRVERSNUM >= 20301
+ LOCK_CHANNELS_READ;
+ const cChannel *channel = Channels->GetByChannelID(recording->Info()->ChannelID());
+#else
+ Channels.Lock(false);
+ const cChannel *channel = Channels.GetByChannelID(recording->Info()->ChannelID());
+ Channels.Unlock();
+#endif
+ if (channel)
+ {
+ resp.add_U32(CreateChannelUID(channel));
+ resp.add_U8(cVNSIChannelFilter::IsRadio(channel) ? 1 : 2);
+ }
+ else
+ {
+ resp.add_U32(0);
+ resp.add_U8(0);
+ }
+ }
char* fullname = strdup(recording->Name());
char* recname = strrchr(fullname, FOLDERDELIMCHAR);
char* directory = NULL;
- if(recname == NULL) {
+ if(recname == NULL)
+ {
recname = fullname;
}
- else {
+ else
+ {
*recname = 0;
recname++;
directory = fullname;
}
// title
- m_resp->add_String(m_toUTF8.Convert(recname));
+ resp.add_String(m_toUTF8.Convert(recname));
// subtitle
if (!isempty(recording->Info()->ShortText()))
- m_resp->add_String(m_toUTF8.Convert(recording->Info()->ShortText()));
+ resp.add_String(m_toUTF8.Convert(recording->Info()->ShortText()));
else
- m_resp->add_String("");
+ resp.add_String("");
// description
if (!isempty(recording->Info()->Description()))
- m_resp->add_String(m_toUTF8.Convert(recording->Info()->Description()));
+ resp.add_String(m_toUTF8.Convert(recording->Info()->Description()));
else
- m_resp->add_String("");
+ resp.add_String("");
// directory
- if(directory != NULL) {
+ if(directory != NULL)
+ {
char* p = directory;
while(*p != 0) {
if(*p == FOLDERDELIMCHAR) *p = '/';
@@ -1788,68 +2138,77 @@ bool cVNSIClient::processRECORDINGS_GetList() /* OPCODE 102 */
while(*directory == '/') directory++;
}
- m_resp->add_String((isempty(directory)) ? "" : m_toUTF8.Convert(directory));
+ resp.add_String((isempty(directory)) ? "" : m_toUTF8.Convert(directory));
// filename / uid of recording
uint32_t uid = cRecordingsCache::GetInstance().Register(recording, false);
- m_resp->add_U32(uid);
+ resp.add_U32(uid);
free(fullname);
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRECORDINGS_Rename() /* OPCODE 103 */
+bool cVNSIClient::processRECORDINGS_Rename(cRequestPacket &req) /* OPCODE 103 */
{
- uint32_t uid = m_req->extract_U32();
- char* newtitle = m_req->extract_String();
- cRecording* recording = cRecordingsCache::GetInstance().Lookup(uid);
- int r = VNSI_RET_DATAINVALID;
+ uint32_t uid = req.extract_U32();
+ char* newtitle = req.extract_String();
+ int r = VNSI_RET_DATAINVALID;
+
+#if VDRVERSNUM >= 20301
+ LOCK_RECORDINGS_WRITE;
+#endif
+
+ const cRecording* recording = cRecordingsCache::GetInstance().Lookup(uid);
if(recording != NULL) {
// get filename and remove last part (recording time)
- char* filename_old = strdup((const char*)recording->FileName());
- char* sep = strrchr(filename_old, '/');
- if(sep != NULL) {
- *sep = 0;
- }
+ std::string filename_old(recording->FileName());
+ std::string::size_type i = filename_old.rfind('/');
+ if (i != filename_old.npos)
+ filename_old.erase(i);
// replace spaces in newtitle
strreplace(newtitle, ' ', '_');
- char* filename_new = new char[1024];
- strncpy(filename_new, filename_old, 512);
- sep = strrchr(filename_new, '/');
- if(sep != NULL) {
- sep++;
- *sep = 0;
- }
- strncat(filename_new, newtitle, 512);
+ std::string filename_new(filename_old);
+ i = filename_new.rfind('/');
+ if (i != filename_new.npos)
+ filename_new.erase(i + 1);
- INFOLOG("renaming recording '%s' to '%s'", filename_old, filename_new);
- r = rename(filename_old, filename_new);
- Recordings.Update();
+ filename_new += newtitle;
+
+ INFOLOG("renaming recording '%s' to '%s'", filename_old.c_str(), filename_new.c_str());
+ r = rename(filename_old.c_str(), filename_new.c_str());
- free(filename_old);
- delete[] filename_new;
+#if VDRVERSNUM >= 20301
+ Recordings->Update();
+#else
+ Recordings.Update();
+#endif
}
- m_resp->add_U32(r);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(r);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRECORDINGS_Delete() /* OPCODE 104 */
+bool cVNSIClient::processRECORDINGS_Delete(cRequestPacket &req) /* OPCODE 104 */
{
cString recName;
cRecording* recording = NULL;
- uint32_t uid = m_req->extract_U32();
- recording = cRecordingsCache::GetInstance().Lookup(uid);
+ uint32_t uid = req.extract_U32();
+ recording = cRecordingsCache::GetInstance().LookupWrite(uid);
+
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
if (recording)
{
@@ -1861,42 +2220,50 @@ bool cVNSIClient::processRECORDINGS_Delete() /* OPCODE 104 */
if (recording->Delete())
{
// Copy svdrdeveldevelp's way of doing this, see if it works
+#if VDRVERSNUM >= 20301
+ LOCK_RECORDINGS_WRITE;
+ Recordings->DelByName(recording->FileName());
+#else
Recordings.DelByName(recording->FileName());
+#endif
INFOLOG("Recording \"%s\" deleted", recording->FileName());
- m_resp->add_U32(VNSI_RET_OK);
+ resp.add_U32(VNSI_RET_OK);
}
else
{
ERRORLOG("Error while deleting recording!");
- m_resp->add_U32(VNSI_RET_ERROR);
+ resp.add_U32(VNSI_RET_ERROR);
}
}
else
{
ERRORLOG("Recording \"%s\" is in use by timer %d", recording->Name(), rc->Timer()->Index() + 1);
- m_resp->add_U32(VNSI_RET_DATALOCKED);
+ resp.add_U32(VNSI_RET_DATALOCKED);
}
}
else
{
ERRORLOG("Error in recording name \"%s\"", (const char*)recName);
- m_resp->add_U32(VNSI_RET_DATAUNKNOWN);
+ resp.add_U32(VNSI_RET_DATAUNKNOWN);
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRECORDINGS_GetEdl() /* OPCODE 105 */
+bool cVNSIClient::processRECORDINGS_GetEdl(cRequestPacket &req) /* OPCODE 105 */
{
cString recName;
- cRecording* recording = NULL;
+ const cRecording* recording = NULL;
- uint32_t uid = m_req->extract_U32();
+ uint32_t uid = req.extract_U32();
recording = cRecordingsCache::GetInstance().Lookup(uid);
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
if (recording)
{
cMarks marks;
@@ -1907,15 +2274,15 @@ bool cVNSIClient::processRECORDINGS_GetEdl() /* OPCODE 105 */
double fps = recording->FramesPerSecond();
while((mark = marks.GetNextBegin(mark)) != NULL)
{
- m_resp->add_U64(mark->Position() *1000 / fps);
- m_resp->add_U64(mark->Position() *1000 / fps);
- m_resp->add_S32(2);
+ resp.add_U64(mark->Position() *1000 / fps);
+ resp.add_U64(mark->Position() *1000 / fps);
+ resp.add_S32(2);
}
#endif
}
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
@@ -1923,16 +2290,21 @@ bool cVNSIClient::processRECORDINGS_GetEdl() /* OPCODE 105 */
/** OPCODE 120 - 139: VNSI network functions for epg access and manipulating */
-bool cVNSIClient::processEPG_GetForChannel() /* OPCODE 120 */
+bool cVNSIClient::processEPG_GetForChannel(cRequestPacket &req) /* OPCODE 120 */
{
uint32_t channelUID = 0;
- channelUID = m_req->extract_U32();
+ channelUID = req.extract_U32();
- uint32_t startTime = m_req->extract_U32();
- uint32_t duration = m_req->extract_U32();
+ uint32_t startTime = req.extract_U32();
+ uint32_t duration = req.extract_U32();
+#if VDRVERSNUM >= 20301
+ LOCK_CHANNELS_READ;
+ LOCK_SCHEDULES_READ;
+#else
Channels.Lock(false);
+#endif
const cChannel* channel = NULL;
@@ -1942,37 +2314,50 @@ bool cVNSIClient::processEPG_GetForChannel() /* OPCODE 120 */
DEBUGLOG("get schedule called for channel '%s'", (const char*)channel->GetChannelID().ToString());
}
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
if (!channel)
{
- m_resp->add_U32(0);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.add_U32(0);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+#if VDRVERSNUM < 20301
Channels.Unlock();
+#endif
ERRORLOG("written 0 because channel = NULL");
return true;
}
+#if VDRVERSNUM < 20301
cSchedulesLock MutexLock;
const cSchedules *Schedules = cSchedules::Schedules(MutexLock);
if (!Schedules)
{
- m_resp->add_U32(0);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.add_U32(0);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
Channels.Unlock();
DEBUGLOG("written 0 because Schedule!s! = NULL");
return true;
}
+#endif
+#if VDRVERSNUM >= 20301
const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
+#else
+ const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
+#endif
if (!Schedule)
{
- m_resp->add_U32(0);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.add_U32(0);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
+#if VDRVERSNUM < 20301
Channels.Unlock();
+#endif
DEBUGLOG("written 0 because Schedule = NULL");
return true;
@@ -2009,48 +2394,58 @@ bool cVNSIClient::processEPG_GetForChannel() /* OPCODE 120 */
#endif
//in the past filter
- if ((thisEventTime + thisEventDuration) < (uint32_t)time(NULL)) continue;
+ if ((thisEventTime + thisEventDuration) < (uint32_t)time(NULL))
+ continue;
//start time filter
- if ((thisEventTime + thisEventDuration) <= startTime) continue;
+ if ((thisEventTime + thisEventDuration) <= startTime)
+ continue;
//duration filter
- if (duration != 0 && thisEventTime >= (startTime + duration)) continue;
+ if (duration != 0 && thisEventTime >= (startTime + duration))
+ continue;
- if (!thisEventTitle) thisEventTitle = "";
- if (!thisEventSubTitle) thisEventSubTitle = "";
- if (!thisEventDescription) thisEventDescription = "";
+ if (!thisEventTitle)
+ thisEventTitle = "";
+ if (!thisEventSubTitle)
+ thisEventSubTitle = "";
+ if (!thisEventDescription)
+ thisEventDescription = "";
- m_resp->add_U32(thisEventID);
- m_resp->add_U32(thisEventTime);
- m_resp->add_U32(thisEventDuration);
- m_resp->add_U32(thisEventContent);
- m_resp->add_U32(thisEventRating);
+ resp.add_U32(thisEventID);
+ resp.add_U32(thisEventTime);
+ resp.add_U32(thisEventDuration);
+ resp.add_U32(thisEventContent);
+ resp.add_U32(thisEventRating);
- m_resp->add_String(m_toUTF8.Convert(thisEventTitle));
- m_resp->add_String(m_toUTF8.Convert(thisEventSubTitle));
- m_resp->add_String(m_toUTF8.Convert(thisEventDescription));
+ resp.add_String(m_toUTF8.Convert(thisEventTitle));
+ resp.add_String(m_toUTF8.Convert(thisEventSubTitle));
+ resp.add_String(m_toUTF8.Convert(thisEventDescription));
atLeastOneEvent = true;
}
+#if VDRVERSNUM < 20301
Channels.Unlock();
+#endif
+
DEBUGLOG("Got all event data");
if (!atLeastOneEvent)
{
- m_resp->add_U32(0);
+ resp.add_U32(0);
DEBUGLOG("Written 0 because no data");
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
- cEvent *lastEvent = Schedule->Events()->Last();
+ const cEvent *lastEvent = Schedule->Events()->Last();
if (lastEvent)
{
- m_epgUpdate[channelUID].lastEvent = lastEvent->StartTime();
- m_epgUpdate[channelUID].attempts = 0;
+ auto &u = m_epgUpdate[channelUID];
+ u.lastEvent = lastEvent->StartTime();
+ u.attempts = 0;
}
DEBUGLOG("written schedules packet");
@@ -2063,19 +2458,21 @@ bool cVNSIClient::processEPG_GetForChannel() /* OPCODE 120 */
* VNSI network functions for channel scanning
*/
-bool cVNSIClient::processSCAN_ScanSupported() /* OPCODE 140 */
+bool cVNSIClient::processSCAN_ScanSupported(cRequestPacket &req) /* OPCODE 140 */
{
uint32_t retValue = VNSI_RET_NOTSUPPORTED;
if (!m_inhibidDataUpdates && m_ChannelScanControl.IsSupported())
retValue = VNSI_RET_OK;
- m_resp->add_U32(retValue);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(retValue);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processSCAN_GetSupportedTypes()
+bool cVNSIClient::processSCAN_GetSupportedTypes(cRequestPacket &req)
{
uint32_t retValue = 0;
if (m_ChannelScanControl.IsSupported())
@@ -2088,241 +2485,221 @@ bool cVNSIClient::processSCAN_GetSupportedTypes()
retValue |= m_ChannelScanControl.SupportsATSC() ? VNSI_SCAN_SUPPORT_ATSC : 0;
}
- m_resp->add_U32(retValue);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(retValue);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processSCAN_GetCountries() /* OPCODE 141 */
+bool cVNSIClient::processSCAN_GetCountries(cRequestPacket &req) /* OPCODE 141 */
{
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
scannerEntryList list;
if (m_ChannelScanControl.GetCountries(list))
{
- m_resp->add_U32(VNSI_RET_OK);
- for (scannerEntryList::const_iterator it = list.begin(); it != list.end(); ++it)
+ resp.add_U32(VNSI_RET_OK);
+ for (const auto &i : list)
{
- m_resp->add_U32(it->index);
- m_resp->add_String(it->name);
- m_resp->add_String(it->longName);
+ resp.add_U32(i.index);
+ resp.add_String(i.name);
+ resp.add_String(i.longName);
}
}
else
{
- m_resp->add_U32(VNSI_RET_NOTSUPPORTED);
+ resp.add_U32(VNSI_RET_NOTSUPPORTED);
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processSCAN_GetSatellites() /* OPCODE 142 */
+bool cVNSIClient::processSCAN_GetSatellites(cRequestPacket &req) /* OPCODE 142 */
{
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
scannerEntryList list;
if (m_ChannelScanControl.GetSatellites(list))
{
- m_resp->add_U32(VNSI_RET_OK);
- for (scannerEntryList::const_iterator it = list.begin(); it != list.end(); ++it)
+ resp.add_U32(VNSI_RET_OK);
+ for (const auto &i : list)
{
- m_resp->add_U32(it->index);
- m_resp->add_String(it->name);
- m_resp->add_String(it->longName);
+ resp.add_U32(i.index);
+ resp.add_String(i.name);
+ resp.add_String(i.longName);
}
}
else
{
- m_resp->add_U32(VNSI_RET_NOTSUPPORTED);
+ resp.add_U32(VNSI_RET_NOTSUPPORTED);
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processSCAN_Start() /* OPCODE 143 */
+bool cVNSIClient::processSCAN_Start(cRequestPacket &req) /* OPCODE 143 */
{
sScanServiceData svc;
- svc.type = (int)m_req->extract_U32();
- svc.scan_tv = (bool)m_req->extract_U8();
- svc.scan_radio = (bool)m_req->extract_U8();
- svc.scan_fta = (bool)m_req->extract_U8();
- svc.scan_scrambled = (bool)m_req->extract_U8();
- svc.scan_hd = (bool)m_req->extract_U8();
- svc.CountryIndex = (int)m_req->extract_U32();
- svc.DVBC_Inversion = (int)m_req->extract_U32();
- svc.DVBC_Symbolrate = (int)m_req->extract_U32();
- svc.DVBC_QAM = (int)m_req->extract_U32();
- svc.DVBT_Inversion = (int)m_req->extract_U32();
- svc.SatIndex = (int)m_req->extract_U32();
- svc.ATSC_Type = (int)m_req->extract_U32();
+ svc.type = (int)req.extract_U32();
+ svc.scan_tv = (bool)req.extract_U8();
+ svc.scan_radio = (bool)req.extract_U8();
+ svc.scan_fta = (bool)req.extract_U8();
+ svc.scan_scrambled = (bool)req.extract_U8();
+ svc.scan_hd = (bool)req.extract_U8();
+ svc.CountryIndex = (int)req.extract_U32();
+ svc.DVBC_Inversion = (int)req.extract_U32();
+ svc.DVBC_Symbolrate = (int)req.extract_U32();
+ svc.DVBC_QAM = (int)req.extract_U32();
+ svc.DVBT_Inversion = (int)req.extract_U32();
+ svc.SatIndex = (int)req.extract_U32();
+ svc.ATSC_Type = (int)req.extract_U32();
+
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
if (!m_inhibidDataUpdates && m_ChannelScanControl.IsSupported())
{
if (m_ChannelScanControl.StartScan(svc))
{
- m_resp->add_U32(VNSI_RET_OK);
+ resp.add_U32(VNSI_RET_OK);
m_inhibidDataUpdates = true;
}
else
- m_resp->add_U32(VNSI_RET_ERROR);
+ resp.add_U32(VNSI_RET_ERROR);
}
else
- m_resp->add_U32(VNSI_RET_NOTSUPPORTED);
+ resp.add_U32(VNSI_RET_NOTSUPPORTED);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processSCAN_Stop() /* OPCODE 144 */
+bool cVNSIClient::processSCAN_Stop(cRequestPacket &req) /* OPCODE 144 */
{
m_inhibidDataUpdates = false;
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
if (m_ChannelScanControl.IsSupported())
{
if (m_ChannelScanControl.StopScan())
- m_resp->add_U32(VNSI_RET_OK);
+ resp.add_U32(VNSI_RET_OK);
else
- m_resp->add_U32(VNSI_RET_ERROR);
+ resp.add_U32(VNSI_RET_ERROR);
}
else
- m_resp->add_U32(VNSI_RET_NOTSUPPORTED);
+ resp.add_U32(VNSI_RET_NOTSUPPORTED);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
void cVNSIClient::processSCAN_SetPercentage(int percent)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initScan(VNSI_SCANNER_PERCENTAGE))
- {
- delete resp;
- return;
- }
- resp->add_U32(percent);
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initScan(VNSI_SCANNER_PERCENTAGE);
+ resp.add_U32(percent);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
void cVNSIClient::processSCAN_SetSignalStrength(int strength, bool locked)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initScan(VNSI_SCANNER_SIGNAL))
- {
- delete resp;
- return;
- }
- resp->add_U32(strength);
- resp->add_U32(locked);
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initScan(VNSI_SCANNER_SIGNAL);
+ resp.add_U32(strength);
+ resp.add_U32(locked);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
void cVNSIClient::processSCAN_SetDeviceInfo(const char *Info)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initScan(VNSI_SCANNER_DEVICE))
- {
- delete resp;
- return;
- }
- resp->add_String(Info);
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initScan(VNSI_SCANNER_DEVICE);
+ resp.add_String(Info);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
void cVNSIClient::processSCAN_SetTransponder(const char *Info)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initScan(VNSI_SCANNER_TRANSPONDER))
- {
- delete resp;
- return;
- }
- resp->add_String(Info);
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initScan(VNSI_SCANNER_TRANSPONDER);
+ resp.add_String(Info);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
void cVNSIClient::processSCAN_NewChannel(const char *Name, bool isRadio, bool isEncrypted, bool isHD)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initScan(VNSI_SCANNER_NEWCHANNEL))
- {
- delete resp;
- return;
- }
- resp->add_U32(isRadio);
- resp->add_U32(isEncrypted);
- resp->add_U32(isHD);
- resp->add_String(Name);
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initScan(VNSI_SCANNER_NEWCHANNEL);
+ resp.add_U32(isRadio);
+ resp.add_U32(isEncrypted);
+ resp.add_U32(isHD);
+ resp.add_String(Name);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
void cVNSIClient::processSCAN_IsFinished()
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initScan(VNSI_SCANNER_FINISHED))
- {
- delete resp;
- return;
- }
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initScan(VNSI_SCANNER_FINISHED);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
void cVNSIClient::processSCAN_SetStatus(int status)
{
- cResponsePacket *resp = new cResponsePacket();
- if (!resp->initScan(VNSI_SCANNER_STATUS))
- {
- delete resp;
- return;
- }
- resp->add_U32(status);
- resp->finalise();
- m_socket.write(resp->getPtr(), resp->getLen());
- delete resp;
+ cResponsePacket resp;
+ resp.initScan(VNSI_SCANNER_STATUS);
+ resp.add_U32(status);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
}
-bool cVNSIClient::processOSD_Connect() /* OPCODE 160 */
+bool cVNSIClient::processOSD_Connect(cRequestPacket &req) /* OPCODE 160 */
{
+ delete m_Osd;
m_Osd = new cVnsiOsdProvider(&m_socket);
int osdWidth, osdHeight;
double aspect;
cDevice::PrimaryDevice()->GetOsdSize(osdWidth, osdHeight, aspect);
- m_resp->add_U32(osdWidth);
- m_resp->add_U32(osdHeight);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(osdWidth);
+ resp.add_U32(osdHeight);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
bool cVNSIClient::processOSD_Disconnect() /* OPCODE 161 */
{
- if (m_Osd)
- {
- delete m_Osd;
- m_Osd = NULL;
- }
+ delete m_Osd;
+ m_Osd = NULL;
return true;
}
-bool cVNSIClient::processOSD_Hitkey() /* OPCODE 162 */
+bool cVNSIClient::processOSD_Hitkey(cRequestPacket &req) /* OPCODE 162 */
{
if (m_Osd)
{
- unsigned int key = m_req->extract_U32();
+ unsigned int key = req.extract_U32();
cVnsiOsdProvider::SendKey(key);
}
return true;
@@ -2330,29 +2707,45 @@ bool cVNSIClient::processOSD_Hitkey() /* OPCODE 162 */
/** OPCODE 180 - 189: VNSI network functions for deleted recording access */
-bool cVNSIClient::processRECORDINGS_DELETED_Supported() /* OPCODE 180 */
+bool cVNSIClient::processRECORDINGS_DELETED_Supported(cRequestPacket &req) /* OPCODE 180 */
{
- m_resp->add_U32(VNSI_RET_OK);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(VNSI_RET_OK);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRECORDINGS_DELETED_GetCount() /* OPCODE 181 */
+bool cVNSIClient::processRECORDINGS_DELETED_GetCount(cRequestPacket &req) /* OPCODE 181 */
{
- DeletedRecordings.Load();
- m_resp->add_U32(DeletedRecordings.Count());
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+#if VDRVERSNUM >= 20301
+ LOCK_DELETEDRECORDINGS_READ;
+ resp.add_U32(DeletedRecordings->Count());
+#else
+ resp.add_U32(DeletedRecordings.Count());
+#endif
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRECORDINGS_DELETED_GetList() /* OPCODE 182 */
+bool cVNSIClient::processRECORDINGS_DELETED_GetList(cRequestPacket &req) /* OPCODE 182 */
{
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
cMutexLock lock(&m_timerLock);
- cThreadLock RecordingsLock(&Recordings);
+#if VDRVERSNUM >= 20301
+ LOCK_DELETEDRECORDINGS_READ;
+ for (const cRecording *recording = DeletedRecordings->First(); recording; recording = DeletedRecordings->Next(recording))
+#else
+ cThreadLock RecordingsLock(&Recordings);
for (cRecording *recording = DeletedRecordings.First(); recording; recording = DeletedRecordings.Next(recording))
+#endif
{
#if APIVERSNUM >= 10705
const cEvent *event = recording->Info()->GetEvent();
@@ -2387,27 +2780,27 @@ bool cVNSIClient::processRECORDINGS_DELETED_GetList() /* OPCODE 182 */
DEBUGLOG("GRI: RC: recordingStart=%lu recordingDuration=%i", recordingStart, recordingDuration);
// recording_time
- m_resp->add_U32(recordingStart);
+ resp.add_U32(recordingStart);
// duration
- m_resp->add_U32(recordingDuration);
+ resp.add_U32(recordingDuration);
// priority
#if APIVERSNUM >= 10727
- m_resp->add_U32(recording->Priority());
+ resp.add_U32(recording->Priority());
#else
- m_resp->add_U32(recording->priority);
+ resp.add_U32(recording->priority);
#endif
// lifetime
#if APIVERSNUM >= 10727
- m_resp->add_U32(recording->Lifetime());
+ resp.add_U32(recording->Lifetime());
#else
- m_resp->add_U32(recording->lifetime);
+ resp.add_U32(recording->lifetime);
#endif
// channel_name
- m_resp->add_String(recording->Info()->ChannelName() ? m_toUTF8.Convert(recording->Info()->ChannelName()) : "");
+ resp.add_String(recording->Info()->ChannelName() ? m_toUTF8.Convert(recording->Info()->ChannelName()) : "");
char* fullname = strdup(recording->Name());
char* recname = strrchr(fullname, FOLDERDELIMCHAR);
@@ -2423,19 +2816,19 @@ bool cVNSIClient::processRECORDINGS_DELETED_GetList() /* OPCODE 182 */
}
// title
- m_resp->add_String(m_toUTF8.Convert(recname));
+ resp.add_String(m_toUTF8.Convert(recname));
// subtitle
if (!isempty(recording->Info()->ShortText()))
- m_resp->add_String(m_toUTF8.Convert(recording->Info()->ShortText()));
+ resp.add_String(m_toUTF8.Convert(recording->Info()->ShortText()));
else
- m_resp->add_String("");
+ resp.add_String("");
// description
if (!isempty(recording->Info()->Description()))
- m_resp->add_String(m_toUTF8.Convert(recording->Info()->Description()));
+ resp.add_String(m_toUTF8.Convert(recording->Info()->Description()));
else
- m_resp->add_String("");
+ resp.add_String("");
// directory
if(directory != NULL) {
@@ -2448,22 +2841,25 @@ bool cVNSIClient::processRECORDINGS_DELETED_GetList() /* OPCODE 182 */
while(*directory == '/') directory++;
}
- m_resp->add_String((isempty(directory)) ? "" : m_toUTF8.Convert(directory));
+ resp.add_String((isempty(directory)) ? "" : m_toUTF8.Convert(directory));
// filename / uid of recording
uint32_t uid = cRecordingsCache::GetInstance().Register(recording, false);
- m_resp->add_U32(uid);
+ resp.add_U32(uid);
free(fullname);
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRECORDINGS_DELETED_Delete() /* OPCODE 183 */
+bool cVNSIClient::processRECORDINGS_DELETED_Delete(cRequestPacket &req) /* OPCODE 183 */
{
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+
cString recName;
cRecording* recording = NULL;
@@ -2474,11 +2870,15 @@ bool cVNSIClient::processRECORDINGS_DELETED_Delete() /* OPCODE 183 */
#endif
if (LockFile.Lock())
{
- uint32_t uid = m_req->extract_U32();
+ uint32_t uid = req.extract_U32();
+#if VDRVERSNUM >= 20301
+ LOCK_DELETEDRECORDINGS_WRITE;
+ for (recording = DeletedRecordings->First(); recording; recording = DeletedRecordings->Next(recording))
+#else
cThreadLock DeletedRecordingsLock(&DeletedRecordings);
-
for (recording = DeletedRecordings.First(); recording; recording = DeletedRecordings.Next(recording))
+#endif
{
if (uid == CreateStringHash(recording->FileName()))
{
@@ -2489,22 +2889,27 @@ bool cVNSIClient::processRECORDINGS_DELETED_Delete() /* OPCODE 183 */
#endif
{
ERRORLOG("Error while remove deleted recording (%s)", recording->FileName());
- m_resp->add_U32(VNSI_RET_ERROR);
+ resp.add_U32(VNSI_RET_ERROR);
}
else
{
+#if VDRVERSNUM >= 20301
+ DeletedRecordings->Del(recording);
+ DeletedRecordings->Update();
+#else
DeletedRecordings.Del(recording);
DeletedRecordings.Update();
+#endif
INFOLOG("Recording \"%s\" permanent deleted", recording->FileName());
- m_resp->add_U32(VNSI_RET_OK);
+ resp.add_U32(VNSI_RET_OK);
}
break;
}
}
}
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
@@ -2517,7 +2922,7 @@ bool cVNSIClient::Undelete(cRecording* recording)
char *ext = strrchr(NewName, '.');
if (ext && strcmp(ext, ".del") == 0)
{
- strncpy(ext, ".rec", strlen(ext));
+ strcpy(ext, ".rec");
if (!access(NewName, F_OK))
{
ERRORLOG("Recording with the same name exists (%s)", NewName);
@@ -2536,14 +2941,13 @@ bool cVNSIClient::Undelete(cRecording* recording)
ERRORLOG("Error while rename deleted recording (%s) to (%s)", recording->FileName(), NewName);
}
- cIndexFile *index = new cIndexFile(NewName, false, recording->IsPesRecording());
- int LastFrame = index->Last() - 1;
+ cIndexFile index(NewName, false, recording->IsPesRecording());
+ int LastFrame = index.Last() - 1;
if (LastFrame > 0)
{
uint16_t FileNumber = 0;
off_t FileOffset = 0;
- index->Get(LastFrame, &FileNumber, &FileOffset);
- delete index;
+ index.Get(LastFrame, &FileNumber, &FileOffset);
if (FileNumber == 0)
{
ERRORLOG("while read last filenumber (%s)", NewName);
@@ -2564,14 +2968,21 @@ bool cVNSIClient::Undelete(cRecording* recording)
}
else
{
- delete index;
ERRORLOG("accessing indexfile (%s)", NewName);
OsdStatusMessage(*cString::sprintf("%s (%s)", tr("Error while accessing indexfile"), NewName));
}
+#if VDRVERSNUM >= 20301
+ LOCK_RECORDINGS_WRITE;
+ LOCK_DELETEDRECORDINGS_WRITE;
+ DeletedRecordings->Del(recording);
+ Recordings->Update();
+ DeletedRecordings->Update();
+#else
DeletedRecordings.Del(recording);
Recordings.Update();
DeletedRecordings.Update();
+#endif
}
else
{
@@ -2584,7 +2995,7 @@ bool cVNSIClient::Undelete(cRecording* recording)
return true;
}
-bool cVNSIClient::processRECORDINGS_DELETED_Undelete() /* OPCODE 184 */
+bool cVNSIClient::processRECORDINGS_DELETED_Undelete(cRequestPacket &req) /* OPCODE 184 */
{
int ret = VNSI_RET_DATAUNKNOWN;
@@ -2595,11 +3006,15 @@ bool cVNSIClient::processRECORDINGS_DELETED_Undelete() /* OPCODE 184 */
#endif
if (LockFile.Lock())
{
- uint32_t uid = m_req->extract_U32();
+ uint32_t uid = req.extract_U32();
+#if VDRVERSNUM >= 20301
+ LOCK_DELETEDRECORDINGS_WRITE;
+ for (cRecording* recording = DeletedRecordings->First(); recording; recording = DeletedRecordings->Next(recording))
+#else
cThreadLock DeletedRecordingsLock(&DeletedRecordings);
-
for (cRecording* recording = DeletedRecordings.First(); recording; recording = DeletedRecordings.Next(recording))
+#endif
{
if (uid == CreateStringHash(recording->FileName()))
{
@@ -2615,13 +3030,15 @@ bool cVNSIClient::processRECORDINGS_DELETED_Undelete() /* OPCODE 184 */
}
}
- m_resp->add_U32(ret);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(ret);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
-bool cVNSIClient::processRECORDINGS_DELETED_DeleteAll() /* OPCODE 185 */
+bool cVNSIClient::processRECORDINGS_DELETED_DeleteAll(cRequestPacket &req) /* OPCODE 185 */
{
int ret = VNSI_RET_OK;
@@ -2633,11 +3050,19 @@ bool cVNSIClient::processRECORDINGS_DELETED_DeleteAll() /* OPCODE 185 */
if (LockFile.Lock())
{
+#if VDRVERSNUM >= 20301
+ LOCK_DELETEDRECORDINGS_WRITE;
+ for (cRecording *recording = DeletedRecordings->First(); recording; )
+#else
cThreadLock DeletedRecordingsLock(&DeletedRecordings);
-
for (cRecording *recording = DeletedRecordings.First(); recording; )
+#endif
{
+#if VDRVERSNUM >= 20301
+ cRecording *next = DeletedRecordings->Next(recording);
+#else
cRecording *next = DeletedRecordings.Next(recording);
+#endif
#if VDRVERSNUM >= 20102
if (!cVideoDirectory::RemoveVideoFile(recording->FileName()))
#else
@@ -2652,19 +3077,26 @@ bool cVNSIClient::processRECORDINGS_DELETED_DeleteAll() /* OPCODE 185 */
INFOLOG("Recording \"%s\" permanent deleted", recording->FileName());
recording = next;
}
+#if VDRVERSNUM >= 20301
+ DeletedRecordings->Clear();
+ DeletedRecordings->Update();
+#else
DeletedRecordings.Clear();
DeletedRecordings.Update();
+#endif
}
- m_resp->add_U32(ret);
- m_resp->finalise();
- m_socket.write(m_resp->getPtr(), m_resp->getLen());
+ cResponsePacket resp;
+ resp.init(req.getRequestID());
+ resp.add_U32(ret);
+ resp.finalise();
+ m_socket.write(resp.getPtr(), resp.getLen());
return true;
}
// part of this method is taken from XVDR
-cString cVNSIClient::CreatePiconRef(cChannel* channel)
+cString cVNSIClient::CreatePiconRef(const cChannel* channel)
{
int hash = 0;
diff --git a/vnsiclient.h b/vnsiclient.h
index aadcffa..92b7c48 100644
--- a/vnsiclient.h
+++ b/vnsiclient.h
@@ -46,57 +46,59 @@ class cResponsePacket;
class cRecPlayer;
class cCmdControl;
class cVnsiOsdProvider;
+class CVNSITimers;
class cVNSIClient : public cThread
, public cStatus
{
-private:
-
- unsigned int m_Id;
+ const unsigned int m_Id;
cxSocket m_socket;
- bool m_loggedIn;
- bool m_StatusInterfaceEnabled;
- cLiveStreamer *m_Streamer;
- bool m_isStreaming;
- bool m_bSupportRDS;
- cString m_ClientAddress;
- cRecPlayer *m_RecPlayer;
- cRequestPacket *m_req;
- cResponsePacket *m_resp;
+ bool m_loggedIn = false;
+ bool m_StatusInterfaceEnabled = false;
+ cLiveStreamer *m_Streamer = nullptr;
+ bool m_isStreaming = false;
+ bool m_bSupportRDS = false;
+ const cString m_ClientAddress;
+ cRecPlayer *m_RecPlayer = nullptr;
cCharSetConv m_toUTF8;
uint32_t m_protocolVersion;
cMutex m_msgLock;
static cMutex m_timerLock;
- cVnsiOsdProvider *m_Osd;
+ cVnsiOsdProvider *m_Osd = nullptr;
CScanControl m_ChannelScanControl;
static bool m_inhibidDataUpdates;
typedef struct
{
- int attempts;
- time_t lastEvent;
+ int attempts = 0;
+ time_t lastEvent = 0;
+ time_t lastTrigger = 0;
} sEpgUpdate;
std::map<int, sEpgUpdate> m_epgUpdate;
+ CVNSITimers &m_vnsiTimers;
protected:
- bool processRequest(cRequestPacket* req);
+ bool processRequest(cRequestPacket &req);
- virtual void Action(void);
-
- virtual void TimerChange(const cTimer *Timer, eTimerChange Change);
- virtual void Recording(const cDevice *Device, const char *Name, const char *FileName, bool On);
- virtual void OsdStatusMessage(const char *Message);
- virtual void ChannelChange(const cChannel *Channel);
+ virtual void Action(void) override;
+ virtual void Recording(const cDevice *Device, const char *Name, const char *FileName, bool On) override;
+ virtual void OsdStatusMessage(const char *Message) override;
+#if VDRVERSNUM >= 20104
+ virtual void ChannelChange(const cChannel *Channel) override;
+#endif
public:
- cVNSIClient(int fd, unsigned int id, const char *ClientAdr);
+ cVNSIClient(int fd, unsigned int id, const char *ClientAdr, CVNSITimers &timers);
virtual ~cVNSIClient();
+ cVNSIClient(const cVNSIClient &) = delete;
+ cVNSIClient &operator=(const cVNSIClient &) = delete;
+
void ChannelsChange();
void RecordingsChange();
- void TimerChange();
- void EpgChange();
+ void SignalTimerChange();
+ bool EpgChange();
static bool InhibidDataUpdates() { return m_inhibidDataUpdates; }
unsigned int GetID() { return m_Id; }
@@ -105,7 +107,7 @@ protected:
void SetLoggedIn(bool yesNo) { m_loggedIn = yesNo; }
void SetStatusInterface(bool yesNo) { m_StatusInterfaceEnabled = yesNo; }
- bool StartChannelStreaming(const cChannel *channel, int32_t priority, uint8_t timeshift, uint32_t timeout);
+ bool StartChannelStreaming(cResponsePacket &resp, const cChannel *channel, int32_t priority, uint8_t timeshift, uint32_t timeout);
void StopChannelStreaming();
private:
@@ -118,76 +120,77 @@ private:
std::map<std::string, ChannelGroup> m_channelgroups[2];
- bool process_Login();
- bool process_GetTime();
- bool process_EnableStatusInterface();
- bool process_Ping();
- bool process_GetSetup();
- bool process_StoreSetup();
-
- bool processChannelStream_Open();
- bool processChannelStream_Close();
- bool processChannelStream_Seek();
-
- bool processRecStream_Open();
- bool processRecStream_Close();
- bool processRecStream_GetBlock();
- bool processRecStream_PositionFromFrameNumber();
- bool processRecStream_FrameNumberFromPosition();
- bool processRecStream_GetIFrame();
- bool processRecStream_GetLength();
-
- bool processCHANNELS_GroupsCount();
- bool processCHANNELS_ChannelsCount();
- bool processCHANNELS_GroupList();
- bool processCHANNELS_GetChannels();
- bool processCHANNELS_GetGroupMembers();
- bool processCHANNELS_GetCaids();
- bool processCHANNELS_GetWhitelist();
- bool processCHANNELS_GetBlacklist();
- bool processCHANNELS_SetWhitelist();
- bool processCHANNELS_SetBlacklist();
+ bool process_Login(cRequestPacket &r);
+ bool process_GetTime(cRequestPacket &r);
+ bool process_EnableStatusInterface(cRequestPacket &r);
+ bool process_Ping(cRequestPacket &r);
+ bool process_GetSetup(cRequestPacket &r);
+ bool process_StoreSetup(cRequestPacket &r);
+
+ bool processChannelStream_Open(cRequestPacket &r);
+ bool processChannelStream_Close(cRequestPacket &req);
+ bool processChannelStream_Seek(cRequestPacket &r);
+
+ bool processRecStream_Open(cRequestPacket &r);
+ bool processRecStream_Close(cRequestPacket &r);
+ bool processRecStream_GetBlock(cRequestPacket &r);
+ bool processRecStream_PositionFromFrameNumber(cRequestPacket &r);
+ bool processRecStream_FrameNumberFromPosition(cRequestPacket &r);
+ bool processRecStream_GetIFrame(cRequestPacket &r);
+ bool processRecStream_GetLength(cRequestPacket &r);
+
+ bool processCHANNELS_GroupsCount(cRequestPacket &r);
+ bool processCHANNELS_ChannelsCount(cRequestPacket &r);
+ bool processCHANNELS_GroupList(cRequestPacket &r);
+ bool processCHANNELS_GetChannels(cRequestPacket &r);
+ bool processCHANNELS_GetGroupMembers(cRequestPacket &r);
+ bool processCHANNELS_GetCaids(cRequestPacket &r);
+ bool processCHANNELS_GetWhitelist(cRequestPacket &r);
+ bool processCHANNELS_GetBlacklist(cRequestPacket &r);
+ bool processCHANNELS_SetWhitelist(cRequestPacket &r);
+ bool processCHANNELS_SetBlacklist(cRequestPacket &r);
void CreateChannelGroups(bool automatic);
- bool processTIMER_GetCount();
- bool processTIMER_Get();
- bool processTIMER_GetList();
- bool processTIMER_Add();
- bool processTIMER_Delete();
- bool processTIMER_Update();
-
- bool processRECORDINGS_GetDiskSpace();
- bool processRECORDINGS_GetCount();
- bool processRECORDINGS_GetList();
- bool processRECORDINGS_GetInfo();
- bool processRECORDINGS_Rename();
- bool processRECORDINGS_Delete();
- bool processRECORDINGS_Move();
- bool processRECORDINGS_GetEdl();
- bool processRECORDINGS_DELETED_Supported();
- bool processRECORDINGS_DELETED_GetCount();
- bool processRECORDINGS_DELETED_GetList();
- bool processRECORDINGS_DELETED_Delete();
- bool processRECORDINGS_DELETED_Undelete();
- bool processRECORDINGS_DELETED_DeleteAll();
-
- bool processEPG_GetForChannel();
-
- bool processSCAN_ScanSupported();
- bool processSCAN_GetSupportedTypes();
- bool processSCAN_GetCountries();
- bool processSCAN_GetSatellites();
- bool processSCAN_Start();
- bool processSCAN_Stop();
+ bool processTIMER_GetCount(cRequestPacket &r);
+ bool processTIMER_Get(cRequestPacket &r);
+ bool processTIMER_GetList(cRequestPacket &r);
+ bool processTIMER_Add(cRequestPacket &r);
+ bool processTIMER_Delete(cRequestPacket &r);
+ bool processTIMER_Update(cRequestPacket &r);
+ bool processTIMER_GetTypes(cRequestPacket &r);
+
+ bool processRECORDINGS_GetDiskSpace(cRequestPacket &r);
+ bool processRECORDINGS_GetCount(cRequestPacket &r);
+ bool processRECORDINGS_GetList(cRequestPacket &r);
+ bool processRECORDINGS_GetInfo(cRequestPacket &r);
+ bool processRECORDINGS_Rename(cRequestPacket &r);
+ bool processRECORDINGS_Delete(cRequestPacket &r);
+ bool processRECORDINGS_Move(cRequestPacket &r);
+ bool processRECORDINGS_GetEdl(cRequestPacket &r);
+ bool processRECORDINGS_DELETED_Supported(cRequestPacket &r);
+ bool processRECORDINGS_DELETED_GetCount(cRequestPacket &r);
+ bool processRECORDINGS_DELETED_GetList(cRequestPacket &r);
+ bool processRECORDINGS_DELETED_Delete(cRequestPacket &r);
+ bool processRECORDINGS_DELETED_Undelete(cRequestPacket &r);
+ bool processRECORDINGS_DELETED_DeleteAll(cRequestPacket &r);
+
+ bool processEPG_GetForChannel(cRequestPacket &r);
+
+ bool processSCAN_ScanSupported(cRequestPacket &r);
+ bool processSCAN_GetSupportedTypes(cRequestPacket &r);
+ bool processSCAN_GetCountries(cRequestPacket &r);
+ bool processSCAN_GetSatellites(cRequestPacket &r);
+ bool processSCAN_Start(cRequestPacket &r);
+ bool processSCAN_Stop(cRequestPacket &r);
bool Undelete(cRecording* recording);
- bool processOSD_Connect();
+ bool processOSD_Connect(cRequestPacket &req);
bool processOSD_Disconnect();
- bool processOSD_Hitkey();
+ bool processOSD_Hitkey(cRequestPacket &req);
- cString CreatePiconRef(cChannel* channel);
+ cString CreatePiconRef(const cChannel* channel);
private:
/** Static callback functions to interact with wirbelscan plugin over
diff --git a/vnsicommand.h b/vnsicommand.h
index e5be0bf..7a0b1aa 100644
--- a/vnsicommand.h
+++ b/vnsicommand.h
@@ -27,7 +27,7 @@
#define VNSI_COMMAND_H
/** Current VNSI Protocol Version number */
-#define VNSI_PROTOCOLVERSION 8
+#define VNSI_PROTOCOLVERSION 9
/** Start of RDS support protocol Version */
#define VNSI_RDS_PROTOCOLVERSION 8
@@ -53,6 +53,8 @@
#define CONFNAME_TIMESHIFTBUFFERDIR "TimeshiftBufferDir"
#define CONFNAME_PLAYRECORDING "PlayRecording"
#define CONFNAME_AVOIDEPGSCAN "AvoidEPGScan"
+#define CONFNAME_DISABLESCRAMBLETIMEOUT "DisableScrambleTimeout"
+#define CONFNAME_DISABLECAMBLACKLIST "DisableCamBlacklist"
/* OPCODE 1 - 19: VNSI network functions for general purpose */
#define VNSI_LOGIN 1
@@ -95,6 +97,7 @@
#define VNSI_TIMER_ADD 83
#define VNSI_TIMER_DELETE 84
#define VNSI_TIMER_UPDATE 85
+#define VNSI_TIMER_GETTYPES 86
/* OPCODE 100 - 119: VNSI network functions for recording access */
#define VNSI_RECORDINGS_DISKSIZE 100
@@ -171,6 +174,13 @@
#define VNSI_SCAN_SUPPORT_ANALOG_RADIO 0x10
#define VNSI_SCAN_SUPPORT_ATSC 0x20
+/** Timer */
+#define VNSI_TIMER_TYPE_MAN 1
+#define VNSI_TIMER_TYPE_MAN_REPEAT 2
+#define VNSI_TIMER_TYPE_EPG 3
+#define VNSI_TIMER_TYPE_VPS 4
+#define VNSI_TIMER_TYPE_EPG_SEARCH 5
+
/** Packet return codes */
#define VNSI_RET_OK 0
#define VNSI_RET_RECRUNNING 1
diff --git a/vnsiosd.c b/vnsiosd.c
index 3d6f7da..e455025 100644
--- a/vnsiosd.c
+++ b/vnsiosd.c
@@ -22,8 +22,8 @@
*
*/
-#include "config.h"
#include "vnsiosd.h"
+#include "config.h"
#include "vnsicommand.h"
#include "responsepacket.h"
#include "vnsi.h"
@@ -210,7 +210,6 @@ void cVnsiOsd::Flush(void)
// --- cVnsiOsdProvider -------------------------------------------------------
-cResponsePacket cVnsiOsdProvider::m_OsdPacket;
cxSocket *cVnsiOsdProvider::m_Socket;
cMutex cVnsiOsdProvider::m_Mutex;
bool cVnsiOsdProvider::m_RequestFull;
@@ -245,11 +244,8 @@ void cVnsiOsdProvider::SendOsdPacket(int cmd, int wnd, int color, int x0, int y0
if (!m_Socket)
return;
- if (!m_OsdPacket.initOsd(cmd, wnd, color, x0, y0, x1, y1))
- {
- ERRORLOG("OSD response packet init fail");
- return;
- }
+ cResponsePacket m_OsdPacket;
+ m_OsdPacket.initOsd(cmd, wnd, color, x0, y0, x1, y1);
m_OsdPacket.setLen(m_OsdPacket.getOSDHeaderLength() + size);
m_OsdPacket.finaliseOSD();
diff --git a/vnsiosd.h b/vnsiosd.h
index 454099d..3776612 100644
--- a/vnsiosd.h
+++ b/vnsiosd.h
@@ -23,7 +23,6 @@
*/
#include <vdr/osd.h>
-#include "responsepacket.h"
class cxSocket;
@@ -37,7 +36,6 @@ public:
static bool IsRequestFull();
static void SendKey(unsigned int key);
private:
- static cResponsePacket m_OsdPacket;
static cxSocket *m_Socket;
static cMutex m_Mutex;
static bool m_RequestFull;
diff --git a/vnsiserver.c b/vnsiserver.c
index ca565a5..3afe259 100644
--- a/vnsiserver.c
+++ b/vnsiserver.c
@@ -23,6 +23,11 @@
*
*/
+#include "vnsiserver.h"
+#include "vnsiclient.h"
+#include "vnsi.h"
+#include "channelfilter.h"
+
#include <netdb.h>
#include <poll.h>
#include <assert.h>
@@ -40,11 +45,6 @@
#include <vdr/plugin.h>
-#include "vnsi.h"
-#include "vnsiserver.h"
-#include "vnsiclient.h"
-#include "channelfilter.h"
-
unsigned int cVNSIServer::m_IdCnt = 0;
class cAllowedHosts : public cSVDRPhosts
@@ -69,7 +69,7 @@ public:
}
};
-cVNSIServer::cVNSIServer(int listenPort) : cThread("VDR VNSI Server")
+cVNSIServer::cVNSIServer(int listenPort) : cThread("VNSI Server")
{
m_ServerPort = listenPort;
@@ -82,8 +82,9 @@ cVNSIServer::cVNSIServer(int listenPort) : cThread("VDR VNSI Server")
cVNSIServer::~cVNSIServer()
{
- m_Status.Shutdown();
Cancel();
+ m_Status.Shutdown();
+ m_timers.Shutdown();
INFOLOG("VNSI Server stopped");
}
@@ -133,8 +134,7 @@ void cVNSIServer::NewClientConnected(int fd)
#endif
INFOLOG("Client with ID %d connected: %s", m_IdCnt, cxSocket::ip2txt(sin.sin_addr.s_addr, sin.sin_port, buf));
- cVNSIClient *connection = new cVNSIClient(fd, m_IdCnt, cxSocket::ip2txt(sin.sin_addr.s_addr, sin.sin_port, buf));
- m_Status.AddClient(connection);
+ m_Status.AddClient(fd, m_IdCnt, cxSocket::ip2txt(sin.sin_addr.s_addr, sin.sin_port, buf), m_timers);
m_IdCnt++;
}
@@ -155,7 +155,9 @@ void cVNSIServer::Action(void)
VNSIChannelFilter.Load();
VNSIChannelFilter.SortChannels();
- m_Status.Start();
+ m_Status.Init(&m_timers);
+ m_timers.Load();
+ m_timers.Start();
m_ServerFD = socket(AF_INET, SOCK_STREAM, 0);
if(m_ServerFD == -1)
diff --git a/vnsiserver.h b/vnsiserver.h
index 43c0865..b09338a 100644
--- a/vnsiserver.h
+++ b/vnsiserver.h
@@ -30,6 +30,7 @@
#include "config.h"
#include "status.h"
+#include "vnsitimer.h"
class cVNSIClient;
@@ -40,10 +41,11 @@ protected:
virtual void Action(void);
void NewClientConnected(int fd);
- int m_ServerPort;
- int m_ServerFD;
- cString m_AllowedHostsFile;
- cVNSIStatus m_Status;
+ int m_ServerPort;
+ int m_ServerFD;
+ cString m_AllowedHostsFile;
+ CVNSITimers m_timers;
+ cVNSIStatus m_Status;
static unsigned int m_IdCnt;
diff --git a/vnsitimer.c b/vnsitimer.c
new file mode 100644
index 0000000..cbba00f
--- /dev/null
+++ b/vnsitimer.c
@@ -0,0 +1,360 @@
+/*
+ * vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ * Copyright (C) 2005-2016 Team Kodi
+ *
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KODI; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "config.h"
+#include "hash.h"
+#include "time.h"
+#include <vdr/tools.h>
+#include <vdr/epg.h>
+#include <vdr/timers.h>
+#include <vdr/recording.h>
+#include <algorithm>
+#include <iostream>
+#include <fstream>
+#include <regex>
+#include "vnsitimer.h"
+
+CVNSITimers::CVNSITimers() : cThread("VNSITimers")
+{
+ m_doScan = false;
+ m_state = 0;
+}
+
+void CVNSITimers::Load()
+{
+ cString filename;
+ std::string line;
+ std::ifstream rfile;
+ CVNSITimer timer;
+
+ cMutexLock lock(&m_timerLock);
+
+ filename = cString::sprintf("%s/timers.vnsi", *VNSIServerConfig.ConfigDirectory);
+ rfile.open(filename);
+ m_timers.clear();
+ if (rfile.is_open())
+ {
+ while(getline(rfile,line))
+ {
+ // timer name
+ size_t pos = line.find(";");
+ if(pos == line.npos)
+ {
+ continue;
+ }
+ timer.m_name = line.substr(0, pos);
+
+ // channelUID
+ line = line.substr(pos+1);
+ pos = line.find(";");
+ if(pos == line.npos)
+ {
+ continue;
+ }
+ char *pend;
+ std::string channeluid = line.substr(0, pos);
+ timer.m_channelUID = strtol(channeluid.c_str(), &pend, 10);
+
+ const cChannel *channel = FindChannelByUID(timer.m_channelUID);
+ if (!channel)
+ {
+ continue;
+ }
+ timer.m_channelID = channel->GetChannelID();
+
+ // enabled
+ line = line.substr(pos+1);
+ pos = line.find(";");
+ if(pos == line.npos)
+ {
+ continue;
+ }
+ std::string enabled = line.substr(0, pos);
+ timer.m_enabled = strtol(enabled.c_str(), &pend, 10);
+
+ // priority
+ line = line.substr(pos+1);
+ pos = line.find(";");
+ if(pos == line.npos)
+ {
+ continue;
+ }
+ std::string priority = line.substr(0, pos);
+ timer.m_priority = strtol(priority.c_str(), &pend, 10);
+
+ // lifetime
+ line = line.substr(pos+1);
+ pos = line.find(";");
+ if(pos == line.npos)
+ {
+ continue;
+ }
+ std::string lifetime = line.substr(0, pos);
+ timer.m_lifetime = strtol(lifetime.c_str(), &pend, 10);
+
+ timer.m_search = line.substr(pos+1);
+
+ m_timers.emplace_back(std::move(timer));
+ }
+ rfile.close();
+ }
+}
+
+void CVNSITimers::Save()
+{
+ cString filename;
+ std::ofstream wfile;
+ filename = cString::sprintf("%s/timers.vnsi", *VNSIServerConfig.ConfigDirectory);
+
+ cMutexLock lock(&m_timerLock);
+
+ wfile.open(filename);
+ if(wfile.is_open())
+ {
+ for (auto &timer : m_timers)
+ {
+ wfile << timer.m_name << ';'
+ << timer.m_channelUID << ';'
+ << timer.m_enabled << ';'
+ << timer.m_priority << ';'
+ << timer.m_lifetime << ';'
+ << timer.m_search << '\n';
+ }
+ wfile.close();
+ }
+}
+
+void CVNSITimers::Add(CVNSITimer &&timer)
+{
+ const cChannel *channel = FindChannelByUID(timer.m_channelUID);
+ if (!channel)
+ return;
+
+ timer.m_channelID = channel->GetChannelID();
+
+ cMutexLock lock(&m_timerLock);
+ m_timers.emplace_back(std::move(timer));
+ m_state++;
+
+ Save();
+}
+
+void CVNSITimers::Scan()
+{
+ m_doScan = true;
+}
+
+size_t CVNSITimers::GetTimersCount()
+{
+ cMutexLock lock(&m_timerLock);
+ return m_timers.size();
+}
+
+std::vector<CVNSITimer> CVNSITimers::GetTimers()
+{
+ cMutexLock lock(&m_timerLock);
+ return m_timers;
+}
+
+bool CVNSITimers::GetTimer(int idx, CVNSITimer &timer)
+{
+ cMutexLock lock(&m_timerLock);
+ idx &= ~INDEX_MASK;
+ if (idx < 0 || idx >= (int)m_timers.size())
+ return false;
+ timer = m_timers[idx];
+ return true;
+}
+
+bool CVNSITimers::UpdateTimer(int idx, CVNSITimer &timer)
+{
+ cMutexLock lock(&m_timerLock);
+ idx &= ~INDEX_MASK;
+ if (idx < 0 || idx >= (int)m_timers.size())
+ return false;
+ m_timers[idx] = timer;
+ m_state++;
+ Save();
+ return true;
+}
+
+bool CVNSITimers::DeleteTimer(int idx)
+{
+ cMutexLock lock(&m_timerLock);
+ idx &= ~INDEX_MASK;
+ if (idx < 0 || idx >= (int)m_timers.size())
+ return false;
+ m_timers.erase(m_timers.begin()+idx);
+ m_state++;
+ Save();
+ return true;
+}
+
+bool CVNSITimers::StateChange(int &state)
+{
+ if (state != m_state)
+ {
+ state = m_state;
+ return true;
+ }
+ return false;
+}
+
+std::string CVNSITimers::Convert(std::string search)
+{
+ std::string regex;
+ size_t pos = search.find("*");
+ while (pos != search.npos)
+ {
+ regex += search.substr(0, pos);
+ regex += ".*";
+ search = search.substr(pos + 1);
+ pos = search.find("*");
+ }
+ regex += search;
+ return regex;
+}
+
+bool CVNSITimers::IsDuplicateEvent(cTimers *timers, const cEvent *event)
+{
+ for (const cTimer *timer = timers->First(); timer; timer = timers->Next(timer))
+ {
+ const cEvent *timerEvent = timer->Event();
+ if (timerEvent == nullptr)
+ continue;
+ if (timer->HasFlags(tfActive) &&
+ strcmp(timerEvent->Title(), event->Title()) == 0)
+ {
+ if (timerEvent->ShortText() != nullptr && event->ShortText() != nullptr &&
+ strcmp(timerEvent->ShortText(), event->ShortText()) == 0)
+ return true;
+
+ if (abs(difftime(timerEvent->StartTime(), event->StartTime())) < 300)
+ return true;
+ }
+ }
+ return false;
+}
+
+void CVNSITimers::Action()
+{
+#if VDRVERSNUM >= 20301
+ bool modified;
+ cStateKey timerState;
+
+ // set thread priority (nice level)
+ SetPriority(1);
+
+ while (Running())
+ {
+ if (!m_doScan)
+ {
+ usleep(1000*1000);
+ continue;
+ }
+ m_doScan = false;
+
+ std::vector<CVNSITimer> timers;
+ {
+ cMutexLock lock(&m_timerLock);
+ timers = m_timers;
+ }
+
+ cTimers *Timers = cTimers::GetTimersWrite(timerState);
+ if (!Timers)
+ continue;
+
+ Timers->SetExplicitModify();
+ modified = false;
+ cStateKey SchedulesStateKey(true);
+ const cSchedules *schedules = cSchedules::GetSchedulesRead(SchedulesStateKey);
+ if (schedules)
+ {
+ for (const cSchedule *schedule = schedules->First(); schedule; schedule = schedules->Next(schedule))
+ {
+ for (auto &searchTimer : timers)
+ {
+ if (!searchTimer.m_enabled)
+ continue;
+
+ if (!(searchTimer.m_channelID == schedule->ChannelID()))
+ continue;
+
+ for (const cEvent *event = schedule->Events()->First(); event; event = schedule->Events()->Next(event))
+ {
+ std::string title(event->Title());
+ std::smatch m;
+ std::regex e(Convert(searchTimer.m_search));
+
+ if (std::regex_search(title, m, e, std::regex_constants::match_not_null))
+ {
+ bool duplicate = false;
+ LOCK_RECORDINGS_READ;
+ for (const cRecording *recording = Recordings->First(); recording; recording = Recordings->Next(recording))
+ {
+ if (recording->Info() != nullptr)
+ {
+ if (strcmp(recording->Info()->Title(), event->Title()) == 0)
+ {
+ if (recording->Info()->ShortText() != nullptr && event->ShortText() != nullptr &&
+ strcmp(recording->Info()->ShortText(), event->ShortText()) == 0)
+ {
+ duplicate = true;
+ break;
+ }
+ }
+ }
+ if (abs(difftime(event->StartTime(), recording->Start())) < 300)
+ {
+ duplicate = true;
+ break;
+ }
+ }
+ if (duplicate)
+ continue;
+
+ if (IsDuplicateEvent(Timers, event))
+ continue;
+
+ std::unique_ptr<cTimer> newTimer(new cTimer(event));
+ Timers->Add(newTimer.release());
+ modified = true;
+ }
+ }
+ }
+ }
+ }
+ if (modified)
+ Timers->SetModified();
+ timerState.Remove(modified);
+ SchedulesStateKey.Remove(modified);
+ }
+
+#endif
+}
+
+void CVNSITimers::Shutdown()
+{
+ Cancel(5);
+ m_timers.clear();
+}
diff --git a/vnsitimer.h b/vnsitimer.h
new file mode 100644
index 0000000..b282afd
--- /dev/null
+++ b/vnsitimer.h
@@ -0,0 +1,75 @@
+/*
+ * vdr-plugin-vnsi - KODI server plugin for VDR
+ *
+ * Copyright (C) 2005-2016 Team XBMC
+ *
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with KODI; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "stdint.h"
+#include <string>
+#include <vector>
+#include <atomic>
+#include <vdr/channels.h>
+#include <vdr/thread.h>
+
+class cEvent;
+class cTimers;
+
+class CVNSITimer
+{
+public:
+ std::string m_name;
+ uint32_t m_channelUID;
+ int32_t m_enabled;
+ int32_t m_priority;
+ int32_t m_lifetime;
+ std::string m_search;
+ tChannelID m_channelID;
+};
+
+class CVNSITimers : public cThread
+{
+public:
+ CVNSITimers();
+ void Load();
+ void Save();
+ void Shutdown();
+ void Add(CVNSITimer &&timer);
+ void Scan();
+ size_t GetTimersCount();
+ bool StateChange(int &state);
+ std::vector<CVNSITimer> GetTimers();
+ bool GetTimer(int idx, CVNSITimer &timer);
+ bool UpdateTimer(int idx, CVNSITimer &timer);
+ bool DeleteTimer(int idx);
+
+ static constexpr uint32_t INDEX_MASK = 0xF0000000;
+protected:
+ virtual void Action(void) override;
+ std::string Convert(std::string search);
+ bool IsDuplicateEvent(cTimers *timers, const cEvent *event);
+
+ std::vector<CVNSITimer> m_timers;
+ std::atomic_bool m_doScan;
+ std::atomic_int m_state;
+ cMutex m_timerLock;
+};
+
--
vdr-plugin-vnsiserver packaging
More information about the pkg-multimedia-commits
mailing list