1
0
mirror of https://github.com/rofafor/vdr-plugin-satip.git synced 2023-10-10 11:37:42 +00:00

14 Commits

Author SHA1 Message Date
Rolf Ahrenberg
fbbfdfab2b Fixed the device discovery. 2014-04-24 20:04:43 +03:00
Rolf Ahrenberg
78ef582bea Tweaked the pid update mechanism. 2014-04-19 17:27:47 +03:00
Rolf Ahrenberg
6e72eba09c Increased the pid update interval to 250ms. 2014-04-15 20:04:01 +03:00
Rolf Ahrenberg
fb40846171 Bumped up the version number. 2014-04-12 23:07:27 +03:00
Rolf Ahrenberg
b19be5b5c5 Reformatted the channel frequency value. 2014-04-12 23:02:26 +03:00
Rolf Ahrenberg
1a304e9dc2 Improved debug messages. 2014-04-12 16:57:28 +03:00
Rolf Ahrenberg
5ff54d27a3 Removed unnecessary PLAY commands and header callbacks. 2014-04-12 16:45:29 +03:00
Rolf Ahrenberg
276370afbb Added Spanish translation (Thanks to Gabriel Bonich). 2014-04-11 13:22:34 +03:00
Rolf Ahrenberg
f2081c4f00 Fixed the OPTIONS URL and enchanced the user agent string. 2014-04-06 23:42:49 +03:00
Rolf Ahrenberg
388543a58d Added a recommendation for using libcurl version >= 7.36.0. 2014-04-06 00:55:16 +03:00
Rolf Ahrenberg
f46d07a95f Added Catalan translation (Thanks to Gabriel Bonich). 2014-04-05 13:50:55 +03:00
Rolf Ahrenberg
43cc15357e Optimized re-sending. 2014-04-05 13:46:07 +03:00
Rolf Ahrenberg
5b1af5ba29 Refactored the section filtering. 2014-04-04 00:56:00 +03:00
Rolf Ahrenberg
80fc28d8cf Fixed eMinKeepAliveIntervalMs typo. 2014-04-02 21:06:37 +03:00
18 changed files with 505 additions and 195 deletions

21
HISTORY
View File

@@ -33,3 +33,24 @@ VDR Plugin 'satip' Revision History
- Added a check to write new sections only if there
is no data in the read socket.
- Fixed keepalive heartbeat again.
2014-04-05: Version 0.2.2
- Fixed the default keepalive interval.
- Refactored the section filtering.
- Added Catalan translation (Thanks to Gabriel Bonich).
2014-04-12: Version 0.2.3
- Added Spanish translation (Thanks to Gabriel Bonich).
- Fixed parameters of the OPTIONS command.
- Added a device identication into the user agent string.
- Removed unnecessary PLAY commands and header callbacks.
2014-04-20: Version 0.3.0
- Tweaked the pid update mechanism.
2014-04-27: Version 0.3.1
- Fixed the device discovery.

11
README
View File

@@ -14,7 +14,7 @@ See the file COPYING for more information.
Requirements:
- Libcurl - the multiprotocol file transfer library with RTSP support
- Libcurl >= 7.36.0 - the multiprotocol file transfer library with RTSP support
http://curl.haxx.se/libcurl/
- PugiXML - Light-weight, simple and fast XML parser for C++
@@ -23,7 +23,7 @@ Requirements:
TinyXML - a simple, small, C++ XML parser
http://www.grinninglizard.com/tinyxml/
- VDR-2.1.4+ for scrambled channels
- VDR >= 2.1.4 for scrambled channels
Description:
@@ -108,13 +108,6 @@ Notes:
direct access to any DVB card devices. The integrated CAM slot in
Octopus Net devices isn't supported.
- The 100% compliance against SAT>IP specification 1.2 requires a
patched VDR providing channel configuration for pilot, T2 system id,
and SISO/MISO values.
- If you're using Triax TSS400, you'll need the libcurl from 2013-03-20
or newer.
Acknowledgements:
- Big thanks to Digital Devices GmbH for providing the Octopus Net

View File

@@ -57,30 +57,6 @@ char *StripTags(char *strP)
return NULL;
}
int select_single_desc(int descriptorP, const int msP, const bool selectWriteP)
{
// Wait for data
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = msP * 1000L;
// Use select
fd_set infd;
fd_set outfd;
fd_set errfd;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
FD_SET(descriptorP, &errfd);
if (selectWriteP)
FD_SET(descriptorP, &outfd);
else
FD_SET(descriptorP, &infd);
int retval = select(descriptorP + 1, &infd, &outfd, &errfd, &tv);
// Check if error
ERROR_IF_RET(retval < 0, "select()", return retval);
return retval;
}
cString ChangeCase(const cString &strP, bool upperP)
{
cString res(strP);

View File

@@ -93,7 +93,6 @@ uint16_t ts_pid(const uint8_t *bufP);
uint8_t payload(const uint8_t *bufP);
const char *id_pid(const u_short pidP);
char *StripTags(char *strP);
int select_single_desc(int descriptorP, const int msP, const bool selectWriteP);
cString ChangeCase(const cString &strP, bool upperP);
struct section_filter_table_type {

View File

@@ -184,7 +184,7 @@ int cSatipDevice::SignalQuality(void) const
bool cSatipDevice::ProvidesSource(int sourceP) const
{
debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
return (!SatipConfig.IsOperatingModeOff() && !!cSatipDiscover::GetInstance()->GetServer(sourceP));
}
@@ -381,6 +381,12 @@ unsigned int cSatipDevice::CheckData(void)
return 0;
}
int cSatipDevice::GetId(void)
{
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
return deviceIndexM;
}
uchar *cSatipDevice::GetData(int *availableP)
{
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);

View File

@@ -107,6 +107,7 @@ public:
public:
virtual void WriteData(u_char *bufferP, int lengthP);
virtual unsigned int CheckData(void);
virtual int GetId(void);
};
#endif // __SATIP_DEVICE_H

