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

27 Commits

Author SHA1 Message Date
Rolf Ahrenberg
fb9c1c6a44 Added a session id quirk for Triax TSS 400. 2014-05-17 21:41:55 +03:00
Rolf Ahrenberg
5e2770a0e5 Added a validity check for the session member. 2014-05-14 22:14:59 +03:00
Rolf Ahrenberg
53b643139f Fixed the warning message about the libcurl version. 2014-05-11 17:11:28 +03:00
Rolf Ahrenberg
9a8c6f8c0d Fixed model detection and OctopusNet DVB-C model quirks.
Added a session id quirk for GSSBOX.
2014-05-08 22:09:35 +03:00
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
Rolf Ahrenberg
5e8b7b7c5e Fixed keepalive heartbeat again. 2014-04-01 09:05:13 +03:00
Rolf Ahrenberg
88b2ad9244 Added missing RTP packet error message. 2014-03-30 22:58:43 +03:00
Rolf Ahrenberg
7b58d9f28f Added a check to write new sections only if there is no data in the read socket. 2014-03-30 22:20:56 +03:00
Rolf Ahrenberg
f493df0e3d Changed implementation to report about RTP packet errors on 5 minutes interval only. 2014-03-30 18:20:20 +03:00
Rolf Ahrenberg
9a6ae40954 Optimized the startup delay. 2014-03-28 19:53:22 +02:00
Rolf Ahrenberg
b5ec84fd91 Fixed keepalive heartbeat. 2014-03-28 19:52:17 +02:00
Rolf Ahrenberg
e7a74f3ad4 Fixed reconnection. 2014-03-25 23:50:30 +02:00
Rolf Ahrenberg
40d280af10 Fixed pid leaking while disabling section filters, EIT filter defition and RTP sequence overflow detection. 2014-03-25 23:25:36 +02:00
Rolf Ahrenberg
9f2d99435d Added support for cDevice::Ready() and preliminary RTP packet sequence check. 2014-03-23 17:59:08 +02:00
23 changed files with 649 additions and 182 deletions

45
HISTORY
View File

@@ -19,3 +19,48 @@ VDR Plugin 'satip' Revision History
- Refactored the session code.
- Fixed EIT scan functionality.
- Updated for vdr-2.1.6.
2014-03-28: Version 0.2.0
- Added support for cDevice::Ready().
- Fixed pid leaking while disabling section filters.
- Fixed keepalive heartbeat.
2014-04-01: Version 0.2.1
- Changed implementation to report about RTP packet
errors on 5 minutes interval only.
- 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.
2014-05-10: Version 0.3.2
- Fixed model detection and OctopusNet DVB-C model quirks.
- Added a session id quirk for GSSBOX.
2014-05-18: Version 0.3.3
- Added a validity check for the session member.
- Added a session id quirk for Triax TSS 400.

8
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,10 +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.
Acknowledgements:
- Big thanks to Digital Devices GmbH for providing the Octopus Net

View File

@@ -57,6 +57,15 @@ char *StripTags(char *strP)
return NULL;
}
char *SkipZeroes(const char *strP)
{
if ((uchar)*strP != '0')
return (char *)strP;
while (*strP && (uchar)*strP == '0')
strP++;
return (char *)strP;
}
cString ChangeCase(const cString &strP, bool upperP)
{
cString res(strP);
@@ -70,12 +79,10 @@ cString ChangeCase(const cString &strP, bool upperP)
const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE] =
{
/* description tag pid tid mask */
{trNOOP("PAT (0x00)"), "PAT", 0x00, 0x00, 0xFF},
{trNOOP("NIT (0x40)"), "NIT", 0x10, 0x40, 0xFF},
{trNOOP("SDT (0x42)"), "SDT", 0x11, 0x42, 0xFF},
{trNOOP("EIT (0x4E/0x4F)"), "EIT", 0x12, 0x4E, 0xFE},
{trNOOP("EIT (0x5X)"), "EIT", 0x12, 0x50, 0xF0},
{trNOOP("EIT (0x6X)"), "EIT", 0x12, 0x60, 0xF0},
{trNOOP("TDT (0x70)"), "TDT", 0x14, 0x70, 0xFF},
/* description tag pid tid mask */
{trNOOP("PAT (0x00)"), "PAT", 0x00, 0x00, 0xFF},
{trNOOP("NIT (0x40)"), "NIT", 0x10, 0x40, 0xFF},
{trNOOP("SDT (0x42)"), "SDT", 0x11, 0x42, 0xFF},
{trNOOP("EIT (0x4E/0x4F/0x5X/0x6X)"), "EIT", 0x12, 0x40, 0xC0},
{trNOOP("TDT (0x70)"), "TDT", 0x14, 0x70, 0xFF},
};

