summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2013-11-28 20:56:20 +0000
committerrandomdan <randomdan@localhost>2013-11-28 20:56:20 +0000
commit79eec1ed7f52b06395417bae225132be99f6b92e (patch)
treeab3f8706b07314bfe9ada95a3df8ea975eb8ea74
parentCompat fixes for recent p2 updates (diff)
downloadp2pvr-79eec1ed7f52b06395417bae225132be99f6b92e.tar.bz2
p2pvr-79eec1ed7f52b06395417bae225132be99f6b92e.tar.xz
p2pvr-79eec1ed7f52b06395417bae225132be99f6b92e.zip
First commit for big refactor into a Project2 daemon, much still to do, but much core stuff in place
-rw-r--r--p2pvr/.p2config6
-rw-r--r--p2pvr/Jamfile.jam27
-rw-r--r--p2pvr/carddaemon/Jamfile.jam10
-rw-r--r--p2pvr/carddaemon/carddaemon.cpp53
-rw-r--r--p2pvr/cron/epg.xml35
-rw-r--r--p2pvr/cron/importEpg.xml67
-rw-r--r--p2pvr/cron/importServices.xml28
-rw-r--r--p2pvr/cron/services.xml16
-rw-r--r--p2pvr/daemon/Jamfile.jam10
-rw-r--r--p2pvr/daemon/daemon.cpp64
-rw-r--r--p2pvr/datasources/postgres.xml6
-rw-r--r--p2pvr/datasources/schema.sql382
-rw-r--r--p2pvr/doc/en_300468v011101p.pdfbin0 -> 1424273 bytes
-rw-r--r--p2pvr/ice/Jamfile.jam13
-rw-r--r--p2pvr/ice/commonHelpers.h22
-rw-r--r--p2pvr/ice/p2pvr.ice248
-rw-r--r--p2pvr/lib/Jamfile.jam18
-rw-r--r--p2pvr/lib/containerCreator.h32
-rw-r--r--p2pvr/lib/containerIterator.h41
-rw-r--r--p2pvr/lib/dvbsiHelpers.cpp190
-rw-r--r--p2pvr/lib/dvbsiHelpers.h60
-rw-r--r--p2pvr/lib/fileHandle.cpp27
-rw-r--r--p2pvr/lib/fileHandle.h19
-rw-r--r--p2pvr/lib/frontend.cpp35
-rw-r--r--p2pvr/lib/frontend.h32
-rw-r--r--p2pvr/lib/frontends/ofdm.cpp145
-rw-r--r--p2pvr/lib/globalDevices.cpp59
-rw-r--r--p2pvr/lib/globalDevices.h24
-rw-r--r--p2pvr/lib/localDevices.cpp151
-rw-r--r--p2pvr/lib/localDevices.h42
-rw-r--r--p2pvr/lib/maintenance.cpp288
-rw-r--r--p2pvr/lib/maintenance.h18
-rw-r--r--p2pvr/lib/objectRowState.h43
-rw-r--r--p2pvr/lib/p2Helpers.cpp18
-rw-r--r--p2pvr/lib/p2Helpers.h46
-rw-r--r--p2pvr/lib/si.cpp33
-rw-r--r--p2pvr/lib/si.h13
-rw-r--r--p2pvr/lib/siParsers/event.cpp250
-rw-r--r--p2pvr/lib/siParsers/event.h35
-rw-r--r--p2pvr/lib/siParsers/network.cpp219
-rw-r--r--p2pvr/lib/siParsers/network.h35
-rw-r--r--p2pvr/lib/siParsers/service.cpp68
-rw-r--r--p2pvr/lib/siParsers/service.h25
-rw-r--r--p2pvr/lib/siParsers/table.cpp76
-rw-r--r--p2pvr/lib/siParsers/table.h185
-rw-r--r--p2pvr/lib/singleIterator.h39
-rw-r--r--p2pvr/lib/temporaryIceAdapterObject.h39
-rw-r--r--p2pvr/lib/tuner.cpp355
-rw-r--r--p2pvr/lib/tuner.h50
-rw-r--r--p2pvr/scanner/Jamfile.jam17
-rw-r--r--p2pvr/scanner/dvbSiReaderHelper.cpp133
-rw-r--r--p2pvr/scanner/dvbSiReaderHelper.h40
-rw-r--r--p2pvr/scanner/epgRows.cpp528
-rw-r--r--p2pvr/scanner/epgRows.h52
-rw-r--r--p2pvr/scanner/serviceRows.cpp155
-rw-r--r--p2pvr/scanner/serviceRows.h43
-rw-r--r--p2pvr/scanner/si_tables.h1667
57 files changed, 3511 insertions, 2821 deletions
diff --git a/p2pvr/.p2config b/p2pvr/.p2config
new file mode 100644
index 0000000..8c4269f
--- /dev/null
+++ b/p2pvr/.p2config
@@ -0,0 +1,6 @@
+library = libp2pvrdaemon.so
+daemon.type = p2pvrdaemon
+common.filelog.level = 9
+common.filelog.path = /tmp/p2daemon.log
+common.consolelogLevel = 9
+p2pvr.globaldevices.carddaemon = Devices:default -h defiant -p 10001
diff --git a/p2pvr/Jamfile.jam b/p2pvr/Jamfile.jam
index 5d63f0d..d709f2d 100644
--- a/p2pvr/Jamfile.jam
+++ b/p2pvr/Jamfile.jam
@@ -1,2 +1,25 @@
-build-project scanner ;
-build-project ice ;
+import package ;
+
+alias glibmm : : : :
+ <cflags>"`pkg-config --cflags glibmm-2.4`"
+ <linkflags>"`pkg-config --libs glibmm-2.4`"
+ ;
+alias p2common : glibmm : : :
+ <include>/usr/include/project2/common
+ <include>/usr/include/project2/lib
+ <linkflags>"-lp2common"
+;
+alias p2sql : glibmm : : :
+ <include>/usr/include/project2/sql
+ <linkflags>"-lp2sql"
+;
+alias p2daemonlib : glibmm : : :
+ <cflags>"-I /usr/include/project2/daemon/lib"
+ <linkflags>"-lp2daemonlib"
+;
+build-project daemon ;
+build-project carddaemon ;
+
+install debuginstall : lib carddaemon daemon ice : <location>./testing ;
+package.install install : : : carddaemon daemon ;
+
diff --git a/p2pvr/carddaemon/Jamfile.jam b/p2pvr/carddaemon/Jamfile.jam
new file mode 100644
index 0000000..9b4aa83
--- /dev/null
+++ b/p2pvr/carddaemon/Jamfile.jam
@@ -0,0 +1,10 @@
+lib boost_filesystem ;
+lib boost_system ;
+
+lib p2pvrcarddaemon :
+ [ glob *.cpp ]
+ :
+ <library>..//p2daemonlib
+ <library>../ice//p2pvrice
+ <library>../lib//p2pvrlib
+ ;
diff --git a/p2pvr/carddaemon/carddaemon.cpp b/p2pvr/carddaemon/carddaemon.cpp
new file mode 100644
index 0000000..f75109e
--- /dev/null
+++ b/p2pvr/carddaemon/carddaemon.cpp
@@ -0,0 +1,53 @@
+#include <daemon.h>
+#include <options.h>
+#include <logger.h>
+#include <Ice/Ice.h>
+#include "localDevices.h"
+
+class P2PvrCardDaemon : public Daemon {
+ public:
+ P2PvrCardDaemon(int argc, char ** argv) :
+ ic(Ice::initialize(argc, argv))
+ {
+ }
+
+ ~P2PvrCardDaemon()
+ {
+ ic->destroy();
+ }
+
+ void run() const
+ {
+ Logger()->messagebf(LOG_INFO, "Creating adapter (%s, %s)", Adapter, Endpoint);
+ auto adapter = ic->createObjectAdapterWithEndpoints(Adapter, Endpoint);
+ P2PVR::LocalDevicesPrx::checkedCast(adapter->add(new LocalDevices(), ic->stringToIdentity(Identity)));
+ adapter->activate();
+ ic->waitForShutdown();
+ }
+
+ void shutdown() const
+ {
+ ic->shutdown();
+ }
+ INITOPTIONS;
+
+ private:
+ Ice::CommunicatorPtr ic;
+
+ static std::string Adapter;
+ static std::string Endpoint;
+ static std::string Identity;
+};
+
+std::string P2PvrCardDaemon::Adapter;
+std::string P2PvrCardDaemon::Endpoint;
+std::string P2PvrCardDaemon::Identity;
+
+DECLARE_GENERIC_LOADER("p2pvrcarddaemon", DaemonLoader, P2PvrCardDaemon);
+
+DECLARE_OPTIONS(P2PvrCardDaemon, "P2PVR Card Daemon")
+("p2pvr.carddaemon.iceadapter", Options::value(&Adapter, "DefaultAdapter"), "ICE Adapter name")
+("p2pvr.carddaemon.iceendpoint", Options::value(&Endpoint, "default -p 10001"), "ICE Endpoint address")
+("p2pvr.carddaemon.iceidentity", Options::value(&Identity, "Devices"), "ICE Interface identity")
+END_OPTIONS(P2PvrCardDaemon);
+
diff --git a/p2pvr/cron/epg.xml b/p2pvr/cron/epg.xml
deleted file mode 100644
index 8fa9828..0000000
--- a/p2pvr/cron/epg.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0"?>
-<block name="importSchedule" xmlns:p2="http://project2.randomdan.homeip.net">
- <p2:library path="libp2pvr-scan-p2.so" />
- <p2:epgrows name="schedule" demux="/dev/dvb/adapter0/demux0" />
- <p2:view name="showSchedule" source="schedule" rootname="sched" recordname="show">
- <columns>
- <title source="parent" attribute="title" depth="1" />
- <titleLang source="parent" attribute="titleLang" depth="1" />
- <subtitle source="parent" attribute="subtitle" depth="1" />
- <serviceID source="parent" attribute="serviceID" depth="1" />
- <descLang source="parent" attribute="descLang" depth="1" />
- <desc1 source="parent" attribute="desc1" depth="1" />
- <desc2 source="parent" attribute="desc2" depth="1" />
- <desc3 source="parent" attribute="desc3" depth="1" />
- <videoAspect source="parent" attribute="videoAspect" depth="1" />
- <videoFrameRate source="parent" attribute="videoFrameRate" depth="1" />
- <videoHD source="parent" attribute="videoHD" depth="1" />
- <audioChannels source="parent" attribute="audioChannels" depth="1" />
- <language source="parent" attribute="language" depth="1" />
- <teletextSubtitleLang source="parent" attribute="teletextSubtitleLang" depth="1" />
- <category source="parent" attribute="category" depth="1" />
- <dvbRating source="parent" attribute="dvbRating" depth="1" />
- <contentItemID source="parent" attribute="contentItemID" depth="1" />
- <contentRecommendation source="parent" attribute="contentRecommendation" depth="1" />
- <contentSeriesID source="parent" attribute="contentSeriesID" depth="1" />
- <startTime source="parent" attribute="startTime" depth="1" />
- <stopTime source="parent" attribute="stopTime" depth="1" />
- <eventID source="parent" attribute="eventID" depth="1" />
- <episode source="parent" attribute="episode" depth="1" />
- <episodes source="parent" attribute="episodes" depth="1" />
- <year source="parent" attribute="year" depth="1" />
- <flags source="parent" attribute="flags" depth="1" />
- </columns>
- </p2:view>
-</block>
diff --git a/p2pvr/cron/importEpg.xml b/p2pvr/cron/importEpg.xml
deleted file mode 100644
index c3858f5..0000000
--- a/p2pvr/cron/importEpg.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0"?>
-<block name="importSchedule" xmlns:p2="http://project2.randomdan.homeip.net">
- <p2:library path="libp2pvr-scan-p2.so" />
- <p2:epgrows name="schedule" demux="/dev/dvb/adapter0/demux0" />
- <p2:sqlmerge name="mergeSchedule" datasource="postgres" targettable="programs">
- <p2:iterate name="programs" source="schedule">
- <p2:sqlmergeinsert name="insertProgram">
- <parameters>
- <title source="parent" attribute="title" depth="1" />
- <titleLang source="parent" attribute="titleLang" depth="1" />
- <subtitle source="parent" attribute="subtitle" depth="1" />
- <serviceID source="parent" attribute="serviceID" depth="1" />
- <descLang source="parent" attribute="descLang" depth="1" />
- <desc1 source="parent" attribute="desc1" depth="1" />
- <desc2 source="parent" attribute="desc2" depth="1" />
- <desc3 source="parent" attribute="desc3" depth="1" />
- <videoAspect source="parent" attribute="videoAspect" depth="1" />
- <videoFrameRate source="parent" attribute="videoFrameRate" depth="1" />
- <videoHD source="parent" attribute="videoHD" depth="1" />
- <audioChannels source="parent" attribute="audioChannels" depth="1" />
- <language source="parent" attribute="language" depth="1" />
- <teletextSubtitleLang source="parent" attribute="teletextSubtitleLang" depth="1" />
- <category source="parent" attribute="category" depth="1" />
- <dvbRating source="parent" attribute="dvbRating" depth="1" />
- <contentItemID source="parent" attribute="contentItemID" depth="1" />
- <contentRecommendation source="parent" attribute="contentRecommendation" depth="1" />
- <contentSeriesID source="parent" attribute="contentSeriesID" depth="1" />
- <startTime source="parent" attribute="startTime" depth="1" />
- <stopTime source="parent" attribute="stopTime" depth="1" />
- <eventID source="parent" attribute="eventID" depth="1" />
- <episode source="parent" attribute="episode" depth="1" />
- <episodes source="parent" attribute="episodes" depth="1" />
- <year source="parent" attribute="year" depth="1" />
- <flags source="parent" attribute="flags" depth="1" />
- </parameters>
- </p2:sqlmergeinsert>
- </p2:iterate>
- <columns>
- <title />
- <titleLang />
- <subtitle />
- <serviceID key="true" />
- <eventID key="true" />
- <descLang />
- <desc1 />
- <desc2 />
- <desc3 />
- <videoAspect />
- <videoFrameRate />
- <videoHD />
- <audioChannels />
- <language />
- <teletextSubtitleLang />
- <category />
- <dvbRating />
- <contentItemID />
- <contentRecommendation />
- <contentSeriesID />
- <startTime />
- <stopTime />
- <episode />
- <episodes />
- <year />
- <flags />
- </columns>
- </p2:sqlmerge>
-</block>
diff --git a/p2pvr/cron/importServices.xml b/p2pvr/cron/importServices.xml
deleted file mode 100644
index d914d15..0000000
--- a/p2pvr/cron/importServices.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0"?>
-<block name="importServices" xmlns:p2="http://project2.randomdan.homeip.net">
- <p2:library path="libp2pvr-scan-p2.so" />
- <p2:servicerows name="services" demux="/dev/dvb/adapter0/demux0" />
- <p2:sqlmerge name="mergeServices" datasource="postgres" targettable="services">
- <p2:iterate name="programs" source="services">
- <p2:sqlmergeinsert name="insertProgram">
- <parameters>
- <serviceID source="parent" attribute="serviceID" depth="1" />
- <name source="parent" attribute="name" depth="1" />
- <providerName source="parent" attribute="providerName" depth="1" />
- <transportID source="parent" attribute="transportID" depth="1" />
- <type source="parent" attribute="type" depth="1" />
- <defaultAuthority source="parent" attribute="defaultAuthority" depth="1" />
- </parameters>
- </p2:sqlmergeinsert>
- </p2:iterate>
- <columns>
- <serviceID key="true" />
- <name />
- <providerName />
- <transportID />
- <type />
- <defaultAuthority />
- </columns>
- </p2:sqlmerge>
-</block>
-
diff --git a/p2pvr/cron/services.xml b/p2pvr/cron/services.xml
deleted file mode 100644
index bdd038e..0000000
--- a/p2pvr/cron/services.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0"?>
-<block name="showServices" xmlns:p2="http://project2.randomdan.homeip.net">
- <p2:library path="libp2pvr-scan-p2.so" />
- <p2:servicerows name="services" demux="/dev/dvb/adapter0/demux0" />
- <p2:view name="showServices" source="services" rootname="services" recordname="service">
- <columns>
- <serviceID source="parent" attribute="serviceID" depth="1" />
- <name source="parent" attribute="name" depth="1" />
- <providerName source="parent" attribute="providerName" depth="1" />
- <transportID source="parent" attribute="transportID" depth="1" />
- <type source="parent" attribute="type" depth="1" />
- <defaultAuthority source="parent" attribute="defaultAuthority" depth="1" />
- </columns>
- </p2:view>
-</block>
-
diff --git a/p2pvr/daemon/Jamfile.jam b/p2pvr/daemon/Jamfile.jam
new file mode 100644
index 0000000..7379c7a
--- /dev/null
+++ b/p2pvr/daemon/Jamfile.jam
@@ -0,0 +1,10 @@
+lib Ice ;
+lib IceUtil ;
+
+lib p2pvrdaemon :
+ [ glob *.cpp ]
+ :
+ <library>..//p2daemonlib
+ <library>../ice//p2pvrice
+ <library>../lib//p2pvrlib
+ ;
diff --git a/p2pvr/daemon/daemon.cpp b/p2pvr/daemon/daemon.cpp
new file mode 100644
index 0000000..de470d3
--- /dev/null
+++ b/p2pvr/daemon/daemon.cpp
@@ -0,0 +1,64 @@
+#include <daemon.h>
+#include <options.h>
+#include <Ice/Ice.h>
+#include "localDevices.h"
+#include "globalDevices.h"
+#include "maintenance.h"
+#include "si.h"
+#include <logger.h>
+
+#include <linux/dvb/frontend.h>
+
+class P2PvrDaemon : public Daemon {
+ public:
+ P2PvrDaemon(int argc, char ** argv) :
+ ic(Ice::initialize(argc, argv))
+ {
+ }
+
+ ~P2PvrDaemon()
+ {
+ ic->destroy();
+ }
+
+ void run() const
+ {
+ Logger()->messagebf(LOG_INFO, "Creating adapter (%s, %s)", Adapter, Endpoint);
+ auto adapter = ic->createObjectAdapterWithEndpoints(Adapter, Endpoint);
+ adapter->add(new LocalDevices(), ic->stringToIdentity("Devices"));
+ adapter->add(new GlobalDevices(), ic->stringToIdentity("GlobalDevices"));
+ adapter->add(new Maintenance(), ic->stringToIdentity("Maintenance"));
+ adapter->add(new SI(), ic->stringToIdentity("SI"));
+ adapter->activate();
+
+ auto maint = P2PVR::MaintenancePrx::checkedCast(adapter->createProxy(ic->stringToIdentity("Maintenance")));
+ maint->UpdateTransports(FE_OFDM);
+ maint->UpdateServices(FE_OFDM);
+ maint->UpdateEvents(FE_OFDM);
+
+ //ic->waitForShutdown();
+ }
+
+ void shutdown() const
+ {
+ ic->shutdown();
+ }
+ INITOPTIONS;
+
+ private:
+ Ice::CommunicatorPtr ic;
+
+ static std::string Adapter;
+ static std::string Endpoint;
+};
+
+std::string P2PvrDaemon::Adapter;
+std::string P2PvrDaemon::Endpoint;
+
+DECLARE_GENERIC_LOADER("p2pvrdaemon", DaemonLoader, P2PvrDaemon);
+
+DECLARE_OPTIONS(P2PvrDaemon, "P2PVR Daemon")
+("p2pvr.daemon.iceadapter", Options::value(&Adapter, "DefaultAdapter"), "ICE Adapter name")
+("p2pvr.daemon.iceendpoint", Options::value(&Endpoint, "default -p 10000"), "ICE Endpoint address")
+END_OPTIONS(P2PvrDaemon);
+
diff --git a/p2pvr/datasources/postgres.xml b/p2pvr/datasources/postgres.xml
index 7d7440e..c538a8c 100644
--- a/p2pvr/datasources/postgres.xml
+++ b/p2pvr/datasources/postgres.xml
@@ -1,8 +1,4 @@
<?xml version="1.0"?>
<project2:rdbmsdatasource xmlns:project2="http://project2.randomdan.homeip.net" name="postgres">
- <readonly preferlocal="true">
- <dsn host="defiant" provider="postgresql" dsn="host=defiant sslmode=disable user=p2tv dbname=gentoo options='-c search_path=p2tv,public'" />
- <dsn host="firebrand" provider="postgresql" dsn="host=firebrand sslmode=disable user=p2tv dbname=gentoo options='-c search_path=p2tv,public'" />
- </readonly>
- <masterdsn host="defiant" provider="postgresql" dsn="host=defiant sslmode=disable user=p2tv dbname=gentoo options='-c search_path=p2tv,public'" />
+ <masterdsn provider="postgresql" dsn="user=gentoo dbname=p2pvr" />
</project2:rdbmsdatasource>
diff --git a/p2pvr/datasources/schema.sql b/p2pvr/datasources/schema.sql
new file mode 100644
index 0000000..c628bf0
--- /dev/null
+++ b/p2pvr/datasources/schema.sql
@@ -0,0 +1,382 @@
+--
+-- PostgreSQL database dump
+--
+
+SET statement_timeout = 0;
+SET lock_timeout = 0;
+SET client_encoding = 'UTF8';
+SET standard_conforming_strings = on;
+SET check_function_bodies = false;
+SET client_min_messages = warning;
+
+--
+-- Name: plpgsql; Type: EXTENSION; Schema: -; Owner:
+--
+
+CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;
+
+
+--
+-- Name: EXTENSION plpgsql; Type: COMMENT; Schema: -; Owner:
+--
+
+COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language';
+
+
+SET search_path = public, pg_catalog;
+
+SET default_tablespace = '';
+
+SET default_with_oids = false;
+
+--
+-- Name: delivery_dvbc; Type: TABLE; Schema: public; Owner: gentoo; Tablespace:
+--
+
+CREATE TABLE delivery_dvbc (
+ frequency bigint NOT NULL,
+ transportstreamid integer NOT NULL,
+ fecouter smallint,
+ modulation smallint,
+ symbolrate integer,
+ fecinner smallint
+);
+
+
+ALTER TABLE public.delivery_dvbc OWNER TO gentoo;
+
+--
+-- Name: delivery_dvbs; Type: TABLE; Schema: public; Owner: gentoo; Tablespace:
+--
+
+CREATE TABLE delivery_dvbs (
+ frequency bigint NOT NULL,
+ transportstreamid integer NOT NULL,
+ orbitalposition integer,
+ westeastflag boolean,
+ polarization smallint,
+ rolloff smallint,
+ modulationsystem boolean,
+ modulationtype smallint,
+ symbolrate integer,
+ fecinner smallint
+);
+
+
+ALTER TABLE public.delivery_dvbs OWNER TO gentoo;
+
+--
+-- Name: delivery_dvbt; Type: TABLE; Schema: public; Owner: gentoo; Tablespace:
+--
+
+CREATE TABLE delivery_dvbt (
+ frequency bigint NOT NULL,
+ transportstreamid integer NOT NULL,
+ bandwidth smallint,
+ priority boolean,
+ timeslicing boolean,
+ mpefec boolean,
+ constellation smallint,
+ hierarchy smallint,
+ coderatehp smallint,
+ coderatelp smallint,
+ guardinterval smallint,
+ transmissionmode smallint,
+ otherfrequencyflag boolean
+);
+
+
+ALTER TABLE public.delivery_dvbt OWNER TO gentoo;
+
+--
+-- Name: event_schedule; Type: TABLE; Schema: public; Owner: gentoo; Tablespace:
+--
+
+CREATE TABLE event_schedule (
+ serviceid integer NOT NULL,
+ eventid integer NOT NULL,
+ scheduleid integer NOT NULL
+);
+
+
+ALTER TABLE public.event_schedule OWNER TO gentoo;
+
+--
+-- Name: events; Type: TABLE; Schema: public; Owner: gentoo; Tablespace:
+--
+
+CREATE TABLE events (
+ serviceid integer NOT NULL,
+ eventid integer NOT NULL,
+ title text,
+ titlelang text,
+ subtitle text,
+ description text,
+ descriptionlang text,
+ videoaspect smallint,
+ videoframerate smallint,
+ videohd boolean,
+ audiochannels smallint,
+ audiolanguage text,
+ subtitlelanguage text,
+ category smallint,
+ subcategory smallint,
+ usercategory smallint,
+ dvbrating smallint,
+ starttime timestamp without time zone,
+ stoptime timestamp without time zone,
+ episode smallint,
+ episodes smallint,
+ year smallint,
+ flags text
+);
+
+
+ALTER TABLE public.events OWNER TO gentoo;
+
+--
+-- Name: networks; Type: TABLE; Schema: public; Owner: gentoo; Tablespace:
+--
+
+CREATE TABLE networks (
+ networkid integer NOT NULL,
+ name text NOT NULL
+);
+
+
+ALTER TABLE public.networks OWNER TO gentoo;
+
+--
+-- Name: schedules; Type: TABLE; Schema: public; Owner: gentoo; Tablespace:
+--
+
+CREATE TABLE schedules (
+ scheduleid integer NOT NULL,
+ serviceid integer,
+ eventid integer,
+ title text,
+ search text
+);
+
+
+ALTER TABLE public.schedules OWNER TO gentoo;
+
+--
+-- Name: schedules_scheduleid_seq; Type: SEQUENCE; Schema: public; Owner: gentoo
+--
+
+CREATE SEQUENCE schedules_scheduleid_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+
+ALTER TABLE public.schedules_scheduleid_seq OWNER TO gentoo;
+
+--
+-- Name: schedules_scheduleid_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: gentoo
+--
+
+ALTER SEQUENCE schedules_scheduleid_seq OWNED BY schedules.scheduleid;
+
+
+--
+-- Name: services; Type: TABLE; Schema: public; Owner: gentoo; Tablespace:
+--
+
+CREATE TABLE services (
+ serviceid integer NOT NULL,
+ name text,
+ providername text,
+ type smallint,
+ defaultauthority text,
+ runningstatus smallint,
+ eitschedule boolean,
+ eitpresentfollowing boolean,
+ freecamode boolean,
+ transportstreamid integer NOT NULL
+);
+
+
+ALTER TABLE public.services OWNER TO gentoo;
+
+--
+-- Name: transportstreams; Type: TABLE; Schema: public; Owner: gentoo; Tablespace:
+--
+
+CREATE TABLE transportstreams (
+ transportstreamid integer NOT NULL,
+ networkid integer NOT NULL,
+ originalnetworkid integer
+);
+
+
+ALTER TABLE public.transportstreams OWNER TO gentoo;
+
+--
+-- Name: scheduleid; Type: DEFAULT; Schema: public; Owner: gentoo
+--
+
+ALTER TABLE ONLY schedules ALTER COLUMN scheduleid SET DEFAULT nextval('schedules_scheduleid_seq'::regclass);
+
+
+--
+-- Name: pk_delivery_dvbc; Type: CONSTRAINT; Schema: public; Owner: gentoo; Tablespace:
+--
+
+ALTER TABLE ONLY delivery_dvbc
+ ADD CONSTRAINT pk_delivery_dvbc PRIMARY KEY (frequency);
+
+
+--
+-- Name: pk_delivery_dvbs; Type: CONSTRAINT; Schema: public; Owner: gentoo; Tablespace:
+--
+
+ALTER TABLE ONLY delivery_dvbs
+ ADD CONSTRAINT pk_delivery_dvbs PRIMARY KEY (frequency);
+
+
+--
+-- Name: pk_delivery_dvbt; Type: CONSTRAINT; Schema: public; Owner: gentoo; Tablespace:
+--
+
+ALTER TABLE ONLY delivery_dvbt
+ ADD CONSTRAINT pk_delivery_dvbt PRIMARY KEY (frequency);
+
+
+--
+-- Name: pk_events; Type: CONSTRAINT; Schema: public; Owner: gentoo; Tablespace:
+--
+
+ALTER TABLE ONLY events
+ ADD CONSTRAINT pk_events PRIMARY KEY (serviceid, eventid);
+
+
+--
+-- Name: pk_eventschedule; Type: CONSTRAINT; Schema: public; Owner: gentoo; Tablespace:
+--
+
+ALTER TABLE ONLY event_schedule
+ ADD CONSTRAINT pk_eventschedule PRIMARY KEY (eventid, scheduleid);
+
+
+--
+-- Name: pk_networks; Type: CONSTRAINT; Schema: public; Owner: gentoo; Tablespace:
+--
+
+ALTER TABLE ONLY networks
+ ADD CONSTRAINT pk_networks PRIMARY KEY (networkid);
+
+
+--
+-- Name: pk_schedules; Type: CONSTRAINT; Schema: public; Owner: gentoo; Tablespace:
+--
+
+ALTER TABLE ONLY schedules
+ ADD CONSTRAINT pk_schedules PRIMARY KEY (scheduleid);
+
+
+--
+-- Name: pk_services; Type: CONSTRAINT; Schema: public; Owner: gentoo; Tablespace:
+--
+
+ALTER TABLE ONLY services
+ ADD CONSTRAINT pk_services PRIMARY KEY (serviceid);
+
+
+--
+-- Name: pk_transportstreams; Type: CONSTRAINT; Schema: public; Owner: gentoo; Tablespace:
+--
+
+ALTER TABLE ONLY transportstreams
+ ADD CONSTRAINT pk_transportstreams PRIMARY KEY (transportstreamid);
+
+
+--
+-- Name: fk_delivery_dvbc_transportstream; Type: FK CONSTRAINT; Schema: public; Owner: gentoo
+--
+
+ALTER TABLE ONLY delivery_dvbc
+ ADD CONSTRAINT fk_delivery_dvbc_transportstream FOREIGN KEY (transportstreamid) REFERENCES transportstreams(transportstreamid) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: fk_delivery_dvbs_transportstream; Type: FK CONSTRAINT; Schema: public; Owner: gentoo
+--
+
+ALTER TABLE ONLY delivery_dvbs
+ ADD CONSTRAINT fk_delivery_dvbs_transportstream FOREIGN KEY (transportstreamid) REFERENCES transportstreams(transportstreamid) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: fk_delivery_dvbt_transportstream; Type: FK CONSTRAINT; Schema: public; Owner: gentoo
+--
+
+ALTER TABLE ONLY delivery_dvbt
+ ADD CONSTRAINT fk_delivery_dvbt_transportstream FOREIGN KEY (transportstreamid) REFERENCES transportstreams(transportstreamid) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: fk_eventschedule; Type: FK CONSTRAINT; Schema: public; Owner: gentoo
+--
+
+ALTER TABLE ONLY event_schedule
+ ADD CONSTRAINT fk_eventschedule FOREIGN KEY (serviceid, eventid) REFERENCES events(serviceid, eventid) ON DELETE CASCADE;
+
+
+--
+-- Name: fk_eventschedule_schedule; Type: FK CONSTRAINT; Schema: public; Owner: gentoo
+--
+
+ALTER TABLE ONLY event_schedule
+ ADD CONSTRAINT fk_eventschedule_schedule FOREIGN KEY (scheduleid) REFERENCES schedules(scheduleid) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: fk_schedule_event; Type: FK CONSTRAINT; Schema: public; Owner: gentoo
+--
+
+ALTER TABLE ONLY schedules
+ ADD CONSTRAINT fk_schedule_event FOREIGN KEY (serviceid, eventid) REFERENCES events(serviceid, eventid) ON DELETE CASCADE;
+
+
+--
+-- Name: fk_schedule_service; Type: FK CONSTRAINT; Schema: public; Owner: gentoo
+--
+
+ALTER TABLE ONLY schedules
+ ADD CONSTRAINT fk_schedule_service FOREIGN KEY (serviceid) REFERENCES services(serviceid) ON DELETE CASCADE;
+
+
+--
+-- Name: fk_services_transportstreams; Type: FK CONSTRAINT; Schema: public; Owner: gentoo
+--
+
+ALTER TABLE ONLY services
+ ADD CONSTRAINT fk_services_transportstreams FOREIGN KEY (transportstreamid) REFERENCES transportstreams(transportstreamid) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: fk_transportstreams_network; Type: FK CONSTRAINT; Schema: public; Owner: gentoo
+--
+
+ALTER TABLE ONLY transportstreams
+ ADD CONSTRAINT fk_transportstreams_network FOREIGN KEY (networkid) REFERENCES networks(networkid) ON UPDATE CASCADE ON DELETE CASCADE;
+
+
+--
+-- Name: public; Type: ACL; Schema: -; Owner: postgres
+--
+
+REVOKE ALL ON SCHEMA public FROM PUBLIC;
+REVOKE ALL ON SCHEMA public FROM postgres;
+GRANT ALL ON SCHEMA public TO postgres;
+GRANT ALL ON SCHEMA public TO PUBLIC;
+
+
+--
+-- PostgreSQL database dump complete
+--
+
diff --git a/p2pvr/doc/en_300468v011101p.pdf b/p2pvr/doc/en_300468v011101p.pdf
new file mode 100644
index 0000000..6aae6b2
--- /dev/null
+++ b/p2pvr/doc/en_300468v011101p.pdf
Binary files differ
diff --git a/p2pvr/ice/Jamfile.jam b/p2pvr/ice/Jamfile.jam
index 9055b2e..219c508 100644
--- a/p2pvr/ice/Jamfile.jam
+++ b/p2pvr/ice/Jamfile.jam
@@ -1,13 +1,16 @@
-import package ;
-
-lib Ice : : <name>Ice ;
-lib IceUtil : : <name>IceUtil ;
-lib pthread : : <name>pthread ;
+lib Ice ;
+lib IceUtil ;
+lib pthread ;
lib p2pvrice :
[ glob *.ice ] :
<library>Ice
<library>IceUtil
<library>pthread
+ : :
+ <include>.
+ <library>Ice
+ <library>IceUtil
+ <library>pthread
;
diff --git a/p2pvr/ice/commonHelpers.h b/p2pvr/ice/commonHelpers.h
new file mode 100644
index 0000000..b54523e
--- /dev/null
+++ b/p2pvr/ice/commonHelpers.h
@@ -0,0 +1,22 @@
+#ifndef ICE_COMMON_HELPERS_H
+#define ICE_COMMON_HELPERS_H
+
+#include <p2pvr.h>
+#include <ostream>
+
+namespace Common {
+ template<typename C, typename T>
+ std::basic_ostream<C, T> &
+ operator<<(std::basic_ostream<C, T> & o, const Common::DateTime & dt)
+ {
+ o << std::setw(4) << std::setfill('0') << dt.Year
+ << "-" << std::setw(2) << std::setfill('0') << dt.Month
+ << "-" << std::setw(2) << std::setfill('0') << dt.Day
+ << "T" << std::setw(2) << std::setfill('0') << dt.Hour
+ << ":" << std::setw(2) << std::setfill('0') << dt.Minute;
+ return o;
+ }
+}
+
+#endif
+
diff --git a/p2pvr/ice/p2pvr.ice b/p2pvr/ice/p2pvr.ice
index aaa01bf..250cc37 100644
--- a/p2pvr/ice/p2pvr.ice
+++ b/p2pvr/ice/p2pvr.ice
@@ -1,40 +1,232 @@
-module P2TV {
+module Common {
+ struct DateTime {
+ short Year;
+ short Month;
+ short Day;
+ short Hour;
+ short Minute;
+ };
+
+ struct TimeOfDay {
+ short Hour;
+ short Minute;
+ };
+};
+
+// This attempts to define an ICE representation of domain objects contained
+// within the DVB SI (Digital Video Broadcasting specification for Service
+// Information - EN 300 468 v1.11.1)
+
+module DVBSI {
+ // Descriptors
+ class Delivery {
+ long Frequency;
+ };
+
+ class SatelliteDelivery extends Delivery {
+ int OrbitalPosition;
+ bool WestEastFlag;
+ short Polarization;
+ short RollOff;
+ bool ModulationSystem;
+ short ModulationType;
+ int SymbolRate;
+ short FecInner;
+ };
+
+ class CableDelivery extends Delivery {
+ short FecOuter;
+ short Modulation;
+ int SymbolRate;
+ short FecInner;
+ };
+
+ class TerrestrialDelivery extends Delivery {
+ short Bandwidth;
+ bool Priority;
+ bool TimeSlicing;
+ bool MpeFec;
+ short Constellation;
+ short Hierarchy;
+ short CodeRateHP;
+ short CodeRateLP;
+ short GuardInterval;
+ short TransmissionMode;
+ bool OtherFrequencyFlag;
+ };
+
+ struct NetworkService {
+ int ServiceId;
+ short ServiceType;
+ };
+ sequence<NetworkService> NetworkServiceList;
+
+ class NetworkTransportStream {
+ int TransportStreamId;
+ int OriginalNetworkId;
+ SatelliteDelivery Satellite;
+ CableDelivery Cable;
+ TerrestrialDelivery Terrestrial;
+ NetworkServiceList Services;
+ };
+ sequence<NetworkTransportStream> NetworkTransportStreams;
+
+ class Network {
+ int NetworkId;
+ optional(1) string Name;
+ NetworkTransportStreams TransportStreams;
+ };
+
+ class BouquetTransportStream {
+ int TransportStreamId;
+ int OriginalNetworkId;
+ };
+ sequence <BouquetTransportStream> BouquetTransportStreamList;
+
+ class Bouquet {
+ int BouquetId;
+ optional(1) string Name;
+ optional(2) string DefaultAuthority;
+ BouquetTransportStreamList Streams;
+ };
+
+ class Service {
+ int ServiceId;
+ bool EitSchedule;
+ bool EitPresentFollowing;
+ short RunningStatus;
+ bool FreeCaMode;
+ optional(1) string ProviderName;
+ optional(2) string Name;
+ optional(3) short Type;
+ optional(4) string DefaultAuthority;
+ };
+ sequence<Service> ServiceList;
+
+ class TransportStream {
+ int TransportStreamId;
+ int OriginalNetworkId;
+ ServiceList Services;
+ };
+
+ class EitInformation {
+ int ServiceId;
+ int TransportStreamId;
+ int OriginalNetworkId;
+ };
+
+ class Event {
+ int ServiceId;
+ int EventId;
+ string Title;
+ string TitleLang;
+ optional(1) string Subtitle;
+ optional(2) string Description;
+ optional(3) string DescriptionLang;
+ Common::DateTime StartTime;
+ Common::DateTime StopTime;
+ optional(4) short Episode;
+ optional(5) short Episodes;
+ optional(6) short Year;
+ optional(7) string Flags;
+ optional(8) short DvbRating;
+ optional(9) short VideoAspect;
+ optional(10) short VideoFrameRate;
+ optional(11) bool VideoHD;
+ optional(12) short AudioChannels;
+ optional(13) string AudioLanguage;
+ optional(14) string SubtitleLanguage;
+ optional(15) short Category;
+ optional(16) short SubCategory;
+ optional(17) short UserCategory;
+ };
+};
+module P2PVR {
+ exception DeviceError {
+ string Device;
+ string Message;
+ int Errno;
+ };
+ exception IncorrectDeliveryType { };
+
+ // Event in the database, it has a unique Id.
+ class Program extends DVBSI::Event {
+ int ProgramId;
+ };
+ sequence<Program> ProgramList;
+
+ // Something that we have recorded.
struct Recording {
- int recordingId;
+ int RecordingId;
string Title;
string Subtitle;
string Description;
- long startTime;
- long endTime;
- long fileSize;
- int serviceId;
+ Common::DateTime StartTime;
+ Common::DateTime EndTime;
+ long FileSize;
+ int ServiceId;
};
sequence<Recording> RecordingList;
- struct Schedule {
- int scheduleId;
+ // Something that defines what we would like to record.
+ class Schedule {
+ int ScheduleId;
+ optional(1) string Title;
+ optional(2) string Subtitle;
+ optional(3) int ServiceId;
+ optional(4) Common::TimeOfDay Time;
+ optional(5) string Search;
+ bool Repeats;
};
sequence<Schedule> ScheduleList;
-
- struct Program {
- int programId;
- int serviceId;
- int eventId;
- string Title;
- string Subtitle;
- string Description;
- long startTime;
- long endTime;
+
+ sequence<byte> Data;
+ sequence<short> PacketIds;
+
+ interface RawDataClient {
+ bool NewData(Data bytes);
+ };
+
+ interface Tuner {
+ idempotent int GetStatus();
+
+ idempotent void SendNetworkInformation(RawDataClient * client);
+ idempotent void SendBouquetAssociations(RawDataClient * client);
+ idempotent void SendServiceDescriptions(RawDataClient * client);
+ idempotent void SendEventInformation(RawDataClient * client);
+
+ int StartSendingTS(PacketIds pids, RawDataClient * client);
+ idempotent void StopSendingTS(int handle);
+ };
+ interface PrivateTuner extends Tuner {
+ idempotent void TuneTo(DVBSI::Delivery d);
+ idempotent void ScanAndSendNetworkInformation(RawDataClient * client);
};
- sequence<Program> ProgramList;
- struct Service {
- int serviceId;
- string name;
- string authority;
+ interface Devices {
+ // Get a tuner that is tuned to <del>, acquire and tune to <del> if required.
+ Tuner * GetTunerSpecific(DVBSI::Delivery del, long until);
+ // Get any tuner that is tuned, acquire and tune to <del> if required.
+ Tuner * GetTunerAny(short type, DVBSI::Delivery del, long until);
+ // Get a private tuner, not shared or sharable
+ PrivateTuner * GetPrivateTuner(short type, long until);
+ // Release a tuner when no longer required.
+ idempotent void ReleaseTuner(Tuner * t);
+ };
+
+ interface LocalDevices extends Devices {
+ idempotent void Scan();
+ idempotent void Add(string frontend);
+ idempotent void Remove(string frontend);
};
- sequence<Service> ServiceList;
+ interface Maintenance {
+ idempotent void UpdateAll();
+ idempotent void UpdateTransports(short type);
+ idempotent void UpdateServices(short type);
+ idempotent void UpdateEvents(short type);
+ };
+
interface Recordings {
idempotent void DeleteRecording(int recordingId);
idempotent RecordingList GetRecordings();
@@ -47,10 +239,10 @@ module P2TV {
idempotent void DoReschedule();
};
- interface EPG {
- idempotent ServiceList GetServices();
- idempotent ProgramList GetPrograms(int serviceId, int limit);
- idempotent ProgramList GetNowAndNext();
+ sequence<DVBSI::Delivery> Deliveries;
+ interface SI {
+ // Get any delivery suitable for SI reading
+ idempotent Deliveries GetAllDeliveries(short type);
};
};
diff --git a/p2pvr/lib/Jamfile.jam b/p2pvr/lib/Jamfile.jam
new file mode 100644
index 0000000..b05e572
--- /dev/null
+++ b/p2pvr/lib/Jamfile.jam
@@ -0,0 +1,18 @@
+lib boost_system ;
+lib boost_filesystem ;
+
+lib p2pvrlib :
+ [ glob-tree *.cpp ]
+ ../../libmisc/misc.cpp
+ :
+ <library>boost_system
+ <library>boost_filesystem
+ <library>../ice//p2pvrice
+ <library>..//p2common
+ <library>..//p2sql
+ <implicit-dependency>../ice//p2pvrice
+ : :
+ <library>boost_filesystem
+ <implicit-dependency>../ice//p2pvrice
+ <include>.
+ ;
diff --git a/p2pvr/lib/containerCreator.h b/p2pvr/lib/containerCreator.h
new file mode 100644
index 0000000..aed2479
--- /dev/null
+++ b/p2pvr/lib/containerCreator.h
@@ -0,0 +1,32 @@
+#ifndef CONTAINERCREATOR_H
+#define CONTAINERCREATOR_H
+
+#include <boost/function.hpp>
+
+template <typename T, typename V>
+class ContainerCreator {
+ public:
+ ContainerCreator(T & c) : container(c) { }
+
+ void populate(
+ boost::function<bool()> fetch,
+ boost::function<VariableType(unsigned int)> get,
+ boost::function<unsigned int()> columns)
+ {
+ while (fetch()) {
+ auto v = new V;
+ container.push_back(v);
+ ObjectRowState<IceInternal::Handle<V>> rs;
+ const auto columnCount = columns();
+ for (unsigned int c = 0; c < columnCount; c++) {
+ rs.fields[c] = get(c);
+ }
+ UnbindColumns<IceInternal::Handle<V>>(rs, v);
+ }
+ }
+ private:
+ T & container;
+};
+
+#endif
+
diff --git a/p2pvr/lib/containerIterator.h b/p2pvr/lib/containerIterator.h
new file mode 100644
index 0000000..1c4e6bf
--- /dev/null
+++ b/p2pvr/lib/containerIterator.h
@@ -0,0 +1,41 @@
+#ifndef CONTAINERITERATOR_H
+#define CONTAINERITERATOR_H
+
+#include <iHaveSubTasks.h>
+#include <boost/foreach.hpp>
+#include "objectRowState.h"
+
+template <typename T>
+class ContainerIterator : public IHaveSubTasks {
+ public:
+ template <typename ... Parents>
+ ContainerIterator(const T * con, const Parents & ... p) :
+ SourceObject(__PRETTY_FUNCTION__),
+ IHaveSubTasks(NULL),
+ binder(boost::bind(&BindColumns<typename T::value_type, Parents...>, _1, _2, p...)),
+ container(con)
+ {
+ }
+ void execute(ExecContext * ec) const
+ {
+ ObjectRowState<typename T::value_type> rs;
+ BOOST_FOREACH(const auto & i, *container) {
+ binder(rs, i);
+ rs.process(boost::bind(&ContainerIterator::executeChildren, this, ec));
+ }
+ }
+
+ private:
+ boost::function<void(RowState &, const typename T::value_type &)> binder;
+ const T * container;
+
+ void executeChildren(ExecContext * ec) const
+ {
+ BOOST_FOREACH(const Tasks::value_type & sq, normal) {
+ sq->execute(ec);
+ }
+ }
+};
+
+#endif
+
diff --git a/p2pvr/lib/dvbsiHelpers.cpp b/p2pvr/lib/dvbsiHelpers.cpp
new file mode 100644
index 0000000..3dcbdcc
--- /dev/null
+++ b/p2pvr/lib/dvbsiHelpers.cpp
@@ -0,0 +1,190 @@
+#include "dvbsiHelpers.h"
+#include "p2Helpers.h"
+
+template<>
+void
+CreateColumns<DVBSI::NetworkPtr>(const ColumnCreator & cc)
+{
+ cc("networkId", true);
+ cc("name", false);
+}
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::NetworkPtr & network)
+{
+ rs.fields[0] << network->NetworkId;
+ rs.fields[1] << network->Name;
+}
+
+template<>
+void
+CreateColumns<DVBSI::NetworkTransportStreamPtr>(const ColumnCreator & cc)
+{
+ cc("transportStreamId", true);
+ cc("networkId", false);
+ cc("originalNetworkId", false);
+}
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::NetworkTransportStreamPtr & ts, const DVBSI::NetworkPtr & network)
+{
+ rs.fields[0] << ts->TransportStreamId;
+ rs.fields[1] << network->NetworkId;
+ rs.fields[2] << ts->OriginalNetworkId;
+}
+
+template<>
+void
+CreateColumns<DVBSI::NetworkService>(const ColumnCreator & cc)
+{
+ cc("serviceId", true);
+ cc("type", false);
+ cc("transportStreamId", false);
+}
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::NetworkService & s, const DVBSI::NetworkTransportStreamPtr & ts)
+{
+ rs.fields[0] << s.ServiceId;
+ rs.fields[1] << s.ServiceType;
+ rs.fields[2] << ts->TransportStreamId;
+}
+
+template<>
+void
+CreateColumns<DVBSI::ServicePtr>(const ColumnCreator & cc)
+{
+ cc("serviceId", true);
+ cc("transportStreamId", true);
+ cc("name", false);
+ cc("providerName", false);
+ cc("defaultAuthority", false);
+}
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::ServicePtr & s, const DVBSI::TransportStreamPtr & ts)
+{
+ rs.fields[0] << s->ServiceId;
+ rs.fields[1] << ts->TransportStreamId;
+ rs.fields[2] << s->Name;
+ rs.fields[4] << s->ProviderName;
+ rs.fields[4] << s->DefaultAuthority;
+}
+
+template<>
+void
+CreateColumns<DVBSI::EventPtr>(const ColumnCreator & cc)
+{
+ cc("serviceId", true);
+ cc("eventId", true);
+ cc("title", false);
+ cc("titleLang", false);
+ cc("subtitle", false);
+ cc("description", false);
+ cc("descriptionLang", false);
+ cc("videoAspect", false);
+ cc("videoFrameRate", false);
+ cc("videoHd", false);
+ cc("audioChannels", false);
+ cc("audioLanguage", false);
+ cc("subtitleLanguage", false);
+ cc("category", false);
+ cc("subCategory", false);
+ cc("userCategory", false);
+ cc("dvbRating", false);
+ cc("startTime", false);
+ cc("stopTime", false);
+ cc("episode", false);
+ cc("episodes", false);
+ cc("year", false);
+ cc("flags", false);
+}
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::EventPtr & e)
+{
+ rs.fields[0] << e->ServiceId;
+ rs.fields[1] << e->EventId;
+ rs.fields[2] << e->Title;
+ rs.fields[3] << e->TitleLang;
+ rs.fields[4] << e->Subtitle;
+ rs.fields[5] << e->Description;
+ rs.fields[6] << e->DescriptionLang;
+ rs.fields[7] << e->VideoAspect;
+ rs.fields[8] << e->VideoFrameRate;
+ rs.fields[9] << e->VideoHD;
+ rs.fields[10] << e->AudioChannels;
+ rs.fields[11] << e->AudioLanguage;
+ rs.fields[12] << e->SubtitleLanguage;
+ rs.fields[13] << e->Category;
+ rs.fields[14] << e->SubCategory;
+ rs.fields[15] << e->UserCategory;
+ rs.fields[16] << e->DvbRating;
+ rs.fields[17] << e->StartTime;
+ rs.fields[18] << e->StopTime;
+ rs.fields[19] << e->Episode;
+ rs.fields[20] << e->Episodes;
+ rs.fields[21] << e->Year;
+ rs.fields[22] << e->Flags;
+}
+
+template<>
+void
+CreateColumns<DVBSI::TerrestrialDeliveryPtr>(const ColumnCreator & cc)
+{
+ cc("frequency", false);
+ cc("transportStreamId", true);
+ cc("bandwidth", false);
+ cc("priority", false);
+ cc("timeSlicing", false);
+ cc("mpeFec", false);
+ cc("constellation", false);
+ cc("hierarchy", false);
+ cc("codeRateHP", false);
+ cc("codeRateLP", false);
+ cc("guardInterval", false);
+ cc("transmissionMode", false);
+ cc("otherFrequencyFlag", false);
+}
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::TerrestrialDeliveryPtr & s, const DVBSI::NetworkTransportStreamPtr & ts)
+{
+ rs.fields[0] << s->Frequency;
+ rs.fields[1] << ts->TransportStreamId;
+ rs.fields[2] << s->Bandwidth;
+ rs.fields[3] << s->Priority;
+ rs.fields[4] << s->TimeSlicing;
+ rs.fields[5] << s->MpeFec;
+ rs.fields[6] << s->Constellation;
+ rs.fields[7] << s->Hierarchy;
+ rs.fields[8] << s->CodeRateHP;
+ rs.fields[9] << s->CodeRateLP;
+ rs.fields[10] << s->GuardInterval;
+ rs.fields[11] << s->TransmissionMode;
+ rs.fields[12] << s->OtherFrequencyFlag;
+}
+template<>
+void
+UnbindColumns(RowState & rs, DVBSI::TerrestrialDeliveryPtr const & s)
+{
+ rs.fields[0] >> s->Frequency;
+ rs.fields[2] >> s->Bandwidth;
+ rs.fields[3] >> s->Priority;
+ rs.fields[4] >> s->TimeSlicing;
+ rs.fields[5] >> s->MpeFec;
+ rs.fields[6] >> s->Constellation;
+ rs.fields[7] >> s->Hierarchy;
+ rs.fields[8] >> s->CodeRateHP;
+ rs.fields[9] >> s->CodeRateLP;
+ rs.fields[10] >> s->GuardInterval;
+ rs.fields[11] >> s->TransmissionMode;
+ rs.fields[12] >> s->OtherFrequencyFlag;
+}
+
diff --git a/p2pvr/lib/dvbsiHelpers.h b/p2pvr/lib/dvbsiHelpers.h
new file mode 100644
index 0000000..49cb404
--- /dev/null
+++ b/p2pvr/lib/dvbsiHelpers.h
@@ -0,0 +1,60 @@
+#ifndef ICE_DVBSI_HELPERS_H
+#define ICE_DVBSI_HELPERS_H
+
+#include <p2pvr.h>
+#include "objectRowState.h"
+
+template<>
+void
+CreateColumns<DVBSI::NetworkPtr>(const ColumnCreator & cc);
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::NetworkPtr & network);
+
+template<>
+void
+CreateColumns<DVBSI::NetworkTransportStreamPtr>(const ColumnCreator & cc);
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::NetworkTransportStreamPtr & ts, const DVBSI::NetworkPtr & network);
+
+template<>
+void
+CreateColumns<DVBSI::NetworkService>(const ColumnCreator & cc);
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::NetworkService & s, const DVBSI::NetworkTransportStreamPtr & ts);
+
+template<>
+void
+CreateColumns<DVBSI::ServicePtr>(const ColumnCreator & cc);
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::ServicePtr & s, const DVBSI::TransportStreamPtr & ts);
+
+template<>
+void
+CreateColumns<DVBSI::EventPtr>(const ColumnCreator & cc);
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::EventPtr & e);
+
+template<>
+void
+CreateColumns<DVBSI::TerrestrialDeliveryPtr>(const ColumnCreator & cc);
+
+template<>
+void
+BindColumns(RowState & rs, const DVBSI::TerrestrialDeliveryPtr & e, const DVBSI::TransportStreamPtr & ts);
+
+template<>
+void
+UnbindColumns(RowState & rs, const DVBSI::TerrestrialDeliveryPtr & s);
+
+#endif
+
diff --git a/p2pvr/lib/fileHandle.cpp b/p2pvr/lib/fileHandle.cpp
new file mode 100644
index 0000000..08575b3
--- /dev/null
+++ b/p2pvr/lib/fileHandle.cpp
@@ -0,0 +1,27 @@
+#include "fileHandle.h"
+#include <unistd.h>
+#include <stdexcept>
+
+class InvalidFileHandle : public std::runtime_error {
+ public:
+ InvalidFileHandle() : std::runtime_error("Invalid file handle") { }
+};
+
+FileHandle::FileHandle(int f) :
+ fd(f)
+{
+ if (fd < 0) {
+ throw InvalidFileHandle();
+ }
+}
+
+FileHandle::~FileHandle()
+{
+ close(fd);
+}
+
+FileHandle::operator int() const
+{
+ return fd;
+}
+
diff --git a/p2pvr/lib/fileHandle.h b/p2pvr/lib/fileHandle.h
new file mode 100644
index 0000000..3c8d45e
--- /dev/null
+++ b/p2pvr/lib/fileHandle.h
@@ -0,0 +1,19 @@
+#ifndef FILEHANDLE_H
+#define FILEHANDLE_H
+
+class FileHandle {
+ public:
+ FileHandle(int fd);
+ ~FileHandle();
+
+ FileHandle(const FileHandle &) = delete;
+ void operator=(const FileHandle &) = delete;
+
+ operator int() const;
+
+ private:
+ const int fd;
+};
+
+#endif
+
diff --git a/p2pvr/lib/frontend.cpp b/p2pvr/lib/frontend.cpp
new file mode 100644
index 0000000..1044f6f
--- /dev/null
+++ b/p2pvr/lib/frontend.cpp
@@ -0,0 +1,35 @@
+#include "frontend.h"
+#include "tuner.h"
+#include <logger.h>
+#include <sys/ioctl.h>
+#include <linux/dvb/frontend.h>
+
+Frontend::Frontend(Tuner * t, int fd, const struct dvb_frontend_info & i) :
+ tuner(t),
+ frontendFD(fd),
+ fe_info(i)
+{
+}
+
+Frontend::~Frontend()
+{
+ close(frontendFD);
+}
+
+const struct dvb_frontend_info &
+Frontend::Info() const
+{
+ return fe_info;
+}
+
+fe_status
+Frontend::GetStatus() const
+{
+ fe_status_t status;
+ if (ioctl(frontendFD, FE_READ_STATUS, &status) < 0) {
+ Logger()->messagebf(LOG_ERR, "Reading frontend %s status failed (%s:%d)", tuner->Device(), strerror(errno), errno);
+ throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno);
+ }
+ return status;
+}
+
diff --git a/p2pvr/lib/frontend.h b/p2pvr/lib/frontend.h
new file mode 100644
index 0000000..994abfa
--- /dev/null
+++ b/p2pvr/lib/frontend.h
@@ -0,0 +1,32 @@
+#ifndef P2PVR_FRONTEND_H
+#define P2PVR_FRONTEND_H
+
+#include <linux/dvb/frontend.h>
+#include <genLoader.h>
+#include <p2pvr.h>
+
+class Tuner;
+
+class Frontend {
+ public:
+ typedef boost::function<bool(long)> OnFrequencyFound;
+ Frontend(Tuner *, int fd, const struct dvb_frontend_info &);
+ virtual ~Frontend();
+
+ fe_status_t GetStatus() const;
+ virtual void TuneTo(const DVBSI::DeliveryPtr &) const = 0;
+ virtual void FrequencyScan(const OnFrequencyFound & off) const = 0;
+ virtual std::string Type() const = 0;
+ const struct dvb_frontend_info & Info() const;
+
+ protected:
+ const Tuner * tuner;
+ const int frontendFD;
+ const struct dvb_frontend_info fe_info;
+};
+
+typedef GenLoader<Frontend, fe_type, Tuner *, int, const struct dvb_frontend_info &> FrontendLoader;
+typedef boost::shared_ptr<Frontend> FrontendPtr;
+
+#endif
+
diff --git a/p2pvr/lib/frontends/ofdm.cpp b/p2pvr/lib/frontends/ofdm.cpp
new file mode 100644
index 0000000..8e2b23c
--- /dev/null
+++ b/p2pvr/lib/frontends/ofdm.cpp
@@ -0,0 +1,145 @@
+#include "../frontend.h"
+#include "../tuner.h"
+#include <sys/ioctl.h>
+#include <logger.h>
+#include <linux/dvb/frontend.h>
+
+#define FREQ_OFFSET_MIN 0
+#define FREQ_OFFSET_MAX 4
+
+class Frontend_OFDM : public Frontend {
+ public:
+ Frontend_OFDM(Tuner * t, int fd, const struct dvb_frontend_info & i) : Frontend(t, fd, i) { }
+
+ void TuneTo(const DVBSI::DeliveryPtr & mp) const
+ {
+ auto td = DVBSI::TerrestrialDeliveryPtr::dynamicCast(mp);
+ if (!td) {
+ throw P2PVR::IncorrectDeliveryType();
+ }
+ dvb_frontend_parameters feparams;
+ memset(&feparams, 0, sizeof(dvb_frontend_parameters));
+ feparams.frequency = td->Frequency;
+ feparams.inversion = INVERSION_OFF;
+ feparams.u.ofdm.bandwidth = (fe_bandwidth)td->Bandwidth;
+ feparams.u.ofdm.code_rate_HP = (fe_code_rate_t)td->CodeRateHP;
+ feparams.u.ofdm.code_rate_LP = (fe_code_rate_t)td->CodeRateLP;
+ feparams.u.ofdm.constellation = (fe_modulation_t)td->Constellation;
+ feparams.u.ofdm.transmission_mode = (fe_transmit_mode)td->TransmissionMode;
+ feparams.u.ofdm.guard_interval = (fe_guard_interval_t)td->GuardInterval;
+ feparams.u.ofdm.hierarchy_information = (fe_hierarchy_t)td->Hierarchy;
+ SetParameters(feparams);
+ }
+
+ dvb_frontend_parameters GetParameters() const
+ {
+ dvb_frontend_parameters feparams;
+ memset(&feparams, 0, sizeof(dvb_frontend_parameters));
+ if (ioctl(frontendFD, FE_GET_FRONTEND, &feparams) < 0) {
+ Logger()->messagebf(LOG_ERR, "Reading frontend parameters failed (%s:%d)", tuner->Device(), strerror(errno), errno);
+ throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno);
+ }
+ return feparams;
+ }
+
+ void SetParameters(const dvb_frontend_parameters & feparams) const
+ {
+ if (ioctl(frontendFD, FE_SET_FRONTEND, &feparams) < 0) {
+ Logger()->messagebf(LOG_ERR, "Tuning of device %s failed (%s:%d)", tuner->Device(), strerror(errno), errno);
+ throw P2PVR::DeviceError(tuner->Device(), strerror(errno), errno);
+ }
+ }
+
+ std::string Type() const
+ {
+ return "OFDM (DVB-T)";
+ }
+
+ enum Country { DVBT_AU, DVBT_DE, DVBT_FR, DVBT_GB };
+
+ static uint32_t FrequencyForCountry(Country country, int channel)
+ {
+ switch (country) {
+ case DVBT_AU: //AUSTRALIA, 7MHz step list
+ switch (channel) {
+ case 5 ... 12: return 142500000;
+ case 21 ... 69: return 333500000;
+ }
+ case DVBT_DE: //GERMANY
+ case DVBT_FR: //FRANCE, +/- offset 166kHz & +offset 332kHz & +offset 498kHz
+ case DVBT_GB: //UNITED KINGDOM, +/- offset
+ switch (channel) {
+ case 5 ... 12: return 142500000; // VHF unused in FRANCE, skip those in offset loop
+ case 21 ... 69: return 306000000;
+ }
+ }
+ return 0;
+ }
+ static uint32_t FrequencyStepForCountry(Country country, int channel)
+ {
+ switch (country) {
+ case DVBT_AU:
+ return 7000000; // dvb-t australia, 7MHz step
+ case DVBT_DE:
+ case DVBT_FR:
+ case DVBT_GB:
+ switch (channel) { // dvb-t europe, 7MHz VHF ch5..12, all other 8MHz
+ case 5 ... 12: return 7000000;
+ case 21 ... 69: return 8000000;
+ }
+ }
+ return 0;
+ }
+ static uint32_t ChannelFrequencyForCountry(Country country, int channel, int)
+ {
+ return FrequencyForCountry(country, channel) + (channel * FrequencyStepForCountry(country, channel));
+ }
+
+ void FrequencyScan(const OnFrequencyFound & onFrequencyFound) const
+ {
+ struct dvb_frontend_parameters feparams;
+ memset(&feparams, 0, sizeof(dvb_frontend_parameters));
+ feparams.inversion = (fe_info.caps & FE_CAN_INVERSION_AUTO ? INVERSION_AUTO : INVERSION_OFF);
+ feparams.u.ofdm.constellation = (fe_info.caps & FE_CAN_QAM_AUTO ? QAM_AUTO : QAM_64);
+ feparams.u.ofdm.hierarchy_information = HIERARCHY_NONE;
+
+ for (int channel = 0; channel < 134; channel += 1) {
+ for (uint32_t offset = FREQ_OFFSET_MIN; offset <= 0/*FREQ_OFFSET_MAX*/; offset += 1) {
+ feparams.frequency = ChannelFrequencyForCountry(DVBT_GB, channel, offset);
+ if (feparams.frequency == 0) {
+ continue;
+ }
+ if (fe_info.frequency_min > feparams.frequency || fe_info.frequency_max < feparams.frequency) {
+ Logger()->messagebf(LOG_WARNING, "Channel %d, freq (%d Hz) outside card range", channel, feparams.frequency);
+ continue;
+ }
+ Logger()->messagebf(LOG_DEBUG, "Channel %d, Frequency %d Hz", channel, feparams.frequency);
+ SetParameters(feparams);
+ fe_status status;
+ // Wait for something
+ for (int x = 0; x < 150 && (status = GetStatus()) == 0; x += 100) {
+ usleep(1000);
+ }
+ // Was it useful?
+ if (!(status & (FE_HAS_SIGNAL | FE_HAS_CARRIER))) {
+ continue;
+ }
+ // Wait for lock
+ for (int x = 0; x < 500 && ((status = GetStatus()) & FE_HAS_LOCK) == 0; x += 100) {
+ usleep(10000);
+ }
+ // Did we get lock?
+ if (status & FE_HAS_LOCK) {
+ Logger()->messagebf(LOG_INFO, "Found multiplex at %d Hz", feparams.frequency);
+ Logger()->messagebf(LOG_DEBUG, "frequency %d", feparams.frequency);
+ if (onFrequencyFound(feparams.frequency)) {
+ return;
+ }
+ }
+ }
+ }
+ }
+};
+
+DECLARE_GENERIC_LOADER(FE_OFDM, FrontendLoader, Frontend_OFDM);
+
diff --git a/p2pvr/lib/globalDevices.cpp b/p2pvr/lib/globalDevices.cpp
new file mode 100644
index 0000000..8dfe77d
--- /dev/null
+++ b/p2pvr/lib/globalDevices.cpp
@@ -0,0 +1,59 @@
+#include "globalDevices.h"
+#include <Ice/Ice.h>
+
+std::vector<std::string> GlobalDevices::Devices;
+
+DECLARE_OPTIONS(GlobalDevices, "P2PVR Devices")
+("p2pvr.globaldevices.carddaemon",
+ Options::functions(
+ [](const VariableType & df) { Devices.push_back(df); },
+ []{ Devices.clear(); }),
+ "ICE address of remote device pools (<adapter>:<endpoint>)")
+END_OPTIONS(GlobalDevices);
+
+P2PVR::TunerPrx
+GlobalDevices::GetTunerSpecific(const DVBSI::DeliveryPtr & delivery, Ice::Long until, const Ice::Current & ice)
+{
+ auto ic = ice.adapter->getCommunicator();
+ BOOST_FOREACH(const auto & pool, Devices) {
+ auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool));
+ auto tuner = poolprx->GetTunerSpecific(delivery, until);
+ if (tuner) return tuner;
+ }
+ return NULL;
+}
+
+P2PVR::TunerPrx
+GlobalDevices::GetTunerAny(short type, const DVBSI::DeliveryPtr & delivery, Ice::Long until, const Ice::Current & ice)
+{
+ auto ic = ice.adapter->getCommunicator();
+ BOOST_FOREACH(const auto & pool, Devices) {
+ auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool));
+ auto tuner = poolprx->GetTunerAny(type, delivery, until);
+ if (tuner) return tuner;
+ }
+ return NULL;
+}
+
+P2PVR::PrivateTunerPrx
+GlobalDevices::GetPrivateTuner(short type, Ice::Long until, const Ice::Current & ice)
+{
+ auto ic = ice.adapter->getCommunicator();
+ BOOST_FOREACH(const auto & pool, Devices) {
+ auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool));
+ auto tuner = poolprx->GetPrivateTuner(type, until);
+ if (tuner) return tuner;
+ }
+ return NULL;
+}
+
+void
+GlobalDevices::ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice)
+{
+ auto ic = ice.adapter->getCommunicator();
+ BOOST_FOREACH(const auto & pool, Devices) {
+ auto poolprx = P2PVR::DevicesPrx::checkedCast(ic->stringToProxy(pool));
+ poolprx->ReleaseTuner(tuner);
+ }
+}
+
diff --git a/p2pvr/lib/globalDevices.h b/p2pvr/lib/globalDevices.h
new file mode 100644
index 0000000..0cf9636
--- /dev/null
+++ b/p2pvr/lib/globalDevices.h
@@ -0,0 +1,24 @@
+#ifndef GLOBALDEVICES_H
+#define GLOBALDEVICES_H
+
+// Global devices implements a device collection (P2PVR::Devices) for any devices known
+// throughout the system through other Devices interfaces
+
+#include <p2pvr.h>
+#include <options.h>
+
+class GlobalDevices : public P2PVR::Devices {
+ public:
+ P2PVR::TunerPrx GetTunerSpecific(const DVBSI::DeliveryPtr &, Ice::Long until, const Ice::Current &);
+ P2PVR::TunerPrx GetTunerAny(short type, const DVBSI::DeliveryPtr &, Ice::Long until, const Ice::Current &);
+ P2PVR::PrivateTunerPrx GetPrivateTuner(short type, Ice::Long until, const Ice::Current &);
+ void ReleaseTuner(const P2PVR::TunerPrx &, const Ice::Current &);
+
+ INITOPTIONS;
+ private:
+ static std::vector<std::string> Devices;
+};
+
+#endif
+
+
diff --git a/p2pvr/lib/localDevices.cpp b/p2pvr/lib/localDevices.cpp
new file mode 100644
index 0000000..330271a
--- /dev/null
+++ b/p2pvr/lib/localDevices.cpp
@@ -0,0 +1,151 @@
+#include "localDevices.h"
+#include <Ice/Ice.h>
+#include "tuner.h"
+#include <logger.h>
+
+LocalDevices::Devices LocalDevices::devices;
+std::mutex LocalDevices::lock;
+
+DECLARE_OPTIONS(LocalDevices, "P2PVR Devices")
+("p2pvr.localdevices.frontend",
+ Options::functions(
+ [](const VariableType & df) { devices.insert(Devices::value_type(df.as<std::string>(), OpenTunerPtr())); },
+ []{ devices.clear(); }),
+ "Frontend of DVB devices to use (/dev/dvb/adapterX/frontendY)")
+END_OPTIONS(LocalDevices);
+
+P2PVR::TunerPrx
+LocalDevices::GetTunerSpecific(const DVBSI::DeliveryPtr & delivery, Ice::Long until, const Ice::Current & ice)
+{
+ std::lock_guard<std::mutex> g(lock);
+ Logger()->messagebf(LOG_DEBUG, "%s: Searching for an open sharable tuner (frequency %d)", __PRETTY_FUNCTION__, delivery->Frequency);
+ auto openTuner = std::find_if(devices.begin(), devices.end(), [delivery](const Devices::value_type & ot) {
+ return ot.second && !ot.second->openedPrivate && ot.second->delivery && ot.second->delivery->Frequency == delivery->Frequency;
+ });
+ if (openTuner != devices.end()) {
+ openTuner->second->until = std::max(openTuner->second->until, time(NULL) + until);
+ openTuner->second->clients += 1;
+ return openTuner->second->tuner;
+ }
+
+ openTuner = std::find_if(devices.begin(), devices.end(), [](const Devices::value_type & ot) { return !ot.second; });
+ if (openTuner == devices.end()) {
+ Logger()->messagebf(LOG_DEBUG, "%s: None suitable and none free (frequency %d)",
+ __PRETTY_FUNCTION__, delivery->Frequency);
+ return NULL;
+ }
+
+ Logger()->messagebf(LOG_DEBUG, "%s: Opening a sharable tuner (frequency %d, frontend %s)",
+ __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first);
+ auto tuner = P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new Tuner(openTuner->first)));
+ openTuner->second = OpenTunerPtr(new OpenTuner(delivery, tuner, until, false));
+ tuner->TuneTo(delivery);
+
+ Logger()->messagebf(LOG_DEBUG, "%s: Tuned, returning (frequency %d, frontend %s)",
+ __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first);
+ return tuner;
+}
+
+P2PVR::TunerPrx
+LocalDevices::GetTunerAny(short , const DVBSI::DeliveryPtr & delivery, Ice::Long until, const Ice::Current & ice)
+{
+ std::lock_guard<std::mutex> g(lock);
+ Logger()->messagebf(LOG_DEBUG, "%s: Searching for an open sharable tuner any frequency", __PRETTY_FUNCTION__);
+ auto openTuner = std::find_if(devices.begin(), devices.end(), [delivery](const Devices::value_type & ot) {
+ return ot.second && !ot.second->openedPrivate && ot.second->delivery;
+ });
+ if (openTuner != devices.end()) {
+ openTuner->second->until = std::max(openTuner->second->until, time(NULL) + until);
+ openTuner->second->clients += 1;
+ return openTuner->second->tuner;
+ }
+
+ openTuner = std::find_if(devices.begin(), devices.end(), [](const Devices::value_type & ot) { return !ot.second; });
+ if (openTuner == devices.end()) {
+ Logger()->messagebf(LOG_DEBUG, "%s: None suitable and none free (frequency %d)",
+ __PRETTY_FUNCTION__, delivery->Frequency);
+ return NULL;
+ }
+
+ Logger()->messagebf(LOG_DEBUG, "%s: Opening a sharable tuner (frequency %d, frontend %s)",
+ __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first);
+ auto tuner = P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new Tuner(openTuner->first)));
+ openTuner->second = OpenTunerPtr(new OpenTuner(delivery, tuner, until, false));
+ tuner->TuneTo(delivery);
+
+ Logger()->messagebf(LOG_DEBUG, "%s: Tuned, returning (frequency %d, frontend %s)",
+ __PRETTY_FUNCTION__, delivery->Frequency, openTuner->first);
+ return tuner;
+}
+
+P2PVR::PrivateTunerPrx
+LocalDevices::GetPrivateTuner(short , Ice::Long until, const Ice::Current & ice)
+{
+ std::lock_guard<std::mutex> g(lock);
+ Logger()->messagebf(LOG_DEBUG, "%s: Opening a private tuner", __PRETTY_FUNCTION__);
+ auto openTuner = std::find_if(devices.begin(), devices.end(), [](const Devices::value_type & ot) { return !ot.second; });
+ if (openTuner == devices.end()) {
+ Logger()->messagebf(LOG_DEBUG, "%s: None free", __PRETTY_FUNCTION__);
+ return NULL;
+ }
+
+ Logger()->messagebf(LOG_DEBUG, "%s: Opening a private tuner (frontend %s)",
+ __PRETTY_FUNCTION__, openTuner->first);
+ auto tuner = P2PVR::PrivateTunerPrx::checkedCast(ice.adapter->addWithUUID(new Tuner(openTuner->first)));
+ openTuner->second = OpenTunerPtr(new OpenTuner(NULL, tuner, until, true));
+
+ return tuner;
+}
+
+void
+LocalDevices::ReleaseTuner(const P2PVR::TunerPrx & tuner, const Ice::Current & ice)
+{
+ std::lock_guard<std::mutex> g(lock);
+ Logger()->messagebf(LOG_DEBUG, "%s", __PRETTY_FUNCTION__);
+ auto openTuner = std::find_if(devices.begin(), devices.end(), [tuner](const Devices::value_type & ot) {
+ return ot.second && ot.second->tuner == tuner;
+ });
+ auto id = tuner->ice_getIdentity();
+ if (ice.adapter->find(id)) {
+ ice.adapter->remove(id);
+ }
+ if (openTuner == devices.end()) {
+ Logger()->messagebf(LOG_DEBUG, "%s: Not one of mine", __PRETTY_FUNCTION__);
+ return;
+ }
+ Logger()->messagebf(LOG_DEBUG, "%s: Locally owned deivce %s", __PRETTY_FUNCTION__, openTuner->first);
+ openTuner->second->clients -= 1;
+ if (openTuner->second->clients == 0) {
+ openTuner->second.reset();
+ }
+}
+
+void
+LocalDevices::Scan(const Ice::Current &)
+{
+ std::lock_guard<std::mutex> g(lock);
+}
+
+void
+LocalDevices::Add(const std::string & frontend, const Ice::Current &)
+{
+ std::lock_guard<std::mutex> g(lock);
+ devices.insert(Devices::value_type(frontend, OpenTunerPtr()));
+}
+
+void
+LocalDevices::Remove(const std::string & frontend, const Ice::Current &)
+{
+ std::lock_guard<std::mutex> g(lock);
+ devices.erase(frontend);
+}
+
+LocalDevices::OpenTuner::OpenTuner(DVBSI::DeliveryPtr d, P2PVR::PrivateTunerPrx t, Ice::Long u, bool op) :
+ openedPrivate(op),
+ delivery(d),
+ tuner(t),
+ until(u),
+ clients(1)
+{
+}
+
diff --git a/p2pvr/lib/localDevices.h b/p2pvr/lib/localDevices.h
new file mode 100644
index 0000000..a16443c
--- /dev/null
+++ b/p2pvr/lib/localDevices.h
@@ -0,0 +1,42 @@
+#ifndef LOCALDEVICES_H
+#define LOCALDEVICES_H
+
+// Local devices implements a device collection (P2PVR::Devices) for any devices physically
+// attached to the local machine; that is, can be accessed directly through /dev/dvb/adapterX
+
+#include <p2pvr.h>
+#include <options.h>
+#include <mutex>
+
+class LocalDevices : public P2PVR::LocalDevices {
+ public:
+ P2PVR::TunerPrx GetTunerSpecific(const DVBSI::DeliveryPtr &, Ice::Long until, const Ice::Current &);
+ P2PVR::TunerPrx GetTunerAny(short type, const DVBSI::DeliveryPtr &, Ice::Long until, const Ice::Current &);
+ P2PVR::PrivateTunerPrx GetPrivateTuner(short type, Ice::Long until, const Ice::Current &);
+ void ReleaseTuner(const P2PVR::TunerPrx &, const Ice::Current &);
+
+ void Scan(const Ice::Current &);
+ void Add(const std::string & frontend, const Ice::Current &);
+ void Remove(const std::string & frontend, const Ice::Current &);
+
+ INITOPTIONS;
+ private:
+ class OpenTuner {
+ public:
+ OpenTuner(DVBSI::DeliveryPtr, P2PVR::PrivateTunerPrx, Ice::Long, bool);
+
+ const bool openedPrivate;
+ const DVBSI::DeliveryPtr delivery;
+ const P2PVR::PrivateTunerPrx tuner;
+
+ Ice::Long until;
+ unsigned int clients;
+ };
+ typedef boost::shared_ptr<OpenTuner> OpenTunerPtr;
+ typedef std::map<std::string, OpenTunerPtr> Devices;
+ static Devices devices;
+ static std::mutex lock;
+};
+
+#endif
+
diff --git a/p2pvr/lib/maintenance.cpp b/p2pvr/lib/maintenance.cpp
new file mode 100644
index 0000000..71ddf60
--- /dev/null
+++ b/p2pvr/lib/maintenance.cpp
@@ -0,0 +1,288 @@
+#include "maintenance.h"
+#include "siParsers/network.h"
+#include "siParsers/event.h"
+#include "siParsers/service.h"
+#include <Ice/Ice.h>
+#include <stdexcept>
+#include <iomanip>
+#include <logger.h>
+#include <sqlMergeTask.h>
+#include <commonObjects.h>
+#include <commonHelpers.h>
+#include "p2Helpers.h"
+#include "dvbsiHelpers.h"
+#include "containerIterator.h"
+#include "singleIterator.h"
+#include "temporaryIceAdapterObject.h"
+
+#include <linux/dvb/frontend.h>
+
+void
+SqlMergeColumnsInserter(SqlMergeTask * merge, const std::string & name, bool key)
+{
+ merge->cols.insert(new SqlMergeTask::TargetColumn(name, key));
+ if (key) {
+ merge->keys.insert(name);
+ }
+}
+
+class SiNetworkInformationMerger : public SiNetworkInformationParser {
+ public:
+ SiNetworkInformationMerger(CommonObjects * co) : commonObjects(co) { }
+
+ void HandleTable(DVBSI::NetworkPtr n)
+ {
+ Logger()->messagebf(LOG_DEBUG, "Network Id: %d Name: %s", n->NetworkId, *n->Name);
+ BOOST_FOREACH(const auto & ts, n->TransportStreams) {
+ Logger()->messagebf(LOG_DEBUG, "\tTransport Stream Id: %d Original Network Id: %d", ts->TransportStreamId, ts->OriginalNetworkId);
+ BOOST_FOREACH(const auto & s, ts->Services) {
+ Logger()->messagebf(LOG_DEBUG, "\t\tService Id: %d Service Type: %d", s.ServiceId, s.ServiceType);
+ }
+ if (ts->Terrestrial) {
+ Logger()->messagebf(LOG_DEBUG, "\t\tDVB-T: Frequency: %d", ts->Terrestrial->Frequency);
+ }
+ }
+
+ SqlMergeTask mergeNetwork("postgres", "networks");
+ CreateColumns<DVBSI::NetworkPtr>(boost::bind(SqlMergeColumnsInserter, &mergeNetwork, _1, _2));
+ std::vector<DVBSI::NetworkPtr> networks = { n };
+ mergeNetwork.sources.insert(new ContainerIterator<std::vector<DVBSI::NetworkPtr>>(&networks));
+ mergeNetwork.loadComplete(commonObjects);
+ mergeNetwork.execute(NULL);
+
+ SqlMergeTask mergeTransports("postgres", "transportstreams");
+ CreateColumns<DVBSI::NetworkTransportStreamPtr>(boost::bind(SqlMergeColumnsInserter, &mergeTransports, _1, _2));
+ mergeTransports.sources.insert(new ContainerIterator<DVBSI::NetworkTransportStreams>(&n->TransportStreams, n));
+ mergeTransports.loadComplete(commonObjects);
+ mergeTransports.execute(NULL);
+
+ SqlMergeTask mergeDvbt("postgres", "delivery_dvbt");
+ CreateColumns<DVBSI::TerrestrialDeliveryPtr>(boost::bind(SqlMergeColumnsInserter, &mergeDvbt, _1, _2));
+ BOOST_FOREACH(const auto & s, n->TransportStreams) {
+ if (s->Terrestrial) {
+ mergeDvbt.sources.insert(new SingleIterator<DVBSI::TerrestrialDeliveryPtr>(&s->Terrestrial, s));
+ }
+ }
+ mergeDvbt.loadComplete(commonObjects);
+ mergeDvbt.execute(NULL);
+
+ SqlMergeTask mergeServices("postgres", "services");
+ CreateColumns<DVBSI::NetworkService>(boost::bind(SqlMergeColumnsInserter, &mergeServices, _1, _2));
+ BOOST_FOREACH(const auto & s, n->TransportStreams) {
+ mergeServices.sources.insert(new ContainerIterator<DVBSI::NetworkServiceList>(&s->Services, s));
+ }
+ mergeServices.loadComplete(commonObjects);
+ mergeServices.execute(NULL);
+ }
+ private:
+ CommonObjects * commonObjects;
+};
+
+class SiServicesMerger : public SiServicesParser {
+ public:
+ SiServicesMerger(CommonObjects * co) : commonObjects(co) { }
+
+ void HandleTable(DVBSI::TransportStreamPtr ts)
+ {
+ Logger()->messagebf(LOG_DEBUG, "Transport Stream Id: %d Original Network Id: %s", ts->TransportStreamId, ts->OriginalNetworkId);
+ BOOST_FOREACH(const auto & s, ts->Services) {
+ Logger()->messagebf(LOG_DEBUG, "\tService Id: %d Name: %s Type: %d, Provider: %s, DefaultAuthority: %s, RunningStatus %d FreeCaMode %d",
+ s->ServiceId, (s->Name ? *s->Name : "?"), (s->Type ? *s->Type : -1),
+ (s->ProviderName ? *s->ProviderName : "?"), (s->DefaultAuthority ? *s->DefaultAuthority : "?"),
+ s->RunningStatus, s->FreeCaMode);
+ }
+
+ SqlMergeTask mergeServices("postgres", "services");
+ CreateColumns<DVBSI::ServicePtr>(boost::bind(SqlMergeColumnsInserter, &mergeServices, _1, _2));
+ // Don't change the list of services available from the network
+ mergeServices.doDelete = VariableType(false);
+ mergeServices.doInsert = VariableType(false);
+ mergeServices.sources.insert(new ContainerIterator<DVBSI::ServiceList>(&ts->Services, ts));
+ mergeServices.loadComplete(commonObjects);
+ mergeServices.execute(NULL);
+ }
+
+ private:
+ CommonObjects * commonObjects;
+};
+
+class SiEventsHandler : public SiEpgParser {
+ public:
+ SiEventsHandler(const RowProcessorCallback & cb) :
+ callBack(cb) {}
+
+ void HandleTable(DVBSI::EventPtr e)
+ {
+ Logger()->messagebf(LOG_DEBUG, "Service Id: %d Program Id: %d Title: %s Time: %s - %s",
+ e->ServiceId, e->EventId, e->Title, e->StartTime, e->StopTime);
+ BindColumns<DVBSI::EventPtr>(rowState, e);
+ rowState.process(callBack);
+ }
+
+ private:
+ ObjectRowState<DVBSI::EventPtr> rowState;
+ const RowProcessorCallback callBack;
+};
+
+void
+Maintenance::UpdateAll(const Ice::Current & ice)
+{
+ UpdateAll(FE_OFDM, ice);
+ UpdateAll(FE_QPSK, ice);
+ UpdateAll(FE_ATSC, ice);
+ UpdateAll(FE_QAM, ice);
+}
+
+void
+Maintenance::UpdateAll(short type, const Ice::Current & ice)
+{
+ UpdateTransports(type, ice);
+ UpdateServices(type, ice);
+ UpdateEvents(type, ice);
+}
+
+void
+Maintenance::UpdateTransports(short type, const Ice::Current & ice)
+{
+ auto ic = ice.adapter->getCommunicator();
+ UpdateTransports(type, ic, ice.adapter);
+}
+
+void
+Maintenance::UpdateTransports(short type, Ice::CommunicatorPtr ic, Ice::ObjectAdapterPtr adapter)
+{
+ auto devs = P2PVR::DevicesPrx::checkedCast(adapter->createProxy(ic->stringToIdentity("GlobalDevices")));
+ auto si = P2PVR::SIPrx::checkedCast(adapter->createProxy(ic->stringToIdentity("SI")));
+ auto siparser = new SiNetworkInformationMerger(this);
+ TemporarayIceAdapterObject<P2PVR::RawDataClient> parser(adapter, siparser);
+
+ if (!devs) {
+ throw std::runtime_error("bad proxy(s)");
+ }
+ const auto transports = si->GetAllDeliveries(FE_OFDM);
+ // Attempt to just download fresh data
+ BOOST_FOREACH(const auto & transport, transports) {
+ P2PVR::TunerPrx tuner;
+ try {
+ tuner = devs->GetTunerAny(type, transport, time(NULL) + 300);
+ }
+ catch (...) {
+ Logger()->messagebf(LOG_WARNING, "%s: Failed to get a suitable tuner", __PRETTY_FUNCTION__);
+ continue;
+ }
+ if (!tuner) {
+ continue;
+ }
+ try {
+ tuner->SendNetworkInformation(parser);
+ devs->ReleaseTuner(tuner);
+ BOOST_FOREACH(const CommonObjects::DataSources::value_type & ds, CommonObjects::datasources) {
+ ds.second->commit();
+ }
+ return;
+ }
+ catch (const std::exception & ex) {
+ Logger()->messagebf(LOG_WARNING, "%s: Failed to fetch network information: %s", __PRETTY_FUNCTION__, ex.what());
+ devs->ReleaseTuner(tuner);
+ throw;
+ }
+ catch (...) {
+ Logger()->messagebf(LOG_WARNING, "%s: Failed to fetch network information", __PRETTY_FUNCTION__);
+ devs->ReleaseTuner(tuner);
+ throw;
+ }
+ }
+ // If we can't do that, do a complete scan
+ auto tuner = devs->GetPrivateTuner(type, time(NULL) + 300);
+ tuner->ScanAndSendNetworkInformation(parser);
+ devs->ReleaseTuner(tuner);
+}
+
+void
+Maintenance::UpdateServices(short type, const Ice::Current & ice)
+{
+ auto ic = ice.adapter->getCommunicator();
+ auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices")));
+ auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI")));
+
+ if (!devs || !si) {
+ throw std::runtime_error("bad proxy(s)");
+ }
+
+ auto siparser = new SiServicesMerger(this);
+ TemporarayIceAdapterObject<P2PVR::RawDataClient> parser(ice.adapter, siparser);
+
+ const auto deliveries = si->GetAllDeliveries(type);
+ if (deliveries.empty()) {
+ throw std::runtime_error("no delivery methods");
+ }
+
+ Logger()->messagebf(LOG_DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__);
+ auto tuner = devs->GetTunerAny(type, deliveries.front(), time(NULL) + 90);
+ Logger()->messagebf(LOG_DEBUG, "%s: Fetching service list", __PRETTY_FUNCTION__);
+ tuner->SendServiceDescriptions(parser);
+ Logger()->messagebf(LOG_INFO, "%s: Updated service list", __PRETTY_FUNCTION__);
+ devs->ReleaseTuner(tuner);
+ BOOST_FOREACH(const CommonObjects::DataSources::value_type & ds, CommonObjects::datasources) {
+ ds.second->commit();
+ }
+}
+
+class SiEventsMerger : public IHaveSubTasks {
+ public:
+ SiEventsMerger(short t, const Ice::Current & i) :
+ SourceObject(__PRETTY_FUNCTION__),
+ IHaveSubTasks(NULL),
+ type(t),
+ ice(i) { }
+
+ void execute(ExecContext * ec) const
+ {
+ auto ic = ice.adapter->getCommunicator();
+ auto devs = P2PVR::DevicesPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("GlobalDevices")));
+ auto si = P2PVR::SIPrx::checkedCast(ice.adapter->createProxy(ic->stringToIdentity("SI")));
+
+ if (!devs || !si) {
+ throw std::runtime_error("bad proxy(s)");
+ }
+
+ TemporarayIceAdapterObject<P2PVR::RawDataClient> parser(ice.adapter,
+ new SiEventsHandler(boost::bind(&SiEventsMerger::executeChildren, this, ec)));
+
+ const auto deliveries = si->GetAllDeliveries(type);
+ if (deliveries.empty()) {
+ throw std::runtime_error("no delivery methods");
+ }
+
+ Logger()->messagebf(LOG_DEBUG, "%s: Getting a tuner", __PRETTY_FUNCTION__);
+ auto tuner = devs->GetTunerAny(type, deliveries.front(), time(NULL) + 600);
+ Logger()->messagebf(LOG_DEBUG, "%s: Fetching events", __PRETTY_FUNCTION__);
+ tuner->SendEventInformation(parser);
+ devs->ReleaseTuner(tuner);
+ }
+
+ private:
+ const short type;
+ const Ice::Current & ice;
+
+ void executeChildren(ExecContext * ec) const
+ {
+ BOOST_FOREACH(const Tasks::value_type & sq, normal) {
+ sq->execute(ec);
+ }
+ }
+};
+
+void
+Maintenance::UpdateEvents(short type, const Ice::Current & ice)
+{
+ SqlMergeTask mergeEvents("postgres", "events");
+ CreateColumns<DVBSI::EventPtr>(boost::bind(SqlMergeColumnsInserter, &mergeEvents, _1, _2));
+ mergeEvents.sources.insert(new SiEventsMerger(type, ice));
+ mergeEvents.loadComplete(this);
+ mergeEvents.execute(NULL);
+ BOOST_FOREACH(const CommonObjects::DataSources::value_type & ds, CommonObjects::datasources) {
+ ds.second->commit();
+ }
+ Logger()->messagebf(LOG_INFO, "%s: Updated events", __PRETTY_FUNCTION__);
+}
diff --git a/p2pvr/lib/maintenance.h b/p2pvr/lib/maintenance.h
new file mode 100644
index 0000000..b3773cf
--- /dev/null
+++ b/p2pvr/lib/maintenance.h
@@ -0,0 +1,18 @@
+#ifndef P2PVR_MAINTENANCE_H
+#define P2PVR_MAINTENANCE_H
+
+#include <p2pvr.h>
+#include <commonObjects.h>
+
+class Maintenance : public P2PVR::Maintenance, public virtual CommonObjects {
+ public:
+ void UpdateAll(const Ice::Current &);
+ void UpdateAll(short type, const Ice::Current &);
+ void UpdateTransports(short type, const Ice::Current &);
+ void UpdateTransports(short type, Ice::CommunicatorPtr, Ice::ObjectAdapterPtr);
+ void UpdateServices(short type, const Ice::Current &);
+ void UpdateEvents(short type, const Ice::Current &);
+};
+
+#endif
+
diff --git a/p2pvr/lib/objectRowState.h b/p2pvr/lib/objectRowState.h
new file mode 100644
index 0000000..9d53d43
--- /dev/null
+++ b/p2pvr/lib/objectRowState.h
@@ -0,0 +1,43 @@
+#ifndef OBJECT_ROW_STATE_H
+#define OBJECT_ROW_STATE_H
+
+#include <boost/function.hpp>
+#include <string>
+#include <rowSet.h>
+
+typedef boost::function<void(const std::string &, bool)> ColumnCreator;
+
+template <typename V, typename... Parents>
+void BindColumns(RowState &, const V &, const Parents & ...);
+
+template <typename V>
+void UnbindColumns(RowState &, const V &);
+
+template <typename V>
+void CreateColumns(const ColumnCreator &);
+
+template <typename T>
+class ObjectRowState : public RowState {
+ public:
+ ObjectRowState() :
+ columns(ColumnCreatorHelper())
+ {
+ fields.resize(columns.size());
+ }
+ const Columns & getColumns() const { return columns; }
+
+ private:
+ Columns ColumnCreatorHelper()
+ {
+ int index = 0;
+ Columns columns;
+ CreateColumns<T>([&columns, &index](const std::string & name, bool) {
+ columns.insert(new Column(index++, name));
+ });
+ return columns;
+ }
+ Columns columns;
+};
+
+#endif
+
diff --git a/p2pvr/lib/p2Helpers.cpp b/p2pvr/lib/p2Helpers.cpp
new file mode 100644
index 0000000..b564e3b
--- /dev/null
+++ b/p2pvr/lib/p2Helpers.cpp
@@ -0,0 +1,18 @@
+#include "p2Helpers.h"
+
+template <>
+VariableType &
+operator<<<Common::DateTime>(VariableType & vt, const Common::DateTime & dt)
+{
+ vt = boost::posix_time::ptime(boost::gregorian::date(dt.Year, dt.Month, dt.Day),
+ boost::posix_time::time_duration(dt.Hour, dt.Minute, 0));
+ return vt;
+}
+
+template <>
+VariableType &
+operator>>(VariableType & vt, short int & v)
+{
+ v = (int)vt;
+ return vt;
+}
diff --git a/p2pvr/lib/p2Helpers.h b/p2pvr/lib/p2Helpers.h
new file mode 100644
index 0000000..7f2f577
--- /dev/null
+++ b/p2pvr/lib/p2Helpers.h
@@ -0,0 +1,46 @@
+#ifndef ICE_P2_HELPERS_H
+#define ICE_P2_HELPERS_H
+
+#include <variableType.h>
+#include <p2pvr.h>
+
+template <typename T>
+VariableType &
+operator>>(VariableType & vt, T & v)
+{
+ v = vt;
+ return vt;
+}
+
+template <>
+VariableType &
+operator>>(VariableType & vt, short int & v);
+
+template <typename T>
+VariableType &
+operator<<(VariableType & vt, const T & v)
+{
+ vt = v;
+ return vt;
+}
+
+template <>
+VariableType &
+operator<<<Common::DateTime>(VariableType & vt, const Common::DateTime & dt);
+
+template <typename T>
+VariableType &
+operator<<(VariableType & vt, const IceUtil::Optional<T> & v)
+{
+ if (v) {
+ vt << *v;
+ }
+ else {
+ vt = Null();
+ }
+ return vt;
+}
+
+
+#endif
+
diff --git a/p2pvr/lib/si.cpp b/p2pvr/lib/si.cpp
new file mode 100644
index 0000000..45fa793
--- /dev/null
+++ b/p2pvr/lib/si.cpp
@@ -0,0 +1,33 @@
+#include "si.h"
+#include "dvbsiHelpers.h"
+#include "containerCreator.h"
+#include <linux/dvb/frontend.h>
+#include <rdbmsDataSource.h>
+#include <sqlHandleAsVariableType.h>
+#include <selectcommand.h>
+#include <logger.h>
+
+typedef boost::shared_ptr<DB::SelectCommand> SelectPtr;
+
+P2PVR::Deliveries
+SI::GetAllDeliveries(short type, const Ice::Current &)
+{
+ auto db = dataSource<RdbmsDataSource>("postgres");
+ SelectPtr sel;
+ switch (type) {
+ case FE_OFDM:
+ sel = SelectPtr(db->getReadonly().newSelectCommand("SELECT * FROM delivery_dvbt"));
+ break;
+ }
+ Logger()->messagebf(LOG_DEBUG, "%s: ", __PRETTY_FUNCTION__);
+ P2PVR::Deliveries rtn;
+ ContainerCreator<P2PVR::Deliveries, DVBSI::TerrestrialDelivery> cc(rtn);
+ cc.populate(boost::bind(&DB::SelectCommand::fetch, sel), [sel](unsigned int c) {
+ HandleAsVariableType h;
+ const DB::Column & col = (*sel)[c];
+ col.apply(h);
+ return h.variable;
+ }, boost::bind(&DB::SelectCommand::columnCount, sel));
+ return rtn;
+}
+
diff --git a/p2pvr/lib/si.h b/p2pvr/lib/si.h
new file mode 100644
index 0000000..2740c8e
--- /dev/null
+++ b/p2pvr/lib/si.h
@@ -0,0 +1,13 @@
+#ifndef P2PVR_SI_H
+#define P2PVR_SI_H
+
+#include <p2pvr.h>
+#include <commonObjects.h>
+
+class SI : public P2PVR::SI, public virtual CommonObjects {
+ public:
+ P2PVR::Deliveries GetAllDeliveries(short type, const Ice::Current&);
+};
+
+#endif
+
diff --git a/p2pvr/lib/siParsers/event.cpp b/p2pvr/lib/siParsers/event.cpp
new file mode 100644
index 0000000..6e5446d
--- /dev/null
+++ b/p2pvr/lib/siParsers/event.cpp
@@ -0,0 +1,250 @@
+#include <time.h>
+#include <glibmm/regex.h>
+#include <boost/regex.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+#include <boost/date_time/gregorian_calendar.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/trim.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include "event.h"
+
+struct ShortEvent {
+ char lang_code[3];
+ uint8_t event_name_length;
+ u_char data[];
+} __attribute__((packed));
+
+struct Component {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ u_char :4;
+ u_char stream_content :4;
+#else
+ u_char stream_content :4;
+ u_char :4;
+#endif
+ u_char component_type /*:8*/;
+ u_char component_tag /*:8*/;
+ char lang_code[3];
+} __attribute__((packed));
+
+struct Content {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ uint8_t content_nibble_level_1 :4;
+ uint8_t content_nibble_level_2 :4;
+#else
+ uint8_t content_nibble_level_2 :4;
+ uint8_t content_nibble_level_1 :4;
+#endif
+ uint8_t user_byte;
+};
+
+struct ParentalRating {
+ char country_code[3];
+ uint8_t rating;
+} __attribute__((packed));
+
+struct EventDescriptor {
+ uint16_t EventId;
+ uint16_t mjd;
+ uint8_t start_time_h;
+ uint8_t start_time_m;
+ uint8_t start_time_s;
+ uint8_t duration_h;
+ uint8_t duration_m;
+ uint8_t duration_s;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ u_char RunningStatus : 3;
+ u_char FreeCaMode : 1;
+ u_char descriptors_length_hi : 4;
+#else
+ u_char descriptors_length_hi : 4;
+ u_char FreeCaMode : 1;
+ u_char RunningStatus : 3;
+#endif
+ u_char descriptors_length_lo;
+ u_char data[];
+} __attribute__((packed));
+
+static Glib::RefPtr<Glib::Regex> episodeRegex = Glib::Regex::create("(?:[ (]+|^)(?:\\w+ )?([0-9]+)(?: of |/)([0-9]+)[.)]+");
+static Glib::RefPtr<Glib::Regex> yearRegex = Glib::Regex::create("\\(([0-9]{4})[ )]+");
+static Glib::RefPtr<Glib::Regex> flagsRegex = Glib::Regex::create("[ []+([A-Z,]+)\\]");
+
+void
+SiEpgParser::parseDescriptor_ShortEvent(DVBSI::EventPtr current, const u_char * data)
+{
+ auto * evtdesc = reinterpret_cast<const struct ShortEvent *>(data);
+ StrPtr title, subtitle, desc;
+
+ current->TitleLang = std::string(evtdesc->lang_code, 3);
+
+ size_t evtlen = evtdesc->event_name_length;
+ if (evtlen) {
+ title = convert((const char *)evtdesc->data, evtlen);
+ }
+
+ size_t dsclen = evtdesc->data[evtlen];
+ if (dsclen) {
+ subtitle = convert((const char *)evtdesc->data + evtlen + 1, dsclen);
+ }
+
+ if (subtitle) {
+ Glib::MatchInfo matches;
+ if (episodeRegex->match(*subtitle, matches)) {
+ current->Episode = boost::lexical_cast<int>(matches.fetch(1));
+ current->Episodes = boost::lexical_cast<int>(matches.fetch(2));
+ *subtitle = episodeRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY);
+ }
+ if (yearRegex->match(*subtitle, matches)) {
+ current->Year = boost::lexical_cast<int>(matches.fetch(1));
+ *subtitle = yearRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY);
+ }
+ if (flagsRegex->match(*subtitle, matches)) {
+ current->Flags = matches.fetch(1);
+ *subtitle = yearRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY);
+ }
+ }
+ if (title && subtitle) {
+ if (boost::algorithm::ends_with(*title, "...") && boost::algorithm::starts_with(*subtitle, "...")) {
+ title->resize(title->length() - 3);
+ *title += " ";
+ size_t dot = subtitle->find('.', 4);
+ if (dot == Glib::ustring::npos) {
+ title->append(*subtitle, 3, subtitle->length() - 3);
+ }
+ else {
+ title->append(*subtitle, 3, dot - 3);
+ subtitle->erase(0, dot + 2);
+ }
+ }
+ size_t colon = subtitle->find(':');
+ if (colon != Glib::ustring::npos) {
+ desc = StrPtr(new Glib::ustring(*subtitle, colon + 1, subtitle->length() - colon));
+ subtitle->resize(colon);
+ }
+ else {
+ colon = title->find(':');
+ desc = subtitle;
+ if (colon != Glib::ustring::npos) {
+ subtitle = StrPtr(new Glib::ustring(*title, colon + 1, title->length() - colon));
+ title->resize(colon);
+ }
+ else {
+ subtitle.reset();
+ }
+ }
+ }
+ if (title) {
+ boost::algorithm::trim_if(*title, isspace);
+ current->Title = *title;
+ }
+ if (subtitle) {
+ boost::algorithm::trim_if(*subtitle, isspace);
+ if (!subtitle->empty()) {
+ current->Subtitle = *subtitle;
+ }
+ }
+ if (desc) {
+ boost::algorithm::trim_if(*desc, isspace);
+ if (!desc->empty()) {
+ current->Description = *desc;
+ }
+ }
+}
+
+void
+SiEpgParser::parseDescriptor_Component(DVBSI::EventPtr current, const u_char * data)
+{
+ auto * dc = reinterpret_cast<const struct Component *>(data);
+
+ switch (dc->stream_content) {
+ case 0x01: // Video Info
+ current->VideoHD = ((dc->component_type - 1) & 0x08) ? 1 : 0;
+ current->VideoFrameRate = ((dc->component_type - 1) & 0x04) ? 30 : 25;
+ current->VideoAspect = ((dc->component_type - 1) & 0x03);
+ break;
+ case 0x02: // Audio Info
+ current->AudioChannels = dc->component_type;
+ current->AudioLanguage = Glib::ustring(dc->lang_code, 3);
+ break;
+ case 0x03: // Teletext Info
+ current->SubtitleLanguage = Glib::ustring(dc->lang_code, 3);
+ break;
+ }
+}
+
+void
+SiEpgParser::parseDescriptor_Content(DVBSI::EventPtr current, const u_char * data)
+{
+ auto nc = reinterpret_cast<const Content *>(data);
+ current->Category = nc->content_nibble_level_1;
+ current->SubCategory = nc->content_nibble_level_2;
+ current->UserCategory = nc->user_byte;
+}
+
+void
+SiEpgParser::parseDescriptor_ParentalRating(DVBSI::EventPtr current, const u_char * data)
+{
+ auto * pr = reinterpret_cast<const ParentalRating *>(data);
+ switch (pr->rating) {
+ case 0x01 ... 0x0F:
+ current->DvbRating = pr->rating + 3;
+ break;
+ case 0x00: /*undefined*/
+ case 0x10 ... 0xFF: /*broadcaster defined*/
+ current->DvbRating = NULL;
+ break;
+ }
+}
+
+bool
+SiEpgParser::CheckTableId(u_char tableId) const
+{
+ return ((tableId >= 0x50 && tableId <= 0x5f) || (tableId >= 0x60 && tableId <= 0x6f));
+}
+
+void
+SiEpgParser::HandleTable(DVBSI::EitInformationPtr)
+{
+}
+
+Common::DateTime &
+operator<<(Common::DateTime & dt, const boost::posix_time::ptime & pt)
+{
+ dt.Year = pt.date().year();
+ dt.Month = pt.date().month();
+ dt.Day = pt.date().day();
+ dt.Hour = pt.time_of_day().hours();
+ dt.Minute = pt.time_of_day().minutes();
+ return dt;
+}
+
+void
+SiEpgParser::ParseSiTable(const EventInformation * eit, DVBSI::EitInformationPtr ei)
+{
+ ei->ServiceId = ntohs(eit->header.content_id);
+ ei->TransportStreamId = ntohs(eit->TransportStreamId);
+ ei->OriginalNetworkId = ntohs(eit->OriginalNetworkId);
+ LoopOver<EventDescriptor>(eit->data, HILO(eit->header.section_length) - 15, [this,ei](const EventDescriptor * ed) {
+ DVBSI::EventPtr e = new DVBSI::Event();
+ e->EventId = ntohs(ed->EventId);
+ e->ServiceId = ei->ServiceId;
+ // <ew>
+ boost::gregorian::date startDate(boost::gregorian::gregorian_calendar::from_modjulian_day_number(ntohs(ed->mjd)));
+ boost::posix_time::ptime time(startDate);
+ time += boost::posix_time::time_duration(BcdCharToInt(ed->start_time_h), BcdCharToInt(ed->start_time_m), BcdCharToInt(ed->start_time_s));
+ e->StartTime << time;
+ time += boost::posix_time::time_duration(BcdCharToInt(ed->duration_h), BcdCharToInt(ed->duration_m), BcdCharToInt(ed->duration_s));
+ e->StopTime << time;
+ // </ew>
+ ParseDescriptors(ed->data, HILO(ed->descriptors_length),
+ 0x4d, boost::bind(&SiEpgParser::parseDescriptor_ShortEvent, e, _1),
+ 0x50, boost::bind(&SiEpgParser::parseDescriptor_Component, e, _1),
+ 0x54, boost::bind(&SiEpgParser::parseDescriptor_Content, e, _1),
+ 0x55, boost::bind(&SiEpgParser::parseDescriptor_ParentalRating, e, _1));
+ HandleTable(e);
+ });
+}
+
diff --git a/p2pvr/lib/siParsers/event.h b/p2pvr/lib/siParsers/event.h
new file mode 100644
index 0000000..0528d98
--- /dev/null
+++ b/p2pvr/lib/siParsers/event.h
@@ -0,0 +1,35 @@
+#ifndef EPGROWS_H
+#define EPGROWS_H
+
+#include "table.h"
+#include <p2pvr.h>
+
+struct EventInformation {
+ SiTableHeader header;
+ uint16_t TransportStreamId;
+ uint16_t OriginalNetworkId;
+ uint8_t SegmentLastSectionNumber;
+ uint8_t LastTableId;
+ u_char data[];
+} __attribute__((packed));
+
+class SiEpgParser : public SiTableParser<EventInformation, DVBSI::EitInformationPtr, int> {
+ protected:
+ bool CheckTableId(u_char tableId) const;
+ int SectionNumberShift() const { return 3; }
+ uint8_t FirstTableId(const EventInformation * ei) { return (ei->header.tableid >= 0x60 ? 0x60 : 0x50); }
+ uint8_t LastTableId(const EventInformation * ei) { return ei->LastTableId; }
+ void ParseSiTable(const EventInformation * eit, DVBSI::EitInformationPtr);
+ void HandleTable(DVBSI::EitInformationPtr);
+ virtual void HandleTable(DVBSI::EventPtr) = 0;
+
+ private:
+ static void parseStartTimeAndDuration(DVBSI::EventPtr, const u_char * data);
+ static void parseDescriptor_ShortEvent(DVBSI::EventPtr, const u_char * data);
+ static void parseDescriptor_Component(DVBSI::EventPtr, const u_char * data);
+ static void parseDescriptor_Content(DVBSI::EventPtr, const u_char * data);
+ static void parseDescriptor_ParentalRating(DVBSI::EventPtr, const u_char * data);
+};
+
+#endif
+
diff --git a/p2pvr/lib/siParsers/network.cpp b/p2pvr/lib/siParsers/network.cpp
new file mode 100644
index 0000000..9f7434a
--- /dev/null
+++ b/p2pvr/lib/siParsers/network.cpp
@@ -0,0 +1,219 @@
+#include "network.h"
+#include <boost/bind.hpp>
+
+struct NetworkStreamsHeader {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ u_char reserved1 :4;
+ u_char transport_stream_loop_length_hi :4;
+#else
+ u_char transport_stream_loop_length_hi :4;
+ u_char reserved1 :4;
+#endif
+ u_char transport_stream_loop_length_lo;
+ u_char data[];
+} __attribute__((packed));
+
+struct TransportStream {
+ uint16_t transportStreamId;
+ uint16_t originalNetworkId;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ u_char reserved1 :4;
+ u_char descriptors_length_hi :4;
+#else
+ u_char descriptors_length_hi :4;
+ u_char reserved1 :4;
+#endif
+ u_char descriptors_length_lo;
+ u_char data[];
+} __attribute__((packed));
+
+struct TerrestrialDeliveryDescriptor {
+ uint32_t Frequency;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ uint8_t Bandwidth : 3;
+ uint8_t Priority : 1;
+ uint8_t TimeSlicing : 1;
+ uint8_t MpeFec : 1;
+ uint8_t _reserved1 : 2;
+#else
+ uint8_t _reserved1 : 2;
+ uint8_t MpeFec : 1;
+ uint8_t TimeSlicing : 1;
+ uint8_t Priority : 1;
+ uint8_t Bandwidth : 3;
+#endif
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ uint8_t Constellation : 2;
+ uint8_t Hierarchy : 3;
+ uint8_t CodeRateHP : 3;
+#else
+ uint8_t CodeRateHP : 3;
+ uint8_t Hierarchy : 3;
+ uint8_t Constellation : 2;
+#endif
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ uint8_t CodeRateLP : 3;
+ uint8_t GuardInterval : 2;
+ uint8_t TransmissionMode : 2;
+ uint8_t OtherFrequencyFlag : 1;
+#else
+ uint8_t OtherFrequencyFlag : 1;
+ uint8_t TransmissionMode : 2;
+ uint8_t GuardInterval : 2;
+ uint8_t CodeRateLP : 3;
+#endif
+ uint32_t _reserved2;
+} __attribute__((packed));
+
+struct CableDeliveryDescriptor {
+ uint32_t Frequency;
+ uint8_t _reserved2;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ uint8_t _reserved1 : 4;
+ uint8_t FecOuter : 4;
+#else
+ uint8_t FecOuter : 4;
+ uint8_t _reserved1 : 4;
+#endif
+ uint8_t Modulation;
+ uint8_t SymbolRate1;
+ uint8_t SymbolRate2;
+ uint8_t SymbolRate3;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ uint8_t SymbolRate4 : 4;
+ uint8_t FecInner : 4;
+#else
+ uint8_t FecInner : 4;
+ uint8_t SymbolRate4 : 4;
+#endif
+} __attribute__((packed));
+
+struct SatelliteDeliveryDescriptor {
+ uint32_t Frequency;
+ uint16_t OrbitalPosition;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ uint8_t WestEastFlag : 1;
+ uint8_t Polarization : 2;
+ uint8_t RollOff : 2;
+ uint8_t ModulationSystem : 1;
+ uint8_t ModulationType : 2;
+#else
+ uint8_t ModulationType : 2;
+ uint8_t ModulationSystem : 1;
+ uint8_t RollOff : 2;
+ uint8_t Polarization : 2;
+ uint8_t WestEastFlag : 1;
+#endif
+ uint8_t SymbolRate1;
+ uint8_t SymbolRate2;
+ uint8_t SymbolRate3;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ uint8_t SymbolRate4 : 4;
+ uint8_t FecInner : 4;
+#else
+ uint8_t FecInner : 4;
+ uint8_t SymbolRate4 : 4;
+#endif
+} __attribute__((packed));
+
+struct ServiceListDescriptor {
+ uint16_t ServiceId;
+ uint8_t ServiceType;
+} __attribute__((packed));
+
+bool
+SiNetworkInformationParser::CheckTableId(u_char tableId) const
+{
+ return (tableId == 0x40 || tableId == 0x041);
+}
+
+void
+SiNetworkInformationParser::ParseSiTable(const struct NetworkInformation * nit, DVBSI::NetworkPtr n)
+{
+ n->NetworkId = ntohs(nit->header.content_id);
+ auto nsh = ParseDescriptors<NetworkStreamsHeader>(nit->data, HILO(nit->network_descriptor_length),
+ 0x40, boost::bind(&SiNetworkInformationParser::parseDescriptor_NetworkName, n, _1, _2));
+ LoopOver<TransportStream>(nsh->data, HILO(nsh->transport_stream_loop_length), [this,n](const TransportStream * ts) {
+ DVBSI::NetworkTransportStreamPtr nts = new DVBSI::NetworkTransportStream();
+ nts->TransportStreamId = ntohs(ts->transportStreamId);
+ nts->OriginalNetworkId = ntohs(ts->originalNetworkId);
+ ParseDescriptors(ts->data, HILO(ts->descriptors_length),
+ 0x41, boost::bind(&SiNetworkInformationParser::parseDescriptor_ServiceList, nts, _1, _2),
+ 0x43, boost::bind(&SiNetworkInformationParser::parseDescriptor_SatelliteDelivery, nts, _1, _2),
+ 0x44, boost::bind(&SiNetworkInformationParser::parseDescriptor_CableDelivery, nts, _1, _2),
+ 0x5a, boost::bind(&SiNetworkInformationParser::parseDescriptor_TerrestrialDelivery, nts, _1, _2));
+ n->TransportStreams.push_back(nts);
+ });
+}
+
+void
+SiNetworkInformationParser::parseDescriptor_NetworkName(DVBSI::NetworkPtr n, const u_char * p, size_t len)
+{
+ n->Name = *convert((const char *)p, len);
+}
+
+void
+SiNetworkInformationParser::parseDescriptor_TerrestrialDelivery(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len)
+{
+ assert(len == sizeof(TerrestrialDeliveryDescriptor));
+ auto tdd = reinterpret_cast<const TerrestrialDeliveryDescriptor *>(data);
+ DVBSI::TerrestrialDeliveryPtr td = new DVBSI::TerrestrialDelivery;
+ td->Frequency = ((uint64_t)ntohl(tdd->Frequency)) * 10;
+ td->Bandwidth = tdd->Bandwidth;
+ td->Priority = tdd->Priority;
+ td->TimeSlicing = tdd->TimeSlicing;
+ td->MpeFec = tdd->MpeFec;
+ td->Constellation = tdd->Constellation;
+ td->Hierarchy = tdd->Hierarchy;
+ td->CodeRateHP = tdd->CodeRateHP;
+ td->CodeRateLP = tdd->CodeRateLP;
+ td->GuardInterval = tdd->GuardInterval;
+ td->TransmissionMode = tdd->TransmissionMode;
+ td->OtherFrequencyFlag = tdd->OtherFrequencyFlag;
+ nts->Terrestrial = td;
+}
+
+void
+SiNetworkInformationParser::parseDescriptor_CableDelivery(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len)
+{
+ assert(len == sizeof(CableDeliveryDescriptor));
+ auto cdd = reinterpret_cast<const CableDeliveryDescriptor *>(data);
+ DVBSI::CableDeliveryPtr cd = new DVBSI::CableDelivery;
+ cd->Frequency = ((uint64_t)ntohl(cdd->Frequency)) * 10;
+ cd->FecOuter = cdd->FecOuter;
+ cd->Modulation = cdd->Modulation;
+ cd->SymbolRate = HILO4(cdd->SymbolRate);
+ cd->FecInner = cdd->FecInner;
+ nts->Cable = cd;
+}
+
+void
+SiNetworkInformationParser::parseDescriptor_SatelliteDelivery(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len)
+{
+ assert(len == sizeof(SatelliteDeliveryDescriptor));
+ auto sdd = reinterpret_cast<const SatelliteDeliveryDescriptor *>(data);
+ DVBSI::SatelliteDeliveryPtr sd = new DVBSI::SatelliteDelivery;
+ sd->Frequency = ((uint64_t)ntohl(sdd->Frequency)) * 10;
+ sd->OrbitalPosition = ntohs(sdd->OrbitalPosition);
+ sd->WestEastFlag = sdd->WestEastFlag;
+ sd->Polarization = sdd->Polarization;
+ sd->RollOff = sdd->RollOff;
+ sd->ModulationSystem = sdd->ModulationSystem;
+ sd->ModulationType = sdd->ModulationType;
+ sd->SymbolRate = HILO4(sdd->SymbolRate);
+ sd->FecInner = sdd->FecInner;
+ nts->Satellite = sd;
+}
+
+void
+SiNetworkInformationParser::parseDescriptor_ServiceList(DVBSI::NetworkTransportStreamPtr nts, const u_char * data, size_t len)
+{
+ auto end = data + len;
+ while (data < end) {
+ auto d = reinterpret_cast<const ServiceListDescriptor *>(data);
+ nts->Services.push_back({ ntohs(d->ServiceId), d->ServiceType });
+ data += sizeof(ServiceListDescriptor);
+ }
+}
+
+
diff --git a/p2pvr/lib/siParsers/network.h b/p2pvr/lib/siParsers/network.h
new file mode 100644
index 0000000..6cf3b50
--- /dev/null
+++ b/p2pvr/lib/siParsers/network.h
@@ -0,0 +1,35 @@
+#ifndef NETWORKINFORMATIONPARSER_H
+#define NETWORKINFORMATIONPARSER_H
+
+#include "table.h"
+#include <p2pvr.h>
+
+struct NetworkInformation {
+ SiTableHeader header;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ u_char reserved2 :4;
+ u_char network_descriptor_length_hi :4;
+#else
+ u_char network_descriptor_length_hi :4;
+ u_char reserved2 :4;
+#endif
+ u_char network_descriptor_length_lo /*:8*/;
+ u_char data[];
+} __attribute__((packed));
+
+class SiNetworkInformationParser : public SiTableParser<NetworkInformation, DVBSI::NetworkPtr, u_char> {
+ protected:
+ bool CheckTableId(u_char tableId) const;
+ void ParseSiTable(const struct NetworkInformation * nit, DVBSI::NetworkPtr);
+
+ private:
+ static void parseDescriptor_NetworkName(DVBSI::NetworkPtr, const u_char *data, size_t len);
+ static void parseDescriptor_ServiceList(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len);
+ static void parseDescriptor_TerrestrialDelivery(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len);
+ static void parseDescriptor_SatelliteDelivery(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len);
+ static void parseDescriptor_CableDelivery(DVBSI::NetworkTransportStreamPtr, const u_char *data, size_t len);
+};
+
+#endif
+
+
diff --git a/p2pvr/lib/siParsers/service.cpp b/p2pvr/lib/siParsers/service.cpp
new file mode 100644
index 0000000..b8092af
--- /dev/null
+++ b/p2pvr/lib/siParsers/service.cpp
@@ -0,0 +1,68 @@
+#include "service.h"
+#include <boost/bind.hpp>
+
+struct ServiceDescriptor {
+ uint16_t ServiceId;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ u_char _reserved1 : 6;
+ u_char EitSchedule : 1;
+ u_char EitPresentFollowing : 1;
+#else
+ u_char EitPresentFollowing : 1;
+ u_char EitSchedule : 1;
+ u_char _reserved1 : 6;
+#endif
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ u_char RunningStatus : 3;
+ u_char FreeCaMode : 1;
+ u_char descriptors_length_hi : 4;
+#else
+ u_char descriptors_length_hi : 4;
+ u_char FreeCaMode : 1;
+ u_char RunningStatus : 3;
+#endif
+ u_char descriptors_length_lo;
+ u_char data[];
+} __attribute__((packed));
+
+bool
+SiServicesParser::CheckTableId(u_char tableId) const
+{
+ return (tableId == 0x42 || tableId == 0x46);
+}
+
+void
+SiServicesParser::ParseSiTable(const TransportStreamDescriptor * tsd, DVBSI::TransportStreamPtr ts)
+{
+ ts->TransportStreamId = ntohs(tsd->header.content_id);
+ ts->OriginalNetworkId = ntohs(tsd->original_network_id);
+ LoopOver<ServiceDescriptor>(tsd->data, HILO(tsd->header.section_length) - 12, [this,ts](const ServiceDescriptor * sd) {
+ DVBSI::ServicePtr s = new DVBSI::Service();
+ s->ServiceId = ntohs(sd->ServiceId);
+ s->EitSchedule = sd->EitSchedule;
+ s->EitPresentFollowing = sd->EitPresentFollowing;
+ s->RunningStatus = sd->RunningStatus;
+ s->FreeCaMode = sd->FreeCaMode;
+ ParseDescriptors(sd->data, HILO(sd->descriptors_length),
+ 0x48, boost::bind(&SiServicesParser::parseDescriptor_Service, s, _1, _2),
+ 0x73, boost::bind(&SiServicesParser::parseDescriptor_DefaultAuthority, s, _1, _2));
+ ts->Services.push_back(s);
+ });
+}
+
+void
+SiServicesParser::parseDescriptor_Service(DVBSI::ServicePtr s, const u_char * p, size_t)
+{
+ s->Type = p[0];
+ if (p[1]) {
+ s->ProviderName = *convert((const char *)(p + 2), p[1]);
+ }
+ s->Name = *convert((const char *)(p + 3 + p[1]), p[2 + p[1]]);
+}
+
+void
+SiServicesParser::parseDescriptor_DefaultAuthority(DVBSI::ServicePtr s, const u_char * p, size_t len)
+{
+ s->DefaultAuthority = *convert((const char *)p, len);
+}
+
diff --git a/p2pvr/lib/siParsers/service.h b/p2pvr/lib/siParsers/service.h
new file mode 100644
index 0000000..65cdbdb
--- /dev/null
+++ b/p2pvr/lib/siParsers/service.h
@@ -0,0 +1,25 @@
+#ifndef SERVICEROWS_H
+#define SERVICEROWS_H
+
+#include "table.h"
+#include <p2pvr.h>
+
+struct TransportStreamDescriptor {
+ SiTableHeader header;
+ uint16_t original_network_id;
+ uint8_t _reserved1;
+ u_char data[];
+} __attribute__((packed));
+
+class SiServicesParser : public SiTableParser<TransportStreamDescriptor, DVBSI::TransportStreamPtr, int> {
+ protected:
+ bool CheckTableId(u_char tableId) const;
+ void ParseSiTable(const struct TransportStreamDescriptor * nit, DVBSI::TransportStreamPtr);
+
+ private:
+ static void parseDescriptor_Service(DVBSI::ServicePtr, const u_char *data, size_t len);
+ static void parseDescriptor_DefaultAuthority(DVBSI::ServicePtr, const u_char *data, size_t len);
+};
+
+#endif
+
diff --git a/p2pvr/lib/siParsers/table.cpp b/p2pvr/lib/siParsers/table.cpp
new file mode 100644
index 0000000..48efd0a
--- /dev/null
+++ b/p2pvr/lib/siParsers/table.cpp
@@ -0,0 +1,76 @@
+#include "table.h"
+#include <string.h>
+#include <stdio.h>
+#include <glibmm.h>
+#include <exceptions.h>
+#include <logger.h>
+
+SimpleMessageException(ErrorReadingData);
+SimpleMessageException(TimeoutReadingData);
+SimpleMessageException(DemuxOpenFailure);
+
+const std::string SiTableParserBase::ISO10646("ISO-10646");
+const std::string SiTableParserBase::EitEncoding("ISO6937");
+const std::string SiTableParserBase::UTF8("UTF8");
+
+SiTableParserBase::SiTableParserBase() :
+ startTime(time(NULL)),
+ incomplete(0)
+{
+}
+
+SiTableParserBase::~SiTableParserBase()
+{
+}
+
+bool
+SiTableParserBase::NewData(const P2PVR::Data & bytes, const Ice::Current&)
+{
+ //Logger()->messagebf(LOG_DEBUG, "%s: Got %d bytes", __PRETTY_FUNCTION__, bytes.size());
+ return ParseInfoTable(&bytes.front(), bytes.size());
+}
+
+SiTableParserBase::StrPtr
+SiTableParserBase::convert(const char * txt, size_t len)
+{
+ if (len == 0) {
+ return boost::shared_ptr<Glib::ustring>(new Glib::ustring());
+ }
+ char enc[20];
+ switch (*txt) {
+ default:
+ EitEncoding.copy(enc, EitEncoding.length());
+ enc[EitEncoding.length()] = '\0';
+ break;
+ case 0x01 ... 0x05:
+ snprintf(enc, sizeof(enc), "ISO-8859-%d\n", txt[0] + 4);
+ txt += 1;
+ len -= 1;
+ break;
+ case 0x10:
+ snprintf(enc, sizeof(enc), "ISO-8859-%02x%02x\n", txt[1], txt[2]);
+ txt += 3;
+ len -= 3;
+ break;
+ case 0x11:
+ ISO10646.copy(enc, ISO10646.length());
+ enc[ISO10646.length()] = '\0';
+ break;
+ case 0x1F:
+ // Values for the first byte of "0x00", "0x06" to "0x0F", and "0x12" to "0x1F" are reserved for future use.
+ //fprintf(stderr, "Reserved encoding: %02x\n", txt[0]);
+ //fprintf(stderr, "%d: %.*s\n", txt[1], len - 2, txt + 2);
+ case 0x06 ... 0x0F:
+ case 0x12 ... 0x1E:
+ case 0x00: // empty string
+ return boost::shared_ptr<Glib::ustring>(new Glib::ustring());
+ }
+ size_t used = 0, newlen = 0;
+ GError * err = NULL;
+ boost::shared_ptr<gchar> utf8 = boost::shared_ptr<gchar>(g_convert(txt, len, "utf-8", enc, &used, &newlen, &err), g_free);
+ if (err) {
+ throw Glib::ConvertError(err);
+ }
+ return boost::shared_ptr<Glib::ustring>(new Glib::ustring(utf8.get()));
+}
+
diff --git a/p2pvr/lib/siParsers/table.h b/p2pvr/lib/siParsers/table.h
new file mode 100644
index 0000000..be40813
--- /dev/null
+++ b/p2pvr/lib/siParsers/table.h
@@ -0,0 +1,185 @@
+#ifndef DVBSIREADERHELPER_H
+#define DVBSIREADERHELPER_H
+
+#include <glibmm/ustring.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/function.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <arpa/inet.h>
+#include <p2pvr.h>
+#include <logger.h>
+
+typedef unsigned char u_char;
+
+#define HILO(x) (x##_hi << 8 | x##_lo)
+#define HILO2(x) (x##1 << 8 | x##2)
+#define HILO3(x) (x##1 << 16 | x##2 << 8 | x##3)
+#define HILO4(x) (x##4 << 24 | x##2 << 16 | x##3 << 8 | x##4)
+#define BcdCharToInt(x) (10*((x & 0xF0)>>4) + (x & 0xF))
+
+class SiTableParserBase : public P2PVR::RawDataClient {
+ protected:
+ SiTableParserBase();
+ virtual ~SiTableParserBase() = 0;
+
+ typedef boost::shared_ptr<Glib::ustring> StrPtr;
+
+ bool NewData(const P2PVR::Data & bytes, const Ice::Current&);
+
+ static StrPtr convert(const char * txt, size_t len);
+
+ static const std::string ISO10646;
+ static const std::string EitEncoding;
+ static const std::string UTF8;
+ protected:
+ virtual bool ParseInfoTable(const u_char * data, size_t len) = 0;
+ time_t startTime;
+ unsigned int incomplete;
+};
+
+struct SiTableHeaderBase {
+ uint8_t tableid;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ u_char section_syntax_indicator :1;
+ u_char reserved2 :3;
+ u_char section_length_hi :4;
+#else
+ u_char section_length_hi :4;
+ u_char reserved2 :3;
+ u_char section_syntax_indicator :1;
+#endif
+ uint16_t section_length_lo :8;
+} __attribute__((packed));
+
+struct SiTableHeader : public SiTableHeaderBase {
+ uint16_t content_id;
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ u_char reserved1 :2;
+ u_char version_number :5;
+ u_char current_next_indicator :1;
+#else
+ u_char current_next_indicator :1;
+ u_char version_number :5;
+ u_char reserved1 :2;
+#endif
+ uint8_t section_number;
+ uint8_t last_section_number;
+} __attribute__((packed));
+
+struct SiDescriptorHeader {
+ u_char tag;
+ u_char length;
+ u_char data[];
+} __attribute__((packed));
+
+template <class TableType, class TargetType, class Key>
+class SiTableParser : public SiTableParserBase {
+ protected:
+ typedef std::set<uint8_t> Sections; // Section numbers
+ typedef boost::tuple<uint8_t, Sections> TargetSections; // Last section number | Seen section numbers
+ typedef std::map<uint8_t, TargetSections> TableTargetSections; // TableID -> Needed references
+ typedef boost::tuple<TargetType, TableTargetSections> ContentType; // TemplateData | Needed references
+ typedef std::map<uint16_t, ContentType> Contents; // ContentID -> data
+
+ virtual int SectionNumberShift() const { return 0; }
+ virtual uint8_t LastTableId(const TableType * t) { return t->header.tableid; }
+ virtual uint8_t FirstTableId(const TableType * t) { return t->header.tableid; }
+
+ bool ParseInfoTable(const u_char * data, size_t len)
+ {
+ const u_char * dataEnd = data + len;
+ while (data < dataEnd) {
+ auto siTable = reinterpret_cast<const TableType *>(data);
+ if (siTable->header.current_next_indicator == 1 // current only, please.
+ && CheckTableId(siTable->header.tableid)) { // only tables we're interested in, please.
+ uint16_t contentId = ntohs(siTable->header.content_id);
+ ContentType & content = contents[contentId];
+ uint8_t sectionNumber = siTable->header.section_number >> SectionNumberShift();
+ TableTargetSections & targetTableSections = boost::get<1>(content);
+ TargetSections & targetSections = targetTableSections[siTable->header.tableid];
+ boost::get<0>(targetSections) = siTable->header.last_section_number >> SectionNumberShift();
+ Sections & seen = boost::get<1>(targetSections);
+ if (seen.find(sectionNumber) == seen.end()) {
+ auto & obj = boost::get<0>(content);
+ if (!obj) {
+ obj = new typename TargetType::element_type();
+ incomplete += 1;
+ }
+ ParseSiTable(siTable, obj);
+ seen.insert(sectionNumber);
+ bool complete = true;
+ for (int tid = FirstTableId(siTable); tid <= LastTableId(siTable); tid += 1) {
+ TableTargetSections::const_iterator tts = targetTableSections.find(tid);
+ if (tts == targetTableSections.end()) {
+ complete = false;
+ break;
+ }
+ if (boost::get<1>(tts->second).size() <= boost::get<0>(tts->second)) {
+ complete = false;
+ break;
+ }
+ }
+ if (complete) {
+ HandleTable(obj);
+ obj = NULL;
+ incomplete -= 1;
+ }
+ }
+ }
+ data += HILO(siTable->header.section_length) + 4;
+ }
+ return ((incomplete == 0) && (startTime < (time(NULL) - 10)));
+ }
+
+ static void ParseDescriptor(const SiDescriptorHeader * descriptor)
+ {
+ (void)descriptor;
+ // Logger()->messagef(LOG_DEBUG, "Dropped descriptor with tag 0x%02x", descriptor->tag);
+ return;
+ }
+
+ template <typename ... OtherParers>
+ static void ParseDescriptor(const SiDescriptorHeader * descriptor, u_char tag, boost::function<void(const u_char *, size_t)> parser, OtherParers ... otherParers)
+ {
+ if (tag == descriptor->tag) {
+ parser(descriptor->data, descriptor->length);
+ }
+ else {
+ ParseDescriptor(descriptor, otherParers...);
+ }
+ }
+
+ template <typename NextData = void, typename ... Parsers>
+ static const NextData * ParseDescriptors(const u_char * data, size_t len, Parsers ... parsers)
+ {
+ auto end = data + len;
+ while (data < end) {
+ auto descriptor = reinterpret_cast<const SiDescriptorHeader *>(data);
+ ParseDescriptor(descriptor, parsers...);
+ data += descriptor->length + 2;
+ }
+ return reinterpret_cast<const NextData *>(end);
+ }
+
+ template<typename LoopContent>
+ static void LoopOver(const u_char * data, size_t len, boost::function<void(const LoopContent *)> parser)
+ {
+ auto end = data + len;
+ while (data < end) {
+ auto loopData = reinterpret_cast<const LoopContent *>(data);
+ parser(loopData);
+ data += HILO(loopData->descriptors_length) + (loopData->data - data);
+ }
+ }
+
+ virtual bool CheckTableId(u_char tableId) const = 0;
+ virtual void ParseSiTable(const TableType *, TargetType) = 0;
+ virtual void HandleTable(TargetType table) = 0;
+
+ private:
+ mutable Contents contents;
+};
+
+#endif
+
diff --git a/p2pvr/lib/singleIterator.h b/p2pvr/lib/singleIterator.h
new file mode 100644
index 0000000..232ad91
--- /dev/null
+++ b/p2pvr/lib/singleIterator.h
@@ -0,0 +1,39 @@
+#ifndef SINGLEITERATOR_H
+#define SINGLEITERATOR_H
+
+#include <iHaveSubTasks.h>
+#include <boost/foreach.hpp>
+#include "objectRowState.h"
+
+template <typename T>
+class SingleIterator : public IHaveSubTasks {
+ public:
+ template <typename ... Parents>
+ SingleIterator(const T * i, const Parents & ... p) :
+ SourceObject(__PRETTY_FUNCTION__),
+ IHaveSubTasks(NULL),
+ binder(boost::bind(&BindColumns<T, Parents...>, _1, _2, p...)),
+ item(i)
+ {
+ }
+ void execute(ExecContext * ec) const
+ {
+ ObjectRowState<T> rs;
+ binder(rs, *item);
+ rs.process(boost::bind(&SingleIterator::executeChildren, this, ec));
+ }
+
+ private:
+ boost::function<void(RowState &, const T &)> binder;
+ const T * item;
+
+ void executeChildren(ExecContext * ec) const
+ {
+ BOOST_FOREACH(const Tasks::value_type & sq, normal) {
+ sq->execute(ec);
+ }
+ }
+};
+
+#endif
+
diff --git a/p2pvr/lib/temporaryIceAdapterObject.h b/p2pvr/lib/temporaryIceAdapterObject.h
new file mode 100644
index 0000000..db4b340
--- /dev/null
+++ b/p2pvr/lib/temporaryIceAdapterObject.h
@@ -0,0 +1,39 @@
+#ifndef TEMPORARYICEADAPTER_H
+#define TEMPORARYICEADAPTER_H
+
+template <typename Object>
+class TemporarayIceAdapterObject {
+ public:
+ TemporarayIceAdapterObject(Ice::ObjectAdapterPtr a, Object * object) :
+ adapter(a),
+ proxy(Object::ProxyType::checkedCast(adapter->addWithUUID(object)))
+ {
+ if (!proxy) {
+ }
+ }
+
+ ~TemporarayIceAdapterObject()
+ {
+ adapter->remove(proxy->ice_getIdentity());
+ }
+
+ TemporarayIceAdapterObject(const TemporarayIceAdapterObject &) = delete;
+ void operator=(const TemporarayIceAdapterObject &) = delete;
+
+ operator typename Object::ProxyType() const
+ {
+ return proxy;
+ }
+
+ typename Object::ProxyType operator->() const
+ {
+ return proxy;
+ }
+
+ private:
+ Ice::ObjectAdapterPtr adapter;
+ typename Object::ProxyType proxy;
+};
+
+#endif
+
diff --git a/p2pvr/lib/tuner.cpp b/p2pvr/lib/tuner.cpp
new file mode 100644
index 0000000..e508152
--- /dev/null
+++ b/p2pvr/lib/tuner.cpp
@@ -0,0 +1,355 @@
+#include "tuner.h"
+#include <fcntl.h>
+#include <Ice/Ice.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+#include <logger.h>
+#include <misc.h>
+#include <plugable.h>
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/dmx.h>
+#include <boost/crc.hpp>
+#include <boost/tuple/tuple.hpp>
+#include "fileHandle.h"
+#include "siParsers/table.h"
+
+class FrontendNotSupported : public NotSupported {
+ public:
+ FrontendNotSupported(fe_type t) : NotSupported(stringbf("Frontend not supported: %s", t))
+ { }
+};
+
+Tuner::Tuner(const boost::filesystem::path & df) :
+ deviceFrontend(df),
+ deviceRoot(df.branch_path()),
+ timeout(20000),
+ backgroundThread(NULL)
+{
+ int fd = open(deviceFrontend.string().c_str(), O_RDWR);
+ if (fd < 0) {
+ throw P2PVR::DeviceError(deviceFrontend.string(), strerror(errno), errno);
+ }
+ try {
+ struct dvb_frontend_info fe_info;
+ if (ioctl(fd, FE_GET_INFO, &fe_info) < 0) {
+ throw P2PVR::DeviceError(deviceFrontend.string(), strerror(errno), errno);
+ }
+ frontend = FrontendPtr(FrontendLoader::createNew<FrontendNotSupported>(fe_info.type, this, fd, fe_info));
+ }
+ catch (...) {
+ close(fd);
+ throw;
+ }
+ Logger()->messagebf(LOG_INFO, "%s: Attached to %s (%s, type %s)", __PRETTY_FUNCTION__,
+ deviceRoot, frontend->Info().name, frontend->Type());
+}
+
+Tuner::~Tuner()
+{
+ while (!backgroundClients.empty()) {
+ close(backgroundClients.begin()->first);
+ backgroundClients.erase(backgroundClients.begin());
+ }
+ if (backgroundThread) {
+ backgroundThread->join();
+ delete backgroundThread;
+ }
+}
+
+void
+Tuner::TuneTo(const DVBSI::DeliveryPtr & mp, const Ice::Current&)
+{
+ frontend->TuneTo(mp);
+}
+
+int
+Tuner::GetStatus(const Ice::Current &)
+{
+ return frontend->GetStatus();
+}
+
+std::string
+Tuner::Device() const
+{
+ return deviceRoot.string();
+}
+
+int
+Tuner::OpenDemux() const
+{
+ int demux = open((deviceRoot / "demux0").string().c_str(), O_RDWR | O_NONBLOCK);
+ if (demux < 0) {
+ throw P2PVR::DeviceError(deviceRoot.string(), strerror(errno), errno);
+ }
+ return demux;
+}
+
+void
+Tuner::ScanAndSendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice)
+{
+ frontend->FrequencyScan([this, &client, &ice](long) {
+ try {
+ SendNetworkInformation(client, ice);
+ return true;
+ }
+ catch (...) {
+ return false;
+ }
+ });
+}
+
+void
+Tuner::SendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice)
+{
+ SendPID(0x10, client, ice);
+}
+
+void
+Tuner::SendBouquetAssociations(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice)
+{
+ SendPID(0x11, client, ice);
+}
+
+void
+Tuner::SendServiceDescriptions(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice)
+{
+ SendPID(0x11, client, ice);
+}
+
+void
+Tuner::SendEventInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current & ice)
+{
+ SendPID(0x12, client, ice);
+}
+
+void
+Tuner::SendPID(int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current & ice) const
+{
+ Logger()->messagebf(LOG_DEBUG, "%s: pid = 0x%x", __PRETTY_FUNCTION__, pid);
+
+ ice.con->createProxy(client->ice_getIdentity());
+ FileHandle demux(OpenDemux());
+ struct dmx_sct_filter_params sctFilterParams;
+ memset(&sctFilterParams, 0, sizeof(dmx_sct_filter_params));
+ sctFilterParams.pid = pid;
+ sctFilterParams.flags = DMX_IMMEDIATE_START;
+
+ if (ioctl(demux, DMX_SET_FILTER, &sctFilterParams) < 0) {
+ throw P2PVR::DeviceError("demux", strerror(errno), errno);
+ }
+
+ ReadDemuxAndSend(demux, client);
+}
+
+void
+Tuner::ReadDemuxAndSend(int demux, const P2PVR::RawDataClientPrx & client) const
+{
+ Logger()->messagebf(LOG_DEBUG, "%s: begin", __PRETTY_FUNCTION__);
+ std::vector<Ice::AsyncResultPtr> asyncs;
+ struct pollfd ufd;
+ bool exitFlag = false;
+ do {
+ // Wait for data to appear
+ memset(&ufd, 0, sizeof(pollfd));
+ ufd.fd = demux;
+ ufd.events = POLLIN;
+ if (poll(&ufd, 1, timeout) < 1) {
+ Logger()->messagebf(LOG_DEBUG, "%s: Timed out waiting for data", __PRETTY_FUNCTION__);
+ throw P2PVR::DeviceError("demux", "Timed out. Tuned to a multiplex?", 0);
+ }
+
+ // Read it
+ P2PVR::Data buf(1 << 12);
+ int nr = read(demux, &buf.front(), buf.size());
+ if (nr < 0) {
+ throw P2PVR::DeviceError("demux", strerror(errno), errno);
+ }
+ size_t n = nr;
+ buf.resize(n);
+
+ // Verify it
+ if (n < sizeof(SiTableHeader)) {
+ Logger()->messagebf(LOG_WARNING, "Received data too small to be an SI table.");
+ }
+ auto * tab = (const SiTableHeader *)(&buf.front());
+ size_t l = sizeof(SiTableHeaderBase) + HILO(tab->section_length);
+ if (n < l) {
+ Logger()->messagebf(LOG_WARNING, "Received data shorter than its defined length.");
+ continue;
+ }
+ if (n > l) {
+ Logger()->messagebf(LOG_WARNING, "Received data longer than its defined length.");
+ continue;
+ }
+ if (!crc32(buf)) {
+ Logger()->messagebf(LOG_WARNING, "Received data is corrupted (crc32 failed).");
+ continue;
+ }
+
+ asyncs.push_back(client->begin_NewData(buf));
+
+ asyncs.erase(std::remove_if(asyncs.begin(), asyncs.end(), [&exitFlag, &client](const Ice::AsyncResultPtr & a) {
+ if (a->isCompleted()) {
+ exitFlag = client->end_NewData(a);
+ return true;
+ }
+ return false;
+ }), asyncs.end());
+ } while (!exitFlag);
+ BOOST_FOREACH(const auto & a, asyncs) {
+ client->end_NewData(a);
+ }
+ Logger()->messagebf(LOG_DEBUG, "%s: end", __PRETTY_FUNCTION__);
+}
+
+int
+Tuner::StartSendingTS(const P2PVR::PacketIds & pids, const P2PVR::RawDataClientPrx & client, const Ice::Current &)
+{
+ Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__);
+ if (pids.empty()) {
+ throw P2PVR::DeviceError("demux", "Packet Id list cannot be empty", 0);
+ }
+
+ std::lock_guard<std::mutex> g(lock);
+ int demux = backgroundClients.insert(BackgroundClients::value_type(OpenDemux(), client)).first->first;
+
+ struct dmx_pes_filter_params pesFilterParams;
+ memset(&pesFilterParams, 0, sizeof(struct dmx_pes_filter_params));
+ Logger()->messagebf(LOG_ERR, "%s: DMX_SET_PES_FILTER for pid %d", __PRETTY_FUNCTION__, pids[0]);
+ pesFilterParams.pid = pids[0];
+ pesFilterParams.input = DMX_IN_FRONTEND;
+ pesFilterParams.output = DMX_OUT_TSDEMUX_TAP;
+ pesFilterParams.pes_type = DMX_PES_OTHER;
+ pesFilterParams.flags = 0;
+
+ if (ioctl(demux, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
+ backgroundClients.erase(demux);
+ Logger()->messagebf(LOG_ERR, "%s: DMX_SET_PES_FILTER failed (%d: %s)", __PRETTY_FUNCTION__, errno, strerror(errno));
+ throw P2PVR::DeviceError("demux", strerror(errno), errno);
+ }
+
+ for (unsigned int x = 1; x < pids.size(); x += 1) {
+ __u16 p = pids[x];
+ Logger()->messagebf(LOG_ERR, "%s: DMX_ADD_PID for pid %d", __PRETTY_FUNCTION__, p);
+ if (ioctl(demux, DMX_ADD_PID, &p) < 0) {
+ backgroundClients.erase(demux);
+ Logger()->messagebf(LOG_ERR, "%s: DMX_ADD_PID failed (%d: %s)", __PRETTY_FUNCTION__, errno, strerror(errno));
+ throw P2PVR::DeviceError("demux", strerror(errno), errno);
+ }
+ }
+
+ if (ioctl(demux, DMX_START) < 0) {
+ backgroundClients.erase(demux);
+ Logger()->messagebf(LOG_ERR, "%s: DMX_START failed (%d: %s)", __PRETTY_FUNCTION__, errno, strerror(errno));
+ throw P2PVR::DeviceError("demux", strerror(errno), errno);
+ }
+
+ startSenderThread();
+ return demux;
+}
+
+void
+Tuner::StopSendingTS(int handle, const Ice::Current &)
+{
+ Logger()->message(LOG_DEBUG, __PRETTY_FUNCTION__);
+ std::lock_guard<std::mutex> g(lock);
+ if (backgroundClients.find(handle) != backgroundClients.end()) {
+ close(handle);
+ backgroundClients.erase(handle);
+ }
+}
+
+void
+Tuner::startSenderThread()
+{
+ if (!backgroundThread) {
+ backgroundThread = new std::thread(&Tuner::senderThread, this);
+ }
+}
+
+void
+Tuner::senderThread()
+{
+ lock.lock();
+ typedef boost::tuple<P2PVR::RawDataClientPrx, Ice::AsyncResultPtr, int> AsyncCall;
+ std::vector<AsyncCall> asyncs;
+ while (!backgroundClients.empty()) {
+ int n = backgroundClients.rbegin()->first + 1;
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ BOOST_FOREACH(const auto & c, backgroundClients) {
+ FD_SET(c.first, &rfds);
+ }
+ lock.unlock();
+
+ struct timeval tv { 2, 0 };
+ switch (select(n, &rfds, NULL, NULL, &tv)) {
+ case -1: // error
+ case 0: // nothing to read, but all is well
+ break;
+ default:
+ { // stuff to do
+ std::lock_guard<std::mutex> g(lock);
+ BOOST_FOREACH(const auto & c, backgroundClients) {
+ if (FD_ISSET(c.first, &rfds)) {
+ // Read it
+ P2PVR::Data buf(1 << 16);
+ int nr = read(c.first, &buf.front(), buf.size());
+ if (nr < 0) {
+ close(c.first);
+ backgroundClients.erase(c.first);
+ break; // backgroundClients has changed, bailout and start again
+ }
+ size_t n = nr;
+ buf.resize(n);
+ // Send it
+ asyncs.push_back(AsyncCall(c.second, c.second->begin_NewData(buf), c.first));
+ //c.second->NewData(buf);
+ }
+ }
+ }
+ break;
+ }
+ // Clean up finished async requests
+ asyncs.erase(std::remove_if(asyncs.begin(), asyncs.end(), [this](const AsyncCall & a) {
+ try {
+ if (a.get<1>()->isCompleted()) {
+ if (!a.get<0>()->end_NewData(a.get<1>())) {
+ close(a.get<2>());
+ std::lock_guard<std::mutex> g(lock);
+ backgroundClients.erase(a.get<2>());
+ }
+ return true;
+ }
+ return false;
+ }
+ catch (...) {
+ close(a.get<2>());
+ std::lock_guard<std::mutex> g(lock);
+ backgroundClients.erase(a.get<2>());
+ return true;
+ }
+ }), asyncs.end());
+ lock.lock();
+ }
+ Logger()->messagebf(LOG_DEBUG, "%s: Cleaning up", __PRETTY_FUNCTION__);
+ BOOST_FOREACH(const auto & a, asyncs) {
+ try {
+ a.get<0>()->end_NewData(a.get<1>());
+ }
+ catch (...) {
+ }
+ }
+ backgroundThread = NULL;
+ Logger()->messagebf(LOG_DEBUG, "%s: Unlocking", __PRETTY_FUNCTION__);
+ lock.unlock();
+}
+
+bool
+Tuner::crc32(const P2PVR::Data & buf)
+{
+ boost::crc_optimal<32, 0x0, 0xFFFFFFFF, 0x0, true, false> crc;
+ crc.process_bytes(&buf.front(), buf.size());
+ return crc.checksum() == 0;
+}
+
diff --git a/p2pvr/lib/tuner.h b/p2pvr/lib/tuner.h
new file mode 100644
index 0000000..8111f1e
--- /dev/null
+++ b/p2pvr/lib/tuner.h
@@ -0,0 +1,50 @@
+#ifndef P2PVR_TUNER_H
+#define P2PVR_TUNER_H
+
+#include <p2pvr.h>
+#include <boost/filesystem/path.hpp>
+#include "frontend.h"
+#include <map>
+#include <thread>
+#include <mutex>
+#include <boost/bind.hpp>
+
+class Tuner : public P2PVR::PrivateTuner {
+ public:
+ Tuner(const boost::filesystem::path & deviceFrontend);
+ ~Tuner();
+
+ void TuneTo(const DVBSI::DeliveryPtr &, const Ice::Current&);
+ int GetStatus(const Ice::Current&);
+ std::string Device() const;
+
+ void ScanAndSendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current&);
+ void SendNetworkInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current&);
+ void SendBouquetAssociations(const P2PVR::RawDataClientPrx & client, const Ice::Current&);
+ void SendServiceDescriptions(const P2PVR::RawDataClientPrx & client, const Ice::Current&);
+ void SendEventInformation(const P2PVR::RawDataClientPrx & client, const Ice::Current&);
+
+ int StartSendingTS(const P2PVR::PacketIds & pids, const P2PVR::RawDataClientPrx & client, const Ice::Current &);
+ void StopSendingTS(int handle, const Ice::Current &);
+
+ private:
+ static bool crc32(const P2PVR::Data &);
+ int OpenDemux() const;
+ void SendPID(int pid, const P2PVR::RawDataClientPrx & client, const Ice::Current &) const;
+ void ReadDemuxAndSend(int fd, const P2PVR::RawDataClientPrx & client) const;
+ void startSenderThread();
+ void senderThread();
+
+ const boost::filesystem::path deviceFrontend;
+ const boost::filesystem::path deviceRoot;
+ const int timeout;
+ typedef std::map<int, P2PVR::RawDataClientPrx> BackgroundClients;
+ BackgroundClients backgroundClients;
+ std::thread * backgroundThread;
+ std::mutex lock;
+
+ FrontendPtr frontend;
+};
+
+#endif
+
diff --git a/p2pvr/scanner/Jamfile.jam b/p2pvr/scanner/Jamfile.jam
deleted file mode 100644
index 768e86c..0000000
--- a/p2pvr/scanner/Jamfile.jam
+++ /dev/null
@@ -1,17 +0,0 @@
-alias glibmm : : : :
- <cflags>"`pkg-config --cflags glibmm-2.4`"
- <linkflags>"`pkg-config --libs glibmm-2.4`"
- ;
-project
- : requirements
- <variant>debug:<linkflags>-Wl,-z,defs <cflags>"-W -Wall -Werror -Wwrite-strings"
- ;
-
-# Scanner - t
-lib p2pvrscanner :
- [ glob *.cpp ]
- :
- <library>../../project2/common//p2common
- <library>glibmm
- ;
-
diff --git a/p2pvr/scanner/dvbSiReaderHelper.cpp b/p2pvr/scanner/dvbSiReaderHelper.cpp
deleted file mode 100644
index 88b025d..0000000
--- a/p2pvr/scanner/dvbSiReaderHelper.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-#include "dvbSiReaderHelper.h"
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdio.h>
-#include <glibmm.h>
-#include <sys/poll.h>
-#include "si_tables.h"
-#include <boost/crc.hpp>
-
-SimpleMessageException(ErrorReadingData);
-SimpleMessageException(TimeoutReadingData);
-SimpleMessageException(DemuxOpenFailure);
-
-const std::string DvbSiParserHelper::ISO10646("ISO-10646");
-const std::string DvbSiParserHelper::EitEncoding("ISO6937");
-const std::string DvbSiParserHelper::UTF8("UTF8");
-
-DvbSiReaderHelper::DvbSiReaderHelper(const ScriptNodePtr p) :
- demux(p, "demux", "/dev/dvb/adapter0/demux0"),
- timeout(p, "timeout", 10000),
- fd_epg(0)
-{
-}
-
-DvbSiReaderHelper::~DvbSiReaderHelper()
-{
- closeInput();
-}
-
-void
-DvbSiReaderHelper::openInput(ExecContext * ec) const
-{
- if ((fd_epg = open(demux(ec), O_RDWR)) < 0) {
- throw DemuxOpenFailure(strerror(errno));
- }
- filterInput(fd_epg);
-}
-
-void
-DvbSiReaderHelper::closeInput() const
-{
- if (fd_epg) {
- close(fd_epg);
- fd_epg = 0;
- }
-}
-
-DvbSiParserHelper::StrPtr
-DvbSiParserHelper::convert(const char * txt, size_t len)
-{
- if (len == 0) {
- return boost::shared_ptr<Glib::ustring>(new Glib::ustring());
- }
- char enc[20];
- switch (*txt) {
- default:
- EitEncoding.copy(enc, EitEncoding.length());
- enc[EitEncoding.length()] = '\0';
- break;
- case 0x01 ... 0x05:
- snprintf(enc, sizeof(enc), "ISO-8859-%d\n", txt[0] + 4);
- txt += 1;
- len -= 1;
- break;
- case 0x10:
- snprintf(enc, sizeof(enc), "ISO-8859-%02x%02x\n", txt[1], txt[2]);
- txt += 3;
- len -= 3;
- break;
- case 0x11:
- ISO10646.copy(enc, ISO10646.length());
- enc[ISO10646.length()] = '\0';
- break;
- case 0x1F:
- // Values for the first byte of "0x00", "0x06" to "0x0F", and "0x12" to "0x1F" are reserved for future use.
- //fprintf(stderr, "Reserved encoding: %02x\n", txt[0]);
- //fprintf(stderr, "%d: %.*s\n", txt[1], len - 2, txt + 2);
- case 0x06 ... 0x0F:
- case 0x12 ... 0x1E:
- case 0x00: // empty string
- return boost::shared_ptr<Glib::ustring>(new Glib::ustring());
- }
- size_t used = 0, newlen = 0;
- GError * err = NULL;
- boost::shared_ptr<gchar> utf8 = boost::shared_ptr<gchar>(g_convert(txt, len, "utf-8", enc, &used, &newlen, &err), g_free);
- if (err) {
- throw Glib::ConvertError(err);
- }
- return boost::shared_ptr<Glib::ustring>(new Glib::ustring(utf8.get()));
-}
-
-bool
-_dvb_crc32(void * buf, size_t len)
-{
- boost::crc_optimal<32, 0x0, 0xFFFFFFFF, 0x0, true, false> crc;
- crc.process_bytes(buf, len);
- return crc.checksum() == 0;
-}
-
-void
-DvbSiReaderHelper::readTables(const InfoTableParser & parseInfoTable) const
-{
- u_char buf[1<<12];
- struct pollfd ufd;
- memset(&ufd, 0, sizeof(pollfd));
- ufd.fd = fd_epg;
- ufd.events = POLLIN;
- size_t n;
- int prtn = 0;
- time_t lastuseful = time(NULL);
- while (((prtn = poll(&ufd, 1, timeout(NULL))) == 1) && (n = read(fd_epg, buf, sizeof(buf)))) {
- if (n < sizeof(struct si_tab))
- throw ErrorReadingData("Smaller that si_tab");
- struct si_tab *tab = (struct si_tab *)buf;
- size_t l = sizeof(struct si_tab) + GetSectionLength(tab);
- if (n < l)
- throw ErrorReadingData("Smaller that section length");
- if (_dvb_crc32(buf, l)) {
- if (parseInfoTable(buf, l)) {
- time(&lastuseful);
- }
- else {
- if (lastuseful < time(NULL) - 15) {
- break;
- }
- }
- }
- }
- if (prtn < 1) {
- throw TimeoutReadingData("Tuned to a multiplex?");
- }
-}
diff --git a/p2pvr/scanner/dvbSiReaderHelper.h b/p2pvr/scanner/dvbSiReaderHelper.h
deleted file mode 100644
index d0080f1..0000000
--- a/p2pvr/scanner/dvbSiReaderHelper.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef DVBSIREADERHELPER_H
-#define DVBSIREADERHELPER_H
-
-#include "scripts.h"
-#include "variables.h"
-#include <boost/function.hpp>
-
-class RowProcessor;
-
-class DvbSiReaderHelper {
- public:
- typedef boost::function<bool (const u_char *, size_t)> InfoTableParser;
-
- DvbSiReaderHelper(const ScriptNodePtr p);
- ~DvbSiReaderHelper();
-
- const Variable demux;
- const Variable timeout;
-
- protected:
- void openInput(ExecContext *) const;
- virtual void filterInput(int fd) const = 0;
- void readTables(const InfoTableParser &) const;
- void closeInput() const;
-
- private:
- mutable int fd_epg;
-};
-
-class DvbSiParserHelper {
- protected:
- typedef boost::shared_ptr<Glib::ustring> StrPtr;
- static StrPtr convert(const char * txt, size_t len);
- static const std::string ISO10646;
- static const std::string EitEncoding;
- static const std::string UTF8;
-};
-
-#endif
-
diff --git a/p2pvr/scanner/epgRows.cpp b/p2pvr/scanner/epgRows.cpp
deleted file mode 100644
index e27769d..0000000
--- a/p2pvr/scanner/epgRows.cpp
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * tv_grab_dvb - dump dvb epg info in xmltv
- * Version 0.2 - 20/04/2004 - First Public Release
- *
- * Copyright (C) 2004 Mark Bryars <dvb at darkskiez d0t co d0t uk>
- *
- * DVB code Mercilessly ripped off from dvddate
- * dvbdate Copyright (C) Laurence Culhane 2002 <dvbdate@holmes.demon.co.uk>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <stdint.h>
-#include <time.h>
-#include <glibmm/regex.h>
-#include <boost/regex.hpp>
-#include <boost/bind.hpp>
-#include <boost/date_time/gregorian_calendar.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/algorithm/string/trim.hpp>
-#include <boost/foreach.hpp>
-#include <boost/lexical_cast.hpp>
-
-#include <linux/dvb/dmx.h>
-#include "si_tables.h"
-
-#include "rowProcessor.h"
-#include "epgRows.h"
-#include <boost/tuple/tuple_comparison.hpp>
-
-struct EpgProgram {
- VariableType serviceID;
- VariableType eventID;
- VariableType title;
- VariableType titleLang;
- VariableType subtitle;
- VariableType descLang;
- VariableType desc1;
- VariableType desc2;
- VariableType desc3;
- VariableType videoAspect;
- VariableType videoFrameRate;
- VariableType videoHD;
- VariableType audioChannels;
- VariableType language;
- VariableType teletextSubtitleLang;
- VariableType category;
- VariableType dvbRating;
- VariableType contentItemID;
- VariableType contentSeriesID;
- VariableType contentRecommendation;
- VariableType startTime;
- VariableType stopTime;
- VariableType episode;
- VariableType episodes;
- VariableType year;
- VariableType flags;
-};
-
-static Glib::ustring title("title");
-template <class C, class M>
-const M &
-getMember(M C::*t, C * p) {
- return p->*t;
-}
-SimpleMessageException(NoSuchAttribute);
-
-void
-EpgRows::loadComplete(const CommonObjects *)
-{
-}
-
-EpgRowState::EpgRowState() :
- current(NULL)
-{
-}
-
-const Columns &
-EpgRowState::getColumns() const
-{
- return columns;
-}
-
-#define returnAttr(name) if (attrName == #name) return boost::bind(getMember<EpgProgram, VariableType>, &EpgProgram::name, boost::ref(current))
-RowState::RowAttribute
-EpgRowState::resolveAttr(const Glib::ustring & attrName) const {
- returnAttr(serviceID);
- returnAttr(eventID);
- returnAttr(title);
- returnAttr(titleLang);
- returnAttr(subtitle);
- returnAttr(descLang);
- returnAttr(desc1);
- returnAttr(desc2);
- returnAttr(desc3);
- returnAttr(videoAspect);
- returnAttr(videoFrameRate);
- returnAttr(videoHD);
- returnAttr(audioChannels);
- returnAttr(language);
- returnAttr(teletextSubtitleLang);
- returnAttr(category);
- returnAttr(dvbRating);
- returnAttr(contentItemID);
- returnAttr(contentSeriesID);
- returnAttr(contentRecommendation);
- returnAttr(startTime);
- returnAttr(stopTime);
- returnAttr(episode);
- returnAttr(episodes);
- returnAttr(year);
- returnAttr(flags);
- throw NoSuchAttribute(attrName);
-}
-
-DECLARE_LOADER("epgrows", EpgRows);
-
-EpgRows::EpgRows(const ScriptNodePtr p) :
- RowSet(p),
- DvbSiReaderHelper(p)
-{
-}
-
-EpgRows::~EpgRows()
-{
-}
-
-static int time_offset = 0;
-static int chan_filter = 0;
-static int chan_filter_mask = 0;
-static Glib::RefPtr<Glib::Regex> episodeRegex = Glib::Regex::create("[ (]+(?:\\w+ )?([0-9]+)(?: of |/)([0-9]+)[.)]+");
-static Glib::RefPtr<Glib::Regex> yearRegex = Glib::Regex::create("\\(([0-9]{4})[ )]+");
-static Glib::RefPtr<Glib::Regex> flagsRegex = Glib::Regex::create("[ []+([A-Z,]+)\\]");
-
-void
-EpgRowState::parseEventDescription(const u_char * data, EpgProgram * current) const {
- assert(GetDescriptorTag(data) == 0x4D);
- const struct descr_short_event *evtdesc = reinterpret_cast<const struct descr_short_event *>(data);
-
- size_t evtlen = evtdesc->event_name_length;
- StrPtr title, subtitle, desc;
- if (evtlen) {
- current->titleLang = Glib::ustring((const char *)&evtdesc->lang_code1, 3);
- title = convert((const char *)evtdesc->data, evtlen);
- }
-
- size_t dsclen = evtdesc->data[evtlen];
- if (dsclen) {
- subtitle = convert((const char *)evtdesc->data + evtlen + 1, dsclen);
- }
- if (subtitle) {
- Glib::MatchInfo matches;
- if (episodeRegex->match(*subtitle, matches)) {
- current->episode = boost::lexical_cast<int>(matches.fetch(1));
- current->episodes = boost::lexical_cast<int>(matches.fetch(2));
- *subtitle = episodeRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY);
- }
- if (yearRegex->match(*subtitle, matches)) {
- current->year = boost::lexical_cast<int>(matches.fetch(1));
- *subtitle = yearRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY);
- }
- if (flagsRegex->match(*subtitle, matches)) {
- current->flags = matches.fetch(1);
- *subtitle = yearRegex->replace_literal(*subtitle, 0, "", Glib::REGEX_MATCH_NOTEMPTY);
- }
- }
- if (title && subtitle) {
- if (boost::algorithm::ends_with(*title, "...") && boost::algorithm::starts_with(*subtitle, "...")) {
- title->resize(title->length() - 3);
- *title += " ";
- size_t dot = subtitle->find('.', 4);
- if (dot == Glib::ustring::npos) {
- title->append(*subtitle, 3, subtitle->length() - 3);
- }
- else {
- title->append(*subtitle, 3, dot - 3);
- subtitle->erase(0, dot + 2);
- }
- }
- size_t colon = subtitle->find(':');
- if (colon != Glib::ustring::npos) {
- desc = StrPtr(new Glib::ustring(*subtitle, colon + 1, subtitle->length() - colon));
- subtitle->resize(colon);
- }
- else {
- colon = title->find(':');
- desc = subtitle;
- if (colon != Glib::ustring::npos) {
- subtitle = StrPtr(new Glib::ustring(*title, colon + 1, title->length() - colon));
- title->resize(colon);
- }
- else {
- subtitle.reset();
- }
- }
- }
- if (title) {
- boost::algorithm::trim_if(*title, isspace);
- current->title = *title;
- }
- if (subtitle) {
- boost::algorithm::trim_if(*subtitle, isspace);
- if (!subtitle->empty()) {
- current->subtitle = *subtitle;
- }
- }
- if (desc) {
- boost::algorithm::trim_if(*desc, isspace);
- if (!desc->empty()) {
- current->desc1 = *desc;
- }
- }
-}
-
-/* Parse 0x4E Extended Event Descriptor. {{{ */
-void
-EpgRowState::parseLongEventDescription(const u_char * data, EpgProgram * current) const {
- assert(GetDescriptorTag(data) == 0x4E);
- const struct descr_extended_event *levt = reinterpret_cast<const struct descr_extended_event *>(data);
- bool non_empty = (levt->descriptor_number || levt->last_descriptor_number || levt->length_of_items || levt->data[0]);
-
- if (non_empty && levt->descriptor_number == 0) {
- current->descLang = Glib::ustring((const char *)&levt->lang_code1, 3);
-
- const u_char *p = reinterpret_cast<const u_char *>(&levt->data);
-#ifndef NDEBUG
- const void *data_end = data + DESCR_GEN_LEN + GetDescriptorLength(data);
-#endif
- while (p < levt->data + levt->length_of_items) {
- const struct item_extended_event *name = reinterpret_cast<const struct item_extended_event *>(p);
- size_t name_len = name->item_description_length;
- assert(p + ITEM_EXTENDED_EVENT_LEN + name_len < data_end);
- current->desc1 = *convert((const char *)name->data, name_len);
-
- p += ITEM_EXTENDED_EVENT_LEN + name_len;
-
- const struct item_extended_event *value = reinterpret_cast<const struct item_extended_event *>(p);
- size_t value_len = value->item_description_length;
- assert(p + ITEM_EXTENDED_EVENT_LEN + value_len < data_end);
- current->desc2 = *convert((const char *)value->data, value_len);
-
- p += ITEM_EXTENDED_EVENT_LEN + value_len;
- }
- const struct item_extended_event *text = reinterpret_cast<const struct item_extended_event *>(p);
- size_t len = text->item_description_length;
- if (non_empty && len) {
- current->desc3 = *convert((const char *)text->data, len);
- }
-
- }
-} /*}}}*/
-
-/* Parse 0x50 Component Descriptor. {{{
- video is a flag, 1=> output the video information, 0=> output the
- audio information. seen is a pointer to a counter to ensure we
- only output the first one of each (XMLTV can't cope with more than
- one) */
-void
-EpgRowState::parseComponentDescription(const u_char * data, EpgProgram * current) const {
- assert(GetDescriptorTag(data) == 0x50);
- const struct descr_component *dc = reinterpret_cast<const struct descr_component *>(data);
-
- switch (dc->stream_content) {
- case 0x01: // Video Info
- current->videoHD = ((dc->component_type - 1) & 0x08) ? 1 : 0;
- current->videoFrameRate = ((dc->component_type - 1) & 0x04) ? 30 : 25;
- current->videoAspect = ((dc->component_type - 1) & 0x03);
- break;
- case 0x02: // Audio Info
- current->audioChannels = dc->component_type;
- current->language = Glib::ustring((const char *)&dc->lang_code1, 3);
- break;
- case 0x03: // Teletext Info
- // FIXME: is there a suitable XMLTV output for this?
- // if ((dc->component_type)&0x10) //subtitles
- // if ((dc->component_type)&0x20) //subtitles for hard of hearing
- current->teletextSubtitleLang = Glib::ustring((const char *)&dc->lang_code1, 3);
- break;
- // case 0x04: // AC3 info
- }
-} /*}}}*/
-
-void
-EpgRowState::parseContentDescription(const u_char * data, EpgProgram * current) const {
- assert(GetDescriptorTag(data) == 0x54);
- const struct descr_content * dc = reinterpret_cast<const struct descr_content *>(data);
- for (const u_char * p = reinterpret_cast<const u_char*>(&dc->data); p < data + DESCR_GEN_LEN + dc->descriptor_length; p += NIBBLE_CONTENT_LEN) {
- const struct nibble_content *nc = reinterpret_cast<const nibble_content *>(p);
- int c1 = (nc->content_nibble_level_1 << 4) + nc->content_nibble_level_2;
- // This is weird in the uk, they use user but not content, and almost the same values
- current->category = c1 ? c1 : (nc->user_nibble_1 << 4) + nc->user_nibble_2;
- }
-}
-
-void
-EpgRowState::parseRatingDescription(const u_char * data, EpgProgram * current) const {
- assert(GetDescriptorTag(data) == 0x55);
- const struct descr_parental_rating * pr = reinterpret_cast<const struct descr_parental_rating *>(data);
- for (const u_char * p = reinterpret_cast<const u_char *>(&pr->data); p < data + DESCR_GEN_LEN + pr->descriptor_length; p += PARENTAL_RATING_ITEM_LEN) {
- const struct parental_rating_item *pr = reinterpret_cast<const struct parental_rating_item *>(p);
- switch (pr->rating) {
- case 0x00: /*undefined*/
- break;
- case 0x01 ... 0x0F:
- current->dvbRating = pr->rating + 3;
- break;
- case 0x10 ... 0xFF: /*broadcaster defined*/
- break;
- }
- }
-}
-
-int parsePrivateDataSpecifier(const u_char *data) {
- assert(GetDescriptorTag(data) == 0x5F);
- return GetPrivateDataSpecifier(data);
-}
-
-/* Parse 0x76 Content Identifier Descriptor. {{{ */
-/* See ETSI TS 102 323, section 12 */
-void
-EpgRowState::parseContentIdentifierDescription(const u_char * data, EpgProgram * current) const {
- assert(GetDescriptorTag(data) == 0x76);
- const struct descr_content_identifier *ci = reinterpret_cast<const struct descr_content_identifier *>(data);
- for (const u_char * p = reinterpret_cast<const u_char *>(&ci->data); p < data + DESCR_GEN_LEN + ci->descriptor_length; p += DESCR_GEN_LEN + ci->descriptor_length) {
- const struct descr_content_identifier_crid *crid = reinterpret_cast<const struct descr_content_identifier_crid *>(p);
-
- switch (crid->crid_location)
- {
- case 0x01: /* Carried in Content Identifier Table (CIT) */
- default:
- break;
- case 0x00: /* Carried explicitly within descriptor */
- struct descr_content_identifier_crid_local * crid_data = (descr_content_identifier_crid_local_t *)&crid->crid_ref_data;
- size_t len = crid_data->crid_length;
- switch (crid->crid_type) {
- case 0x01:
- case 0x31:
- current->contentItemID = Glib::ustring((const char *)crid_data->crid_byte, len);
- break;
- case 0x02:
- case 0x32:
- current->contentSeriesID = Glib::ustring((const char *)crid_data->crid_byte, len);
- break;
- case 0x03:
- case 0x33:
- current->contentRecommendation = Glib::ustring((const char *)crid_data->crid_byte, len);
- break;
- }
- break;
- }
- }
-} /*}}}*/
-
-/* Parse Descriptor. {{{
- * Tags should be output in this order:
-
-'title', 'sub-title', 'desc', 'credits', 'date', 'category', 'language',
-'orig-language', 'length', 'icon', 'url', 'country', 'episode-num',
-'video', 'audio', 'previously-shown', 'premiere', 'last-chance',
-'new', 'subtitles', 'rating', 'star-rating'
-*/
-void
-EpgRowState::parseDescription(const u_char * data, size_t len, EpgProgram * current) const {
- int pds = 0;
- for (const u_char * p = data; p < data + len; p += DESCR_GEN_LEN + GetDescriptorLength(p)) {
- const struct descr_gen *desc = reinterpret_cast<const struct descr_gen *>(p);
- switch (GetDescriptorTag(desc)) {
- case 0:
- break;
- case 0x4D: //short evt desc, [title] [sub-title]
- // there can be multiple language versions of these
- parseEventDescription(p, current);
- break;
- case 0x4E: //long evt descriptor [desc]
- parseLongEventDescription(p, current);
- break;
- case 0x50: //component desc [language] [video] [audio] [subtitles]
- parseComponentDescription(p, current);
- break;
- case 0x53: // CA Identifier Descriptor
- break;
- case 0x54: // content desc [category]
- parseContentDescription(p, current);
- break;
- case 0x55: // Parental Rating Descriptor [rating]
- parseRatingDescription(p, current);
- break;
- case 0x5f: // Private Data Specifier
- pds = parsePrivateDataSpecifier(p);
- break;
- case 0x64: // Data broadcast desc - Text Desc for Data components
- break;
- case 0x69: // Programm Identification Label
- break;
- case 0x81: // TODO ???
- if (pds == 5) // ARD_ZDF_ORF
- break;
- case 0x82: // VPS (ARD, ZDF, ORF)
- if (pds == 5) // ARD_ZDF_ORF
- // TODO: <programme @vps-start="???">
- break;
- case 0x4F: // Time Shifted Event
- case 0x52: // Stream Identifier Descriptor
- case 0x5E: // Multi Lingual Component Descriptor
- case 0x83: // Logical Channel Descriptor (some kind of news-ticker on ARD-MHP-Data?)
- case 0x84: // Preferred Name List Descriptor
- case 0x85: // Preferred Name Identifier Descriptor
- case 0x86: // Eacem Stream Identifier Descriptor
- break;
- case 0x76: // Content identifier descriptor
- parseContentIdentifierDescription(p, current);
- break;
- default:
- break;
- }
- }
-} /*}}}*/
-
-/* Check that program has at least a title as is required by xmltv.dtd. {{{ */
-static bool validateDescription(const u_char *data, size_t len) {
- for (const u_char * p = data; p < data + len; p += DESCR_GEN_LEN + GetDescriptorLength(p)) {
- const struct descr_gen *desc = reinterpret_cast<const struct descr_gen *>(p);
- if (GetDescriptorTag(desc) == 0x4D) {
- const struct descr_short_event *evtdesc = reinterpret_cast<const struct descr_short_event *>(p);
- // make sure that title isn't empty
- if (evtdesc->event_name_length) return true;
- }
- }
- return false;
-} /*}}}*/
-
-bool
-EpgRowState::parseInfoTable(const u_char *data, size_t len, const RowProcessorCallback & rp) {
- const struct eit *e = reinterpret_cast<const struct eit *>(data);
-
- len -= 4; //remove CRC
-
- // For each event listing
- bool found = false;
- for (const u_char *p = reinterpret_cast<const u_char *>(&e->data); p < data + len; p += EIT_EVENT_LEN + GetEITDescriptorsLoopLength(p)) {
- const struct eit_event *evt = reinterpret_cast<const struct eit_event *>(p);
- SeenProgram sp(HILO(e->service_id), HILO(evt->event_id));
- if (seenPrograms.find(sp) != seenPrograms.end()) {
- continue;
- }
- seenPrograms.insert(sp);
-
- // No program info at end! Just skip it
- if (GetEITDescriptorsLoopLength(evt) == 0) {
- continue;
- }
-
- boost::gregorian::date startDate(boost::gregorian::gregorian_calendar::from_modjulian_day_number(HILO(evt->mjd)));
- boost::posix_time::ptime startTime(startDate);
- startTime += boost::posix_time::time_duration(
- BcdCharToInt(evt->start_time_h) + time_offset,
- BcdCharToInt(evt->start_time_m),
- BcdCharToInt(evt->start_time_s));
- EpgProgram results;
- current = &results;
- results.startTime = startTime;
- results.stopTime = startTime + boost::posix_time::time_duration(
- BcdCharToInt(evt->duration_h),
- BcdCharToInt(evt->duration_m),
- BcdCharToInt(evt->duration_s));
-
- // a program must have a title that isn't empty
- if (!validateDescription(reinterpret_cast<const u_char *>(&evt->data), GetEITDescriptorsLoopLength(evt))) {
- continue;
- }
-
-
- results.serviceID = HILO(e->service_id);
- results.eventID = HILO(evt->event_id);
-
- parseDescription(reinterpret_cast<const u_char *>(&evt->data), GetEITDescriptorsLoopLength(evt), &results);
- process(rp);
- found = true;
- }
- return found;
-}
-
-SimpleMessageException(DemuxSetFilterFailure);
-
-void
-EpgRows::filterInput(int fd) const
-{
- struct dmx_sct_filter_params sctFilterParams;
- memset(&sctFilterParams, 0, sizeof(dmx_sct_filter_params));
- sctFilterParams.pid = 0x12; // EIT data
- sctFilterParams.timeout = 0;
- sctFilterParams.flags = DMX_IMMEDIATE_START;
- sctFilterParams.filter.filter[0] = chan_filter; // 4e is now/next this multiplex, 4f others
- sctFilterParams.filter.mask[0] = chan_filter_mask;
-
- if (ioctl(fd, DMX_SET_FILTER, &sctFilterParams) < 0) {
- throw DemuxSetFilterFailure(strerror(errno));
- }
-}
-
-void
-EpgRows::execute(const Glib::ustring &, const RowProcessorCallback & rp, ExecContext * ec) const
-{
- EpgRowState state;
- openInput(ec);
- readTables(boost::bind(&EpgRowState::parseInfoTable, &state, _1, _2, rp));
- closeInput();
-}
-
diff --git a/p2pvr/scanner/epgRows.h b/p2pvr/scanner/epgRows.h
deleted file mode 100644
index 61c55ff..0000000
--- a/p2pvr/scanner/epgRows.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef EPGROWS_H
-#define EPGROWS_H
-
-#include "scripts.h"
-#include "rowSet.h"
-#include "variables.h"
-#include "dvbSiReaderHelper.h"
-#include <boost/tuple/tuple.hpp>
-
-class EpgProgram;
-
-class EpgRows : public RowSet, DvbSiReaderHelper {
- public:
- EpgRows(const ScriptNodePtr p);
- ~EpgRows();
-
- void execute(const Glib::ustring &, const RowProcessorCallback &, ExecContext *) const;
- void loadComplete(const CommonObjects *);
-
- private:
- void filterInput(int fd) const;
-};
-
-class EpgRowState : public RowState, DvbSiParserHelper {
- public:
- EpgRowState();
- const Columns & getColumns() const;
- RowAttribute resolveAttr(const Glib::ustring & attrName) const;
-
- bool parseInfoTable(const u_char *data, size_t len, const RowProcessorCallback &);
-
- private:
- void parseEventDescription(const u_char *data, EpgProgram * current) const;
- void parseLongEventDescription(const u_char *data, EpgProgram * current) const;
- void parseComponentDescription(const u_char *data, EpgProgram * current) const;
- void parseContentDescription(const u_char *data, EpgProgram * current) const;
- void parseRatingDescription(const u_char *data, EpgProgram * current) const;
- void parseContentIdentifierDescription(const u_char *data, EpgProgram * current) const;
- void parseDescription(const u_char * data, size_t len, EpgProgram * current) const;
-
- typedef boost::tuple<int, int> SeenProgram;
- typedef std::set<SeenProgram> SeenPrograms;
- SeenPrograms seenPrograms;
-
- Columns columns;
- friend class EpgRows;
- mutable EpgProgram * current;
-};
-
-
-#endif
-
diff --git a/p2pvr/scanner/serviceRows.cpp b/p2pvr/scanner/serviceRows.cpp
deleted file mode 100644
index e743858..0000000
--- a/p2pvr/scanner/serviceRows.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <stdint.h>
-#include <time.h>
-#include <boost/bind.hpp>
-#include <boost/date_time/gregorian_calendar.hpp>
-
-#include <linux/dvb/dmx.h>
-#include "si_tables.h"
-
-#include "rowProcessor.h"
-#include "serviceRows.h"
-
-class Service {
- public:
- VariableType serviceID;
- VariableType name;
- VariableType type;
- VariableType providerName;
- VariableType defaultAuthority;
- VariableType transportID;
-};
-
-void
-ServiceRows::loadComplete(const CommonObjects *)
-{
-}
-
-ServiceRowState::ServiceRowState() :
- current(NULL)
-{
-}
-
-const Columns &
-ServiceRowState::getColumns() const
-{
- return columns;
-}
-
-SimpleMessageException(NoSuchAttribute);
-template <class C, class M>
-const M &
-getMember(M C::*t, C * p) {
- return p->*t;
-}
-#define returnAttr(name) if (attrName == #name) return boost::bind(getMember<Service, VariableType>, &Service::name, boost::ref(current))
-RowState::RowAttribute
-ServiceRowState::resolveAttr(const Glib::ustring & attrName) const {
- returnAttr(serviceID);
- returnAttr(name);
- returnAttr(type);
- returnAttr(providerName);
- returnAttr(defaultAuthority);
- returnAttr(transportID);
- throw NoSuchAttribute(attrName);
-}
-
-DECLARE_LOADER("servicerows", ServiceRows);
-
-ServiceRows::ServiceRows(const ScriptNodePtr e) :
- RowSet(e),
- DvbSiReaderHelper(e)
-{
-}
-
-ServiceRows::~ServiceRows()
-{
-}
-
-SimpleMessageException(DemuxSetFilterFailure);
-
-void
-ServiceRows::filterInput(int fd) const
-{
- struct dmx_sct_filter_params sctFilterParams;
- memset(&sctFilterParams, 0, sizeof(dmx_sct_filter_params));
- sctFilterParams.pid = 0x11; // Service data
- sctFilterParams.timeout = 0;
- sctFilterParams.flags = DMX_IMMEDIATE_START;
-
- if (ioctl(fd, DMX_SET_FILTER, &sctFilterParams) < 0) {
- throw DemuxSetFilterFailure(strerror(errno));
- }
-}
-
-void
-ServiceRows::execute(const Glib::ustring &, const RowProcessorCallback & rp, ExecContext * ec) const
-{
- ServiceRowState state;
- openInput(ec);
- readTables(boost::bind(&ServiceRowState::parseInfoTable, &state, _1, _2, rp));
- closeInput();
-}
-
-bool
-ServiceRowState::parseInfoTable(const u_char * data, size_t len, const RowProcessorCallback & rp) {
- const struct sit *e = reinterpret_cast<const struct sit *>(data);
- assert(e->tableid == 0x42 || e->tableid == 0x46);
- len -= 4; //remove CRC
-
- // For each event listing
- bool found = false;
- for (const u_char * p = e->serviceData; p < data + len; ) {
- const struct si * sid = reinterpret_cast<const struct si *>(p);
- int sID = be16toh(sid->serviceid);
- bool seen = (seenServices.find(sID) != seenServices.end());
- size_t dll = HILO(sid->desc_loop_len);
- Service serv;
- current = &serv;
- for (p = sid->descData; p < sid->descData + dll; p += DESCR_GEN_LEN + GetDescriptorLength(p)) {
- if (!seen) {
- serv.serviceID = sID;
- serv.transportID = be16toh(e->transport_stream_id);
- const struct descr_gen *desc = reinterpret_cast<const struct descr_gen *>(p);
- switch (GetDescriptorTag(desc)) {
- case 0x48: // Service descriptor
- parseServiceDescriptor(p, GetDescriptorLength(desc), &serv);
- break;
- case 0x73: // Service authority descriptor
- parseServiceAuthDescriptor(p, GetDescriptorLength(desc), &serv);
- break;
- default:
- break;
- }
- }
- }
- if (!seen) {
- found = true;
- seenServices.insert(sID);
- process(rp);
- }
- }
- return found;
-}
-
-void
-ServiceRowState::parseServiceDescriptor(const u_char * p, size_t, Service * current) const
-{
- current->type = p[2];
- if (p[3]) {
- current->providerName = *convert((const char *)(p + 4), p[3]);
- }
- current->name = *convert((const char *)(p + 5 + p[3]), p[4 + p[3]]);
-}
-
-void
-ServiceRowState::parseServiceAuthDescriptor(const u_char * p, size_t len, Service * current) const
-{
- current->defaultAuthority = *convert((const char *)(p + 2), len);
-}
-
diff --git a/p2pvr/scanner/serviceRows.h b/p2pvr/scanner/serviceRows.h
deleted file mode 100644
index 36cbee7..0000000
--- a/p2pvr/scanner/serviceRows.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef SERVICEROWS_H
-#define SERVICEROWS_H
-
-#include "scripts.h"
-#include "rowSet.h"
-#include "variables.h"
-#include "dvbSiReaderHelper.h"
-
-class Service;
-
-class ServiceRows : public RowSet, DvbSiReaderHelper {
- public:
- ServiceRows(const ScriptNodePtr p);
- ~ServiceRows();
-
- void execute(const Glib::ustring &, const RowProcessorCallback &, ExecContext *) const;
- void loadComplete(const CommonObjects *);
-
- private:
- void filterInput(int fd) const;
-};
-
-class ServiceRowState : public RowState, DvbSiParserHelper {
- public:
- ServiceRowState();
- const Columns & getColumns() const;
- RowAttribute resolveAttr(const Glib::ustring & attrName) const;
- bool parseInfoTable(const u_char *data, size_t len, const RowProcessorCallback &);
-
- private:
- void parseServiceDescriptor(const u_char *data, size_t len, Service * current) const;
- void parseServiceAuthDescriptor(const u_char *data, size_t len, Service * current) const;
-
- typedef std::set<int> SeenServices;
- SeenServices seenServices;
-
- Columns columns;
- friend class ServiceRows;
- mutable Service * current;
-};
-
-#endif
-
diff --git a/p2pvr/scanner/si_tables.h b/p2pvr/scanner/si_tables.h
deleted file mode 100644
index c48fdae..0000000
--- a/p2pvr/scanner/si_tables.h
+++ /dev/null
@@ -1,1667 +0,0 @@
-//////////////////////////////////////////////////////////////
-/// ///
-/// si_tables.h: definitions for data structures of the ///
-/// incoming SI data stream ///
-/// ///
-//////////////////////////////////////////////////////////////
-
-// $Revision: 84 $
-// $Date: 2010-03-05 17:46:16 +0000 (Fri, 05 Mar 2010) $
-// $Author: cpaton $
-//
-// (C) 2001-03 Rolf Hakenes <hakenes@hippomi.de>, under the
-// GNU GPL with contribution of Oleg Assovski,
-// www.satmania.com
-//
-// libsi is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2, or (at your option)
-// any later version.
-//
-// libsi is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You may have received a copy of the GNU General Public License
-// along with libsi; see the file COPYING. If not, write to the
-// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-// Boston, MA 02111-1307, USA.
-
-#include <stdint.h>
-
-#define HILO(x) (x##_hi << 8 | x##_lo)
-#define HILO2(x) (x##1 << 8 | x##2)
-#define HILO3(x) (x##1 << 16 | x##2 << 8 | x##3)
-#define HILO4(x) (x##4 << 24 | x##2 << 16 | x##3 << 8 | x##4)
-
-#define MjdToEpochTime(x) ((HILO(x)-40587)*86400)
-#define BcdTimeToSeconds(x) ((3600 * ((10*((x##_h & 0xF0)>>4)) + (x##_h & 0xF))) + \
- (60 * ((10*((x##_m & 0xF0)>>4)) + (x##_m & 0xF))) + \
- ((10*((x##_s & 0xF0)>>4)) + (x##_s & 0xF)))
-#define BcdTimeToMinutes(x) ((60 * ((10*((x##_h & 0xF0)>>4)) + (x##_h & 0xF))) + \
- (((10*((x##_m & 0xF0)>>4)) + (x##_m & 0xF))))
-#define BcdCharToInt(x) (10*((x & 0xF0)>>4) + (x & 0xF))
-#define CheckBcdChar(x) ((((x & 0xF0)>>4) <= 9) && \
- ((x & 0x0F) <= 9))
-#define CheckBcdSignedChar(x) ((((x & 0xF0)>>4) >= 0) && (((x & 0xF0)>>4) <= 9) && \
- ((x & 0x0F) >= 0) && ((x & 0x0F) <= 9))
-
-#define GetTableId(x) (((si_tab_t *)(x))->table_id)
-#define GetSectionLength(x) HILO(((si_tab_t *)(x))->section_length)
-typedef struct si_tab {
- u_char table_id /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char section_syntax_indicator :1;
- u_char dummy :1; // has to be 0
- u_char :2;
- u_char section_length_hi :4;
-#else
- u_char section_length_hi :4;
- u_char :2;
- u_char dummy :1; // has to be 0
- u_char section_syntax_indicator :1;
-#endif
- u_char section_length_lo /*:8*/;
-} si_tab_t;
-
-/*
- *
- * ETSI ISO/IEC 13818-1 specifies SI which is referred to as PSI. The PSI
- * data provides information to enable automatic configuration of the
- * receiver to demultiplex and decode the various streams of programs
- * within the multiplex. The PSI data is structured as four types of table.
- * The tables are transmitted in sections.
- *
- * 1) Program Association Table (PAT):
- *
- * - for each service in the multiplex, the PAT indicates the location
- * (the Packet Identifier (PID) values of the Transport Stream (TS)
- * packets) of the corresponding Program Map Table (PMT).
- * It also gives the location of the Network Information Table (NIT).
- *
- */
-#define TableHasMoreSections(x) (((pat_t *)(x))->last_section_number > ((pat_t *)(x))->section_number)
-#define GetSectionNumber(x) ((pat_t *)(x))->section_number
-#define GetLastSectionNumber(x) ((pat_t *)(x))->last_section_number
-#define GetServiceId(x) HILO(((eit_t *)(x))->service_id)
-#define GetLastTableId(x) ((eit_t *)(x))->segment_last_table_id
-#define GetSegmentLastSectionNumber(x) ((eit_t *)(x))->segment_last_section_number
-typedef struct pat {
- u_char table_id /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char section_syntax_indicator :1;
- u_char dummy :1; // has to be 0
- u_char :2;
- u_char section_length_hi :4;
-#else
- u_char section_length_hi :4;
- u_char :2;
- u_char dummy :1; // has to be 0
- u_char section_syntax_indicator :1;
-#endif
- u_char section_length_lo /*:8*/;
- u_char transport_stream_id_hi /*:8*/;
- u_char transport_stream_id_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char version_number :5;
- u_char current_next_indicator :1;
-#else
- u_char current_next_indicator :1;
- u_char version_number :5;
- u_char :2;
-#endif
- u_char section_number /*:8*/;
- u_char last_section_number /*:8*/;
-} pat_t;
-#define PAT_LEN sizeof (pat_t)
-
-typedef struct pat_prog {
- u_char program_number_hi /*:8*/;
- u_char program_number_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :3;
- u_char network_pid_hi :5;
-#else
- u_char network_pid_hi :5;
- u_char :3;
-#endif
- u_char network_pid_lo /*:8*/;
- /* or program_map_pid (if prog_num=0)*/
-} pat_prog_t;
-#define PAT_PROG_LEN sizeof (pat_prog_t)
-
-/*
- *
- * 2) Conditional Access Table (CAT):
- *
- * - the CAT provides information on the CA systems used in the
- * multiplex; the information is private and dependent on the CA
- * system, but includes the location of the EMM stream, when
- * applicable.
- *
- */
-typedef struct cat {
- u_char table_id /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char section_syntax_indicator :1;
- u_char dummy :1; // has to be 0
- u_char :2;
- u_char section_length_hi :4;
-#else
- u_char section_length_hi :4;
- u_char :2;
- u_char dummy :1; // has to be 0
- u_char section_syntax_indicator :1;
-#endif
- u_char section_length_lo /*:8*/;
- u_char :8;
- u_char :8;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char version_number :5;
- u_char current_next_indicator :1;
-#else
- u_char current_next_indicator :1;
- u_char version_number :5;
- u_char :2;
-#endif
- u_char section_number /*:8*/;
- u_char last_section_number /*:8*/;
-} cat_t;
-#define CAT_LEN sizeof (cat_t)
-
-/*
- *
- * 3) Program Map Table (PMT):
- *
- * - the PMT identifies and indicates the locations of the streams that
- * make up each service, and the location of the Program Clock
- * Reference fields for a service.
- *
- */
-typedef struct pmt {
- u_char table_id /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char section_syntax_indicator :1;
- u_char dummy :1; // has to be 0
- u_char :2;
- u_char section_length_hi :4;
-#else
- u_char section_length_hi :4;
- u_char :2;
- u_char dummy :1; // has to be 0
- u_char section_syntax_indicator :1;
-#endif
- u_char section_length_lo /*:8*/;
- u_char program_number_hi /*:8*/;
- u_char program_number_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char version_number :5;
- u_char current_next_indicator :1;
-#else
- u_char current_next_indicator :1;
- u_char version_number :5;
- u_char :2;
-#endif
- u_char section_number /*:8*/;
- u_char last_section_number /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :3;
- u_char PCR_PID_hi :5;
-#else
- u_char PCR_PID_hi :5;
- u_char :3;
-#endif
- u_char PCR_PID_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :4;
- u_char program_info_length_hi :4;
-#else
- u_char program_info_length_hi :4;
- u_char :4;
-#endif
- u_char program_info_length_lo /*:8*/;
- //descriptors
-} pmt_t;
-#define PMT_LEN sizeof (pmt_t)
-
-typedef struct pmt_info {
- u_char stream_type /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :3;
- u_char elementary_PID_hi :5;
-#else
- u_char elementary_PID_hi :5;
- u_char :3;
-#endif
- u_char elementary_PID_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :4;
- u_char ES_info_length_hi :4;
-#else
- u_char ES_info_length_hi :4;
- u_char :4;
-#endif
- u_char ES_info_length_lo /*:8*/;
- // descriptors
-} pmt_info_t;
-#define PMT_INFO_LEN sizeof (pmt_info_t)
-
-/*
- *
- * 4) Network Information Table (NIT):
- *
- * - the NIT is intended to provide information about the physical
- * network. The syntax and semantics of the NIT are defined in
- * ETSI EN 300 468.
- *
- */
-typedef struct nit {
- u_char table_id /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char section_syntax_indicator :1;
- u_char :3;
- u_char section_length_hi :4;
-#else
- u_char section_length_hi :4;
- u_char :3;
- u_char section_syntax_indicator :1;
-#endif
- u_char section_length_lo /*:8*/;
- u_char network_id_hi /*:8*/;
- u_char network_id_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char version_number :5;
- u_char current_next_indicator :1;
-#else
- u_char current_next_indicator :1;
- u_char version_number :5;
- u_char :2;
-#endif
- u_char section_number /*:8*/;
- u_char last_section_number /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :4;
- u_char network_descriptor_length_hi :4;
-#else
- u_char network_descriptor_length_hi :4;
- u_char :4;
-#endif
- u_char network_descriptor_length_lo /*:8*/;
- /* descriptors */
-} nit_t;
-#define NIT_LEN sizeof (nit_t)
-
-typedef struct nit_mid { // after descriptors
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :4;
- u_char transport_stream_loop_length_hi :4;
-#else
- u_char transport_stream_loop_length_hi :4;
- u_char :4;
-#endif
- u_char transport_stream_loop_length_lo /*:8*/;
-} nit_mid_t;
-#define SIZE_NIT_MID sizeof (nit_mid_t)
-
-typedef struct nit_end {
- long CRC;
-} nit_end_t;
-#define SIZE_NIT_END sizeof (nit_end_t)
-
-typedef struct nit_ts {
- u_char transport_stream_id_hi /*:8*/;
- u_char transport_stream_id_lo /*:8*/;
- u_char original_network_id_hi /*:8*/;
- u_char original_network_id_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :4;
- u_char transport_descriptors_length_hi :4;
-#else
- u_char transport_descriptors_length_hi :4;
- u_char :4;
-#endif
- u_char transport_descriptors_length_lo /*:8*/;
- /* descriptors */
-} nit_ts_t;
-#define NIT_TS_LEN sizeof (nit_ts_t)
-
-/*
- *
- * In addition to the PSI, data is needed to provide identification of
- * services and events for the user. In contrast with the PAT, CAT, and
- * PMT of the PSI, which give information only for the multiplex in which
- * they are contained (the actual multiplex), the additional information
- * defined within the present document can also provide information on
- * services and events carried by different multiplexes, and even on other
- * networks. This data is structured as nine tables:
- *
- * 1) Bouquet Association Table (BAT):
- *
- * - the BAT provides information regarding bouquets. As well as giving
- * the name of the bouquet, it provides a list of services for each
- * bouquet.
- *
- */
-/* SEE NIT (It has the same structure but has different allowed descriptors) */
-/*
- *
- * 2) Service Description Table (SDT):
- *
- * - the SDT contains data describing the services in the system e.g.
- * names of services, the service provider, etc.
- *
- */
-typedef struct sdt {
- u_char table_id /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char section_syntax_indicator :1;
- u_char :3;
- u_char section_length_hi :4;
-#else
- u_char section_length_hi :4;
- u_char :3;
- u_char section_syntax_indicator :1;
-#endif
- u_char section_length_lo /*:8*/;
- u_char transport_stream_id_hi /*:8*/;
- u_char transport_stream_id_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char version_number :5;
- u_char current_next_indicator :1;
-#else
- u_char current_next_indicator :1;
- u_char version_number :5;
- u_char :2;
-#endif
- u_char section_number /*:8*/;
- u_char last_section_number /*:8*/;
- u_char original_network_id_hi /*:8*/;
- u_char original_network_id_lo /*:8*/;
- u_char :8;
-} sdt_t;
-#define SDT_LEN sizeof (sdt_t)
-#define GetSDTTransportStreamId(x) HILO(((sdt_t *)x)->transport_stream_id)
-#define GetSDTOriginalNetworkId(x) HILO(((sdt_t *)x)->original_network_id)
-
-typedef struct sdt_descr {
- u_char service_id_hi /*:8*/;
- u_char service_id_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :6;
- u_char eit_schedule_flag :1;
- u_char eit_present_following_flag :1;
- u_char running_status :3;
- u_char free_ca_mode :1;
- u_char descriptors_loop_length_hi :4;
-#else
- u_char eit_present_following_flag :1;
- u_char eit_schedule_flag :1;
- u_char :6;
- u_char descriptors_loop_length_hi :4;
- u_char free_ca_mode :1;
- u_char running_status :3;
-#endif
- u_char descriptors_loop_length_lo /*:8*/;
- u_char data[];
-} sdt_descr_t;
-#define SDT_DESCR_LEN sizeof (sdt_descr_t)
-#define GetSDTDescriptorsLoopLength(x) HILO(((sdt_descr_t *)x)->descriptors_loop_length)
-
-/*
- *
- * 3) Event Information Table (EIT):
- *
- * - the EIT contains data concerning events or programmes such as event
- * name, start time, duration, etc.; - the use of different descriptors
- * allows the transmission of different kinds of event information e.g.
- * for different service types.
- *
- */
-typedef struct eit {
- u_char table_id /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char section_syntax_indicator :1;
- u_char :3;
- u_char section_length_hi :4;
-#else
- u_char section_length_hi :4;
- u_char :3;
- u_char section_syntax_indicator :1;
-#endif
- u_char section_length_lo /*:8*/;
- u_char service_id_hi /*:8*/;
- u_char service_id_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char version_number :5;
- u_char current_next_indicator :1;
-#else
- u_char current_next_indicator :1;
- u_char version_number :5;
- u_char :2;
-#endif
- u_char section_number /*:8*/;
- u_char last_section_number /*:8*/;
- u_char transport_stream_id_hi /*:8*/;
- u_char transport_stream_id_lo /*:8*/;
- u_char original_network_id_hi /*:8*/;
- u_char original_network_id_lo /*:8*/;
- u_char segment_last_section_number /*:8*/;
- u_char segment_last_table_id /*:8*/;
- u_char data[]; /* struct eit_event */
-} eit_t;
-#define EIT_LEN sizeof (eit_t)
-
-typedef struct eit_event {
- u_char event_id_hi /*:8*/;
- u_char event_id_lo /*:8*/;
- u_char mjd_hi /*:8*/;
- u_char mjd_lo /*:8*/;
- u_char start_time_h /*:8*/;
- u_char start_time_m /*:8*/;
- u_char start_time_s /*:8*/;
- u_char duration_h /*:8*/;
- u_char duration_m /*:8*/;
- u_char duration_s /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char running_status :3;
- u_char free_ca_mode :1;
- u_char descriptors_loop_length_hi :4;
-#else
- u_char descriptors_loop_length_hi :4;
- u_char free_ca_mode :1;
- u_char running_status :3;
-#endif
- u_char descriptors_loop_length_lo /*:8*/;
- u_char data[]; /* struct descr_gen */
-} eit_event_t;
-#define EIT_EVENT_LEN sizeof (eit_event_t)
-#define GetEITDescriptorsLoopLength(x) HILO(((eit_event_t *)x)->descriptors_loop_length)
-
-/*
- *
- * 4) Running Status Table (RST):
- *
- * - the RST gives the status of an event (running/not running). The RST
- * updates this information and allows timely automatic switching to
- * events.
- *
- */
- /* TO BE DONE */
-/*
- *
- * 5) Time and Date Table (TDT):
- *
- * - the TDT gives information relating to the present time and date.
- * This information is given in a separate table due to the frequent
- * updating of this information.
- *
- */
-
-typedef struct tdt {
- u_char table_id /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char section_syntax_indicator :1;
- u_char :3;
- u_char section_length_hi :4;
-#else
- u_char section_length_hi :4;
- u_char :3;
- u_char section_syntax_indicator :1;
-#endif
- u_char section_length_lo /*:8*/;
- u_char utc_mjd_hi /*:8*/;
- u_char utc_mjd_lo /*:8*/;
- u_char utc_time_h /*:8*/;
- u_char utc_time_m /*:8*/;
- u_char utc_time_s /*:8*/;
-} tdt_t;
-#define TDT_LEN sizeof (tdt_t)
-
-/*
- *
- * 6) Time Offset Table (TOT):
- *
- * - the TOT gives information relating to the present time and date and
- * local time offset. This information is given in a separate table due
- * to the frequent updating of the time information.
- *
- */
-typedef struct tot {
- u_char table_id /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char section_syntax_indicator :1;
- u_char :3;
- u_char section_length_hi :4;
-#else
- u_char section_length_hi :4;
- u_char :3;
- u_char section_syntax_indicator :1;
-#endif
- u_char section_length_lo /*:8*/;
- u_char utc_mjd_hi /*:8*/;
- u_char utc_mjd_lo /*:8*/;
- u_char utc_time_h /*:8*/;
- u_char utc_time_m /*:8*/;
- u_char utc_time_s /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :4;
- u_char descriptors_loop_length_hi :4;
-#else
- u_char descriptors_loop_length_hi :4;
- u_char :4;
-#endif
- u_char descriptors_loop_length_lo /*:8*/;
-} tot_t;
-#define TOT_LEN sizeof (tot_t)
-
-/*
- *
- * 7) Stuffing Table (ST):
- *
- * - the ST is used to invalidate existing sections, for example at
- * delivery system boundaries.
- *
- */
- /* TO BE DONE */
-/*
- *
- * 8) Selection Information Table (SIT):
- *
- * - the SIT is used only in "partial" (i.e. recorded) bitstreams. It
- * carries a summary of the SI information required to describe the
- * streams in the partial bitstream.
- *
- */
-struct sit {
- uint8_t tableid;
-#if BYTE_ORDER == BIG_ENDIAN
- uint8_t section_length_hi : 4;
- bool reserved1 : 2;
- bool reserved_fu : 1;
- bool section_syntax : 1;
-#else
- bool section_syntax : 1;
- bool reserved_fu : 1;
- bool reserved1 : 2;
- uint8_t section_length_hi : 4;
-#endif
- uint8_t section_length_lo;
- uint16_t transport_stream_id ;
- bool reserved2 : 2;
- uint8_t version : 5;
- bool current_next_ind : 1;
- uint8_t section_number;
- uint8_t last_section_number;
- uint16_t original_network_id;
- uint8_t reserved3;
- u_char serviceData[];
-} __attribute__((packed));
-struct si {
- uint16_t serviceid;
- uint8_t reserved_fu : 6;
- bool eit_sched : 1;
- bool eit_now_and_next : 1;
-#if BYTE_ORDER == BIG_ENDIAN
- uint8_t running_status : 3;
- bool free_ca_mode : 1;
- uint8_t desc_loop_len_hi : 4;
-#else
- uint8_t desc_loop_len_hi : 4;
- bool free_ca_mode : 1;
- uint8_t running_status : 3;
-#endif
- uint8_t desc_loop_len_lo;
- u_char descData[];
-} __attribute__((packed));
-/*
- *
- * 9) Discontinuity Information Table (DIT):
- *
- * - the DIT is used only in "partial" (i.e. recorded) bitstreams.
- * It is inserted where the SI information in the partial bitstream may
- * be discontinuous. Where applicable the use of descriptors allows a
- * flexible approach to the organization of the tables and allows for
- * future compatible extensions.
- *
- */
- /* TO BE DONE */
-/*
- *
- * The following describes the different descriptors that can be used within
- * the SI.
- *
- * The following semantics apply to all the descriptors defined in this
- * subclause:
- *
- * descriptor_tag: The descriptor tag is an 8-bit field which identifies
- * each descriptor. Those values with MPEG-2 normative
- * meaning are described in ISO/IEC 13818-1. The values of
- * descriptor_tag are defined in 'libsi.h'
- * descriptor_length: The descriptor length is an 8-bit field specifying the
- * total number of bytes of the data portion of the
- * descriptor following the byte defining the value of
- * this field.
- *
- */
-
-typedef struct descr_gen {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-} descr_gen_t;
-#define DESCR_GEN_LEN sizeof (descr_gen_t)
-#define CastGenericDescriptor(x) ((descr_gen_t *)(x))
-
-#define GetDescriptorTag(x) (((descr_gen_t *)x)->descriptor_tag)
-#define GetDescriptorLength(x) (((descr_gen_t *)x)->descriptor_length)
-
-/* 0x09 ca_descriptor */
-typedef struct descr_ca {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char CA_type_hi /*:8*/;
- u_char CA_type_lo /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :3;
- u_char CA_PID_hi :5;
-#else
- u_char CA_PID_hi :5;
- u_char :3;
-#endif
- u_char CA_PID_lo /*:8*/;
-} descr_ca_t;
-#define DESCR_CA_LEN sizeof (descr_ca_t)
-#define CastCaDescriptor(x) ((descr_ca_t *)(x))
-
-/* 0x0A iso_639_language_descriptor */
-typedef struct descr_iso_639_language {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
-} descr_iso_639_language_t;
-#define DESCR_ISO_639_LANGUAGE_LEN sizeof (descr_iso_639_language_t)
-#define CastIso639LanguageDescriptor(x) ((descr_iso_639_language_t *)(x))
-
-/* 0x40 network_name_descriptor */
-typedef struct descr_network_name {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-} descr_network_name_t;
-#define DESCR_NETWORK_NAME_LEN sizeof (descr_network_name_t)
-#define CastNetworkNameDescriptor(x) ((descr_network_name_t *)(x))
-
-/* 0x41 service_list_descriptor */
-typedef struct descr_service_list {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-} descr_service_list_t;
-#define DESCR_SERVICE_LIST_LEN sizeof (descr_service_list_t)
-#define CastServiceListDescriptor(x) ((descr_service_list_t *)(x))
-
-typedef struct descr_service_list_loop {
- u_char service_id_hi /*:8*/;
- u_char service_id_lo /*:8*/;
- u_char service_type /*:8*/;
-} descr_service_list_loop_t;
-#define DESCR_SERVICE_LIST_LOOP_LEN sizeof (descr_service_list_loop_t)
-#define CastServiceListDescriptorLoop(x) ((descr_service_list_loop_t *)(x))
-
-/* 0x42 stuffing_descriptor */
-typedef struct descr_stuffing {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data[];
-} descr_stuffing_t;
-#define DESCR_STUFFING_LEN sizeof (descr_stuffing_t)
-#define CastStuffingDescriptor(x) ((descr_stuffing_t *)(x))
-
-/* 0x43 satellite_delivery_system_descriptor */
-typedef struct descr_satellite_delivery_system {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char frequency1 /*:8*/;
- u_char frequency2 /*:8*/;
- u_char frequency3 /*:8*/;
- u_char frequency4 /*:8*/;
- u_char orbital_position1 /*:8*/;
- u_char orbital_position2 /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char west_east_flag :1;
- u_char polarization :2;
- u_char modulation :5;
-#else
- u_char modulation :5;
- u_char polarization :2;
- u_char west_east_flag :1;
-#endif
- u_char symbol_rate1 /*:8*/;
- u_char symbol_rate2 /*:8*/;
- u_char symbol_rate3 /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char symbol_rate4 :4;
- u_char fec_inner :4;
-#else
- u_char fec_inner :4;
- u_char symbol_rate4 :4;
-#endif
-} descr_satellite_delivery_system_t;
-#define DESCR_SATELLITE_DELIVERY_SYSTEM_LEN sizeof (descr_satellite_delivery_system_t)
-#define CastSatelliteDeliverySystemDescriptor(x) ((descr_satellite_delivery_system_t *)(x))
-#define GetSatelliteDeliverySystemFrequency(x) HILO4(((descr_satellite_delivert_system_t *)x)->frequency)
-#define GetSatelliteDeliverySystemSymbolRate(x) HILO4(((descr_satellite_delivert_system_t *)x)->symbol_rate)
-
-
-/* 0x44 cable_delivery_system_descriptor */
-typedef struct descr_cable_delivery_system {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char frequency1 /*:8*/;
- u_char frequency2 /*:8*/;
- u_char frequency3 /*:8*/;
- u_char frequency4 /*:8*/;
- u_char :8;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :4;
- u_char fec_outer :4;
-#else
- u_char fec_outer :4;
- u_char :4;
-#endif
- u_char modulation /*:8*/;
- u_char symbol_rate1 /*:8*/;
- u_char symbol_rate2 /*:8*/;
- u_char symbol_rate3 /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char symbol_rate4 :4;
- u_char fec_inner :4;
-#else
- u_char fec_inner :4;
- u_char symbol_rate4 :4;
-#endif
-} descr_cable_delivery_system_t;
-#define DESCR_CABLE_DELIVERY_SYSTEM_LEN sizeof (descr_cable_delivery_system_t)
-#define CastCableDeliverySystemDescriptor(x) ((descr_cable_delivery_system_t *)(x))
-#define GetCableDeliverySystemFrequency(x) HILO4(((descr_cable_delivert_system_t *)x)->frequency)
-#define GetCableDeliverySystemSymbolRate(x) HILO4(((descr_cable_delivert_system_t *)x)->symbol_rate)
-
-/* 0x45 vbi_data_descriptor */
-typedef struct descr_vbi_data {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- /* TBD */
-} descr_vbi_data_t;
-#define DESCR_VBI_DATA_LEN sizeof (descr_vbi_data_t)
-#define CastVbiDataDescriptor(x) ((descr_vbi_data_t *)(x))
-
-/* 0x46 vbi_teletext_descriptor */
-typedef struct descr_vbi_teletext {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- /* TBD */
-} descr_vbi_teletext_t;
-#define DESCR_VBI_TELETEXT_LEN sizeof (descr_vbi_teletext_t)
-#define CastVbiDescriptor(x) ((descr_vbi_teletext_t *)(x))
-
-/* 0x47 bouquet_name_descriptor */
-typedef struct descr_bouquet_name {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-} descr_bouquet_name_t;
-#define DESCR_BOUQUET_NAME_LEN sizeof (descr_bouquet_name_t)
-
-#define CastBouquetNameDescriptor(x) ((descr_bouquet_name_t *)(x))
-
-/* 0x48 service_descriptor */
-typedef struct descr_service {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char service_type /*:8*/;
- u_char provider_name_length /*:8*/;
-} descr_service_t;
-#define DESCR_SERVICE_LEN sizeof (descr_service_t)
-#define CastServiceDescriptor(x) ((descr_service_t *)(x))
-
-/* 0x49 country_availability_descriptor */
-typedef struct descr_country_availability {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char country_availability_flag :1;
- u_char :7;
-#else
- u_char :7;
- u_char country_availability_flag :1;
-#endif
-} descr_country_availability_t;
-#define DESCR_COUNTRY_AVAILABILITY_LEN sizeof (descr_country_availability_t)
-#define CastCountryAvailabilityDescriptor(x) ((descr_country_availability_t *)(x))
-
-/* 0x4A linkage_descriptor */
-typedef struct descr_linkage {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char transport_stream_id_hi /*:8*/;
- u_char transport_stream_id_lo /*:8*/;
- u_char original_network_id_hi /*:8*/;
- u_char original_network_id_lo /*:8*/;
- u_char service_id_hi /*:8*/;
- u_char service_id_lo /*:8*/;
- u_char linkage_type /*:8*/;
-} descr_linkage_t;
-#define DESCR_LINKAGE_LEN sizeof (descr_linkage_t)
-#define CastLinkageDescriptor(x) ((descr_linkage_t *)(x))
-
-/* 0x4B nvod_reference_descriptor */
-typedef struct descr_nvod_reference {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data[]; /* struct item_nvod_reference */
-} descr_nvod_reference_t;
-#define DESCR_NVOD_REFERENCE_LEN sizeof (descr_nvod_reference_t)
-#define CastNvodReferenceDescriptor(x) ((descr_nvod_reference_t *)(x))
-
-typedef struct item_nvod_reference {
- u_char transport_stream_id_hi /*:8*/;
- u_char transport_stream_id_lo /*:8*/;
- u_char original_network_id_hi /*:8*/;
- u_char original_network_id_lo /*:8*/;
- u_char service_id_hi /*:8*/;
- u_char service_id_lo /*:8*/;
-} item_nvod_reference_t;
-#define ITEM_NVOD_REFERENCE_LEN sizeof (item_nvod_reference_t)
-#define CastNvodReferenceItem(x) ((item_nvod_reference_t *)(x))
-
-/* 0x4C time_shifted_service_descriptor */
-typedef struct descr_time_shifted_service {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char reference_service_id_hi /*:8*/;
- u_char reference_service_id_lo /*:8*/;
-} descr_time_shifted_service_t;
-#define DESCR_TIME_SHIFTED_SERVICE_LEN sizeof (descr_time_shifted_service_t)
-#define CastTimeShiftedServiceDescriptor(x) ((descr_time_shifted_service_t *)(x))
-
-/* 0x4D short_event_descriptor */
-typedef struct descr_short_event {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
- u_char event_name_length /*:8*/;
- u_char data[];
-} descr_short_event_t;
-#define DESCR_SHORT_EVENT_LEN sizeof (descr_short_event_t)
-#define CastShortEventDescriptor(x) ((descr_short_event_t *)(x))
-
-/* 0x4E extended_event_descriptor */
-typedef struct descr_extended_event {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char descriptor_number :4;
- u_char last_descriptor_number :4;
-#else
- u_char last_descriptor_number :4;
- u_char descriptor_number :4;
-#endif
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
- u_char length_of_items /*:8*/;
- u_char data[]; /* struct item_extended_event */
-} descr_extended_event_t;
-#define DESCR_EXTENDED_EVENT_LEN sizeof (descr_extended_event_t)
-#define CastExtendedEventDescriptor(x) ((descr_extended_event_t *)(x))
-
-typedef struct item_extended_event {
- u_char item_description_length /*:8*/;
- u_char data[];
-} item_extended_event_t;
-#define ITEM_EXTENDED_EVENT_LEN sizeof (item_extended_event_t)
-#define CastExtendedEventItem(x) ((item_extended_event_t *)(x))
-
-/* 0x4F time_shifted_event_descriptor */
-typedef struct descr_time_shifted_event {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char reference_service_id_hi /*:8*/;
- u_char reference_service_id_lo /*:8*/;
- u_char reference_event_id_hi /*:8*/;
- u_char reference_event_id_lo /*:8*/;
-} descr_time_shifted_event_t;
-#define DESCR_TIME_SHIFTED_EVENT_LEN sizeof (descr_time_shifted_event_t)
-#define CastTimeShiftedEventDescriptor(x) ((descr_time_shifted_event_t *)(x))
-
-/* 0x50 component_descriptor */
-typedef struct descr_component {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :4;
- u_char stream_content :4;
-#else
- u_char stream_content :4;
- u_char :4;
-#endif
- u_char component_type /*:8*/;
- u_char component_tag /*:8*/;
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
- u_char data[];
-} descr_component_t;
-#define DESCR_COMPONENT_LEN sizeof (descr_component_t)
-#define CastComponentDescriptor(x) ((descr_component_t *)(x))
-
-/* 0x51 mosaic_descriptor */
-typedef struct descr_mosaic {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char mosaic_entry_point :1;
- u_char number_of_horizontal_elementary_cells :3;
- u_char :1;
- u_char number_of_vertical_elementary_cells :3;
-#else
- u_char number_of_vertical_elementary_cells :3;
- u_char :1;
- u_char number_of_horizontal_elementary_cells :3;
- u_char mosaic_entry_point :1;
-#endif
- u_char data[]; /* struct item_mosaic */
-} descr_mosaic_t;
-#define DESCR_MOSAIC_LEN sizeof (descr_mosaic_t)
-#define CastMosaicDescriptor(x) ((descr_mosaic_t *)(x))
-
-typedef struct item_mosaic {
-#if BYTE_ORDER == BIG_ENDIAN
- u_char logical_cell_id :6;
- u_char :7;
- u_char logical_cell_presentation_info :3;
-#else
- u_char :2;
- u_char logical_cell_id :6;
- u_char logical_cell_presentation_info :3; /*0=undefined, 1=video, 2=still picture, 3=graphical text, 4--7=reserved*/
- u_char :5;
-#endif
- u_char elementary_cell_field_length /*:8*/;
- u_char data[]; /* struct item_mosaic_cell; struct item_mosaic_end */
-} item_mosaic_t;
-typedef struct item_mosaic_end {
- u_char cell_linkage_info /*:8*/; /*0=undefined, 1=bouquet, 2=service, 3=other mosaic, 4=event, 5--255=reserved*/
- u_char data[]; /* union item_cell_linkage */
-} item_mosaic_end_t;
-
-typedef struct item_mosaic_cell {
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char elementary_cell_id :6;
-#else
- u_char elementary_cell_id :6;
- u_char :2;
-#endif
-} item_mosaic_cell_t;
-typedef union item_mosaic_cell_linkage {
- struct item_mosaic_cell_bouquet {
- u_char bouquet_id_hi /*:8*/;
- u_char bouquet_id_lo /*:8*/;
- } bouquet;
- struct item_mosaic_cell_service {
- u_char original_network_id_hi /*:8*/;
- u_char original_network_id_lo /*:8*/;
- u_char transport_stream_id_hi /*:8*/;
- u_char transport_stream_id_lo /*:8*/;
- u_char service_id_hi /*:8*/;
- u_char service_id_lo /*:8*/;
- } service;
- struct item_mosaic_cell_other {
- u_char original_network_id_hi /*:8*/;
- u_char original_network_id_lo /*:8*/;
- u_char transport_stream_id_hi /*:8*/;
- u_char transport_stream_id_lo /*:8*/;
- u_char service_id_hi /*:8*/;
- u_char service_id_lo /*:8*/;
- } other;
- struct item_mosaic_cell_event {
- u_char original_network_id_hi /*:8*/;
- u_char original_network_id_lo /*:8*/;
- u_char transport_stream_id_hi /*:8*/;
- u_char transport_stream_id_lo /*:8*/;
- u_char service_id_hi /*:8*/;
- u_char service_id_lo /*:8*/;
- u_char event_id_hi /*:8*/;
- u_char event_id_lo /*:8*/;
- } event;
-} item_mosaic_cell_linkage_t;
-
-/* 0x52 stream_identifier_descriptor */
-typedef struct descr_stream_identifier {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char component_tag /*:8*/;
-} descr_stream_identifier_t;
-#define DESCR_STREAM_IDENTIFIER_LEN sizeof (descr_stream_identifier_t)
-#define CastStreamIdentifierDescriptor(x) ((descr_stream_identifier_t *)(x))
-
-/* 0x53 ca_identifier_descriptor */
-typedef struct descr_ca_identifier {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-} descr_ca_identifier_t;
-#define DESCR_CA_IDENTIFIER_LEN sizeof (descr_ca_identifier_t)
-#define CastCaIdentifierDescriptor(x) ((descr_ca_identifier_t *)(x))
-
-/* 0x54 content_descriptor */
-typedef struct descr_content {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data[]; /* struct nibble_content */
-} descr_content_t;
-#define DESCR_CONTENT_LEN sizeof (descr_content_t)
-#define CastContentDescriptor(x) ((descr_content_t *)(x))
-
-typedef struct nibble_content {
-#if BYTE_ORDER == BIG_ENDIAN
- u_char content_nibble_level_1 :4;
- u_char content_nibble_level_2 :4;
- u_char user_nibble_1 :4;
- u_char user_nibble_2 :4;
-#else
- u_char user_nibble_2 :4;
- u_char user_nibble_1 :4;
- u_char content_nibble_level_2 :4;
- u_char content_nibble_level_1 :4;
-#endif
-} nibble_content_t;
-#define NIBBLE_CONTENT_LEN sizeof (nibble_content_t)
-#define CastContentNibble(x) ((nibble_content_t *)(x))
-
-/* 0x55 parental_rating_descriptor */
-typedef struct descr_parental_rating {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data[]; /* struct parental_rating_item */
-} descr_parental_rating_t;
-#define DESCR_PARENTAL_RATING_LEN sizeof (descr_parental_rating_t)
-#define CastParentalRatingDescriptor(x) ((descr_parental_rating_t *)(x))
-
-typedef struct parental_rating_item {
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
- u_char rating /*:8*/;
-} parental_rating_item_t;
-#define PARENTAL_RATING_ITEM_LEN sizeof (parental_rating_item_t)
-#define CastParentalRatingItem(x) ((parental_rating_item_t *)(x))
-
-/* 0x56 teletext_descriptor */
-typedef struct descr_teletext {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data[]; /* struct item_teletext */
-} descr_teletext_t;
-#define DESCR_TELETEXT_LEN sizeof (descr_teletext_t)
-#define CastTeletextDescriptor(x) ((descr_teletext_t *)(x))
-
-typedef struct item_teletext {
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char type :5;
- u_char magazine_number :3;
-#else
- u_char magazine_number :3;
- u_char type :5;
-#endif
- u_char page_number /*:8*/;
-} item_teletext_t;
-#define ITEM_TELETEXT_LEN sizeof (item_teletext_t)
-#define CastTeletextItem(x) ((item_teletext_t *)(x))
-
-/* 0x57 telephone_descriptor */
-typedef struct descr_telephone {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char foreign_availability :1;
- u_char connection_type :5;
-#else
- u_char connection_type :5;
- u_char foreign_availability :1;
- u_char :2;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :1;
- u_char country_prefix_length :2;
- u_char international_area_code_length :3;
- u_char operator_code_length :2;
-#else
- u_char operator_code_length :2;
- u_char international_area_code_length :3;
- u_char country_prefix_length :2;
- u_char :1;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :1;
- u_char national_area_code_length :3;
- u_char core_number_length :4;
-#else
- u_char core_number_length :4;
- u_char national_area_code_length :3;
- u_char :1;
-#endif
- u_char data[]; /* coutry area operator national core */
-} descr_telephone_t;
-#define DESCR_TELEPHONE_LEN sizeof (descr_telephone_t)
-#define CastTelephoneDescriptor(x) ((descr_telephone_t *)(x))
-
-/* 0x58 local_time_offset_descriptor */
-typedef struct descr_local_time_offset {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-} descr_local_time_offset_t;
-#define DESCR_LOCAL_TIME_OFFSET_LEN sizeof (descr_local_time_offset_t)
-#define CastLocalTimeOffsetDescriptor(x) ((descr_local_time_offset_t *)(x))
-
-typedef struct local_time_offset_entry {
- u_char country_code1 /*:8*/;
- u_char country_code2 /*:8*/;
- u_char country_code3 /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char country_region_id :6;
- u_char :1;
- u_char local_time_offset_polarity :1;
-#else
- u_char local_time_offset_polarity :1;
- u_char :1;
- u_char country_region_id :6;
-#endif
- u_char local_time_offset_h /*:8*/;
- u_char local_time_offset_m /*:8*/;
- u_char time_of_change_mjd_hi /*:8*/;
- u_char time_of_change_mjd_lo /*:8*/;
- u_char time_of_change_time_h /*:8*/;
- u_char time_of_change_time_m /*:8*/;
- u_char time_of_change_time_s /*:8*/;
- u_char next_time_offset_h /*:8*/;
- u_char next_time_offset_m /*:8*/;
-} local_time_offset_entry_t ;
-#define LOCAL_TIME_OFFSET_ENTRY_LEN sizeof (local_time_offset_entry_t)
-#define CastLocalTimeOffsetEntry(x) ((local_time_offset_entry_t *)(x))
-
-/* 0x59 subtitling_descriptor */
-typedef struct descr_subtitling {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data[]; /* item_subtitling */
-} descr_subtitling_t;
-#define DESCR_SUBTITLING_LEN sizeof (descr_subtitling_t)
-#define CastSubtitlingDescriptor(x) ((descr_subtitling_t *)(x))
-
-typedef struct item_subtitling {
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
- u_char subtitling_type /*:8*/;
- u_char composition_page_id_hi /*:8*/;
- u_char composition_page_id_lo /*:8*/;
- u_char ancillary_page_id_hi /*:8*/;
- u_char ancillary_page_id_lo /*:8*/;
-} item_subtitling_t;
-#define ITEM_SUBTITLING_LEN sizeof (item_subtitling_t)
-#define CastSubtitlingItem(x) ((item_subtitling_t *)(x))
-
-/* 0x5A terrestrial_delivery_system_descriptor */
-typedef struct descr_terrestrial_delivery {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char frequency1 /*:8*/;
- u_char frequency2 /*:8*/;
- u_char frequency3 /*:8*/;
- u_char frequency4 /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char bandwidth :3;
- u_char :5;
-#else
- u_char :5;
- u_char bandwidth :3;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- u_char constellation :2;
- u_char hierarchy :3;
- u_char code_rate_HP :3;
-#else
- u_char code_rate_HP :3;
- u_char hierarchy :3;
- u_char constellation :2;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- u_char code_rate_LP :3;
- u_char guard_interval :2;
- u_char transmission_mode :2;
- u_char other_frequency_flag :1;
-#else
- u_char other_frequency_flag :1;
- u_char transmission_mode :2;
- u_char guard_interval :2;
- u_char code_rate_LP :3;
-#endif
- u_char reserver2 /*:8*/;
- u_char reserver3 /*:8*/;
- u_char reserver4 /*:8*/;
- u_char reserver5 /*:8*/;
-} descr_terrestrial_delivery_system_t;
-#define DESCR_TERRESTRIAL_DELIVERY_SYSTEM_LEN sizeof (descr_terrestrial_delivery_system_t)
-#define CastTerrestrialDeliverySystemDescriptor(x) ((descr_terrestrial_delivery_system_t *)(x))
-#define GetTerrestrialDeliverySystemFrequency(x) HILO4(((descr_terrestrial_delivert_system_t *)x)->frequency)
-
-/* 0x5B multilingual_network_name_descriptor */
-typedef struct descr_multilingual_network_name {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data[]; /* struct item_multilingual_network_name */
-} descr_multilingual_network_name_t;
-#define DESCR_MULTILINGUAL_NETWORK_NAME_LEN sizeof (descr_multilingual_network_name_t)
-#define CastMultilingualNetworkNameDescriptor(x) ((descr_multilingual_network_name_t *)(x))
-
-typedef struct item_multilingual_network_name {
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
- u_char network_name_length /*:8*/;
- u_char network_name[];
-} item_multilingual_network_name_t;
-
-/* 0x5C multilingual_bouquet_name_descriptor */
-typedef struct descr_multilingual_bouquet_name {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char names[]; /* struct item_multilingual_bouquet_name */
-} descr_multilingual_bouquet_name_t;
-#define DESCR_MULTILINGUAL_BOUQUET_NAME_LEN sizeof (descr_multilingual_bouquet_name_t)
-#define CastMultilingualBouquetNameDescriptor(x) ((descr_multilingual_bouquet_name_t *)(x))
-
-typedef struct item_multilingual_bouquet_name {
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
- u_char bouquet_name_length /*:8*/;
- u_char bouquet_name[];
-} item_multilingual_bouquet_name_t;
-
-/* 0x5D multilingual_service_name_descriptor */
-typedef struct descr_multilingual_service_name {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data[]; /* struct multilingual_service_name_item */
-} descr_multilingual_service_name_t;
-#define DESCR_MULTILINGUAL_SERVICE_NAME_LEN sizeof (descr_multilingual_service_name_t)
-#define CastMultilingualServiceNameDescriptor(x) ((descr_multilingual_service_name_t *)(x))
-
-typedef struct multilingual_service_name_item {
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
- u_char data[]; /* struct multilingual_service_name_item_(mid|end) */
-} multilingual_service_name_item_t;
-typedef struct multilingual_service_name_item_mid {
- u_char service_provider_name_length /*:8*/;
- u_char service_provider_name[];
-} multilingual_service_name_item_mid_t;
-typedef struct multilingual_service_name_item_end {
- u_char service_name_length /*:8*/;
- u_char service_name[];
-} multilingual_service_name_item_end_t;
-
-/* 0x5E multilingual_component_descriptor */
-typedef struct descr_multilingual_component {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char component_tag /*:8*/;
- u_char data[]; /* struct multilingual_component_item */
-} descr_multilingual_component_t;
-#define DESCR_MULTILINGUAL_COMPONENT_LEN sizeof (descr_multilingual_component_t)
-#define CastMultilingualComponentDescriptor(x) ((descr_multilingual_component_t *)(x))
-
-typedef struct item_multilingual_component {
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
- u_char text_description_length /*:8*/;
- u_char text_description[];
-} item_multilingual_component_t;
-
-/* 0x5F private_data_specifier_descriptor */
-typedef struct descr_private_data_specifier {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char private_data_specifier1 /*:8*/;
- u_char private_data_specifier2 /*:8*/;
- u_char private_data_specifier3 /*:8*/;
- u_char private_data_specifier4 /*:8*/;
-} descr_private_data_specifier_t;
-#define DESCR_PRIVATE_DATA_SPECIFIER_LEN sizeof (descr_private_data_specifier_t)
-#define CastPrivateDataSpecifierDescriptor(x) ((descr_private_data_specifier_t *)(x))
-#define GetPrivateDataSpecifier(x) HILO4(((descr_private_data_specifier_t *)x)->private_data_specifier)
-
-/* 0x60 service_move_descriptor */
-typedef struct descr_service_move {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char new_original_network_id_hi /*:8*/;
- u_char new_original_network_id_lo /*:8*/;
- u_char new_transport_stream_id_hi /*:8*/;
- u_char new_transport_stream_id_lo /*:8*/;
- u_char new_service_id_hi /*:8*/;
- u_char new_service_id_lo /*:8*/;
-} descr_service_move_t;
-#define DESCR_SERVICE_MOVE_LEN sizeof (descr_service_move_t)
-#define CastServiceMoveDescriptor(x) ((descr_service_move_t *)(x))
-
-/* 0x61 short_smoothing_buffer_descriptor */
-typedef struct descr_short_smoothing_buffer {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char sb_size :2;
- u_char sb_leak_rate :6;
-#else
- u_char sb_leak_rate :6;
- u_char sb_size :2;
-#endif
- u_char data[];
-} descr_short_smoothing_buffer_t;
-#define DESCR_SHORT_SMOOTHING_BUFFER_LEN sizeof (descr_short_smoothing_buffer_t)
-#define CastShortSmoothingBufferDescriptor(x) ((descr_short_smoothing_buffer_t *)(x))
-
-/* 0x62 frequency_list_descriptor */
-typedef struct descr_frequency_list {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :6;
- u_char coding_type :2; /* 00=not def 01=satelite 10=cable 11=terrestrial */
-#else
- u_char coding_type :2; /* 00=not def 01=satelite 10=cable 11=terrestrial */
- u_char :6;
-#endif
- u_char centre_frequency1 /*:8*/;
- u_char centre_frequency2 /*:8*/;
- u_char centre_frequency3 /*:8*/;
- u_char centre_frequency4 /*:8*/;
-} descr_frequency_list_t;
-#define DESCR_FREQUENCY_LIST_LEN sizeof (descr_frequency_list_t)
-#define CastFrequencyListDescriptor(x) ((descr_frequency_list_t *)(x))
-
-/* 0x63 partial_transport_stream_descriptor */
-typedef struct descr_partial_transport_stream {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char peak_rate1 :6;
-#else
- u_char peak_rate1 :6;
- u_char :2;
-#endif
- u_char peak_rate2 /*:8*/;
- u_char peak_rate3 /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char minimum_overall_smoothing_rate1 :6;
-#else
- u_char minimum_overall_smoothing_rate1 :6;
- u_char :2;
-#endif
- u_char minimum_overall_smoothing_rate2 /*:8*/;
- u_char minimum_overall_smoothing_rate3 /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :2;
- u_char maximum_overall_smoothing_rate1 :6;
-#else
- u_char maximum_overall_smoothing_rate1 :6;
- u_char :2;
-#endif
- u_char maximum_overall_smoothing_rate2 /*:8*/;
-} descr_partial_transport_stream_t;
-#define DESCR_PARTIAL_TRANSPORT_STREAM_LEN sizeof (descr_partial_transport_stream_t)
-#define CastPartialDescriptor(x) ((descr_partial_transport_stream_t *)(x))
-#define GetPartialTransportStreamCentreFrequency(x) HILO4(((descr_partial_transport_stream_t *)x)->centre_frequency)
-#define GetPTSPeakRate(x) HILO2(((descr_partial_transport_stream *)x)->peak_rate)
-#define GetPTSMinOSRate(x) HILO3(((descr_partial_transport_stream *)x)->minimum_overall_smoothing_rate)
-#define GetPTSMaxOSRate(x) HILO2(((descr_partial_transport_stream *)x)->minimum_overall_smoothing_rate)
-
-/* 0x64 data_broadcast_descriptor */
-typedef struct descr_data_broadcast {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data_broadcast_id_hi /*:8*/;
- u_char data_broadcast_id_lo /*:8*/;
- u_char component_tag /*:8*/;
- u_char selector_length /*:8*/;
- u_char data[]; /* char[]; struct descr_data_broadcast_end */
-} descr_data_broadcast_t;
-typedef struct descr_data_broadcast_end {
- u_char lang_code1 /*:8*/;
- u_char lang_code2 /*:8*/;
- u_char lang_code3 /*:8*/;
- u_char text_length /*:8*/;
- u_char text[];
-} descr_data_broadcast_end_t;
-
-/* 0x65 ca_system_descriptor */
-typedef struct descr_ca_system {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data[]; /* struct item_ca_system */
-} descr_ca_system_t;
-#define DESCR_CA_SYSTEM_LEN sizeof (descr_ca_system_t)
-#define CastCaSystemDescriptor(x) ((descr_ca_system_t *)(x))
-
-typedef struct item_ca_system {
- u_char CA_system_id_hi /*:8*/;
- u_char CA_system_id_lo /*:8*/;
-} item_ca_system_t;
-
-/* 0x66 data_broadcast_id_descriptor */
-typedef struct descr_data_broadcast_id {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data_broadcast_id_hi /*:8*/;
- u_char data_broadcast_id_lo /*:8*/;
-} descr_data_broadcast_id_t;
-#define DESCR_DATA_BROADCAST_ID_LEN sizeof (descr_data_broadcast_id_t)
-#define CastDataBroadcastIdDescriptor(x) ((descr_data_broadcast_id_t *)(x))
-
-/* 0x67 transport_stream_descriptor */
-typedef struct descr_transport_stream {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- /* TBD */
-} descr_transport_stream_t;
-#define DESCR_TRANSPORT_STREAM_LEN sizeof (descr_transport_stream_t)
-#define CastTransportStreamDescriptor(x) ((descr_transport_stream_t *)(x))
-
-/* 0x68 dsng_descriptor */
-typedef struct descr_dsng {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- /* TBD */
-} descr_dsng_t;
-#define DESCR_DSNG_LEN sizeof (descr_dsng_t)
-#define CastDsngDescriptor(x) ((descr_dsng_t *)(x))
-
-/* 0x69 programme_identificaion_label_descriptor */
-typedef struct descr_pdc {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char :4;
- u_char day :5;
- u_char month :4;
- u_char hour :5;
- u_char minute :6;
-#else
- u_char minute :6;
- u_char hour :5;
- u_char month :4;
- u_char day :5;
- u_char :4;
-#endif
-} descr_pdc_t;
-#define DESCR_PDC_LEN sizeof (descr_pdc_t)
-#define CastPdcDescriptor(x) ((descr_pdc_t *)(x))
-
-/* 0x6A ac3_descriptor */
-typedef struct descr_ac3 {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
-#if BYTE_ORDER == BIG_ENDIAN
- u_char ac3_type_flag :1;
- u_char bsid_flag :1;
- u_char mainid_flag :1;
- u_char asvc_flag :1;
- u_char :4;
-#else
- u_char :4;
- u_char asvc_flag :1;
- u_char mainid_flag :1;
- u_char bsid_flag :1;
- u_char ac3_type_flag :1;
-#endif
- u_char ac3_type /*:8*/;
- u_char bsid /*:8*/;
- u_char mainid /*:8*/;
- u_char asvc /*:8*/;
-} descr_ac3_t;
-#define DESCR_AC3_LEN sizeof (descr_ac3_t)
-#define CastAc3Descriptor(x) ((descr_ac3_t *)(x))
-
-/* 0x6B ancillary_data_descriptor */
-typedef struct descr_ancillary_data {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char ancillary_data_identifier /*:8*/;
-} descr_ancillary_data_t;
-#define DESCR_ANCILLARY_DATA_LEN sizeof (descr_ancillary_data_t)
-#define CastAncillaryDataDescriptor(x) ((descr_ancillary_data_t *)(x))
-
-/* 0x6C cell_list_descriptor */
-typedef struct descr_cell_list {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- /* TBD */
-} descr_cell_list_t;
-#define DESCR_CELL_LIST_LEN sizeof (descr_cell_list_t)
-#define CastCellListDescriptor(x) ((descr_cell_list_t *)(x))
-
-/* 0x6D cell_frequency_link_descriptor */
-typedef struct descr_cell_frequency_link {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- /* TBD */
-} descr_cell_frequency_link_t;
-#define DESCR_CELL_FREQUENCY_LINK_LEN sizeof (descr_cell_frequency_link_t)
-#define CastCellFrequencyLinkDescriptor(x) ((descr_cell_frequency_link_t *)(x))
-
-/* 0x6E announcement_support_descriptor */
-typedef struct descr_announcement_support {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- /* TBD */
-} descr_announcement_support_t;
-#define DESCR_ANNOUNCEMENT_SUPPORT_LEN sizeof (descr_announcement_support_t)
-#define CastAnnouncementSupportDescriptor(x) ((descr_announcement_support_t *)(x))
-
-/* 0x76 content_identifier_descriptor */
-typedef struct descr_content_identifier {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char data[];
-} descr_content_identifier_t;
-
-typedef struct descr_content_identifier_crid {
-#if BYTE_ORDER == BIG_ENDIAN
- u_char crid_type :6;
- u_char crid_location :2;
-#else
- u_char crid_location :2;
- u_char crid_type :6;
-#endif
- u_char crid_ref_data[];
-} descr_content_identifier_crid_t;
-
-typedef struct descr_content_identifier_crid_local {
- u_char crid_length /*:8*/;
- u_char crid_byte[];
-} descr_content_identifier_crid_local_t;
-
-
-/* 0x80 custom_category_descriptor TODO */
-typedef struct descr_custom_category {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char dummy /*:8*/; // 7F
- u_char data_length /*:8*/;
- u_char data[]; /* struct custom_category_item(1|2) */
-} descr_custom_category_t;
-struct custom_category_item1 {
- u_char dummy /*:8*/; // 10 40
-};
-struct custom_category_item2 {
- u_char length /*:8*/;
- u_char data[]; /* struct custom_category_item3 */
-};
-struct custom_category_item3 {
- u_char dummy0 /*:8*/; // FF
-#if BYTE_ORDER == BIG_ENDIAN
- u_char content_nibble_level_1 :4;
- u_char content_nibble_level_2 :4;
- u_char user_nibble_1 :4;
- u_char user_nibble_2 :4;
-#else
- u_char user_nibble_2 :4;
- u_char user_nibble_1 :4;
- u_char content_nibble_level_2 :4;
- u_char content_nibble_level_1 :4;
-#endif
- u_char dummy1[2] /*:8*/; // CF E2 | D4 48
- u_char text_length /*:8*/;
- u_char text[];
-};
-
-/* 0x81 xxx_descriptor TODO */
-typedef struct descr_xxx {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char dummy /*:8 FF*/;
-} descr_xxx_t;
-#define DESCR_XXX_LEN sizeof (descr_xxx_t)
-#define CastXxxDescriptor(x) ((descr_xxx_t *)(x))
-
-/* 0x82 vps_descriptor TODO */
-typedef struct descr_vps {
- u_char descriptor_tag /*:8*/;
- u_char descriptor_length /*:8*/;
- u_char hour[2] /*:8*/;
- u_char delimiter_time /*:8 ':'*/;
- u_char minute[2] /*:8*/;
- u_char day[2] /*:8*/;
- u_char delimiter_date /*:8 '.'*/;
- u_char month[2] /*:8*/;
- u_char delimiter /*:8 '#'*/;
- u_char number[2] /*:8*/;
-} descr_vps_t;
-#define DESCR_VPS_LEN sizeof (descr_vps_t)
-#define CastVpsDescriptor(x) ((descr_vps_t *)(x))