View File

@@ -14,6 +14,7 @@ public:
virtual ~cSatipDeviceIf() {}
virtual void WriteData(u_char *bufferP, int lengthP) = 0;
virtual unsigned int CheckData(void) = 0;
virtual int GetId(void) = 0;
private:
cSatipDeviceIf(const cSatipDeviceIf&);

View File

@@ -179,7 +179,7 @@ void cSatipDiscover::Read(void)
int len = socketM->Read(buf, eProbeBufferSize);
if (len > 0) {
//debug("cSatipDiscover::%s(): len=%d", __FUNCTION__, len);
bool status = false;
bool status = false, valid = false;
char *s, *p = reinterpret_cast<char *>(buf), *location = NULL;
char *r = strtok_r(p, "\r\n", &s);
while (r) {
@@ -187,18 +187,30 @@ void cSatipDiscover::Read(void)
// Check the status code
// HTTP/1.1 200 OK
if (!status && startswith(r, "HTTP/1.1 200 OK")) {
status = true;
}
// Check the location data
// LOCATION: http://192.168.0.115:8888/octonet.xml
if (status && startswith(r, "LOCATION:")) {
location = compactspace(r + 9);
debug("cSatipDiscover::%s(): location='%s'", __FUNCTION__, location);
break;
}
status = true;
}
if (status) {
// Check the location data
// LOCATION: http://192.168.0.115:8888/octonet.xml
if (startswith(r, "LOCATION:")) {
location = compactspace(r + 9);
debug("cSatipDiscover::%s(): location='%s'", __FUNCTION__, location);
}
// Check the source type
// ST: urn:ses-com:device:SatIPServer:1
else if (startswith(r, "ST:")) {
char *st = compactspace(r + 3);
if (strstr(st, "urn:ses-com:device:SatIPServer:1"))
valid = true;
debug("cSatipDiscover::%s(): st='%s'", __FUNCTION__, st);
}
// Check whether all the required data is found
if (valid && !isempty(location))
break;
}
r = strtok_r(NULL, "\r\n", &s);
}
if (handleM && !isempty(location)) {
if (handleM && valid && !isempty(location)) {
long rc = 0;
CURLcode res = CURLE_OK;
#ifdef DEBUG

View File

@@ -158,7 +158,7 @@ cString GetTransponderUrlParameters(const cChannel *channelP)
freq /= 1000L;
#define ST(s) if (strchr(s, type) && (strchr(s, '0' + dtp.System() + 1) || strchr(s, '*')))
#define STBUFLEFT (sizeof(buffer) - (q - buffer))
q += snprintf(q, STBUFLEFT, "freq=%s", *dtoa(freq, "%.3f"));
q += snprintf(q, STBUFLEFT, "freq=%s", *dtoa(freq, "%lg"));
ST(" S *") q += snprintf(q, STBUFLEFT, "&src=%d", ((src > 0) && (src <= 255)) ? src : 1);
ST("CS *") q += snprintf(q, STBUFLEFT, "&sr=%d", channelP->Srate());
ST(" S *") q += snprintf(q, STBUFLEFT, "&pol=%c", tolower(dtp.Polarization()));

137
po/ca_ES.po Normal file
View File

@@ -0,0 +1,137 @@
# VDR plugin language source file.
# Copyright (C) 2007-2014 Rolf Ahrenberg
# This file is distributed under the same license as the satip package.
# Gabriel Bonich, 2014
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 0.3.1\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2014-04-27 04:27+0200\n"
"PO-Revision-Date: 2014-04-27 04:27+0200\n"
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
"Language-Team: Catalan <vdr@linuxtv.org>\n"
"Language: ca\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "PAT (0x00)"
msgstr "PAT (0x00)"
msgid "NIT (0x40)"
msgstr "NIT (0x40)"
msgid "SDT (0x42)"
msgstr "SDT (0x42)"
msgid "EIT (0x4E/0x4F/0x5X/0x6X)"
msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
msgid "TDT (0x70)"
msgstr "TDT (0x70)"
msgid "SAT>IP Devices"
msgstr "SAT>IP Dispositius"
msgid "SAT>IP Device"
msgstr "SAT>IP Dispositiu"
msgid "Address"
msgstr "Adressa"
msgid "Model"
msgstr "Model"
msgid "Description"
msgstr "Descripció"
msgid "Creation date"
msgstr "Creació de data"
msgid "SAT>IP Information"
msgstr "SAT>IP Informació"
msgid "General"
msgstr "General"
msgid "Pids"
msgstr "Pids"
msgid "Filters"
msgstr "Filtres"
msgid "Bits/bytes"
msgstr "Bits/Bytes"
msgid "SAT>IP information not available!"
msgstr "SAT>IP Informació no disponible!"
msgid "off"
msgstr "Apagat"
msgid "low"
msgstr "Baix"
msgid "normal"
msgstr "Normal"
msgid "high"
msgstr "Alt"
msgid "Operating mode"
msgstr "Mode de operació"
msgid ""
"Define the used operating mode for all SAT>IP devices:\n"
"\n"
"off - devices are disabled\n"
"low - devices are working at the lowest priority\n"
"normal - devices are working within normal parameters\n"
"high - devices are working at the highest priority"
msgstr ""
"Defineig la manera de operar els Disposituis SAT>IP:\n"
"\n"
"Apagat - Dispositius desactivats\n"
"Baix - Dispositius treballan a baixa prioritat\n"
"Normal - Dispositius treballan en parametres normals\n"
"Alta - Dispositius treballan a prioritat Alta"
msgid "Enable EPG scanning"
msgstr "Activa Escanneig EPG"
msgid ""
"Define whether the EPG background scanning shall be used.\n"
"\n"
"This setting disables the automatic EIT scanning functionality for all SAT>IP devices."
msgstr ""
"Definir si s'utilitzarà l'anàlisi en segon pla del EPG.\n"
"\n"
"Aquesta configuració desactiva la funcionalitat d'escaneig EIT automàtica per a tots els dispositius SAT>IP."
msgid "Disabled filters"
msgstr "Desactiva filtres"
msgid "none"
msgstr "no"
msgid ""
"Define number of section filters to be disabled.\n"
"\n"
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
msgstr ""
"Defineix el numero de filtres de secció que seran deshabilitats.\n"
"\n"
"Alguns filtres de secció podrien provocar un comportament no desitjat a VDR, com sincronitzar malament l'hora. Posant aquests filtres a la llista negra, aqui, la secció de dades útil pot ser deixada intacta pel seu procès en el VDR."
msgid "Filter"
msgstr "Filtra"
msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Definir un filtre mal comportar a la llista negra."
msgid "Active SAT>IP devices:"
msgstr "Dispositius SAT>IP actius:"
msgid "Help"
msgstr "Ajuda"

View File

@@ -1,14 +1,14 @@
# VDR plugin language source file.
# Copyright (C) 2007-2014 Rolf Ahrenberg & Antti Seppala
# This file is distributed under the same license as the iptv package.
# Copyright (C) 2007-2014 Rolf Ahrenberg
# This file is distributed under the same license as the satip package.
# Frank Neumann, 2014
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 0.2.1\n"
"Project-Id-Version: vdr-satip 0.3.1\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2014-04-01 04:01+0200\n"
"PO-Revision-Date: 2014-04-01 04:01+0200\n"
"POT-Creation-Date: 2014-04-27 04:27+0200\n"
"PO-Revision-Date: 2014-04-27 04:27+0200\n"
"Last-Translator: Frank Neumann <fnu@yavdr.org>\n"
"Language-Team: German <vdr@linuxtv.org>\n"
"Language: de\n"

137
po/es_ES.po Normal file
View File

@@ -0,0 +1,137 @@
# VDR plugin language source file.
# Copyright (C) 2007-2014 Rolf Ahrenberg
# This file is distributed under the same license as the satip package.
# Gabriel Bonich, 2014
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 0.3.1\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2014-04-27 04:27+0200\n"
"PO-Revision-Date: 2014-04-27 04:27+0200\n"
"Last-Translator: Gabriel Bonich <gbonich@gmail.com>\n"
"Language-Team: Spanish <vdr@linuxtv.org>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
msgid "PAT (0x00)"
msgstr "PAT (0x00)"
msgid "NIT (0x40)"
msgstr "NIT (0x40)"
msgid "SDT (0x42)"
msgstr "SDT (0x42)"
msgid "EIT (0x4E/0x4F/0x5X/0x6X)"
msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
msgid "TDT (0x70)"
msgstr "TDT (0x70)"
msgid "SAT>IP Devices"
msgstr "SAT>IP Dispositivos"
msgid "SAT>IP Device"
msgstr "SAT>IP Dispositivo"
msgid "Address"
msgstr "Dirección"
msgid "Model"
msgstr "Modelo"
msgid "Description"
msgstr "Descripción"
msgid "Creation date"
msgstr "Fecha creación"
msgid "SAT>IP Information"
msgstr "SAT>IP Información"
msgid "General"
msgstr "General"
msgid "Pids"
msgstr "Pids"
msgid "Filters"
msgstr "Filtros"
msgid "Bits/bytes"
msgstr "Bits/Bytes"
msgid "SAT>IP information not available!"
msgstr "SAT>IP Información no disponible!"
msgid "off"
msgstr "Apagado"
msgid "low"
msgstr "Bajo"
msgid "normal"
msgstr "Normal"
msgid "high"
msgstr "Alto"
msgid "Operating mode"
msgstr "Modo de operación"
msgid ""
"Define the used operating mode for all SAT>IP devices:\n"
"\n"
"off - devices are disabled\n"
"low - devices are working at the lowest priority\n"
"normal - devices are working within normal parameters\n"
"high - devices are working at the highest priority"
msgstr ""
"Define la manera que trabajan los Dispositivos SAT>IP:\n"
"\n"
"Apagat - Dispositivos desactivados\n"
"Baix - Dispositivos trabajando con prioridad Baja\n"
"Normal - Dispositivos trabajando con prioridad Normal\n"
"Alta - Dispositivos trabajando con prioridad Alta"
msgid "Enable EPG scanning"
msgstr "Activa Escaneo EPG"
msgid ""
"Define whether the EPG background scanning shall be used.\n"
"\n"
"This setting disables the automatic EIT scanning functionality for all SAT>IP devices."
msgstr ""
"Definir si se utilitzará el analisí en segundo plano del EPG.\n"
"\n"
"Esta configuración desactiva la funcionalidad del escaneo EIT automática para todos los Dispositivos SAT>IP."
msgid "Disabled filters"
msgstr "Desactiva filtros"
msgid "none"
msgstr "no"
msgid ""
"Define number of section filters to be disabled.\n"
"\n"
"Certain section filters might cause some unwanted behaviour to VDR such as time being falsely synchronized. By black-listing the filters here useful section data can be left intact for VDR to process."
msgstr ""
"Define el numero de filtros de sección que seran deshabilitados.\n"
"\n"
"Algunos filtros de sección podrian causar un comportamiento no deseado a VDR, como sincronizar mal la hora. Poniendo estos filtros en la lista negra, aqui, la sección de datos útiles se puede dejar intacta para su proceso con el VDR."
msgid "Filter"
msgstr "Filtra"
msgid "Define an ill-behaving filter to be blacklisted."
msgstr "Define un filtro para poner en la lista negra."
msgid "Active SAT>IP devices:"
msgstr "Dispositivos SAT>IP activos:"
msgid "Help"
msgstr "Ayuda"

View File

@@ -1,14 +1,14 @@
# VDR plugin language source file.
# Copyright (C) 2007-2014 Rolf Ahrenberg & Antti Seppala
# This file is distributed under the same license as the iptv package.
# Copyright (C) 2007-2014 Rolf Ahrenberg
# This file is distributed under the same license as the satip package.
# Rolf Ahrenberg, 2014
#
msgid ""
msgstr ""
"Project-Id-Version: vdr-satip 0.2.1\n"
"Project-Id-Version: vdr-satip 0.3.1\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2014-04-01 04:01+0200\n"
"PO-Revision-Date: 2014-04-01 04:01+0200\n"
"POT-Creation-Date: 2014-04-27 04:27+0200\n"
"PO-Revision-Date: 2014-04-27 04:27+0200\n"
"Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
"Language: fi\n"

View File

@@ -13,6 +13,10 @@
#include "discover.h"
#include "setup.h"
#if defined(LIBCURL_VERSION_NUM) && LIBCURL_VERSION_NUM < 0x072400
#warning "CURL version >= 0.7.36 is recommended"
#endif
#if defined(APIVERSNUM) && APIVERSNUM < 20000
#error "VDR-2.0.0 API version or greater is required!"
#endif
@@ -21,7 +25,7 @@
#define GITVERSION ""
#endif
const char VERSION[] = "0.2.1" GITVERSION;
const char VERSION[] = "0.3.1" GITVERSION;
static const char DESCRIPTION[] = trNOOP("SAT>IP Devices");
class cPluginSatip : public cPlugin {

View File

@@ -17,6 +17,7 @@ cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_
secLenM(0),
tsFeedpM(0),
pidM(pidP),
ringBufferM(new cRingBufferFrame(eDmxMaxSectionCount * eDmxMaxSectionSize)),
deviceIndexM(deviceIndexP)
{
//debug("cSatipSectionFilter::%s(%d, %d)", __FUNCTION__, deviceIndexM, pidM);
@@ -48,7 +49,7 @@ cSatipSectionFilter::cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_
// Create sockets
socketM[0] = socketM[1] = -1;
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socketM) != 0) {
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, socketM) != 0) {
char tmp[64];
error("Opening section filter sockets failed (device=%d pid=%d): %s", deviceIndexM, pidM, strerror_r(errno, tmp, sizeof(tmp)));
}
@@ -70,6 +71,7 @@ cSatipSectionFilter::~cSatipSectionFilter()
if (tmp >= 0)
close(tmp);
secBufM = NULL;
DELETENULL(ringBufferM);
}
inline uint16_t cSatipSectionFilter::GetLength(const uint8_t *dataP)
@@ -99,21 +101,8 @@ int cSatipSectionFilter::Filter(void)
if (doneqM && !neq)
return 0;
// There is no data in the read socket, more can be written
if ((secLenM > 0) && (socketM[1] >= 0) && (socketM[0] >= 0)) {
for (i = 0; i < eWriteMaxRetries; ++i) {
if (select_single_desc(socketM[0], 10, false))
continue;
ssize_t len = write(socketM[1], secBufM, secLenM);
ERROR_IF(len < 0, "write()");
// Update statistics
if (len >= 0)
AddSectionStatistic(len, 1);
break;
}
if (i >= eWriteMaxRetries)
debug("Skipped section write (%d bytes)", secLenM);
}
if (ringBufferM && (secLenM > 0))
ringBufferM->Put(new cFrame(secBufM, secLenM));
}
return 0;
}
@@ -219,13 +208,31 @@ void cSatipSectionFilter::Process(const uint8_t* dataP)
}
}
bool cSatipSectionFilter::Send(void)
{
bool result = false;
cFrame *section = ringBufferM->Get();
if (section) {
uchar *data = section->Data();
int count = section->Count();
if (data && (count > 0) && (socketM[1] >= 0) && (socketM[0] >= 0)) {
ssize_t len = send(socketM[1], data, count, MSG_EOR);
ERROR_IF(len < 0 && errno != EAGAIN, "send()");
if (len > 0) {
ringBufferM->Drop(section);
result = !!ringBufferM->Available();
// Update statistics
AddSectionStatistic(len, 1);
}
}
}
return result;
}
cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP)
:
#ifdef USE_THREADED_SECTIONFILTER
cThread("SAT>IP section handler", true),
: cThread("SAT>IP section handler"),
ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("SAT>IP SECTION HANDLER %d", deviceIndexP))),
#endif
mutexM(),
deviceIndexM(deviceIndexP)
{
@@ -234,7 +241,6 @@ cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigne
// Initialize filter pointers
memset(filtersM, 0, sizeof(filtersM));
#ifdef USE_THREADED_SECTIONFILTER
// Create input buffer
if (ringBufferM) {
ringBufferM->SetTimeouts(100, 100);
@@ -242,19 +248,17 @@ cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigne
}
else
error("Failed to allocate buffer for section filter handler (device=%d): ", deviceIndexM);
Start();
#endif
}
cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
{
debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
#ifdef USE_THREADED_SECTIONFILTER
// Stop thread
if (Running())
Cancel(3);
DELETE_POINTER(ringBufferM);
#endif
// Destroy all filters
cMutexLock MutexLock(&mutexM);
@@ -262,13 +266,22 @@ cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
Delete(i);
}
#ifdef USE_THREADED_SECTIONFILTER
void cSatipSectionFilterHandler::Action(void)
{
debug("cSatipSectionFilterHandler::%s(%d): entering", __FUNCTION__, deviceIndexM);
bool processed = false;
// Do the thread loop
while (Running()) {
// Send demuxed section packets through all filters
bool retry = false;
mutexM.Lock();
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (filtersM[i] && filtersM[i]->Send())
retry = true;
}
mutexM.Unlock();
if (retry)
continue;
// Read one TS packet
if (ringBufferM) {
int len = 0;
@@ -304,7 +317,6 @@ void cSatipSectionFilterHandler::Action(void)
}
debug("cSatipSectionFilterHandler::%s(%d): exiting", __FUNCTION__, deviceIndexM);
}
#endif
cString cSatipSectionFilterHandler::GetInformation(void)
{
@@ -405,35 +417,10 @@ int cSatipSectionFilterHandler::GetPid(int handleP)
void cSatipSectionFilterHandler::Write(uchar *bufferP, int lengthP)
{
//debug("cSatipSectionFilterHandler::%s(%d): length=%d", __FUNCTION__, deviceIndexM, lengthP);
#ifdef USE_THREADED_SECTIONFILTER
// Fill up the buffer
if (ringBufferM) {
int len = ringBufferM->Put(bufferP, lengthP);
if (len != lengthP)
ringBufferM->ReportOverflow(lengthP - len);
}
#else
// Lock
cMutexLock MutexLock(&mutexM);
uchar *p = bufferP;
int len = lengthP;
// Process TS packets through all filters
while (p && (len >= TS_SIZE)) {
if (*p != TS_SYNC_BYTE) {
for (int i = 1; i < len; ++i) {
if (p[i] == TS_SYNC_BYTE) {
p += i;
len -= i;
break;
}
}
}
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
if (filtersM[i])
filtersM[i]->Process(p);
}
p += TS_SIZE;
len -= TS_SIZE;
}
#endif
}