View File

@@ -36,7 +36,7 @@
#define SATIP_STATS_ACTIVE_PIDS_COUNT 10
#define SATIP_STATS_ACTIVE_FILTERS_COUNT 10
#define SECTION_FILTER_TABLE_SIZE 7
#define SECTION_FILTER_TABLE_SIZE 5
#define SATIP_CURL_EASY_GETINFO(X, Y, Z) \
if ((res = curl_easy_getinfo((X), (Y), (Z))) != CURLE_OK) { \
@@ -93,6 +93,7 @@ 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);
char *SkipZeroes(const char *strP);
cString ChangeCase(const cString &strP, bool upperP);
struct section_filter_table_type {

View File

@@ -19,7 +19,9 @@ cSatipDevice::cSatipDevice(unsigned int indexP)
isPacketDeliveredM(false),
isOpenDvrM(false),
deviceNameM(*cString::sprintf("%s %d", *DeviceType(), deviceIndexM)),
channelM()
channelM(),
createdM(0),
mutexM()
{
unsigned int bufsize = (unsigned int)SATIP_BUFFER_SIZE;
bufsize -= (bufsize % TS_SIZE);
@@ -144,6 +146,12 @@ cString cSatipDevice::GetInformation(unsigned int pageP)
return s;
}
bool cSatipDevice::Ready(void)
{
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
return ((cSatipDiscover::GetInstance()->GetServerCount() > 0) || (createdM.Elapsed() > eReadyTimeoutMs));
}
cString cSatipDevice::DeviceType(void) const
{
//debug("cSatipDevice::%s(%u)", __FUNCTION__, deviceIndexM);
@@ -176,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));
}
@@ -300,11 +308,12 @@ bool cSatipDevice::SetPid(cPidHandle *handleP, int typeP, bool onP)
int cSatipDevice::OpenFilter(u_short pidP, u_char tidP, u_char maskP)
{
//debug("cSatipDevice::%s(%u): pid=%d tid=%d mask=%d", __FUNCTION__, deviceIndexM, pidP, tidP, maskP);
//debug("cSatipDevice::%s(%u): pid=%d tid=%d mask=%d", __FUNCTION__, deviceIndexM, pidP, tidP, maskP);
if (pSectionFilterHandlerM) {
if (pTunerM)
int handle = pSectionFilterHandlerM->Open(pidP, tidP, maskP);
if (pTunerM && (handle >= 0))
pTunerM->SetPid(pidP, ptOther, true);
return pSectionFilterHandlerM->Open(pidP, tidP, maskP);
return handle;
}
return -1;
}
@@ -372,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

