diff options
| author | Felix Domke <tmbinc@elitedvb.net> | 2003-10-17 15:36:42 +0000 |
|---|---|---|
| committer | Felix Domke <tmbinc@elitedvb.net> | 2003-10-17 15:36:42 +0000 |
| commit | d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5 (patch) | |
| tree | 84d0cacfd0b6c1241c236c7860f7cbd7f26901bb /lib/dvb | |
| download | enigma2-d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5.tar.gz enigma2-d63d2c3c6cbbd574dda4f8b00ebe6c661735edd5.zip | |
import of enigma2
Diffstat (limited to 'lib/dvb')
| -rw-r--r-- | lib/dvb/Makefile.am | 8 | ||||
| -rw-r--r-- | lib/dvb/Makefile.in | 0 | ||||
| -rw-r--r-- | lib/dvb/crc32.cpp | 164 | ||||
| -rw-r--r-- | lib/dvb/crc32.h | 22 | ||||
| -rw-r--r-- | lib/dvb/db.cpp | 274 | ||||
| -rw-r--r-- | lib/dvb/db.h | 48 | ||||
| -rw-r--r-- | lib/dvb/decoder.cpp | 245 | ||||
| -rw-r--r-- | lib/dvb/decoder.h | 66 | ||||
| -rw-r--r-- | lib/dvb/demux.cpp | 131 | ||||
| -rw-r--r-- | lib/dvb/demux.h | 41 | ||||
| -rw-r--r-- | lib/dvb/dvb.cpp | 211 | ||||
| -rw-r--r-- | lib/dvb/dvb.h | 67 | ||||
| -rw-r--r-- | lib/dvb/esection.cpp | 130 | ||||
| -rw-r--r-- | lib/dvb/esection.h | 189 | ||||
| -rw-r--r-- | lib/dvb/frontend.cpp | 465 | ||||
| -rw-r--r-- | lib/dvb/frontend.h | 61 | ||||
| -rw-r--r-- | lib/dvb/idvb.h | 354 | ||||
| -rw-r--r-- | lib/dvb/isection.h | 53 | ||||
| -rw-r--r-- | lib/dvb/list.h | 13 | ||||
| -rw-r--r-- | lib/dvb/pmt.cpp | 142 | ||||
| -rw-r--r-- | lib/dvb/pmt.h | 71 | ||||
| -rw-r--r-- | lib/dvb/scan.cpp | 374 | ||||
| -rw-r--r-- | lib/dvb/scan.h | 69 | ||||
| -rw-r--r-- | lib/dvb/sec.cpp | 58 | ||||
| -rw-r--r-- | lib/dvb/sec.h | 13 | ||||
| -rw-r--r-- | lib/dvb/specs.h | 108 | ||||
| -rw-r--r-- | lib/dvb/stT1RVV7 | bin | 0 -> 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 Binary files differnew file mode 100644 index 00000000..a9d6d3dc --- /dev/null +++ b/lib/dvb/stT1RVV7 |