View File

@@ -8,21 +8,16 @@
#ifndef __SATIP_SECTIONFILTER_H
#define __SATIP_SECTIONFILTER_H
#ifdef __FreeBSD__
#include <sys/socket.h>
#endif // __FreeBSD__
#include <vdr/device.h>
#include "common.h"
#include "statistics.h"
#define USE_THREADED_SECTIONFILTER
class cSatipSectionFilter : public cSatipSectionStatistics {
private:
enum {
eWriteMaxRetries = 20,
eDmxMaxFilterSize = 18,
eDmxMaxSectionCount = 64,
eDmxMaxSectionSize = 4096,
eDmxMaxSectionFeedSize = (eDmxMaxSectionSize + TS_SIZE)
};
@@ -38,6 +33,7 @@ private:
uint16_t tsFeedpM;
uint16_t pidM;
cRingBufferFrame *ringBufferM;
int deviceIndexM;
int socketM[2];
@@ -59,23 +55,17 @@ public:
cSatipSectionFilter(int deviceIndexP, uint16_t pidP, uint8_t tidP, uint8_t maskP);
virtual ~cSatipSectionFilter();
void Process(const uint8_t* dataP);
bool Send(void);
int GetFd(void) { return socketM[0]; }
uint16_t GetPid(void) const { return pidM; }
};
#ifdef USE_THREADED_SECTIONFILTER
class cSatipSectionFilterHandler : public cThread {
protected:
virtual void Action(void);
private:
cRingBufferLinear *ringBufferM;
#else
class cSatipSectionFilterHandler {
#endif
private:
enum {
eMaxSecFilterCount = 32
};
cRingBufferLinear *ringBufferM;
cMutex mutexM;
int deviceIndexM;
cSatipSectionFilter *filtersM[eMaxSecFilterCount];
@@ -83,6 +73,9 @@ private:
bool Delete(unsigned int indexP);
bool IsBlackListed(u_short pidP, u_char tidP, u_char maskP) const;
protected:
virtual void Action(void);
public:
cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP);
virtual ~cSatipSectionFilterHandler();

174
tuner.c
View File

@@ -34,23 +34,24 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
signalStrengthM(-1),
signalQualityM(-1),
streamIdM(-1),
pidUpdatedM(false),
addPidsM(),
delPidsM(),
pidsM()
{
debug("cSatipTuner::%s(%d)", __FUNCTION__, packetBufferLenM);
debug("cSatipTuner::%s(%d) [device %d]", __FUNCTION__, packetBufferLenM, deviceM->GetId());
// Allocate packet buffer
packetBufferM = MALLOC(unsigned char, packetBufferLenM);
if (packetBufferM)
memset(packetBufferM, 0, packetBufferLenM);
else
error("MALLOC() failed for packet buffer");
error("MALLOC() failed for packet buffer [device %d]", deviceM->GetId());
// Start thread
Start();
}
cSatipTuner::~cSatipTuner()
{
debug("cSatipTuner::%s()", __FUNCTION__);
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
// Stop thread
sleepM.Signal();
if (Running())
@@ -83,7 +84,7 @@ size_t cSatipTuner::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void
int timeout = -1;
char *session = NULL;
if (sscanf(r, "Session:%m[^;];timeout=%11d", &session, &timeout) == 2)
obj->SetSessionTimeout(skipspace(session), (timeout - 1) * 1000);
obj->SetSessionTimeout(skipspace(session), timeout * 1000);
else if (sscanf(r, "Session:%m[^;]", &session) == 1)
obj->SetSessionTimeout(skipspace(session));
FREE_POINTER(session);
@@ -96,7 +97,7 @@ size_t cSatipTuner::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void
void cSatipTuner::Action(void)
{
debug("cSatipTuner::%s(): entering", __FUNCTION__);
debug("cSatipTuner::%s(): entering [device %d]", __FUNCTION__, deviceM->GetId());
cTimeMs timeout(eReConnectTimeoutMs);
// Increase priority
SetPriority(-1);
@@ -137,12 +138,12 @@ void cSatipTuner::Action(void)
sleepM.Wait(10); // to avoid busy loop and reduce cpu load
}
}
debug("cSatipTuner::%s(): exiting", __FUNCTION__);
debug("cSatipTuner::%s(): exiting [device %d]", __FUNCTION__, deviceM->GetId());
}
bool cSatipTuner::Open(void)
{
debug("cSatipTuner::%s()", __FUNCTION__);
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
if (Connect()) {
openedM = true;
return true;
@@ -152,7 +153,7 @@ bool cSatipTuner::Open(void)
bool cSatipTuner::Close(void)
{
debug("cSatipTuner::%s()", __FUNCTION__);
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
openedM = false;
Disconnect();
return true;
@@ -161,7 +162,7 @@ bool cSatipTuner::Close(void)
bool cSatipTuner::Connect(void)
{
cMutexLock MutexLock(&mutexM);
debug("cSatipTuner::%s()", __FUNCTION__);
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
// Initialize the curl session
if (!handleM)
@@ -173,13 +174,9 @@ bool cSatipTuner::Connect(void)
// Just retune
if (tunedM && (streamIdM >= 0)) {
debug("cSatipTuner::%s(): retune", __FUNCTION__);
uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
SATIP_CURL_EASY_PERFORM(handleM);
if (!ValidateLatestResponse())
return false;
debug("cSatipTuner::%s(): retune [device %d]", __FUNCTION__, deviceM->GetId());
keepAliveM.Set(0);
KeepAlive();
// Flush any old content
if (rtpSocketM)
rtpSocketM->Flush();
@@ -191,11 +188,6 @@ bool cSatipTuner::Connect(void)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_VERBOSE, 1L);
#endif
// Set callback
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipTuner::HeaderCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEDATA, this);
// No progress meter and no signaling
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOPROGRESS, 1L);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_NOSIGNAL, 1L);
@@ -205,7 +197,7 @@ bool cSatipTuner::Connect(void)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_CONNECTTIMEOUT_MS, (long)eConnectTimeoutMs);
// Set user-agent
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s", PLUGIN_NAME_I18N, VERSION));
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_USERAGENT, *cString::sprintf("vdr-%s/%s (device %d)", PLUGIN_NAME_I18N, VERSION, deviceM->GetId()));
// Set URL
char *p = curl_easy_unescape(handleM, *streamAddrM, 0, NULL);
@@ -223,37 +215,38 @@ bool cSatipTuner::Connect(void)
rtcpSocketM->Close();
}
if ((rtpSocketM->Port() <= 0) || (rtcpSocketM->Port() <= 0)) {
error("Cannot open required ports!");
error("Cannot open required RTP/RTCP ports [device %d]", deviceM->GetId());
return false;
}
// Request server options: "&pids=all" for the whole mux
// Request server options
keepAliveM.Set(timeoutM);
uri = cString::sprintf("rtsp://%s/?%s&pids=0", *streamAddrM, *streamParamM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
SATIP_CURL_EASY_PERFORM(handleM);
if (!ValidateLatestResponse())
return false;
// Setup media stream
// Setup media stream: "&pids=all" for the whole mux
uri = cString::sprintf("rtsp://%s/?%s", *streamAddrM, *streamParamM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
transport = cString::sprintf("RTP/AVP;unicast;client_port=%d-%d", rtpSocketM->Port(), rtcpSocketM->Port());
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_TRANSPORT, *transport);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_SETUP);
// Set header callback for catching the session and timeout
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, cSatipTuner::HeaderCallback);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, this);
SATIP_CURL_EASY_PERFORM(handleM);
// Session id is now known - disable header parsing
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_HEADERFUNCTION, NULL);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_WRITEHEADER, NULL);
//SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, *sessionM);
if (!ValidateLatestResponse())
return false;
// Start playing
uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
//SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, *sessionM);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
SATIP_CURL_EASY_PERFORM(handleM);
if (!ValidateLatestResponse())
return false;
tunedM = true;
UpdatePids(true);
if (nextServerM) {
cSatipDiscover::GetInstance()->UseServer(nextServerM, true);
currentServerM = nextServerM;
@@ -268,7 +261,7 @@ bool cSatipTuner::Connect(void)
bool cSatipTuner::Disconnect(void)
{
cMutexLock MutexLock(&mutexM);
debug("cSatipTuner::%s()", __FUNCTION__);
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
// Terminate curl session
if (handleM) {
@@ -305,13 +298,15 @@ bool cSatipTuner::Disconnect(void)
cSatipDiscover::GetInstance()->UseServer(currentServerM, false);
tunedM = false;
timeoutM = eMinKeepAliveIntervalMs;
addPidsM.Clear();
delPidsM.Clear();
return true;
}
bool cSatipTuner::ValidateLatestResponse(void)
{
//debug("cSatipTuner::%s()", __FUNCTION__);
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
if (handleM) {
long rc = 0;
CURLcode res = CURLE_OK;
@@ -319,7 +314,7 @@ bool cSatipTuner::ValidateLatestResponse(void)
if (rc == 200)
return true;
else if (rc != 0)
error("Tuner detected invalid status code: %ld", rc);
error("Tuner detected invalid status code %ld [device %d]", rc, deviceM->GetId());
}
return false;
@@ -327,7 +322,7 @@ bool cSatipTuner::ValidateLatestResponse(void)
void cSatipTuner::ParseReceptionParameters(const char *paramP)
{
//debug("cSatipTuner::%s(%s)", __FUNCTION__, paramP);
//debug("cSatipTuner::%s(%s) [device %d]", __FUNCTION__, paramP, deviceM->GetId());
// DVB-S2:
// ver=<major>.<minor>;src=<srcID>;tuner=<feID>,<level>,<lock>,<quality>,<frequency>,<polarisation>,<system>,<type>,<pilots>,<roll_off>,<symbol_rate>,<fec_inner>;pids=<pid0>,...,<pidn>
// DVB-T2:
@@ -374,21 +369,21 @@ void cSatipTuner::ParseReceptionParameters(const char *paramP)
void cSatipTuner::SetStreamId(int streamIdP)
{
cMutexLock MutexLock(&mutexM);
debug("cSatipTuner::%s(%d)", __FUNCTION__, streamIdP);
debug("cSatipTuner::%s(%d) [device %d]", __FUNCTION__, streamIdP, deviceM->GetId());
streamIdM = streamIdP;
}
void cSatipTuner::SetSessionTimeout(const char *sessionP, int timeoutP)
{
cMutexLock MutexLock(&mutexM);
debug("cSatipTuner::%s(%s, %d)", __FUNCTION__, sessionP, timeoutP);
debug("cSatipTuner::%s(%s, %d) [device %d]", __FUNCTION__, sessionP, timeoutP, deviceM->GetId());
sessionM = sessionP;
timeoutM = (timeoutP > eMinKeepAliveIntervalMs) ? timeoutP : eMinKeepAliveIntervalMs;
}
bool cSatipTuner::SetSource(cSatipServer *serverP, const char *parameterP, const int indexP)
{
debug("cSatipTuner::%s(%s, %d)", __FUNCTION__, parameterP, indexP);
debug("cSatipTuner::%s(%s, %d) [device %d]", __FUNCTION__, parameterP, indexP, deviceM->GetId());
cMutexLock MutexLock(&mutexM);
nextServerM = cSatipDiscover::GetInstance()->GetServer(serverP);
if (nextServerM && !isempty(nextServerM->Address()) && !isempty(parameterP)) {
@@ -403,44 +398,91 @@ bool cSatipTuner::SetSource(cSatipServer *serverP, const char *parameterP, const
bool cSatipTuner::SetPid(int pidP, int typeP, bool onP)
{
//debug("cSatipTuner::%s(%d, %d, %d)", __FUNCTION__, pidP, typeP, onP);
//debug("cSatipTuner::%s(%d, %d, %d) [device %d]", __FUNCTION__, pidP, typeP, onP, deviceM->GetId());
cMutexLock MutexLock(&mutexM);
bool found = false;
for (int i = 0; i < pidsM.Size(); ++i) {
if (pidsM[i] == pidP) {
found = true;
if (!onP) {
if (!onP)
pidsM.Remove(i);
pidUpdatedM = true;
}
break;
}
}
if (onP && !found) {
if (onP && !found)
pidsM.Append(pidP);
pidUpdatedM = true;
}
// Generate deltas
found = false;
if (onP) {
for (int i = 0; i < addPidsM.Size(); ++i) {
if (addPidsM[i] == pidP) {
found = true;
break;
}
}
if (!found)
addPidsM.Append(pidP);
for (int i = 0; i < delPidsM.Size(); ++i) {
if (delPidsM[i] == pidP) {
delPidsM.Remove(i);
break;
}
}
}
else {
for (int i = 0; i < delPidsM.Size(); ++i) {
if (delPidsM[i] == pidP) {
found = true;
break;
}
}
if (!found)
delPidsM.Append(pidP);
for (int i = 0; i < addPidsM.Size(); ++i) {
if (addPidsM[i] == pidP) {
addPidsM.Remove(i);
break;
}
}
}
pidUpdateCacheM.Set(ePidUpdateIntervalMs);
return true;
}
bool cSatipTuner::UpdatePids(void)
bool cSatipTuner::UpdatePids(bool forceP)
{
cMutexLock MutexLock(&mutexM);
if (pidUpdateCacheM.TimedOut() && pidUpdatedM && pidsM.Size() && tunedM && handleM && !isempty(*streamAddrM) && (streamIdM > 0)) {
//debug("cSatipTuner::%s()", __FUNCTION__);
if (((forceP && pidsM.Size()) || (pidUpdateCacheM.TimedOut() && (addPidsM.Size() || delPidsM.Size()))) &&
tunedM && handleM && !isempty(*streamAddrM) && (streamIdM > 0)) {
CURLcode res = CURLE_OK;
//cString uri = cString::sprintf("rtsp://%s/stream=%d?%spids=%d", *streamAddrM, streamIdM, onP ? "add" : "del", pidP);
cString uri = cString::sprintf("rtsp://%s/stream=%d?pids=", *streamAddrM, streamIdM);
for (int i = 0; i < pidsM.Size(); ++i)
uri = cString::sprintf("%s%d%s", *uri, pidsM[i], (i == (pidsM.Size() - 1)) ? "" : ",");
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
if (forceP) {
if (pidsM.Size()) {
uri = cString::sprintf("%s?pids=", *uri);
for (int i = 0; i < pidsM.Size(); ++i)
uri = cString::sprintf("%s%d%s", *uri, pidsM[i], (i == (pidsM.Size() - 1)) ? "" : ",");
}
}
else {
if (addPidsM.Size()) {
uri = cString::sprintf("%s?addpids=", *uri);
for (int i = 0; i < addPidsM.Size(); ++i)
uri = cString::sprintf("%s%d%s", *uri, addPidsM[i], (i == (addPidsM.Size() - 1)) ? "" : ",");
}
if (delPidsM.Size()) {
uri = cString::sprintf("%s%sdelpids=", *uri, addPidsM.Size() ? "&" : "?");
for (int i = 0; i < delPidsM.Size(); ++i)
uri = cString::sprintf("%s%d%s", *uri, delPidsM[i], (i == (delPidsM.Size() - 1)) ? "" : ",");
}
}
//debug("cSatipTuner::%s(): %s [device %d]", __FUNCTION__, *uri, deviceM->GetId());
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_STREAM_URI, *uri);
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_PLAY);
SATIP_CURL_EASY_PERFORM(handleM);
if (ValidateLatestResponse())
pidUpdatedM = false;
if (ValidateLatestResponse()) {
addPidsM.Clear();
delPidsM.Clear();
}
else
Disconnect();
@@ -454,7 +496,7 @@ bool cSatipTuner::KeepAlive(void)
{
cMutexLock MutexLock(&mutexM);
if (tunedM && handleM && keepAliveM.TimedOut()) {
debug("cSatipTuner::%s()", __FUNCTION__);
debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
CURLcode res = CURLE_OK;
cString uri = cString::sprintf("rtsp://%s/stream=%d", *streamAddrM, streamIdM);
@@ -474,30 +516,30 @@ bool cSatipTuner::KeepAlive(void)
int cSatipTuner::SignalStrength(void)
{
//debug("cSatipTuner::%s()", __FUNCTION__);
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
return signalStrengthM;
}
int cSatipTuner::SignalQuality(void)
{
//debug("cSatipTuner::%s()", __FUNCTION__);
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
return signalQualityM;
}
bool cSatipTuner::HasLock(void)
{
//debug("cSatipTuner::%s()", __FUNCTION__);
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
return tunedM && hasLockM;
}
cString cSatipTuner::GetSignalStatus(void)
{
//debug("cSatipTuner::%s()", __FUNCTION__);
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
return cString::sprintf("lock=%d strength=%d quality=%d", HasLock(), SignalStrength(), SignalQuality());
}
cString cSatipTuner::GetInformation(void)
{
//debug("cSatipTuner::%s()", __FUNCTION__);
//debug("cSatipTuner::%s() [device %d]", __FUNCTION__, deviceM->GetId());
return tunedM ? cString::sprintf("rtsp://%s/?%s [stream=%d]", *streamAddrM, *streamParamM, streamIdM) : "connection failed";
}

13
tuner.h
View File

@@ -26,10 +26,10 @@
class cSatipTuner : public cThread, public cSatipTunerStatistics {
private:
enum {
eConnectTimeoutMs = 1500, // in milliseconds
ePidUpdateIntervalMs = 100, // in milliseconds
eReConnectTimeoutMs = 5000, // in milliseconds
eMinKeepAliveIntervalMs = 300000 // in milliseconds
eConnectTimeoutMs = 1500, // in milliseconds
ePidUpdateIntervalMs = 250, // in milliseconds
eReConnectTimeoutMs = 5000, // in milliseconds
eMinKeepAliveIntervalMs = 30000 // in milliseconds
};
static size_t HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void *dataP);
@@ -58,7 +58,8 @@ private:
int signalStrengthM;
int signalQualityM;
int streamIdM;
bool pidUpdatedM;
cVector<int> addPidsM;
cVector<int> delPidsM;
cVector<int> pidsM;
bool Connect(void);
@@ -69,7 +70,7 @@ private:
void SetSessionTimeout(const char *sessionP, int timeoutP = 0);
bool KeepAlive(void);
bool UpdateSignalInfoCache(void);
bool UpdatePids(void);
bool UpdatePids(bool forceP = false);
protected:
virtual void Action(void);