@@ -26,6 +26,9 @@ public:
// private parts
private:
enum {
eReadyTimeoutMs = 2000 // in milliseconds
};
unsigned int deviceIndexM;
bool isPacketDeliveredM;
bool isOpenDvrM;
@@ -34,6 +37,7 @@ private:
cRingBufferLinear *tsBufferM;
cSatipTuner *pTunerM;
cSatipSectionFilterHandler *pSectionFilterHandlerM;
cTimeMs createdM;
cMutex mutexM;
// constructor & destructor
@@ -54,6 +58,7 @@ private:
// for channel info
public:
virtual bool Ready(void);
virtual cString DeviceType(void) const;
virtual cString DeviceName(void) const;
virtual bool AvoidRecording(void) const;
@@ -102,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
@@ -251,6 +263,13 @@ void cSatipDiscover::AddServer(const char *addrP, const char *descP, const char
}
}
int cSatipDiscover::GetServerCount(void)
{
//debug("cSatipDiscover::%s()", __FUNCTION__);
cMutexLock MutexLock(&mutexM);
return serversM ? serversM->Count() : -1;
}
cSatipServer *cSatipDiscover::GetServer(int sourceP, int systemP)
{
//debug("cSatipDiscover::%s(%d, %d)", __FUNCTION__, sourceP, systemP);

View File

@@ -56,6 +56,7 @@ public:
static void Destroy(void);
virtual ~cSatipDiscover();
void TriggerScan(void) { probeIntervalM.Set(0); }
int GetServerCount(void);
cSatipServer *GetServer(int sourceP, int systemP = -1);
cSatipServer *GetServer(cSatipServer *serverP);
cSatipServers *GetServers(void);

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.3\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
"PO-Revision-Date: 2014-05-18 05:18+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.1.1\n"
"Project-Id-Version: vdr-satip 0.3.3\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2014-03-16 03:16+0200\n"
"PO-Revision-Date: 2014-03-16 03:16+0200\n"
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
"PO-Revision-Date: 2014-05-18 05:18+0200\n"
"Last-Translator: Frank Neumann <fnu@yavdr.org>\n"
"Language-Team: German <vdr@linuxtv.org>\n"
"Language: de\n"
@@ -25,14 +25,8 @@ msgstr "NIT (0x40)"
msgid "SDT (0x42)"
msgstr "SDT (0x42)"
msgid "EIT (0x4E/0x4F)"
msgstr "EIT (0x4E/0x4F)"
msgid "EIT (0x5X)"
msgstr "EIT (0x5X)"
msgid "EIT (0x6X)"
msgstr "EIT (0x6X)"
msgid "EIT (0x4E/0x4F/0x5X/0x6X)"
msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
msgid "TDT (0x70)"
msgstr "TDT (0x70)"

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.3\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
"PO-Revision-Date: 2014-05-18 05:18+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.1.1\n"
"Project-Id-Version: vdr-satip 0.3.3\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2014-03-16 03:16+0200\n"
"PO-Revision-Date: 2014-03-16 03:16+0200\n"
"POT-Creation-Date: 2014-05-18 05:18+0200\n"
"PO-Revision-Date: 2014-05-18 05:18+0200\n"
"Last-Translator: Rolf Ahrenberg\n"
"Language-Team: Finnish <vdr@linuxtv.org>\n"
"Language: fi\n"
@@ -25,14 +25,8 @@ msgstr "NIT (0x40)"
msgid "SDT (0x42)"
msgstr "SDT (0x42)"
msgid "EIT (0x4E/0x4F)"
msgstr "EIT (0x4E/0x4F)"
msgid "EIT (0x5X)"
msgstr "EIT (0x5X)"
msgid "EIT (0x6X)"
msgstr "EIT (0x6X)"
msgid "EIT (0x4E/0x4F/0x5X/0x6X)"
msgstr "EIT (0x4E/0x4F/0x5X/0x6X)"
msgid "TDT (0x70)"
msgstr "TDT (0x70)"

View File

@@ -13,6 +13,10 @@
#include "discover.h"
#include "setup.h"
#if defined(LIBCURL_VERSION_NUM) && LIBCURL_VERSION_NUM < 0x072400
#warning "CURL version >= 7.36.0 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.1.1" GITVERSION;
const char VERSION[] = "0.3.3" 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,13 +101,8 @@ int cSatipSectionFilter::Filter(void)
if (doneqM && !neq)
return 0;
// There is no data in the read socket, more can be written
if ((socketM[0] >= 0) && (socketM[1] >= 0) /*&& !select_single_desc(socketM[0], 0, false)*/) {
ssize_t len = write(socketM[1], secBufM, secLenM);
ERROR_IF(len < 0, "write()");
// Update statistics
AddSectionStatistic(len, 1);
}
if (ringBufferM && (secLenM > 0))
ringBufferM->Put(new cFrame(secBufM, secLenM));
}
return 0;
}
@@ -211,13 +208,33 @@ 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)
: 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))),
mutexM(),
deviceIndexM(deviceIndexP),
processedM(false),
ringBufferM(new cRingBufferLinear(bufferLenP, TS_SIZE, false, *cString::sprintf("SAT>IP SECTION HANDLER %d", deviceIndexP)))
deviceIndexM(deviceIndexP)
{
debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
@@ -238,8 +255,9 @@ cSatipSectionFilterHandler::cSatipSectionFilterHandler(int deviceIndexP, unsigne
cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
{
debug("cSatipSectionFilterHandler::%s(%d)", __FUNCTION__, deviceIndexM);
Stop();
// Stop thread
if (Running())
Cancel(3);
DELETE_POINTER(ringBufferM);
// Destroy all filters
@@ -248,26 +266,28 @@ cSatipSectionFilterHandler::~cSatipSectionFilterHandler()
Delete(i);
}
bool cSatipSectionFilterHandler::Stop(void)
{
debug("cSatipSectionFilterHandler::%s(%d): entering", __FUNCTION__, deviceIndexM);
// Stop thread
if (Running())
Cancel(3);
return true;
}
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;
if (processedM) {
if (processed) {
ringBufferM->Del(TS_SIZE);
processedM = false;
processed = false;
}
uchar *p = ringBufferM->Get(len);
if (p && (len >= TS_SIZE)) {
@@ -289,7 +309,7 @@ void cSatipSectionFilterHandler::Action(void)
filtersM[i]->Process(p);
}
mutexM.Unlock();
processedM = true;
processed = true;
continue;
}
}

View File

@@ -8,9 +8,6 @@
#ifndef __SATIP_SECTIONFILTER_H
#define __SATIP_SECTIONFILTER_H
#ifdef __FreeBSD__
#include <sys/socket.h>
#endif // __FreeBSD__
#include <vdr/device.h>
#include "common.h"
@@ -18,9 +15,10 @@
class cSatipSectionFilter : public cSatipSectionStatistics {
private:
enum dmx_limits {
eDmxMaxFilterSize = 18,
eDmxMaxSectionSize = 4096,
enum {
eDmxMaxFilterSize = 18,
eDmxMaxSectionCount = 64,
eDmxMaxSectionSize = 4096,
eDmxMaxSectionFeedSize = (eDmxMaxSectionSize + TS_SIZE)
};
@@ -35,6 +33,7 @@ private:
uint16_t tsFeedpM;
uint16_t pidM;
cRingBufferFrame *ringBufferM;
int deviceIndexM;
int socketM[2];
@@ -56,6 +55,7 @@ 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; }
};
@@ -65,10 +65,9 @@ private:
enum {
eMaxSecFilterCount = 32
};
cRingBufferLinear *ringBufferM;
cMutex mutexM;
int deviceIndexM;
bool processedM;
cRingBufferLinear *ringBufferM;
cSatipSectionFilter *filtersM[eMaxSecFilterCount];
bool Delete(unsigned int indexP);
@@ -80,7 +79,6 @@ protected:
public:
cSatipSectionFilterHandler(int deviceIndexP, unsigned int bufferLenP);
virtual ~cSatipSectionFilterHandler();
bool Stop(void);
cString GetInformation(void);
int Open(u_short pidP, u_char tidP, u_char maskP);
void Close(int handleP);

View File

@@ -16,7 +16,8 @@ cSatipServer::cSatipServer(const char *addressP, const char *descriptionP, const
: addressM(addressP),
descriptionM(descriptionP),
modelM(modelP),
modelTypeM(eSatipModelTypeMask),
modelTypeM(eSatipModelTypeNone),
quirkM(eSatipQuirkNone),
useCountM(0),
createdM(time(NULL)),
lastSeenM(0)
@@ -24,6 +25,15 @@ cSatipServer::cSatipServer(const char *addressP, const char *descriptionP, const
memset(modelCountM, 0, sizeof(modelCountM));
if (isempty(*modelM))
modelM = "DVBS-1";
// These devices contain a session id bug:
// Inverto Airscreen Server IDL 400 ?
// Telestar Digibit R1 ?
// Elgato EyeTV Netstream 4Sat ?
if (!isempty(*descriptionM) &&
(strstr(*descriptionM, "GSSBOX") || // Grundig Sat Systems GSS.box DSI 400
strstr(*descriptionM, "Triax SatIP Converter") // Triax TSS 400
))
quirkM |= eSatipQuirkSessionId;
char *s, *p = strdup(*modelM);
char *r = strtok_r(p, ",", &s);
while (r) {
@@ -41,7 +51,7 @@ cSatipServer::cSatipServer(const char *addressP, const char *descriptionP, const
else
modelCountM[eSatipModuleDVBT2] = 1;
// Add model quirks here
if (strstr(*addressM, "OctopusNet"))
if (!isempty(*descriptionM) && strstr(*descriptionM, "OctopusNet"))
modelTypeM |= cSatipServer::eSatipModelTypeDVBC;
}
if (strstr(r, "DVBT")) {
@@ -51,7 +61,7 @@ cSatipServer::cSatipServer(const char *addressP, const char *descriptionP, const
else
modelCountM[eSatipModuleDVBT] = 1;
// Add model quirks here
if (strstr(*addressM, "OctopusNet"))
if (!isempty(*descriptionM) && strstr(*descriptionM, "OctopusNet"))
modelTypeM |= cSatipServer::eSatipModelTypeDVBC;
}
r = strtok_r(NULL, ",", &s);
@@ -149,7 +159,7 @@ cString cSatipServers::GetString(cSatipServer *serverP)
cString list = "";
for (cSatipServer *s = First(); s; s = Next(s)) {
if (s == serverP) {
list = cString::sprintf("%s:%s:%s", s->Address(), s->Model(), s->Description());
list = cString::sprintf("%s|%s|%s", s->Address(), s->Model(), s->Description());
break;
}
}
@@ -160,7 +170,7 @@ cString cSatipServers::List(void)
{
cString list = "";
for (cSatipServer *s = First(); s; s = Next(s))
list = cString::sprintf("%s%s:%s:%s\n", *list, s->Address(), s->Model(), s->Description());
list = cString::sprintf("%s%s|%s|%s\n", *list, s->Address(), s->Model(), s->Description());
return list;
}

View File

@@ -23,12 +23,19 @@ private:
cString modelM;
int modelCountM[eSatipModuleCount];
int modelTypeM;
int quirkM;
int useCountM;
time_t createdM;
cTimeMs lastSeenM;
public:
enum eSatipQuirk {
eSatipQuirkNone = 0x00,
eSatipQuirkSessionId = 0x01,
eSatipQuirkMask = 0x0F
};
enum eSatipModelType {
eSatipModelTypeNone = 0x00,
eSatipModelTypeDVBS2 = 0x01,
eSatipModelTypeDVBT = 0x02,
eSatipModelTypeDVBT2 = 0x04,
@@ -43,6 +50,7 @@ public:
const char *Description() { return *descriptionM; }
const char *Address() { return *addressM; }
const char *Model(void) { return modelM; }
bool Quirk(int quirkP) { return ((quirkP & eSatipQuirkMask) & quirkM); }
int ModelType(void) { return modelTypeM; }
bool Match(int modelP) { return ((modelP & eSatipModelTypeMask) & modelTypeM); }
int Cable() { return Match(eSatipModelTypeDVBC) ? (Match(eSatipModelTypeDVBT2) ? modelCountM[eSatipModuleDVBT2] : modelCountM[eSatipModuleDVBT]) : 0; } // an ugly hack

View File

@@ -20,7 +20,10 @@
cSatipSocket::cSatipSocket()
: socketPortM(0),
socketDescM(-1)
socketDescM(-1),
lastErrorReportM(0),
packetErrorsM(0),
sequenceNumberM(-1)
{
debug("cSatipSocket::%s()", __FUNCTION__);
memset(&sockAddrM, 0, sizeof(sockAddrM));
@@ -72,8 +75,14 @@ void cSatipSocket::Close(void)
close(socketDescM);
socketDescM = -1;
socketPortM = 0;
sequenceNumberM = -1;
memset(&sockAddrM, 0, sizeof(sockAddrM));
}
if (packetErrorsM) {
info("detected %d RTP packet errors", packetErrorsM);
packetErrorsM = 0;
lastErrorReportM = time(NULL);
}
}
bool cSatipSocket::Flush(void)
@@ -150,6 +159,21 @@ int cSatipSocket::ReadVideo(unsigned char *bufferAddrP, unsigned int bufferLenP)
unsigned int cc = bufferAddrP[0] & 0x0F;
// Payload type: MPEG2 TS = 33
//unsigned int pt = bufferAddrP[1] & 0x7F;
// Sequence number
int seq = ((bufferAddrP[2] & 0xFF) << 8) | (bufferAddrP[3] & 0xFF);
if ((((sequenceNumberM + 1) % 0xFFFF) == 0) && (seq == 0xFFFF))
sequenceNumberM = -1;
else if ((sequenceNumberM >= 0) && (((sequenceNumberM + 1) % 0xFFFF) != seq)) {
packetErrorsM++;
if (time(NULL) - lastErrorReportM > eReportIntervalS) {
info("detected %d RTP packet errors", packetErrorsM);
packetErrorsM = 0;
lastErrorReportM = time(NULL);
}
sequenceNumberM = seq;
}
else
sequenceNumberM = seq;
// Header lenght
unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
// Check if extension

View File

@@ -12,9 +12,15 @@
class cSatipSocket {
private:
enum {
eReportIntervalS = 300 // in seconds
};
int socketPortM;
int socketDescM;
struct sockaddr_in sockAddrM;
time_t lastErrorReportM;
int packetErrorsM;
int sequenceNumberM;
public:
cSatipSocket();

193
tuner.c
View File

@@ -26,31 +26,32 @@ cSatipTuner::cSatipTuner(cSatipDeviceIf &deviceP, unsigned int packetLenP)
headerListM(NULL),
keepAliveM(),
pidUpdateCacheM(),
sessionM(),
timeoutM(eKeepAliveIntervalMs),
sessionM(""),
timeoutM(eMinKeepAliveIntervalMs),
openedM(false),
tunedM(false),
hasLockM(false),
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,9 +84,9 @@ 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);
obj->SetSessionTimeout(skipspace(session), timeout * 1000);
else if (sscanf(r, "Session:%m[^;]", &session) == 1)
obj->SetSessionTimeout(skipspace(session), -1);
obj->SetSessionTimeout(skipspace(session));
FREE_POINTER(session);
}
r = strtok_r(NULL, "\r\n", &s);
@@ -96,8 +97,8 @@ size_t cSatipTuner::HeaderCallback(void *ptrP, size_t sizeP, size_t nmembP, void
void cSatipTuner::Action(void)
{
debug("cSatipTuner::%s(): entering", __FUNCTION__);
cTimeMs timeout(0);
debug("cSatipTuner::%s(): entering [device %d]", __FUNCTION__, deviceM->GetId());
cTimeMs timeout(eReConnectTimeoutMs);
// Increase priority
SetPriority(-1);
// Do the thread loop
@@ -129,7 +130,7 @@ void cSatipTuner::Action(void)
}
else {
// Reconnect if necessary
if (openedM && !tunedM && timeout.TimedOut()) {
if (openedM && timeout.TimedOut()) {
Disconnect();
Connect();
timeout.Set(eReConnectTimeoutMs);
@@ -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,17 +174,12 @@ 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();
keepAliveM.Set(eKeepAliveIntervalMs);
return true;
}
@@ -192,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);
@@ -206,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);
@@ -224,37 +215,41 @@ 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
uri = cString::sprintf("rtsp://%s/?%s&pids=0", *streamAddrM, *streamParamM);
// Request server options
keepAliveM.Set(timeoutM);
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);
if (nextServerM && nextServerM->Quirk(cSatipServer::eSatipQuirkSessionId) && !isempty(*sessionM) && startswith(*sessionM, "0")) {
debug("cSatipTuner::%s(): session id quirk [device %d]", __FUNCTION__, deviceM->GetId());
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_SESSION_ID, SkipZeroes(*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;
keepAliveM.Set(eKeepAliveIntervalMs);
tunedM = true;
UpdatePids(true);
if (nextServerM) {
cSatipDiscover::GetInstance()->UseServer(nextServerM, true);
currentServerM = nextServerM;
@@ -269,7 +264,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 +300,16 @@ bool cSatipTuner::Disconnect(void)
if (currentServerM)
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 +317,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 +325,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 +372,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 > 0 ? timeoutP * 1000L : eKeepAliveIntervalMs;
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,45 +401,90 @@ 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()) {
keepAliveM.Set(eKeepAliveIntervalMs);
pidUpdatedM = false;
addPidsM.Clear();
delPidsM.Clear();
}
else
Disconnect();
@@ -456,7 +499,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);
@@ -464,7 +507,7 @@ bool cSatipTuner::KeepAlive(void)
SATIP_CURL_EASY_SETOPT(handleM, CURLOPT_RTSP_REQUEST, (long)CURL_RTSPREQ_OPTIONS);
SATIP_CURL_EASY_PERFORM(handleM);
if (ValidateLatestResponse())
keepAliveM.Set(eKeepAliveIntervalMs);
keepAliveM.Set(timeoutM);
else
Disconnect();
@@ -476,30 +519,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";
}

15
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
eKeepAliveIntervalMs = 600000 // 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);
@@ -66,10 +67,10 @@ private:
bool ValidateLatestResponse(void);
void ParseReceptionParameters(const char *paramP);
void SetStreamId(int streamIdP);
void SetSessionTimeout(const char *sessionP, int timeoutP);
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);