mirror of
https://github.com/rofafor/vdr-plugin-iptv.git
synced 2023-10-10 11:37:03 +00:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c975d458f5 | ||
|
|
11d864c16b | ||
|
|
75d17b289b | ||
|
|
547306b67c | ||
|
|
763c83209d | ||
|
|
af85ef1703 | ||
|
|
24ecadf414 | ||
|
|
f4126b7e2c | ||
|
|
c7cbde301b | ||
|
|
06506c41f6 | ||
|
|
c33b05076a | ||
|
|
38bd9a21f6 | ||
|
|
4c7b2ea69b | ||
|
|
c475b26515 | ||
|
|
9145fb8bb8 | ||
|
|
7a8b2962b2 | ||
|
|
626d0402c2 | ||
|
|
b3b06e569f | ||
|
|
ff84c54d50 | ||
|
|
4c39d8cf72 | ||
|
|
0b790260fa | ||
|
|
79113bbe09 | ||
|
|
30de763a4b | ||
|
|
868865c47d | ||
|
|
a73921041f | ||
|
|
49e3a9e23a | ||
|
|
73311873bc | ||
|
|
816c357065 | ||
|
|
5838bda3f0 | ||
|
|
079b02d69e | ||
|
|
6582f137b9 | ||
|
|
2bd31e9eda | ||
|
|
c2f88fbbb3 | ||
|
|
52ae2bdf63 | ||
|
|
1898defeb6 | ||
|
|
21719d3397 | ||
|
|
bf3fc70d2d | ||
|
|
99d6c0f207 | ||
|
|
ca4fdc761f | ||
|
|
37c5ee26ae | ||
|
|
8ba0b3a417 | ||
|
|
cfb60a06ba | ||
|
|
6ed0ebd734 | ||
|
|
2081ab41a8 | ||
|
|
66ab92584b | ||
|
|
05e57802c3 | ||
|
|
55bb0e65df | ||
|
|
ea4f8fde31 | ||
|
|
ef615c4bc5 | ||
|
|
a6d4e850fc | ||
|
|
fd06641449 | ||
|
|
05e52079f8 | ||
|
|
f0469e24cc | ||
|
|
7629e34d2a | ||
|
|
ac458b0c36 | ||
|
|
2d583e8cfa | ||
|
|
b0dba49fbc | ||
|
|
a05766c90d | ||
|
|
d1fdc390c9 | ||
|
|
d126da8ed8 | ||
|
|
2567501b65 | ||
|
|
12b54fbbc2 | ||
|
|
a2d8c367f6 | ||
|
|
3f88e7a911 | ||
|
|
8a96e5b327 | ||
|
|
170cb56263 | ||
|
|
899db53845 | ||
|
|
6eb259e8fb |
51
HISTORY
51
HISTORY
@@ -137,3 +137,54 @@ VDR Plugin 'iptv' Revision History
|
|||||||
|
|
||||||
- Fixed channel parameter corruption.
|
- Fixed channel parameter corruption.
|
||||||
- Added Dutch translation (Thanks to Carel).
|
- Added Dutch translation (Thanks to Carel).
|
||||||
|
|
||||||
|
2010-06-06: Version 0.4.2
|
||||||
|
|
||||||
|
- Updated for vdr-1.7.15.
|
||||||
|
|
||||||
|
2012-02-02: Version 0.5.0
|
||||||
|
|
||||||
|
- Updated for vdr-1.7.23.
|
||||||
|
- Renamed Sid scanner to section id scanner and added
|
||||||
|
experimental Tid/Nid support into it.
|
||||||
|
- Added optional source address validation for UDP protocol.
|
||||||
|
- Fixed audio pid detection in pid scanner.
|
||||||
|
- Changed ProvidesChannel() to set the need of detaching
|
||||||
|
receivers due to VDR's channel selection mechanism.
|
||||||
|
- Enabled partial content responses for HTTP protocol.
|
||||||
|
- Fixed EXT protocol execution (Thanks to Peter Holik).
|
||||||
|
- Disable detaching of receivers if retuned to an existing
|
||||||
|
channel (Thanks to Zdeněk Kopřivík).
|
||||||
|
- Canonicalized the configuration directory.
|
||||||
|
- Added support for LDFLAGS.
|
||||||
|
- Added cppcheck target into Makefile.
|
||||||
|
|
||||||
|
2012-04-02: Version 0.5.1
|
||||||
|
|
||||||
|
- Updated for vdr-1.7.27.
|
||||||
|
- Updated Makefile.
|
||||||
|
- Silenced compilation warnings.
|
||||||
|
- Fixed channel switching bugs.
|
||||||
|
- Added support for a service interface.
|
||||||
|
- Changed UDP protocol to always utilize the source address
|
||||||
|
validation.
|
||||||
|
|
||||||
|
2012-04-26: Version 0.5.2
|
||||||
|
|
||||||
|
- Fixed connection problems in HTTP protocol.
|
||||||
|
|
||||||
|
2012-06-03: Version 1.0.0
|
||||||
|
|
||||||
|
- Optimized reading from UDP sockets.
|
||||||
|
- Fixed ProvidesChannel method.
|
||||||
|
|
||||||
|
2012-07-10: Version 1.0.1
|
||||||
|
|
||||||
|
- Added FreeBSD support (Thanks to Jürgen Lock).
|
||||||
|
|
||||||
|
2012-09-30: Version 1.1.0
|
||||||
|
|
||||||
|
- Updated for vdr-1.7.30.
|
||||||
|
- Added support for source-specific multicasts (SSM).
|
||||||
|
- Changed default external script directory from the
|
||||||
|
configuration to the resource.
|
||||||
|
|||||||
39
Makefile
39
Makefile
@@ -5,9 +5,15 @@
|
|||||||
# Debugging on/off
|
# Debugging on/off
|
||||||
#IPTV_DEBUG = 1
|
#IPTV_DEBUG = 1
|
||||||
|
|
||||||
|
# Default shell for EXT protocol
|
||||||
|
#IPTV_EXTSHELL = /bin/bash
|
||||||
|
|
||||||
# Strip debug symbols? Set eg. to /bin/true if not
|
# Strip debug symbols? Set eg. to /bin/true if not
|
||||||
STRIP = strip
|
STRIP = strip
|
||||||
|
|
||||||
|
# Install command
|
||||||
|
INSTALL = cp --remove-destination
|
||||||
|
|
||||||
# The official name of this plugin.
|
# The official name of this plugin.
|
||||||
# This name will be used in the '-P...' option of VDR to load the plugin.
|
# This name will be used in the '-P...' option of VDR to load the plugin.
|
||||||
# By default the main source file also carries this name.
|
# By default the main source file also carries this name.
|
||||||
@@ -18,18 +24,20 @@ PLUGIN = iptv
|
|||||||
|
|
||||||
### The version number of this plugin (taken from the main source file):
|
### The version number of this plugin (taken from the main source file):
|
||||||
|
|
||||||
VERSION = $(shell grep 'static const char VERSION\[\] *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g')
|
VERSION = $(shell grep 'const char VERSION\[\] *=' $(PLUGIN).c | awk '{ print $$5 }' | sed -e 's/[";]//g')
|
||||||
|
GITTAG = $(shell git describe --always 2>/dev/null)
|
||||||
|
|
||||||
### The C++ compiler and options:
|
### The C++ compiler and options:
|
||||||
|
|
||||||
CXX ?= g++
|
CXX ?= g++
|
||||||
CXXFLAGS ?= -fPIC -g -O2 -Wall -Wextra -Wswitch-default -Wfloat-equal -Wundef -Wpointer-arith -Wconversion -Wcast-align -Wredundant-decls -Wno-unused-parameter -Woverloaded-virtual -Wno-parentheses
|
CXXFLAGS ?= -fPIC -g -O3 -Wall -Wextra -Wswitch-default -Wfloat-equal -Wundef -Wpointer-arith -Wconversion -Wcast-align -Wredundant-decls -Wno-unused-parameter -Werror=overloaded-virtual -Wno-parentheses
|
||||||
|
LDFLAGS ?= -Wl,--as-needed
|
||||||
|
|
||||||
### The directory environment:
|
### The directory environment:
|
||||||
|
|
||||||
VDRDIR = ../../..
|
VDRDIR ?= ../../..
|
||||||
LIBDIR = ../../lib
|
LIBDIR ?= ../../lib
|
||||||
TMPDIR = /tmp
|
TMPDIR ?= /tmp
|
||||||
|
|
||||||
### Make sure that necessary options are included:
|
### Make sure that necessary options are included:
|
||||||
|
|
||||||
@@ -58,6 +66,14 @@ ifdef IPTV_DEBUG
|
|||||||
DEFINES += -DDEBUG
|
DEFINES += -DDEBUG
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef IPTV_EXTSHELL
|
||||||
|
DEFINES += -DEXTSHELL='"$(IPTV_EXTSHELL)"'
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(strip $(GITTAG)),)
|
||||||
|
DEFINES += -DGITVERSION='"-GIT-$(GITTAG)"'
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: all all-redirect
|
.PHONY: all all-redirect
|
||||||
all-redirect: all
|
all-redirect: all
|
||||||
|
|
||||||
@@ -73,7 +89,7 @@ all: libvdr-$(PLUGIN).so i18n
|
|||||||
|
|
||||||
### Implicit rules:
|
### Implicit rules:
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c Makefile
|
||||||
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
|
$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
|
||||||
|
|
||||||
### Dependencies:
|
### Dependencies:
|
||||||
@@ -97,7 +113,7 @@ I18Npot = $(PODIR)/$(PLUGIN).pot
|
|||||||
msgfmt -c -o $@ $<
|
msgfmt -c -o $@ $<
|
||||||
|
|
||||||
$(I18Npot): $(wildcard *.c)
|
$(I18Npot): $(wildcard *.c)
|
||||||
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --msgid-bugs-address='Rolf Ahrenberg' -o $@ $^
|
xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name='vdr-$(PLUGIN)' --package-version='$(VERSION)' --msgid-bugs-address='<see README>' -o $@ `ls $^`
|
||||||
|
|
||||||
%.po: $(I18Npot)
|
%.po: $(I18Npot)
|
||||||
msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
|
msgmerge -U --no-wrap --no-location --backup=none -q $@ $<
|
||||||
@@ -113,13 +129,13 @@ i18n: $(I18Nmsgs) $(I18Npot)
|
|||||||
### Targets:
|
### Targets:
|
||||||
|
|
||||||
libvdr-$(PLUGIN).so: $(OBJS)
|
libvdr-$(PLUGIN).so: $(OBJS)
|
||||||
$(CXX) $(CXXFLAGS) -shared $(OBJS) -o $@
|
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
|
||||||
ifndef IPTV_DEBUG
|
ifndef IPTV_DEBUG
|
||||||
@$(STRIP) $@
|
@$(STRIP) $@
|
||||||
endif
|
endif
|
||||||
@cp --remove-destination $@ $(LIBDIR)/$@.$(APIVERSION)
|
@$(INSTALL) $@ $(LIBDIR)/$@.$(APIVERSION)
|
||||||
|
|
||||||
dist: clean
|
dist: $(I18Npo) clean
|
||||||
@-rm -rf $(TMPDIR)/$(ARCHIVE)
|
@-rm -rf $(TMPDIR)/$(ARCHIVE)
|
||||||
@mkdir $(TMPDIR)/$(ARCHIVE)
|
@mkdir $(TMPDIR)/$(ARCHIVE)
|
||||||
@cp -a * $(TMPDIR)/$(ARCHIVE)
|
@cp -a * $(TMPDIR)/$(ARCHIVE)
|
||||||
@@ -129,3 +145,6 @@ dist: clean
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot
|
@-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ $(PODIR)/*.mo $(PODIR)/*.pot
|
||||||
|
|
||||||
|
cppcheck: $(OBJS)
|
||||||
|
@cppcheck --enable=information,style,unusedFunction -v -f $(OBJS:%.o=%.c)
|
||||||
|
|||||||
37
README
37
README
@@ -44,7 +44,7 @@ cd /put/your/path/here/VDR/PLUGINS/src
|
|||||||
tar -xzf /put/your/path/here/vdr-iptv-X.Y.Z.tgz
|
tar -xzf /put/your/path/here/vdr-iptv-X.Y.Z.tgz
|
||||||
ln -s iptv-X.Y.Z iptv
|
ln -s iptv-X.Y.Z iptv
|
||||||
cd /put/your/path/here/VDR
|
cd /put/your/path/here/VDR
|
||||||
cp -R PLUGINS/src/iptv/iptv /path/to/vdrconf/plugins/
|
cp -R PLUGINS/src/iptv/iptv /path/to/vdrresource/plugins/
|
||||||
make
|
make
|
||||||
make plugins
|
make plugins
|
||||||
./vdr -P iptv
|
./vdr -P iptv
|
||||||
@@ -91,34 +91,38 @@ Configuration:
|
|||||||
TV4;IPTV:40:S=1|P=0|F=EXT|U=iptvstream.sh|A=0:I:0:0:680:0:0:4:0:0:0
|
TV4;IPTV:40:S=1|P=0|F=EXT|U=iptvstream.sh|A=0:I:0:0:680:0:0:4:0:0:0
|
||||||
TV3;IPTV:30:S=0|P=1|F=FILE|U=/video/stream.ts|A=5:I:0:514:670:2321:0:3:0:0:0
|
TV3;IPTV:30:S=0|P=1|F=FILE|U=/video/stream.ts|A=5:I:0:514:670:2321:0:3:0:0:0
|
||||||
TV2;IPTV:20:S=0|P=1|F=HTTP|U=127.0.0.1/TS/2|A=3000:I:0:513:660:2321:0:2:0:0:0
|
TV2;IPTV:20:S=0|P=1|F=HTTP|U=127.0.0.1/TS/2|A=3000:I:0:513:660:2321:0:2:0:0:0
|
||||||
|
TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1@127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0
|
||||||
TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0
|
TV1;IPTV:10:S=1|P=0|F=UDP|U=127.0.0.1|A=1234:I:0:512:650:2321:0:1:0:0:0
|
||||||
^ ^ ^ ^ ^ ^ ^
|
^ ^ ^ ^ ^ ^ ^
|
||||||
| | | | | | Source type ("I")
|
| | | | | | Source type ("I")
|
||||||
| | | | | Stream parameter (multicast port
|
| | | | | Stream parameter (multicast port
|
||||||
| | | | | number, HTTP port number, file delay
|
| | | | | number, HTTP port number, file delay
|
||||||
| | | | | (ms), script parameter)
|
| | | | | (ms), script parameter)
|
||||||
| | | | Stream address (multicast address, URL, file
|
| | | | Stream address (multicast source@group address,
|
||||||
| | | | location, script location)
|
| | | | URL, file location, script location)
|
||||||
| | | Stream protocol ("UDP", "HTTP", "FILE", "EXT")
|
| | | Stream protocol ("UDP", "HTTP", "FILE", "EXT")
|
||||||
| | PID Scan ("0" disable, "1" enable)
|
| | Pid scanner ("0" disable, "1" enable)
|
||||||
| SID Scan ("0" disable, "1" enable)
|
| Section id (Sid/Nid/Tid) scanner ("0" disable, "1" enable)
|
||||||
Unique enumeration
|
Unique enumeration
|
||||||
|
|
||||||
- UDP multicast rules for iptables firewall
|
- UDP multicast rules for iptables firewall
|
||||||
|
|
||||||
# Multicast UDP -packets
|
# Multicast UDP packets
|
||||||
iptables -A INPUT -i eth0 -p udp -d 224.0.0.0/4 --dport 1234 -j ACCEPT
|
iptables -A INPUT -i eth0 -p udp -d 224.0.0.0/4 --dport 1234 -j ACCEPT
|
||||||
|
|
||||||
# IGMP required by multicasts
|
# IGMP required by multicasts
|
||||||
iptables -A INPUT -i eth0 -p igmp -d 224.0.0.0/4 -j ACCEPT
|
iptables -A INPUT -i eth0 -p igmp -d 224.0.0.0/4 -j ACCEPT
|
||||||
|
|
||||||
|
# Default routing for multicast
|
||||||
|
route add -net 224.0.0.0 netmask 224.0.0.0 eth0
|
||||||
|
|
||||||
External streaming:
|
External streaming:
|
||||||
|
|
||||||
- To watch an externally received channel add an EXT entry to channels.conf
|
- To watch an externally received channel add an EXT entry to channels.conf
|
||||||
and specify a script name and parameter. The specified script is executed
|
and specify a script name and parameter. The specified script is executed
|
||||||
from plugin configuration directory when VDR tunes to the channel. The
|
from plugin resource directory when VDR tunes to the channel. The specified
|
||||||
specified script parameter is passed to the script and it can be used to
|
script parameter is passed to the script and it can be used to select for
|
||||||
select for example between different URLs.
|
example between different URLs.
|
||||||
|
|
||||||
- When an EXT channel is opened the IPTV plugin opens an UDP listening port
|
- When an EXT channel is opened the IPTV plugin opens an UDP listening port
|
||||||
on the localhost. The external script is responsible for supplying IPTV
|
on the localhost. The external script is responsible for supplying IPTV
|
||||||
@@ -154,6 +158,21 @@ Notes:
|
|||||||
script and the iptvstream-notrap.sh script should be used instead in these
|
script and the iptvstream-notrap.sh script should be used instead in these
|
||||||
cases.
|
cases.
|
||||||
|
|
||||||
|
- If received MPEG-2 TS streams carry CA descriptors, you'll have to apply
|
||||||
|
"disable_ca_updates" patch to the VDR in order to get rid of "Channel not
|
||||||
|
available" messages.
|
||||||
|
|
||||||
|
- EIT scanning functionality can be disabled for all IPTV channels by applying
|
||||||
|
the "disable_eitscan" patch to the VDR.
|
||||||
|
|
||||||
|
- Section id and pid scanners should be disabled after the correct data is
|
||||||
|
found. This can be made via VDR's channel editor.
|
||||||
|
|
||||||
|
- Source-specific multicast (SSM) can be enabled by defining both the source
|
||||||
|
address and the group address separated by a '@' character. This will use
|
||||||
|
IGMP v3 protocol:
|
||||||
|
"U=<source address>@<group address>"
|
||||||
|
|
||||||
Acknowledgements:
|
Acknowledgements:
|
||||||
|
|
||||||
- The IPTV section filtering code is derived from Linux kernel.
|
- The IPTV section filtering code is derived from Linux kernel.
|
||||||
|
|||||||
19
common.h
19
common.h
@@ -30,6 +30,8 @@
|
|||||||
#define IPTV_DEVICE_INFO_GENERAL 1
|
#define IPTV_DEVICE_INFO_GENERAL 1
|
||||||
#define IPTV_DEVICE_INFO_PIDS 2
|
#define IPTV_DEVICE_INFO_PIDS 2
|
||||||
#define IPTV_DEVICE_INFO_FILTERS 3
|
#define IPTV_DEVICE_INFO_FILTERS 3
|
||||||
|
#define IPTV_DEVICE_INFO_PROTOCOL 4
|
||||||
|
#define IPTV_DEVICE_INFO_BITRATE 5
|
||||||
|
|
||||||
#define IPTV_STATS_ACTIVE_PIDS_COUNT 10
|
#define IPTV_STATS_ACTIVE_PIDS_COUNT 10
|
||||||
#define IPTV_STATS_ACTIVE_FILTERS_COUNT 10
|
#define IPTV_STATS_ACTIVE_FILTERS_COUNT 10
|
||||||
@@ -37,13 +39,14 @@
|
|||||||
#define SECTION_FILTER_TABLE_SIZE 7
|
#define SECTION_FILTER_TABLE_SIZE 7
|
||||||
|
|
||||||
#define ERROR_IF_FUNC(exp, errstr, func, ret) \
|
#define ERROR_IF_FUNC(exp, errstr, func, ret) \
|
||||||
do { \
|
do { \
|
||||||
if (exp) { \
|
if (exp) { \
|
||||||
char tmp[64]; \
|
char tmp[64]; \
|
||||||
error(errstr": %s", strerror_r(errno, tmp, sizeof(tmp))); \
|
strerror_r(errno, tmp, sizeof(tmp)); \
|
||||||
func; \
|
error(errstr": %s", tmp); \
|
||||||
ret; \
|
func; \
|
||||||
} \
|
ret; \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
@@ -77,5 +80,7 @@ struct section_filter_table_type {
|
|||||||
|
|
||||||
extern const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE];
|
extern const section_filter_table_type section_filter_table[SECTION_FILTER_TABLE_SIZE];
|
||||||
|
|
||||||
|
extern const char VERSION[];
|
||||||
|
|
||||||
#endif // __IPTV_COMMON_H
|
#endif // __IPTV_COMMON_H
|
||||||
|
|
||||||
|
|||||||
4
config.c
4
config.c
@@ -42,6 +42,6 @@ void cIptvConfig::SetDisabledFilters(unsigned int Index, int Number)
|
|||||||
|
|
||||||
void cIptvConfig::SetConfigDirectory(const char *directoryP)
|
void cIptvConfig::SetConfigDirectory(const char *directoryP)
|
||||||
{
|
{
|
||||||
debug("cIptvConfig::SetConfigDirectory(%s)", directoryP);
|
debug("cIptvConfig::SetConfigDirectory(%s)\n", directoryP);
|
||||||
strn0cpy(configDirectory, directoryP, sizeof(configDirectory));
|
ERROR_IF(!realpath(directoryP, configDirectory), "Cannot canonicalize configuration directory");
|
||||||
}
|
}
|
||||||
|
|||||||
2
config.h
2
config.h
@@ -20,7 +20,7 @@ private:
|
|||||||
unsigned int useBytes;
|
unsigned int useBytes;
|
||||||
unsigned int sectionFiltering;
|
unsigned int sectionFiltering;
|
||||||
int disabledFilters[SECTION_FILTER_TABLE_SIZE];
|
int disabledFilters[SECTION_FILTER_TABLE_SIZE];
|
||||||
char configDirectory[255];
|
char configDirectory[PATH_MAX];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cIptvConfig();
|
cIptvConfig();
|
||||||
|
|||||||
105
device.c
105
device.c
@@ -21,7 +21,8 @@ cIptvDevice::cIptvDevice(unsigned int Index)
|
|||||||
isPacketDelivered(false),
|
isPacketDelivered(false),
|
||||||
isOpenDvr(false),
|
isOpenDvr(false),
|
||||||
sidScanEnabled(false),
|
sidScanEnabled(false),
|
||||||
pidScanEnabled(false)
|
pidScanEnabled(false),
|
||||||
|
channelId(tChannelID::InvalidID)
|
||||||
{
|
{
|
||||||
unsigned int bufsize = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize());
|
unsigned int bufsize = (unsigned int)MEGABYTE(IptvConfig.GetTsBufferSize());
|
||||||
bufsize -= (bufsize % TS_SIZE);
|
bufsize -= (bufsize % TS_SIZE);
|
||||||
@@ -35,13 +36,13 @@ cIptvDevice::cIptvDevice(unsigned int Index)
|
|||||||
pFileProtocol = new cIptvProtocolFile();
|
pFileProtocol = new cIptvProtocolFile();
|
||||||
pExtProtocol = new cIptvProtocolExt();
|
pExtProtocol = new cIptvProtocolExt();
|
||||||
pIptvStreamer = new cIptvStreamer(tsBuffer, (100 * TS_SIZE));
|
pIptvStreamer = new cIptvStreamer(tsBuffer, (100 * TS_SIZE));
|
||||||
pPidScanner = new cPidScanner;
|
pPidScanner = new cPidScanner();
|
||||||
// Initialize filter pointers
|
// Initialize filter pointers
|
||||||
memset(secfilters, '\0', sizeof(secfilters));
|
memset(secfilters, '\0', sizeof(secfilters));
|
||||||
// Start section handler for iptv device
|
// Start section handler for iptv device
|
||||||
StartSectionHandler();
|
StartSectionHandler();
|
||||||
// Sid scanner must be created after the section handler
|
// Sid scanner must be created after the section handler
|
||||||
pSidScanner = new cSidScanner;
|
pSidScanner = new cSidScanner();
|
||||||
if (pSidScanner)
|
if (pSidScanner)
|
||||||
AttachFilter(pSidScanner);
|
AttachFilter(pSidScanner);
|
||||||
// Check if dvr fifo exists
|
// Check if dvr fifo exists
|
||||||
@@ -122,7 +123,7 @@ cIptvDevice *cIptvDevice::GetIptvDevice(int CardIndex)
|
|||||||
cString cIptvDevice::GetGeneralInformation(void)
|
cString cIptvDevice::GetGeneralInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cIptvDevice::GetGeneralInformation(%d)\n", deviceIndex);
|
//debug("cIptvDevice::GetGeneralInformation(%d)\n", deviceIndex);
|
||||||
return cString::sprintf("IPTV device: %d\nCardIndex: %d\n%s%s%sChannel: %s",
|
return cString::sprintf("IPTV device: %d\nCardIndex: %d\nStream: %s\nStream bitrate: %s\n%sChannel: %s",
|
||||||
deviceIndex, CardIndex(),
|
deviceIndex, CardIndex(),
|
||||||
pIptvStreamer ? *pIptvStreamer->GetInformation() : "",
|
pIptvStreamer ? *pIptvStreamer->GetInformation() : "",
|
||||||
pIptvStreamer ? *pIptvStreamer->GetStreamerStatistic() : "",
|
pIptvStreamer ? *pIptvStreamer->GetStreamerStatistic() : "",
|
||||||
@@ -168,6 +169,12 @@ cString cIptvDevice::GetInformation(unsigned int Page)
|
|||||||
case IPTV_DEVICE_INFO_FILTERS:
|
case IPTV_DEVICE_INFO_FILTERS:
|
||||||
info = GetFiltersInformation();
|
info = GetFiltersInformation();
|
||||||
break;
|
break;
|
||||||
|
case IPTV_DEVICE_INFO_PROTOCOL:
|
||||||
|
info = pIptvStreamer ? *pIptvStreamer->GetInformation() : "";
|
||||||
|
break;
|
||||||
|
case IPTV_DEVICE_INFO_BITRATE:
|
||||||
|
info = pIptvStreamer ? *pIptvStreamer->GetStreamerStatistic() : "";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
info = cString::sprintf("%s%s%s",
|
info = cString::sprintf("%s%s%s",
|
||||||
*GetGeneralInformation(),
|
*GetGeneralInformation(),
|
||||||
@@ -178,10 +185,34 @@ cString cIptvDevice::GetInformation(unsigned int Page)
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cString cIptvDevice::DeviceType(void) const
|
||||||
|
{
|
||||||
|
debug("cIptvDevice::DeviceType(%d)\n", deviceIndex);
|
||||||
|
return "IPTV";
|
||||||
|
}
|
||||||
|
|
||||||
|
cString cIptvDevice::DeviceName(void) const
|
||||||
|
{
|
||||||
|
debug("cIptvDevice::DeviceName(%d)\n", deviceIndex);
|
||||||
|
return cString::sprintf("IPTV %d", deviceIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cIptvDevice::SignalStrength(void) const
|
||||||
|
{
|
||||||
|
debug("cIptvDevice::SignalStrength(%d)\n", deviceIndex);
|
||||||
|
return (100);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cIptvDevice::SignalQuality(void) const
|
||||||
|
{
|
||||||
|
debug("cIptvDevice::SignalQuality(%d)\n", deviceIndex);
|
||||||
|
return (100);
|
||||||
|
}
|
||||||
|
|
||||||
bool cIptvDevice::ProvidesSource(int Source) const
|
bool cIptvDevice::ProvidesSource(int Source) const
|
||||||
{
|
{
|
||||||
debug("cIptvDevice::ProvidesSource(%d)\n", deviceIndex);
|
debug("cIptvDevice::ProvidesSource(%d)\n", deviceIndex);
|
||||||
return ((Source & cSource::st_Mask) == (IPTV_SOURCE_CHARACTER << 24));
|
return (cSource::IsType(Source, IPTV_SOURCE_CHARACTER));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIptvDevice::ProvidesTransponder(const cChannel *Channel) const
|
bool cIptvDevice::ProvidesTransponder(const cChannel *Channel) const
|
||||||
@@ -193,16 +224,30 @@ bool cIptvDevice::ProvidesTransponder(const cChannel *Channel) const
|
|||||||
bool cIptvDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
bool cIptvDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsDetachReceivers) const
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
bool hasPriority = Priority == IDLEPRIORITY || Priority > this->Priority();
|
||||||
bool needsDetachReceivers = false;
|
bool needsDetachReceivers = false;
|
||||||
|
|
||||||
debug("cIptvDevice::ProvidesChannel(%d)\n", deviceIndex);
|
debug("cIptvDevice::ProvidesChannel(%d)\n", deviceIndex);
|
||||||
if (ProvidesTransponder(Channel))
|
|
||||||
result = true;
|
if (Channel && ProvidesTransponder(Channel)) {
|
||||||
|
result = hasPriority;
|
||||||
|
if (Receiving()) {
|
||||||
|
if (Channel->GetChannelID() == channelId)
|
||||||
|
result = true;
|
||||||
|
else
|
||||||
|
needsDetachReceivers = Receiving();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (NeedsDetachReceivers)
|
if (NeedsDetachReceivers)
|
||||||
*NeedsDetachReceivers = needsDetachReceivers;
|
*NeedsDetachReceivers = needsDetachReceivers;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cIptvDevice::ProvidesEIT(void) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int cIptvDevice::NumProvidedSystems(void) const
|
int cIptvDevice::NumProvidedSystems(void) const
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
@@ -214,7 +259,7 @@ bool cIptvDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
cIptvTransponderParameters itp(Channel->Parameters());
|
cIptvTransponderParameters itp(Channel->Parameters());
|
||||||
|
|
||||||
debug("cIptvDevice::SetChannelDevice(%d)\n", deviceIndex);
|
debug("cIptvDevice::SetChannelDevice(%d)\n", deviceIndex);
|
||||||
|
|
||||||
if (isempty(itp.Address())) {
|
if (isempty(itp.Address())) {
|
||||||
error("Unrecognized IPTV address: %s", Channel->Parameters());
|
error("Unrecognized IPTV address: %s", Channel->Parameters());
|
||||||
return false;
|
return false;
|
||||||
@@ -240,10 +285,11 @@ bool cIptvDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
|||||||
sidScanEnabled = itp.SidScan() ? true : false;
|
sidScanEnabled = itp.SidScan() ? true : false;
|
||||||
pidScanEnabled = itp.PidScan() ? true : false;
|
pidScanEnabled = itp.PidScan() ? true : false;
|
||||||
if (pIptvStreamer->Set(itp.Address(), itp.Parameter(), deviceIndex, protocol)) {
|
if (pIptvStreamer->Set(itp.Address(), itp.Parameter(), deviceIndex, protocol)) {
|
||||||
|
channelId = Channel->GetChannelID();
|
||||||
if (sidScanEnabled && pSidScanner && IptvConfig.GetSectionFiltering())
|
if (sidScanEnabled && pSidScanner && IptvConfig.GetSectionFiltering())
|
||||||
pSidScanner->SetChannel(Channel);
|
pSidScanner->SetChannel(channelId);
|
||||||
if (pidScanEnabled && pPidScanner)
|
if (pidScanEnabled && pPidScanner)
|
||||||
pPidScanner->SetChannel(Channel);
|
pPidScanner->SetChannel(channelId);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -297,26 +343,37 @@ int cIptvDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
|
|||||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
||||||
if (!secfilters[i]) {
|
if (!secfilters[i]) {
|
||||||
//debug("cIptvDevice::OpenFilter(%d): Pid=%d Tid=%02X Mask=%02X Index=%d\n", deviceIndex, Pid, Tid, Mask, i);
|
//debug("cIptvDevice::OpenFilter(%d): Pid=%d Tid=%02X Mask=%02X Index=%d\n", deviceIndex, Pid, Tid, Mask, i);
|
||||||
secfilters[i] = new cIptvSectionFilter(deviceIndex, i, Pid, Tid, Mask);
|
secfilters[i] = new cIptvSectionFilter(deviceIndex, Pid, Tid, Mask);
|
||||||
return secfilters[i]->GetReadDesc();
|
if (secfilters[i])
|
||||||
|
return i;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No free filter slot found
|
// No free filter slot found
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cIptvDevice::ReadFilter(int Handle, void *Buffer, size_t Length)
|
||||||
|
{
|
||||||
|
// Lock
|
||||||
|
cMutexLock MutexLock(&mutex);
|
||||||
|
// ... and load
|
||||||
|
if (secfilters[Handle]) {
|
||||||
|
return secfilters[Handle]->Read(Buffer, Length);
|
||||||
|
//debug("cIptvDevice::ReadFilter(%d): %d %d\n", deviceIndex, Handle, Length);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void cIptvDevice::CloseFilter(int Handle)
|
void cIptvDevice::CloseFilter(int Handle)
|
||||||
{
|
{
|
||||||
// Lock
|
// Lock
|
||||||
cMutexLock MutexLock(&mutex);
|
cMutexLock MutexLock(&mutex);
|
||||||
// Search the filter for deletion
|
// ... and load
|
||||||
for (unsigned int i = 0; i < eMaxSecFilterCount; ++i) {
|
if (secfilters[Handle]) {
|
||||||
if (secfilters[i] && (Handle == secfilters[i]->GetReadDesc())) {
|
//debug("cIptvDevice::CloseFilter(%d): %d\n", deviceIndex, Handle);
|
||||||
//debug("cIptvDevice::CloseFilter(%d): %d\n", deviceIndex, Handle);
|
DeleteFilter(Handle);
|
||||||
DeleteFilter(i);
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIptvDevice::OpenDvr(void)
|
bool cIptvDevice::OpenDvr(void)
|
||||||
@@ -349,6 +406,12 @@ bool cIptvDevice::HasLock(int TimeoutMs)
|
|||||||
return (!IsBuffering());
|
return (!IsBuffering());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cIptvDevice::HasInternalCam(void)
|
||||||
|
{
|
||||||
|
//debug("cIptvDevice::HasInternalCam(%d)\n", deviceIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void cIptvDevice::ResetBuffering(void)
|
void cIptvDevice::ResetBuffering(void)
|
||||||
{
|
{
|
||||||
debug("cIptvDevice::ResetBuffering(%d)\n", deviceIndex);
|
debug("cIptvDevice::ResetBuffering(%d)\n", deviceIndex);
|
||||||
@@ -370,7 +433,6 @@ bool cIptvDevice::IsBuffering(void)
|
|||||||
|
|
||||||
bool cIptvDevice::GetTSPacket(uchar *&Data)
|
bool cIptvDevice::GetTSPacket(uchar *&Data)
|
||||||
{
|
{
|
||||||
int Count = 0;
|
|
||||||
//debug("cIptvDevice::GetTSPacket(%d)\n", deviceIndex);
|
//debug("cIptvDevice::GetTSPacket(%d)\n", deviceIndex);
|
||||||
if (tsBuffer && !IsBuffering()) {
|
if (tsBuffer && !IsBuffering()) {
|
||||||
if (isPacketDelivered) {
|
if (isPacketDelivered) {
|
||||||
@@ -379,6 +441,7 @@ bool cIptvDevice::GetTSPacket(uchar *&Data)
|
|||||||
// Update buffer statistics
|
// Update buffer statistics
|
||||||
AddBufferStatistic(TS_SIZE, tsBuffer->Available());
|
AddBufferStatistic(TS_SIZE, tsBuffer->Available());
|
||||||
}
|
}
|
||||||
|
int Count = 0;
|
||||||
uchar *p = tsBuffer->Get(Count);
|
uchar *p = tsBuffer->Get(Count);
|
||||||
if (p && Count >= TS_SIZE) {
|
if (p && Count >= TS_SIZE) {
|
||||||
if (*p != TS_SYNC_BYTE) {
|
if (*p != TS_SYNC_BYTE) {
|
||||||
|
|||||||
16
device.h
16
device.h
@@ -41,6 +41,7 @@ private:
|
|||||||
bool pidScanEnabled;
|
bool pidScanEnabled;
|
||||||
cRingBufferLinear *tsBuffer;
|
cRingBufferLinear *tsBuffer;
|
||||||
int tsBufferPrefill;
|
int tsBufferPrefill;
|
||||||
|
tChannelID channelId;
|
||||||
cIptvProtocolUdp *pUdpProtocol;
|
cIptvProtocolUdp *pUdpProtocol;
|
||||||
cIptvProtocolHttp *pHttpProtocol;
|
cIptvProtocolHttp *pHttpProtocol;
|
||||||
cIptvProtocolFile *pFileProtocol;
|
cIptvProtocolFile *pFileProtocol;
|
||||||
@@ -49,7 +50,7 @@ private:
|
|||||||
cPidScanner *pPidScanner;
|
cPidScanner *pPidScanner;
|
||||||
cSidScanner *pSidScanner;
|
cSidScanner *pSidScanner;
|
||||||
cMutex mutex;
|
cMutex mutex;
|
||||||
cIptvSectionFilter* secfilters[eMaxSecFilterCount];
|
cIptvSectionFilter *secfilters[eMaxSecFilterCount];
|
||||||
|
|
||||||
// constructor & destructor
|
// constructor & destructor
|
||||||
public:
|
public:
|
||||||
@@ -74,11 +75,19 @@ private:
|
|||||||
bool DeleteFilter(unsigned int Index);
|
bool DeleteFilter(unsigned int Index);
|
||||||
bool IsBlackListed(u_short Pid, u_char Tid, u_char Mask) const;
|
bool IsBlackListed(u_short Pid, u_char Tid, u_char Mask) const;
|
||||||
|
|
||||||
|
// for channel info
|
||||||
|
public:
|
||||||
|
virtual cString DeviceType(void) const;
|
||||||
|
virtual cString DeviceName(void) const;
|
||||||
|
virtual int SignalStrength(void) const;
|
||||||
|
virtual int SignalQuality(void) const;
|
||||||
|
|
||||||
// for channel selection
|
// for channel selection
|
||||||
public:
|
public:
|
||||||
virtual bool ProvidesSource(int Source) const;
|
virtual bool ProvidesSource(int Source) const;
|
||||||
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
virtual bool ProvidesTransponder(const cChannel *Channel) const;
|
||||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
|
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsDetachReceivers = NULL) const;
|
||||||
|
virtual bool ProvidesEIT(void) const;
|
||||||
virtual int NumProvidedSystems(void) const;
|
virtual int NumProvidedSystems(void) const;
|
||||||
protected:
|
protected:
|
||||||
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
||||||
@@ -93,11 +102,16 @@ protected:
|
|||||||
// for section filtering
|
// for section filtering
|
||||||
public:
|
public:
|
||||||
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
|
virtual int OpenFilter(u_short Pid, u_char Tid, u_char Mask);
|
||||||
|
virtual int ReadFilter(int Handle, void *Buffer, size_t Length);
|
||||||
virtual void CloseFilter(int Handle);
|
virtual void CloseFilter(int Handle);
|
||||||
|
|
||||||
// for transponder lock
|
// for transponder lock
|
||||||
public:
|
public:
|
||||||
virtual bool HasLock(int);
|
virtual bool HasLock(int);
|
||||||
|
|
||||||
|
// for common interface
|
||||||
|
public:
|
||||||
|
virtual bool HasInternalCam(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __IPTV_DEVICE_H
|
#endif // __IPTV_DEVICE_H
|
||||||
|
|||||||
27
iptv.c
27
iptv.c
@@ -11,12 +11,17 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "iptvservice.h"
|
||||||
|
|
||||||
#if defined(APIVERSNUM) && APIVERSNUM < 10713
|
#if defined(APIVERSNUM) && APIVERSNUM < 10730
|
||||||
#error "VDR-1.7.13 API version or greater is required!"
|
#error "VDR-1.7.30 API version or greater is required!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const char VERSION[] = "0.4.1";
|
#ifndef GITVERSION
|
||||||
|
#define GITVERSION ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char VERSION[] = "1.1.0" GITVERSION;
|
||||||
static const char DESCRIPTION[] = trNOOP("Experience the IPTV");
|
static const char DESCRIPTION[] = trNOOP("Experience the IPTV");
|
||||||
|
|
||||||
class cPluginIptv : public cPlugin {
|
class cPluginIptv : public cPlugin {
|
||||||
@@ -94,7 +99,7 @@ bool cPluginIptv::Initialize(void)
|
|||||||
{
|
{
|
||||||
debug("cPluginIptv::Initialize()\n");
|
debug("cPluginIptv::Initialize()\n");
|
||||||
// Initialize any background activities the plugin shall perform.
|
// Initialize any background activities the plugin shall perform.
|
||||||
IptvConfig.SetConfigDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N));
|
IptvConfig.SetConfigDirectory(cPlugin::ResourceDirectory(PLUGIN_NAME_I18N));
|
||||||
return cIptvDevice::Initialize(deviceCount);
|
return cIptvDevice::Initialize(deviceCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,8 +201,18 @@ bool cPluginIptv::SetupParse(const char *Name, const char *Value)
|
|||||||
|
|
||||||
bool cPluginIptv::Service(const char *Id, void *Data)
|
bool cPluginIptv::Service(const char *Id, void *Data)
|
||||||
{
|
{
|
||||||
//debug("cPluginIptv::Service()\n");
|
debug("cPluginIptv::Service()\n");
|
||||||
// Handle custom service requests from other plugins
|
if (strcmp(Id,"IptvService-v1.0") == 0) {
|
||||||
|
if (Data) {
|
||||||
|
IptvService_v1_0 *data = (IptvService_v1_0*)Data;
|
||||||
|
cIptvDevice *dev = cIptvDevice::GetIptvDevice(data->cardIndex);
|
||||||
|
if (!dev)
|
||||||
|
return false;
|
||||||
|
data->protocol = dev->GetInformation(IPTV_DEVICE_INFO_PROTOCOL);
|
||||||
|
data->bitrate = dev->GetInformation(IPTV_DEVICE_INFO_BITRATE);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ case ${PARAMETER} in
|
|||||||
URL=""
|
URL=""
|
||||||
WIDTH=720
|
WIDTH=720
|
||||||
HEIGHT=576
|
HEIGHT=576
|
||||||
|
FPS=25
|
||||||
;;
|
;;
|
||||||
2)
|
2)
|
||||||
URL=""
|
URL=""
|
||||||
@@ -66,6 +67,9 @@ TRANSCODE_OPTS="vcodec=${VCODEC},acodec=${ACODEC},vb=${VBITRATE},ab=${ABITRATE}"
|
|||||||
if [ -n "${WIDTH}" -a -n "${HEIGHT}" ] ; then
|
if [ -n "${WIDTH}" -a -n "${HEIGHT}" ] ; then
|
||||||
TRANSCODE_OPTS="${TRANSCODE_OPTS},width=${WIDTH},height=${HEIGHT}"
|
TRANSCODE_OPTS="${TRANSCODE_OPTS},width=${WIDTH},height=${HEIGHT}"
|
||||||
fi
|
fi
|
||||||
|
if [ -n "${FPS}" ] ; then
|
||||||
|
TRANSCODE_OPTS="${TRANSCODE_OPTS},fps=${FPS}"
|
||||||
|
fi
|
||||||
|
|
||||||
# Create unique pids for the stream
|
# Create unique pids for the stream
|
||||||
let VPID=${PARAMETER}+1
|
let VPID=${PARAMETER}+1
|
||||||
|
|||||||
22
iptvservice.h
Normal file
22
iptvservice.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* iptvservice.h: IPTV plugin for the Video Disk Recorder
|
||||||
|
*
|
||||||
|
* See the README file for copyright information and how to reach the author.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __IPTVSERVICE_H
|
||||||
|
#define __IPTVSERVICE_H
|
||||||
|
|
||||||
|
#include <vdr/tools.h>
|
||||||
|
|
||||||
|
#define stIptv ('I' << 24)
|
||||||
|
|
||||||
|
struct IptvService_v1_0 {
|
||||||
|
unsigned int cardIndex;
|
||||||
|
cString protocol;
|
||||||
|
cString bitrate;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__IPTVSERVICE_H
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
diff -Nru vdr-1.7.13-vanilla/pat.c vdr-1.7.13-disable_ca_updates/pat.c
|
|
||||||
--- vdr-1.7.13-vanilla/pat.c 2010-01-01 17:40:05.000000000 +0200
|
|
||||||
+++ vdr-1.7.13-disable_ca_updates/pat.c 2010-03-09 16:33:03.000000000 +0200
|
|
||||||
@@ -458,6 +458,7 @@
|
|
||||||
}
|
|
||||||
if (Setup.UpdateChannels >= 2) {
|
|
||||||
Channel->SetPids(Vpid, Ppid, Vtype, Apids, ALangs, Dpids, DLangs, Spids, SLangs, Tpid);
|
|
||||||
+ if ((Channel->Source() & cSource::st_Mask) != ('I' << 24))
|
|
||||||
Channel->SetCaIds(CaDescriptors->CaIds());
|
|
||||||
Channel->SetSubtitlingDescriptors(SubtitlingTypes, CompositionPageIds, AncillaryPageIds);
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
diff -Nru vdr-1.7.13-vanilla/eitscan.c vdr-1.7.13-disable_eitscan/eitscan.c
|
|
||||||
--- vdr-1.7.13-vanilla/eitscan.c 2010-02-07 14:12:05.000000000 +0200
|
|
||||||
+++ vdr-1.7.13-disable_eitscan/eitscan.c 2010-03-09 16:30:02.000000000 +0200
|
|
||||||
@@ -146,7 +146,7 @@
|
|
||||||
if (Device) {
|
|
||||||
for (cScanData *ScanData = scanList->First(); ScanData; ScanData = scanList->Next(ScanData)) {
|
|
||||||
const cChannel *Channel = ScanData->GetChannel();
|
|
||||||
- if (Channel) {
|
|
||||||
+ if (Channel && ((Channel->Source() & cSource::st_Mask) != ('I' << 24))) {
|
|
||||||
if (!Channel->Ca() || Channel->Ca() == Device->DeviceNumber() + 1 || Channel->Ca() >= CA_ENCRYPTED_MIN) {
|
|
||||||
if (Device->ProvidesTransponder(Channel)) {
|
|
||||||
if (!Device->Receiving()) {
|
|
||||||
37
pidscanner.c
37
pidscanner.c
@@ -13,8 +13,9 @@
|
|||||||
#define PIDSCANNER_VPID_COUNT 5 /* minimum count of video pid samples for pid detection */
|
#define PIDSCANNER_VPID_COUNT 5 /* minimum count of video pid samples for pid detection */
|
||||||
#define PIDSCANNER_PID_DELTA_COUNT 100 /* minimum count of pid samples for audio/video only pid detection */
|
#define PIDSCANNER_PID_DELTA_COUNT 100 /* minimum count of pid samples for audio/video only pid detection */
|
||||||
|
|
||||||
cPidScanner::cPidScanner(void)
|
cPidScanner::cPidScanner(void)
|
||||||
: timeout(0),
|
: timeout(0),
|
||||||
|
channelId(tChannelID::InvalidID),
|
||||||
process(true),
|
process(true),
|
||||||
Vpid(0xFFFF),
|
Vpid(0xFFFF),
|
||||||
Apid(0xFFFF),
|
Apid(0xFFFF),
|
||||||
@@ -22,24 +23,17 @@ cPidScanner::cPidScanner(void)
|
|||||||
numApids(0)
|
numApids(0)
|
||||||
{
|
{
|
||||||
debug("cPidScanner::cPidScanner()\n");
|
debug("cPidScanner::cPidScanner()\n");
|
||||||
channel = cChannel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cPidScanner::~cPidScanner()
|
cPidScanner::~cPidScanner()
|
||||||
{
|
{
|
||||||
debug("cPidScanner::~cPidScanner()\n");
|
debug("cPidScanner::~cPidScanner()\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void cPidScanner::SetChannel(const cChannel *Channel)
|
void cPidScanner::SetChannel(const tChannelID &ChannelId)
|
||||||
{
|
{
|
||||||
if (Channel) {
|
debug("cPidScanner::SetChannel(): %s\n", *ChannelId.ToString());
|
||||||
debug("cPidScanner::SetChannel(): %s\n", Channel->Parameters());
|
channelId = ChannelId;
|
||||||
channel = *Channel;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
debug("cPidScanner::SetChannel()\n");
|
|
||||||
channel = cChannel();
|
|
||||||
}
|
|
||||||
Vpid = 0xFFFF;
|
Vpid = 0xFFFF;
|
||||||
numVpids = 0;
|
numVpids = 0;
|
||||||
Apid = 0xFFFF;
|
Apid = 0xFFFF;
|
||||||
@@ -119,14 +113,17 @@ void cPidScanner::Process(const uint8_t* buf)
|
|||||||
timeout.Set(PIDSCANNER_TIMEOUT_IN_MS);
|
timeout.Set(PIDSCANNER_TIMEOUT_IN_MS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cChannel *IptvChannel = Channels.GetByChannelID(channel.GetChannelID());
|
cChannel *IptvChannel = Channels.GetByChannelID(channelId);
|
||||||
if (IptvChannel) {
|
if (IptvChannel) {
|
||||||
int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
|
int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
|
||||||
|
int Atypes[MAXAPIDS + 1] = { 0 };
|
||||||
int Dpids[MAXDPIDS + 1] = { 0 };
|
int Dpids[MAXDPIDS + 1] = { 0 };
|
||||||
|
int Dtypes[MAXDPIDS + 1] = { 0 };
|
||||||
int Spids[MAXSPIDS + 1] = { 0 };
|
int Spids[MAXSPIDS + 1] = { 0 };
|
||||||
char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
|
char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
|
||||||
char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
|
char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
|
||||||
char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
|
char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
|
||||||
|
int Vtype = IptvChannel->Vtype();
|
||||||
int Ppid = IptvChannel->Ppid();
|
int Ppid = IptvChannel->Ppid();
|
||||||
int Tpid = IptvChannel->Tpid();
|
int Tpid = IptvChannel->Tpid();
|
||||||
bool foundApid = false;
|
bool foundApid = false;
|
||||||
@@ -134,20 +131,24 @@ void cPidScanner::Process(const uint8_t* buf)
|
|||||||
Vpid = 0; // No detected video pid
|
Vpid = 0; // No detected video pid
|
||||||
else if (numApids < PIDSCANNER_APID_COUNT)
|
else if (numApids < PIDSCANNER_APID_COUNT)
|
||||||
Apid = 0; // No detected audio pid
|
Apid = 0; // No detected audio pid
|
||||||
for (unsigned int i = 1; i < MAXAPIDS; ++i) {
|
for (unsigned int i = 0; i < MAXAPIDS; ++i) {
|
||||||
Apids[i] = IptvChannel->Apid(i);
|
Apids[i] = IptvChannel->Apid(i);
|
||||||
|
Atypes[i] = IptvChannel->Atype(i);
|
||||||
if (Apids[i] && (Apids[i] == Apid))
|
if (Apids[i] && (Apids[i] == Apid))
|
||||||
foundApid = true;
|
foundApid = true;
|
||||||
}
|
}
|
||||||
if (!foundApid)
|
if (!foundApid) {
|
||||||
Apids[0] = Apid;
|
Apids[0] = Apid;
|
||||||
for (unsigned int i = 0; i < MAXDPIDS; ++i)
|
Atypes[0] = 4;
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i < MAXDPIDS; ++i) {
|
||||||
Dpids[i] = IptvChannel->Dpid(i);
|
Dpids[i] = IptvChannel->Dpid(i);
|
||||||
|
Dtypes[i] = IptvChannel->Dtype(i);
|
||||||
|
}
|
||||||
for (unsigned int i = 0; i < MAXSPIDS; ++i)
|
for (unsigned int i = 0; i < MAXSPIDS; ++i)
|
||||||
Spids[i] = IptvChannel->Spid(i);
|
Spids[i] = IptvChannel->Spid(i);
|
||||||
debug("cPidScanner::Process(): Vpid=0x%04X, Apid=0x%04X\n", Vpid, Apid);
|
debug("cPidScanner::Process(): Vpid=0x%04X, Apid=0x%04X\n", Vpid, Apid);
|
||||||
int Vtype = IptvChannel->Vtype();
|
IptvChannel->SetPids(Vpid, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid);
|
||||||
IptvChannel->SetPids(Vpid, Ppid, Vtype, Apids, ALangs, Dpids, DLangs, Spids, SLangs, Tpid);
|
|
||||||
}
|
}
|
||||||
Channels.Unlock();
|
Channels.Unlock();
|
||||||
process = false;
|
process = false;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
class cPidScanner {
|
class cPidScanner {
|
||||||
private:
|
private:
|
||||||
cTimeMs timeout;
|
cTimeMs timeout;
|
||||||
cChannel channel;
|
tChannelID channelId;
|
||||||
bool process;
|
bool process;
|
||||||
int Vpid;
|
int Vpid;
|
||||||
int Apid;
|
int Apid;
|
||||||
@@ -24,7 +24,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
cPidScanner(void);
|
cPidScanner(void);
|
||||||
~cPidScanner();
|
~cPidScanner();
|
||||||
void SetChannel(const cChannel *Channel);
|
void SetChannel(const tChannelID &ChannelId);
|
||||||
void Process(const uint8_t* buf);
|
void Process(const uint8_t* buf);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
15
po/de_DE.po
15
po/de_DE.po
@@ -5,12 +5,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-04 18:12+0200\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2007-10-29 21:19+0100\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: Tobias Grimm <tg@e-tobi.net>\n"
|
"Last-Translator: Tobias Grimm <tg@e-tobi.net>\n"
|
||||||
"Language-Team: German\n"
|
"Language-Team: German <vdr@linuxtv.org>\n"
|
||||||
|
"Language: de\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -135,8 +136,8 @@ msgstr "Tid"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Rid"
|
msgstr "Rid"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Scanne SID"
|
msgstr "Scanne Section IDS"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Scanne PIDS"
|
msgstr "Scanne PIDS"
|
||||||
|
|||||||
15
po/fi_FI.po
15
po/fi_FI.po
@@ -5,12 +5,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-04 18:12+0200\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2007-08-12 23:22+0300\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: Rolf Ahrenberg\n"
|
"Last-Translator: Rolf Ahrenberg\n"
|
||||||
"Language-Team: <vdr@linuxtv.org>\n"
|
"Language-Team: Finnish <vdr@linuxtv.org>\n"
|
||||||
|
"Language: fi\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -150,8 +151,8 @@ msgstr "Lähete-ID"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Radio-ID"
|
msgstr "Radio-ID"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Etsi palvelu-ID"
|
msgstr "Etsi sektiotunnisteet"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Etsi pidit"
|
msgstr "Etsi pidit"
|
||||||
|
|||||||
15
po/fr_FR.po
15
po/fr_FR.po
@@ -6,12 +6,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-04 18:12+0200\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2008-01-26 13:14+0100\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: NIVAL Michaël <mnival@club-internet.fr>\n"
|
"Last-Translator: NIVAL Michaël <mnival@club-internet.fr>\n"
|
||||||
"Language-Team: French\n"
|
"Language-Team: French <vdr@linuxtv.org>\n"
|
||||||
|
"Language: fr\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -152,8 +153,8 @@ msgstr "Tid"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Rid"
|
msgstr "Rid"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Scanne les SID"
|
msgstr "Scanne les section ID"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Scanne les PID"
|
msgstr "Scanne les PID"
|
||||||
|
|||||||
15
po/it_IT.po
15
po/it_IT.po
@@ -5,12 +5,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-04 18:12+0200\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2008-07-13 03:28+0100\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n"
|
||||||
"Language-Team: Italian\n"
|
"Language-Team: Italian <vdr@linuxtv.org>\n"
|
||||||
|
"Language: it\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -151,8 +152,8 @@ msgstr "Tid"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Rid"
|
msgstr "Rid"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Scansione Sid"
|
msgstr "Scansione Section Ids"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Scansione Pids"
|
msgstr "Scansione Pids"
|
||||||
|
|||||||
15
po/nl_NL.po
15
po/nl_NL.po
@@ -5,12 +5,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-05 09:42+0100\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2007-10-29 21:19+0100\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: Carel\n"
|
"Last-Translator: Carel\n"
|
||||||
"Language-Team: Dutch\n"
|
"Language-Team: Dutch <vdr@linuxtv.org>\n"
|
||||||
|
"Language: nl\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: text/plain; charset=utf-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -150,8 +151,8 @@ msgstr "Tid"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Rid"
|
msgstr "Rid"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Scan SID"
|
msgstr "Scan section IDS"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Scan PIDS"
|
msgstr "Scan PIDS"
|
||||||
|
|||||||
15
po/ru_RU.po
15
po/ru_RU.po
@@ -5,12 +5,13 @@
|
|||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: iptv 0.4.0\n"
|
"Project-Id-Version: vdr-iptv 1.0.0\n"
|
||||||
"Report-Msgid-Bugs-To: Rolf Ahrenberg\n"
|
"Report-Msgid-Bugs-To: <see README>\n"
|
||||||
"POT-Creation-Date: 2010-03-04 18:12+0200\n"
|
"POT-Creation-Date: 2012-06-03 06:03+0300\n"
|
||||||
"PO-Revision-Date: 2008-03-16 12:14+0100\n"
|
"PO-Revision-Date: 2012-06-03 06:03+0300\n"
|
||||||
"Last-Translator: Alexander Gross <Bikalexander@gmail.com>\n"
|
"Last-Translator: Alexander Gross <Bikalexander@gmail.com>\n"
|
||||||
"Language-Team: Russian <de@li.org>\n"
|
"Language-Team: Russian <vdr@linuxtv.org>\n"
|
||||||
|
"Language: ru\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
@@ -136,8 +137,8 @@ msgstr "Tid"
|
|||||||
msgid "Rid"
|
msgid "Rid"
|
||||||
msgstr "Rid"
|
msgstr "Rid"
|
||||||
|
|
||||||
msgid "Scan sid"
|
msgid "Scan section ids"
|
||||||
msgstr "Сканировать SID"
|
msgstr "Сканировать section ids"
|
||||||
|
|
||||||
msgid "Scan pids"
|
msgid "Scan pids"
|
||||||
msgstr "Сканировать пиды"
|
msgstr "Сканировать пиды"
|
||||||
|
|||||||
@@ -19,10 +19,15 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "protocolext.h"
|
#include "protocolext.h"
|
||||||
|
|
||||||
|
#ifndef EXTSHELL
|
||||||
|
#define EXTSHELL "/bin/bash"
|
||||||
|
#endif
|
||||||
|
|
||||||
cIptvProtocolExt::cIptvProtocolExt()
|
cIptvProtocolExt::cIptvProtocolExt()
|
||||||
: pid(-1),
|
: pid(-1),
|
||||||
scriptFile(""),
|
scriptFile(""),
|
||||||
scriptParameter(0)
|
scriptParameter(0),
|
||||||
|
streamPort(0)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolExt::cIptvProtocolExt()\n");
|
debug("cIptvProtocolExt::cIptvProtocolExt()\n");
|
||||||
}
|
}
|
||||||
@@ -38,6 +43,8 @@ void cIptvProtocolExt::ExecuteScript(void)
|
|||||||
{
|
{
|
||||||
debug("cIptvProtocolExt::ExecuteScript()\n");
|
debug("cIptvProtocolExt::ExecuteScript()\n");
|
||||||
// Check if already executing
|
// Check if already executing
|
||||||
|
if (isActive || isempty(scriptFile))
|
||||||
|
return;
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
error("Cannot execute script!");
|
error("Cannot execute script!");
|
||||||
return;
|
return;
|
||||||
@@ -51,9 +58,11 @@ void cIptvProtocolExt::ExecuteScript(void)
|
|||||||
for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
|
for (int i = STDERR_FILENO + 1; i < MaxPossibleFileDescriptors; i++)
|
||||||
close(i);
|
close(i);
|
||||||
// Execute the external script
|
// Execute the external script
|
||||||
cString cmd = cString::sprintf("%s %d %d", *scriptFile, scriptParameter, socketPort);
|
cString cmd = cString::sprintf("%s %d %d", *scriptFile, scriptParameter, streamPort);
|
||||||
debug("cIptvProtocolExt::ExecuteScript(child): %s\n", *cmd);
|
debug("cIptvProtocolExt::ExecuteScript(child): %s\n", *cmd);
|
||||||
if (execl("/bin/sh", "sh", "-c", *cmd, (char *)NULL) == -1) {
|
// Create a new session for a process group
|
||||||
|
ERROR_IF_RET(setsid() == -1, "setsid()", _exit(-1));
|
||||||
|
if (execl(EXTSHELL, "sh", "-c", *cmd, (char *)NULL) == -1) {
|
||||||
error("Script execution failed: %s", *cmd);
|
error("Script execution failed: %s", *cmd);
|
||||||
_exit(-1);
|
_exit(-1);
|
||||||
}
|
}
|
||||||
@@ -67,30 +76,41 @@ void cIptvProtocolExt::ExecuteScript(void)
|
|||||||
void cIptvProtocolExt::TerminateScript(void)
|
void cIptvProtocolExt::TerminateScript(void)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolExt::TerminateScript(): pid=%d\n", pid);
|
debug("cIptvProtocolExt::TerminateScript(): pid=%d\n", pid);
|
||||||
|
if (!isActive || isempty(scriptFile))
|
||||||
|
return;
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
const unsigned int timeoutms = 100;
|
const unsigned int timeoutms = 100;
|
||||||
unsigned int waitms = 0;
|
unsigned int waitms = 0;
|
||||||
siginfo_t waitStatus;
|
|
||||||
bool waitOver = false;
|
bool waitOver = false;
|
||||||
// signal and wait for termination
|
// Signal and wait for termination
|
||||||
int retval = kill(pid, SIGINT);
|
int retval = killpg(pid, SIGINT);
|
||||||
ERROR_IF_RET(retval < 0, "kill()", waitOver = true);
|
ERROR_IF_RET(retval < 0, "kill()", waitOver = true);
|
||||||
while (!waitOver) {
|
while (!waitOver) {
|
||||||
retval = 0;
|
retval = 0;
|
||||||
waitms += timeoutms;
|
waitms += timeoutms;
|
||||||
if ((waitms % 2000) == 0) {
|
if ((waitms % 2000) == 0) {
|
||||||
error("Script '%s' won't terminate - killing it!", *scriptFile);
|
error("Script '%s' won't terminate - killing it!", *scriptFile);
|
||||||
kill(pid, SIGKILL);
|
killpg(pid, SIGKILL);
|
||||||
}
|
}
|
||||||
// Clear wait status to make sure child exit status is accessible
|
// Clear wait status to make sure child exit status is accessible
|
||||||
|
// and wait for child termination
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
int waitStatus = 0;
|
||||||
|
retval = waitpid(pid, &waitStatus, WNOHANG);
|
||||||
|
#else // __FreeBSD__
|
||||||
|
siginfo_t waitStatus;
|
||||||
memset(&waitStatus, '\0', sizeof(waitStatus));
|
memset(&waitStatus, '\0', sizeof(waitStatus));
|
||||||
// Wait for child termination
|
|
||||||
retval = waitid(P_PID, pid, &waitStatus, (WNOHANG | WEXITED));
|
retval = waitid(P_PID, pid, &waitStatus, (WNOHANG | WEXITED));
|
||||||
|
#endif // __FreeBSD__
|
||||||
ERROR_IF_RET(retval < 0, "waitid()", waitOver = true);
|
ERROR_IF_RET(retval < 0, "waitid()", waitOver = true);
|
||||||
// These are the acceptable conditions under which child exit is
|
// These are the acceptable conditions under which child exit is
|
||||||
// regarded as successful
|
// regarded as successful
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
if (retval > 0 && (WIFEXITED(waitStatus) || WIFSIGNALED(waitStatus))) {
|
||||||
|
#else // __FreeBSD__
|
||||||
if (!retval && waitStatus.si_pid && (waitStatus.si_pid == pid) &&
|
if (!retval && waitStatus.si_pid && (waitStatus.si_pid == pid) &&
|
||||||
((waitStatus.si_code == CLD_EXITED) || (waitStatus.si_code == CLD_KILLED))) {
|
((waitStatus.si_code == CLD_EXITED) || (waitStatus.si_code == CLD_KILLED))) {
|
||||||
|
#endif // __FreeBSD__
|
||||||
debug("Child (%d) exited as expected\n", pid);
|
debug("Child (%d) exited as expected\n", pid);
|
||||||
waitOver = true;
|
waitOver = true;
|
||||||
}
|
}
|
||||||
@@ -109,7 +129,7 @@ bool cIptvProtocolExt::Open(void)
|
|||||||
if (!strlen(*scriptFile))
|
if (!strlen(*scriptFile))
|
||||||
return false;
|
return false;
|
||||||
// Create the listening socket
|
// Create the listening socket
|
||||||
OpenSocket(socketPort);
|
OpenSocket(streamPort);
|
||||||
// Execute the external script
|
// Execute the external script
|
||||||
ExecuteScript();
|
ExecuteScript();
|
||||||
isActive = true;
|
isActive = true;
|
||||||
@@ -119,11 +139,11 @@ bool cIptvProtocolExt::Open(void)
|
|||||||
bool cIptvProtocolExt::Close(void)
|
bool cIptvProtocolExt::Close(void)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolExt::Close()\n");
|
debug("cIptvProtocolExt::Close()\n");
|
||||||
// Close the socket
|
|
||||||
CloseSocket();
|
|
||||||
// Terminate the external script
|
// Terminate the external script
|
||||||
TerminateScript();
|
TerminateScript();
|
||||||
isActive = false;
|
isActive = false;
|
||||||
|
// Close the socket
|
||||||
|
CloseSocket();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +165,7 @@ bool cIptvProtocolExt::Set(const char* Location, const int Parameter, const int
|
|||||||
}
|
}
|
||||||
scriptParameter = Parameter;
|
scriptParameter = Parameter;
|
||||||
// Update listen port
|
// Update listen port
|
||||||
socketPort = IptvConfig.GetExtProtocolBasePort() + Index;
|
streamPort = IptvConfig.GetExtProtocolBasePort() + Index;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ private:
|
|||||||
int pid;
|
int pid;
|
||||||
cString scriptFile;
|
cString scriptFile;
|
||||||
int scriptParameter;
|
int scriptParameter;
|
||||||
|
int streamPort;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void TerminateScript(void);
|
void TerminateScript(void);
|
||||||
|
|||||||
106
protocolhttp.c
106
protocolhttp.c
@@ -19,10 +19,11 @@
|
|||||||
#include "protocolhttp.h"
|
#include "protocolhttp.h"
|
||||||
|
|
||||||
cIptvProtocolHttp::cIptvProtocolHttp()
|
cIptvProtocolHttp::cIptvProtocolHttp()
|
||||||
|
: streamAddr(strdup("")),
|
||||||
|
streamPath(strdup("/")),
|
||||||
|
streamPort(0)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolHttp::cIptvProtocolHttp()\n");
|
debug("cIptvProtocolHttp::cIptvProtocolHttp()\n");
|
||||||
streamAddr = strdup("");
|
|
||||||
streamPath = strdup("/");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cIptvProtocolHttp::~cIptvProtocolHttp()
|
cIptvProtocolHttp::~cIptvProtocolHttp()
|
||||||
@@ -40,66 +41,29 @@ bool cIptvProtocolHttp::Connect(void)
|
|||||||
debug("cIptvProtocolHttp::Connect()\n");
|
debug("cIptvProtocolHttp::Connect()\n");
|
||||||
// Check that stream address is valid
|
// Check that stream address is valid
|
||||||
if (!isActive && !isempty(streamAddr) && !isempty(streamPath)) {
|
if (!isActive && !isempty(streamAddr) && !isempty(streamPath)) {
|
||||||
// Ensure that socket is valid
|
// Ensure that socket is valid and connect
|
||||||
OpenSocket(socketPort);
|
OpenSocket(streamPort, streamAddr);
|
||||||
|
if (!ConnectSocket()) {
|
||||||
// First try only the IP address
|
|
||||||
sockAddr.sin_addr.s_addr = inet_addr(streamAddr);
|
|
||||||
|
|
||||||
if (sockAddr.sin_addr.s_addr == INADDR_NONE) {
|
|
||||||
debug("Cannot convert %s directly to internet address\n", streamAddr);
|
|
||||||
|
|
||||||
// It may be a host name, get the name
|
|
||||||
struct hostent *host;
|
|
||||||
host = gethostbyname(streamAddr);
|
|
||||||
if (!host) {
|
|
||||||
char tmp[64];
|
|
||||||
error("%s is not valid address: %s", streamAddr, strerror_r(h_errno, tmp, sizeof(tmp)));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sockAddr.sin_addr.s_addr = inet_addr(*host->h_addr_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
int err = connect(socketDesc, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
|
|
||||||
// Non-blocking sockets always report in-progress error when connected
|
|
||||||
ERROR_IF_FUNC(err < 0 && errno != EINPROGRESS, "connect()", CloseSocket(), return false);
|
|
||||||
// Select with 800ms timeout on the socket completion, check if it is writable
|
|
||||||
int retval = select_single_desc(socketDesc, 800000, true);
|
|
||||||
if (retval < 0)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
// Select has returned. Get socket errors if there are any
|
|
||||||
int socketStatus = 0;
|
|
||||||
socklen_t len = sizeof(socketStatus);
|
|
||||||
getsockopt(socketDesc, SOL_SOCKET, SO_ERROR, &socketStatus, &len);
|
|
||||||
|
|
||||||
// If not any errors, then socket must be ready and connected
|
|
||||||
if (socketStatus != 0) {
|
|
||||||
char tmp[64];
|
|
||||||
error("Cannot connect to %s: %s", streamAddr, strerror_r(socketStatus, tmp, sizeof(tmp)));
|
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formulate and send HTTP request
|
// Formulate and send HTTP request
|
||||||
cString buffer = cString::sprintf("GET %s HTTP/1.1\r\n"
|
cString buffer = cString::sprintf("GET %s HTTP/1.1\r\n"
|
||||||
"Host: %s\r\n"
|
"Host: %s\r\n"
|
||||||
"User-Agent: vdr-iptv\r\n"
|
"User-Agent: vdr-%s/%s\r\n"
|
||||||
"Range: bytes=0-\r\n"
|
"Range: bytes=0-\r\n"
|
||||||
"Connection: Close\r\n"
|
"Connection: Close\r\n"
|
||||||
"\r\n", streamPath, streamAddr);
|
"\r\n", streamPath, streamAddr, PLUGIN_NAME_I18N, VERSION);
|
||||||
|
|
||||||
debug("Sending http request: %s\n", *buffer);
|
debug("Sending http request: %s\n", *buffer);
|
||||||
ssize_t err2 = send(socketDesc, buffer, strlen(buffer), 0);
|
if (!Write(*buffer, (unsigned int)strlen(*buffer))) {
|
||||||
ERROR_IF_FUNC(err2 < 0, "send()", CloseSocket(), return false);
|
CloseSocket();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// Now process headers
|
// Now process headers
|
||||||
if (!ProcessHeaders()) {
|
if (!ProcessHeaders()) {
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update active flag
|
// Update active flag
|
||||||
isActive = true;
|
isActive = true;
|
||||||
}
|
}
|
||||||
@@ -109,7 +73,6 @@ bool cIptvProtocolHttp::Connect(void)
|
|||||||
bool cIptvProtocolHttp::Disconnect(void)
|
bool cIptvProtocolHttp::Disconnect(void)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolHttp::Disconnect()\n");
|
debug("cIptvProtocolHttp::Disconnect()\n");
|
||||||
// Check that stream address is valid
|
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
// Close the socket
|
// Close the socket
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
@@ -125,24 +88,15 @@ bool cIptvProtocolHttp::GetHeaderLine(char* dest, unsigned int destLen,
|
|||||||
debug("cIptvProtocolHttp::GetHeaderLine()\n");
|
debug("cIptvProtocolHttp::GetHeaderLine()\n");
|
||||||
bool linefeed = false;
|
bool linefeed = false;
|
||||||
bool newline = false;
|
bool newline = false;
|
||||||
char buf[4096];
|
char *bufptr = dest;
|
||||||
char *bufptr = buf;
|
|
||||||
memset(buf, '\0', sizeof(buf));
|
|
||||||
recvLen = 0;
|
recvLen = 0;
|
||||||
|
|
||||||
|
if (!dest)
|
||||||
|
return false;
|
||||||
|
|
||||||
while (!newline || !linefeed) {
|
while (!newline || !linefeed) {
|
||||||
socklen_t addrlen = sizeof(sockAddr);
|
|
||||||
// Wait 500ms for data
|
// Wait 500ms for data
|
||||||
int retval = select_single_desc(socketDesc, 500000, false);
|
if (ReadChar(bufptr, 500)) {
|
||||||
// Check if error
|
|
||||||
if (retval < 0)
|
|
||||||
return false;
|
|
||||||
// Check if data available
|
|
||||||
else if (retval) {
|
|
||||||
ssize_t retval = recvfrom(socketDesc, bufptr, 1, MSG_DONTWAIT,
|
|
||||||
(struct sockaddr *)&sockAddr, &addrlen);
|
|
||||||
if (retval <= 0)
|
|
||||||
return false;
|
|
||||||
// Parsing end conditions, if line ends with \r\n
|
// Parsing end conditions, if line ends with \r\n
|
||||||
if (linefeed && *bufptr == '\n')
|
if (linefeed && *bufptr == '\n')
|
||||||
newline = true;
|
newline = true;
|
||||||
@@ -155,19 +109,18 @@ bool cIptvProtocolHttp::GetHeaderLine(char* dest, unsigned int destLen,
|
|||||||
++recvLen;
|
++recvLen;
|
||||||
}
|
}
|
||||||
++bufptr;
|
++bufptr;
|
||||||
// Check that buffers won't be exceeded
|
// Check that buffer won't be exceeded
|
||||||
if (recvLen >= sizeof(buf) || recvLen >= destLen) {
|
if (recvLen >= destLen) {
|
||||||
error("Header wouldn't fit into buffer\n");
|
error("Header wouldn't fit into buffer\n");
|
||||||
recvLen = 0;
|
recvLen = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
error("No HTTP response received\n");
|
error("No HTTP response received in 500ms\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memcpy(dest, buf, recvLen);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,22 +128,27 @@ bool cIptvProtocolHttp::ProcessHeaders(void)
|
|||||||
{
|
{
|
||||||
debug("cIptvProtocolHttp::ProcessHeaders()\n");
|
debug("cIptvProtocolHttp::ProcessHeaders()\n");
|
||||||
unsigned int lineLength = 0;
|
unsigned int lineLength = 0;
|
||||||
int response = 0;
|
int version = 0, response = 0;
|
||||||
bool responseFound = false;
|
bool responseFound = false;
|
||||||
|
char fmt[32];
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
|
|
||||||
|
// Generate HTTP response format string with 2 arguments
|
||||||
|
snprintf(fmt, sizeof(fmt), "HTTP/1.%%%zui %%%zui ", sizeof(version) - 1, sizeof(response) - 1);
|
||||||
|
|
||||||
while (!responseFound || lineLength != 0) {
|
while (!responseFound || lineLength != 0) {
|
||||||
memset(buf, '\0', sizeof(buf));
|
memset(buf, '\0', sizeof(buf));
|
||||||
if (!GetHeaderLine(buf, sizeof(buf), lineLength))
|
if (!GetHeaderLine(buf, sizeof(buf), lineLength))
|
||||||
return false;
|
return false;
|
||||||
if (!responseFound && sscanf(buf, "HTTP/1.%*i %i ", &response) != 1) {
|
if (!responseFound && sscanf(buf, fmt, &version, &response) != 2) {
|
||||||
error("Expected HTTP header not found\n");
|
error("Expected HTTP header not found\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
responseFound = true;
|
responseFound = true;
|
||||||
if (response != 200) {
|
// Allow only 'OK' and 'Partial Content'
|
||||||
error("%s\n", buf);
|
if ((response != 200) && (response != 206)) {
|
||||||
|
error("Invalid HTTP response (%d): %s\n", response, buf);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,8 +190,8 @@ bool cIptvProtocolHttp::Set(const char* Location, const int Parameter, const int
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
streamPath = strcpyrealloc(streamPath, "/");
|
streamPath = strcpyrealloc(streamPath, "/");
|
||||||
socketPort = Parameter;
|
streamPort = Parameter;
|
||||||
//debug("http://%s:%d%s\n", streamAddr, socketPort, streamPath);
|
//debug("http://%s:%d%s\n", streamAddr, streamPort, streamPath);
|
||||||
// Re-connect the socket
|
// Re-connect the socket
|
||||||
Connect();
|
Connect();
|
||||||
}
|
}
|
||||||
@@ -243,5 +201,5 @@ bool cIptvProtocolHttp::Set(const char* Location, const int Parameter, const int
|
|||||||
cString cIptvProtocolHttp::GetInformation(void)
|
cString cIptvProtocolHttp::GetInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cIptvProtocolHttp::GetInformation()");
|
//debug("cIptvProtocolHttp::GetInformation()");
|
||||||
return cString::sprintf("http://%s:%d%s", streamAddr, socketPort, streamPath);
|
return cString::sprintf("http://%s:%d%s", streamAddr, streamPort, streamPath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class cIptvProtocolHttp : public cIptvTcpSocket, public cIptvProtocolIf {
|
|||||||
private:
|
private:
|
||||||
char* streamAddr;
|
char* streamAddr;
|
||||||
char* streamPath;
|
char* streamPath;
|
||||||
|
int streamPort;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Connect(void);
|
bool Connect(void);
|
||||||
|
|||||||
106
protocoludp.c
106
protocoludp.c
@@ -19,9 +19,12 @@
|
|||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
|
||||||
cIptvProtocolUdp::cIptvProtocolUdp()
|
cIptvProtocolUdp::cIptvProtocolUdp()
|
||||||
|
: isIGMPv3(false),
|
||||||
|
sourceAddr(strdup("")),
|
||||||
|
streamAddr(strdup("")),
|
||||||
|
streamPort(0)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolUdp::cIptvProtocolUdp()\n");
|
debug("cIptvProtocolUdp::cIptvProtocolUdp()\n");
|
||||||
streamAddr = strdup("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cIptvProtocolUdp::~cIptvProtocolUdp()
|
cIptvProtocolUdp::~cIptvProtocolUdp()
|
||||||
@@ -31,63 +34,34 @@ cIptvProtocolUdp::~cIptvProtocolUdp()
|
|||||||
cIptvProtocolUdp::Close();
|
cIptvProtocolUdp::Close();
|
||||||
// Free allocated memory
|
// Free allocated memory
|
||||||
free(streamAddr);
|
free(streamAddr);
|
||||||
}
|
free(sourceAddr);
|
||||||
|
|
||||||
bool cIptvProtocolUdp::JoinMulticast(void)
|
|
||||||
{
|
|
||||||
debug("cIptvProtocolUdp::JoinMulticast()\n");
|
|
||||||
// Check that stream address is valid
|
|
||||||
if (!isActive && !isempty(streamAddr)) {
|
|
||||||
// Ensure that socket is valid
|
|
||||||
OpenSocket(socketPort);
|
|
||||||
// Join a new multicast group
|
|
||||||
struct ip_mreq mreq;
|
|
||||||
mreq.imr_multiaddr.s_addr = inet_addr(streamAddr);
|
|
||||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
|
||||||
int err = setsockopt(socketDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq,
|
|
||||||
sizeof(mreq));
|
|
||||||
ERROR_IF_RET(err < 0, "setsockopt()", return false);
|
|
||||||
// Update multicasting flag
|
|
||||||
isActive = true;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cIptvProtocolUdp::DropMulticast(void)
|
|
||||||
{
|
|
||||||
debug("cIptvProtocolUdp::DropMulticast()\n");
|
|
||||||
// Check that stream address is valid
|
|
||||||
if (isActive && !isempty(streamAddr)) {
|
|
||||||
// Ensure that socket is valid
|
|
||||||
OpenSocket(socketPort);
|
|
||||||
// Drop the multicast group
|
|
||||||
struct ip_mreq mreq;
|
|
||||||
mreq.imr_multiaddr.s_addr = inet_addr(streamAddr);
|
|
||||||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
|
||||||
int err = setsockopt(socketDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq,
|
|
||||||
sizeof(mreq));
|
|
||||||
ERROR_IF_RET(err < 0, "setsockopt()", return false);
|
|
||||||
// Update multicasting flag
|
|
||||||
isActive = false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIptvProtocolUdp::Open(void)
|
bool cIptvProtocolUdp::Open(void)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolUdp::Open()\n");
|
debug("cIptvProtocolUdp::Open(): streamAddr=%s\n", streamAddr);
|
||||||
// Join a new multicast group
|
OpenSocket(streamPort, streamAddr, sourceAddr, isIGMPv3);
|
||||||
JoinMulticast();
|
if (!isempty(streamAddr)) {
|
||||||
|
// Join a new multicast group
|
||||||
|
JoinMulticast();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIptvProtocolUdp::Close(void)
|
bool cIptvProtocolUdp::Close(void)
|
||||||
{
|
{
|
||||||
debug("cIptvProtocolUdp::Close()\n");
|
debug("cIptvProtocolUdp::Close(): streamAddr=%s\n", streamAddr);
|
||||||
// Drop the multicast group
|
if (!isempty(streamAddr)) {
|
||||||
DropMulticast();
|
// Drop the multicast group
|
||||||
|
OpenSocket(streamPort, streamAddr, sourceAddr, isIGMPv3);
|
||||||
|
DropMulticast();
|
||||||
|
}
|
||||||
// Close the socket
|
// Close the socket
|
||||||
CloseSocket();
|
CloseSocket();
|
||||||
|
// Do NOT reset stream and source addresses
|
||||||
|
//sourceAddr = strcpyrealloc(sourceAddr, "");
|
||||||
|
//streamAddr = strcpyrealloc(streamAddr, "");
|
||||||
|
//streamPort = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,19 +74,39 @@ bool cIptvProtocolUdp::Set(const char* Location, const int Parameter, const int
|
|||||||
{
|
{
|
||||||
debug("cIptvProtocolUdp::Set(): Location=%s Parameter=%d Index=%d\n", Location, Parameter, Index);
|
debug("cIptvProtocolUdp::Set(): Location=%s Parameter=%d Index=%d\n", Location, Parameter, Index);
|
||||||
if (!isempty(Location)) {
|
if (!isempty(Location)) {
|
||||||
// Drop the multicast group
|
// Drop the multicast group
|
||||||
DropMulticast();
|
if (!isempty(streamAddr)) {
|
||||||
// Update stream address and port
|
OpenSocket(streamPort, streamAddr, sourceAddr, isIGMPv3);
|
||||||
streamAddr = strcpyrealloc(streamAddr, Location);
|
DropMulticast();
|
||||||
socketPort = Parameter;
|
}
|
||||||
// Join a new multicast group
|
// Update stream address and port
|
||||||
JoinMulticast();
|
streamAddr = strcpyrealloc(streamAddr, Location);
|
||||||
}
|
// <group address> or <source address>@<group address>
|
||||||
|
char *p = strstr(streamAddr, "@");
|
||||||
|
if (p) {
|
||||||
|
*p = 0;
|
||||||
|
sourceAddr = strcpyrealloc(sourceAddr, streamAddr);
|
||||||
|
streamAddr = strcpyrealloc(streamAddr, p + 1);
|
||||||
|
isIGMPv3 = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sourceAddr = strcpyrealloc(sourceAddr, streamAddr);
|
||||||
|
isIGMPv3 = false;
|
||||||
|
}
|
||||||
|
streamPort = Parameter;
|
||||||
|
// Join a new multicast group
|
||||||
|
if (!isempty(streamAddr)) {
|
||||||
|
OpenSocket(streamPort, streamAddr, sourceAddr, isIGMPv3);
|
||||||
|
JoinMulticast();
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cString cIptvProtocolUdp::GetInformation(void)
|
cString cIptvProtocolUdp::GetInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cIptvProtocolUdp::GetInformation()");
|
//debug("cIptvProtocolUdp::GetInformation()");
|
||||||
return cString::sprintf("udp://%s:%d", streamAddr, socketPort);
|
if (isIGMPv3)
|
||||||
|
return cString::sprintf("udp://%s@%s:%d", sourceAddr, streamAddr, streamPort);
|
||||||
|
return cString::sprintf("udp://%s:%d", streamAddr, streamPort);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,10 @@
|
|||||||
|
|
||||||
class cIptvProtocolUdp : public cIptvUdpSocket, public cIptvProtocolIf {
|
class cIptvProtocolUdp : public cIptvUdpSocket, public cIptvProtocolIf {
|
||||||
private:
|
private:
|
||||||
|
bool isIGMPv3;
|
||||||
|
char* sourceAddr;
|
||||||
char* streamAddr;
|
char* streamAddr;
|
||||||
|
int streamPort;
|
||||||
private:
|
|
||||||
bool JoinMulticast(void);
|
|
||||||
bool DropMulticast(void);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cIptvProtocolUdp();
|
cIptvProtocolUdp();
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "sectionfilter.h"
|
#include "sectionfilter.h"
|
||||||
|
|
||||||
cIptvSectionFilter::cIptvSectionFilter(int DeviceIndex, int Index,
|
cIptvSectionFilter::cIptvSectionFilter(int DeviceIndex, uint16_t Pid, uint8_t Tid, uint8_t Mask)
|
||||||
uint16_t Pid, uint8_t Tid, uint8_t Mask)
|
|
||||||
: pusi_seen(0),
|
: pusi_seen(0),
|
||||||
feedcc(0),
|
feedcc(0),
|
||||||
doneq(0),
|
doneq(0),
|
||||||
@@ -17,10 +17,9 @@ cIptvSectionFilter::cIptvSectionFilter(int DeviceIndex, int Index,
|
|||||||
seclen(0),
|
seclen(0),
|
||||||
tsfeedp(0),
|
tsfeedp(0),
|
||||||
pid(Pid),
|
pid(Pid),
|
||||||
devid(DeviceIndex),
|
devid(DeviceIndex)
|
||||||
id(Index)
|
|
||||||
{
|
{
|
||||||
//debug("cIptvSectionFilter::cIptvSectionFilter(%d, %d)\n", devid, id);
|
//debug("cIptvSectionFilter::cIptvSectionFilter(%d, %d)\n", devid, pid);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memset(secbuf_base, '\0', sizeof(secbuf_base));
|
memset(secbuf_base, '\0', sizeof(secbuf_base));
|
||||||
@@ -47,35 +46,30 @@ cIptvSectionFilter::cIptvSectionFilter(int DeviceIndex, int Index,
|
|||||||
}
|
}
|
||||||
doneq = local_doneq ? 1 : 0;
|
doneq = local_doneq ? 1 : 0;
|
||||||
|
|
||||||
// Create sockets
|
// Create filtering buffer
|
||||||
socket[0] = socket[1] = -1;
|
ringbuffer = new cRingBufferLinear(KILOBYTE(128), 0, false, *cString::sprintf("IPTV SECTION %d/%d", devid, pid));
|
||||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socket) != 0) {
|
if (ringbuffer)
|
||||||
char tmp[64];
|
ringbuffer->SetTimeouts(10, 10);
|
||||||
error("Opening section filter sockets failed (device=%d id=%d): %s\n", devid, id, strerror_r(errno, tmp, sizeof(tmp)));
|
else
|
||||||
}
|
error("Failed to allocate buffer for section filter (device=%d pid=%d): ", devid, pid);
|
||||||
else if ((fcntl(socket[0], F_SETFL, O_NONBLOCK) != 0) || (fcntl(socket[1], F_SETFL, O_NONBLOCK) != 0)) {
|
|
||||||
char tmp[64];
|
|
||||||
error("Setting section filter socket to non-blocking mode failed (device=%d id=%d): %s", devid, id, strerror_r(errno, tmp, sizeof(tmp)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cIptvSectionFilter::~cIptvSectionFilter()
|
cIptvSectionFilter::~cIptvSectionFilter()
|
||||||
{
|
{
|
||||||
//debug("cIptvSectionFilter::~cIptvSectionfilter(%d, %d)\n", devid, id);
|
//debug("cIptvSectionFilter::~cIptvSectionfilter(%d, %d)\n", devid, pid);
|
||||||
int tmp = socket[1];
|
DELETE_POINTER(ringbuffer);
|
||||||
socket[1] = -1;
|
|
||||||
if (tmp >= 0)
|
|
||||||
close(tmp);
|
|
||||||
tmp = socket[0];
|
|
||||||
socket[0] = -1;
|
|
||||||
if (tmp >= 0)
|
|
||||||
close(tmp);
|
|
||||||
secbuf = NULL;
|
secbuf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cIptvSectionFilter::GetReadDesc(void)
|
int cIptvSectionFilter::Read(void *Data, size_t Length)
|
||||||
{
|
{
|
||||||
return socket[0];
|
int count = 0;
|
||||||
|
uchar *p = ringbuffer->Get(count);
|
||||||
|
if (p && count > 0) {
|
||||||
|
memcpy(Data, p, count);
|
||||||
|
ringbuffer->Del(count);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint16_t cIptvSectionFilter::GetLength(const uint8_t *Data)
|
inline uint16_t cIptvSectionFilter::GetLength(const uint8_t *Data)
|
||||||
@@ -91,10 +85,10 @@ void cIptvSectionFilter::New(void)
|
|||||||
|
|
||||||
int cIptvSectionFilter::Filter(void)
|
int cIptvSectionFilter::Filter(void)
|
||||||
{
|
{
|
||||||
uint8_t neq = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (secbuf) {
|
if (secbuf) {
|
||||||
|
int i;
|
||||||
|
uint8_t neq = 0;
|
||||||
|
|
||||||
for (i = 0; i < DMX_MAX_FILTER_SIZE; ++i) {
|
for (i = 0; i < DMX_MAX_FILTER_SIZE; ++i) {
|
||||||
uint8_t local_xor = (uint8_t)(filter_value[i] ^ secbuf[i]);
|
uint8_t local_xor = (uint8_t)(filter_value[i] ^ secbuf[i]);
|
||||||
if (maskandmode[i] & local_xor)
|
if (maskandmode[i] & local_xor)
|
||||||
@@ -105,10 +99,10 @@ int cIptvSectionFilter::Filter(void)
|
|||||||
if (doneq && !neq)
|
if (doneq && !neq)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// There is no data in the read socket, more can be written
|
if (ringbuffer) {
|
||||||
if ((socket[0] >= 0) && (socket[1] >= 0) /*&& !select_single_desc(socket[0], 0, false)*/) {
|
int len = ringbuffer->Put(secbuf, seclen);
|
||||||
ssize_t len = write(socket[1], secbuf, seclen);
|
if (len != seclen)
|
||||||
ERROR_IF(len < 0, "write()");
|
ringbuffer->ReportOverflow(seclen - len);
|
||||||
// Update statistics
|
// Update statistics
|
||||||
AddSectionStatistic(len, 1);
|
AddSectionStatistic(len, 1);
|
||||||
}
|
}
|
||||||
@@ -138,7 +132,7 @@ int cIptvSectionFilter::CopyDump(const uint8_t *buf, uint8_t len)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
memcpy(secbuf_base + tsfeedp, buf, len);
|
memcpy(secbuf_base + tsfeedp, buf, len);
|
||||||
tsfeedp += len;
|
tsfeedp = uint16_t(tsfeedp + len);
|
||||||
|
|
||||||
limit = tsfeedp;
|
limit = tsfeedp;
|
||||||
if (limit > DMX_MAX_SECFEED_SIZE)
|
if (limit > DMX_MAX_SECFEED_SIZE)
|
||||||
@@ -154,7 +148,7 @@ int cIptvSectionFilter::CopyDump(const uint8_t *buf, uint8_t len)
|
|||||||
seclen = seclen_local;
|
seclen = seclen_local;
|
||||||
if (pusi_seen)
|
if (pusi_seen)
|
||||||
Feed();
|
Feed();
|
||||||
secbufp += seclen_local;
|
secbufp = uint16_t(secbufp + seclen_local);
|
||||||
secbuf += seclen_local;
|
secbuf += seclen_local;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#ifndef __IPTV_SECTIONFILTER_H
|
#ifndef __IPTV_SECTIONFILTER_H
|
||||||
#define __IPTV_SECTIONFILTER_H
|
#define __IPTV_SECTIONFILTER_H
|
||||||
|
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif // __FreeBSD__
|
||||||
#include <vdr/device.h>
|
#include <vdr/device.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
@@ -33,8 +36,6 @@ private:
|
|||||||
uint16_t pid;
|
uint16_t pid;
|
||||||
|
|
||||||
int devid;
|
int devid;
|
||||||
int id;
|
|
||||||
int socket[2];
|
|
||||||
|
|
||||||
uint8_t filter_value[DMX_MAX_FILTER_SIZE];
|
uint8_t filter_value[DMX_MAX_FILTER_SIZE];
|
||||||
uint8_t filter_mask[DMX_MAX_FILTER_SIZE];
|
uint8_t filter_mask[DMX_MAX_FILTER_SIZE];
|
||||||
@@ -43,6 +44,8 @@ private:
|
|||||||
uint8_t maskandmode[DMX_MAX_FILTER_SIZE];
|
uint8_t maskandmode[DMX_MAX_FILTER_SIZE];
|
||||||
uint8_t maskandnotmode[DMX_MAX_FILTER_SIZE];
|
uint8_t maskandnotmode[DMX_MAX_FILTER_SIZE];
|
||||||
|
|
||||||
|
cRingBufferLinear *ringbuffer;
|
||||||
|
|
||||||
inline uint16_t GetLength(const uint8_t *Data);
|
inline uint16_t GetLength(const uint8_t *Data);
|
||||||
void New(void);
|
void New(void);
|
||||||
int Filter(void);
|
int Filter(void);
|
||||||
@@ -51,11 +54,10 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// constructor & destructor
|
// constructor & destructor
|
||||||
cIptvSectionFilter(int Index, int DeviceIndex, uint16_t Pid,
|
cIptvSectionFilter(int DeviceIndex, uint16_t Pid, uint8_t Tid, uint8_t Mask);
|
||||||
uint8_t Tid, uint8_t Mask);
|
|
||||||
virtual ~cIptvSectionFilter();
|
virtual ~cIptvSectionFilter();
|
||||||
void Process(const uint8_t* Data);
|
void Process(const uint8_t* Data);
|
||||||
int GetReadDesc(void);
|
int Read(void *Buffer, size_t Length);
|
||||||
uint16_t GetPid(void) const { return pid; }
|
uint16_t GetPid(void) const { return pid; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
2
setup.c
2
setup.c
@@ -66,7 +66,7 @@ void cIptvMenuInfo::Display(void)
|
|||||||
|
|
||||||
eOSState cIptvMenuInfo::ProcessKey(eKeys Key)
|
eOSState cIptvMenuInfo::ProcessKey(eKeys Key)
|
||||||
{
|
{
|
||||||
switch (Key) {
|
switch (int(Key)) {
|
||||||
case kUp|k_Repeat:
|
case kUp|k_Repeat:
|
||||||
case kUp:
|
case kUp:
|
||||||
case kDown|k_Repeat:
|
case kDown|k_Repeat:
|
||||||
|
|||||||
98
sidscanner.c
98
sidscanner.c
@@ -11,10 +11,19 @@
|
|||||||
#include "sidscanner.h"
|
#include "sidscanner.h"
|
||||||
|
|
||||||
cSidScanner::cSidScanner(void)
|
cSidScanner::cSidScanner(void)
|
||||||
|
: channelId(tChannelID::InvalidID),
|
||||||
|
sidFound(false),
|
||||||
|
nidFound(false),
|
||||||
|
tidFound(false)
|
||||||
{
|
{
|
||||||
debug("cSidScanner::cSidScanner()\n");
|
debug("cSidScanner::cSidScanner()\n");
|
||||||
channel = cChannel();
|
|
||||||
Set(0x00, 0x00); // PAT
|
Set(0x00, 0x00); // PAT
|
||||||
|
Set(0x10, 0x40); // NIT
|
||||||
|
}
|
||||||
|
|
||||||
|
cSidScanner::~cSidScanner()
|
||||||
|
{
|
||||||
|
debug("cSidScanner::~cSidScanner()\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSidScanner::SetStatus(bool On)
|
void cSidScanner::SetStatus(bool On)
|
||||||
@@ -23,43 +32,70 @@ void cSidScanner::SetStatus(bool On)
|
|||||||
cFilter::SetStatus(On);
|
cFilter::SetStatus(On);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSidScanner::SetChannel(const cChannel *Channel)
|
void cSidScanner::SetChannel(const tChannelID &ChannelId)
|
||||||
{
|
{
|
||||||
if (Channel) {
|
debug("cSidScanner::SetChannel(): %s\n", *ChannelId.ToString());
|
||||||
debug("cSidScanner::SetChannel(): %s\n", Channel->Parameters());
|
channelId = ChannelId;
|
||||||
channel = *Channel;
|
sidFound = false;
|
||||||
}
|
nidFound = false;
|
||||||
else {
|
tidFound = false;
|
||||||
debug("cSidScanner::SetChannel()\n");
|
|
||||||
channel = cChannel();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSidScanner::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
void cSidScanner::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
||||||
{
|
{
|
||||||
|
int newSid = -1, newNid = -1, newTid = -1;
|
||||||
|
|
||||||
//debug("cSidScanner::Process()\n");
|
//debug("cSidScanner::Process()\n");
|
||||||
if ((Pid == 0x00) && (Tid == 0x00) && channel.GetChannelID().Valid()) {
|
if (channelId.Valid()) {
|
||||||
debug("cSidScanner::Process(): Pid=%d Tid=%02X\n", Pid, Tid);
|
if ((Pid == 0x00) && (Tid == 0x00)) {
|
||||||
SI::PAT pat(Data, false);
|
debug("cSidScanner::Process(): Pid=%d Tid=%02X\n", Pid, Tid);
|
||||||
if (!pat.CheckCRCAndParse())
|
SI::PAT pat(Data, false);
|
||||||
return;
|
if (!pat.CheckCRCAndParse())
|
||||||
SI::PAT::Association assoc;
|
return;
|
||||||
for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
|
SI::PAT::Association assoc;
|
||||||
if (!assoc.isNITPid()) {
|
for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
|
||||||
if (assoc.getServiceId() != channel.Sid()) {
|
if (!assoc.isNITPid()) {
|
||||||
debug("cSidScanner::Process(): Sid=%d\n", assoc.getServiceId());
|
if (assoc.getServiceId() != channelId.Sid()) {
|
||||||
if (!Channels.Lock(true, 10))
|
debug("cSidScanner::Process(): Sid=%d\n", assoc.getServiceId());
|
||||||
return;
|
newSid = assoc.getServiceId();
|
||||||
cChannel *IptvChannel = Channels.GetByChannelID(channel.GetChannelID());
|
}
|
||||||
if (IptvChannel)
|
sidFound = true;
|
||||||
IptvChannel->SetId(IptvChannel->Nid(), IptvChannel->Tid(),
|
break;
|
||||||
assoc.getServiceId(), IptvChannel->Rid());
|
|
||||||
Channels.Unlock();
|
|
||||||
}
|
}
|
||||||
SetChannel(NULL);
|
|
||||||
SetStatus(false);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ((Pid == 0x10) && (Tid == 0x40)) {
|
||||||
|
debug("cSidScanner::Process(): Pid=%d Tid=%02X\n", Pid, Tid);
|
||||||
|
SI::NIT nit(Data, false);
|
||||||
|
if (!nit.CheckCRCAndParse())
|
||||||
|
return;
|
||||||
|
SI::NIT::TransportStream ts;
|
||||||
|
for (SI::Loop::Iterator it; nit.transportStreamLoop.getNext(ts, it); ) {
|
||||||
|
if (ts.getTransportStreamId() != channelId.Tid()) {
|
||||||
|
debug("cSidScanner::Process(): TSid=%d\n", ts.getTransportStreamId());
|
||||||
|
newTid = ts.getTransportStreamId();
|
||||||
|
}
|
||||||
|
tidFound = true;
|
||||||
|
break; // default to the first one
|
||||||
|
}
|
||||||
|
if (nit.getNetworkId() != channelId.Nid()) {
|
||||||
|
debug("cSidScanner::Process(): Nid=%d\n", ts.getTransportStreamId());
|
||||||
|
newNid = nit.getNetworkId();
|
||||||
|
}
|
||||||
|
nidFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((newSid >= 0) || (newNid >= 0) || (newTid >= 0)) {
|
||||||
|
if (!Channels.Lock(true, 10))
|
||||||
|
return;
|
||||||
|
cChannel *IptvChannel = Channels.GetByChannelID(channelId);
|
||||||
|
if (IptvChannel)
|
||||||
|
IptvChannel->SetId((newNid < 0) ? IptvChannel->Nid() : newNid, (newTid < 0) ? IptvChannel->Tid() : newTid,
|
||||||
|
(newSid < 0) ? IptvChannel->Sid() : newSid, IptvChannel->Rid());
|
||||||
|
Channels.Unlock();
|
||||||
|
}
|
||||||
|
if (sidFound && nidFound && tidFound) {
|
||||||
|
SetChannel(tChannelID::InvalidID);
|
||||||
|
SetStatus(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,10 @@
|
|||||||
|
|
||||||
class cSidScanner : public cFilter {
|
class cSidScanner : public cFilter {
|
||||||
private:
|
private:
|
||||||
cChannel channel;
|
tChannelID channelId;
|
||||||
|
bool sidFound;
|
||||||
|
bool nidFound;
|
||||||
|
bool tidFound;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
|
virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
|
||||||
@@ -21,7 +24,8 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
cSidScanner(void);
|
cSidScanner(void);
|
||||||
void SetChannel(const cChannel *Channel);
|
~cSidScanner();
|
||||||
|
void SetChannel(const tChannelID &ChannelId);
|
||||||
void Open() { SetStatus(true); }
|
void Open() { SetStatus(true); }
|
||||||
void Close() { SetStatus(false); }
|
void Close() { SetStatus(false); }
|
||||||
};
|
};
|
||||||
|
|||||||
318
socket.c
318
socket.c
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <net/if.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -23,6 +24,7 @@ cIptvSocket::cIptvSocket()
|
|||||||
isActive(false)
|
isActive(false)
|
||||||
{
|
{
|
||||||
debug("cIptvSocket::cIptvSocket()\n");
|
debug("cIptvSocket::cIptvSocket()\n");
|
||||||
|
memset(&sockAddr, '\0', sizeof(sockAddr));
|
||||||
}
|
}
|
||||||
|
|
||||||
cIptvSocket::~cIptvSocket()
|
cIptvSocket::~cIptvSocket()
|
||||||
@@ -51,13 +53,18 @@ bool cIptvSocket::OpenSocket(const int Port, const bool isUdp)
|
|||||||
socketDesc = socket(PF_INET, SOCK_STREAM, 0);
|
socketDesc = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
ERROR_IF_RET(socketDesc < 0, "socket()", return false);
|
ERROR_IF_RET(socketDesc < 0, "socket()", return false);
|
||||||
// Make it use non-blocking I/O to avoid stuck read calls
|
// Make it use non-blocking I/O to avoid stuck read calls
|
||||||
ERROR_IF_FUNC(fcntl(socketDesc, F_SETFL, O_NONBLOCK), "fcntl()",
|
ERROR_IF_FUNC(fcntl(socketDesc, F_SETFL, O_NONBLOCK), "fcntl(O_NONBLOCK)",
|
||||||
CloseSocket(), return false);
|
CloseSocket(), return false);
|
||||||
// Allow multiple sockets to use the same PORT number
|
// Allow multiple sockets to use the same PORT number
|
||||||
ERROR_IF_FUNC(setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0, "setsockopt()",
|
ERROR_IF_FUNC(setsockopt(socketDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0, "setsockopt(SO_REUSEADDR)",
|
||||||
CloseSocket(), return false);
|
CloseSocket(), return false);
|
||||||
|
#ifndef __FreeBSD__
|
||||||
|
// Allow packet information to be fetched
|
||||||
|
ERROR_IF_FUNC(setsockopt(socketDesc, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0, "setsockopt(IP_PKTINFO)",
|
||||||
|
CloseSocket(), return false);
|
||||||
|
#endif // __FreeBSD__
|
||||||
// Bind socket
|
// Bind socket
|
||||||
memset(&sockAddr, '\0', sizeof(sockAddr));
|
memset(&sockAddr, 0, sizeof(sockAddr));
|
||||||
sockAddr.sin_family = AF_INET;
|
sockAddr.sin_family = AF_INET;
|
||||||
sockAddr.sin_port = htons((uint16_t)(Port & 0xFFFF));
|
sockAddr.sin_port = htons((uint16_t)(Port & 0xFFFF));
|
||||||
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
@@ -78,11 +85,38 @@ void cIptvSocket::CloseSocket(void)
|
|||||||
if (socketDesc >= 0) {
|
if (socketDesc >= 0) {
|
||||||
close(socketDesc);
|
close(socketDesc);
|
||||||
socketDesc = -1;
|
socketDesc = -1;
|
||||||
|
socketPort = 0;
|
||||||
|
memset(&sockAddr, 0, sizeof(sockAddr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cIptvSocket::CheckAddress(const char *Addr, in_addr_t *InAddr)
|
||||||
|
{
|
||||||
|
if (InAddr) {
|
||||||
|
// First try only the IP address
|
||||||
|
*InAddr = htonl(inet_addr(Addr));
|
||||||
|
if (*InAddr == htonl(INADDR_NONE)) {
|
||||||
|
debug("Cannot convert %s directly to internet address\n", Addr);
|
||||||
|
// It may be a host name, get the name
|
||||||
|
struct hostent *host;
|
||||||
|
host = gethostbyname(Addr);
|
||||||
|
if (!host) {
|
||||||
|
char tmp[64];
|
||||||
|
error("gethostbyname() failed: %s is not valid address: %s", Addr, strerror_r(h_errno, tmp, sizeof(tmp)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*InAddr = htonl(inet_addr(*host->h_addr_list));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// UDP socket class
|
// UDP socket class
|
||||||
cIptvUdpSocket::cIptvUdpSocket()
|
cIptvUdpSocket::cIptvUdpSocket()
|
||||||
|
: streamAddr(htonl(INADDR_ANY)),
|
||||||
|
sourceAddr(htonl(INADDR_ANY)),
|
||||||
|
useIGMPv3(false)
|
||||||
{
|
{
|
||||||
debug("cIptvUdpSocket::cIptvUdpSocket()\n");
|
debug("cIptvUdpSocket::cIptvUdpSocket()\n");
|
||||||
}
|
}
|
||||||
@@ -95,9 +129,99 @@ cIptvUdpSocket::~cIptvUdpSocket()
|
|||||||
bool cIptvUdpSocket::OpenSocket(const int Port)
|
bool cIptvUdpSocket::OpenSocket(const int Port)
|
||||||
{
|
{
|
||||||
debug("cIptvUdpSocket::OpenSocket()\n");
|
debug("cIptvUdpSocket::OpenSocket()\n");
|
||||||
|
streamAddr = htonl(INADDR_ANY);
|
||||||
|
sourceAddr = htonl(INADDR_ANY);
|
||||||
|
useIGMPv3 = false;
|
||||||
return cIptvSocket::OpenSocket(Port, true);
|
return cIptvSocket::OpenSocket(Port, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cIptvUdpSocket::OpenSocket(const int Port, const char *StreamAddr, const char *SourceAddr, bool UseIGMPv3)
|
||||||
|
{
|
||||||
|
debug("cIptvUdpSocket::OpenSocket()\n");
|
||||||
|
CheckAddress(StreamAddr, &streamAddr);
|
||||||
|
CheckAddress(SourceAddr, &sourceAddr);
|
||||||
|
useIGMPv3 = UseIGMPv3;
|
||||||
|
return cIptvSocket::OpenSocket(Port, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cIptvUdpSocket::CloseSocket(void)
|
||||||
|
{
|
||||||
|
debug("cIptvUdpSocket::CloseSocket()\n");
|
||||||
|
streamAddr = htonl(INADDR_ANY);
|
||||||
|
sourceAddr = htonl(INADDR_ANY);
|
||||||
|
useIGMPv3 = false;
|
||||||
|
cIptvSocket::CloseSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIptvUdpSocket::JoinMulticast(void)
|
||||||
|
{
|
||||||
|
debug("cIptvUdpSocket::JoinMulticast()\n");
|
||||||
|
// Check if socket exists
|
||||||
|
if (!isActive && (socketDesc >= 0)) {
|
||||||
|
// Join a new multicast group
|
||||||
|
if (useIGMPv3) {
|
||||||
|
// Source-specific multicast (SSM) is used
|
||||||
|
struct group_source_req gsr;
|
||||||
|
struct sockaddr_in *grp;
|
||||||
|
struct sockaddr_in *src;
|
||||||
|
gsr.gsr_interface = 0; // if_nametoindex("any") ?
|
||||||
|
grp = (struct sockaddr_in*)&gsr.gsr_group;
|
||||||
|
grp->sin_family = AF_INET;
|
||||||
|
grp->sin_addr.s_addr = streamAddr;
|
||||||
|
grp->sin_port = 0;
|
||||||
|
src = (struct sockaddr_in*)&gsr.gsr_source;
|
||||||
|
src->sin_family = AF_INET;
|
||||||
|
src->sin_addr.s_addr = sourceAddr;
|
||||||
|
src->sin_port = 0;
|
||||||
|
ERROR_IF_RET(setsockopt(socketDesc, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_JOIN_SOURCE_GROUP)", return false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct ip_mreq mreq;
|
||||||
|
mreq.imr_multiaddr.s_addr = streamAddr;
|
||||||
|
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||||
|
ERROR_IF_RET(setsockopt(socketDesc, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_ADD_MEMBERSHIP)", return false);
|
||||||
|
}
|
||||||
|
// Update multicasting flag
|
||||||
|
isActive = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIptvUdpSocket::DropMulticast(void)
|
||||||
|
{
|
||||||
|
debug("cIptvUdpSocket::DropMulticast()\n");
|
||||||
|
// Check if socket exists
|
||||||
|
if (isActive && (socketDesc >= 0)) {
|
||||||
|
// Drop the existing multicast group
|
||||||
|
if (useIGMPv3) {
|
||||||
|
// Source-specific multicast (SSM) is used
|
||||||
|
struct group_source_req gsr;
|
||||||
|
struct sockaddr_in *grp;
|
||||||
|
struct sockaddr_in *src;
|
||||||
|
gsr.gsr_interface = 0; // if_nametoindex("any") ?
|
||||||
|
grp = (struct sockaddr_in*)&gsr.gsr_group;
|
||||||
|
grp->sin_family = AF_INET;
|
||||||
|
grp->sin_addr.s_addr = streamAddr;
|
||||||
|
grp->sin_port = 0;
|
||||||
|
src = (struct sockaddr_in*)&gsr.gsr_source;
|
||||||
|
src->sin_family = AF_INET;
|
||||||
|
src->sin_addr.s_addr = sourceAddr;
|
||||||
|
src->sin_port = 0;
|
||||||
|
ERROR_IF_RET(setsockopt(socketDesc, SOL_IP, MCAST_LEAVE_SOURCE_GROUP, &gsr, sizeof(gsr)) < 0, "setsockopt(MCAST_LEAVE_SOURCE_GROUP)", return false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct ip_mreq mreq;
|
||||||
|
mreq.imr_multiaddr.s_addr = streamAddr;
|
||||||
|
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||||
|
ERROR_IF_RET(setsockopt(socketDesc, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0, "setsockopt(IP_DROP_MEMBERSHIP)", return false);
|
||||||
|
}
|
||||||
|
// Update multicasting flag
|
||||||
|
isActive = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
||||||
{
|
{
|
||||||
//debug("cIptvUdpSocket::Read()\n");
|
//debug("cIptvUdpSocket::Read()\n");
|
||||||
@@ -106,43 +230,77 @@ int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
|||||||
error("Invalid socket in %s\n", __FUNCTION__);
|
error("Invalid socket in %s\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
socklen_t addrlen = sizeof(sockAddr);
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
// Read data from socket
|
// Read data from socket in a loop
|
||||||
if (isActive && socketDesc && BufferAddr && (BufferLen > 0))
|
do {
|
||||||
len = (int)recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT,
|
socklen_t addrlen = sizeof(sockAddr);
|
||||||
(struct sockaddr *)&sockAddr, &addrlen);
|
struct msghdr msgh;
|
||||||
if ((len > 0) && (BufferAddr[0] == TS_SYNC_BYTE)) {
|
struct iovec iov;
|
||||||
return len;
|
char cbuf[256];
|
||||||
}
|
len = 0;
|
||||||
else if (len > 3) {
|
// Initialize iov and msgh structures
|
||||||
// http://www.networksorcery.com/enp/rfc/rfc2250.txt
|
memset(&msgh, 0, sizeof(struct msghdr));
|
||||||
// version
|
iov.iov_base = BufferAddr;
|
||||||
unsigned int v = (BufferAddr[0] >> 6) & 0x03;
|
iov.iov_len = BufferLen;
|
||||||
// extension bit
|
msgh.msg_control = cbuf;
|
||||||
unsigned int x = (BufferAddr[0] >> 4) & 0x01;
|
msgh.msg_controllen = sizeof(cbuf);
|
||||||
// cscr count
|
msgh.msg_name = &sockAddr;
|
||||||
unsigned int cc = BufferAddr[0] & 0x0F;
|
msgh.msg_namelen = addrlen;
|
||||||
// payload type: MPEG2 TS = 33
|
msgh.msg_iov = &iov;
|
||||||
//unsigned int pt = readBuffer[1] & 0x7F;
|
msgh.msg_iovlen = 1;
|
||||||
// header lenght
|
msgh.msg_flags = 0;
|
||||||
unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
|
|
||||||
// check if extension
|
if (isActive && socketDesc && BufferAddr && (BufferLen > 0))
|
||||||
if (x) {
|
len = (int)recvmsg(socketDesc, &msgh, MSG_DONTWAIT);
|
||||||
// extension header length
|
else
|
||||||
unsigned int ehl = (((BufferAddr[headerlen + 2] & 0xFF) << 8) |
|
break;
|
||||||
(BufferAddr[headerlen + 3] & 0xFF));
|
if (len > 0) {
|
||||||
// update header length
|
#ifndef __FreeBSD__
|
||||||
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
|
// Process auxiliary received data and validate source address
|
||||||
}
|
for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
|
||||||
// Check that rtp is version 2 and payload contains multiple of TS packet data
|
if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
|
||||||
if ((v == 2) && (((len - headerlen) % TS_SIZE) == 0) &&
|
struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
||||||
(BufferAddr[headerlen] == TS_SYNC_BYTE)) {
|
if ((i->ipi_addr.s_addr == streamAddr) || (htonl(INADDR_ANY) == streamAddr)) {
|
||||||
// Set argument point to payload in read buffer
|
#endif // __FreeBSD__
|
||||||
memmove(BufferAddr, &BufferAddr[headerlen], (len - headerlen));
|
if (BufferAddr[0] == TS_SYNC_BYTE)
|
||||||
return (len - headerlen);
|
return len;
|
||||||
}
|
else if (len > 3) {
|
||||||
}
|
// http://www.networksorcery.com/enp/rfc/rfc2250.txt
|
||||||
|
// version
|
||||||
|
unsigned int v = (BufferAddr[0] >> 6) & 0x03;
|
||||||
|
// extension bit
|
||||||
|
unsigned int x = (BufferAddr[0] >> 4) & 0x01;
|
||||||
|
// cscr count
|
||||||
|
unsigned int cc = BufferAddr[0] & 0x0F;
|
||||||
|
// payload type: MPEG2 TS = 33
|
||||||
|
//unsigned int pt = readBuffer[1] & 0x7F;
|
||||||
|
// header lenght
|
||||||
|
unsigned int headerlen = (3 + cc) * (unsigned int)sizeof(uint32_t);
|
||||||
|
// check if extension
|
||||||
|
if (x) {
|
||||||
|
// extension header length
|
||||||
|
unsigned int ehl = (((BufferAddr[headerlen + 2] & 0xFF) << 8) |
|
||||||
|
(BufferAddr[headerlen + 3] & 0xFF));
|
||||||
|
// update header length
|
||||||
|
headerlen += (ehl + 1) * (unsigned int)sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
// Check that rtp is version 2 and payload contains multiple of TS packet data
|
||||||
|
if ((v == 2) && (((len - headerlen) % TS_SIZE) == 0) &&
|
||||||
|
(BufferAddr[headerlen] == TS_SYNC_BYTE)) {
|
||||||
|
// Set argument point to payload in read buffer
|
||||||
|
memmove(BufferAddr, &BufferAddr[headerlen], (len - headerlen));
|
||||||
|
return (len - headerlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifndef __FreeBSD__
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // __FreeBSD__
|
||||||
|
}
|
||||||
|
} while (len > 0);
|
||||||
|
ERROR_IF_RET(len < 0 && errno != EAGAIN, "recvmsg()", return -1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,10 +315,43 @@ cIptvTcpSocket::~cIptvTcpSocket()
|
|||||||
debug("cIptvTcpSocket::~cIptvTcpSocket()\n");
|
debug("cIptvTcpSocket::~cIptvTcpSocket()\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cIptvTcpSocket::OpenSocket(const int Port)
|
bool cIptvTcpSocket::OpenSocket(const int Port, const char *StreamAddr)
|
||||||
{
|
{
|
||||||
debug("cIptvTcpSocket::OpenSocket()\n");
|
debug("cIptvTcpSocket::OpenSocket()\n");
|
||||||
return cIptvSocket::OpenSocket(Port, false);
|
// Socket must be opened before setting the host address
|
||||||
|
return (cIptvSocket::OpenSocket(Port, false) && CheckAddress(StreamAddr, &sockAddr.sin_addr.s_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
void cIptvTcpSocket::CloseSocket(void)
|
||||||
|
{
|
||||||
|
debug("cIptvTcpSocket::CloseSocket()\n");
|
||||||
|
cIptvSocket::CloseSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIptvTcpSocket::ConnectSocket(void)
|
||||||
|
{
|
||||||
|
debug("cIptvTcpSocket::ConnectSocket()\n");
|
||||||
|
if (!isActive && (socketDesc >= 0)) {
|
||||||
|
int retval = connect(socketDesc, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
|
||||||
|
// Non-blocking sockets always report in-progress error when connected
|
||||||
|
ERROR_IF_RET(retval < 0 && errno != EINPROGRESS, "connect()", return false);
|
||||||
|
// Select with 800ms timeout on the socket completion, check if it is writable
|
||||||
|
retval = select_single_desc(socketDesc, 800000, true);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
// Select has returned. Get socket errors if there are any
|
||||||
|
retval = 0;
|
||||||
|
socklen_t len = sizeof(retval);
|
||||||
|
getsockopt(socketDesc, SOL_SOCKET, SO_ERROR, &retval, &len);
|
||||||
|
// If not any errors, then socket must be ready and connected
|
||||||
|
if (retval != 0) {
|
||||||
|
char tmp[64];
|
||||||
|
error("Connect() failed: %s", strerror_r(retval, tmp, sizeof(tmp)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cIptvTcpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
int cIptvTcpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
||||||
@@ -171,10 +362,49 @@ int cIptvTcpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen)
|
|||||||
error("Invalid socket in %s\n", __FUNCTION__);
|
error("Invalid socket in %s\n", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
int len = 0;
|
||||||
socklen_t addrlen = sizeof(sockAddr);
|
socklen_t addrlen = sizeof(sockAddr);
|
||||||
// Read data from socket
|
// Read data from socket
|
||||||
if (isActive && socketDesc && BufferAddr && (BufferLen > 0))
|
if (isActive && socketDesc && BufferAddr && (BufferLen > 0))
|
||||||
return (int)recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT,
|
len = (int)recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT,
|
||||||
(struct sockaddr *)&sockAddr, &addrlen);
|
(struct sockaddr *)&sockAddr, &addrlen);
|
||||||
return 0;
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIptvTcpSocket::ReadChar(char* BufferAddr, unsigned int TimeoutMs)
|
||||||
|
{
|
||||||
|
//debug("cIptvTcpSocket::ReadChar()\n");
|
||||||
|
// Error out if socket not initialized
|
||||||
|
if (socketDesc <= 0) {
|
||||||
|
error("Invalid socket in %s\n", __FUNCTION__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
socklen_t addrlen = sizeof(sockAddr);
|
||||||
|
// Wait 500ms for data
|
||||||
|
int retval = select_single_desc(socketDesc, 1000 * TimeoutMs, false);
|
||||||
|
// Check if error
|
||||||
|
if (retval < 0)
|
||||||
|
return false;
|
||||||
|
// Check if data available
|
||||||
|
else if (retval) {
|
||||||
|
retval = (int)recvfrom(socketDesc, BufferAddr, 1, MSG_DONTWAIT,
|
||||||
|
(struct sockaddr *)&sockAddr, &addrlen);
|
||||||
|
if (retval <= 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIptvTcpSocket::Write(const char* BufferAddr, unsigned int BufferLen)
|
||||||
|
{
|
||||||
|
//debug("cIptvTcpSocket::Write()\n");
|
||||||
|
// Error out if socket not initialized
|
||||||
|
if (socketDesc <= 0) {
|
||||||
|
error("Invalid socket in %s\n", __FUNCTION__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ERROR_IF_RET(send(socketDesc, BufferAddr, BufferLen, 0) < 0, "send()", return false);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
23
socket.h
23
socket.h
@@ -9,10 +9,15 @@
|
|||||||
#define __IPTV_SOCKET_H
|
#define __IPTV_SOCKET_H
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif // __FreeBSD__
|
||||||
|
|
||||||
class cIptvSocket {
|
class cIptvSocket {
|
||||||
protected:
|
private:
|
||||||
int socketPort;
|
int socketPort;
|
||||||
|
|
||||||
|
protected:
|
||||||
int socketDesc;
|
int socketDesc;
|
||||||
struct sockaddr_in sockAddr;
|
struct sockaddr_in sockAddr;
|
||||||
bool isActive;
|
bool isActive;
|
||||||
@@ -20,6 +25,7 @@ protected:
|
|||||||
protected:
|
protected:
|
||||||
bool OpenSocket(const int Port, const bool isUdp);
|
bool OpenSocket(const int Port, const bool isUdp);
|
||||||
void CloseSocket(void);
|
void CloseSocket(void);
|
||||||
|
bool CheckAddress(const char *Addr, in_addr_t *InAddr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cIptvSocket();
|
cIptvSocket();
|
||||||
@@ -27,11 +33,20 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class cIptvUdpSocket : public cIptvSocket {
|
class cIptvUdpSocket : public cIptvSocket {
|
||||||
|
private:
|
||||||
|
in_addr_t streamAddr;
|
||||||
|
in_addr_t sourceAddr;
|
||||||
|
bool useIGMPv3;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cIptvUdpSocket();
|
cIptvUdpSocket();
|
||||||
virtual ~cIptvUdpSocket();
|
virtual ~cIptvUdpSocket();
|
||||||
virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen);
|
virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen);
|
||||||
bool OpenSocket(const int Port);
|
bool OpenSocket(const int Port);
|
||||||
|
bool OpenSocket(const int Port, const char *StreamAddr, const char *SourceAddr, bool UseIGMPv3);
|
||||||
|
void CloseSocket(void);
|
||||||
|
bool JoinMulticast(void);
|
||||||
|
bool DropMulticast(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
class cIptvTcpSocket : public cIptvSocket {
|
class cIptvTcpSocket : public cIptvSocket {
|
||||||
@@ -39,7 +54,11 @@ public:
|
|||||||
cIptvTcpSocket();
|
cIptvTcpSocket();
|
||||||
virtual ~cIptvTcpSocket();
|
virtual ~cIptvTcpSocket();
|
||||||
virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen);
|
virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen);
|
||||||
bool OpenSocket(const int Port);
|
bool OpenSocket(const int Port, const char *StreamAddr);
|
||||||
|
void CloseSocket(void);
|
||||||
|
bool ConnectSocket(void);
|
||||||
|
bool ReadChar(char* BufferAddr, unsigned int TimeoutMs);
|
||||||
|
bool Write(const char* BufferAddr, unsigned int BufferLen);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __IPTV_SOCKET_H
|
#endif // __IPTV_SOCKET_H
|
||||||
|
|||||||
20
source.c
20
source.c
@@ -127,7 +127,9 @@ cIptvSourceParam::cIptvSourceParam(char Source, const char *Description)
|
|||||||
param(0),
|
param(0),
|
||||||
nid(0),
|
nid(0),
|
||||||
tid(0),
|
tid(0),
|
||||||
rid(0)
|
rid(0),
|
||||||
|
data(),
|
||||||
|
itp()
|
||||||
{
|
{
|
||||||
debug("cIptvSourceParam::cIptvSourceParam(): Source=%c Description=%s\n", Source, Description);
|
debug("cIptvSourceParam::cIptvSourceParam(): Source=%c Description=%s\n", Source, Description);
|
||||||
|
|
||||||
@@ -160,14 +162,14 @@ cOsdItem *cIptvSourceParam::GetOsdItem(void)
|
|||||||
{
|
{
|
||||||
debug("cIptvSourceParam::GetOsdItem()\n");
|
debug("cIptvSourceParam::GetOsdItem()\n");
|
||||||
switch (param++) {
|
switch (param++) {
|
||||||
case 0: return new cMenuEditIntItem( tr("Nid"), &nid, 0);
|
case 0: return new cMenuEditIntItem( tr("Nid"), &nid, 0);
|
||||||
case 1: return new cMenuEditIntItem( tr("Tid"), &tid, 0);
|
case 1: return new cMenuEditIntItem( tr("Tid"), &tid, 0);
|
||||||
case 2: return new cMenuEditIntItem( tr("Rid"), &rid, 0);
|
case 2: return new cMenuEditIntItem( tr("Rid"), &rid, 0);
|
||||||
case 3: return new cMenuEditBoolItem(tr("Scan sid"), &itp.sidscan);
|
case 3: return new cMenuEditBoolItem(tr("Scan section ids"), &itp.sidscan);
|
||||||
case 4: return new cMenuEditBoolItem(tr("Scan pids"), &itp.pidscan);
|
case 4: return new cMenuEditBoolItem(tr("Scan pids"), &itp.pidscan);
|
||||||
case 5: return new cMenuEditStraItem(tr("Protocol"), &itp.protocol, ELEMENTS(protocols), protocols);
|
case 5: return new cMenuEditStraItem(tr("Protocol"), &itp.protocol, ELEMENTS(protocols), protocols);
|
||||||
case 6: return new cMenuEditStrItem( tr("Address"), itp.address, sizeof(itp.address));
|
case 6: return new cMenuEditStrItem( tr("Address"), itp.address, sizeof(itp.address));
|
||||||
case 7: return new cMenuEditIntItem( tr("Parameter"), &itp.parameter, 0, 0xFFFF);
|
case 7: return new cMenuEditIntItem( tr("Parameter"), &itp.parameter, 0, 0xFFFF);
|
||||||
default: return NULL;
|
default: return NULL;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ cString cIptvStreamerStatistics::GetStreamerStatistic()
|
|||||||
long bitrate = elapsed ? (long)(1000.0L * dataBytes / KILOBYTE(1) / elapsed) : 0L;
|
long bitrate = elapsed ? (long)(1000.0L * dataBytes / KILOBYTE(1) / elapsed) : 0L;
|
||||||
if (!IptvConfig.GetUseBytes())
|
if (!IptvConfig.GetUseBytes())
|
||||||
bitrate *= 8;
|
bitrate *= 8;
|
||||||
cString info = cString::sprintf("Stream bitrate: %ld k%s/s\n", bitrate, IptvConfig.GetUseBytes() ? "B" : "bit");
|
cString info = cString::sprintf("%ld k%s/s", bitrate, IptvConfig.GetUseBytes() ? "B" : "bit");
|
||||||
dataBytes = 0;
|
dataBytes = 0;
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@@ -164,6 +164,7 @@ void cIptvStreamerStatistics::AddStreamerStatistic(long Bytes)
|
|||||||
// Buffer statistic class
|
// Buffer statistic class
|
||||||
cIptvBufferStatistics::cIptvBufferStatistics()
|
cIptvBufferStatistics::cIptvBufferStatistics()
|
||||||
: dataBytes(0),
|
: dataBytes(0),
|
||||||
|
freeSpace(0),
|
||||||
usedSpace(0),
|
usedSpace(0),
|
||||||
timer(),
|
timer(),
|
||||||
mutex()
|
mutex()
|
||||||
|
|||||||
@@ -108,8 +108,8 @@ bool cIptvStreamer::Set(const char* Location, const int Parameter, const int Ind
|
|||||||
cString cIptvStreamer::GetInformation(void)
|
cString cIptvStreamer::GetInformation(void)
|
||||||
{
|
{
|
||||||
//debug("cIptvStreamer::GetInformation()");
|
//debug("cIptvStreamer::GetInformation()");
|
||||||
cString info("Stream:");
|
cString info;
|
||||||
if (protocol)
|
if (protocol)
|
||||||
info = cString::sprintf("%s %s", *info, *protocol->GetInformation());
|
info = protocol->GetInformation();
|
||||||
return cString::sprintf("%s\n", *info);
|
return info;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user