aboutsummaryrefslogtreecommitdiff
path: root/lib/dvb
diff options
context:
space:
mode:
authorFelix Domke <tmbinc@elitedvb.net>2003-10-17 15:36:42 +0000
committerFelix Domke <tmbinc@elitedvb.net>2003-10-17 15:36:42 +0000
commitd63d2c3c6cbbd574dda4f8b00ebe6c661735edd5 (patch)
tree84d0cacfd0b6c1241c236c7860f7cbd7f26901bb /lib/dvb
downloadenigma2-d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5.tar.gz
enigma2-d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5.zip
import of enigma2
Diffstat (limited to 'lib/dvb')
-rw-r--r--lib/dvb/Makefile.am8
-rw-r--r--lib/dvb/Makefile.in0
-rw-r--r--lib/dvb/crc32.cpp164
-rw-r--r--lib/dvb/crc32.h22
-rw-r--r--lib/dvb/db.cpp274
-rw-r--r--lib/dvb/db.h48
-rw-r--r--lib/dvb/decoder.cpp245
-rw-r--r--lib/dvb/decoder.h66
-rw-r--r--lib/dvb/demux.cpp131
-rw-r--r--lib/dvb/demux.h41
-rw-r--r--lib/dvb/dvb.cpp211
-rw-r--r--lib/dvb/dvb.h67
-rw-r--r--lib/dvb/esection.cpp130
-rw-r--r--lib/dvb/esection.h189
-rw-r--r--lib/dvb/frontend.cpp465
-rw-r--r--lib/dvb/frontend.h61
-rw-r--r--lib/dvb/idvb.h354
-rw-r--r--lib/dvb/isection.h53
-rw-r--r--lib/dvb/list.h13
-rw-r--r--lib/dvb/pmt.cpp142
-rw-r--r--lib/dvb/pmt.h71
-rw-r--r--lib/dvb/scan.cpp374
-rw-r--r--lib/dvb/scan.h69
-rw-r--r--lib/dvb/sec.cpp58
-rw-r--r--lib/dvb/sec.h13
-rw-r--r--lib/dvb/specs.h108
-rw-r--r--lib/dvb/stT1RVV7bin0 -> 1490944 bytes
27 files changed, 3377 insertions, 0 deletions
diff --git a/lib/dvb/Makefile.am b/lib/dvb/Makefile.am
new file mode 100644
index 00000000..a3b81bc7
--- /dev/null
+++ b/lib/dvb/Makefile.am
@@ -0,0 +1,8 @@
+INCLUDES = \
+ -I$(top_srcdir)/include
+
+noinst_LIBRARIES = libenigma_dvb.a
+
+libenigma_dvb_a_SOURCES = dvb.cpp demux.cpp frontend.cpp esection.cpp db.cpp \
+ sec.cpp scan.cpp crc32.cpp pmt.cpp decoder.cpp
+ \ No newline at end of file
diff --git a/lib/dvb/Makefile.in b/lib/dvb/Makefile.in
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/lib/dvb/Makefile.in
diff --git a/lib/dvb/crc32.cpp b/lib/dvb/crc32.cpp
new file mode 100644
index 00000000..049af37e
--- /dev/null
+++ b/lib/dvb/crc32.cpp
@@ -0,0 +1,164 @@
+/*
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ * First, the polynomial itself and its table of feedback terms. The
+ * polynomial is
+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ * Note that we take it "backwards" and put the highest-order term in
+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the
+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in
+ * the MSB being 1
+ *
+ * Note that the usual hardware shift register implementation, which
+ * is what we're using (we're merely optimizing it by doing eight-bit
+ * chunks at a time) shifts bits into the lowest-order term. In our
+ * implementation, that means shifting towards the right. Why do we
+ * do it this way? Because the calculated CRC must be transmitted in
+ * order from highest-order term to lowest-order term. UARTs transmit
+ * characters in order from LSB to MSB. By storing the CRC this way
+ * we hand it to the UART in the order low-byte to high-byte; the UART
+ * sends each low-bit to hight-bit; and the result is transmission bit
+ * by bit from highest- to lowest-order term without requiring any bit
+ * shuffling on our part. Reception works similarly
+ *
+ * The feedback terms table consists of 256, 32-bit entries. Notes
+ *
+ * The table can be generated at runtime if desired; code to do so
+ * is shown later. It might not be obvious, but the feedback
+ * terms simply represent the results of eight shift/xor opera
+ * tions for all combinations of data and CRC register values
+ *
+ * The values must be right-shifted by eight bits by the "updcrc
+ * logic; the shift must be unsigned (bring in zeroes). On some
+ * hardware you could probably optimize the shift in assembler by
+ * using byte-swap instructions
+ * polynomial $edb88320
+ */
+
+/* $Id: crc32.cpp,v 1.1 2003-10-17 15:35:50 tmbinc Exp $ */
+
+#include "crc32.h"
+#if 0
+const uint32_t crc32_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+#else
+const uint32_t crc32_table[256] = {
+ 0, 0x4C11DB7, 0x9823B6E, 0xD4326D9,
+ 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
+ 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
+ 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
+ 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9,
+ 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
+ 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011,
+ 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD,
+ 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
+ 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5,
+ 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81,
+ 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
+ 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49,
+ 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
+ 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
+ 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D,
+ 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE,
+ 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
+ 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
+ 0x18AEB13, 0x54BF6A4, 0x808D07D, 0xCC9CDCA,
+ 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
+ 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02,
+ 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066,
+ 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
+ 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E,
+ 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692,
+ 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
+ 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A,
+ 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
+ 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
+ 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686,
+ 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A,
+ 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
+ 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
+ 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F,
+ 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
+ 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47,
+ 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B,
+ 0x315D626, 0x7D4CB91, 0xA97ED48, 0xE56F0FF,
+ 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623,
+ 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7,
+ 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
+ 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F,
+ 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
+ 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
+ 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B,
+ 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F,
+ 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
+ 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
+ 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C,
+ 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
+ 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24,
+ 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30,
+ 0x29F3D35, 0x65E2082, 0xB1D065B, 0xFDC1BEC,
+ 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088,
+ 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654,
+ 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
+ 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C,
+ 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
+ 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
+ 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0,
+ 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C,
+ 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
+ 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4};
+#endif
diff --git a/lib/dvb/crc32.h b/lib/dvb/crc32.h
new file mode 100644
index 00000000..99254532
--- /dev/null
+++ b/lib/dvb/crc32.h
@@ -0,0 +1,22 @@
+#ifndef CRC32_H
+#define CRC32_H
+
+/* $Id: crc32.h,v 1.1 2003-10-17 15:35:49 tmbinc Exp $ */
+
+typedef unsigned int uint32_t;
+
+extern const uint32_t crc32_table[256];
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+static inline uint32_t
+crc32(uint32_t val, const void *ss, int len)
+{
+ const unsigned char *s =(const unsigned char *) ss;
+ while (--len >= 0)
+// val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
+ val = (val << 8) ^ crc32_table[(val >> 24) ^ *s++];
+ return val;
+}
+
+#endif
diff --git a/lib/dvb/db.cpp b/lib/dvb/db.cpp
new file mode 100644
index 00000000..f8233a64
--- /dev/null
+++ b/lib/dvb/db.cpp
@@ -0,0 +1,274 @@
+#include <errno.h>
+#include <lib/dvb/db.h>
+#include <lib/dvb/frontend.h>
+#include <lib/base/eerror.h>
+#include <lib/dvb_si/sdt.h>
+#include <lib/dvb_si/descriptor_tag.h>
+#include <lib/dvb_si/service_descriptor.h>
+#include <lib/dvb_si/satellite_delivery_system_descriptor.h>
+
+DEFINE_REF(eDVBService);
+
+eDVBService::eDVBService(): ref(0)
+{
+}
+
+eDVBService::~eDVBService()
+{
+}
+
+DEFINE_REF(eDVBDB);
+
+eDVBDB::eDVBDB()
+{
+ eDebug("---- opening lame channel db");
+ FILE *f=fopen("lamedb", "rt");
+ if (!f)
+ return;
+ char line[256];
+ if ((!fgets(line, 256, f)) || strncmp(line, "eDVB services", 13))
+ {
+ eDebug("not a servicefile");
+ fclose(f);
+ return;
+ }
+ eDebug("reading services");
+ if ((!fgets(line, 256, f)) || strcmp(line, "transponders\n"))
+ {
+ eDebug("services invalid, no transponders");
+ fclose(f);
+ return;
+ }
+
+ // clear all transponders
+
+ while (!feof(f))
+ {
+ if (!fgets(line, 256, f))
+ break;
+ if (!strcmp(line, "end\n"))
+ break;
+ int dvb_namespace=-1, transport_stream_id=-1, original_network_id=-1;
+ sscanf(line, "%x:%x:%x", &dvb_namespace, &transport_stream_id, &original_network_id);
+ if (original_network_id == -1)
+ continue;
+ eDVBChannelID channelid = eDVBChannelID(
+ eDVBNamespace(dvb_namespace),
+ eTransportStreamID(transport_stream_id),
+ eOriginalNetworkID(original_network_id));
+
+ ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
+ while (!feof(f))
+ {
+ fgets(line, 256, f);
+ if (!strcmp(line, "/\n"))
+ break;
+ if (line[1]=='s')
+ {
+ eDVBFrontendParametersSatellite sat;
+ int frequency, symbol_rate, polarisation, fec, orbital_position, inversion;
+ sscanf(line+2, "%d:%d:%d:%d:%d:%d", &frequency, &symbol_rate, &polarisation, &fec, &orbital_position, &inversion);
+ sat.frequency = frequency;
+ sat.symbol_rate = symbol_rate;
+ sat.polarisation = polarisation;
+ sat.fec = fec;
+ sat.orbital_position = orbital_position;
+ sat.inversion = inversion;
+ // ...
+// t.setSatellite(frequency, symbol_rate, polarisation, fec, sat, inversion);
+ feparm->setDVBS(sat);
+ }
+ if (line[1]=='c')
+ {
+ int frequency, symbol_rate, inversion=0, modulation=3;
+ sscanf(line+2, "%d:%d:%d:%d", &frequency, &symbol_rate, &inversion, &modulation);
+// t.setCable(frequency, symbol_rate, inversion, modulation);
+ }
+ }
+ addChannelToList(channelid, feparm);
+ }
+
+ if ((!fgets(line, 256, f)) || strcmp(line, "services\n"))
+ {
+ eDebug("services invalid, no services");
+ return;
+ }
+
+ // clear all services
+
+ int count=0;
+
+ while (!feof(f))
+ {
+ if (!fgets(line, 256, f))
+ break;
+ if (!strcmp(line, "end\n"))
+ break;
+
+ int service_id=-1, dvb_namespace, transport_stream_id=-1, original_network_id=-1, service_type=-1, service_number=-1;
+ sscanf(line, "%x:%x:%x:%x:%d:%d", &service_id, &dvb_namespace, &transport_stream_id, &original_network_id, &service_type, &service_number);
+ if (service_number == -1)
+ continue;
+ ePtr<eDVBService> s = new eDVBService;
+ eServiceReferenceDVB ref =
+ eServiceReferenceDVB(
+ eDVBNamespace(dvb_namespace),
+ eTransportStreamID(transport_stream_id),
+ eOriginalNetworkID(original_network_id),
+ eServiceID(service_id),
+ service_type);
+ count++;
+ fgets(line, 256, f);
+ if (strlen(line))
+ line[strlen(line)-1]=0;
+ s->m_service_name=line;
+ fgets(line, 256, f);
+ if (strlen(line))
+ line[strlen(line)-1]=0;
+
+ eString str=line;
+
+ if (str[1]!=':') // old ... (only service_provider)
+ {
+ s->m_provider_name=line;
+ } else
+ while ((!str.empty()) && str[1]==':') // new: p:, f:, c:%02d...
+ {
+ unsigned int c=str.find(',');
+ char p=str[0];
+ eString v;
+ if (c == eString::npos)
+ {
+ v=str.mid(2);
+ str="";
+ } else
+ {
+ v=str.mid(2, c-2);
+ str=str.mid(c+1);
+ }
+// eDebug("%c ... %s", p, v.c_str());
+ if (p == 'p')
+ s->m_provider_name=v;
+ else if (p == 'f')
+ {
+ sscanf(v.c_str(), "%x", &s->m_flags);
+ } else if (p == 'c')
+ {
+ int cid, val;
+ sscanf(v.c_str(), "%02d%04x", &cid, &val);
+ s->m_cache[cid]=val;
+ } else if (p == 'C')
+ {
+ int val;
+ sscanf(v.c_str(), "%04x", &val);
+ s->m_ca.insert(val);
+ }
+ }
+ addService(ref, s);
+ }
+
+ eDebug("loaded %d services", count);
+
+ fclose(f);
+
+}
+
+eDVBDB::~eDVBDB()
+{
+ eDebug("---- saving lame channel db");
+ FILE *f=fopen("lamedb", "wt");
+ int channels=0, services=0;
+ if (!f)
+ eFatal("couldn't save lame channel db!");
+ fprintf(f, "eDVB services /3/\n");
+ fprintf(f, "transponders\n");
+ for (std::map<eDVBChannelID, channel>::const_iterator i(m_channels.begin());
+ i != m_channels.end(); ++i)
+ {
+ const eDVBChannelID &chid = i->first;
+ const channel &ch = i->second;
+
+ fprintf(f, "%08x:%04x:%04x\n", chid.dvbnamespace.get(),
+ chid.transport_stream_id.get(), chid.original_network_id.get());
+ eDVBFrontendParametersSatellite sat;
+ if (!ch.m_frontendParameters->getDVBS(sat))
+ {
+ fprintf(f, "\ts %d:%d:%d:%d:%d:%d\n",
+ sat.frequency, sat.symbol_rate,
+ sat.polarisation, sat.fec, sat.inversion,
+ sat.orbital_position);
+ }
+ fprintf(f, "/\n");
+ channels++;
+ }
+ fprintf(f, "end\nservices\n");
+
+ for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator i(m_services.begin());
+ i != m_services.end(); ++i)
+ {
+ const eServiceReferenceDVB &s = i->first;
+ fprintf(f, "%04x:%08x:%04x:%04x:%d:%d\n",
+ s.getServiceID().get(), s.getDVBNamespace().get(),
+ s.getOriginalNetworkID().get(), s.getTransportStreamID().get(),
+ s.getServiceType(),
+ 0);
+
+ fprintf(f, "%s\n", i->second->m_service_name.c_str());
+ fprintf(f, "p=%s", i->second->m_provider_name.c_str());
+ for (std::set<int>::const_iterator ca(i->second->m_ca.begin());
+ ca != i->second->m_ca.end(); ++ca)
+ fprintf(f, ",C=%04x", *ca);
+ fprintf(f, "\n");
+ services++;
+ }
+ fprintf(f, "end\nHave a lot of bugs!\n");
+ eDebug("saved %d channels and %d services!", channels, services);
+ fclose(f);
+}
+
+RESULT eDVBDB::addChannelToList(const eDVBChannelID &id, iDVBFrontendParameters *feparm)
+{
+ channel ch;
+ assert(feparm);
+ ch.m_frontendParameters = feparm;
+ m_channels.insert(std::pair<eDVBChannelID, channel>(id, ch));
+ return 0;
+}
+
+RESULT eDVBDB::removeChannel(const eDVBChannelID &id)
+{
+ m_channels.erase(id);
+ return 0;
+}
+
+RESULT eDVBDB::getChannelFrontendData(const eDVBChannelID &id, ePtr<iDVBFrontendParameters> &parm)
+{
+ std::map<eDVBChannelID, channel>::iterator i = m_channels.find(id);
+ if (i == m_channels.end())
+ {
+ parm = 0;
+ return -ENOENT;
+ }
+ parm = i->second.m_frontendParameters;
+ return 0;
+}
+
+RESULT eDVBDB::addService(const eServiceReferenceDVB &serviceref, eDVBService *service)
+{
+ m_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(serviceref, service));
+ return 0;
+}
+
+RESULT eDVBDB::getService(const eServiceReferenceDVB &reference, ePtr<eDVBService> &service)
+{
+ std::map<eServiceReferenceDVB, ePtr<eDVBService> >::iterator i;
+ i = m_services.find(reference);
+ if (i == m_services.end())
+ {
+ service = 0;
+ return -ENOENT;
+ }
+ service = i->second;
+ return 0;
+}
+
diff --git a/lib/dvb/db.h b/lib/dvb/db.h
new file mode 100644
index 00000000..763df7eb
--- /dev/null
+++ b/lib/dvb/db.h
@@ -0,0 +1,48 @@
+#ifndef __db_h
+#define __db_h
+
+#include <lib/dvb/idvb.h>
+#include <set>
+
+class eDVBService: public iObject
+{
+ DECLARE_REF;
+public:
+ eDVBService();
+ eString m_service_name;
+ eString m_provider_name;
+
+ int m_flags;
+ std::set<int> m_ca;
+ std::map<int,int> m_cache;
+ virtual ~eDVBService();
+};
+
+class ServiceDescriptionTable;
+
+class eDVBDB: public virtual iDVBChannelList
+{
+DECLARE_REF;
+private:
+ struct channel
+ {
+ ePtr<iDVBFrontendParameters> m_frontendParameters;
+ };
+
+ std::map<eDVBChannelID, channel> m_channels;
+
+ std::map<eServiceReferenceDVB, ePtr<eDVBService> > m_services;
+public:
+ eDVBDB();
+ virtual ~eDVBDB();
+
+ RESULT addChannelToList(const eDVBChannelID &id, iDVBFrontendParameters *feparm);
+ RESULT removeChannel(const eDVBChannelID &id);
+
+ RESULT getChannelFrontendData(const eDVBChannelID &id, ePtr<iDVBFrontendParameters> &parm);
+
+ RESULT addService(const eServiceReferenceDVB &service, eDVBService *service);
+ RESULT getService(const eServiceReferenceDVB &reference, ePtr<eDVBService> &service);
+};
+
+#endif
diff --git a/lib/dvb/decoder.cpp b/lib/dvb/decoder.cpp
new file mode 100644
index 00000000..e21e4567
--- /dev/null
+++ b/lib/dvb/decoder.cpp
@@ -0,0 +1,245 @@
+#include <lib/dvb/decoder.h>
+#include <linux/dvb/audio.h>
+#include <linux/dvb/video.h>
+#include <linux/dvb/dmx.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+DEFINE_REF(eDVBAudio);
+
+eDVBAudio::eDVBAudio(eDVBDemux *demux, int dev): ref(0), m_demux(demux)
+{
+ char filename[128];
+ sprintf(filename, "/dev/dvb/adapter%d/audio%d", demux->adapter, dev);
+ m_fd = ::open(filename, O_RDWR);
+ if (m_fd < 0)
+ eWarning("%s: %m", filename);
+ sprintf(filename, "/dev/dvb/adapter%d/demux%d", demux->adapter, demux->demux);
+ m_fd_demux = ::open(filename, O_RDWR);
+ if (m_fd_demux < 0)
+ eWarning("%s: %m", filename);
+}
+
+int eDVBAudio::startPid(int pid)
+{
+ eDebug("setting audio pid to %x", pid);
+ if ((m_fd < 0) || (m_fd_demux < 0))
+ return -1;
+ dmx_pes_filter_params pes;
+
+ pes.pid = pid;
+ pes.input = DMX_IN_FRONTEND;
+ pes.output = DMX_OUT_DECODER;
+ pes.pes_type = DMX_PES_AUDIO0;
+ pes.flags = 0;
+ if (::ioctl(m_fd_demux, DMX_SET_PES_FILTER, &pes) < 0)
+ {
+ eWarning("audio: DMX_SET_PES_FILTER: %m");
+ return -errno;
+ }
+ if (::ioctl(m_fd_demux, DMX_START, &pes) < 0)
+ {
+ eWarning("audio: DMX_START: %m");
+ return -errno;
+ }
+
+ if (::ioctl(m_fd, AUDIO_PLAY) < 0)
+ eWarning("audio: AUDIO_PLAY: %m");
+ return 0;
+}
+
+void eDVBAudio::stop()
+{
+ if (::ioctl(m_fd, AUDIO_STOP) < 0)
+ eWarning("audio: AUDIO_STOP: %m");
+ if (::ioctl(m_fd_demux, DMX_STOP) < 0)
+ eWarning("audio: DMX_STOP: %m");
+}
+
+eDVBAudio::~eDVBAudio()
+{
+ if (m_fd >= 0)
+ ::close(m_fd);
+ if (m_fd_demux >= 0)
+ ::close(m_fd_demux);
+}
+
+DEFINE_REF(eDVBVideo);
+
+eDVBVideo::eDVBVideo(eDVBDemux *demux, int dev): ref(0), m_demux(demux)
+{
+ char filename[128];
+ sprintf(filename, "/dev/dvb/adapter%d/video%d", demux->adapter, dev);
+ m_fd = ::open(filename, O_RDWR);
+ if (m_fd < 0)
+ eWarning("%s: %m", filename);
+ sprintf(filename, "/dev/dvb/adapter%d/demux%d", demux->adapter, demux->demux);
+ m_fd_demux = ::open(filename, O_RDWR);
+ if (m_fd_demux < 0)
+ eWarning("%s: %m", filename);
+}
+
+int eDVBVideo::startPid(int pid)
+{
+ if ((m_fd < 0) || (m_fd_demux < 0))
+ return -1;
+ dmx_pes_filter_params pes;
+
+ pes.pid = pid;
+ pes.input = DMX_IN_FRONTEND;
+ pes.output = DMX_OUT_DECODER;
+ pes.pes_type = DMX_PES_VIDEO0;
+ pes.flags = 0;
+ if (::ioctl(m_fd_demux, DMX_SET_PES_FILTER, &pes) < 0)
+ {
+ eWarning("video: DMX_SET_PES_FILTER: %m");
+ return -errno;
+ }
+ if (::ioctl(m_fd_demux, DMX_START, &pes) < 0)
+ {
+ eWarning("video: DMX_START: %m");
+ return -errno;
+ }
+
+ if (::ioctl(m_fd, VIDEO_PLAY) < 0)
+ eWarning("video: VIDEO_PLAY: %m");
+ else
+ eDebug("video ok");
+ return 0;
+}
+
+void eDVBVideo::stop()
+{
+ if (::ioctl(m_fd, VIDEO_STOP) < 0)
+ eWarning("video: VIDEO_STOP: %m");
+ if (::ioctl(m_fd_demux, DMX_STOP) < 0)
+ eWarning("video: DMX_STOP: %m");
+}
+
+eDVBVideo::~eDVBVideo()
+{
+ if (m_fd >= 0)
+ ::close(m_fd);
+ if (m_fd_demux >= 0)
+ ::close(m_fd_demux);
+}
+
+DEFINE_REF(eTSMPEGDecoder);
+
+int eTSMPEGDecoder::setState()
+{
+ int res = 0;
+ eDebug("changed %x", m_changed);
+ if (m_changed & changeAudio)
+ {
+ if (m_audio)
+ m_audio->stop();
+ m_audio = 0;
+ m_audio = new eDVBAudio(m_demux, 0);
+ if (m_audio->startPid(m_apid))
+ {
+ eWarning("audio: startpid failed!");
+ res = -1;
+ }
+ m_changed &= ~changeAudio;
+ }
+ if (m_changed & changeVideo)
+ {
+ if (m_video)
+ m_video->stop();
+ m_video = 0;
+ m_video = new eDVBVideo(m_demux, 0);
+ if (m_video->startPid(m_vpid))
+ {
+ eWarning("video: startpid failed!");
+ res = -1;
+ }
+ m_changed &= ~changeVideo;
+ }
+ return res;
+}
+
+eTSMPEGDecoder::eTSMPEGDecoder(eDVBDemux *demux, int decoder): m_demux(demux)
+{
+}
+
+eTSMPEGDecoder::~eTSMPEGDecoder()
+{
+ m_vpid = m_apid = m_pcrpid = pidNone;
+ m_changed = -1;
+ setState();
+}
+
+RESULT eTSMPEGDecoder::setVideoPID(int vpid)
+{
+ if (m_vpid != vpid)
+ {
+ m_changed |= changeVideo;
+ m_vpid = vpid;
+ }
+ return 0;
+}
+
+RESULT eTSMPEGDecoder::setAudioPID(int apid, int type)
+{
+ if ((m_apid != apid) || (m_atype != type))
+ {
+ m_changed |= changeAudio;
+ m_atype = type;
+ m_apid = apid;
+ }
+ return 0;
+}
+
+RESULT eTSMPEGDecoder::setSyncPCR(int pcrpid)
+{
+ if (m_pcrpid != pcrpid)
+ {
+ m_changed |= changeAudio;
+ m_pcrpid = pcrpid;
+ }
+ return -1;
+}
+
+RESULT eTSMPEGDecoder::setSyncMaster(int who)
+{
+ return -1;
+}
+
+RESULT eTSMPEGDecoder::start()
+{
+ return setState();
+}
+
+RESULT eTSMPEGDecoder::freeze(int cont)
+{
+ return -1;
+}
+
+RESULT eTSMPEGDecoder::unfreeze()
+{
+ return -1;
+}
+
+RESULT eTSMPEGDecoder::setSinglePictureMode(int when)
+{
+ return -1;
+}
+
+RESULT eTSMPEGDecoder::setPictureSkipMode(int what)
+{
+ return -1;
+}
+
+RESULT eTSMPEGDecoder::setSlowMotion(int repeat)
+{
+ return -1;
+}
+
+RESULT eTSMPEGDecoder::setZoom(int what)
+{
+ return -1;
+}
diff --git a/lib/dvb/decoder.h b/lib/dvb/decoder.h
new file mode 100644
index 00000000..6694e9fc
--- /dev/null
+++ b/lib/dvb/decoder.h
@@ -0,0 +1,66 @@
+#ifndef __decoder_h
+#define __decoder_h
+
+#include <lib/base/object.h>
+#include <lib/dvb/demux.h>
+
+class eDVBAudio: public virtual iObject
+{
+DECLARE_REF;
+private:
+ ePtr<eDVBDemux> m_demux;
+ int m_fd, m_fd_demux;
+public:
+ eDVBAudio(eDVBDemux *demux, int dev);
+ int startPid(int pid);
+ void stop();
+ virtual ~eDVBAudio();
+};
+
+class eDVBVideo: public virtual iObject
+{
+DECLARE_REF;
+private:
+ ePtr<eDVBDemux> m_demux;
+ int m_fd, m_fd_demux;
+public:
+ eDVBVideo(eDVBDemux *demux, int dev);
+ int startPid(int pid);
+ void stop();
+ virtual ~eDVBVideo();
+};
+
+class eTSMPEGDecoder: public virtual iTSMPEGDecoder
+{
+DECLARE_REF;
+private:
+ ePtr<eDVBDemux> m_demux;
+ ePtr<eDVBAudio> m_audio;
+ ePtr<eDVBVideo> m_video;
+
+ int m_vpid, m_apid, m_atype, m_pcrpid;
+ enum
+ {
+ changeVideo = 1,
+ changeAudio = 2,
+ changePCR = 4
+ };
+ int m_changed;
+ int setState();
+public:
+ enum { pidNone = -1 };
+ eTSMPEGDecoder(eDVBDemux *demux, int decoder);
+ virtual ~eTSMPEGDecoder();
+ RESULT setVideoPID(int vpid);
+ RESULT setAudioPID(int apid, int type);
+ RESULT setSyncPCR(int pcrpid);
+ RESULT setSyncMaster(int who);
+ RESULT start();
+ RESULT freeze(int cont);
+ RESULT unfreeze();
+ RESULT setSinglePictureMode(int when);
+ RESULT setPictureSkipMode(int what);
+ RESULT setSlowMotion(int repeat);
+ RESULT setZoom(int what);
+};
+#endif
diff --git a/lib/dvb/demux.cpp b/lib/dvb/demux.cpp
new file mode 100644
index 00000000..e1d8bbaf
--- /dev/null
+++ b/lib/dvb/demux.cpp
@@ -0,0 +1,131 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <linux/dvb/dmx.h>
+#include "crc32.h"
+
+#include <lib/base/eerror.h>
+#include <lib/dvb/idvb.h>
+#include <lib/dvb/demux.h>
+#include <lib/dvb/esection.h>
+#include <lib/dvb/decoder.h>
+
+eDVBDemux::eDVBDemux(int adapter, int demux): adapter(adapter), demux(demux), ref(0)
+{
+}
+
+eDVBDemux::~eDVBDemux()
+{
+}
+
+DEFINE_REF(eDVBDemux)
+
+RESULT eDVBDemux::createSectionReader(eMainloop *context, ePtr<iDVBSectionReader> &reader)
+{
+ RESULT res;
+ reader = new eDVBSectionReader(this, context, res);
+ if (res)
+ reader = 0;
+ return res;
+}
+
+RESULT eDVBDemux::getMPEGDecoder(ePtr<iTSMPEGDecoder> &decoder)
+{
+ decoder = new eTSMPEGDecoder(this, 0);
+ return 0;
+}
+
+void eDVBSectionReader::data(int)
+{
+ __u8 data[4096]; // max. section size
+ int r;
+ r = ::read(fd, data, 4096);
+ if(r < 0)
+ {
+ eWarning("ERROR reading section - %m\n");
+ return;
+ }
+ if (checkcrc)
+ {
+ // this check should never happen unless the driver is crappy!
+ unsigned int c;
+ if ((c = crc32((unsigned)-1, data, r)))
+ eFatal("crc32 failed! is %x\n", c);
+ }
+ read(data);
+}
+
+eDVBSectionReader::eDVBSectionReader(eDVBDemux *demux, eMainloop *context, RESULT &res): ref(0), demux(demux)
+{
+ char filename[128];
+ sprintf(filename, "/dev/dvb/adapter%d/demux%d", demux->adapter, demux->demux);
+ fd = ::open(filename, O_RDWR);
+
+ if (fd >= 0)
+ {
+ notifier=new eSocketNotifier(context, fd, eSocketNotifier::Read);
+ CONNECT(notifier->activated, eDVBSectionReader::data);
+ res = 0;
+ } else
+ {
+ perror(filename);
+ res = errno;
+ }
+}
+
+DEFINE_REF(eDVBSectionReader)
+
+eDVBSectionReader::~eDVBSectionReader()
+{
+ if (notifier)
+ delete notifier;
+ if (fd >= 0)
+ ::close(fd);
+}
+
+RESULT eDVBSectionReader::start(const eDVBSectionFilterMask &mask)
+{
+ RESULT res;
+ if (fd < 0)
+ return -ENODEV;
+
+ dmx_sct_filter_params sct;
+
+ sct.pid = mask.pid;
+ sct.timeout = 0;
+ sct.flags = DMX_IMMEDIATE_START;
+ if (mask.flags & eDVBSectionFilterMask::rfCRC)
+ {
+ sct.flags |= DMX_CHECK_CRC;
+ checkcrc = 1;
+ } else
+ checkcrc = 0;
+
+ memcpy(sct.filter.filter, mask.data, DMX_FILTER_SIZE);
+ memcpy(sct.filter.mask, mask.mask, DMX_FILTER_SIZE);
+ memcpy(sct.filter.mode, mask.mode, DMX_FILTER_SIZE);
+
+ res = ::ioctl(fd, DMX_SET_FILTER, &sct);
+ if (!res)
+ active = 1;
+ return res;
+}
+
+RESULT eDVBSectionReader::stop()
+{
+ if (!active)
+ return -1;
+
+ ::ioctl(fd, DMX_STOP);
+
+ return 0;
+}
+
+RESULT eDVBSectionReader::connectRead(const Slot1<void,const __u8*> &r, ePtr<eConnection> &conn)
+{
+ conn = new eConnection(read.connect(r));
+ return 0;
+}
diff --git a/lib/dvb/demux.h b/lib/dvb/demux.h
new file mode 100644
index 00000000..3b4cbede
--- /dev/null
+++ b/lib/dvb/demux.h
@@ -0,0 +1,41 @@
+#ifndef __dvb_demux_h
+#define __dvb_demux_h
+
+#include <lib/dvb/idvb.h>
+#include <lib/dvb/isection.h>
+
+class eDVBDemux: public virtual iDVBDemux
+{
+ int adapter, demux;
+ friend class eDVBSectionReader;
+ friend class eDVBAudio;
+ friend class eDVBVideo;
+public:
+ DECLARE_REF
+ eDVBDemux(int adapter, int demux);
+ virtual ~eDVBDemux();
+ RESULT createSectionReader(eMainloop *context, ePtr<iDVBSectionReader> &reader);
+ RESULT getMPEGDecoder(ePtr<iTSMPEGDecoder> &reader);
+};
+
+class eDVBSectionReader: public virtual iDVBSectionReader, public Object
+{
+ DECLARE_REF
+private:
+ int fd;
+ Signal1<void, const __u8*> read;
+ ePtr<eDVBDemux> demux;
+ int active;
+ int checkcrc;
+ void data(int);
+ eSocketNotifier *notifier;
+public:
+
+ eDVBSectionReader(eDVBDemux *demux, eMainloop *context, RESULT &res);
+ virtual ~eDVBSectionReader();
+ RESULT start(const eDVBSectionFilterMask &mask);
+ RESULT stop();
+ RESULT connectRead(const Slot1<void,const __u8*> &read, ePtr<eConnection> &conn);
+};
+
+#endif
diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp
new file mode 100644
index 00000000..176b07c5
--- /dev/null
+++ b/lib/dvb/dvb.cpp
@@ -0,0 +1,211 @@
+#include <lib/dvb/idvb.h>
+#include <lib/base/eerror.h>
+#include <lib/dvb/dvb.h>
+#include <lib/dvb/sec.h>
+#include <errno.h>
+
+DEFINE_REF(eDVBResourceManager);
+
+eDVBResourceManager *eDVBResourceManager::instance;
+
+eDVBResourceManager::eDVBResourceManager(): ref(0)
+{
+ avail = 1;
+ busy = 0;
+ m_sec = new eDVBSatelliteEquipmentControl;
+ if (!instance)
+ instance = this;
+}
+
+eDVBResourceManager::~eDVBResourceManager()
+{
+ if (instance == this)
+ instance = 0;
+}
+
+RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
+{
+ m_list = list;
+ return 0;
+}
+
+RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
+{
+ list = m_list;
+ if (list)
+ return 0;
+ else
+ return -ENOENT;
+}
+
+
+RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, ePtr<iDVBChannel> &channel)
+{
+ RESULT res;
+ eDVBChannel *ch;
+ channel = ch = new eDVBChannel(this, 0, 0, 0);
+
+ ePtr<iDVBFrontend> fe;
+ if (!channel->getFrontend(fe))
+ fe->setSEC(m_sec);
+
+ res = ch->setChannel(channelid);
+ if (res)
+ {
+ channel = 0;
+ return res;
+ }
+ return 0;
+}
+
+RESULT eDVBResourceManager::allocateRawChannel(ePtr<iDVBChannel> &channel)
+{
+ channel = new eDVBChannel(this, 0, 0, 0);
+ ePtr<iDVBFrontend> fe;
+ if (!channel->getFrontend(fe))
+ fe->setSEC(m_sec);
+
+ return 0;
+}
+
+RESULT eDVBResourceManager::allocatePVRChannel(int caps)
+{
+ return -1; // will nicht, mag nicht, und das interface ist auch kaputt
+}
+
+RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
+{
+ eDebug("add channel %p", ch);
+ m_active_channels.insert(std::pair<eDVBChannelID,eDVBChannel*>(chid, ch));
+ return 0;
+}
+
+RESULT eDVBResourceManager::removeChannel(const eDVBChannelID &chid, eDVBChannel *)
+{
+ int cnt = m_active_channels.erase(chid);
+ eDebug("remove channel: removed %d channels", cnt);
+ ASSERT(cnt <= 1);
+ if (cnt == 1)
+ return 0;
+ return -ENOENT;
+}
+
+eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, int adapter, int frontend, int demux): eDVBDemux(adapter, demux), m_state(state_idle), m_mgr(mgr)
+{
+ if (frontend >= 0)
+ {
+ int ok;
+ m_frontend = new eDVBFrontend(adapter, frontend, ok);
+ if (!ok)
+ {
+ eDebug("warning, frontend failed");
+ m_frontend = 0;
+ return;
+ }
+ m_frontend->connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
+ }
+}
+
+eDVBChannel::~eDVBChannel()
+{
+ if (m_channel_id)
+ m_mgr->removeChannel(m_channel_id, this);
+}
+
+void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
+{
+ eDebug("fe state changed!");
+ int state, ourstate = 0;
+ if (fe->getState(state))
+ return;
+
+ if (state == iDVBFrontend::stateLock)
+ {
+ eDebug("OURSTATE: ok");
+ ourstate = state_ok;
+ } else if (state == iDVBFrontend::stateTuning)
+ {
+ eDebug("OURSTATE: tuning");
+ ourstate = state_tuning;
+ } else if (state == iDVBFrontend::stateFailed)
+ {
+ eDebug("OURSTATE: failed/unavailable");
+ ourstate = state_unavailable;
+ } else
+ eFatal("state unknown");
+
+ if (ourstate != m_state)
+ {
+ m_state = ourstate;
+ m_stateChanged(this);
+ }
+}
+
+RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid)
+{
+ ePtr<iDVBChannelList> list;
+
+ if (m_mgr->getChannelList(list))
+ {
+ eDebug("no channel list set!");
+ return -ENOENT;
+ }
+
+ eDebug("tuning to chid: ns: %08x tsid %04x onid %04x",
+ channelid.dvbnamespace.get(), channelid.transport_stream_id.get(), channelid.original_network_id.get());
+
+
+ ePtr<iDVBFrontendParameters> feparm;
+ if (list->getChannelFrontendData(channelid, feparm))
+ {
+ eDebug("channel not found!");
+ return -ENOENT;
+ }
+ eDebug("allocateChannel: channel found..");
+
+ if (!m_frontend)
+ {
+ eDebug("no frontend to tune!");
+ return -ENODEV;
+ }
+
+ if (m_channel_id)
+ m_mgr->removeChannel(m_channel_id, this);
+ m_channel_id = channelid;
+ m_mgr->addChannel(m_channel_id, this);
+ m_state = state_tuning;
+ eDebug("%p", &*feparm);
+ return m_frontend->tune(*feparm);
+}
+
+RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
+{
+ connection = new eConnection( m_stateChanged.connect(stateChange) );
+ return 0;
+}
+
+RESULT eDVBChannel::getState(int &state)
+{
+ state = m_state;
+ return 0;
+}
+
+RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
+{
+ return -1;
+}
+
+RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux)
+{
+ demux = this;
+ return 0;
+}
+
+RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
+{
+ frontend = m_frontend;
+ if (frontend)
+ return 0;
+ else
+ return -ENODEV;
+}
diff --git a/lib/dvb/dvb.h b/lib/dvb/dvb.h
new file mode 100644
index 00000000..f6aae238
--- /dev/null
+++ b/lib/dvb/dvb.h
@@ -0,0 +1,67 @@
+#ifndef __dvb_dvb_h
+#define __dvb_dvb_h
+
+#include <lib/dvb/idvb.h>
+#include <lib/dvb/demux.h>
+#include <lib/dvb/frontend.h>
+#include <connection.h>
+
+class eDVBChannel;
+
+class eDVBResourceManager: public virtual iDVBResourceManager
+{
+ DECLARE_REF;
+ int avail, busy;
+ struct adapter
+ {
+ eSmartPtrList<eDVBFrontend> fe;
+ eSmartPtrList<eDVBDemux> demux;
+ };
+ std::multimap<eDVBChannelID,eDVBChannel*> m_active_channels;
+ ePtr<iDVBChannelList> m_list;
+ ePtr<iDVBSatelliteEquipmentControl> m_sec;
+ static eDVBResourceManager *instance;
+public:
+ eDVBResourceManager();
+ virtual ~eDVBResourceManager();
+
+ static RESULT getInstance(ePtr<eDVBResourceManager> &ptr) { if (instance) { ptr = instance; return 0; } return -1; }
+
+ RESULT setChannelList(iDVBChannelList *list);
+ RESULT getChannelList(ePtr<iDVBChannelList> &list);
+
+ RESULT allocateChannel(const eDVBChannelID &channelid, ePtr<iDVBChannel> &channel);
+ RESULT allocateRawChannel(ePtr<iDVBChannel> &channel);
+ RESULT allocatePVRChannel(int caps);
+
+ RESULT addChannel(const eDVBChannelID &chid, eDVBChannel *ch);
+ RESULT removeChannel(const eDVBChannelID &chid, eDVBChannel *ch);
+};
+
+class eDVBChannel: public virtual iDVBChannel, public virtual eDVBDemux, public Object
+{
+ ePtr<eDVBFrontend> m_frontend;
+ ePtr<iDVBFrontendParameters> m_current_frontend_parameters;
+ eDVBChannelID m_channel_id;
+ Signal1<void,iDVBChannel*> m_stateChanged;
+ int m_state;
+ ePtr<eDVBResourceManager> m_mgr;
+
+ void frontendStateChanged(iDVBFrontend*fe);
+ ePtr<eConnection> m_conn_frontendStateChanged;
+public:
+ eDVBChannel(eDVBResourceManager *mgr, int adapter, int frontend, int demux);
+ virtual ~eDVBChannel();
+
+ /* only for managed channels */
+ RESULT setChannel(const eDVBChannelID &id);
+
+ RESULT connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection);
+ RESULT getState(int &state);
+
+ RESULT setCIRouting(const eDVBCIRouting &routing);
+ RESULT getDemux(ePtr<iDVBDemux> &demux);
+ RESULT getFrontend(ePtr<iDVBFrontend> &frontend);
+};
+
+#endif
diff --git a/lib/dvb/esection.cpp b/lib/dvb/esection.cpp
new file mode 100644
index 00000000..08cb49be
--- /dev/null
+++ b/lib/dvb/esection.cpp
@@ -0,0 +1,130 @@
+#include <lib/dvb/esection.h>
+#include <lib/base/eerror.h>
+
+void eGTable::sectionRead(const __u8 *d)
+{
+ unsigned int last_section_number = d[7];
+ m_table.flags &= ~eDVBTableSpec::tfAnyVersion;
+ m_table.flags |= eDVBTableSpec::tfThisVersion;
+ m_table.version = (d[5]>>1)&0x1F;
+
+
+ if (createTable(d[6], d, last_section_number + 1))
+ {
+ if (m_timeout)
+ m_timeout->stop();
+ m_reader->stop();
+ ready = 1;
+ tableReady(error);
+ } else if ((m_table.flags & eDVBTableSpec::tfHaveTimeout) && m_timeout)
+ m_timeout->start(m_table.timeout, 1); // reset timeout
+}
+
+void eGTable::timeout()
+{
+ eDebug("timeout!");
+ m_reader->stop();
+ ready = 1;
+ error = -1;
+ tableReady(error);
+}
+
+eGTable::eGTable():
+ ref(0), m_timeout(0), error(0)
+{
+}
+
+DEFINE_REF(eGTable);
+
+RESULT eGTable::start(iDVBSectionReader *reader, const eDVBTableSpec &table)
+{
+ RESULT res;
+ m_table = table;
+
+ m_reader = reader;
+ m_reader->connectRead(slot(*this, &eGTable::sectionRead), m_sectionRead_conn);
+
+ // setup filter struct
+ eDVBSectionFilterMask mask;
+
+ memset(&mask, 0, sizeof(mask));
+ mask.pid = m_table.pid;
+ mask.flags = 0;
+
+ if (m_table.flags & eDVBTableSpec::tfCheckCRC)
+ mask.flags |= eDVBSectionFilterMask::rfCRC;
+
+ if (m_table.flags & eDVBTableSpec::tfHaveTID)
+ {
+ mask.data[0] = m_table.tid;
+ mask.mask[0] = 0xFF;
+ }
+
+ if (m_table.flags & eDVBTableSpec::tfHaveTIDExt)
+ {
+ mask.data[1] = m_table.tidext >> 8;
+ mask.data[2] = m_table.tidext;
+ mask.mask[1] = 0xFF;
+ mask.mask[2] = 0xFF;
+ }
+
+ if (!(m_table.flags & eDVBTableSpec::tfAnyVersion))
+ {
+ eDebug("doing version filtering");
+ mask.data[3] |= (m_table.version << 1)|1;
+ mask.mask[3] |= 0x3f;
+ if (!(m_table.flags & eDVBTableSpec::tfThisVersion))
+ mask.mode[3] |= 0x3e; // negative filtering
+ } else
+ eDebug("no version filtering");
+
+ eDebug("%04x: %02x %02x %02x %02x %02x %02x",
+ mask.pid,
+ mask.data[0], mask.data[1], mask.data[2],
+ mask.data[3], mask.data[4], mask.data[5]);
+ eDebug("mask: %02x %02x %02x %02x %02x %02x",
+ mask.mask[0], mask.mask[1], mask.mask[2],
+ mask.mask[3], mask.mask[4], mask.mask[5]);
+ eDebug("mode: %02x %02x %02x %02x %02x %02x",
+ mask.mode[0], mask.mode[1], mask.mode[2],
+ mask.mode[3], mask.mode[4], mask.mode[5]);
+
+ if ((res = m_reader->start(mask)))
+ {
+ eDebug("reader failed to start.");
+ return res;
+ }
+
+ if (m_table.flags & eDVBTableSpec::tfHaveTimeout)
+ {
+ eDebug("have timeout, %d", m_table.timeout);
+ if (m_timeout)
+ delete m_timeout;
+ m_timeout = new eTimer(eApp);
+ m_timeout->start(m_table.timeout, 1); // begin timeout
+ CONNECT(m_timeout->timeout, eGTable::timeout);
+ }
+
+ return 0;
+}
+
+RESULT eGTable::start(iDVBDemux *demux, const eDVBTableSpec &table)
+{
+ int res;
+ ePtr<iDVBSectionReader> reader;
+ res = demux->createSectionReader(eApp, reader);
+ if (res)
+ return res;
+ return start(reader, table);
+}
+
+eGTable::~eGTable()
+{
+ if (m_timeout)
+ delete m_timeout;
+}
+
+void eAUGTable::slotTableReady(int error)
+{
+ getNext(error);
+}
diff --git a/lib/dvb/esection.h b/lib/dvb/esection.h
new file mode 100644
index 00000000..ca63c184
--- /dev/null
+++ b/lib/dvb/esection.h
@@ -0,0 +1,189 @@
+#ifndef __esection_h
+#define __esection_h
+
+#include <lib/dvb/isection.h>
+#include <set>
+
+class eGTable: public virtual iObject, public Object
+{
+DECLARE_REF;
+private:
+ ePtr<iDVBSectionReader> m_reader;
+ eDVBTableSpec m_table;
+
+ eTimer *m_timeout;
+
+ void sectionRead(const __u8 *data);
+ void timeout();
+ ePtr<eConnection> m_sectionRead_conn;
+protected:
+ virtual int createTable(int nr, const __u8 *data, unsigned int max)=0;
+public:
+ Signal1<void, int> tableReady;
+ eGTable();
+ RESULT start(iDVBSectionReader *reader, const eDVBTableSpec &table);
+ RESULT start(iDVBDemux *reader, const eDVBTableSpec &table);
+ RESULT getSpec(eDVBTableSpec &spec) { spec = m_table; return 0; }
+ virtual ~eGTable();
+ int error;
+ int ready;
+};
+
+template <class Section>
+class eTable: public eGTable
+{
+private:
+ std::vector<Section*> sections;
+ std::set<int> avail;
+protected:
+ int createTable(int nr, const __u8 *data, unsigned int max)
+ {
+ if (avail.find(nr) != avail.end())
+ delete sections[nr];
+ sections.resize(max);
+
+
+ sections[nr] = new Section(data);
+ avail.insert(nr);
+
+ for (unsigned int i = 0; i < max; ++i)
+ if (avail.find(i) != avail.end())
+ printf("+");
+ else
+ printf("-");
+
+ printf(" %d/%d\n", avail.size(), max);
+
+ if (avail.size() == max)
+ return 1;
+ else
+ return 0;
+ }
+public:
+ std::vector<Section*> &getSections() { return sections; }
+ eTable(): eGTable()
+ {
+ }
+ ~eTable()
+ {
+ for (typename std::vector<Section*>::iterator i(sections.begin()); i != sections.end(); ++i)
+ delete *i;
+ }
+};
+
+class eAUGTable: public Object
+{
+protected:
+ void slotTableReady(int);
+public:
+ Signal1<void, int> tableReady;
+ virtual void getNext(int err)=0;
+};
+
+template <class Table>
+class eAUTable: public eAUGTable
+{
+ ePtr<Table> current, next; // current is READY AND ERRORFREE, next is not yet ready
+ int first;
+ ePtr<iDVBDemux> m_demux;
+ eMainloop *ml;
+public:
+
+ eAUTable()
+ {
+ }
+
+ ~eAUTable()
+ {
+ current=next=0;
+ }
+
+ int begin(eMainloop *m, const eDVBTableSpec &spec, ePtr<iDVBDemux> demux)
+ {
+ ml = m;
+ m_demux = demux;
+ first= 1;
+ current = 0;
+ next = new Table();
+ CONNECT(next->tableReady, eAUTable::slotTableReady);
+ next->start(demux, spec);
+ return 0;
+ }
+
+ int get()
+ {
+ if (current)
+ {
+ /*emit*/ tableReady(0);
+ return 0;
+ } else if (!next)
+ {
+ /*emit*/ tableReady(-1);
+ return 0;
+ } else
+ return 1;
+ }
+
+ RESULT getCurrent(ePtr<Table> &ptr)
+ {
+ if (!current)
+ return -1;
+ ptr = current;
+ return 0;
+ }
+
+#if 0
+ void abort()
+ {
+ eDebug("eAUTable: aborted!");
+ if (next)
+ next->abort();
+ delete next;
+ next=0;
+ }
+#endif
+
+ int ready()
+ {
+ return !!current;
+ }
+
+ void inject(Table *t)
+ {
+ next=t;
+ getNext(0);
+ }
+
+ void getNext(int error)
+ {
+ current = 0;
+ if (error)
+ {
+ next=0;
+ if (first)
+ /*emit*/ tableReady(error);
+ first=0;
+ return;
+ } else
+ current=next;
+
+ next=0;
+ first=0;
+
+ assert(current->ready);
+
+ /*emit*/ tableReady(0);
+
+ eDVBTableSpec spec;
+
+ if (current && (!current->getSpec(spec)))
+ {
+ next = new Table();
+ CONNECT(next->tableReady, eAUTable::slotTableReady);
+ spec.flags &= ~(eDVBTableSpec::tfAnyVersion|eDVBTableSpec::tfThisVersion|eDVBTableSpec::tfHaveTimeout);
+ next->eGTable::start(m_demux, spec);
+ }
+ }
+};
+
+#endif
diff --git a/lib/dvb/frontend.cpp b/lib/dvb/frontend.cpp
new file mode 100644
index 00000000..c51eeea7
--- /dev/null
+++ b/lib/dvb/frontend.cpp
@@ -0,0 +1,465 @@
+#include <lib/dvb/dvb.h>
+#include <lib/base/eerror.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+#include <linux/dvb/frontend.h>
+
+#include <lib/dvb_si/satellite_delivery_system_descriptor.h>
+#include <lib/dvb_si/cable_delivery_system_descriptor.h>
+#include <lib/dvb_si/terrestrial_delivery_system_descriptor.h>
+
+void eDVBFrontendParametersSatellite::set(const SatelliteDeliverySystemDescriptor &descriptor)
+{
+ frequency = descriptor.getFrequency() * 10;
+ symbol_rate = descriptor.getSymbolRate() * 100;
+ switch (descriptor.getPolarization())
+ {
+ case 0:
+ polarisation = Polarisation::Horizontal;
+ break;
+ case 1:
+ polarisation = Polarisation::Vertical;
+ break;
+ case 2:
+ polarisation = Polarisation::CircularLeft;
+ break;
+ case 3:
+ polarisation = Polarisation::CircularRight;
+ break;
+ }
+ switch (descriptor.getFecInner())
+ {
+ case 1:
+ fec = FEC::f1_2;
+ break;
+ case 2:
+ fec = FEC::f2_3;
+ break;
+ case 3:
+ fec = FEC::f3_4;
+ break;
+ case 4:
+ fec = FEC::f5_6;
+ break;
+ case 5:
+ fec = FEC::f7_8;
+ break;
+ case 0xF:
+ fec = FEC::fNone;
+ break;
+ default:
+ fec = FEC::fAuto;
+ break;
+ }
+ inversion = Inversion::Unknown;
+ orbital_position = ((descriptor.getOrbitalPosition() >> 12) & 0xF) * 1000;
+ orbital_position += ((descriptor.getOrbitalPosition() >> 8) & 0xF) * 100;
+ orbital_position += ((descriptor.getOrbitalPosition() >> 4) & 0xF) * 10;
+ orbital_position += ((descriptor.getOrbitalPosition()) & 0xF);
+ if (orbital_position && (!descriptor.getWestEastFlag()))
+ orbital_position = 3600 - orbital_position;
+}
+
+void eDVBFrontendParametersCable::set(const CableDeliverySystemDescriptor &descriptor)
+{
+ eFatal("nyi");
+}
+
+void eDVBFrontendParametersTerrestrial::set(const TerrestrialDeliverySystemDescriptor &)
+{
+ eFatal("nyi");
+}
+
+eDVBFrontendParameters::eDVBFrontendParameters(): ref(0), m_type(-1)
+{
+}
+
+DEFINE_REF(eDVBFrontendParameters);
+
+RESULT eDVBFrontendParameters::getSystem(int &t) const
+{
+ if (m_type == -1)
+ return -1;
+ t = m_type;
+ return 0;
+}
+
+RESULT eDVBFrontendParameters::getDVBS(eDVBFrontendParametersSatellite &p) const
+{
+ if (m_type != iDVBFrontend::feSatellite)
+ return -1;
+ p = sat;
+ return 0;
+}
+
+RESULT eDVBFrontendParameters::getDVBC(eDVBFrontendParametersCable &p) const
+{
+ if (m_type != iDVBFrontend::feCable)
+ return -1;
+ p = cable;
+ return 0;
+}
+
+RESULT eDVBFrontendParameters::getDVBT(eDVBFrontendParametersTerrestrial &p) const
+{
+ if (m_type != iDVBFrontend::feTerrestrial)
+ return -1;
+ p = terrestrial;
+ return 0;
+}
+
+RESULT eDVBFrontendParameters::setDVBS(eDVBFrontendParametersSatellite &p)
+{
+ sat = p;
+ m_type = iDVBFrontend::feSatellite;
+ return 0;
+}
+
+RESULT eDVBFrontendParameters::setDVBC(eDVBFrontendParametersCable &p)
+{
+ cable = p;
+ m_type = iDVBFrontend::feCable;
+ return 0;
+}
+
+RESULT eDVBFrontendParameters::setDVBT(eDVBFrontendParametersTerrestrial &p)
+{
+ terrestrial = p;
+ m_type = iDVBFrontend::feTerrestrial;
+ return 0;
+}
+
+RESULT eDVBFrontendParameters::calculateDifference(const iDVBFrontendParameters *parm, int &diff) const
+{
+ if (!parm)
+ return -1;
+ int type;
+ if (parm->getSystem(type))
+ return -1;
+ if (type != m_type)
+ {
+ diff = 1<<30; // big difference
+ return 0;
+ }
+
+ switch (type)
+ {
+ case iDVBFrontend::feSatellite:
+ {
+ eDVBFrontendParametersSatellite osat;
+ if (parm->getDVBS(osat))
+ return -2;
+
+ if (sat.orbital_position != osat.orbital_position)
+ diff = 1<<29;
+ else if (sat.polarisation != osat.polarisation)
+ diff = 1<<28;
+ else
+ diff = abs(sat.frequency - osat.frequency);
+ return 0;
+ }
+ case iDVBFrontend::feCable:
+ case iDVBFrontend::feTerrestrial:
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+RESULT eDVBFrontendParameters::getHash(unsigned long &hash) const
+{
+ switch (m_type)
+ {
+ case iDVBFrontend::feSatellite:
+ {
+ hash = sat.frequency & 0xFFFF;
+ hash |= sat.orbital_position << 16;
+ return 0;
+ }
+ case iDVBFrontend::feCable:
+ case iDVBFrontend::feTerrestrial:
+ default:
+ return -1;
+ }
+}
+
+DEFINE_REF(eDVBFrontend);
+
+eDVBFrontend::eDVBFrontend(int adap, int fe, int &ok): ref(0), m_type(-1)
+{
+ char filename[128];
+ int result;
+ dvb_frontend_info fe_info;
+
+ m_sn = 0;
+ m_timeout = 0;
+
+ sprintf(filename, "/dev/dvb/adapter%d/frontend%d", adap, fe);
+ eDebug("opening frontend.");
+ m_fd = ::open(filename, O_RDWR|O_NONBLOCK);
+ if (m_fd < 0)
+ {
+ eWarning("failed! (%s) %m", filename);
+ ok = 0;
+ return;
+ }
+
+ result = ::ioctl(m_fd, FE_GET_INFO, &fe_info);
+
+ if (result < 0) {
+ eWarning("ioctl FE_GET_INFO failed");
+ ::close(m_fd);
+ m_fd = -1;
+ ok = 0;
+ return;
+ }
+
+ switch (fe_info.type)
+ {
+ case FE_QPSK:
+ m_type = feSatellite;
+ break;
+ case FE_QAM:
+ m_type = feCable;
+ break;
+ case FE_OFDM:
+ m_type = feTerrestrial;
+ break;
+ default:
+ eWarning("unknown frontend type.");
+ ::close(m_fd);
+ m_fd = -1;
+ ok = 0;
+ return;
+ }
+ eDebug("detected %s frontend", "satellite\0cable\0 terrestrial"+feSatellite*9);
+ ok = 1;
+
+ m_sn = new eSocketNotifier(eApp, m_fd, eSocketNotifier::Read);
+ CONNECT(m_sn->activated, eDVBFrontend::feEvent);
+ m_sn->start();
+
+ m_timeout = new eTimer(eApp);
+ CONNECT(m_timeout->timeout, eDVBFrontend::timeout);
+
+ return;
+}
+
+eDVBFrontend::~eDVBFrontend()
+{
+ if (m_fd >= 0)
+ ::close(m_fd);
+ if (m_sn)
+ delete m_sn;
+ if (m_timeout)
+ delete m_timeout;
+}
+
+void eDVBFrontend::feEvent(int w)
+{
+ while (1)
+ {
+ dvb_frontend_event event;
+ int res;
+ int state;
+ res = ::ioctl(m_fd, FE_GET_EVENT, &event);
+
+ if (res && (errno == EAGAIN))
+ break;
+
+ if (res)
+ {
+ eWarning("FE_GET_EVENT failed! %m");
+ return;
+ }
+
+ if (w < 0)
+ continue;
+
+ eDebug("fe event: status %x, inversion %s", event.status, (event.parameters.inversion == INVERSION_ON) ? "on" : "off");
+ if (event.status & FE_HAS_LOCK)
+ {
+ state = stateLock;
+ } else
+ {
+ if (m_tuning)
+ state = stateTuning;
+ else
+ state = stateFailed;
+ }
+ if (m_state != state)
+ {
+ m_state = state;
+ m_stateChanged(this);
+ }
+ }
+}
+
+void eDVBFrontend::timeout()
+{
+ int state;
+ if (m_state == stateTuning)
+ {
+ state = stateFailed;
+ eDebug("DVBFrontend: timeout");
+ if (m_state != state)
+ {
+ m_state = state;
+ m_stateChanged(this);
+ }
+ } else
+ m_tuning = 0;
+}
+
+RESULT eDVBFrontend::getFrontendType(int &t)
+{
+ if (m_type == -1)
+ return -ENODEV;
+ t = m_type;
+ return 0;
+}
+
+RESULT eDVBFrontend::tune(const iDVBFrontendParameters &where)
+{
+ if (m_type == -1)
+ return -ENODEV;
+
+ dvb_frontend_parameters parm;
+
+ feEvent(-1);
+
+ switch (m_type)
+ {
+ case feSatellite:
+ {
+ int res;
+ eDVBFrontendParametersSatellite feparm;
+ if (where.getDVBS(feparm))
+ {
+ eDebug("no dvbs data!");
+ return -EINVAL;
+ }
+ if (!m_sec)
+ {
+ eWarning("no SEC module active!");
+ return -ENOENT;
+ }
+
+ res = m_sec->prepare(*this, parm, feparm);
+ if (res)
+ return res;
+
+ eDebug("tuning to %d mhz", parm.frequency/1000);
+ break;
+ }
+ case feCable:
+ {
+ eDVBFrontendParametersCable feparm;
+ if (where.getDVBC(feparm))
+ return -EINVAL;
+ eFatal("cable tuning nyi");
+ }
+ case feTerrestrial:
+ {
+ eDVBFrontendParametersTerrestrial feparm;
+ if (where.getDVBT(feparm))
+ return -EINVAL;
+ eFatal("terrestrial tuning nyi");
+ }
+ }
+
+ if (ioctl(m_fd, FE_SET_FRONTEND, &parm) == -1)
+ {
+ perror("FE_SET_FRONTEND failed");
+ return errno;
+ }
+
+ if (m_state != stateTuning)
+ {
+ m_tuning = 1;
+ m_state = stateTuning;
+ m_stateChanged(this);
+ }
+
+ m_timeout->start(5000, 1); // 5 sec timeout. TODO: symbolrate dependent
+
+ return 0;
+}
+
+RESULT eDVBFrontend::connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)
+{
+ connection = new eConnection(m_stateChanged.connect(stateChange));
+ return 0;
+}
+
+RESULT eDVBFrontend::setVoltage(int voltage)
+{
+ fe_sec_voltage_t vlt;
+
+ switch (voltage)
+ {
+ case voltageOff:
+ vlt = SEC_VOLTAGE_OFF;
+ break;
+ case voltage13:
+ vlt = SEC_VOLTAGE_13;
+ break;
+ case voltage18:
+ vlt = SEC_VOLTAGE_18;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ return ::ioctl(m_fd, FE_SET_VOLTAGE, vlt);
+}
+
+RESULT eDVBFrontend::getState(int &state)
+{
+ state = m_state;
+ return 0;
+}
+
+RESULT eDVBFrontend::setTone(int t)
+{
+ fe_sec_tone_mode_t tone;
+
+ switch (t)
+ {
+ case toneOn:
+ tone = SEC_TONE_ON;
+ break;
+ case toneOff:
+ tone = SEC_TONE_OFF;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ return ::ioctl(m_fd, FE_SET_TONE, tone);
+}
+
+RESULT eDVBFrontend::sendDiseqc(const eDVBDiseqcCommand &diseqc)
+{
+ struct dvb_diseqc_master_cmd cmd;
+ if (::ioctl(m_fd, FE_SET_TONE, SEC_TONE_OFF))
+ return -EINVAL;
+ usleep(15 * 1000);
+ memcpy(cmd.msg, diseqc.data, diseqc.len);
+ cmd.msg_len = diseqc.len;
+
+ if (::ioctl(m_fd, FE_DISEQC_SEND_MASTER_CMD, &cmd))
+ return -EINVAL;
+ usleep(15 * 1000);
+ eDebug("diseqc ok");
+ return 0;
+}
+
+RESULT eDVBFrontend::setSEC(iDVBSatelliteEquipmentControl *sec)
+{
+ m_sec = sec;
+ return 0;
+}
diff --git a/lib/dvb/frontend.h b/lib/dvb/frontend.h
new file mode 100644
index 00000000..ee7f945a
--- /dev/null
+++ b/lib/dvb/frontend.h
@@ -0,0 +1,61 @@
+#ifndef __dvb_frontend_h
+#define __dvb_frontend_h
+
+#include <lib/dvb/idvb.h>
+
+class eDVBFrontendParameters: public virtual iDVBFrontendParameters
+{
+ DECLARE_REF;
+ union
+ {
+ eDVBFrontendParametersSatellite sat;
+ eDVBFrontendParametersCable cable;
+ eDVBFrontendParametersTerrestrial terrestrial;
+ };
+ int m_type;
+public:
+ eDVBFrontendParameters();
+
+ RESULT getSystem(int &type) const;
+ RESULT getDVBS(eDVBFrontendParametersSatellite &p) const;
+ RESULT getDVBC(eDVBFrontendParametersCable &p) const;
+ RESULT getDVBT(eDVBFrontendParametersTerrestrial &p) const;
+
+ RESULT setDVBS(eDVBFrontendParametersSatellite &p);
+ RESULT setDVBC(eDVBFrontendParametersCable &p);
+ RESULT setDVBT(eDVBFrontendParametersTerrestrial &p);
+
+ RESULT calculateDifference(const iDVBFrontendParameters *parm, int &diff) const;
+
+ RESULT getHash(unsigned long &hash) const;
+};
+
+class eDVBFrontend: public virtual iDVBFrontend, public Object
+{
+ DECLARE_REF;
+ int m_type;
+ int m_fd;
+ int m_state;
+ Signal1<void,iDVBFrontend*> m_stateChanged;
+ ePtr<iDVBSatelliteEquipmentControl> m_sec;
+ eSocketNotifier *m_sn;
+ int m_tuning;
+ eTimer *m_timeout;
+
+ void feEvent(int);
+ void timeout();
+public:
+ eDVBFrontend(int adap, int fe, int &ok);
+ virtual ~eDVBFrontend();
+
+ RESULT getFrontendType(int &type);
+ RESULT tune(const iDVBFrontendParameters &where);
+ RESULT connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection);
+ RESULT getState(int &state);
+ RESULT setTone(int tone);
+ RESULT setVoltage(int voltage);
+ RESULT sendDiseqc(const eDVBDiseqcCommand &diseqc);
+ RESULT setSEC(iDVBSatelliteEquipmentControl *sec);
+};
+
+#endif
diff --git a/lib/dvb/idvb.h b/lib/dvb/idvb.h
new file mode 100644
index 00000000..c4ae488d
--- /dev/null
+++ b/lib/dvb/idvb.h
@@ -0,0 +1,354 @@
+#ifndef __dvb_idvb_h
+#define __dvb_idvb_h
+
+#include <lib/base/object.h>
+#include <lib/base/ebase.h>
+#include <lib/service/service.h>
+#include <libsig_comp.h>
+#include <connection.h>
+
+ // bitte KEINE operator int() definieren, sonst bringt das ganze nix!
+struct eTransportStreamID
+{
+private:
+ int v;
+public:
+ int get() const { return v; }
+ eTransportStreamID(int i): v(i) { }
+ eTransportStreamID(): v(-1) { }
+ bool operator == (const eTransportStreamID &c) const { return v == c.v; }
+ bool operator != (const eTransportStreamID &c) const { return v != c.v; }
+ bool operator < (const eTransportStreamID &c) const { return v < c.v; }
+ bool operator > (const eTransportStreamID &c) const { return v > c.v; }
+};
+
+struct eServiceID
+{
+private:
+ int v;
+public:
+ int get() const { return v; }
+ eServiceID(int i): v(i) { }
+ eServiceID(): v(-1) { }
+ bool operator == (const eServiceID &c) const { return v == c.v; }
+ bool operator != (const eServiceID &c) const { return v != c.v; }
+ bool operator < (const eServiceID &c) const { return v < c.v; }
+ bool operator > (const eServiceID &c) const { return v > c.v; }
+};
+
+struct eOriginalNetworkID
+{
+private:
+ int v;
+public:
+ int get() const { return v; }
+ eOriginalNetworkID(int i): v(i) { }
+ eOriginalNetworkID(): v(-1) { }
+ bool operator == (const eOriginalNetworkID &c) const { return v == c.v; }
+ bool operator != (const eOriginalNetworkID &c) const { return v != c.v; }
+ bool operator < (const eOriginalNetworkID &c) const { return v < c.v; }
+ bool operator > (const eOriginalNetworkID &c) const { return v > c.v; }
+};
+
+struct eDVBNamespace
+{
+private:
+ int v;
+public:
+ int get() const { return v; }
+ eDVBNamespace(int i): v(i) { }
+ eDVBNamespace(): v(-1) { }
+ bool operator == (const eDVBNamespace &c) const { return v == c.v; }
+ bool operator != (const eDVBNamespace &c) const { return v != c.v; }
+ bool operator < (const eDVBNamespace &c) const { return v < c.v; }
+ bool operator > (const eDVBNamespace &c) const { return v > c.v; }
+};
+
+struct eDVBChannelID
+{
+ eDVBNamespace dvbnamespace;
+ eTransportStreamID transport_stream_id;
+ eOriginalNetworkID original_network_id;
+ bool operator<(const eDVBChannelID &c) const
+ {
+ if (dvbnamespace < c.dvbnamespace)
+ return 1;
+ else if (dvbnamespace == c.dvbnamespace)
+ {
+ if (original_network_id < c.original_network_id)
+ return 1;
+ else if (original_network_id == c.original_network_id)
+ if (transport_stream_id < c.transport_stream_id)
+ return 1;
+ }
+ return 0;
+ }
+ eDVBChannelID(eDVBNamespace dvbnamespace, eTransportStreamID tsid, eOriginalNetworkID onid):
+ dvbnamespace(dvbnamespace), transport_stream_id(tsid), original_network_id(onid)
+ {
+ }
+ eDVBChannelID():
+ dvbnamespace(-1), transport_stream_id(-1), original_network_id(-1)
+ {
+ }
+ operator bool() const
+ {
+ return (dvbnamespace != -1) && (transport_stream_id != -1) && (original_network_id != -1);
+ }
+};
+
+struct eServiceReferenceDVB: public eServiceReference
+{
+ int getServiceType() const { return data[0]; }
+ void setServiceType(int service_type) { data[0]=service_type; }
+
+ eServiceID getServiceID() const { return eServiceID(data[1]); }
+ void setServiceID(eServiceID service_id) { data[1]=service_id.get(); }
+
+ eTransportStreamID getTransportStreamID() const { return eTransportStreamID(data[2]); }
+ void setTransportStreamID(eTransportStreamID transport_stream_id) { data[2]=transport_stream_id.get(); }
+
+ eOriginalNetworkID getOriginalNetworkID() const { return eOriginalNetworkID(data[3]); }
+ void setOriginalNetworkID(eOriginalNetworkID original_network_id) { data[3]=original_network_id.get(); }
+
+ eDVBNamespace getDVBNamespace() const { return eDVBNamespace(data[4]); }
+ void setDVBNamespace(eDVBNamespace dvbnamespace) { data[4]=dvbnamespace.get(); }
+
+ eServiceReferenceDVB(eDVBNamespace dvbnamespace, eTransportStreamID transport_stream_id, eOriginalNetworkID original_network_id, eServiceID service_id, int service_type)
+ :eServiceReference(eServiceReference::idDVB, 0)
+ {
+ setTransportStreamID(transport_stream_id);
+ setOriginalNetworkID(original_network_id);
+ setDVBNamespace(dvbnamespace);
+ setServiceID(service_id);
+ setServiceType(service_type);
+ }
+
+ void set(const eDVBChannelID &chid)
+ {
+ setDVBNamespace(chid.dvbnamespace);
+ setOriginalNetworkID(chid.original_network_id);
+ setTransportStreamID(chid.transport_stream_id);
+ }
+
+ void getChannelID(eDVBChannelID &chid)
+ {
+ chid = eDVBChannelID(getDVBNamespace(), getTransportStreamID(), getOriginalNetworkID());
+ }
+
+ eServiceReferenceDVB()
+ :eServiceReference(eServiceReference::idDVB, 0)
+ {
+ }
+};
+
+
+class iDVBChannel;
+class iDVBDemux;
+class iDVBFrontendParameters;
+
+class iDVBChannelList: public virtual iObject
+{
+public:
+ virtual RESULT getChannelFrontendData(const eDVBChannelID &id, ePtr<iDVBFrontendParameters> &parm)=0;
+};
+
+class iDVBResourceManager: public virtual iObject
+{
+public:
+ /*
+ solange rumloopen bis eine resource gefunden wurde, die eine frequenz
+ tunen will
+
+ wenn natuerlich sowas schon vorhanden ist, dann einfach ne ref darauf
+ geben. (zwei services auf dem gleichen transponder teilen sich einen
+ channel)
+ */
+ virtual RESULT setChannelList(iDVBChannelList *list)=0;
+ virtual RESULT getChannelList(ePtr<iDVBChannelList> &list)=0;
+ virtual RESULT allocateChannel(const eDVBChannelID &channel, ePtr<iDVBChannel> &channel)=0;
+ virtual RESULT allocateRawChannel(ePtr<iDVBChannel> &channel)=0;
+ virtual RESULT allocatePVRChannel(int caps)=0;
+};
+
+class SatelliteDeliverySystemDescriptor;
+class CableDeliverySystemDescriptor;
+class TerrestrialDeliverySystemDescriptor;
+
+struct eDVBFrontendParametersSatellite
+{
+ struct Polarisation
+ {
+ enum {
+ Horizontal, Vertical, CircularLeft, CircularRight
+ };
+ };
+ struct Inversion
+ {
+ enum {
+ On, Off, Unknown
+ };
+ };
+ struct FEC
+ {
+ enum {
+ fNone, f1_2, f2_3, f3_4, f5_6, f7_8, fAuto
+ };
+ };
+ unsigned int frequency, symbol_rate;
+ int polarisation, fec, inversion, orbital_position;
+
+ void set(const SatelliteDeliverySystemDescriptor &);
+};
+
+struct eDVBFrontendParametersCable
+{
+ unsigned int frequency, symbol_rate;
+ int modulation, inversion, fec_inner;
+ void set(const CableDeliverySystemDescriptor &);
+};
+
+struct eDVBFrontendParametersTerrestrial
+{
+ int unknown;
+ void set(const TerrestrialDeliverySystemDescriptor &);
+};
+
+class iDVBFrontendParameters: public virtual iObject
+{
+public:
+ virtual RESULT getSystem(int &type) const = 0;
+ virtual RESULT getDVBS(eDVBFrontendParametersSatellite &p) const = 0;
+ virtual RESULT getDVBC(eDVBFrontendParametersCable &p) const = 0;
+ virtual RESULT getDVBT(eDVBFrontendParametersTerrestrial &p) const = 0;
+
+ virtual RESULT calculateDifference(const iDVBFrontendParameters *parm, int &diff) const = 0;
+ virtual RESULT getHash(unsigned long &hash) const = 0;
+};
+
+#define MAX_DISEQC_LENGTH 16
+
+struct eDVBDiseqcCommand
+{
+ int len;
+ __u8 data[MAX_DISEQC_LENGTH];
+};
+
+class iDVBSatelliteEquipmentControl;
+
+class iDVBFrontend: public virtual iObject
+{
+public:
+ enum {
+ feSatellite, feCable, feTerrestrial
+ };
+ virtual RESULT getFrontendType(int &type)=0;
+ virtual RESULT tune(const iDVBFrontendParameters &where)=0;
+ virtual RESULT connectStateChange(const Slot1<void,iDVBFrontend*> &stateChange, ePtr<eConnection> &connection)=0;
+ enum {
+ stateIdle = 0,
+ stateTuning = 1,
+ stateFailed = 2,
+ stateLock = 3
+ };
+ virtual RESULT getState(int &state)=0;
+ enum {
+ toneOn, toneOff
+ };
+ virtual RESULT setTone(int tone)=0;
+ enum {
+ voltageOff, voltage13, voltage18
+ };
+ virtual RESULT setVoltage(int voltage)=0;
+ virtual RESULT sendDiseqc(const eDVBDiseqcCommand &diseqc)=0;
+ virtual RESULT setSEC(iDVBSatelliteEquipmentControl *sec)=0;
+};
+
+class iDVBSatelliteEquipmentControl: public iObject
+{
+public:
+ virtual RESULT prepare(iDVBFrontend &frontend, struct dvb_frontend_parameters &parm, eDVBFrontendParametersSatellite &sat)=0;
+};
+
+struct eDVBCIRouting
+{
+ int enabled;
+};
+
+class iDVBChannel: public virtual iObject
+{
+public:
+ enum
+ {
+ state_idle, /* not yet tuned */
+ state_tuning, /* currently tuning (first time) */
+ state_unavailable, /* currently unavailable, will be back without further interaction */
+ state_ok /* ok */
+ };
+ virtual RESULT connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)=0;
+ virtual RESULT getState(int &state)=0;
+ enum
+ {
+ cap_decode,
+ cap_ci
+ };
+ virtual RESULT setCIRouting(const eDVBCIRouting &routing)=0;
+ virtual RESULT getDemux(ePtr<iDVBDemux> &demux)=0;
+
+ /* direct frontend access for raw channels and/or status inquiries. */
+ virtual RESULT getFrontend(ePtr<iDVBFrontend> &frontend)=0;
+};
+
+class iDVBSectionReader;
+class iTSMPEGDecoder;
+
+class iDVBDemux: public virtual iObject
+{
+public:
+ virtual RESULT createSectionReader(eMainloop *context, ePtr<iDVBSectionReader> &reader)=0;
+ virtual RESULT getMPEGDecoder(ePtr<iTSMPEGDecoder> &reader)=0;
+};
+
+class iTSMPEGDecoder: public iObject
+{
+public:
+ enum { pidDisabled = -1 };
+ /** Set Displayed Video PID */
+ virtual RESULT setVideoPID(int vpid)=0;
+
+ enum { af_MPEG, af_AC3, af_DTS };
+ /** Set Displayed Audio PID and type */
+ virtual RESULT setAudioPID(int apid, int type)=0;
+
+ /** Set Sync mode to PCR */
+ virtual RESULT setSyncPCR(int pcrpid)=0;
+ enum { sm_Audio, sm_Video };
+ /** Set Sync mode to either audio or video master */
+ virtual RESULT setSyncMaster(int who)=0;
+
+ /** Apply settings */
+ virtual RESULT start()=0;
+
+ /** Freeze frame. Either continue decoding (without display) or halt. */
+ virtual RESULT freeze(int cont)=0;
+ /** Continue after freeze. */
+ virtual RESULT unfreeze()=0;
+
+ // stop on .. Picture
+ enum { spm_I, spm_Ref, spm_Any };
+ /** Stop on specific decoded picture. For I-Frame display. */
+ virtual RESULT setSinglePictureMode(int when)=0;
+
+ enum { pkm_B, pkm_PB };
+ /** Fast forward by skipping either B or P/B pictures */
+ virtual RESULT setPictureSkipMode(int what)=0;
+
+ /** Slow Motion by repeating pictures */
+ virtual RESULT setSlowMotion(int repeat)=0;
+
+ enum { zoom_Normal, zoom_PanScan, zoom_Letterbox, zoom_Fullscreen };
+ /** Set Zoom. mode *must* be fitting. */
+ virtual RESULT setZoom(int what)=0;
+};
+
+#endif
diff --git a/lib/dvb/isection.h b/lib/dvb/isection.h
new file mode 100644
index 00000000..04b50f52
--- /dev/null
+++ b/lib/dvb/isection.h
@@ -0,0 +1,53 @@
+#ifndef __dvb_isection_h
+#define __dvb_isection_h
+
+#include <lib/dvb/idvb.h>
+
+#ifndef DMX_FILTER_SIZE
+#define DMX_FILTER_SIZE 16
+#endif
+
+struct eDVBSectionFilterMask
+{
+ int pid;
+ /* mode is 0 for positive, 1 for negative filtering */
+ __u8 data[DMX_FILTER_SIZE], mask[DMX_FILTER_SIZE], mode[DMX_FILTER_SIZE];
+ enum {
+ rfCRC=1,
+ rfNoAbort=2
+ };
+ int flags;
+};
+
+struct eDVBTableSpec
+{
+ int pid, tid, tidext;
+ int version;
+ int timeout; /* timeout in ms */
+ enum
+ {
+ tfInOrder=1,
+ /*
+ tfAnyVersion filter ANY version
+ 0 filter all EXCEPT given version (negative filtering)
+ tfThisVersion filter only THIS version
+ */
+ tfAnyVersion=2,
+ tfThisVersion=4,
+ tfHaveTID=8,
+ tfHaveTIDExt=16,
+ tfCheckCRC=32,
+ tfHaveTimeout=64,
+ };
+ int flags;
+};
+
+class iDVBSectionReader: public virtual iObject
+{
+public:
+ virtual RESULT start(const eDVBSectionFilterMask &mask)=0;
+ virtual RESULT stop()=0;
+ virtual RESULT connectRead(const Slot1<void,const __u8*> &read, ePtr<eConnection> &conn)=0;
+};
+
+#endif
diff --git a/lib/dvb/list.h b/lib/dvb/list.h
new file mode 100644
index 00000000..6df49803
--- /dev/null
+++ b/lib/dvb/list.h
@@ -0,0 +1,13 @@
+#ifndef __list_h
+#define __list_h
+
+class eDVBTransponderList: iDVBChannelList
+{
+ DECLARE_REF;
+private:
+ std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> > channels;
+public:
+ virtual RESULT getChannelFrontendData(const eDVBChannelID &id, ePtr<iDVBFrontendParameters> &parm)=0;
+};
+
+#endif
diff --git a/lib/dvb/pmt.cpp b/lib/dvb/pmt.cpp
new file mode 100644
index 00000000..4ab551f1
--- /dev/null
+++ b/lib/dvb/pmt.cpp
@@ -0,0 +1,142 @@
+#include <lib/dvb/pmt.h>
+#include <lib/dvb/specs.h>
+#include <lib/dvb/dvb.h>
+
+eDVBServicePMTHandler::eDVBServicePMTHandler()
+{
+ ePtr<eDVBResourceManager> mgr;
+ eDVBResourceManager::getInstance(mgr);
+ m_resourceManager = mgr;
+ CONNECT(m_PMT.tableReady, eDVBServicePMTHandler::PMTready);
+ CONNECT(m_PAT.tableReady, eDVBServicePMTHandler::PATready);
+}
+
+void eDVBServicePMTHandler::channelStateChanged(iDVBChannel *channel)
+{
+ int state;
+ channel->getState(state);
+
+ if ((m_last_channel_state != iDVBChannel::state_ok)
+ && (state == iDVBChannel::state_ok) && (!m_demux))
+ {
+ if (m_channel)
+ if (m_channel->getDemux(m_demux))
+ eDebug("shit it failed.. again.");
+
+ if (m_demux)
+ {
+ eDebug("ok ... now we start!!");
+ m_PAT.begin(eApp, eDVBPATSpec(), m_demux);
+ }
+ }
+}
+
+void eDVBServicePMTHandler::PMTready(int error)
+{
+ if (error)
+ serviceEvent(eventNoPMT);
+ else
+ serviceEvent(eventNewProgramInfo);
+}
+
+void eDVBServicePMTHandler::PATready(int)
+{
+ ePtr<eTable<ProgramAssociationTable> > ptr;
+ if (!m_PAT.getCurrent(ptr))
+ {
+ int pmtpid = -1;
+ ProgramAssociationTableConstIterator i;
+ for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
+ {
+ const ProgramAssociationTable &pat = **i;
+ ProgramAssociationConstIterator program;
+ for (program = pat.getPrograms()->begin(); program != pat.getPrograms()->end(); ++program)
+ if (eServiceID((*program)->getProgramNumber()) == m_reference.getServiceID())
+ pmtpid = (*program)->getProgramMapPid();
+ }
+ if (pmtpid == -1)
+ serviceEvent(eventNoPATEntry);
+ else
+ m_PMT.begin(eApp, eDVBPMTSpec(pmtpid, m_reference.getServiceID().get()), m_demux);
+ } else
+ serviceEvent(eventNoPAT);
+}
+
+int eDVBServicePMTHandler::getProgramInfo(struct program &program)
+{
+ ePtr<eTable<ProgramMapTable> > ptr;
+
+ program.videoStreams.clear();
+ program.audioStreams.clear();
+ program.pcrPid = -1;
+
+ if (!m_PMT.getCurrent(ptr))
+ {
+ ProgramMapTableConstIterator i;
+ for (i = ptr->getSections().begin(); i != ptr->getSections().end(); ++i)
+ {
+ const ProgramMapTable &pmt = **i;
+ program.pcrPid = pmt.getPcrPid();
+
+ ElementaryStreamInfoConstIterator es;
+ for (es = pmt.getEsInfo()->begin(); es != pmt.getEsInfo()->end(); ++es)
+ {
+ int isaudio = 0, isvideo = 0;
+ videoStream video;
+ audioStream audio;
+
+ video.pid = (*es)->getPid();
+ audio.pid = (*es)->getPid();
+
+ switch ((*es)->getType())
+ {
+ case 0x01: // MPEG 1 video
+ case 0x02: // MPEG 2 video
+ isvideo = 1;
+ break;
+ case 0x03: // MPEG 1 audio
+ case 0x04: // MPEG 2 audio:
+ isaudio = 1;
+ audio.type = audioStream::atMPEG;
+ break;
+ }
+ if (isaudio)
+ program.audioStreams.push_back(audio);
+ if (isvideo)
+ program.videoStreams.push_back(video);
+ }
+ }
+ return 0;
+ } else
+ return -1;
+}
+
+int eDVBServicePMTHandler::getDemux(ePtr<iDVBDemux> &demux)
+{
+ demux = m_demux;
+ if (demux)
+ return 0;
+ else
+ return -1;
+}
+
+int eDVBServicePMTHandler::tune(eServiceReferenceDVB &ref)
+{
+ RESULT res;
+ m_channel = 0;
+ m_channelStateChanged_connection = 0;
+ m_reference = ref;
+ eDVBChannelID chid;
+ ref.getChannelID(chid);
+ res = m_resourceManager->allocateChannel(chid, m_channel);
+ eDebug("eDVBServicePMTHandler: tune %d", res);
+ if (m_channel)
+ {
+ m_channel->connectStateChange(
+ slot(*this, &eDVBServicePMTHandler::channelStateChanged),
+ m_channelStateChanged_connection);
+ m_last_channel_state = -1;
+ channelStateChanged(m_channel);
+ }
+ return res;
+}
diff --git a/lib/dvb/pmt.h b/lib/dvb/pmt.h
new file mode 100644
index 00000000..ee2040af
--- /dev/null
+++ b/lib/dvb/pmt.h
@@ -0,0 +1,71 @@
+#ifndef __lib_dvb_dvbmid_h
+#define __lib_dvb_dvbmid_h
+
+#include <lib/dvb/idvb.h>
+#include <lib/dvb/isection.h>
+#include <lib/dvb/esection.h>
+#include <lib/dvb_si/pmt.h>
+#include <lib/dvb_si/pat.h>
+
+class eDVBServicePMTHandler: public Object
+{
+ eServiceReferenceDVB m_reference;
+// ePtr<eDVBService> m_service;
+
+ int m_last_channel_state;
+
+ eAUTable<eTable<ProgramMapTable> > m_PMT;
+ eAUTable<eTable<ProgramAssociationTable> > m_PAT;
+
+ ePtr<iDVBChannel> m_channel;
+ ePtr<iDVBResourceManager> m_resourceManager;
+ ePtr<iDVBDemux> m_demux;
+
+ void channelStateChanged(iDVBChannel *);
+ ePtr<eConnection> m_channelStateChanged_connection;
+
+ void PMTready(int error);
+ void PATready(int error);
+
+public:
+ eDVBServicePMTHandler();
+
+ enum
+ {
+ eventNoResources, // a requested resource couldn't be allocated
+ eventNoPAT, // no pat could be received (timeout)
+ eventNoPATEntry, // no pat entry for the corresponding SID could be found
+ eventNoPMT, // no pmt could be received (timeout)
+ eventNewProgramInfo // we just received a PMT
+ };
+
+ Signal1<void,int> serviceEvent;
+
+ struct videoStream
+ {
+ int pid;
+ };
+
+ struct audioStream
+ {
+ int pid;
+ enum { atMPEG, atAC3, atDTS };
+ int type; // mpeg2, ac3, dts, ...
+ // language code, ...
+ };
+
+ struct program
+ {
+ std::vector<videoStream> videoStreams;
+ std::vector<audioStream> audioStreams;
+ // ca info
+ int pcrPid;
+ };
+
+ int getProgramInfo(struct program &program);
+ int getDemux(ePtr<iDVBDemux> &demux);
+
+ int tune(eServiceReferenceDVB &ref);
+};
+
+#endif
diff --git a/lib/dvb/scan.cpp b/lib/dvb/scan.cpp
new file mode 100644
index 00000000..68121c44
--- /dev/null
+++ b/lib/dvb/scan.cpp
@@ -0,0 +1,374 @@
+#include <lib/dvb/idvb.h>
+#include <lib/dvb_si/sdt.h>
+#include <lib/dvb_si/nit.h>
+#include <lib/dvb_si/bat.h>
+#include <lib/dvb_si/descriptor_tag.h>
+#include <lib/dvb_si/service_descriptor.h>
+#include <lib/dvb_si/satellite_delivery_system_descriptor.h>
+#include <lib/dvb_si/ca_identifier_descriptor.h>
+#include <lib/dvb/specs.h>
+#include <lib/dvb/esection.h>
+#include <lib/dvb/scan.h>
+#include <lib/dvb/frontend.h>
+#include <lib/base/eerror.h>
+#include <errno.h>
+
+eDVBScan::eDVBScan(iDVBChannel *channel): m_channel(channel)
+{
+ if (m_channel->getDemux(m_demux))
+ eDebug("scan: failed to allocate demux!");
+ m_channel->connectStateChange(slot(*this, &eDVBScan::stateChange), m_stateChanged_connection);
+}
+
+eDVBScan::~eDVBScan()
+{
+}
+
+int eDVBScan::isValidONIDTSID(eOriginalNetworkID onid, eTransportStreamID tsid)
+{
+ switch (onid.get())
+ {
+ case 0:
+ case 0xFFFF:
+ case 0x1111:
+ return 0;
+ case 1:
+ return tsid>1;
+ case 0x00B1:
+ return tsid != 0x00B0;
+ case 0x0002:
+ return tsid != 0x07E8;
+ default:
+ return 1;
+ }
+}
+
+eDVBNamespace eDVBScan::buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash)
+{
+ // on valid ONIDs, ignore frequency ("sub network") part
+ if (isValidONIDTSID(onid, tsid))
+ hash &= ~0xFFFF;
+ return eDVBNamespace(hash);
+}
+
+void eDVBScan::stateChange(iDVBChannel *ch)
+{
+ int state;
+ if (ch->getState(state))
+ return;
+ if (m_channel_state == state)
+ return;
+
+ if (state == iDVBChannel::state_ok)
+ {
+ startFilter();
+ m_channel_state = state;
+ } else if (state == iDVBChannel::state_unavailable)
+ {
+ m_ch_unavailable.push_back(m_ch_current);
+ nextChannel();
+ }
+}
+
+RESULT eDVBScan::nextChannel()
+{
+ ePtr<iDVBFrontend> fe;
+
+ m_SDT = 0; m_BAT = 0; m_NIT = 0;
+
+ m_ready = readyBAT;
+ if (m_ch_toScan.empty())
+ {
+ eDebug("no channels left to scan.");
+ eDebug("%d channels scanned, %d were unavailable.",
+ m_ch_scanned.size(), m_ch_unavailable.size());
+ eDebug("%d channels in database.", m_new_channels.size());
+ m_event(evtFinish);
+ return -ENOENT;
+ }
+
+ m_ch_current = m_ch_toScan.front();
+ m_ch_toScan.pop_front();
+
+ if (m_channel->getFrontend(fe))
+ return -ENOTSUP;
+
+ m_channel_state = iDVBChannel::state_idle;
+ if (fe->tune(*m_ch_current))
+ return -EINVAL;
+
+ m_event(evtUpdate);
+ return 0;
+}
+
+RESULT eDVBScan::startFilter()
+{
+ assert(m_demux);
+
+ m_SDT = new eTable<ServiceDescriptionTable>();
+ if (m_SDT->start(m_demux, eDVBSDTSpec()))
+ return -1;
+ CONNECT(m_SDT->tableReady, eDVBScan::SDTready);
+
+ m_NIT = 0;
+ m_NIT = new eTable<NetworkInformationTable>();
+ if (m_NIT->start(m_demux, eDVBNITSpec()))
+ return -1;
+ CONNECT(m_NIT->tableReady, eDVBScan::NITready);
+
+ m_BAT = new eTable<BouquetAssociationTable>();
+ if (m_BAT->start(m_demux, eDVBBATSpec()))
+ return -1;
+ CONNECT(m_BAT->tableReady, eDVBScan::BATready);
+
+ return 0;
+}
+
+void eDVBScan::SDTready(int err)
+{
+ eDebug("got sdt");
+ m_ready |= readySDT;
+ if (!err)
+ m_ready |= validSDT;
+ channelDone();
+}
+
+void eDVBScan::NITready(int err)
+{
+ eDebug("got nit, err %d", err);
+ m_ready |= readyNIT;
+ if (!err)
+ m_ready |= validNIT;
+ channelDone();
+}
+
+void eDVBScan::BATready(int err)
+{
+ eDebug("got bat");
+ m_ready |= readyBAT;
+ if (!err)
+ m_ready |= validBAT;
+ channelDone();
+}
+
+void eDVBScan::addChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm)
+{
+ /* add it to the list of known channels. */
+ if (chid)
+ m_new_channels.insert(std::pair<eDVBChannelID,ePtr<iDVBFrontendParameters> >(chid, feparm));
+
+ /* check if we don't already have that channel ... */
+
+ /* ... in the list of channels to scan */
+ for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_toScan.begin()); i != m_ch_toScan.end(); ++i)
+ if (sameChannel(*i, feparm))
+ return;
+
+ /* ... in the list of successfully scanned channels */
+ for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_scanned.begin()); i != m_ch_scanned.end(); ++i)
+ if (sameChannel(*i, feparm))
+ return;
+
+ /* ... in the list of unavailable channels */
+ for (std::list<ePtr<iDVBFrontendParameters> >::const_iterator i(m_ch_unavailable.begin()); i != m_ch_unavailable.end(); ++i)
+ if (sameChannel(*i, feparm))
+ return;
+
+ /* ... on the current channel */
+ if (sameChannel(m_ch_current, feparm))
+ return;
+
+ /* otherwise, add it to the todo list. */
+ m_ch_toScan.push_back(feparm);
+}
+
+int eDVBScan::sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const
+{
+ int diff;
+ if (ch1->calculateDifference(ch2, diff))
+ return 0;
+ if (diff < 4000) // more than 4mhz difference?
+ return 1;
+ return 0;
+}
+
+void eDVBScan::channelDone()
+{
+ if (m_ready & validSDT)
+ {
+ unsigned long hash = 0;
+ m_ch_current->getHash(hash);
+
+ eDVBNamespace dvbnamespace = buildNamespace(
+ (**m_SDT->getSections().begin()).getOriginalNetworkId(),
+ (**m_SDT->getSections().begin()).getTransportStreamId(),
+ hash);
+
+ eDebug("SDT: ");
+ ServiceDescriptionTableConstIterator i;
+ for (i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
+ processSDT(dvbnamespace, **i);
+ m_ready &= ~validSDT;
+ }
+
+ if (m_ready & validNIT)
+ {
+ eDebug("dumping NIT");
+ NetworkInformationTableConstIterator i;
+ for (i = m_NIT->getSections().begin(); i != m_NIT->getSections().end(); ++i)
+ {
+ const TransportStreamInfoVector &tsinfovec = *(*i)->getTsInfo();
+
+ for (TransportStreamInfoConstIterator tsinfo(tsinfovec.begin());
+ tsinfo != tsinfovec.end(); ++tsinfo)
+ {
+ eDebug("TSID: %04x ONID: %04x", (*tsinfo)->getTransportStreamId(),
+ (*tsinfo)->getOriginalNetworkId());
+
+ eOriginalNetworkID onid = (*tsinfo)->getOriginalNetworkId();
+ eTransportStreamID tsid = (*tsinfo)->getTransportStreamId();
+
+ for (DescriptorConstIterator desc = (*tsinfo)->getDescriptors()->begin();
+ desc != (*tsinfo)->getDescriptors()->end(); ++desc)
+ {
+ switch ((*desc)->getTag())
+ {
+// case SERVICE_LIST_DESCRIPTOR:
+ case SATELLITE_DELIVERY_SYSTEM_DESCRIPTOR:
+ {
+ SatelliteDeliverySystemDescriptor &d = (SatelliteDeliverySystemDescriptor&)**desc;
+ eDebug("%d kHz, %d%d%d.%d%c %s MOD:%d %d symb/s, fec %d",
+ d.getFrequency(),
+ (d.getOrbitalPosition()>>12)&0xF,
+ (d.getOrbitalPosition()>>8)&0xF,
+ (d.getOrbitalPosition()>>4)&0xF,
+ d.getOrbitalPosition()&0xF, d.getWestEastFlag()?'E':'W',
+ d.getPolarization() ? "hor" : "vert",
+ d.getModulation(), d.getSymbolRate(), d.getFecInner());
+
+ /* some sanity checking: below 100MHz is invalid */
+ if (d.getFrequency() < 10000)
+ break;
+
+ ePtr<eDVBFrontendParameters> feparm = new eDVBFrontendParameters;
+ eDVBFrontendParametersSatellite sat;
+ sat.set(d);
+ feparm->setDVBS(sat);
+ unsigned long hash=0;
+ feparm->getHash(hash);
+
+ eDVBNamespace ns = buildNamespace(onid, tsid, hash);
+
+ addChannel(
+ eDVBChannelID(ns, tsid, onid),
+ feparm);
+ break;
+ }
+ default:
+ eDebug("descr<%x>", (*desc)->getTag());
+ break;
+ }
+ }
+
+ }
+ }
+ m_ready &= ~validNIT;
+ }
+
+ if ((m_ready & readyAll) != readyAll)
+ return;
+ eDebug("channel done!");
+ m_ch_scanned.push_back(m_ch_current);
+ nextChannel();
+}
+
+void eDVBScan::start(const std::list<ePtr<iDVBFrontendParameters> > &known_transponders)
+{
+ m_ch_toScan.clear();
+ m_ch_scanned.clear();
+ m_ch_unavailable.clear();
+ m_new_channels.clear();
+ m_new_services.clear();
+ m_ch_toScan.insert(m_ch_toScan.end(), known_transponders.begin(), known_transponders.end());
+ nextChannel();
+}
+
+void eDVBScan::insertInto(eDVBDB *db)
+{
+ for (std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> >::const_iterator
+ ch(m_new_channels.begin()); ch != m_new_channels.end(); ++ch)
+ db->addChannelToList(ch->first, ch->second);
+ for (std::map<eServiceReferenceDVB, ePtr<eDVBService> >::const_iterator
+ service(m_new_services.begin()); service != m_new_services.end(); ++service)
+ {
+ ePtr<eDVBService> dvb_service;
+ if (!db->getService(service->first, dvb_service))
+ *dvb_service = *service->second;
+ else
+ db->addService(service->first, service->second);
+ }
+}
+
+RESULT eDVBScan::processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionTable &sdt)
+{
+ const ServiceDescriptionVector &services = *sdt.getDescriptions();
+ eDebug("ONID: %04x", sdt.getOriginalNetworkId());
+ eDVBChannelID chid(dvbnamespace, sdt.getTransportStreamId(), sdt.getOriginalNetworkId());
+
+ for (ServiceDescriptionConstIterator s(services.begin()); s != services.end(); ++s)
+ {
+ eDebugNoNewLine("SID %04x: ", (*s)->getServiceId());
+
+ eServiceReferenceDVB ref;
+ ePtr<eDVBService> service = new eDVBService;
+
+ ref.set(chid);
+ ref.setServiceID((*s)->getServiceId());
+
+ for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
+ desc != (*s)->getDescriptors()->end(); ++desc)
+ if ((*desc)->getTag() == SERVICE_DESCRIPTOR)
+ ref.setServiceType(((ServiceDescriptor&)**desc).getServiceType());
+
+ for (DescriptorConstIterator desc = (*s)->getDescriptors()->begin();
+ desc != (*s)->getDescriptors()->end(); ++desc)
+ {
+ switch ((*desc)->getTag())
+ {
+ case SERVICE_DESCRIPTOR:
+ {
+ ServiceDescriptor &d = (ServiceDescriptor&)**desc;
+ eDebug("name '%s', provider_name '%s'", d.getServiceName().c_str(), d.getServiceProviderName().c_str());
+ service->m_service_name = d.getServiceName();
+ service->m_provider_name = d.getServiceProviderName();
+ break;
+ }
+ case CA_IDENTIFIER_DESCRIPTOR:
+ {
+ CaIdentifierDescriptor &d = (CaIdentifierDescriptor&)**desc;
+ const CaSystemIdVector &caids = *d.getCaSystemIds();
+ eDebugNoNewLine("CA ");
+ for (CaSystemIdVector::const_iterator i(caids.begin()); i != caids.end(); ++i)
+ {
+ eDebugNoNewLine("%04x ", *i);
+ service->m_ca.insert(*i);
+ }
+ eDebug("");
+ break;
+ }
+ default:
+ eDebug("descr<%x>", (*desc)->getTag());
+ break;
+ }
+ }
+
+ m_new_services.insert(std::pair<eServiceReferenceDVB, ePtr<eDVBService> >(ref, service));
+ }
+ return 0;
+}
+
+RESULT eDVBScan::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
+{
+ connection = new eConnection(m_event.connect(event));
+ return 0;
+}
diff --git a/lib/dvb/scan.h b/lib/dvb/scan.h
new file mode 100644
index 00000000..196e52fc
--- /dev/null
+++ b/lib/dvb/scan.h
@@ -0,0 +1,69 @@
+#ifndef __lib_dvb_scan_h
+#define __lib_dvb_scan_h
+
+#include <lib/dvb_si/nit.h>
+#include <lib/dvb_si/sdt.h>
+#include <lib/dvb_si/bat.h>
+#include <lib/dvb/db.h>
+
+class eDVBScan: public Object
+{
+ /* chid helper functions: */
+
+ /* heuristically determine if onid/tsid is valid */
+ int isValidONIDTSID(eOriginalNetworkID onid, eTransportStreamID tsid);
+ /* build dvb namespace */
+ eDVBNamespace buildNamespace(eOriginalNetworkID onid, eTransportStreamID tsid, unsigned long hash);
+
+ /* scan resources */
+ ePtr<iDVBChannel> m_channel;
+ ePtr<iDVBDemux> m_demux;
+
+ /* infrastructure */
+ void stateChange(iDVBChannel *);
+ ePtr<eConnection> m_stateChanged_connection;
+
+ /* state handling */
+ RESULT nextChannel();
+
+ RESULT startFilter();
+ enum { readySDT=1, readyNIT=2, readyBAT=4, readyAll=7,
+ validSDT=8, validNIT=16, validBAT=32};
+
+ /* scan state variables */
+ int m_channel_state;
+ int m_ready;
+
+ std::map<eDVBChannelID, ePtr<iDVBFrontendParameters> > m_new_channels;
+ std::map<eServiceReferenceDVB, ePtr<eDVBService> > m_new_services;
+
+ std::list<ePtr<iDVBFrontendParameters> > m_ch_toScan, m_ch_scanned, m_ch_unavailable;
+ ePtr<iDVBFrontendParameters> m_ch_current;
+
+ ePtr<eTable<ServiceDescriptionTable> > m_SDT;
+ ePtr<eTable<NetworkInformationTable> > m_NIT;
+ ePtr<eTable<BouquetAssociationTable> > m_BAT;
+
+ void SDTready(int err);
+ void NITready(int err);
+ void BATready(int err);
+
+ void addChannel(const eDVBChannelID &chid, iDVBFrontendParameters *feparm);
+ int sameChannel(iDVBFrontendParameters *ch1, iDVBFrontendParameters *ch2) const;
+
+ void channelDone();
+
+ Signal1<void,int> m_event;
+ RESULT processSDT(eDVBNamespace dvbnamespace, const ServiceDescriptionTable &sdt);
+public:
+ eDVBScan(iDVBChannel *channel);
+ ~eDVBScan();
+
+ void start(const std::list<ePtr<iDVBFrontendParameters> > &known_transponders);
+
+ enum { evtUpdate, evtFinish };
+ RESULT connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection);
+ void insertInto(eDVBDB *db);
+};
+
+#endif
diff --git a/lib/dvb/sec.cpp b/lib/dvb/sec.cpp
new file mode 100644
index 00000000..99e39ea6
--- /dev/null
+++ b/lib/dvb/sec.cpp
@@ -0,0 +1,58 @@
+#include <lib/dvb/sec.h>
+#include <linux/dvb/frontend.h>
+#include <lib/base/eerror.h>
+
+DEFINE_REF(eDVBSatelliteEquipmentControl);
+
+RESULT eDVBSatelliteEquipmentControl::prepare(iDVBFrontend &frontend, struct dvb_frontend_parameters &parm, eDVBFrontendParametersSatellite &sat)
+{
+ int hi;
+ eDebug("(very) ugly and hardcoded eDVBSatelliteEquipmentControl");
+
+ if (sat.frequency > 11700000)
+ hi = 1;
+ else
+ hi = 0;
+
+ if (hi)
+ parm.frequency = sat.frequency - 10600000;
+ else
+ parm.frequency = sat.frequency - 9750000;
+
+// frontend.sentDiseqc(...);
+
+ parm.inversion = sat.inversion ? INVERSION_ON : INVERSION_OFF;
+
+ switch (sat.fec)
+ {
+// case 1:
+// case ...:
+ default:
+ parm.u.qpsk.fec_inner = FEC_AUTO;
+ break;
+ }
+ parm.u.qpsk.symbol_rate = sat.symbol_rate;
+
+
+ frontend.setVoltage((sat.polarisation == eDVBFrontendParametersSatellite::Polarisation::Vertical) ? iDVBFrontend::voltage13 : iDVBFrontend::voltage18);
+
+ eDVBDiseqcCommand diseqc;
+
+ diseqc.len = 4;
+ diseqc.data[0] = 0xe0;
+ diseqc.data[1] = 0x10;
+ diseqc.data[2] = 0x38;
+ diseqc.data[3] = 0xF0;
+
+ if (hi)
+ diseqc.data[3] |= 1;
+
+ if (sat.polarisation == eDVBFrontendParametersSatellite::Polarisation::Horizontal)
+ diseqc.data[3] |= 2;
+
+ frontend.sendDiseqc(diseqc);
+ frontend.setTone(hi ? iDVBFrontend::toneOn : iDVBFrontend::toneOff);
+
+ return 0;
+}
+
diff --git a/lib/dvb/sec.h b/lib/dvb/sec.h
new file mode 100644
index 00000000..e4b2d1d2
--- /dev/null
+++ b/lib/dvb/sec.h
@@ -0,0 +1,13 @@
+#ifndef __dvb_sec_h
+#define __dvb_sec_h
+
+#include <lib/dvb/idvb.h>
+
+class eDVBSatelliteEquipmentControl: public iDVBSatelliteEquipmentControl
+{
+public:
+ DECLARE_REF;
+ RESULT prepare(iDVBFrontend &frontend, struct dvb_frontend_parameters &parm, eDVBFrontendParametersSatellite &sat);
+};
+
+#endif
diff --git a/lib/dvb/specs.h b/lib/dvb/specs.h
new file mode 100644
index 00000000..3c6908c2
--- /dev/null
+++ b/lib/dvb/specs.h
@@ -0,0 +1,108 @@
+#ifndef __lib_dvb_specs_h
+#define __lib_dvb_specs_h
+
+#include <lib/dvb/idvb.h>
+#include <lib/dvb/isection.h>
+#include <lib/dvb_si/pmt.h>
+#include <lib/dvb_si/sdt.h>
+#include <lib/dvb_si/nit.h>
+#include <lib/dvb_si/bat.h>
+#include <lib/dvb_si/pat.h>
+
+struct eDVBPMTSpec
+{
+ eDVBTableSpec m_spec;
+public:
+ eDVBPMTSpec(int pid, int sid)
+ {
+ m_spec.pid = pid;
+ m_spec.tid = ProgramMapTable::TID;
+ m_spec.tidext = sid;
+ m_spec.timeout = ProgramMapTable::TIMEOUT;
+ m_spec.flags = eDVBTableSpec::tfAnyVersion |
+ eDVBTableSpec::tfHaveTID | eDVBTableSpec::tfHaveTIDExt |
+ eDVBTableSpec::tfCheckCRC | eDVBTableSpec::tfHaveTimeout;
+ }
+ operator eDVBTableSpec &()
+ {
+ return m_spec;
+ }
+};
+
+struct eDVBSDTSpec
+{
+ eDVBTableSpec m_spec;
+public:
+ eDVBSDTSpec()
+ {
+ m_spec.pid = ServiceDescriptionTable::PID;
+ m_spec.tid = ServiceDescriptionTable::TID;
+ m_spec.timeout = ServiceDescriptionTable::TIMEOUT;
+ m_spec.flags = eDVBTableSpec::tfAnyVersion |
+ eDVBTableSpec::tfHaveTID | eDVBTableSpec::tfCheckCRC |
+ eDVBTableSpec::tfHaveTimeout;
+ }
+ operator eDVBTableSpec &()
+ {
+ return m_spec;
+ }
+};
+
+struct eDVBNITSpec
+{
+ eDVBTableSpec m_spec;
+public:
+ eDVBNITSpec()
+ {
+ m_spec.pid = NetworkInformationTable::PID;
+ m_spec.tid = NetworkInformationTable::TID;
+ m_spec.timeout = NetworkInformationTable::TIMEOUT;
+ m_spec.flags = eDVBTableSpec::tfAnyVersion |
+ eDVBTableSpec::tfHaveTID | eDVBTableSpec::tfCheckCRC |
+ eDVBTableSpec::tfHaveTimeout;
+ }
+ operator eDVBTableSpec &()
+ {
+ return m_spec;
+ }
+};
+
+struct eDVBBATSpec
+{
+ eDVBTableSpec m_spec;
+public:
+ eDVBBATSpec()
+ {
+ m_spec.pid = BouquetAssociationTable::PID;
+ m_spec.tid = BouquetAssociationTable::TID;
+ m_spec.timeout = BouquetAssociationTable::TIMEOUT;
+ m_spec.flags = eDVBTableSpec::tfAnyVersion |
+ eDVBTableSpec::tfHaveTID | eDVBTableSpec::tfCheckCRC |
+ eDVBTableSpec::tfHaveTimeout;
+ }
+ operator eDVBTableSpec &()
+ {
+ return m_spec;
+ }
+};
+
+struct eDVBPATSpec
+{
+ eDVBTableSpec m_spec;
+public:
+ eDVBPATSpec()
+ {
+ m_spec.pid = ProgramAssociationTable::PID;
+ m_spec.tid = ProgramAssociationTable::TID;
+ m_spec.timeout = ProgramAssociationTable::TIMEOUT;
+ m_spec.flags = eDVBTableSpec::tfAnyVersion |
+ eDVBTableSpec::tfHaveTID | eDVBTableSpec::tfCheckCRC |
+ eDVBTableSpec::tfHaveTimeout;
+ }
+ operator eDVBTableSpec &()
+ {
+ return m_spec;
+ }
+};
+
+#endif
diff --git a/lib/dvb/stT1RVV7 b/lib/dvb/stT1RVV7
new file mode 100644
index 00000000..a9d6d3dc
--- /dev/null
+++ b/lib/dvb/stT1RVV7
Binary files differ