summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <Klaus (dot) Schmidinger (at) tvdr (dot) de>2017-05-25 09:32:12 (GMT)
committerManuel Reimer <manuel.reimer@gmx.de>2018-03-26 15:25:33 (GMT)
commite59728f4f77af1ef0cb4a2376b33a5e1d82e2e92 (patch)
treedc6381c833ab8f5d28ed18b86ea48c39752508bd
parent58a45b0a6be32216829d38f296488e11115180fe (diff)
downloadvdr-e59728f4f77af1ef0cb4a2376b33a5e1d82e2e92.tar.gz
vdr-e59728f4f77af1ef0cb4a2376b33a5e1d82e2e92.tar.bz2
Version 2.3.5vdr-2.3.5
VDR developer version 2.3.5 is now available at ftp://ftp.tvdr.de/vdr/Developer/vdr-2.3.5.tar.bz2 A 'diff' against the previous version is available at ftp://ftp.tvdr.de/vdr/Developer/vdr-2.3.4-2.3.5.diff MD5 checksums: 01fabef4d20ec01f11d53354d99a9642 vdr-2.3.5.tar.bz2 a9cc12e0bf76942c6435a36c429c6b42 vdr-2.3.4-2.3.5.diff WARNING: ======== This is a *developer* version. Even though *I* use it in my productive environment, I strongly recommend that you only use it under controlled conditions and for testing and debugging. The changes since version 2.3.4: - CAMs are now sent a generated EIT packet that contains a single 'present event' for the current SID, in order to avoid any parental rating dialogs. - Fixed handling UNC values (the shift operator behaves unexpected for shift values larger than the size of the variable). - Log messages about switching channels now include the channel ID (suggested by Dietmar Spingler). - Events in the EIT that end before the EPG linger time are now ignored in the incoming data stream, because they would just be deleted in the next schedules cleanup anyway. - The constructor of cHash (via cHashBase) now has an additional parameter (OwnObjects) which, if set to true, makes the hash take ownership of the hashed objects, so that they are deleted when the hash is cleared or destroyed. - Fixed a memory leak in cSectionSyncerHash. The cSectionSyncerEntry objects put into the hash were never explicitly deleted. Now the cSectionSyncerHash takes ownership of these objects. - cListObject now implements a private copy constructor and assignment operator, to keep derived objects from calling them implicitly. - When selecting a device/CAM combination for live viewing, CAMs that are known to decrypt the requested channel are now given a higher priority than prefering the primary device (reported by Christian Winkler). - Changed the default return value of cEpgHandler::BeginSegmentTransfer() to true, to avoid problems with derived classes that don't implement this function (reported by Frank Neumann). - Fixed selecting delivery system names in case of undefined indexes (thanks to Jasmin Jessich). - Changed the legacy delivery system name "DMBTH" to "DTMB", and added names for DVBC_ANNEX_C and DVBC2. - Added a Status parameter to the interface of cDevice::SignalStats() and cDvbDevice::SignalStats() (thanks to Rolf Ahrenberg). - Fixed handling line numbers in error messages when reading EPG data. - Added handling RI_HOST_CONTROL to the CI protocol (no actual processing, but its presence is required by some CAMs). - Fixed a crash in case the bottom text of a CAM menu is empty. - Extended the CI API to allow plugins to implement additional CAM resources. - Fixed a race between SVDRP CHAN and cDevice::HasProgramme() (reported by Dietmar Spingler). - Reduced the time before a CAM is marked as known to decrypt a particular channel to 3 seconds. - When the connection to a peer VDR is terminated, any remote timers of that peer are no longer shown on the local VDR. - No longer setting a new timer's remote host name if "SVDRP peering" is turned off. - Fixed a double deletion of a cTimer in case HandleRemoteModifications() returned false (thanks to Johann Friedrichs). - Removed TsGetContinuityCounter() from remux.h, using TsContinuityCounter() instead. - Fixed setting the local machine's SVDRP host name (was overwritten if setup.conf contained an empty string). The SVDRP host name is now only written to setup.conf if it differs from the system's host name. - If the Channel+/- keys are pressed while in the Schedules menu, the menu is now switched to the EPG of the new current channel. - The Makefiles have been modified so that during the build process they no longer display the actual (lengthy) commands, but rather just the name of the file that is being built, as in CC vdr.o The first two characters indicate the kind of operation (CC=compile, LD=link, AR=archive, MO=msgfmt, GT=xgettext, PO=msgmerge, IN=install). This way it is much easier to spot error messages and warnings, since they are not buried under tons of text. Plugin authors should modify their makefiles accordingly, by simply preceeding the respective commands with an '@' and inserting '@echo XX $@' (where XX is one of the character combinations listed above) before the command. The newplugin script has also been modified accordingly. - Fixed detecting the inclusion of STL header files in tools.h (thanks to Jasmin Jessich).
-rw-r--r--CONTRIBUTORS13
-rw-r--r--HISTORY65
-rw-r--r--Makefile20
-rw-r--r--PLUGINS/src/epgtableid0/Makefile8
-rw-r--r--PLUGINS/src/hello/Makefile17
-rw-r--r--PLUGINS/src/osddemo/Makefile8
-rw-r--r--PLUGINS/src/pictures/Makefile17
-rw-r--r--PLUGINS/src/servicedemo/Makefile11
-rw-r--r--PLUGINS/src/skincurses/Makefile17
-rw-r--r--PLUGINS/src/status/Makefile8
-rw-r--r--PLUGINS/src/svdrpdemo/Makefile8
-rw-r--r--ci.c319
-rw-r--r--ci.h114
-rw-r--r--config.c6
-rw-r--r--config.h10
-rw-r--r--cutter.c4
-rw-r--r--device.c33
-rw-r--r--device.h13
-rw-r--r--dvbdevice.c57
-rw-r--r--dvbdevice.h4
-rw-r--r--eit.c6
-rw-r--r--eit.h7
-rw-r--r--epg.c17
-rw-r--r--epg.h6
-rw-r--r--filter.c11
-rw-r--r--filter.h3
-rw-r--r--libsi/Makefile8
-rw-r--r--menu.c43
-rw-r--r--mtd.c29
-rw-r--r--mtd.h3
-rwxr-xr-xnewplugin17
-rw-r--r--receiver.c4
-rw-r--r--receiver.h4
-rw-r--r--remux.c89
-rw-r--r--remux.h26
-rw-r--r--svdrp.c4
-rw-r--r--tools.c12
-rw-r--r--tools.h19
-rw-r--r--vdr.c5
39 files changed, 818 insertions, 247 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index 0852c10..140ae53 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1199,6 +1199,8 @@ Rolf Ahrenberg <Rolf.Ahrenberg@sci.fi>
for the "binary skip" patch
for adding support for LCN (Logical Channel Numbers)
for suggesting to change the naming of "binary skip mode" to "adaptive skip mode"
+ for adding a Status parameter to the interface of cDevice::SignalStats() and
+ cDvbDevice::SignalStats()
Ralf Klueber <ralf.klueber@vodafone.com>
for reporting a bug in cutting a recording if there is only a single editing mark
@@ -2827,6 +2829,8 @@ Johann Friedrichs <johann.friedrichs@web.de>
for fixing loading the setup.conf file in case a parameter contains the '#' character
for reporting that the "Resume" button in the main menu was active even if the
respective recording did not exist
+ for fixing a double deletion of a cTimer in case HandleRemoteModifications() returned
+ false
Timo Helkio <timolavi@mbnet.fi>
for reporting a hangup when replaying a TS recording with subtitles activated
@@ -3022,6 +3026,8 @@ Frank Neumann <fnu@yavdr.org>
for adding support for "Satellite Channel Routing" (SCR) according to EN50607 ("JESS")
for suggesting to make the Setup/CAM menu display which device an individual CAM
is currently assigned to
+ for reporting a problem with the default return value of cEpgHandler::BeginSegmentTransfer()
+ in derived classes that don't implement this function
Gerald Dachs <vdr@dachsweb.de>
for reporting a problem with checking for minimum line length of 21 characters in
@@ -3377,6 +3383,9 @@ Tony Houghton <h@realh.co.uk>
Christian Winkler <winkler_chr@yahoo.de>
for reporting a problem with transfer mode on full featured DVB cards for encrypted
channels that have no audio pid
+ for reporting a problem when selecting a device/CAM combination for live viewing, if
+ the CAM that is known to decrypt the requested channel can not be assigned to the
+ primary device
Dietmar Spingler <d_spingler@gmx.de>
for reporting a problem that led to a fix in detaching receivers from devices in case
@@ -3389,6 +3398,8 @@ Dietmar Spingler <d_spingler@gmx.de>
for suggesting to implement the setup option "Recording/Record key handling"
for suggesting to cache the channel/CAM relations in the file 'cam.data'
for suggesting to optionally list the channels with channel ids in the SVDRP command LSTC
+ for suggesting to include the channel ID in log messages about switching channels
+ for reporting a problem with the SVDRP command CHAN while the channel display is open
Stefan Schallenberg <infos@nafets.de>
for adding the functions IndexOf(), InsertUnique(), AppendUnique() and RemoveElement()
@@ -3411,6 +3422,8 @@ Jasmin Jessich <jasmin@anw.at>
assigned to any devices
for writing the ddci2 plugin and for valuable input and help with testing and
debugging MTD support
+ for fixing selecting delivery system names in case of undefined indexes
+ for fixing detecting the inclusion of STL header files in tools.h
Martin Schirrmacher <schirrmie@gmail.com>
for suggesting to provide a way for skin plugins to get informed about the currently
diff --git a/HISTORY b/HISTORY
index a79eef1..7ce6586 100644
--- a/HISTORY
+++ b/HISTORY
@@ -8990,3 +8990,68 @@ Video Disk Recorder Revision History
- If 0 is given as the channel number in the SVDRP command LSTC, the data of the
current channel is listed.
- Fixed a possible crash when pulling the CAM while decrypting a channel with MTD.
+
+2017-05-25: Version 2.3.5
+
+- CAMs are now sent a generated EIT packet that contains a single 'present event' for
+ the current SID, in order to avoid any parental rating dialogs.
+- Fixed handling UNC values (the shift operator behaves unexpected for shift values
+ larger than the size of the variable).
+- Log messages about switching channels now include the channel ID (suggested by
+ Dietmar Spingler).
+- Events in the EIT that end before the EPG linger time are now ignored in the incoming
+ data stream, because they would just be deleted in the next schedules cleanup anyway.
+- The constructor of cHash (via cHashBase) now has an additional parameter (OwnObjects)
+ which, if set to true, makes the hash take ownership of the hashed objects, so that
+ they are deleted when the hash is cleared or destroyed.
+- Fixed a memory leak in cSectionSyncerHash. The cSectionSyncerEntry objects put into
+ the hash were never explicitly deleted. Now the cSectionSyncerHash takes ownership of
+ these objects.
+- cListObject now implements a private copy constructor and assignment operator, to keep
+ derived objects from calling them implicitly.
+- When selecting a device/CAM combination for live viewing, CAMs that are known to decrypt
+ the requested channel are now given a higher priority than prefering the primary device
+ (reported by Christian Winkler).
+- Changed the default return value of cEpgHandler::BeginSegmentTransfer() to true, to
+ avoid problems with derived classes that don't implement this function (reported by
+ Frank Neumann).
+- Fixed selecting delivery system names in case of undefined indexes (thanks to Jasmin
+ Jessich).
+- Changed the legacy delivery system name "DMBTH" to "DTMB", and added names for
+ DVBC_ANNEX_C and DVBC2.
+- Added a Status parameter to the interface of cDevice::SignalStats() and
+ cDvbDevice::SignalStats() (thanks to Rolf Ahrenberg).
+- Fixed handling line numbers in error messages when reading EPG data.
+- Added handling RI_HOST_CONTROL to the CI protocol (no actual processing, but its
+ presence is required by some CAMs).
+- Fixed a crash in case the bottom text of a CAM menu is empty.
+- Extended the CI API to allow plugins to implement additional CAM resources.
+- Fixed a race between SVDRP CHAN and cDevice::HasProgramme() (reported by Dietmar
+ Spingler).
+- Reduced the time before a CAM is marked as known to decrypt a particular channel to
+ 3 seconds.
+- When the connection to a peer VDR is terminated, any remote timers of that peer
+ are no longer shown on the local VDR.
+- No longer setting a new timer's remote host name if "SVDRP peering" is turned off.
+- Fixed a double deletion of a cTimer in case HandleRemoteModifications() returned
+ false (thanks to Johann Friedrichs).
+- Removed TsGetContinuityCounter() from remux.h, using TsContinuityCounter() instead.
+- Fixed setting the local machine's SVDRP host name (was overwritten if setup.conf
+ contained an empty string). The SVDRP host name is now only written to setup.conf
+ if it differs from the system's host name.
+- If the Channel+/- keys are pressed while in the Schedules menu, the menu is now
+ switched to the EPG of the new current channel.
+- The Makefiles have been modified so that during the build process they no longer
+ display the actual (lengthy) commands, but rather just the name of the file that
+ is being built, as in
+ CC vdr.o
+ The first two characters indicate the kind of operation (CC=compile, LD=link,
+ AR=archive, MO=msgfmt, GT=xgettext, PO=msgmerge, IN=install).
+ This way it is much easier to spot error messages and warnings, since they are not
+ buried under tons of text.
+ Plugin authors should modify their makefiles accordingly, by simply preceeding
+ the respective commands with an '@' and inserting '@echo XX $@' (where XX is one
+ of the character combinations listed above) before the command.
+ The newplugin script has also been modified accordingly.
+- Fixed detecting the inclusion of STL header files in tools.h (thanks to Jasmin
+ Jessich).
diff --git a/Makefile b/Makefile
index d6bdc31..5b95dd0 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Makefile 4.3 2017/02/20 09:22:47 kls Exp $
+# $Id: Makefile 4.4 2017/05/22 15:33:30 kls Exp $
.DELETE_ON_ERROR:
@@ -121,7 +121,8 @@ all: vdr i18n plugins
# Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ @echo CC $@
+ @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
# Dependencies:
@@ -135,7 +136,8 @@ $(DEPFILE): Makefile
# The main program:
vdr: $(OBJS) $(SILIB)
- $(CXX) $(CXXFLAGS) -rdynamic $(LDFLAGS) $(OBJS) $(LIBS) $(SILIB) -o vdr
+ @echo LD $@
+ @$(CXX) $(CXXFLAGS) -rdynamic $(LDFLAGS) $(OBJS) $(LIBS) $(SILIB) -o vdr
# The libsi library:
@@ -177,17 +179,21 @@ I18Nmsgs = $(addprefix $(LOCALEDIR)/, $(addsuffix /LC_MESSAGES/vdr.mo, $(notdir
I18Npot = $(PODIR)/vdr.pot
%.mo: %.po
- msgfmt -c -o $@ $<
+ @echo MO $@
+ @msgfmt -c -o $@ $<
$(I18Npot): $(wildcard *.c)
- xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=VDR --package-version=$(VDRVERSION) --msgid-bugs-address='<vdr-bugs@tvdr.de>' -o $@ `ls $^`
+ @echo GT $@
+ @xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=VDR --package-version=$(VDRVERSION) --msgid-bugs-address='<vdr-bugs@tvdr.de>' -o $@ `ls $^`
%.po: $(I18Npot)
- msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ @echo PO $@
+ @msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(LOCALEDIR)/%/LC_MESSAGES/vdr.mo: $(PODIR)/%.mo
- install -D -m644 $< $@
+ @echo IN $@
+ @install -D -m644 $< $@
.PHONY: i18n
i18n: $(I18Nmsgs)
diff --git a/PLUGINS/src/epgtableid0/Makefile b/PLUGINS/src/epgtableid0/Makefile
index 161fefe..5afb680 100644
--- a/PLUGINS/src/epgtableid0/Makefile
+++ b/PLUGINS/src/epgtableid0/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.0 2014/01/01 13:29:54 kls Exp $
+# $Id: Makefile 4.1 2017/05/22 15:30:42 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -61,7 +61,8 @@ all: $(SOFILE)
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ @echo CC $@
+ @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -75,7 +76,8 @@ $(DEPFILE): Makefile
### Targets:
$(SOFILE): $(OBJS)
- $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ @echo LD $@
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/hello/Makefile b/PLUGINS/src/hello/Makefile
index 186eae4..79dcf22 100644
--- a/PLUGINS/src/hello/Makefile
+++ b/PLUGINS/src/hello/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.0 2014/01/01 13:29:54 kls Exp $
+# $Id: Makefile 4.1 2017/05/22 15:32:10 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -62,7 +62,8 @@ all: $(SOFILE) i18n
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ @echo CC $@
+ @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -82,13 +83,16 @@ I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLU
I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
- msgfmt -c -o $@ $<
+ @echo MO $@
+ @msgfmt -c -o $@ $<
$(I18Npot): $(wildcard *.c)
- xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+ @echo GT $@
+ @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)
- msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ @echo PO $@
+ @msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
@@ -102,7 +106,8 @@ install-i18n: $(I18Nmsgs)
### Targets:
$(SOFILE): $(OBJS)
- $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ @echo LD $@
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/osddemo/Makefile b/PLUGINS/src/osddemo/Makefile
index 980de2a..8750016 100644
--- a/PLUGINS/src/osddemo/Makefile
+++ b/PLUGINS/src/osddemo/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.0 2014/01/01 13:29:54 kls Exp $
+# $Id: Makefile 4.1 2017/05/22 15:30:47 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -61,7 +61,8 @@ all: $(SOFILE)
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ @echo CC $@
+ @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -75,7 +76,8 @@ $(DEPFILE): Makefile
### Targets:
$(SOFILE): $(OBJS)
- $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ @echo LD $@
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/pictures/Makefile b/PLUGINS/src/pictures/Makefile
index e749e98..acb1f8e 100644
--- a/PLUGINS/src/pictures/Makefile
+++ b/PLUGINS/src/pictures/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.0 2014/01/01 13:29:54 kls Exp $
+# $Id: Makefile 4.1 2017/05/22 15:31:28 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -62,7 +62,8 @@ all: $(SOFILE) i18n
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ @echo CC $@
+ @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -82,13 +83,16 @@ I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLU
I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
- msgfmt -c -o $@ $<
+ @echo MO $@
+ @msgfmt -c -o $@ $<
$(I18Npot): $(wildcard *.c)
- xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+ @echo GT $@
+ @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)
- msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ @echo PO $@
+ @msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
@@ -102,7 +106,8 @@ install-i18n: $(I18Nmsgs)
### Targets:
$(SOFILE): $(OBJS)
- $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ @echo LD $@
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/servicedemo/Makefile b/PLUGINS/src/servicedemo/Makefile
index c021fad..074df3d 100644
--- a/PLUGINS/src/servicedemo/Makefile
+++ b/PLUGINS/src/servicedemo/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.0 2014/01/01 13:29:54 kls Exp $
+# $Id: Makefile 4.1 2017/05/22 15:31:59 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -58,7 +58,8 @@ all: libvdr-$(PLUGIN1).so libvdr-$(PLUGIN2).so
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ @echo CC $@
+ @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -72,10 +73,12 @@ $(DEPFILE): Makefile
### Targets:
libvdr-$(PLUGIN1).so: $(PLUGIN1).o
- $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(PLUGIN1).o -o $@
+ @echo LD $@
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(PLUGIN1).o -o $@
libvdr-$(PLUGIN2).so: $(PLUGIN2).o
- $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(PLUGIN2).o -o $@
+ @echo LD $@
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(PLUGIN2).o -o $@
install-lib: libvdr-$(PLUGIN1).so libvdr-$(PLUGIN2).so
install -D libvdr-$(PLUGIN1).so $(DESTDIR)$(LIBDIR)/libvdr-$(PLUGIN1).so.$(APIVERSION)
diff --git a/PLUGINS/src/skincurses/Makefile b/PLUGINS/src/skincurses/Makefile
index 27dafe4..a1e05e5 100644
--- a/PLUGINS/src/skincurses/Makefile
+++ b/PLUGINS/src/skincurses/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.0 2014/01/01 13:29:54 kls Exp $
+# $Id: Makefile 4.1 2017/05/22 15:31:47 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -62,7 +62,8 @@ all: $(SOFILE) i18n
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ @echo CC $@
+ @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -82,13 +83,16 @@ I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLU
I18Npot = $(PODIR)/$(PLUGIN).pot
%.mo: %.po
- msgfmt -c -o $@ $<
+ @echo MO $@
+ @msgfmt -c -o $@ $<
$(I18Npot): $(wildcard *.c)
- xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^`
+ @echo GT $@
+ @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)
- msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
+ @echo PO $@
+ @msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $<
@touch $@
$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo
@@ -102,7 +106,8 @@ install-i18n: $(I18Nmsgs)
### Targets:
$(SOFILE): $(OBJS)
- $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -lncursesw -o $@
+ @echo LD $@
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -lncursesw -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/status/Makefile b/PLUGINS/src/status/Makefile
index 6c997d7..bf5c80b 100644
--- a/PLUGINS/src/status/Makefile
+++ b/PLUGINS/src/status/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.0 2014/01/01 13:29:54 kls Exp $
+# $Id: Makefile 4.1 2017/05/22 15:30:58 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -61,7 +61,8 @@ all: $(SOFILE)
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ @echo CC $@
+ @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -75,7 +76,8 @@ $(DEPFILE): Makefile
### Targets:
$(SOFILE): $(OBJS)
- $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ @echo LD $@
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/PLUGINS/src/svdrpdemo/Makefile b/PLUGINS/src/svdrpdemo/Makefile
index 91fad09..292b8c7 100644
--- a/PLUGINS/src/svdrpdemo/Makefile
+++ b/PLUGINS/src/svdrpdemo/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a Video Disk Recorder plugin
#
-# $Id: Makefile 4.0 2014/01/01 13:29:54 kls Exp $
+# $Id: Makefile 4.1 2017/05/22 15:31:19 kls Exp $
# The official name of this plugin.
# This name will be used in the '-P...' option of VDR to load the plugin.
@@ -61,7 +61,8 @@ all: $(SOFILE)
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
+ @echo CC $@
+ @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $<
### Dependencies:
@@ -75,7 +76,8 @@ $(DEPFILE): Makefile
### Targets:
$(SOFILE): $(OBJS)
- $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
+ @echo LD $@
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@
install-lib: $(SOFILE)
install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION)
diff --git a/ci.c b/ci.c
index f64c17e..5532453 100644
--- a/ci.c
+++ b/ci.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: ci.c 4.13 2017/04/26 09:18:26 kls Exp $
+ * $Id: ci.c 4.16 2017/05/18 09:05:46 kls Exp $
*/
#include "ci.h"
@@ -292,7 +292,7 @@ void cCaActivationReceiver::Receive(const uchar *Data, int Length)
// --- cTPDU -----------------------------------------------------------------
-#define MAX_TPDU_SIZE 2048
+#define MAX_TPDU_SIZE 4096
#define MAX_TPDU_DATA (MAX_TPDU_SIZE - 4)
#define DATA_INDICATOR 0x80
@@ -427,6 +427,7 @@ private:
cTimeMs alive;
cTimeMs timer;
cCiSession *sessions[MAX_SESSIONS_PER_TC + 1]; // session numbering starts with 1
+ cCiSession *tsPostProcessor;
void SendTPDU(uint8_t Tag, int Length = 0, const uint8_t *Data = NULL);
void SendTag(uint8_t Tag, uint16_t SessionId, uint32_t ResourceId = 0, int Status = -1);
void Poll(void);
@@ -438,6 +439,8 @@ private:
public:
cCiTransportConnection(cCamSlot *CamSlot, uint8_t Tcid);
virtual ~cCiTransportConnection();
+ void SetTsPostProcessor(cCiSession *CiSession);
+ bool TsPostProcess(uint8_t *TsPacket);
cCamSlot *CamSlot(void) { return camSlot; }
uint8_t Tcid(void) const { return tcid; }
void CreateConnection(void) { createConnectionRequested = true; }
@@ -527,24 +530,7 @@ public:
#define AOT_COMMS_RCV_LAST 0x9F8C05
#define AOT_COMMS_RCV_MORE 0x9F8C06
-class cCiSession {
-private:
- uint16_t sessionId;
- uint32_t resourceId;
- cCiTransportConnection *tc;
-protected:
- int GetTag(int &Length, const uint8_t **Data);
- const uint8_t *GetData(const uint8_t *Data, int &Length);
- void SendData(int Tag, int Length = 0, const uint8_t *Data = NULL);
- cCiTransportConnection *Tc(void) { return tc; }
-public:
- cCiSession(uint16_t SessionId, uint32_t ResourceId, cCiTransportConnection *Tc);
- virtual ~cCiSession();
- uint16_t SessionId(void) { return sessionId; }
- uint32_t ResourceId(void) { return resourceId; }
- virtual bool HasUserIO(void) { return false; }
- virtual void Process(int Length = 0, const uint8_t *Data = NULL);
- };
+#define RESOURCE_CLASS_MASK 0xFFFF0000
cCiSession::cCiSession(uint16_t SessionId, uint32_t ResourceId, cCiTransportConnection *Tc)
{
@@ -557,6 +543,16 @@ cCiSession::~cCiSession()
{
}
+void cCiSession::SetResourceId(uint32_t Id)
+{
+ resourceId = Id;
+}
+
+void cCiSession::SetTsPostProcessor(void)
+{
+ tc->SetTsPostProcessor(this);
+}
+
int cCiSession::GetTag(int &Length, const uint8_t **Data)
///< Gets the tag at Data.
///< Returns the actual tag, or AOT_NONE in case of error.
@@ -580,7 +576,7 @@ const uint8_t *cCiSession::GetData(const uint8_t *Data, int &Length)
void cCiSession::SendData(int Tag, int Length, const uint8_t *Data)
{
- uint8_t buffer[2048];
+ uint8_t buffer[MAX_TPDU_SIZE];
uint8_t *p = buffer;
*p++ = ST_SESSION_NUMBER;
*p++ = 0x02;
@@ -597,7 +593,12 @@ void cCiSession::SendData(int Tag, int Length, const uint8_t *Data)
tc->SendData(p - buffer, buffer);
}
else
- esyslog("ERROR: CAM %d: data length (%d) exceeds buffer size", Tc()->CamSlot()->SlotNumber(), Length);
+ esyslog("ERROR: CAM %d: data length (%d) exceeds buffer size", CamSlot()->SlotNumber(), Length);
+}
+
+cCamSlot *cCiSession::CamSlot(void)
+{
+ return Tc()->CamSlot();
}
void cCiSession::Process(int Length, const uint8_t *Data)
@@ -617,7 +618,7 @@ public:
cCiResourceManager::cCiResourceManager(uint16_t SessionId, cCiTransportConnection *Tc)
:cCiSession(SessionId, RI_RESOURCE_MANAGER, Tc)
{
- dbgprotocol("Slot %d: new Resource Manager (session id %d)\n", Tc->CamSlot()->SlotNumber(), SessionId);
+ dbgprotocol("Slot %d: new Resource Manager (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
state = 0;
}
@@ -627,39 +628,33 @@ void cCiResourceManager::Process(int Length, const uint8_t *Data)
int Tag = GetTag(Length, &Data);
switch (Tag) {
case AOT_PROFILE_ENQ: {
- dbgprotocol("Slot %d: <== Profile Enquiry (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
- uint32_t resources[] = { htonl(RI_RESOURCE_MANAGER),
- htonl(RI_APPLICATION_INFORMATION),
- htonl(RI_CONDITIONAL_ACCESS_SUPPORT),
- htonl(RI_DATE_TIME),
- htonl(RI_MMI)
- };
- dbgprotocol("Slot %d: ==> Profile (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
- SendData(AOT_PROFILE, sizeof(resources), (uint8_t*)resources);
+ dbgprotocol("Slot %d: <== Profile Enquiry (%d)\n", CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: ==> Profile (%d)\n", CamSlot()->SlotNumber(), SessionId());
+ SendData(AOT_PROFILE, CiResourceHandlers.NumIds() * sizeof(uint32_t), (uint8_t*)CiResourceHandlers.Ids());
state = 3;
}
break;
case AOT_PROFILE: {
- dbgprotocol("Slot %d: <== Profile (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: <== Profile (%d)\n", CamSlot()->SlotNumber(), SessionId());
if (state == 1) {
int l = 0;
const uint8_t *d = GetData(Data, l);
if (l > 0 && d)
- esyslog("ERROR: CAM %d: resource manager: unexpected data", Tc()->CamSlot()->SlotNumber());
- dbgprotocol("Slot %d: ==> Profile Change (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ esyslog("ERROR: CAM %d: resource manager: unexpected data", CamSlot()->SlotNumber());
+ dbgprotocol("Slot %d: ==> Profile Change (%d)\n", CamSlot()->SlotNumber(), SessionId());
SendData(AOT_PROFILE_CHANGE);
state = 2;
}
else {
- esyslog("ERROR: CAM %d: resource manager: unexpected tag %06X in state %d", Tc()->CamSlot()->SlotNumber(), Tag, state);
+ esyslog("ERROR: CAM %d: resource manager: unexpected tag %06X in state %d", CamSlot()->SlotNumber(), Tag, state);
}
}
break;
- default: esyslog("ERROR: CAM %d: resource manager: unknown tag %06X", Tc()->CamSlot()->SlotNumber(), Tag);
+ default: esyslog("ERROR: CAM %d: resource manager: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
}
}
else if (state == 0) {
- dbgprotocol("Slot %d: ==> Profile Enq (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: ==> Profile Enq (%d)\n", CamSlot()->SlotNumber(), SessionId());
SendData(AOT_PROFILE_ENQ);
state = 1;
}
@@ -667,25 +662,10 @@ void cCiResourceManager::Process(int Length, const uint8_t *Data)
// --- cCiApplicationInformation ---------------------------------------------
-class cCiApplicationInformation : public cCiSession {
-private:
- int state;
- uint8_t applicationType;
- uint16_t applicationManufacturer;
- uint16_t manufacturerCode;
- char *menuString;
-public:
- cCiApplicationInformation(uint16_t SessionId, cCiTransportConnection *Tc);
- virtual ~cCiApplicationInformation();
- virtual void Process(int Length = 0, const uint8_t *Data = NULL);
- bool EnterMenu(void);
- const char *GetMenuString(void) { return menuString; }
- };
-
cCiApplicationInformation::cCiApplicationInformation(uint16_t SessionId, cCiTransportConnection *Tc)
:cCiSession(SessionId, RI_APPLICATION_INFORMATION, Tc)
{
- dbgprotocol("Slot %d: new Application Information (session id %d)\n", Tc->CamSlot()->SlotNumber(), SessionId);
+ dbgprotocol("Slot %d: new Application Information (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
state = 0;
menuString = NULL;
}
@@ -701,7 +681,7 @@ void cCiApplicationInformation::Process(int Length, const uint8_t *Data)
int Tag = GetTag(Length, &Data);
switch (Tag) {
case AOT_APPLICATION_INFO: {
- dbgprotocol("Slot %d: <== Application Info (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: <== Application Info (%d)\n", CamSlot()->SlotNumber(), SessionId());
int l = 0;
const uint8_t *d = GetData(Data, l);
if ((l -= 1) < 0) break;
@@ -714,15 +694,15 @@ void cCiApplicationInformation::Process(int Length, const uint8_t *Data)
d += 2;
free(menuString);
menuString = GetString(l, &d);
- isyslog("CAM %d: %s, %02X, %04X, %04X", Tc()->CamSlot()->SlotNumber(), menuString, applicationType, applicationManufacturer, manufacturerCode);
+ isyslog("CAM %d: %s, %02X, %04X, %04X", CamSlot()->SlotNumber(), menuString, applicationType, applicationManufacturer, manufacturerCode);
state = 2;
}
break;
- default: esyslog("ERROR: CAM %d: application information: unknown tag %06X", Tc()->CamSlot()->SlotNumber(), Tag);
+ default: esyslog("ERROR: CAM %d: application information: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
}
}
else if (state == 0) {
- dbgprotocol("Slot %d: ==> Application Info Enq (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: ==> Application Info Enq (%d)\n", CamSlot()->SlotNumber(), SessionId());
SendData(AOT_APPLICATION_INFO_ENQ);
state = 1;
}
@@ -731,7 +711,7 @@ void cCiApplicationInformation::Process(int Length, const uint8_t *Data)
bool cCiApplicationInformation::EnterMenu(void)
{
if (state == 2) {
- dbgprotocol("Slot %d: ==> Enter Menu (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: ==> Enter Menu (%d)\n", CamSlot()->SlotNumber(), SessionId());
SendData(AOT_ENTER_MENU);
return true;
}
@@ -953,7 +933,7 @@ public:
cCiConditionalAccessSupport::cCiConditionalAccessSupport(uint16_t SessionId, cCiTransportConnection *Tc)
:cCiSession(SessionId, RI_CONDITIONAL_ACCESS_SUPPORT, Tc)
{
- dbgprotocol("Slot %d: new Conditional Access Support (session id %d)\n", Tc->CamSlot()->SlotNumber(), SessionId);
+ dbgprotocol("Slot %d: new Conditional Access Support (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
state = 0; // inactive
caSystemIds[numCaSystemIds = 0] = 0;
repliesToQuery = false;
@@ -965,7 +945,7 @@ void cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
int Tag = GetTag(Length, &Data);
switch (Tag) {
case AOT_CA_INFO: {
- dbgprotocol("Slot %d: <== Ca Info (%d)", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: <== Ca Info (%d)", CamSlot()->SlotNumber(), SessionId());
cString Ids;
numCaSystemIds = 0;
int l = 0;
@@ -979,7 +959,7 @@ void cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
if (numCaSystemIds < MAXCASYSTEMIDS)
caSystemIds[numCaSystemIds++] = id;
else {
- esyslog("ERROR: CAM %d: too many CA system IDs!", Tc()->CamSlot()->SlotNumber());
+ esyslog("ERROR: CAM %d: too many CA system IDs!", CamSlot()->SlotNumber());
break;
}
}
@@ -989,17 +969,17 @@ void cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
timer.Set(QUERY_WAIT_TIME); // WORKAROUND: Alphacrypt 3.09 doesn't reply to QUERY immediately after reset
state = 2; // got ca info
}
- dsyslog("CAM %d: system ids:%s", Tc()->CamSlot()->SlotNumber(), *Ids ? *Ids : " none");
+ dsyslog("CAM %d: system ids:%s", CamSlot()->SlotNumber(), *Ids ? *Ids : " none");
}
break;
case AOT_CA_PMT_REPLY: {
- dbgprotocol("Slot %d: <== Ca Pmt Reply (%d)", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: <== Ca Pmt Reply (%d)", CamSlot()->SlotNumber(), SessionId());
if (!repliesToQuery) {
- dsyslog("CAM %d: replies to QUERY - multi channel decryption (MCD) possible", Tc()->CamSlot()->SlotNumber());
+ dsyslog("CAM %d: replies to QUERY - multi channel decryption (MCD) possible", CamSlot()->SlotNumber());
repliesToQuery = true;
- if (Tc()->CamSlot()->MtdAvailable()) {
- dsyslog("CAM %d: supports multi transponder decryption (MTD)", Tc()->CamSlot()->SlotNumber());
- Tc()->CamSlot()->MtdActivate(true);
+ if (CamSlot()->MtdAvailable()) {
+ dsyslog("CAM %d: supports multi transponder decryption (MTD)", CamSlot()->SlotNumber());
+ CamSlot()->MtdActivate(true);
}
}
state = 5; // got ca pmt reply
@@ -1051,11 +1031,11 @@ void cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
dbgprotocol("\n");
}
break;
- default: esyslog("ERROR: CAM %d: conditional access support: unknown tag %06X", Tc()->CamSlot()->SlotNumber(), Tag);
+ default: esyslog("ERROR: CAM %d: conditional access support: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
}
}
else if (state == 0) {
- dbgprotocol("Slot %d: ==> Ca Info Enq (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: ==> Ca Info Enq (%d)\n", CamSlot()->SlotNumber(), SessionId());
SendData(AOT_CA_INFO_ENQ);
state = 1; // enquired ca info
}
@@ -1066,7 +1046,7 @@ void cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
state = 3; // waiting for reply
}
else if (state == 3 && timer.TimedOut()) {
- dsyslog("CAM %d: doesn't reply to QUERY - only a single channel can be decrypted", Tc()->CamSlot()->SlotNumber());
+ dsyslog("CAM %d: doesn't reply to QUERY - only a single channel can be decrypted", CamSlot()->SlotNumber());
state = 4; // normal operation
}
}
@@ -1074,12 +1054,45 @@ void cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
void cCiConditionalAccessSupport::SendPMT(cCiCaPmt *CaPmt)
{
if (CaPmt && state >= 2) {
- dbgprotocol("Slot %d: ==> Ca Pmt (%d) %d %d\n", Tc()->CamSlot()->SlotNumber(), SessionId(), CaPmt->ListManagement(), CaPmt->CmdId());
+ dbgprotocol("Slot %d: ==> Ca Pmt (%d) %d %d\n", CamSlot()->SlotNumber(), SessionId(), CaPmt->ListManagement(), CaPmt->CmdId());
SendData(AOT_CA_PMT, CaPmt->capmt.Length(), CaPmt->capmt.Data());
state = 4; // sent ca pmt
}
}
+// --- cCiHostControl --------------------------------------------------------
+
+class cCiHostControl : public cCiSession {
+public:
+ cCiHostControl(uint16_t SessionId, cCiTransportConnection *Tc);
+ virtual void Process(int Length = 0, const uint8_t *Data = NULL);
+ };
+
+cCiHostControl::cCiHostControl(uint16_t SessionId, cCiTransportConnection* Tc)
+:cCiSession(SessionId, RI_HOST_CONTROL, Tc)
+{
+ dbgprotocol("Slot %d: new Host Control (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
+}
+
+void cCiHostControl::Process(int Length, const uint8_t* Data)
+{
+ if (Data) {
+ int Tag = GetTag(Length, &Data);
+ switch (Tag) {
+ case AOT_TUNE:
+ dbgprotocol("Slot %d: <== Host Control Tune (%d)\n", CamSlot()->SlotNumber(), SessionId());
+ break;
+ case AOT_REPLACE:
+ dbgprotocol("Slot %d: <== Host Control Replace (%d)\n", CamSlot()->SlotNumber(), SessionId());
+ break;
+ case AOT_CLEAR_REPLACE:
+ dbgprotocol("Slot %d: <== Host Control Clear Replace (%d)\n", CamSlot()->SlotNumber(), SessionId());
+ break;
+ default: esyslog("ERROR: CAM %d: Host Control: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
+ }
+ }
+}
+
// --- cCiDateTime -----------------------------------------------------------
class cCiDateTime : public cCiSession {
@@ -1097,7 +1110,7 @@ cCiDateTime::cCiDateTime(uint16_t SessionId, cCiTransportConnection *Tc)
{
interval = 0;
lastTime = 0;
- dbgprotocol("Slot %d: new Date Time (session id %d)\n", Tc->CamSlot()->SlotNumber(), SessionId);
+ dbgprotocol("Slot %d: new Date Time (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
}
void cCiDateTime::SendDateTime(void)
@@ -1119,7 +1132,7 @@ void cCiDateTime::SendDateTime(void)
bool OldDumpTPDUDataTransfer = DumpTPDUDataTransfer;
DumpTPDUDataTransfer &= DumpDateTime;
if (DumpDateTime)
- dbgprotocol("Slot %d: ==> Date Time (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: ==> Date Time (%d)\n", CamSlot()->SlotNumber(), SessionId());
SendData(AOT_DATE_TIME, 7, (uint8_t*)&T);
DumpTPDUDataTransfer = OldDumpTPDUDataTransfer;
}
@@ -1136,12 +1149,12 @@ void cCiDateTime::Process(int Length, const uint8_t *Data)
const uint8_t *d = GetData(Data, l);
if (l > 0)
interval = *d;
- dbgprotocol("Slot %d: <== Date Time Enq (%d), interval = %d\n", Tc()->CamSlot()->SlotNumber(), SessionId(), interval);
+ dbgprotocol("Slot %d: <== Date Time Enq (%d), interval = %d\n", CamSlot()->SlotNumber(), SessionId(), interval);
lastTime = time(NULL);
SendDateTime();
}
break;
- default: esyslog("ERROR: CAM %d: date time: unknown tag %06X", Tc()->CamSlot()->SlotNumber(), Tag);
+ default: esyslog("ERROR: CAM %d: date time: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
}
}
else if (interval && time(NULL) - lastTime > interval) {
@@ -1206,7 +1219,7 @@ public:
cCiMMI::cCiMMI(uint16_t SessionId, cCiTransportConnection *Tc)
:cCiSession(SessionId, RI_MMI, Tc)
{
- dbgprotocol("Slot %d: new MMI (session id %d)\n", Tc->CamSlot()->SlotNumber(), SessionId);
+ dbgprotocol("Slot %d: new MMI (session id %d)\n", CamSlot()->SlotNumber(), SessionId);
menu = fetchedMenu = NULL;
enquiry = fetchedEnquiry = NULL;
}
@@ -1233,11 +1246,11 @@ char *cCiMMI::GetText(int &Length, const uint8_t **Data)
int Tag = GetTag(Length, Data);
if (Tag == AOT_TEXT_LAST) {
char *s = GetString(Length, Data);
- dbgprotocol("Slot %d: <== Text Last (%d) '%s'\n", Tc()->CamSlot()->SlotNumber(), SessionId(), s);
+ dbgprotocol("Slot %d: <== Text Last (%d) '%s'\n", CamSlot()->SlotNumber(), SessionId(), s);
return s;
}
else
- esyslog("ERROR: CAM %d: MMI: unexpected text tag: %06X", Tc()->CamSlot()->SlotNumber(), Tag);
+ esyslog("ERROR: CAM %d: MMI: unexpected text tag: %06X", CamSlot()->SlotNumber(), Tag);
return NULL;
}
@@ -1247,7 +1260,7 @@ void cCiMMI::Process(int Length, const uint8_t *Data)
int Tag = GetTag(Length, &Data);
switch (Tag) {
case AOT_DISPLAY_CONTROL: {
- dbgprotocol("Slot %d: <== Display Control (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: <== Display Control (%d)\n", CamSlot()->SlotNumber(), SessionId());
int l = 0;
const uint8_t *d = GetData(Data, l);
if (l > 0) {
@@ -1256,18 +1269,18 @@ void cCiMMI::Process(int Length, const uint8_t *Data)
if (l == 2 && *++d == MM_HIGH_LEVEL) {
struct tDisplayReply { uint8_t id; uint8_t mode; };
tDisplayReply dr = { id : DRI_MMI_MODE_ACK, mode : MM_HIGH_LEVEL };
- dbgprotocol("Slot %d: ==> Display Reply (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: ==> Display Reply (%d)\n", CamSlot()->SlotNumber(), SessionId());
SendData(AOT_DISPLAY_REPLY, 2, (uint8_t *)&dr);
}
break;
- default: esyslog("ERROR: CAM %d: MMI: unsupported display control command %02X", Tc()->CamSlot()->SlotNumber(), *d);
+ default: esyslog("ERROR: CAM %d: MMI: unsupported display control command %02X", CamSlot()->SlotNumber(), *d);
}
}
}
break;
case AOT_LIST_LAST:
case AOT_MENU_LAST: {
- dbgprotocol("Slot %d: <== Menu Last (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: <== Menu Last (%d)\n", CamSlot()->SlotNumber(), SessionId());
delete menu;
menu = new cCiMenu(this, Tag == AOT_MENU_LAST);
int l = 0;
@@ -1292,7 +1305,7 @@ void cCiMMI::Process(int Length, const uint8_t *Data)
}
break;
case AOT_ENQ: {
- dbgprotocol("Slot %d: <== Enq (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: <== Enq (%d)\n", CamSlot()->SlotNumber(), SessionId());
delete enquiry;
enquiry = new cCiEnquiry(this);
int l = 0;
@@ -1319,10 +1332,10 @@ void cCiMMI::Process(int Length, const uint8_t *Data)
if (l > 1)
delay = *d;
}
- dbgprotocol("Slot %d: <== Close MMI (%d) id = %02X delay = %d\n", Tc()->CamSlot()->SlotNumber(), SessionId(), id, delay);
+ dbgprotocol("Slot %d: <== Close MMI (%d) id = %02X delay = %d\n", CamSlot()->SlotNumber(), SessionId(), id, delay);
}
break;
- default: esyslog("ERROR: CAM %d: MMI: unknown tag %06X", Tc()->CamSlot()->SlotNumber(), Tag);
+ default: esyslog("ERROR: CAM %d: MMI: unknown tag %06X", CamSlot()->SlotNumber(), Tag);
}
}
}
@@ -1351,13 +1364,13 @@ cCiEnquiry *cCiMMI::Enquiry(bool Clear)
void cCiMMI::SendMenuAnswer(uint8_t Selection)
{
- dbgprotocol("Slot %d: ==> Menu Answ (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: ==> Menu Answ (%d)\n", CamSlot()->SlotNumber(), SessionId());
SendData(AOT_MENU_ANSW, 1, &Selection);
}
bool cCiMMI::SendAnswer(const char *Text)
{
- dbgprotocol("Slot %d: ==> Answ (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: ==> Answ (%d)\n", CamSlot()->SlotNumber(), SessionId());
struct tAnswer { uint8_t id; char text[256]; };//XXX
tAnswer answer;
answer.id = Text ? AI_ANSWER : AI_CANCEL;
@@ -1369,7 +1382,7 @@ bool cCiMMI::SendAnswer(const char *Text)
bool cCiMMI::SendCloseMMI(void)
{
- dbgprotocol("Slot %d: ==> Close MMI (%d)\n", Tc()->CamSlot()->SlotNumber(), SessionId());
+ dbgprotocol("Slot %d: ==> Close MMI (%d)\n", CamSlot()->SlotNumber(), SessionId());
SendData(AOT_CLOSE_MMI, 0);
return true;
}
@@ -1468,6 +1481,82 @@ void cCiEnquiry::Abort(void)
mmi->SendCloseMMI();
}
+// --- cCiResourceHandler ----------------------------------------------------
+
+cCiResourceHandler::cCiResourceHandler(void)
+{
+}
+
+cCiResourceHandler::~cCiResourceHandler()
+{
+}
+
+// --- cCiDefaultResourceHandler ---------------------------------------------
+
+class cCiDefaultResourceHandler : public cCiResourceHandler {
+public:
+ virtual const uint32_t *ResourceIds(void) const;
+ virtual cCiSession *GetNewCiSession(uint32_t ResourceId, uint16_t SessionId, cCiTransportConnection *Tc);
+ };
+
+const uint32_t *cCiDefaultResourceHandler::ResourceIds(void) const
+{
+ static uint32_t Ids[] = {
+ RI_RESOURCE_MANAGER,
+ RI_APPLICATION_INFORMATION,
+ RI_CONDITIONAL_ACCESS_SUPPORT,
+ RI_HOST_CONTROL,
+ RI_DATE_TIME,
+ RI_MMI,
+ 0
+ };
+ return Ids;
+}
+
+cCiSession *cCiDefaultResourceHandler::GetNewCiSession(uint32_t ResourceId, uint16_t SessionId, cCiTransportConnection *Tc)
+{
+ switch (ResourceId) {
+ case RI_RESOURCE_MANAGER: return new cCiResourceManager(SessionId, Tc); break;
+ case RI_APPLICATION_INFORMATION: return new cCiApplicationInformation(SessionId, Tc); break;
+ case RI_CONDITIONAL_ACCESS_SUPPORT: return new cCiConditionalAccessSupport(SessionId, Tc); break;
+ case RI_HOST_CONTROL: return new cCiHostControl(SessionId, Tc); break;
+ case RI_DATE_TIME: return new cCiDateTime(SessionId, Tc); break;
+ case RI_MMI: return new cCiMMI(SessionId, Tc); break;
+ default: return NULL;
+ }
+}
+
+// --- cCiResourceHandlers ---------------------------------------------------
+
+cCiResourceHandlers CiResourceHandlers;
+
+cCiResourceHandlers::cCiResourceHandlers(void)
+{
+ Register(new cCiDefaultResourceHandler);
+}
+
+void cCiResourceHandlers::Register(cCiResourceHandler *ResourceHandler)
+{
+ if (ResourceHandler) {
+ Add(ResourceHandler);
+ if (const uint32_t *r = ResourceHandler->ResourceIds()) {
+ while (*r) {
+ resourceIds.Append(htonl(*r));
+ r++;
+ }
+ }
+ }
+}
+
+cCiSession *cCiResourceHandlers::GetNewCiSession(uint32_t ResourceId, uint16_t SessionId, cCiTransportConnection *Tc)
+{
+ for (cCiResourceHandler *r = Last(); r; r = Prev(r)) {
+ if (cCiSession *CiSession = r->GetNewCiSession(ResourceId, SessionId, Tc))
+ return CiSession;
+ }
+ return NULL;
+}
+
// --- cCiTransportConnection (cont'd) ---------------------------------------
#define TC_POLL_TIMEOUT 300 // ms WORKAROUND: TC_POLL_TIMEOUT < 300ms doesn't work with DragonCAM
@@ -1485,6 +1574,7 @@ cCiTransportConnection::cCiTransportConnection(cCamSlot *CamSlot, uint8_t Tcid)
alive.Set(TC_ALIVE_TIMEOUT);
for (int i = 0; i <= MAX_SESSIONS_PER_TC; i++) // sessions[0] is not used, but initialized anyway
sessions[i] = NULL;
+ tsPostProcessor = NULL;
}
cCiTransportConnection::~cCiTransportConnection()
@@ -1493,6 +1583,18 @@ cCiTransportConnection::~cCiTransportConnection()
delete sessions[i];
}
+void cCiTransportConnection::SetTsPostProcessor(cCiSession *CiSession)
+{
+ tsPostProcessor = CiSession;
+}
+
+bool cCiTransportConnection::TsPostProcess(uint8_t *TsPacket)
+{
+ if (tsPostProcessor)
+ return tsPostProcessor->TsPostProcess(TsPacket);
+ return false;
+}
+
bool cCiTransportConnection::Ready(void)
{
cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT);
@@ -1559,11 +1661,16 @@ cCiSession *cCiTransportConnection::GetSessionBySessionId(uint16_t SessionId)
cCiSession *cCiTransportConnection::GetSessionByResourceId(uint32_t ResourceId)
{
+ cCiSession *CiSession = NULL;
for (int i = 1; i <= MAX_SESSIONS_PER_TC; i++) {
- if (sessions[i] && sessions[i]->ResourceId() == ResourceId)
- return sessions[i];
+ if (cCiSession *s = sessions[i]) {
+ if (s->ResourceId() == ResourceId)
+ return s; // prefer exact match
+ if ((s->ResourceId() & RESOURCE_CLASS_MASK) == (ResourceId & RESOURCE_CLASS_MASK))
+ CiSession = s;
+ }
}
- return NULL;
+ return CiSession;
}
void cCiTransportConnection::OpenSession(int Length, const uint8_t *Data)
@@ -1574,17 +1681,11 @@ void cCiTransportConnection::OpenSession(int Length, const uint8_t *Data)
if (!GetSessionByResourceId(ResourceId)) {
for (int i = 1; i <= MAX_SESSIONS_PER_TC; i++) {
if (!sessions[i]) {
- switch (ResourceId) {
- case RI_RESOURCE_MANAGER: sessions[i] = new cCiResourceManager(i, this); break;
- case RI_APPLICATION_INFORMATION: sessions[i] = new cCiApplicationInformation(i, this); break;
- case RI_CONDITIONAL_ACCESS_SUPPORT: sessions[i] = new cCiConditionalAccessSupport(i, this); break;
- case RI_DATE_TIME: sessions[i] = new cCiDateTime(i, this); break;
- case RI_MMI: sessions[i] = new cCiMMI(i, this); break;
- case RI_HOST_CONTROL: // not implemented
- default: esyslog("ERROR: CAM %d: unknown resource identifier: %08X (%d/%d)", camSlot->SlotNumber(), ResourceId, camSlot->SlotIndex(), tcid);
- }
+ sessions[i] = CiResourceHandlers.GetNewCiSession(ResourceId, i, this);
if (sessions[i])
SendTag(ST_OPEN_SESSION_RESPONSE, sessions[i]->SessionId(), sessions[i]->ResourceId(), SS_OK);
+ else
+ esyslog("ERROR: CAM %d: unknown resource identifier: %08X (%d/%d)", camSlot->SlotNumber(), ResourceId, camSlot->SlotIndex(), tcid);
return;
}
}
@@ -2424,6 +2525,22 @@ uchar *cCamSlot::Decrypt(uchar *Data, int &Count)
return Data;
}
+bool cCamSlot::TsPostProcess(uchar *Data)
+{
+ return tc[1] ? tc[1]->TsPostProcess(Data) : false;
+}
+
+bool cCamSlot::Inject(uchar *Data, int Count)
+{
+ return true;
+}
+
+void cCamSlot::InjectEit(int Sid)
+{
+ cEitGenerator Eit(Sid);
+ Inject(Eit.Data(), Eit.Length());
+}
+
// --- cCamSlots -------------------------------------------------------------
cCamSlots CamSlots;
diff --git a/ci.h b/ci.h
index 8d1323a..29dc9db 100644
--- a/ci.h
+++ b/ci.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: ci.h 4.6 2017/04/10 09:17:56 kls Exp $
+ * $Id: ci.h 4.9 2017/05/16 07:42:45 kls Exp $
*/
#ifndef __CI_H
@@ -21,6 +21,99 @@
#define MAX_CONNECTIONS_PER_CAM_SLOT 8 // maximum possible value is 254
#define CAM_READ_TIMEOUT 50 // ms
+class cCiTransportConnection;
+class cCamSlot;
+
+// VDR's Common Interface functions implement only the features that are absolutely
+// necessary to control a CAM. If a plugin wants to implement additional functionality
+// (i.e. "resources"), it can do so by deriving from cCiResourceHandler, cCiSession
+// and (if necessary) from cCiApplicationInformation.
+
+class cCiSession {
+private:
+ uint16_t sessionId;
+ uint32_t resourceId;
+ cCiTransportConnection *tc;
+protected:
+ void SetTsPostProcessor(void);
+ ///< If this cCiSession implements the TsPostProcess() function, it shall call
+ ///< SetTsPostProcessor() to register itself as the TS post processor.
+ void SetResourceId(uint32_t Id);
+ ///< If this is a class that has been derived from an existing cCiSession class,
+ ///< but implements a different resource id, it shall call SetResourceId() with
+ ///< that Id.
+ int GetTag(int &Length, const uint8_t **Data);
+ const uint8_t *GetData(const uint8_t *Data, int &Length);
+ void SendData(int Tag, int Length = 0, const uint8_t *Data = NULL);
+ cCiTransportConnection *Tc(void) { return tc; }
+public:
+ cCiSession(uint16_t SessionId, uint32_t ResourceId, cCiTransportConnection *Tc);
+ virtual ~cCiSession();
+ uint16_t SessionId(void) { return sessionId; }
+ uint32_t ResourceId(void) { return resourceId; }
+ cCamSlot *CamSlot(void);
+ virtual bool HasUserIO(void) { return false; }
+ virtual void Process(int Length = 0, const uint8_t *Data = NULL);
+ virtual bool TsPostProcess(uint8_t *TsPacket) { return false; }
+ ///< If this cCiSession needs to do additional processing on TS packets (after
+ ///< the CAM has done the decryption), it shall implement TsPostProcess() and
+ ///< do whatever operations are necessary on the given TsPacket. This function
+ ///< is called once for each TS packet, and any and all operations must be
+ ///< finished upon return.
+ ///< A derived cCiSession that implements this function must call
+ ///< SetTsPostProcessor() to make it actually get called.
+ ///< Returns true if the TsPacket was in any way modified.
+ };
+
+class cCiApplicationInformation : public cCiSession {
+protected:
+ int state;
+ uint8_t applicationType;
+ uint16_t applicationManufacturer;
+ uint16_t manufacturerCode;
+ char *menuString;
+public:
+ cCiApplicationInformation(uint16_t SessionId, cCiTransportConnection *Tc);
+ virtual ~cCiApplicationInformation();
+ virtual void Process(int Length = 0, const uint8_t *Data = NULL);
+ bool EnterMenu(void);
+ const char *GetMenuString(void) { return menuString; }
+ };
+
+class cCiResourceHandler : public cListObject {
+public:
+ cCiResourceHandler(void);
+ ///< Creates a new resource handler, through which the available resources
+ ///< can be provides. A resource handler shall be allocated on the heap and
+ ///< registered with the global CiResourceHandlers, as in
+ ///< CiResourceHandlers.Register(new cMyResourceHandler);
+ ///< It will be automatically deleted at the end of the program.
+ virtual ~cCiResourceHandler();
+ virtual const uint32_t *ResourceIds(void) const = 0;
+ ///< Returns a pointer to an array of resource identifiers, where the
+ ///< last value is zero.
+ virtual cCiSession *GetNewCiSession(uint32_t ResourceId, uint16_t SessionId, cCiTransportConnection *Tc) = 0;
+ ///< Returns a new cCiSession, according to the given ResourceId.
+ };
+
+class cCiResourceHandlers : public cList<cCiResourceHandler> {
+private:
+ cVector<uint32_t> resourceIds;
+public:
+ cCiResourceHandlers(void);
+ ///< Creates the default list of resourceIds.
+ void Register(cCiResourceHandler *ResourceHandler);
+ ///< Adds the given ResourceHandler to the list of resource handlers and
+ ///< appends its ResourceIds to the global resourceIds.
+ ///< A plugin that implements additional CAM capabilities must call
+ ///< this function to register its resources.
+ const uint32_t *Ids(void) { return &resourceIds[0]; }
+ int NumIds(void) { return resourceIds.Size(); }
+ cCiSession *GetNewCiSession(uint32_t ResourceId, uint16_t SessionId, cCiTransportConnection *Tc);
+ };
+
+extern cCiResourceHandlers CiResourceHandlers;
+
class cCiMMI;
class cCiMenu {
@@ -73,7 +166,6 @@ public:
};
class cDevice;
-class cCamSlot;
enum eModuleStatus { msNone, msReset, msPresent, msReady };
@@ -377,6 +469,24 @@ public:
///< A derived class that implements this function will also need
///< to set the WantsTsData parameter in the call to the base class
///< constructor to true in order to receive the TS data.
+ virtual bool TsPostProcess(uchar *Data);
+ ///< If there is a cCiSession that needs to do additional processing on TS packets
+ ///< (after the CAM has done the decryption), this function will call its
+ ///< TsPostProcess() function to have it do whatever operations are necessary on
+ ///< the given TsPacket.
+ ///< Returns true if the TsPacket was in any way modified.
+ virtual bool Inject(uchar *Data, int Count);
+ ///< Sends all Count bytes of the given Data to the CAM, and returns true
+ ///< if this was possible. If the data can't be sent to the CAM completely,
+ ///< nothing shall be sent and the return value shall be false.
+ ///< No decrypted packet is returned by this function.
+ ///< Data is guaranteed to point to one or more complete TS packets.
+ virtual void InjectEit(int Sid);
+ ///< Injects a generated EIT with a "present event" for the given Sid into
+ ///< the TS data stream sent to the CAM. This only applies to CAM slots that
+ ///< have WantsTsData set to true in their constructor.
+ ///< The default implementation sends an EIT with the minimum event
+ ///< necessary to disable the CAMs parental rating prompt.
};
class cCamSlots : public cList<cCamSlot> {
diff --git a/config.c b/config.c
index 79eec8a..0b5a102 100644
--- a/config.c
+++ b/config.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.c 4.5 2017/02/14 11:02:48 kls Exp $
+ * $Id: config.c 4.6 2017/05/21 10:25:26 kls Exp $
*/
#include "config.h"
@@ -640,7 +640,7 @@ bool cSetup::Parse(const char *Name, const char *Value)
else if (!strcasecmp(Name, "EPGLinger")) EPGLinger = atoi(Value);
else if (!strcasecmp(Name, "SVDRPTimeout")) SVDRPTimeout = atoi(Value);
else if (!strcasecmp(Name, "SVDRPPeering")) SVDRPPeering = atoi(Value);
- else if (!strcasecmp(Name, "SVDRPHostName")) { if (!*SVDRPHostName) strn0cpy(SVDRPHostName, Value, sizeof(SVDRPHostName)); }
+ else if (!strcasecmp(Name, "SVDRPHostName")) { if (*Value) strn0cpy(SVDRPHostName, Value, sizeof(SVDRPHostName)); }
else if (!strcasecmp(Name, "SVDRPdefaultHost")) strn0cpy(SVDRPDefaultHost, Value, sizeof(SVDRPDefaultHost));
else if (!strcasecmp(Name, "ZapTimeout")) ZapTimeout = atoi(Value);
else if (!strcasecmp(Name, "ChannelEntryTimeout")) ChannelEntryTimeout= atoi(Value);
@@ -771,7 +771,7 @@ bool cSetup::Save(void)
Store("EPGLinger", EPGLinger);
Store("SVDRPTimeout", SVDRPTimeout);
Store("SVDRPPeering", SVDRPPeering);
- Store("SVDRPHostName", SVDRPHostName);
+ Store("SVDRPHostName", strcmp(SVDRPHostName, GetHostName()) ? SVDRPHostName : "");
Store("SVDRPDefaultHost", SVDRPDefaultHost);
Store("ZapTimeout", ZapTimeout);
Store("ChannelEntryTimeout",ChannelEntryTimeout);
diff --git a/config.h b/config.h
index e9a9f11..c67b990 100644
--- a/config.h
+++ b/config.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.h 4.8 2017/03/30 13:42:15 kls Exp $
+ * $Id: config.h 4.9 2017/04/29 13:33:13 kls Exp $
*/
#ifndef __CONFIG_H
@@ -22,13 +22,13 @@
// VDR's own version number:
-#define VDRVERSION "2.3.4"
-#define VDRVERSNUM 20304 // Version * 10000 + Major * 100 + Minor
+#define VDRVERSION "2.3.5"
+#define VDRVERSNUM 20305 // Version * 10000 + Major * 100 + Minor
// The plugin API's version number:
-#define APIVERSION "2.3.4"
-#define APIVERSNUM 20304 // Version * 10000 + Major * 100 + Minor
+#define APIVERSION "2.3.5"
+#define APIVERSNUM 20305 // Version * 10000 + Major * 100 + Minor
// When loading plugins, VDR searches them by their APIVERSION, which
// may be smaller than VDRVERSION in case there have been no changes to
diff --git a/cutter.c b/cutter.c
index 587fddf..67dc4ef 100644
--- a/cutter.c
+++ b/cutter.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: cutter.c 4.2 2015/08/09 12:24:28 kls Exp $
+ * $Id: cutter.c 4.3 2017/05/21 09:45:06 kls Exp $
*/
#include "cutter.h"
@@ -500,7 +500,7 @@ bool cCuttingThread::FixFrame(uchar *Data, int &Length, bool Independent, int In
TsSetContinuityCounter(p, counter[Pid]);
}
else
- counter[Pid] = TsGetContinuityCounter(p); // collect initial counters
+ counter[Pid] = TsContinuityCounter(p); // collect initial counters
// Adjust PTS:
int64_t Pts = TsGetPts(p, TS_SIZE);
if (Pts >= 0) {
diff --git a/device.c b/device.c
index 25d1667..7c1c74b 100644
--- a/device.c
+++ b/device.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 4.15 2017/04/17 14:47:42 kls Exp $
+ * $Id: device.c 4.22 2017/05/18 09:27:55 kls Exp $
*/
#include "device.h"
@@ -293,6 +293,7 @@ cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool LiveView
// to their individual severity, where the one listed first will make the most
// difference, because it results in the most significant bit of the result.
uint32_t imp = 0;
+ imp <<= 1; imp |= (LiveView && NumUsableSlots && !HasInternalCam) ? !ChannelCamRelations.CamDecrypt(Channel->GetChannelID(), CamSlots.Get(j)->MasterSlotNumber()) || ndr : 0; // prefer CAMs that are known to decrypt this channel for live viewing, if we don't need to detach existing receivers
imp <<= 1; imp |= LiveView ? !device[i]->IsPrimaryDevice() || ndr : 0; // prefer the primary device for live viewing if we don't need to detach existing receivers
imp <<= 1; imp |= !device[i]->Receiving() && (device[i] != cTransferControl::ReceiverDevice() || device[i]->IsPrimaryDevice()) || ndr; // use receiving devices if we don't need to detach existing receivers, but avoid primary device in local transfer mode
imp <<= 1; imp |= device[i]->Receiving(); // avoid devices that are receiving
@@ -749,7 +750,7 @@ const cPositioner *cDevice::Positioner(void) const
return NULL;
}
-bool cDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per) const
+bool cDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
{
return false;
}
@@ -782,7 +783,7 @@ bool cDevice::MaySwitchTransponder(const cChannel *Channel) const
bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView)
{
if (LiveView) {
- isyslog("switching to channel %d (%s)", Channel->Number(), Channel->Name());
+ isyslog("switching to channel %d %s (%s)", Channel->Number(), *Channel->GetChannelID().ToString(), Channel->Name());
cControl::Shutdown(); // prevents old channel from being shown too long if GetDevice() takes longer
}
for (int i = 3; i--;) {
@@ -833,6 +834,7 @@ bool cDevice::SwitchChannel(int Direction)
eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
{
+ cMutexLock MutexLock(&mutexReceiver); // to avoid a race between SVDRP CHAN and HasProgramme()
cStatus::MsgChannelSwitch(this, 0, LiveView);
if (LiveView) {
@@ -945,6 +947,7 @@ bool cDevice::HasLock(int TimeoutMs) const
bool cDevice::HasProgramme(void) const
{
+ cMutexLock MutexLock(&mutexReceiver); // to avoid a race between SVDRP CHAN and HasProgramme()
return Replaying() || pidHandles[ptAudio].pid || pidHandles[ptVideo].pid;
}
@@ -1651,7 +1654,8 @@ bool cDevice::Receiving(bool Dummy) const
}
#define TS_SCRAMBLING_TIMEOUT 3 // seconds to wait until a TS becomes unscrambled
-#define TS_SCRAMBLING_TIME_OK 10 // seconds before a Channel/CAM combination is marked as known to decrypt
+#define TS_SCRAMBLING_TIME_OK 3 // seconds before a Channel/CAM combination is marked as known to decrypt
+#define EIT_INJECTION_TIME 10 // seconds for which to inject EIT event
void cDevice::Action(void)
{
@@ -1663,6 +1667,9 @@ void cDevice::Action(void)
if (b) {
// Distribute the packet to all attached receivers:
Lock();
+ cCamSlot *cs = CamSlot();
+ if (cs)
+ cs->TsPostProcess(b);
int Pid = TsPid(b);
bool IsScrambled = TsIsScrambled(b);
for (int i = 0; i < MAXRECEIVERS; i++) {
@@ -1671,7 +1678,7 @@ void cDevice::Action(void)
Receiver->Receive(b, TS_SIZE);
// Check whether the TS packet is scrambled:
if (Receiver->startScrambleDetection) {
- if (cCamSlot *cs = CamSlot()) {
+ if (cs) {
int CamSlotNumber = cs->MasterSlotNumber();
if (Receiver->lastScrambledPacket < Receiver->startScrambleDetection)
Receiver->lastScrambledPacket = Receiver->startScrambleDetection;
@@ -1697,6 +1704,18 @@ void cDevice::Action(void)
}
}
}
+ // Inject EIT event to avoid the CAMs parental rating prompt:
+ if (Receiver->startEitInjection) {
+ time_t Now = time(NULL);
+ if (cCamSlot *cs = CamSlot()) {
+ if (Now != Receiver->lastEitInjection) { // once per second
+ cs->InjectEit(Receiver->ChannelID().Sid());
+ Receiver->lastEitInjection = Now;
+ }
+ }
+ if (Now - Receiver->startEitInjection > EIT_INJECTION_TIME)
+ Receiver->startEitInjection = 0;
+ }
}
}
Unlock();
@@ -1755,6 +1774,10 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
Unlock();
if (camSlot && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
camSlot->StartDecrypting();
+ if (camSlot->WantsTsData()) {
+ Receiver->lastEitInjection = 0;
+ Receiver->startEitInjection = time(NULL);
+ }
if (CamSlots.NumReadyMasterSlots() > 1) { // don't try different CAMs if there is only one
Receiver->startScrambleDetection = time(NULL);
Receiver->scramblingTimeout = TS_SCRAMBLING_TIMEOUT;
diff --git a/device.h b/device.h
index 4796258..f6aee4e 100644
--- a/device.h
+++ b/device.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.h 4.8 2017/04/17 14:46:57 kls Exp $
+ * $Id: device.h 4.9 2017/05/09 11:24:47 kls Exp $
*/
#ifndef __DEVICE_H
@@ -112,6 +112,14 @@ public:
#define DTV_STAT_VALID_BERPRE 0x0004
#define DTV_STAT_VALID_BERPOST 0x0008
#define DTV_STAT_VALID_PER 0x0010
+#define DTV_STAT_VALID_STATUS 0x0020
+
+#define DTV_STAT_HAS_NONE 0x0000
+#define DTV_STAT_HAS_SIGNAL 0x0001
+#define DTV_STAT_HAS_CARRIER 0x0002
+#define DTV_STAT_HAS_VITERBI 0x0004
+#define DTV_STAT_HAS_SYNC 0x0008
+#define DTV_STAT_HAS_LOCK 0x0010
class cDevice : public cThread {
friend class cLiveSubtitle;
@@ -291,13 +299,14 @@ public:
///< move the satellite dish to the requested position (only applies to DVB-S
///< devices). If no positioner is involved, or this is not a DVB-S device,
///< NULL will be returned.
- virtual bool SignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL) const;
+ virtual bool SignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL, int *Status = NULL) const;
///< Returns statistics about the currently received signal (if available).
///< Strength is the signal strength in dBm (typical range -100dBm...0dBm).
///< Cnr is the carrier to noise ratio in dB (typical range 0dB...40dB).
///< BerPre is the bit error rate before the forward error correction (FEC).
///< BerPost is the bit error rate after the forward error correction (FEC).
///< Per is the block error rate after the forward error correction (FEC).
+ ///< Status is the masked frontend status (signal/carrier/viterbi/sync/lock).
///< Typical range for BerPre, BerPost and Per is 0...1.
///< If any of the given pointers is not NULL, the value of the respective signal
///< statistic is returned in it. Upon return, Valid holds a combination of
diff --git a/dvbdevice.c b/dvbdevice.c
index 3a900a3..9e07106 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.c 4.9 2017/04/20 14:42:35 kls Exp $
+ * $Id: dvbdevice.c 4.13 2017/05/09 11:50:38 kls Exp $
*/
#include "dvbdevice.h"
@@ -349,7 +349,7 @@ public:
void SetChannel(const cChannel *Channel);
bool Locked(int TimeoutMs = 0);
const cPositioner *Positioner(void) const { return positioner; }
- bool GetSignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL) const;
+ bool GetSignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL, int *Status = NULL) const;
int GetSignalStrength(void) const;
int GetSignalQuality(void) const;
};
@@ -574,14 +574,29 @@ bool cDvbTuner::GetFrontendStatus(fe_status_t &Status) const
}\
}
-bool cDvbTuner::GetSignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per) const
+bool cDvbTuner::GetSignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
{
ClearEventQueue();
+ fe_status_t FeStatus;
dtv_property Props[MAXFRONTENDCMDS];
dtv_properties CmdSeq;
memset(&Props, 0, sizeof(Props));
memset(&CmdSeq, 0, sizeof(CmdSeq));
CmdSeq.props = Props;
+ Valid = DTV_STAT_VALID_NONE;
+ if (ioctl(fd_frontend, FE_READ_STATUS, &FeStatus) != 0) {
+ esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
+ return false;
+ }
+ if (Status) {
+ *Status = DTV_STAT_HAS_NONE;
+ if (FeStatus & FE_HAS_SIGNAL) *Status |= DTV_STAT_HAS_SIGNAL;
+ if (FeStatus & FE_HAS_CARRIER) *Status |= DTV_STAT_HAS_CARRIER;
+ if (FeStatus & FE_HAS_VITERBI) *Status |= DTV_STAT_HAS_VITERBI;
+ if (FeStatus & FE_HAS_SYNC) *Status |= DTV_STAT_HAS_SYNC;
+ if (FeStatus & FE_HAS_LOCK) *Status |= DTV_STAT_HAS_LOCK;
+ Valid |= DTV_STAT_VALID_STATUS;
+ }
if (Strength) SETCMD(DTV_STAT_SIGNAL_STRENGTH, 0);
if (Cnr) SETCMD(DTV_STAT_CNR, 0);
if (BerPre) { SETCMD(DTV_STAT_PRE_ERROR_BIT_COUNT, 0);
@@ -594,7 +609,6 @@ bool cDvbTuner::GetSignalStats(int &Valid, double *Strength, double *Cnr, double
esyslog("ERROR: frontend %d/%d: %m", adapter, frontend);
return false;
}
- Valid = DTV_STAT_VALID_NONE;
int i = 0;
if (Strength) {
if (Props[i].u.st.len > 0) {
@@ -659,6 +673,7 @@ bool cDvbTuner::GetSignalStats(int &Valid, double *Strength, double *Cnr, double
}
#ifdef DEBUG_SIGNALSTATS
fprintf(stderr, "FE %d/%d: API5 %04X", adapter, frontend, Valid);
+ if ((Valid & DTV_STAT_VALID_STATUS) != 0) fprintf(stderr, " STAT=%04X", *Status);
if ((Valid & DTV_STAT_VALID_STRENGTH) != 0) fprintf(stderr, " STR=%1.1fdBm", *Strength);
if ((Valid & DTV_STAT_VALID_CNR) != 0) fprintf(stderr, " CNR=%1.1fdB", *Cnr);
if ((Valid & DTV_STAT_VALID_BERPRE) != 0) fprintf(stderr, " BERPRE=%1.1e", *BerPre);
@@ -844,13 +859,16 @@ int cDvbTuner::GetSignalQuality(void) const
// be considered low even if there haven't been any more uncorrected bocks
// for quite a while.
Unc = lastUncDelta;
- int t = time(NULL) - lastUncChange - 2;
- if (t > 0)
- Unc >>= min(t, 32);
+ if (Unc > 0) {
+ int t = time(NULL) - lastUncChange - 2;
+ if (t > 0)
+ Unc >>= min(t, int(sizeof(Unc) * 8 - 1));
+ if (Unc == 0)
+ lastUncDelta = 0;
#ifdef DEBUG_SIGNALQUALITY
- if (Unc > 0)
fprintf(stderr, "FE %d/%d: API3 UNC = %u\n", adapter, frontend, Unc);
#endif
+ }
break;
}
if (errno != EINTR) {
@@ -1288,14 +1306,25 @@ const char *DeliverySystemNames[] = {
"ISDBC",
"ATSC",
"ATSCMH",
- "DMBTH",
+ "DTMB",
"CMMB",
"DAB",
"DVB-T2",
"TURBO",
+ "DVB-C",
+ "DVB-C2",
NULL
};
+static const int DeliverySystemNamesMax = sizeof(DeliverySystemNames) / sizeof(DeliverySystemNames[0]) - 2; // -1 to get the maximum allowed index & -1 for the NULL => -2
+
+static const char *GetDeliverySystemName(int Index)
+{
+ if (Index > DeliverySystemNamesMax)
+ Index = 0;
+ return DeliverySystemNames[Index];
+};
+
cDvbDevice::cDvbDevice(int Adapter, int Frontend)
{
adapter = Adapter;
@@ -1393,9 +1422,9 @@ cString cDvbDevice::DeviceType(void) const
{
if (dvbTuner) {
if (dvbTuner->FrontendType() != SYS_UNDEFINED)
- return DeliverySystemNames[dvbTuner->FrontendType()];
+ return GetDeliverySystemName(dvbTuner->FrontendType());
if (numDeliverySystems)
- return DeliverySystemNames[deliverySystems[0]]; // to have some reasonable default
+ return GetDeliverySystemName(deliverySystems[0]); // to have some reasonable default
}
return "";
}
@@ -1526,7 +1555,7 @@ bool cDvbDevice::QueryDeliverySystems(int fd_frontend)
if (numDeliverySystems > 0) {
cString ds("");
for (int i = 0; i < numDeliverySystems; i++)
- ds = cString::sprintf("%s%s%s", *ds, i ? "," : "", DeliverySystemNames[deliverySystems[i]]);
+ ds = cString::sprintf("%s%s%s", *ds, i ? "," : "", GetDeliverySystemName(deliverySystems[i]));
cString ms("");
if (frontendInfo.caps & FE_CAN_QPSK) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QPSK, ModulationValues)); }
if (frontendInfo.caps & FE_CAN_QAM_16) { numModulations++; ms = cString::sprintf("%s%s%s", *ms, **ms ? "," : "", MapToUserString(QAM_16, ModulationValues)); }
@@ -1827,9 +1856,9 @@ const cPositioner *cDvbDevice::Positioner(void) const
return dvbTuner ? dvbTuner->Positioner() : NULL;
}
-bool cDvbDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per) const
+bool cDvbDevice::SignalStats(int &Valid, double *Strength, double *Cnr, double *BerPre, double *BerPost, double *Per, int *Status) const
{
- return dvbTuner ? dvbTuner->GetSignalStats(Valid, Strength, Cnr, BerPre, BerPost, Per) : false;
+ return dvbTuner ? dvbTuner->GetSignalStats(Valid, Strength, Cnr, BerPre, BerPost, Per, Status) : false;
}
int cDvbDevice::SignalStrength(void) const
diff --git a/dvbdevice.h b/dvbdevice.h
index edc9460..0490a44 100644
--- a/dvbdevice.h
+++ b/dvbdevice.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.h 4.3 2017/04/17 14:44:43 kls Exp $
+ * $Id: dvbdevice.h 4.4 2017/05/09 11:24:47 kls Exp $
*/
#ifndef __DVBDEVICE_H
@@ -244,7 +244,7 @@ public:
virtual bool ProvidesEIT(void) const;
virtual int NumProvidedSystems(void) const;
virtual const cPositioner *Positioner(void) const;
- virtual bool SignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL) const;
+ virtual bool SignalStats(int &Valid, double *Strength = NULL, double *Cnr = NULL, double *BerPre = NULL, double *BerPost = NULL, double *Per = NULL, int *Status = NULL) const;
virtual int SignalStrength(void) const;
virtual int SignalQuality(void) const;
virtual const cChannel *GetCurrentlyTunedTransponder(void) const;
diff --git a/eit.c b/eit.c
index cfed4d0..ade7928 100644
--- a/eit.c
+++ b/eit.c
@@ -8,7 +8,7 @@
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
* Adapted to 'libsi' for VDR 1.3.0 by Marcel Wiesweg <marcel.wiesweg@gmx.de>.
*
- * $Id: eit.c 4.2 2017/03/31 15:16:46 kls Exp $
+ * $Id: eit.c 4.3 2017/05/03 08:58:41 kls Exp $
*/
#include "eit.h"
@@ -79,6 +79,7 @@ cEIT::cEIT(cSectionSyncerHash &SectionSyncerHash, int Source, u_char Tid, const
bool Empty = true;
bool Modified = false;
+ time_t LingerLimit = Now - Setup.EPGLinger * 60;
time_t SegmentStart = 0;
time_t SegmentEnd = 0;
struct tm t = { 0 };
@@ -93,6 +94,9 @@ cEIT::cEIT(cSectionSyncerHash &SectionSyncerHash, int Source, u_char Tid, const
// Drop bogus events - but keep NVOD reference events, where all bits of the start time field are set to 1, resulting in a negative number.
if (StartTime == 0 || StartTime > 0 && Duration == 0)
continue;
+ // Ignore events that ended before the "EPG linger time":
+ if (StartTime + Duration < LingerLimit)
+ continue;
Empty = false;
if (!SegmentStart)
SegmentStart = StartTime;
diff --git a/eit.h b/eit.h
index 51af643..c93aabc 100644
--- a/eit.h
+++ b/eit.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: eit.h 4.1 2015/07/25 11:03:53 kls Exp $
+ * $Id: eit.h 4.2 2017/05/08 21:10:29 kls Exp $
*/
#ifndef __EIT_H
@@ -15,7 +15,10 @@
class cSectionSyncerEntry : public cListObject, public cSectionSyncer {};
-class cSectionSyncerHash : public cHash<cSectionSyncerEntry> {};
+class cSectionSyncerHash : public cHash<cSectionSyncerEntry> {
+public:
+ cSectionSyncerHash(void) : cHash(HASHSIZE, true) {};
+ };
class cEitFilter : public cFilter {
private:
diff --git a/epg.c b/epg.c
index c67b645..7cbb011 100644
--- a/epg.c
+++ b/epg.c
@@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
- * $Id: epg.c 4.4 2017/04/02 11:34:15 kls Exp $
+ * $Id: epg.c 4.6 2017/05/09 12:16:36 kls Exp $
*/
#include "epg.h"
@@ -529,15 +529,14 @@ bool cEvent::Parse(char *s)
return true;
}
-bool cEvent::Read(FILE *f, cSchedule *Schedule)
+bool cEvent::Read(FILE *f, cSchedule *Schedule, int &Line)
{
if (Schedule) {
cEvent *Event = NULL;
char *s;
- int line = 0;
cReadLine ReadLine;
while ((s = ReadLine.Read(f)) != NULL) {
- line++;
+ Line++;
char *t = skipspace(s + 1);
switch (*s) {
case 'E': if (!Event) {
@@ -573,7 +572,7 @@ bool cEvent::Read(FILE *f, cSchedule *Schedule)
case 'c': // to keep things simple we react on 'c' here
return true;
default: if (Event && !Event->Parse(s)) {
- esyslog("ERROR: EPG data problem in line %d", line);
+ esyslog("ERROR: EPG data problem in line %d", Line);
return false;
}
}
@@ -1098,7 +1097,7 @@ void cSchedule::Cleanup(time_t Time)
{
cEvent *Event;
while ((Event = events.First()) != NULL) {
- if (!Event->HasTimer() && Event->EndTime() + Setup.EPGLinger * 60 + 3600 < Time) // adding one hour for safety
+ if (!Event->HasTimer() && Event->EndTime() + Setup.EPGLinger * 60 < Time)
DelEvent(Event);
else
break;
@@ -1141,9 +1140,11 @@ void cSchedule::Dump(FILE *f, const char *Prefix, eDumpMode DumpMode, time_t AtT
bool cSchedule::Read(FILE *f, cSchedules *Schedules)
{
if (Schedules) {
+ int Line = 0;
cReadLine ReadLine;
char *s;
while ((s = ReadLine.Read(f)) != NULL) {
+ Line++;
if (*s == 'C') {
s = skipspace(s + 1);
char *p = strchr(s, ' ');
@@ -1153,7 +1154,7 @@ bool cSchedule::Read(FILE *f, cSchedules *Schedules)
tChannelID channelID = tChannelID::FromString(s);
if (channelID.Valid()) {
if (cSchedule *p = Schedules->AddSchedule(channelID)) {
- if (!cEvent::Read(f, p))
+ if (!cEvent::Read(f, p, Line))
return false;
p->Sort();
}
@@ -1165,7 +1166,7 @@ bool cSchedule::Read(FILE *f, cSchedules *Schedules)
}
}
else {
- esyslog("ERROR: unexpected tag while reading EPG data: %s", s);
+ esyslog("ERROR: unexpected tag in line %d while reading EPG data: %s", Line, s);
return false;
}
}
diff --git a/epg.h b/epg.h
index 1341aa2..fe536a7 100644
--- a/epg.h
+++ b/epg.h
@@ -7,7 +7,7 @@
* Original version (as used in VDR before 1.3.0) written by
* Robert Schneider <Robert.Schneider@web.de> and Rolf Hakenes <hakenes@hippomi.de>.
*
- * $Id: epg.h 4.4 2017/04/02 11:22:21 kls Exp $
+ * $Id: epg.h 4.6 2017/05/09 12:15:14 kls Exp $
*/
#ifndef __EPG_H
@@ -141,7 +141,7 @@ public:
cString ToDescr(void) const;
void Dump(FILE *f, const char *Prefix = "", bool InfoOnly = false) const;
bool Parse(char *s);
- static bool Read(FILE *f, cSchedule *Schedule);
+ static bool Read(FILE *f, cSchedule *Schedule, int &Line);
void FixEpgBugs(void);
};
@@ -284,7 +284,7 @@ public:
virtual bool DropOutdated(cSchedule *Schedule, time_t SegmentStart, time_t SegmentEnd, uchar TableID, uchar Version) { return false; }
///< Takes a look at all EPG events between SegmentStart and SegmentEnd and
///< drops outdated events.
- virtual bool BeginSegmentTransfer(const cChannel *Channel, bool Dummy) { return false; } // TODO remove obsolete Dummy
+ virtual bool BeginSegmentTransfer(const cChannel *Channel, bool Dummy) { return true; } // TODO remove obsolete Dummy
///< Called directly after IgnoreChannel() before any other handler method is called.
///< Designed to give handlers the possibility to prepare a database transaction.
///< If any EPG handler returns false in this function, it is assumed that
diff --git a/filter.c b/filter.c
index aa91c1f..3156d14 100644
--- a/filter.c
+++ b/filter.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: filter.c 4.2 2015/07/25 10:59:57 kls Exp $
+ * $Id: filter.c 4.3 2017/05/07 15:20:45 kls Exp $
*/
#include "filter.h"
@@ -71,6 +71,15 @@ cFilterData::cFilterData(u_short Pid, u_char Tid, u_char Mask, bool Sticky)
sticky = Sticky;
}
+cFilterData& cFilterData::operator= (const cFilterData &FilterData)
+{
+ pid = FilterData.pid;
+ tid = FilterData.tid;
+ mask = FilterData.mask;
+ sticky = FilterData.sticky;
+ return *this;
+}
+
bool cFilterData::Is(u_short Pid, u_char Tid, u_char Mask)
{
return pid == Pid && tid == Tid && mask == Mask;
diff --git a/filter.h b/filter.h
index 7cc3ec3..8ac83c0 100644
--- a/filter.h
+++ b/filter.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: filter.h 4.2 2015/07/25 10:03:44 kls Exp $
+ * $Id: filter.h 4.3 2017/05/07 15:18:48 kls Exp $
*/
#ifndef __FILTER_H
@@ -38,6 +38,7 @@ public:
bool sticky;
cFilterData(void);
cFilterData(u_short Pid, u_char Tid, u_char Mask, bool Sticky);
+ cFilterData& operator= (const cFilterData &FilterData);
bool Is(u_short Pid, u_char Tid, u_char Mask);
bool Matches(u_short Pid, u_char Tid);
};
diff --git a/libsi/Makefile b/libsi/Makefile
index 4c7630c..2ae223b 100644
--- a/libsi/Makefile
+++ b/libsi/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for a libsi
#
-# $Id: Makefile 4.0 2015/02/11 10:24:54 kls Exp $
+# $Id: Makefile 4.1 2017/05/22 15:33:20 kls Exp $
### The archiver options:
@@ -18,7 +18,8 @@ OBJS = util.o si.o section.o descriptor.o
### Implicit rules:
%.o: %.c
- $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
+ @echo CC libsi/$@
+ @$(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) $<
### Dependencies:
@@ -35,7 +36,8 @@ all: libsi.a
@:
libsi.a : $(OBJS)
- $(AR) $(ARFLAGS) $@ $(OBJS)
+ @echo AR libsi/$@
+ @$(AR) $(ARFLAGS) $@ $(OBJS)
clean:
@-rm -f $(OBJS) $(DEPFILE) *.a *.so *.tgz core* *~
diff --git a/menu.c b/menu.c
index 357aaf8..246c4df 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 4.25 2017/04/20 09:15:49 kls Exp $
+ * $Id: menu.c 4.29 2017/05/21 13:18:26 kls Exp $
*/
#include "menu.h"
@@ -1328,7 +1328,7 @@ eOSState cMenuTimers::New(void)
if (HasSubMenu())
return osContinue;
cTimer *Timer = new cTimer;
- if (*Setup.SVDRPDefaultHost)
+ if (Setup.SVDRPPeering && *Setup.SVDRPDefaultHost)
Timer->SetRemote(Setup.SVDRPDefaultHost);
return AddSubMenu(new cMenuEditTimer(Timer, true));
}
@@ -1660,7 +1660,7 @@ eOSState cMenuWhatsOn::Record(void)
return AddSubMenu(new cMenuEditTimer(Timer));
}
cTimer *Timer = new cTimer(item->event);
- if (*Setup.SVDRPDefaultHost)
+ if (Setup.SVDRPPeering && *Setup.SVDRPDefaultHost)
Timer->SetRemote(Setup.SVDRPDefaultHost);
if (cTimer *t = Timers->GetTimer(Timer)) {
delete Timer;
@@ -1674,7 +1674,6 @@ eOSState cMenuWhatsOn::Record(void)
if (!HandleRemoteModifications(Timer)) {
// must add the timer before HandleRemoteModifications to get proper log messages with timer ids
Timers->Del(Timer);
- delete Timer;
}
}
if (HasSubMenu())
@@ -1692,7 +1691,7 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
- switch (Key) {
+ switch (int(Key)) {
case kRecord:
case kRed: return Record();
case kYellow: state = osBack;
@@ -1708,6 +1707,20 @@ eOSState cMenuWhatsOn::ProcessKey(eKeys Key)
case kBlue: if (canSwitch)
return Switch();
break;
+ case kChanUp|k_Repeat:
+ case kChanUp:
+ case kChanDn|k_Repeat:
+ case kChanDn: if (!HasSubMenu()) {
+ for (cOsdItem *item = First(); item; item = Next(item)) {
+ if (((cMenuScheduleItem *)item)->channel->Number() == cDevice::CurrentChannel()) {
+ SetCurrent(item);
+ Display();
+ SetHelpKeys();
+ break;
+ }
+ }
+ }
+ break;
case kInfo:
case kOk: if (Count()) {
LOCK_TIMERS_READ;
@@ -1944,7 +1957,7 @@ eOSState cMenuSchedule::Record(void)
return AddSubMenu(new cMenuEditTimer(Timer));
}
cTimer *Timer = new cTimer(item->event);
- if (*Setup.SVDRPDefaultHost)
+ if (Setup.SVDRPPeering && *Setup.SVDRPDefaultHost)
Timer->SetRemote(Setup.SVDRPDefaultHost);
if (cTimer *t = Timers->GetTimer(Timer)) {
delete Timer;
@@ -1958,7 +1971,6 @@ eOSState cMenuSchedule::Record(void)
if (!HandleRemoteModifications(Timer)) {
// must add the timer before HandleRemoteModifications to get proper log messages with timer ids
Timers->Del(Timer);
- delete Timer;
}
}
if (HasSubMenu())
@@ -1995,7 +2007,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
eOSState state = cOsdMenu::ProcessKey(Key);
if (state == osUnknown) {
- switch (Key) {
+ switch (int(Key)) {
case k0: return Number();
case kRecord:
case kRed: return Record();
@@ -2025,6 +2037,15 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
case kBlue: if (canSwitch)
return Switch();
break;
+ case kChanUp|k_Repeat:
+ case kChanUp:
+ case kChanDn|k_Repeat:
+ case kChanDn: if (!HasSubMenu()) {
+ LOCK_CHANNELS_READ;
+ if (const cChannel *Channel = Channels->GetByNumber(cDevice::CurrentChannel()))
+ Set(Channel, true);
+ }
+ break;
case kInfo:
case kOk: if (Count()) {
LOCK_TIMERS_READ;
@@ -2243,7 +2264,7 @@ void cMenuCam::Set(void)
SetHasHotkeys(ciMenu->Selectable());
GenerateTitle(ciMenu->TitleText());
dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->TitleText());
- if (*ciMenu->SubTitleText()) {
+ if (!isempty(ciMenu->SubTitleText())) {
dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->SubTitleText());
AddMultiLineItem(ciMenu->SubTitleText());
offset = Count();
@@ -2252,7 +2273,7 @@ void cMenuCam::Set(void)
Add(new cOsdItem(hk(ciMenu->Entry(i)), osUnknown, ciMenu->Selectable()));
dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->Entry(i));
}
- if (*ciMenu->BottomText()) {
+ if (!isempty(ciMenu->BottomText())) {
AddMultiLineItem(ciMenu->BottomText());
dsyslog("CAM %d: '%s'", camSlot->SlotNumber(), ciMenu->BottomText());
}
@@ -5185,7 +5206,7 @@ bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause)
int Priority = Timer ? Timer->Priority() : Pause ? Setup.PausePriority : Setup.DefaultPriority;
cDevice *device = cDevice::GetDevice(Channel, Priority, false);
if (device) {
- dsyslog("switching device %d to channel %d (%s)", device->DeviceNumber() + 1, Channel->Number(), Channel->Name());
+ dsyslog("switching device %d to channel %d %s (%s)", device->DeviceNumber() + 1, Channel->Number(), *Channel->GetChannelID().ToString(), Channel->Name());
if (!device->SwitchChannel(Channel, false)) {
ShutdownHandler.RequestEmergencyExit();
return false;
diff --git a/mtd.c b/mtd.c
index 29fe520..345288e 100644
--- a/mtd.c
+++ b/mtd.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: mtd.c 1.10 2017/04/26 08:33:54 kls Exp $
+ * $Id: mtd.c 1.11 2017/05/01 09:19:52 kls Exp $
*/
#include "mtd.h"
@@ -64,22 +64,20 @@ int cMtdHandler::Put(const uchar *Data, int Count)
if (int Skipped = TS_SYNC(Data, Count))
return Used + Skipped;
int Pid = TsPid(Data);
- if (Pid != CATPID) { // the original CAT with mapped PIDs must be skipped here!
#ifdef KEEPPIDS
- int Index = 0;
+ int Index = 0;
#else
- int Index = (Pid >> UNIQ_PID_SHIFT) - 1;
+ int Index = (Pid >> UNIQ_PID_SHIFT) - 1;
#endif // KEEPPIDS
- if (Index >= 0 && Index < camSlots.Size()) {
- int w = camSlots[Index]->PutData(Data, TS_SIZE);
- if (w == 0)
- break;
- else if (w != TS_SIZE)
- esyslog("ERROR: incomplete MTD packet written (%d) in PID %d (%04X)", Index + 1, Pid, Pid);
- }
- else if (Index >= 0) // we silently ignore Index -1 (i.e. MTD number 0), since there are several hundred empty TS packets when switching to an encrypted channel for the first time since startup
- esyslog("ERROR: invalid MTD number (%d) in PID %d (%04X)", Index + 1, Pid, Pid);
+ if (Index >= 0 && Index < camSlots.Size()) {
+ int w = camSlots[Index]->PutData(Data, TS_SIZE);
+ if (w == 0)
+ break;
+ else if (w != TS_SIZE)
+ esyslog("ERROR: incomplete MTD packet written (%d) in PID %d (%04X)", Index + 1, Pid, Pid);
}
+ else if (Index >= 0) // anything with Index -1 (i.e. MTD number 0) is either garbage or an actual CAT or EIT, which need not be returned to the device
+ esyslog("ERROR: invalid MTD number (%d) in PID %d (%04X)", Index + 1, Pid, Pid);
Data += TS_SIZE;
Count -= TS_SIZE;
Used += TS_SIZE;
@@ -329,6 +327,11 @@ uchar *cMtdCamSlot::Decrypt(uchar *Data, int &Count)
return d;
}
+void cMtdCamSlot::InjectEit(int Sid)
+{
+ MasterSlot()->InjectEit(mtdMapper->RealToUniqSid(Sid));
+}
+
int cMtdCamSlot::PutData(const uchar *Data, int Count)
{
int Free = mtdBuffer->Free();
diff --git a/mtd.h b/mtd.h
index 7f2151a..2be5f3d 100644
--- a/mtd.h
+++ b/mtd.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: mtd.h 1.7 2017/04/26 09:17:08 kls Exp $
+ * $Id: mtd.h 1.8 2017/05/01 09:19:21 kls Exp $
*/
#ifndef __MTD_H
@@ -172,6 +172,7 @@ public:
virtual void StartDecrypting(void);
virtual void StopDecrypting(void);
virtual uchar *Decrypt(uchar *Data, int &Count);
+ virtual void InjectEit(int Sid);
int PutData(const uchar *Data, int Count);
int PutCat(const uchar *Data, int Count);
// The following functions shall not be called for a cMtdCamSlot:
diff --git a/newplugin b/newplugin
index d8e9243..161ffda 100755
--- a/newplugin
+++ b/newplugin
@@ -12,7 +12,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: newplugin 4.1 2015/09/10 11:11:14 kls Exp $
+# $Id: newplugin 4.2 2017/05/22 15:34:01 kls Exp $
$PLUGIN_NAME = $ARGV[0] || die "Usage: newplugin <name>\n";
@@ -121,7 +121,8 @@ all: \$(SOFILE) i18n
### Implicit rules:
%.o: %.c
- \$(CXX) \$(CXXFLAGS) -c \$(DEFINES) \$(INCLUDES) -o \$\@ \$<
+ \@echo CC \$\@
+ \@\$(CXX) \$(CXXFLAGS) -c \$(DEFINES) \$(INCLUDES) -o \$\@ \$<
### Dependencies:
@@ -141,13 +142,16 @@ I18Nmsgs = \$(addprefix \$(DESTDIR)\$(LOCDIR)/, \$(addsuffix /LC_MESSAGES/vdr-\
I18Npot = \$(PODIR)/\$(PLUGIN).pot
%.mo: %.po
- msgfmt -c -o \$\@ \$<
+ \@echo MO \$\@
+ \@msgfmt -c -o \$\@ \$<
\$(I18Npot): \$(wildcard *.c)
- xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-\$(PLUGIN) --package-version=\$(VERSION) --msgid-bugs-address='<see README>' -o \$\@ `ls \$^`
+ \@echo GT \$\@
+ \@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)
- msgmerge -U --no-wrap --no-location --backup=none -q -N \$\@ \$<
+ \@echo PO \$\@
+ \@msgmerge -U --no-wrap --no-location --backup=none -q -N \$\@ \$<
\@touch \$\@
\$(I18Nmsgs): \$(DESTDIR)\$(LOCDIR)/%/LC_MESSAGES/vdr-\$(PLUGIN).mo: \$(PODIR)/%.mo
@@ -161,7 +165,8 @@ install-i18n: \$(I18Nmsgs)
### Targets:
\$(SOFILE): \$(OBJS)
- \$(CXX) \$(CXXFLAGS) \$(LDFLAGS) -shared \$(OBJS) -o \$\@
+ \@echo LD \$\@
+ \@\$(CXX) \$(CXXFLAGS) \$(LDFLAGS) -shared \$(OBJS) -o \$\@
install-lib: \$(SOFILE)
install -D \$^ \$(DESTDIR)\$(LIBDIR)/\$^.\$(APIVERSION)
diff --git a/receiver.c b/receiver.c
index 8009e91..f664da4 100644
--- a/receiver.c
+++ b/receiver.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: receiver.c 4.3 2017/04/01 15:55:38 kls Exp $
+ * $Id: receiver.c 4.4 2017/05/01 08:49:20 kls Exp $
*/
#include "receiver.h"
@@ -19,6 +19,8 @@ cReceiver::cReceiver(const cChannel *Channel, int Priority)
lastScrambledPacket = 0;
startScrambleDetection = 0;
scramblingTimeout = 0;
+ startEitInjection = 0;
+ lastEitInjection = 0;
SetPids(Channel);
}
diff --git a/receiver.h b/receiver.h
index 184d2ee..9bbc6bd 100644
--- a/receiver.h
+++ b/receiver.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: receiver.h 4.2 2017/04/01 15:55:27 kls Exp $
+ * $Id: receiver.h 4.3 2017/05/01 08:48:34 kls Exp $
*/
#ifndef __RECEIVER_H
@@ -25,6 +25,8 @@ private:
time_t lastScrambledPacket;
time_t startScrambleDetection;
int scramblingTimeout;
+ time_t startEitInjection;
+ time_t lastEitInjection;
bool WantsPid(int Pid);
protected:
cDevice *Device(void) { return device; }
diff --git a/remux.c b/remux.c
index 4a3ff14..6993e9b 100644
--- a/remux.c
+++ b/remux.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remux.c 4.6 2017/04/24 14:59:39 kls Exp $
+ * $Id: remux.c 4.7 2017/04/29 12:25:09 kls Exp $
*/
#include "remux.h"
@@ -940,6 +940,93 @@ bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
return patVersion >= 0 && pmtVersion >= 0;
}
+// --- cEitGenerator ---------------------------------------------------------
+
+cEitGenerator::cEitGenerator(int Sid)
+{
+ counter = 0;
+ version = 0;
+ if (Sid)
+ Generate(Sid);
+}
+
+uint16_t cEitGenerator::YMDtoMJD(int Y, int M, int D)
+{
+ int L = (M < 3) ? 1 : 0;
+ return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
+}
+
+uchar *cEitGenerator::AddParentalRatingDescriptor(uchar *p, uchar ParentalRating)
+{
+ *p++ = SI::ParentalRatingDescriptorTag;
+ *p++ = 0x04; // descriptor length
+ *p++ = 'D'; // country code
+ *p++ = 'E';
+ *p++ = 'U';
+ *p++ = ParentalRating;
+ return p;
+}
+
+uchar *cEitGenerator::Generate(int Sid)
+{
+ uchar *PayloadStart;
+ uchar *SectionStart;
+ uchar *DescriptorsStart;
+ memset(eit, 0xFF, sizeof(eit));
+ struct tm tm_r;
+ time_t t = time(NULL) - 3600; // let's have the event start one hour in the past
+ tm *tm = localtime_r(&t, &tm_r);
+ uint16_t MJD = YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
+ uchar *p = eit;
+ // TS header:
+ *p++ = TS_SYNC_BYTE;
+ *p++ = TS_PAYLOAD_START;
+ *p++ = EITPID;
+ *p++ = 0x10 | (counter++ & 0x0F); // continuity counter
+ *p++ = 0x00; // pointer field (payload unit start indicator is set)
+ // payload:
+ PayloadStart = p;
+ *p++ = 0x4E; // TID present/following event on this transponder
+ *p++ = 0xF0;
+ *p++ = 0x00; // section length
+ SectionStart = p;
+ *p++ = Sid >> 8;
+ *p++ = Sid & 0xFF;
+ *p++ = 0xC1 | (version << 1);
+ *p++ = 0x00; // section number
+ *p++ = 0x00; // last section number
+ *p++ = 0x00; // transport stream id
+ *p++ = 0x00; // ...
+ *p++ = 0x00; // original network id
+ *p++ = 0x00; // ...
+ *p++ = 0x00; // segment last section number
+ *p++ = 0x4E; // last table id
+ *p++ = 0x00; // event id
+ *p++ = 0x01; // ...
+ *p++ = MJD >> 8; // start time
+ *p++ = MJD & 0xFF; // ...
+ *p++ = tm->tm_hour; // ...
+ *p++ = tm->tm_min; // ...
+ *p++ = tm->tm_sec; // ...
+ *p++ = 0x24; // duration (one day, should cover everything)
+ *p++ = 0x00; // ...
+ *p++ = 0x00; // ...
+ *p++ = 0x90; // running status, free/CA mode
+ *p++ = 0x00; // descriptors loop length
+ DescriptorsStart = p;
+ p = AddParentalRatingDescriptor(p);
+ // fill in lengths:
+ *(SectionStart - 1) = p - SectionStart + 4; // +4 = length of CRC
+ *(DescriptorsStart - 1) = p - DescriptorsStart;
+ // checksum
+ int crc = SI::CRC32::crc32((char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
+ *p++ = crc >> 24;
+ *p++ = crc >> 16;
+ *p++ = crc >> 8;
+ *p++ = crc;
+ return eit;
+}
+
// --- cTsToPes --------------------------------------------------------------
cTsToPes::cTsToPes(void)
diff --git a/remux.h b/remux.h
index 7dd5b16..eea8a84 100644
--- a/remux.h
+++ b/remux.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: remux.h 4.3 2017/03/26 13:06:37 kls Exp $
+ * $Id: remux.h 4.5 2017/05/21 09:44:52 kls Exp $
*/
#ifndef __REMUX_H
@@ -51,6 +51,7 @@ public:
#define PATPID 0x0000 // PAT PID (constant 0)
#define CATPID 0x0001 // CAT PID (constant 1)
+#define EITPID 0x0012 // EIT PID (constant 18)
#define MAXPID 0x2000 // for arrays that use a PID as the index
#define PTSTICKS 90000 // number of PTS ticks per second
@@ -94,7 +95,7 @@ inline bool TsIsScrambled(const uchar *p)
return p[3] & TS_SCRAMBLING_CONTROL;
}
-inline uchar TsGetContinuityCounter(const uchar *p)
+inline uchar TsContinuityCounter(const uchar *p)
{
return p[3] & TS_CONT_CNT_MASK;
}
@@ -120,11 +121,6 @@ inline int TsGetPayload(const uchar **p)
return 0;
}
-inline int TsContinuityCounter(const uchar *p)
-{
- return p[3] & TS_CONT_CNT_MASK;
-}
-
inline int64_t TsGetPcr(const uchar *p)
{
if (TsHasAdaptationField(p)) {
@@ -431,6 +427,22 @@ public:
uint16_t AncillaryPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? ancillaryPageIds[i] : uint16_t(0); }
};
+// EIT Generator:
+
+class cEitGenerator {
+private:
+ uchar eit[TS_SIZE];
+ int counter;
+ int version;
+ uint16_t YMDtoMJD(int Y, int M, int D);
+ uchar *AddParentalRatingDescriptor(uchar *p, uchar ParentalRating = 0);
+public:
+ cEitGenerator(int Sid = 0);
+ uchar *Generate(int Sid);
+ uchar *Data(void) { return eit; }
+ int Length(void) { return sizeof(eit); }
+ };
+
// TS to PES converter:
// Puts together the payload of several TS packets that form one PES
// packet.
diff --git a/svdrp.c b/svdrp.c
index 993150c..f402c21 100644
--- a/svdrp.c
+++ b/svdrp.c
@@ -10,7 +10,7 @@
* and interact with the Video Disk Recorder - or write a full featured
* graphical interface that sits on top of an SVDRP connection.
*
- * $Id: svdrp.c 4.17 2017/04/22 11:57:31 kls Exp $
+ * $Id: svdrp.c 4.18 2017/05/18 15:51:24 kls Exp $
*/
#include "svdrp.h"
@@ -384,6 +384,8 @@ void cSVDRPClient::Close(void)
SVDRPClientPoller.Del(file, false);
file.Close();
socket.Close();
+ LOCK_TIMERS_WRITE;
+ Timers->DelRemoteTimers(serverName);
}
}
diff --git a/tools.c b/tools.c
index 754673d..a8e6af1 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 4.5 2016/12/23 14:03:40 kls Exp $
+ * $Id: tools.c 4.6 2017/05/09 08:32:54 kls Exp $
*/
#include "tools.h"
@@ -2312,9 +2312,10 @@ void cDynamicBuffer::Append(const uchar *Data, int Length)
// --- cHashBase -------------------------------------------------------------
-cHashBase::cHashBase(int Size)
+cHashBase::cHashBase(int Size, bool OwnObjects)
{
size = Size;
+ ownObjects = OwnObjects;
hashTable = (cList<cHashObject>**)calloc(size, sizeof(cList<cHashObject>*));
}
@@ -2348,6 +2349,13 @@ void cHashBase::Del(cListObject *Object, unsigned int Id)
void cHashBase::Clear(void)
{
for (int i = 0; i < size; i++) {
+ if (ownObjects) {
+ cList<cHashObject> *list = hashTable[i];
+ if (list) {
+ for (cHashObject *hob = list->First(); hob; hob = list->Next(hob))
+ delete hob->object;
+ }
+ }
delete hashTable[i];
hashTable[i] = NULL;
}
diff --git a/tools.h b/tools.h
index d2234c3..f823077 100644
--- a/tools.h
+++ b/tools.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.h 4.6 2017/03/16 16:04:43 kls Exp $
+ * $Id: tools.h 4.10 2017/05/22 11:07:04 kls Exp $
*/
#ifndef __TOOLS_H
@@ -51,10 +51,14 @@ template<class T> inline void DELETENULL(T *&p) { T *q = p; p = NULL; delete q;
#define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls
#define FATALERRNO (errno && errno != EAGAIN && errno != EINTR)
-#ifndef __STL_CONFIG_H // in case some plugin needs to use the STL
+#ifndef _STL_ALGOBASE_H // in case some plugin needs to use the STL
template<class T> inline T min(T a, T b) { return a <= b ? a : b; }
template<class T> inline T max(T a, T b) { return a >= b ? a : b; }
+#endif
+#ifndef __STL_CONFIG_H // in case some plugin needs to use the STL
template<class T> inline int sgn(T a) { return a < 0 ? -1 : a > 0 ? 1 : 0; }
+#endif
+#ifndef _MOVE_H // in case some plugin needs to use the STL
template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
#endif
@@ -479,6 +483,8 @@ class cListObject {
friend class cListGarbageCollector;
private:
cListObject *prev, *next;
+ cListObject(const cListObject &ListObject) { abort(); } // no copy constructor!
+ cListObject& operator= (const cListObject &ListObject) { abort(); return *this; } // no assignment operator!
public:
cListObject(void);
virtual ~cListObject();
@@ -825,9 +831,14 @@ class cHashBase {
private:
cList<cHashObject> **hashTable;
int size;
+ bool ownObjects;
unsigned int hashfn(unsigned int Id) const { return Id % size; }
protected:
- cHashBase(int Size);
+ cHashBase(int Size, bool OwnObjects);
+ ///< Creates a new hash of the given Size. If OwnObjects is true, the
+ ///< hash takes ownership of the objects given in the calls to Add(),
+ ///< and deletes them when Clear() is called or the hash is destroyed
+ ///< (unless the object has been removed from the hash by calling Del()).
public:
virtual ~cHashBase();
void Add(cListObject *Object, unsigned int Id);
@@ -841,7 +852,7 @@ public:
template<class T> class cHash : public cHashBase {
public:
- cHash(int Size = HASHSIZE) : cHashBase(Size) {}
+ cHash(int Size = HASHSIZE, bool OwnObjects = false) : cHashBase(Size, OwnObjects) {}
T *Get(unsigned int Id) const { return (T *)cHashBase::Get(Id); }
};
diff --git a/vdr.c b/vdr.c
index 925f35f..41dbc8f 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.tvdr.de
*
- * $Id: vdr.c 4.12 2017/04/03 12:35:37 kls Exp $
+ * $Id: vdr.c 4.14 2017/05/21 12:31:37 kls Exp $
*/
#include <getopt.h>
@@ -1151,7 +1151,7 @@ int main(int argc, char *argv[])
if (!Device->IsTunedToTransponder(Timer->Channel())) {
if (Device == cDevice::ActualDevice() && !Device->IsPrimaryDevice())
cDevice::PrimaryDevice()->StopReplay(); // stop transfer mode
- dsyslog("switching device %d to channel %d (%s)", Device->DeviceNumber() + 1, Timer->Channel()->Number(), Timer->Channel()->Name());
+ dsyslog("switching device %d to channel %d %s (%s)", Device->DeviceNumber() + 1, Timer->Channel()->Number(), *Timer->Channel()->GetChannelID().ToString(), Timer->Channel()->Name());
if (Device->SwitchChannel(Timer->Channel(), false))
Device->SetOccupied(TIMERDEVICETIMEOUT);
}
@@ -1282,7 +1282,6 @@ int main(int argc, char *argv[])
}
else
cDevice::SwitchChannel(NORMALKEY(key) == kChanUp ? 1 : -1);
- key = kNone; // nobody else needs to see these keys
break;
// Volume control:
case kVolUp|k_Repeat: