Updated Kaffeine to latest upstream version

git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kaffeine@1182813 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
v3.5.13-sru
tpearson 15 years ago
parent c1aed14da1
commit d32030ae51

@ -3,6 +3,31 @@
* KAFFEINE ChangeLog *
****************************
0.8.8
* DVB: allow OSD on HD channels.
* DVB: PAT/PMT radios fixes.
* DVB: added live ringbuffer size option (in misc page)
* DVB: added tuner priority option.
* DVB: added mini-Diseqc option.
* DVB: added "Sending diseqc cmds twice" option.
* DVB: added "External positionner" option.
* DVB: option to disable MFE probing.
* DVB: add DVB-S2 support.
* DVB: port to S2API.
* DVB: fixed crash that sometimes occurred during ATSC scanning
* DVB: improve support for ATSC scanning on cable (QAM)
0.8.7
* kaffeine: add MOD/STM mimetypes
* kaffeine: fullscreen fix, patch by Einars Lielmanis <einars@gmail.com>
* DVB: updated libdvb, added CAM menu.
* DVB: added multiservices CAM support.
* DVB: added ATSC scanning, patch by "Devin Heitmueller" <devin.heitmueller@gmail.com>
* DVB: added 7MHz autoscan.
* DVB: reworked CAM support.
0.8.6
* kaffeine: new jpeg logo (the animated one is renamed logo.avi)

@ -1 +1 @@
kaffeine version 0.8.6
kaffeine version 0.8.8

File diff suppressed because it is too large Load Diff

13128
aclocal.m4 vendored

File diff suppressed because it is too large Load Diff

@ -40,9 +40,7 @@ dnl Perform program name transformation
AC_ARG_PROGRAM
dnl Automake doc recommends to do this only here. (Janos)
AM_INIT_AUTOMAKE(kaffeine, 0.8.5) dnl searches for some needed programs
AM_MAINTAINER_MODE
AM_INIT_AUTOMAKE(kaffeine-0.8.8, "3.5.7") dnl searches for some needed programs
KDE_SET_PREFIX
@ -66,13 +64,6 @@ dnl FILE: configure.in.in
dnl =======================================================
#MIN_CONFIG(3.3)
KDE_ENABLE_HIDDEN_VISIBILITY
dnl PACKAGE set before
AM_MAINTAINER_MODE
CXXFLAGS="$CXXFLAGS $KDE_DEFAULT_CXXFLAGS"
if test "$build_arts" = "yes"; then
@ -309,7 +300,7 @@ dnl --------------------
dnl check for cdparanoia
dnl --------------------
KDE_CHECK_HEADER([cdda_interface.h], [with_cdparanoia=yes], [with_cdparanoia=no])
KDE_CHECK_HEADER([cdio/cdda.h], [with_cdparanoia=yes], [with_cdparanoia=no])
if test "$with_cdparanoia" != "yes" ; then
echo ""
@ -395,6 +386,7 @@ AC_CONFIG_FILES([ kaffeine/src/input/dvb/lib/Makefile ])
AC_CONFIG_FILES([ kaffeine/src/input/dvb/lib/libdvbapi/Makefile ])
AC_CONFIG_FILES([ kaffeine/src/input/dvb/lib/libdvben50221/Makefile ])
AC_CONFIG_FILES([ kaffeine/src/input/dvb/lib/libucsi/Makefile ])
AC_CONFIG_FILES([ kaffeine/src/input/dvb/lib/libucsi/atsc/Makefile ])
AC_CONFIG_FILES([ kaffeine/src/input/dvb/lib/libucsi/dvb/Makefile ])
AC_CONFIG_FILES([ kaffeine/src/input/dvb/lib/libucsi/mpeg/Makefile ])
AC_CONFIG_FILES([ kaffeine/src/input/dvb/plugins/Makefile ])

@ -1,11 +1,4 @@
#MIN_CONFIG(3.3)
KDE_ENABLE_HIDDEN_VISIBILITY
AM_INIT_AUTOMAKE(kaffeine, 0.8.5)
AM_MAINTAINER_MODE
CXXFLAGS="$CXXFLAGS $KDE_DEFAULT_CXXFLAGS"
if test "$build_arts" = "yes"; then

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 KiB

After

Width:  |  Height:  |  Size: 390 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

@ -220,7 +220,7 @@ dnl --------------------
dnl check for cdparanoia
dnl --------------------
KDE_CHECK_HEADER([cdda_interface.h], [with_cdparanoia=yes], [with_cdparanoia=no])
KDE_CHECK_HEADER([cdio/cdda.h], [with_cdparanoia=yes], [with_cdparanoia=no])
if test "$with_cdparanoia" != "yes" ; then
echo ""

Binary file not shown.

@ -28,7 +28,7 @@ libkaffeinedisc_la_LDFLAGS = $(KDE_RPATH) \
libkaffeinedisc_la_LIBADD = $(top_builddir)/kaffeine/src/input/libkaffeineinput.la \
$(top_builddir)/kaffeine/src/player-parts/kaffeine-part/libkaffeinepart.la \
$(top_builddir)/kaffeine/src/input/disc/plugins/libkaffeineaudioencoder.la \
-lcdda_interface -lcdda_paranoia
-lcdio_cdda -lcdio_paranoia
# this is where the XML-GUI resource file goes
shellrcdir = $(kde_datadir)/kaffeine

@ -120,7 +120,7 @@ KiloConfig::~KiloConfig()
{
}
void paranoiaCallback( long, int )
void paranoiaCallback( long int, paranoia_cb_mode_t )
{
}
@ -396,7 +396,7 @@ void Paranoia::run()
curpos = currentSector;
endpos = endOfTrack;
if ( normalize ) {
len = CD_FRAMESIZE_RAW;
len = CDIO_CD_FRAMESIZE_RAW;
fn.open( IO_ReadWrite | IO_Truncate );
do {
buf = paranoia_read_limited( p, paranoiaCallback, 3 );
@ -419,7 +419,7 @@ void Paranoia::run()
while ( curpos<endpos && len!=0 );
factor = 32767.0/max;
buf = new signed short[CD_FRAMESIZE_RAW];
buf = new signed short[CDIO_CD_FRAMESIZE_RAW];
fn.at( 0 );
f.open( IO_ReadWrite | IO_Truncate );
currentEncoder->start( encodingList[i].remove(0,3), encodingList[0], encodingList[1], encodingList[i].left(2) );
@ -428,7 +428,7 @@ void Paranoia::run()
f.writeBlock( encoded, len );
do {
len = fn.readBlock( (char*)buf, CD_FRAMESIZE_RAW );
len = fn.readBlock( (char*)buf, CDIO_CD_FRAMESIZE_RAW );
if ( len>0 ) {
if ( max<32760 )
for ( n=0; n<len/2; ++n )
@ -455,7 +455,7 @@ void Paranoia::run()
encoded = currentEncoder->getHeader( len );
if ( encoded )
f.writeBlock( encoded, len );
len = CD_FRAMESIZE_RAW;
len = CDIO_CD_FRAMESIZE_RAW;
do {
buf = paranoia_read_limited( p, paranoiaCallback, 3 );
if ( Q_BYTE_ORDER == Q_BIG_ENDIAN ) {
@ -514,7 +514,7 @@ QString Paranoia::trackSize( int t )
QString s, c;
long total;
total = CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) );
total = CDIO_CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) );
if ( total>(1048576 ) ) s = c.setNum(total/1048576.0, 'f', 2)+" "+i18n("MB");
else if ( total>1024 ) s = c.setNum(total/1024.0, 'f', 2)+" "+i18n("KB");
else s = c.setNum(total*1.0, 'f', 2)+" "+i18n("Bytes");
@ -532,8 +532,8 @@ QString Paranoia::trackTime( int t )
long total, time;
int m, s;
if ( t<0 ) total = CD_FRAMESIZE_RAW * (cdda_disc_lastsector( d )-cdda_disc_firstsector( d ) );
else total = CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) );
if ( t<0 ) total = CDIO_CD_FRAMESIZE_RAW * (cdda_disc_lastsector( d )-cdda_disc_firstsector( d ) );
else total = CDIO_CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) );
time = (8 * total) / (44100 * 2 * 16);
m = time/60;
s = time%60;

@ -32,8 +32,8 @@
extern "C"
{
#include <cdda_interface.h>
#include <cdda_paranoia.h>
#include <cdio/cdda.h>
#include <cdio/paranoia.h>
}
class KiloConfig : public ParanoiaSettings
@ -91,8 +91,8 @@ private:
bool setPath( QString &path, const QString &artist, const QString &album );
long nTracks;
cdrom_drive *d;
cdrom_paranoia *p;
cdrom_drive_t *d;
cdrom_paranoia_t *p;
long currentSector, endOfTrack;
bool isRunning;
QStringList encodingList;

@ -10,7 +10,7 @@ noinst_HEADERS = koggenc.h
libkaffeineoggvorbis_la_SOURCES = koggenc.cpp oggconfig.ui
libkaffeineoggvorbis_la_LIBADD = ../libkaffeineaudioencoder.la $(LIB_OGGVORBIS)
libkaffeineoggvorbis_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) $(LIB_QT) -lDCOP $(KDE_PLUGIN) $(LIB_KPARTS) $(LIB_KDECORE) $(LIB_KDEUI) $(LIB_KIO) -avoid-version -no-undefined
libkaffeineoggvorbis_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -avoid-version -no-undefined
# this is where the desktop file will go
partdesktopdir = $(kde_servicesdir)

@ -30,6 +30,8 @@ libkaffeinedvb_la_SOURCES = audioeditor.cpp \
dvbsection.h \
dvbsi.cpp \
dvbsi.h \
camdialog.ui \
cammenudialog.ui \
dvbstream.cpp \
dvbstream.h \
gdvb.h \

@ -0,0 +1,149 @@
<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
<class>CamDialog</class>
<widget class="QDialog">
<property name="name">
<cstring>CamDialog</cstring>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>330</width>
<height>198</height>
</rect>
</property>
<property name="caption">
<string>CAM settings</string>
</property>
<grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLayoutWidget" row="0" column="0">
<property name="name">
<cstring>layout5</cstring>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLayoutWidget">
<property name="name">
<cstring>layout5</cstring>
</property>
<hbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLabel">
<property name="name">
<cstring>textLabel9</cstring>
</property>
<property name="text">
<string>Maximum Concurrent Services:</string>
</property>
</widget>
<widget class="QSpinBox">
<property name="name">
<cstring>maxServiceSpin</cstring>
</property>
<property name="minValue">
<number>1</number>
</property>
</widget>
</hbox>
</widget>
<widget class="QGroupBox">
<property name="name">
<cstring>groupBox1</cstring>
</property>
<property name="title">
<string></string>
</property>
<grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLabel" row="0" column="0">
<property name="name">
<cstring>textLabel1</cstring>
</property>
<property name="text">
<string>Application Type:</string>
</property>
</widget>
<widget class="QLabel" row="2" column="0">
<property name="name">
<cstring>textLabel3</cstring>
</property>
<property name="text">
<string>Manufacturer Code:</string>
</property>
</widget>
<widget class="QLabel" row="3" column="0">
<property name="name">
<cstring>textLabel4</cstring>
</property>
<property name="text">
<string>Menu String:</string>
</property>
</widget>
<widget class="QLabel" row="2" column="1">
<property name="name">
<cstring>manuCodeLab</cstring>
</property>
<property name="text">
<string>_</string>
</property>
</widget>
<widget class="QLabel" row="1" column="1">
<property name="name">
<cstring>appManuLab</cstring>
</property>
<property name="text">
<string>_</string>
</property>
</widget>
<widget class="QLabel" row="1" column="0">
<property name="name">
<cstring>textLabel2</cstring>
</property>
<property name="text">
<string>Application Manufacturer:</string>
</property>
</widget>
<widget class="QLabel" row="3" column="1">
<property name="name">
<cstring>menuStringLab</cstring>
</property>
<property name="text">
<string>_</string>
</property>
</widget>
<widget class="QLabel" row="0" column="1">
<property name="name">
<cstring>appTypeLab</cstring>
</property>
<property name="text">
<string>_</string>
</property>
</widget>
</grid>
</widget>
<widget class="QPushButton">
<property name="name">
<cstring>camMenuBtn</cstring>
</property>
<property name="text">
<string>CAM Menu</string>
</property>
</widget>
</vbox>
</widget>
</grid>
</widget>
<tabstops>
<tabstop>maxServiceSpin</tabstop>
</tabstops>
<layoutdefaults spacing="6" margin="11"/>
</UI>

@ -0,0 +1,67 @@
<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
<class>CamMenuDialog</class>
<widget class="QDialog">
<property name="name">
<cstring>CamMenuDialog</cstring>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>317</width>
<height>345</height>
</rect>
</property>
<property name="caption">
<string>CAM Menu</string>
</property>
<grid>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLayoutWidget" row="0" column="0">
<property name="name">
<cstring>layout7</cstring>
</property>
<vbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QTextBrowser">
<property name="name">
<cstring>menuText</cstring>
</property>
</widget>
<widget class="QLayoutWidget">
<property name="name">
<cstring>layout6</cstring>
</property>
<hbox>
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="QLabel">
<property name="name">
<cstring>textLabel1</cstring>
</property>
<property name="text">
<string>Your choice (enter to validate):</string>
</property>
</widget>
<widget class="QLineEdit">
<property name="name">
<cstring>inputLine</cstring>
</property>
</widget>
</hbox>
</widget>
</vbox>
</widget>
</grid>
</widget>
<tabstops>
<tabstop>inputLine</tabstop>
<tabstop>menuText</tabstop>
</tabstops>
<layoutdefaults spacing="6" margin="11"/>
</UI>

@ -115,6 +115,8 @@ Transponder::Transponder()
coderateH=FEC_AUTO;
bandwidth=BANDWIDTH_AUTO;
snr = 0;
rolloff = ROLLOFF_AUTO;
S2 = 0;
}
Transponder::Transponder( const Transponder &trans )
@ -134,6 +136,8 @@ Transponder::Transponder( const Transponder &trans )
coderateL=trans.coderateL;
coderateH=trans.coderateH;
bandwidth=trans.bandwidth;
rolloff = trans.rolloff;
S2 = trans.S2;
}
bool Transponder::sameAs( Transponder *trans )

@ -101,6 +101,8 @@ public:
fe_code_rate_t coderateH;
fe_bandwidth_t bandwidth;
int snr;
fe_rolloff_t rolloff;
char S2;
};
class ChannelDesc

@ -143,6 +143,9 @@ void ChannelEditor::accept()
else channel->tp.pol = 'h';
channel->tp.coderateH = (fe_code_rate_t)(FEC_NONE+coderateHComb->currentItem());
channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem());
channel->tp.modulation = (fe_modulation_t)(QPSK+modulationComb->currentItem());
channel->tp.S2 = stypeComb->currentItem();
channel->tp.rolloff = (fe_rolloff_t)(ROLLOFF_35+rolloffComb->currentItem() );
}
else if ( channel->tp.type==FE_QAM ) {
channel->tp.freq = freqSpin->value();
@ -165,13 +168,7 @@ void ChannelEditor::accept()
else {
channel->tp.freq = freqSpin->value();
channel->tp.inversion = (fe_spectral_inversion_t)(INVERSION_OFF+inversionComb->currentItem());
switch (modulationComb->currentItem()) {
case 0: channel->tp.modulation = QAM_64; break;
case 1: channel->tp.modulation = QAM_256; break;
case 2: channel->tp.modulation = VSB_8; break;
case 3: channel->tp.modulation = VSB_16; break;
default: channel->tp.modulation = QAM_AUTO; break;
}
channel->tp.modulation = (fe_modulation_t)(QPSK+modulationComb->currentItem());
}
done( Accepted );
@ -187,10 +184,15 @@ void ChannelEditor::initS()
inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion );
coderateHComb->insertStringList( coderateList() );
coderateHComb->setCurrentItem( FEC_NONE+channel->tp.coderateH );
modulationComb->insertStringList( modulationList() );
modulationComb->setCurrentItem( QPSK+channel->tp.modulation );
stypeComb->insertStringList( stypeList() );
stypeComb->setCurrentItem( channel->tp.S2 );
rolloffComb->insertStringList( rolloffList() );
rolloffComb->setCurrentItem( ROLLOFF_35+channel->tp.rolloff );
transmissionComb->setEnabled( false );
coderateLComb->setEnabled( false );
bandwidthComb->setEnabled( false );
modulationComb->setEnabled( false );
hierarchyComb->setEnabled( false );
guardComb->setEnabled( false );
}
@ -211,6 +213,8 @@ void ChannelEditor::initC()
bandwidthComb->setEnabled( false );
hierarchyComb->setEnabled( false );
guardComb->setEnabled( false );
stypeComb->setEnabled( false );
rolloffComb->setEnabled( false );
}
void ChannelEditor::initT()
@ -234,6 +238,8 @@ void ChannelEditor::initT()
guardComb->setCurrentItem( GUARD_INTERVAL_1_32+channel->tp.guard );
srSpin->setEnabled( false );
polGroup->setEnabled( false );
stypeComb->setEnabled( false );
rolloffComb->setEnabled( false );
}
void ChannelEditor::initA()
@ -241,14 +247,8 @@ void ChannelEditor::initA()
freqSpin->setValue( channel->tp.freq );
inversionComb->insertStringList( inversionList() );
inversionComb->setCurrentItem( INVERSION_OFF+channel->tp.inversion );
modulationComb->insertStringList( modulationListAtsc() );
switch (channel->tp.modulation) {
case QAM_64: modulationComb->setCurrentItem(0); break;
case QAM_256: modulationComb->setCurrentItem(1); break;
case VSB_8: modulationComb->setCurrentItem(2); break;
case VSB_16: modulationComb->setCurrentItem(3); break;
default: modulationComb->setCurrentItem(4); break;
}
modulationComb->insertStringList( modulationList() );
modulationComb->setCurrentItem( QPSK+channel->tp.modulation );
srSpin->setEnabled( false );
polGroup->setEnabled( false );
transmissionComb->setEnabled( false );
@ -257,6 +257,8 @@ void ChannelEditor::initA()
bandwidthComb->setEnabled( false );
hierarchyComb->setEnabled( false );
guardComb->setEnabled( false );
stypeComb->setEnabled( false );
rolloffComb->setEnabled( false );
}
QStringList ChannelEditor::inversionList()
@ -271,7 +273,7 @@ QStringList ChannelEditor::coderateList()
{
QStringList list;
list<<"NONE"<<"1/2"<<"2/3"<<"3/4"<<"4/5"<<"5/6"<<"6/7"<<"7/8"<<"8/9"<<"AUTO";
list<<"NONE"<<"1/2"<<"2/3"<<"3/4"<<"4/5"<<"5/6"<<"6/7"<<"7/8"<<"8/9"<<"AUTO"<<"3/5"<<"9/10";
return list;
}
@ -279,15 +281,7 @@ QStringList ChannelEditor::modulationList()
{
QStringList list;
list<<"QPSK"<<"QAM 16"<<"QAM 32"<<"QAM 64"<<"QAM 128"<<"QAM 256"<<"AUTO";
return list;
}
QStringList ChannelEditor::modulationListAtsc()
{
QStringList list;
list<<"QAM 64"<<"QAM 256"<<"VSB 8"<<"VSB 16"<<"AUTO";
list<<"QPSK"<<"QAM 16"<<"QAM 32"<<"QAM 64"<<"QAM 128"<<"QAM 256"<<"AUTO"<<"VSB-8"<<"VSB-16"<<"8PSK"<<"16APSK"<<"DQPSK";
return list;
}
@ -323,6 +317,22 @@ QStringList ChannelEditor::guardList()
return list;
}
QStringList ChannelEditor::stypeList()
{
QStringList list;
list<<"DVB-S"<<"DVB-S2";
return list;
}
QStringList ChannelEditor::rolloffList()
{
QStringList list;
list<<"35"<<"20"<<"25"<<"AUTO";
return list;
}
ChannelEditor::~ChannelEditor()
{
}

@ -53,11 +53,12 @@ private:
QStringList inversionList();
QStringList coderateList();
QStringList modulationList();
QStringList modulationListAtsc();
QStringList transmissionList();
QStringList bandwidthList();
QStringList hierarchyList();
QStringList guardList();
QStringList stypeList();
QStringList rolloffList();
ChannelDesc *channel;
QPtrList<ChannelDesc> *chandesc;

@ -9,7 +9,7 @@
<x>0</x>
<y>0</y>
<width>477</width>
<height>533</height>
<height>541</height>
</rect>
</property>
<property name="caption">
@ -19,7 +19,7 @@
<property name="name">
<cstring>unnamed</cstring>
</property>
<widget class="Line" row="1" column="0">
<widget class="Line" row="0" column="1">
<property name="name">
<cstring>line2</cstring>
</property>
@ -35,7 +35,7 @@
</widget>
<widget class="QLayoutWidget" row="0" column="0">
<property name="name">
<cstring>layout9</cstring>
<cstring>layout7</cstring>
</property>
<vbox>
<property name="name">
@ -432,22 +432,6 @@
<cstring>transmissionComb</cstring>
</property>
</widget>
<widget class="QLabel" row="3" column="0">
<property name="name">
<cstring>textLabel11</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>4</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Bandwidth:</string>
</property>
</widget>
<widget class="QLabel" row="2" column="0">
<property name="name">
<cstring>textLabel10</cstring>
@ -480,11 +464,6 @@
<string>Transmission:</string>
</property>
</widget>
<widget class="QComboBox" row="3" column="1">
<property name="name">
<cstring>bandwidthComb</cstring>
</property>
</widget>
<widget class="QComboBox" row="2" column="1">
<property name="name">
<cstring>coderateHComb</cstring>
@ -511,11 +490,6 @@
<string>FEC low:</string>
</property>
</widget>
<widget class="QComboBox" row="3" column="3">
<property name="name">
<cstring>guardComb</cstring>
</property>
</widget>
<widget class="QLabel" row="3" column="2">
<property name="name">
<cstring>textLabel7</cstring>
@ -595,6 +569,58 @@
<string>Inversion:</string>
</property>
</widget>
<widget class="QLabel" row="3" column="0">
<property name="name">
<cstring>textLabel11</cstring>
</property>
<property name="sizePolicy">
<sizepolicy>
<hsizetype>4</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Bandwidth:</string>
</property>
</widget>
<widget class="QComboBox" row="3" column="1">
<property name="name">
<cstring>bandwidthComb</cstring>
</property>
</widget>
<widget class="QLabel" row="4" column="0">
<property name="name">
<cstring>textLabel1_3</cstring>
</property>
<property name="text">
<string>Type:</string>
</property>
</widget>
<widget class="QComboBox" row="4" column="1">
<property name="name">
<cstring>stypeComb</cstring>
</property>
</widget>
<widget class="QComboBox" row="4" column="3">
<property name="name">
<cstring>rolloffComb</cstring>
</property>
</widget>
<widget class="QLabel" row="4" column="2">
<property name="name">
<cstring>textLabel2_4</cstring>
</property>
<property name="text">
<string>Roll off:</string>
</property>
</widget>
<widget class="QComboBox" row="3" column="3">
<property name="name">
<cstring>guardComb</cstring>
</property>
</widget>
</grid>
</widget>
<spacer>
@ -610,7 +636,7 @@
<property name="sizeHint">
<size>
<width>20</width>
<height>98</height>
<height>166</height>
</size>
</property>
</spacer>

File diff suppressed because it is too large Load Diff

@ -1,6 +1,7 @@
/*
* dvbcam.h
*
* Copyright (C) 2008 Christophe Thommeret <hftom@free.fr>
* Copyright (C) 2006 Christoph Pfister <christophpfister@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
@ -21,32 +22,182 @@
#ifndef DVBCAM_H
#define DVBCAM_H
class DvbCamCamThread;
class DvbCamPmtThread;
#include <libdvbapi/dvbca.h>
#include <libdvbapi/dvbdemux.h>
#include <libdvben50221/en50221_app_ai.h>
#include <libdvben50221/en50221_app_ca.h>
#include <libdvben50221/en50221_app_mmi.h>
#include <libdvben50221/en50221_app_rm.h>
#include <libdvben50221/en50221_app_tags.h>
#include <libdvben50221/en50221_session.h>
#include <libdvben50221/en50221_stdcam.h>
#include <libucsi/mpeg/section.h>
class DvbCam
#include <qthread.h>
#include <qmutex.h>
#include <qptrlist.h>
#include "channeldesc.h"
#include "camdialog.h"
#include "cammenudialog.h"
#define MMI_STATE_CLOSED 0
#define MMI_STATE_OPEN 1
#define MMI_STATE_ENQ 2
#define MMI_STATE_MENU 3
#define MMI_NO_MENU 0
#define MMI_MENU 1
class CamService : protected QThread
{
public:
DvbCam(int adapter, int ca_device, int demux_device, int ci_type);
~DvbCam();
enum PmtState{ NotReady=0, Ready, Added, Remove, Destroy };
CamService( int adapter, int demux_device, ChannelDesc *chan, int maxService );
~CamService();
void setState( PmtState st );
int getState();
const ChannelDesc& getChannel() { return channel; }
void restart();
void restart(int service_id);
unsigned char caPmt[4096];
int caPmtSize;
protected:
void run();
private:
int createSectionFilter( uint16_t pid, uint8_t table_id );
int processPat( int demux_fd );
int processPmt( int demux_fd );
bool setCaPmt( int list_management, int cmd_id );
void stop();
bool running() { return isRunning; }
int serviceId() { return sid; }
int Adapter;
int DemuxDevice;
ChannelDesc channel;
unsigned char pmtBuffer[4096];
struct mpeg_pmt_section *parsedPmt;
PmtState state;
bool isRunning;
QMutex mutex;
int CamMaxService;
};
class DvbCam;
class StandardCam
{
public:
StandardCam( en50221_stdcam *sc, DvbCam *dc ) {
stdcam=sc;
dvbcam=dc;
mmi_state=MMI_STATE_CLOSED;
menuType=MMI_NO_MENU;
}
en50221_stdcam *stdcam;
DvbCam *dvbcam;
int mmi_state;
int mmi_enq_blind;
int mmi_enq_length;
int menuType;
QStringList menuList;
QMutex mutex;
};
class MCamMenuDialog : public CamMenuDialog
{
Q_OBJECT
public:
MCamMenuDialog( StandardCam *sc );
private:
StandardCam *stdcam;
QTimer readTimer;
private slots:
void setMenu();
void validateClicked();
signals:
void enteredResponse( QString );
};
class DvbCam : public QObject, public QThread
{
Q_OBJECT
public:
DvbCam(int adapter, int ca_device, int demux_device, int ci_type, int maxService);
~DvbCam();
void startService( ChannelDesc *chan );
void stopService( ChannelDesc *chan );
bool canPlay( ChannelDesc *chan );
static int probe( int adapter, int ca_device );
void setAppType( QString s ) { appType=s; }
void setAppManu( QString s ) { appManu=s; }
void setManuCode( QString s ) { manuCode=s; }
void setMenuString( QString s ) { menuString=s; }
QString getAppType() { return appType; }
QString getAppManu() { return appManu; }
QString getManuCode() { return manuCode; }
QString getMenuString() { return menuString; }
int getCamMaxService() { return CamMaxService; }
int showCamDialog();
protected:
void run();
void timerEvent( QTimerEvent *e );
private slots:
void mmiResponse( QString s );
void showMMI();
void closeMMI();
void enterMenu();
private:
bool init();
bool sendPmt( unsigned char *pmt_buffer, int size );
void resendPmts();
static int infoCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids);
static int aiCallback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t application_type,
uint16_t application_manufacturer, uint16_t manufacturer_code, uint8_t menu_string_length, uint8_t *menu_string);
static int mmi_close_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t delay);
static int mmi_display_control_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t mmi_mode);
static int mmi_enq_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t blind_answer, uint8_t expected_answer_length,
uint8_t *text, uint32_t text_size);
static int mmi_menu_callback(void *arg, uint8_t slot_id, uint16_t session_number, struct en50221_app_mmi_text *title,
struct en50221_app_mmi_text *sub_title, struct en50221_app_mmi_text *bottom, uint32_t item_count,
struct en50221_app_mmi_text *items, uint32_t item_raw_length, uint8_t *items_raw);
int Adapter;
int CaDevice;
int DemuxDevice;
bool isRunning;
int sid;
int ciType;
int CamMaxService;
bool isRunning;
QPtrList<CamService> sidList;
QMutex sidMutex;
QString appType, appManu, manuCode, menuString;
StandardCam *stdcam;
en50221_session_layer *SessionLayer;
en50221_transport_layer *TransportLayer;
DvbCamCamThread *CamThread;
DvbCamPmtThread *PmtThread;
MCamMenuDialog *menuDialog;
};
#endif /* DVBCAM_H */

@ -38,6 +38,7 @@
#include "dvbconfig.h"
#include "kaffeinedvbplugin.h"
#include "dvbpanel.h"
@ -72,6 +73,21 @@ void MPushButton::isClicked()
MCAMButton::MCAMButton( QWidget *parent, int devNum ) : QPushButton( i18n("CAM"), parent )
{
deviceNumber = devNum;
connect( this, SIGNAL(clicked()), this, SLOT(isClicked()) );
}
void MCAMButton::isClicked()
{
emit clicked( deviceNumber );
}
MComboBox::MComboBox( QWidget *parent, int devNum, int lnbNum ) : QComboBox( parent )
{
deviceNumber = devNum;
@ -109,6 +125,12 @@ Device::Device( int anum, int tnum, fe_type_t t, const QString &n, bool as )
source = "";
canAutoscan= as;
tuningTimeout = 1500;
hasCAM = false;
camMaxService = 1;
secMini = 0;
secTwice = 0;
priority = 10;
doS2 = 0;
}
@ -134,6 +156,7 @@ DVBconfig::DVBconfig( const QString &dvbConf )
sizeFile = 0;
categories.setAutoDelete( true );
devList.setAutoDelete( true );
readFirst();
startup();
readConfig();
}
@ -187,6 +210,7 @@ void DVBconfig::startup()
int i=0, j=0, res, fdFrontend=0;
struct dvb_frontend_info info;
bool as;
QTime t1;
QStringList list, flist;
QString s, t;
@ -200,6 +224,11 @@ void DVBconfig::startup()
for ( j=0; j<(int)flist.count(); j++ ) {
s = list[i];
t = flist[j];
if ( devList.count()==MAX_DEVICES )
break;
if ( !probeMfe && t!="frontend0" )
continue;
t1 = QTime::currentTime();
fdFrontend = open( QString("/dev/dvb/%1/%2").arg( s ).arg( t ).ascii(), O_RDWR);
if ( fdFrontend>0 ) {
if ( !(res = ioctl( fdFrontend, FE_GET_INFO, &info ) < 0) ) {
@ -212,13 +241,14 @@ void DVBconfig::startup()
as = true;
else
as = false;
fprintf(stderr,"/dev/dvb/%s/%s : opened ( %s )\n", s.ascii(), t.ascii(), info.name );
fprintf(stderr,"/dev/dvb/%s/%s : opened ( %s ) (%dms)\n", s.ascii(), t.ascii(), info.name, t1.msecsTo(QTime::currentTime()) );
devList.append( new Device( s.replace("adapter","").toInt(), t.replace("frontend","").toInt(), info.type, info.name, as ) );
}
close( fdFrontend );
}
else
perror( QString("/dev/dvb/%1/%2").arg( s ).arg( t ).ascii() );
else {
perror( QString("/dev/dvb/%1/%2 %3/%4").arg( s ).arg( t ).arg( errno ).arg( -EBUSY ).ascii() );
}
}
}
@ -292,9 +322,9 @@ bool DVBconfig::localData()
bool DVBconfig::haveData()
{
if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() ) {
if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() || !QDir( dvbConfigDir+"atsc" ).exists()) {
loadDvbData(0);
if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() ) {
if ( !QDir( dvbConfigDir+"dvb-s" ).exists() || !QDir( dvbConfigDir+"dvb-c" ).exists() || !QDir( dvbConfigDir+"dvb-t" ).exists() || !QDir( dvbConfigDir+"atsc" ).exists() ) {
if ( !localData() )
return false;
}
@ -313,6 +343,7 @@ QStringList DVBconfig::getSourcesList( fe_type_t type )
case FE_QPSK : s = "dvb-s"; break;
case FE_QAM : s = "dvb-c"; break;
case FE_OFDM : s = "dvb-t"; break;
case FE_ATSC : s = "atsc"; break;
default : return list;
}
list = QDir( dvbConfigDir+s ).entryList( QDir::Files, QDir::Name );
@ -383,6 +414,14 @@ void DVBconfig::saveDvbChanOrder( int s, int col )
void DVBconfig::readFirst()
{
config->setGroup( "DVB Options" );
probeMfe = config->readNumEntry( "ProbeMFE", 1 );
}
void DVBconfig::readConfig()
{
QSize size;
@ -413,6 +452,8 @@ void DVBconfig::readConfig()
for ( i=0; i<(int)devList.count(); i++ ) {
devList.at(i)->source = config->readEntry( QString("DVB%1").arg(i), "" );
devList.at(i)->tuningTimeout = config->readNumEntry( QString("DVB%1_TIMEOUT").arg(i), 1500 );
devList.at(i)->camMaxService = config->readNumEntry( QString("DVB%1_CAM_MAX").arg(i), 1 );
devList.at(i)->priority = config->readNumEntry( QString("DVB%1_PRIORITY").arg(i), 10 );
if ( devList.at(i)->type!=FE_QPSK )
continue;
devList.at(i)->numLnb = config->readNumEntry( QString("DVB%1_NLNB").arg(i), 1 );
@ -426,6 +467,9 @@ void DVBconfig::readConfig()
devList.at(i)->lnb[j].speed13v = config->readDoubleNumEntry( QString("DVB%1_LNB%2_speed13v").arg(i).arg(j), 2.5 );
devList.at(i)->lnb[j].speed18v = config->readDoubleNumEntry( QString("DVB%1_LNB%2_speed18v").arg(i).arg(j), 1.5 );
}
devList.at(i)->secMini = config->readNumEntry( QString("DVB%1_SEC_MINI").arg(i), 0 );
devList.at(i)->secTwice = config->readNumEntry( QString("DVB%1_SEC_TWICE").arg(i), 0 );
devList.at(i)->doS2 = config->readNumEntry( QString("DVB%1_DOS2").arg(i), 0 );
}
j = config->readNumEntry( "NumCategories", 0 );
for ( i=0; i<j; i++ )
@ -442,6 +486,9 @@ void DVBconfig::readConfig()
devList.at(i)->usalsLatitude = usalsLatitude;
devList.at(i)->usalsLongitude = usalsLongitude;
}
ringBufSize = config->readNumEntry( "RingBufSize", 2 );
if ( ringBufSize<2 )
ringBufSize = 2;
}
@ -463,9 +510,12 @@ void DVBconfig::saveConfig()
config->writeEntry( "BroadcastAddress", broadcastAddress );
config->writeEntry( "BroadcastPort", broadcastPort );
config->writeEntry( "SenderPort", senderPort );
config->writeEntry( "ProbeMFE", probeMfe );
for ( i=0; i<(int)devList.count(); i++ ) {
config->writeEntry( QString("DVB%1").arg(i), devList.at(i)->source );
config->writeEntry( QString("DVB%1_TIMEOUT").arg(i), devList.at(i)->tuningTimeout );
config->writeEntry( QString("DVB%1_PRIORITY").arg(i), devList.at(i)->priority );
config->writeEntry( QString("DVB%1_CAM_MAX").arg(i), devList.at(i)->camMaxService );
if ( devList.at(i)->type!=FE_QPSK )
continue;
config->writeEntry( QString("DVB%1_NLNB").arg(i), devList.at(i)->numLnb );
@ -479,6 +529,9 @@ void DVBconfig::saveConfig()
config->writeEntry( QString("DVB%1_LNB%2_speed13v").arg(i).arg(j), devList.at(i)->lnb[j].speed13v );
config->writeEntry( QString("DVB%1_LNB%2_speed18v").arg(i).arg(j), devList.at(i)->lnb[j].speed18v );
}
config->writeEntry( QString("DVB%1_SEC_MINI").arg(i), devList.at(i)->secMini );
config->writeEntry( QString("DVB%1_SEC_TWICE").arg(i), devList.at(i)->secTwice );
config->writeEntry( QString("DVB%1_DOS2").arg(i), devList.at(i)->doS2 );
}
config->writeEntry( "NumCategories", categories.count() );
for ( i=0; i<(int)categories.count(); i++ ) {
@ -494,6 +547,7 @@ void DVBconfig::saveConfig()
config->writeEntry( "UsalsLatitude", usalsLatitude );
config->writeEntry( "UsalsLongitude", usalsLongitude );
config->writeEntry( "SizeFile", sizeFile );
config->writeEntry( "RingBufSize", ringBufSize );
config->sync();
}
@ -511,7 +565,7 @@ bool DVBconfig::firstRun()
DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p ) :
DvbConfigDialog::DvbConfigDialog( DvbPanel *pan, DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p ) :
KDialogBase ( IconList, i18n("DVB Settings"), Ok|Cancel, Ok, parent, "dvbConfigDialog", true, true )
{
QLabel *lab;
@ -529,7 +583,7 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu
QSpinBox *spin;
KPushButton *usals;
QWidget *swidg;
QStringList rotorList; rotorList<<i18n("No rotor")<<i18n("USALS rotor")<<i18n("Positions rotor");
QStringList rotorList; rotorList<<i18n("No rotor")<<i18n("USALS rotor")<<i18n("Positions rotor")<<i18n("External positionner");
dvbConfig = dc;
timeoutSpin.setAutoDelete( true );
@ -558,7 +612,22 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu
case FE_ATSC : dvbType->setText( i18n("Atsc") ); break;
default : dvbType->setText( i18n("Unknown") );
}
grid->addMultiCellWidget( dvbType, gridLine, gridLine, 1, 3 );
if ( dvbConfig->devList.at(i)->hasCAM ) {
grid->addWidget( dvbType, gridLine, 1 );
MCAMButton *camb = new MCAMButton( gb, i );
connect( camb, SIGNAL(clicked(int)), pan, SLOT(camClicked(int)) );
grid->addWidget( camb, gridLine, 2 );
}
else
grid->addMultiCellWidget( dvbType, gridLine, gridLine, 1, 3 );
++gridLine;
lab = new QLabel( i18n("Tuner priority (0=Don't use):"), gb );
grid->addWidget( lab, gridLine, 0 );
spin = new QSpinBox( 0, 99, 1, gb );
spin->setValue( dvbConfig->devList.at(i)->priority );
priority.append( spin );
grid->addWidget( spin, gridLine, 1 );
++gridLine;
lab = new QLabel( i18n("Tuner timeout :"), gb );
@ -572,6 +641,11 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu
++gridLine;
if ( dvbConfig->devList.at(i)->type==FE_QPSK ) {
doS2[i] = new QCheckBox( i18n("S2 capable device"), gb );
doS2[i]->setChecked( dvbConfig->devList.at(i)->doS2 );
grid->addWidget( doS2[i], gridLine, 0 );
++gridLine;
lab = new QLabel( i18n("Number of LNBs:"), gb );
grid->addWidget( lab, gridLine, 0 );
satNumber[i] = new MSpinBox( gb, i );
@ -582,6 +656,16 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu
connect( usals, SIGNAL(clicked()), this, SLOT(setUsals()));
grid->addWidget( usals, gridLine, 2 );
++gridLine;
secMini[i] = new QCheckBox( i18n("Mini DiSEqC (A-B)."), gb );
secMini[i]->setChecked( dvbConfig->devList.at(i)->secMini );
secMini[i]->setEnabled( false );
grid->addWidget( secMini[i], gridLine, 1 );
secTwice[i] = new QCheckBox( i18n("Send DiSEqC commands twice."), gb );
secTwice[i]->setChecked( dvbConfig->devList.at(i)->secTwice );
grid->addWidget( secTwice[i], gridLine, 0 );
++gridLine;
lnb0[i] = new MPushButton( gb, i, 0 );
@ -853,9 +937,19 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu
vb = new QVBoxLayout( page, 6, 6 );
gb = new QGroupBox( "", page );
grid = new QGridLayout( gb, 1, 1, 20, 6 );
probeMfe = new QCheckBox( i18n("Probe Multiple-Frontends (Restart required)."), gb );
probeMfe->setChecked( dvbConfig->probeMfe );
grid->addWidget( probeMfe, 0, 0 );
lab = new QLabel( i18n("LiveShow ringbuffer size (MB) :"), gb );
grid->addWidget( lab, 1, 0 );
ringBufSize = new QSpinBox( 2, 99, 1, gb );
ringBufSize->setValue( dvbConfig->ringBufSize );
grid->addWidget( ringBufSize, 1, 1 );
lab = new QLabel( i18n("Default charset (restart needed):"), gb );
grid->addWidget( lab, 0, 0 );
grid->addWidget( lab, 2, 0 );
charsetComb = new QComboBox( gb );
charsetComb->insertItem( "ISO8859-1" );
charsetComb->insertItem( "ISO6937" );
@ -863,19 +957,19 @@ DvbConfigDialog::DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlu
charsetComb->setCurrentItem( 0 );
else if ( dvbConfig->defaultCharset=="ISO6937" )
charsetComb->setCurrentItem( 1 );
grid->addWidget( charsetComb, 0, 1 );
grid->addWidget( charsetComb, 2, 1 );
lab = new QLabel( i18n("Update scan data:"), gb );
grid->addWidget( lab, 1, 0 );
grid->addWidget( lab, 3, 0 );
updateBtn = new KPushButton( gb );
updateBtn->setGuiItem( KGuiItem(i18n("Download"), icon->loadIconSet("khtml_kget", KIcon::Small) ) );
grid->addWidget( updateBtn, 1, 1 );
grid->addWidget( updateBtn, 3, 1 );
lab = new QLabel( i18n("Dump epg's events to \n~/kaffeine_dvb_events.tx:"), gb );
grid->addWidget( lab, 2, 0 );
grid->addWidget( lab, 4, 0 );
dumpBtn = new KPushButton( gb );
dumpBtn->setGuiItem( KGuiItem(i18n("Dump"), icon->loadIconSet("filesave", KIcon::Small) ) );
grid->addWidget( dumpBtn, 2, 1 );
grid->addWidget( dumpBtn, 4, 1 );
vb->addWidget( gb );
vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
@ -1039,6 +1133,8 @@ void DvbConfigDialog::satNumberChanged( int value, int devNum )
rotor1[devNum]->setEnabled( value > 1 );
rotor2[devNum]->setEnabled( value > 2 );
rotor3[devNum]->setEnabled( value > 3 );
secMini[devNum]->setEnabled( value==2 );
}
@ -1103,6 +1199,9 @@ void DvbConfigDialog::accept()
switch (dvbConfig->devList.at(i)->type) {
case FE_QPSK: {
dvbConfig->devList.at(i)->numLnb = satNumber[i]->value();
dvbConfig->devList.at(i)->secMini = secMini[i]->isChecked();
dvbConfig->devList.at(i)->secTwice = secTwice[i]->isChecked();
dvbConfig->devList.at(i)->doS2 = doS2[i]->isChecked();
if ( dvbConfig->devList.at(i)->lnb[3].rotorType==0 ) {
dvbConfig->devList.at(i)->lnb[3].source.clear();
dvbConfig->devList.at(i)->lnb[3].source.append(sat3[i]->currentText());
@ -1140,6 +1239,7 @@ void DvbConfigDialog::accept()
}
dvbConfig->devList.at(i)->source = s;
dvbConfig->devList.at(i)->tuningTimeout = timeoutSpin.at(i)->value();
dvbConfig->devList.at(i)->priority = priority.at(i)->value();
}
dvbConfig->recordDir = recordDirLe->text();
@ -1157,6 +1257,8 @@ void DvbConfigDialog::accept()
dvbConfig->broadcastAddress = broadcastLe->text().stripWhiteSpace();
dvbConfig->broadcastPort = bportSpin->value();
dvbConfig->senderPort = sportSpin->value();
dvbConfig->probeMfe = probeMfe->isChecked();
dvbConfig->ringBufSize = ringBufSize->value();
dvbConfig->saveConfig();
done( Accepted );
}
@ -1403,22 +1505,24 @@ RotorConfig::RotorConfig( Device *d, DVBconfig *c, int lnb, QWidget *parent ) :
vb->addWidget( resetBtn );
vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Fixed, QSizePolicy::Fixed ) );
grid = new QGridLayout( 0, 1, 1 );
lab = new QLabel( i18n("13V rotor speed:"), page );
grid->addWidget( lab, 0, 0 );
speed13 = new QLineEdit( page );
speed13->setText( QString().setNum( dev->lnb[lnbNum].speed13v ) );
grid->addWidget( speed13, 0, 1 );
lab = new QLabel( i18n("sec./ °"), page );
grid->addWidget( lab, 0, 2 );
lab = new QLabel( i18n("18V rotor speed:"), page );
grid->addWidget( lab, 1, 0 );
speed18 = new QLineEdit( page );
speed18->setText( QString().setNum( dev->lnb[lnbNum].speed18v ) );
grid->addWidget( speed18, 1, 1 );
lab = new QLabel( i18n("sec./ °"), page );
grid->addWidget( lab, 1, 2 );
vb->addLayout( grid );
if ( dev->lnb[lnbNum].rotorType!=3 ) {
grid = new QGridLayout( 0, 1, 1 );
lab = new QLabel( i18n("13V rotor speed:"), page );
grid->addWidget( lab, 0, 0 );
speed13 = new QLineEdit( page );
speed13->setText( QString().setNum( dev->lnb[lnbNum].speed13v ) );
grid->addWidget( speed13, 0, 1 );
lab = new QLabel( i18n("sec./ °"), page );
grid->addWidget( lab, 0, 2 );
lab = new QLabel( i18n("18V rotor speed:"), page );
grid->addWidget( lab, 1, 0 );
speed18 = new QLineEdit( page );
speed18->setText( QString().setNum( dev->lnb[lnbNum].speed18v ) );
grid->addWidget( speed18, 1, 1 );
lab = new QLabel( i18n("sec./ °"), page );
grid->addWidget( lab, 1, 2 );
vb->addLayout( grid );
}
vb->addItem( new QSpacerItem( 20, 20, QSizePolicy::Ignored, QSizePolicy::Ignored ) );
@ -1462,8 +1566,14 @@ void RotorConfig::accept()
{
QListViewItem *it;
dev->lnb[lnbNum].speed18v = speed18->text().toDouble();
dev->lnb[lnbNum].speed13v = speed13->text().toDouble();
if ( dev->lnb[lnbNum].rotorType!=3 ) {
dev->lnb[lnbNum].speed18v = speed18->text().toDouble();
dev->lnb[lnbNum].speed13v = speed13->text().toDouble();
}
else {
dev->lnb[lnbNum].speed18v = 0;
dev->lnb[lnbNum].speed13v = 0;
}
dev->lnb[lnbNum].source.clear();
dev->lnb[lnbNum].position.clear();
for ( it=listView->firstChild(); it; it=it->nextSibling() ) {

@ -28,6 +28,7 @@
#include <qtoolbutton.h>
#include <qbuttongroup.h>
#include <qlistview.h>
#include <qcheckbox.h>
#include <kdialogbase.h>
#include <kpushbutton.h>
@ -37,6 +38,8 @@
#include <linux/dvb/frontend.h>
#define MAX_DEVICES 8
using namespace KIO;
class MSpinBox : public QSpinBox
@ -70,6 +73,21 @@ private:
class MCAMButton : public QPushButton
{
Q_OBJECT
public:
MCAMButton( QWidget *parent, int devNum );
private slots:
void isClicked();
signals:
void clicked( int devnum );
private:
int deviceNumber;
};
class MComboBox : public QComboBox
{
Q_OBJECT
@ -116,6 +134,12 @@ public:
bool canAutoscan;
int tuningTimeout;
double usalsLatitude, usalsLongitude;
bool hasCAM;
int camMaxService;
int secMini;
int secTwice;
int priority;
int doS2;
};
@ -138,6 +162,7 @@ public:
DVBconfig( const QString &dvbConf );
~DVBconfig();
void readFirst();
void readConfig();
void saveConfig();
int readDvbChanOrder();
@ -168,6 +193,8 @@ public:
QValueList<int> splitSizes;
QString defaultCharset;
double usalsLatitude, usalsLongitude;
int probeMfe;
int ringBufSize;
private:
@ -183,6 +210,7 @@ private slots:
class KaffeineDvbPlugin;
class DvbPanel;
class DvbConfigDialog : public KDialogBase
{
@ -190,34 +218,39 @@ class DvbConfigDialog : public KDialogBase
public:
DvbConfigDialog( DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p );
DvbConfigDialog( DvbPanel *pan, DVBconfig *dc, QWidget *parent, KaffeineDvbPlugin *p );
~DvbConfigDialog();
void setSource( QComboBox *box, QString s );
QLineEdit *recordDirLe, *shiftDirLe, *broadcastLe, *filenameFormatLe;
QSpinBox *beginSpin, *endSpin, *instantDurationSpin, *bportSpin, *sportSpin, *sizeFileSpin;
MSpinBox *satNumber[8];
QComboBox *sat0[8];
QComboBox *sat1[8];
QComboBox *sat2[8];
QComboBox *sat3[8];
MPushButton *src0[8];
MPushButton *src1[8];
MPushButton *src2[8];
MPushButton *src3[8];
MComboBox *rotor0[8];
MComboBox *rotor1[8];
MComboBox *rotor2[8];
MComboBox *rotor3[8];
MPushButton *lnb0[8];
MPushButton *lnb1[8];
MPushButton *lnb2[8];
MPushButton *lnb3[8];
MSpinBox *satNumber[MAX_DEVICES];
QCheckBox *secMini[MAX_DEVICES], *secTwice[MAX_DEVICES];
QCheckBox *doS2[MAX_DEVICES];
QComboBox *sat0[MAX_DEVICES];
QComboBox *sat1[MAX_DEVICES];
QComboBox *sat2[MAX_DEVICES];
QComboBox *sat3[MAX_DEVICES];
MPushButton *src0[MAX_DEVICES];
MPushButton *src1[MAX_DEVICES];
MPushButton *src2[MAX_DEVICES];
MPushButton *src3[MAX_DEVICES];
MComboBox *rotor0[MAX_DEVICES];
MComboBox *rotor1[MAX_DEVICES];
MComboBox *rotor2[MAX_DEVICES];
MComboBox *rotor3[MAX_DEVICES];
MPushButton *lnb0[MAX_DEVICES];
MPushButton *lnb1[MAX_DEVICES];
MPushButton *lnb2[MAX_DEVICES];
MPushButton *lnb3[MAX_DEVICES];
KPushButton *updateBtn, *dumpBtn;
QToolButton *recordDirBtn, *shiftDirBtn, *helpNameBtn;
DVBconfig *dvbConfig;
QComboBox *charsetComb;
QPtrList<QSpinBox> timeoutSpin;
QPtrList<QSpinBox> priority;
QCheckBox *probeMfe;
QSpinBox *ringBufSize;
private slots:

@ -136,19 +136,23 @@ void DVBout::writePmt()
tspmt[0x0a] = 0xc1;
// section # and last section #
tspmt[0x0b] = tspmt[0x0c] = 0x00;
// PCR PID
tspmt[0x0d] = channel.vpid>>8; tspmt[0x0e] = channel.vpid&0xff;
if ( channel.vpid ) {
// PCR PID
tspmt[0x0d] = channel.vpid>>8; tspmt[0x0e] = channel.vpid&0xff;
}
else if ( channel.napid )
tspmt[0x0d] = channel.apid[0].pid>>8; tspmt[0x0e] = channel.apid[0].pid&0xff;
// program_info_length == 0
tspmt[0x0f] = 0xf0; tspmt[0x10] = 0x00;
// Program Map / Video PID
tspmt[0x11] = channel.vType; // video stream type
tspmt[0x12] = channel.vpid>>8; tspmt[0x13] = channel.vpid&0xff;
tspmt[0x14] = 0xf0; tspmt[0x15] = 0x09; // es info length
// useless info
tspmt[0x16] = 0x07; tspmt[0x17] = 0x04; tspmt[0x18] = 0x08; tspmt[0x19] = 0x80;
tspmt[0x1a] = 0x24; tspmt[0x1b] = 0x02; tspmt[0x1c] = 0x11; tspmt[0x1d] = 0x01;
tspmt[0x1e] = 0xfe;
off = 0x1e;
if ( channel.vpid ) {
// Program Map / Video PID
tspmt[0x11] = channel.vType; // video stream type
tspmt[0x12] = channel.vpid>>8; tspmt[0x13] = channel.vpid&0xff;
tspmt[0x14] = 0xf0; tspmt[0x15] = 0x00; // es info length
off = 0x15;
}
else
off = 0x10;
// audio pids
i = 0;
for ( i=0; i<channel.napid && i<MAX_AUDIO; i++ ) {
@ -258,20 +262,19 @@ bool DVBout::doPause( const QString &name ) // called from dvbstream::run()
liveFile.writeBlock( (char*)tspmt, TS_SIZE );
mutex.lock();
haveLive = false;
mutex.unlock();
if ( !wait(100) ) {
if ( !wait(1000) ) {
terminate();
wait();
}
mutex.lock();
haveLive = true;
if ( close( fdPipe )<0 )
perror("close out pipe: ");
else
fprintf(stderr,"out pipe closed\n");
fdPipe = 0;
mutex.unlock();
if ( wDist>0 )
liveFile.writeBlock( (char*)(wBuf+(wRead*TS_SIZE*NTS)), TS_SIZE*NTS*wDist );
timeShifting = true;
mutex.unlock();
//emit shifting( timeShifting );
}
return true;
@ -286,7 +289,7 @@ void DVBout::setPatPmt()
bool DVBout::goLive( const QString &name )
bool DVBout::goLive( const QString &name, int ringBufSize )
{
if ( fdPipe ) return false;
@ -299,7 +302,8 @@ bool DVBout::goLive( const QString &name )
writePmt();
if ( !pids.contains(8192) )
patpmt = wpatpmt = true;
wBuf = new unsigned char[TS_SIZE*NTS*100];
wbufSize = ringBufSize*1024*1024/(TS_SIZE*NTS);
wBuf = new unsigned char[TS_SIZE*NTS*wbufSize];
if ( !wBuf ) fprintf( stderr, "\nNO WBUF !!!\n\n" );
wRead = wWrite = wDist = 0;
start();
@ -326,7 +330,7 @@ void DVBout::stopLive()
emit shifting( timeShifting );
}
mutex.unlock();
if ( !wait(500) ) {
if ( !wait(1000) ) {
terminate();
wait();
}
@ -469,14 +473,16 @@ void DVBout::process( unsigned char *buf, int size )
beginLive = !beginLive;
start();
}
if ( wDist<95 ) {
if ( wDist<wbufSize ) {
memcpy( wBuf+(wWrite*TS_SIZE*NTS), thBuf, TS_SIZE*NTS );
wpatpmt = patpmt;
++wDist;
++wWrite;
if ( wWrite>99 )
if ( wWrite==wbufSize )
wWrite = 0;
//fprintf(stderr,"WDIST = %d\n",wDist);
}
else {
fprintf(stderr,"Live ringbuffer full!! (%d)\n",wDist);
}
}
else if ( timeShifting ) {
@ -531,7 +537,7 @@ void DVBout::run()
{
if ( haveLive && fdPipe ) {
while ( haveLive && fdPipe ) {
if ( wDist>0 ) {
if ( wDist>5 ) {
if ( wpatpmt ) {
write( fdPipe, tspat, TS_SIZE );
write( fdPipe, tspmt, TS_SIZE );
@ -540,11 +546,12 @@ void DVBout::run()
write( fdPipe, wBuf+(wRead*TS_SIZE*NTS), TS_SIZE*NTS );
--wDist;
++wRead;
if ( wRead>99 )
if ( wRead==wbufSize )
wRead = 0;
}
else
else {
usleep( 100 );
}
}
return;
}

@ -44,7 +44,7 @@ public:
DVBout( ChannelDesc chan, int anum, int tnum, KaffeineDvbPlugin *p );
~DVBout();
void process( unsigned char *buf, int size );
bool goLive( const QString &name );
bool goLive( const QString &name, int ringBufSize );
void preStopLive();
void stopLive();
bool goBroadcast( Ts2Rtp *r );
@ -102,6 +102,7 @@ private:
int fileNumber;
QString fileName;
long long int fileMaxSize;
int wbufSize;
signals:

@ -45,7 +45,6 @@
#include <kxmlguifactory.h>
#include <kparts/componentfactory.h>
#include "kaffeineinput.h"
#include "kaffeinedvbplugin.h"
#include "dvbpanel.h"
#include "channeldesc.h"
@ -56,6 +55,12 @@
#define CHANICONSIZE 28
#define MODE_FREE 0
#define MODE_LIVE 100
#define MODE_BROADCAST 200
#define MODE_RECORD 300
#define MODE_CANTDO 400
DIconViewItem::DIconViewItem( DvbPanel *pan, QIconView *parent, const QString &text, const QPixmap &icon )
@ -1091,7 +1096,7 @@ void DvbPanel::setConfig()
void DvbPanel::showConfigDialog()
{
int ret;
int i, ret;
loop:
if ( !dvbConfig->haveData() ) {
@ -1104,7 +1109,9 @@ loop:
return;
}
DvbConfigDialog dlg( dvbConfig, mainWidget, plug );
for ( i=0; i<(int)dvb.count(); i++ )
dvb.at(i)->probeCam();
DvbConfigDialog dlg( this, dvbConfig, mainWidget, plug );
connect( dlg.dumpBtn, SIGNAL(clicked()), this, SLOT(dumpEvents()) );
ret = dlg.exec();
disconnect( dlg.dumpBtn, SIGNAL(clicked()), this, SLOT(dumpEvents()) );
@ -1112,6 +1119,14 @@ loop:
return;
rtp->setSocket( dvbConfig->broadcastAddress, dvbConfig->broadcastPort, dvbConfig->senderPort );
cleaner->setPaths( dvbConfig->shiftDir, dvbConfig->recordDir );
fillChannelList();
}
void DvbPanel::camClicked( int devNum )
{
dvb.at(devNum)->showCamDialog();
}
@ -1124,6 +1139,8 @@ QPtrList<Transponder> DvbPanel::getSourcesStatus()
Transponder t;
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( !dvb.at(i)->getPriority() ) // priority==0==don't use
continue;
list = dvb.at(i)->getSources();
for ( j=0; j<(int)list.count(); j++ ) {
if ( dvb.at(i)->hasRec() || dvb.at(i)->hasBroadcast() )
@ -1176,7 +1193,7 @@ void DvbPanel::fillChannelList( ChannelDesc *ch )
}
else if ( currentCategory!="All" && chan->category!=currentCategory )
continue;
it = new KListViewItem( channelsCb, QString().sprintf("%04d", chan->num), chan->name, chan->tp.source );
it = new KListViewItem( channelsCb, QString().sprintf("%05d", chan->num), chan->name, chan->tp.source );
if ( ch && ch==chan )
visible = it;
it->setDragEnabled( true );
@ -1211,15 +1228,15 @@ void DvbPanel::fillChannelList( ChannelDesc *ch )
DvbStream* DvbPanel::getWorkingDvb( int mode, ChannelDesc *chan )
{
int i, ret;
QValueList<int> working; // notTuned=0, hasLive=1, hasBroadcast=2, hasRec=3, can'tDoChannel=4
QValueList<int> working; // free=0, hasLive=100, hasBroadcast=200, hasRec=300, can'tDoChannel=400
for ( i=0; i<(int)dvb.count(); i++ )
working.append( 0 );
working.append( 100-dvb.at(i)->getPriority() );
// fill in working status
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( !dvb.at(i)->canSource( chan ) ) {
working[i] = 4;
if ( !dvb.at(i)->canSource( chan ) || working[i]==100 ) {
working[i] = MODE_CANTDO;
continue;
}
if ( dvb.at(i)->isTuned() ) {
@ -1227,14 +1244,18 @@ DvbStream* DvbPanel::getWorkingDvb( int mode, ChannelDesc *chan )
return dvb.at(i); // use that one since it's already tuned on the good mplex
}
else if ( dvb.at(i)->hasRec() )
working[i] = 3;
working[i] += MODE_RECORD;
else if ( dvb.at(i)->hasBroadcast() )
working[i] = 2;
else
working[i] = 1;
working[i] += MODE_BROADCAST;
else {
if ( mode==MODE_LIVE )
working[i] += MODE_FREE;
else
working[i] += MODE_LIVE;
}
}
else
working[i] = 0;
working[i] += MODE_FREE;
}
ret = 0;
// search for least working card
@ -1272,7 +1293,7 @@ void DvbPanel::setBroadcast()
return;
}
d = getWorkingDvb( 2, list.at(0) );
d = getWorkingDvb( MODE_BROADCAST, list.at(0) );
if ( d )
ret = d->canStartBroadcast( live, list.at(0) );
@ -1316,7 +1337,7 @@ void DvbPanel::checkTimers()
}
if ( !chan )
continue;
d = getWorkingDvb( 3, chan );
d = getWorkingDvb( MODE_RECORD, chan );
live = false;
if ( d )
ret = d->canStartTimer( live, chan );
@ -1826,7 +1847,7 @@ void DvbPanel::playLastChannel()
QTimer::singleShot( 2000, this, SLOT(playLastChannel()) );
return;
}
d = getWorkingDvb( 2, list.at(0) );
d = getWorkingDvb( MODE_BROADCAST, list.at(0) );
if ( d )
ret = d->canStartBroadcast( live, list.at(0) );
else
@ -1880,7 +1901,7 @@ void DvbPanel::next()
QListViewItem* nextItem;
QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%04d", dvbConfig->lastChannel), 0 );
QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%05d", dvbConfig->lastChannel), 0 );
if ( !playingItem == 0 ) // yes, it's in the current category
{
@ -1906,7 +1927,7 @@ void DvbPanel::previous()
QListViewItem* prevItem;
QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%04d", dvbConfig->lastChannel), 0 );
QListViewItem* playingItem = channelsCb->findItem( QString().sprintf("%05d", dvbConfig->lastChannel), 0 );
if ( !playingItem == 0 ) // yes, it's in the current category
{
@ -1927,19 +1948,14 @@ void DvbPanel::previous()
void DvbPanel::dvbZap( ChannelDesc *chan )
{
int i;
DvbStream *d=0;
DvbStream *d;
if ( currentFifo.isEmpty() || isTuning )
return;
isTuning = true;
emit setTimeShiftFilename( "" );
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) {
d = dvb.at(i);
break;
}
}
d = getWorkingDvb( MODE_LIVE, chan );
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( dvb.at(i)->hasLive() ) {
dvb.at(i)->preStopLive();
@ -1973,40 +1989,20 @@ void DvbPanel::finalZap( DvbStream *d, ChannelDesc *chan )
{
QString s, t;
int i;
DvbStream *d1=d, *d2=0;
emit setCurrentPlugin( this );
fprintf( stderr, "Tuning to: %s / autocount: %lu\n", chan->name.latin1(), autocount );
QTime tm;
tm.start();
if ( !d1 ) {
for ( i=0; i<(int)dvb.count(); i++ ) {
if ( !dvb.at(i)->canSource( chan ) )
continue;
if ( dvb.at(i)->isTuned() ) {
if ( dvb.at(i)->getCurrentTransponder()==chan->tp ) {
d1 = dvb.at(i);
break;
}
else d2 = dvb.at(i);
}
else {
d1 = dvb.at(i);
break;
}
}
if ( !d1 && d2 )
d1 = d2;
}
if ( !d1 ) {
if ( !d ) {
emit dvbStop();
isTuning = false;
return;
}
int ret = d1->goLive( chan, currentFifo );
int ret = d->goLive( chan, currentFifo, dvbConfig->ringBufSize );
switch ( ret ) {
case DvbStream::ErrIsRecording :
@ -2045,7 +2041,7 @@ void DvbPanel::finalZap( DvbStream *d, ChannelDesc *chan )
resetSearch();
}
if ( d1->liveIsRecording() )
if ( d->liveIsRecording() )
recordBtn->setOn( true );
else
recordBtn->setOn( false );
@ -2255,6 +2251,8 @@ bool DvbPanel::getChannelList()
case 67 : chan->tp.coderateH = FEC_6_7; break;
case 78 : chan->tp.coderateH = FEC_7_8; break;
case 89 : chan->tp.coderateH = FEC_8_9; break;
case 35 : chan->tp.coderateH = FEC_3_5; break;
case 910 : chan->tp.coderateH = FEC_9_10; break;
case -1 : chan->tp.coderateH = FEC_AUTO;
}
s = s.right( s.length()-pos-1 );
@ -2275,6 +2273,9 @@ bool DvbPanel::getChannelList()
case 256 : chan->tp.modulation = QAM_256; break;
case 108 : chan->tp.modulation = VSB_8; break;
case 116 : chan->tp.modulation = VSB_16; break;
case 1000 : chan->tp.modulation = PSK_8; break;
case 1001 : chan->tp.modulation = APSK_16; break;
case 1003 : chan->tp.modulation = DQPSK; break;
case -1 : chan->tp.modulation = QAM_AUTO;
}
s = s.right( s.length()-pos-1 );
@ -2289,6 +2290,8 @@ bool DvbPanel::getChannelList()
case 67 : chan->tp.coderateL = FEC_6_7; break;
case 78 : chan->tp.coderateL = FEC_7_8; break;
case 89 : chan->tp.coderateL = FEC_8_9; break;
case 35 : chan->tp.coderateH = FEC_3_5; break;
case 910 : chan->tp.coderateH = FEC_9_10; break;
case -1 : chan->tp.coderateL = FEC_AUTO;
}
s = s.right( s.length()-pos-1 );
@ -2356,6 +2359,17 @@ bool DvbPanel::getChannelList()
s = s.right( s.length()-pos-1 );
pos = s.find("|");
chan->tp.nid = s.left(pos).toUShort();
s = s.right( s.length()-pos-1 );
pos = s.find("|");
switch ( s.left(pos).toInt() ) {
case 20 : chan->tp.rolloff = ROLLOFF_20; break;
case 25 : chan->tp.rolloff = ROLLOFF_25; break;
case 35 : chan->tp.rolloff = ROLLOFF_35; break;
case -1 : chan->tp.rolloff = ROLLOFF_AUTO;
}
s = s.right( s.length()-pos-1 );
pos = s.find("|");
chan->tp.S2 = s.left(pos).toInt();
if ( chan->tp.source.isEmpty() ) {
delete chan;
@ -2363,7 +2377,7 @@ bool DvbPanel::getChannelList()
}
chan->pix.load( dvbConfig->dvbConfigIconsDir+chan->name );
it = new KListViewItem( channelsCb, QString().sprintf("%04d", chan->num), chan->name, chan->tp.source );
it = new KListViewItem( channelsCb, QString().sprintf("%05d", chan->num), chan->name, chan->tp.source );
it->setDragEnabled( true );
if ( !chan->pix.isNull() )
it->setPixmap( 1, chan->pix );
@ -2467,6 +2481,8 @@ bool DvbPanel::saveChannelList()
case FEC_6_7 : tt<< "67|"; break;
case FEC_7_8 : tt<< "78|"; break;
case FEC_8_9 : tt<< "89|"; break;
case FEC_3_5 : tt<< "35|"; break;
case FEC_9_10 : tt<< "910|"; break;
case FEC_AUTO : tt<< "-1|";
}
switch ( chan->tp.inversion ) {
@ -2483,6 +2499,9 @@ bool DvbPanel::saveChannelList()
case QAM_256 : tt<< "256|"; break;
case VSB_8 : tt<< "108|"; break;
case VSB_16 : tt<< "116|"; break;
case PSK_8 : tt<< "1000|"; break;
case APSK_16 : tt<< "1001|"; break;
case DQPSK : tt<< "1003|"; break;
case QAM_AUTO : tt<< "-1|";
}
switch ( chan->tp.coderateL ) {
@ -2495,6 +2514,8 @@ bool DvbPanel::saveChannelList()
case FEC_6_7 : tt<< "67|"; break;
case FEC_7_8 : tt<< "78|"; break;
case FEC_8_9 : tt<< "89|"; break;
case FEC_3_5 : tt<< "35|"; break;
case FEC_9_10 : tt<< "910|"; break;
case FEC_AUTO : tt<< "-1|";
}
switch ( chan->tp.bandwidth ) {
@ -2533,7 +2554,15 @@ bool DvbPanel::saveChannelList()
}
tt<< "|";
tt<< chan->category+"|";
tt<< s.setNum(chan->tp.nid)+"|\n";
tt<< s.setNum(chan->tp.nid)+"|";
switch ( chan->tp.rolloff ) {
case ROLLOFF_20 : tt<< "20|"; break;
case ROLLOFF_25 : tt<< "25|"; break;
case ROLLOFF_35 : tt<< "35|"; break;
case ROLLOFF_AUTO : tt<< "-1|";
}
tt<< s.setNum(chan->tp.S2)+"|";
tt<< "\n";
}
ret = true;
f.close();

@ -42,13 +42,13 @@
#include "ts2rtp.h"
#include "cleaner.h"
#include "dvbevents.h"
#include "kaffeineinput.h"
class ChannelDesc;
class DvbStream;
class DvbPanel;
class KaffeineInput;
class KaffeineDvbPlugin;
@ -153,6 +153,7 @@ public slots:
void dvbNewTimer( QString name, QString channel, QString datetime, QString duration );
int getSNR( int device );
void diskStatus();
void camClicked( int devNum );
private:

@ -2,6 +2,7 @@
* dvbsi.cpp
*
* Copyright (C) 2003-2007 Christophe Thommeret <hftom@free.fr>
* Copyright (C) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -30,7 +31,22 @@
#define TIMER_EVENT_SCAN_END 100
// These values are taken from ATSC A/65C Sec 5
#define PSIP_BASE_PID 0x1ffb
// This shouldn't be necessary, but at least the HVR-950 doesn't seem to
// find them in the time specified in the spec (needs more investigation)
#define CYCLE_TIME_FUDGEFACTOR 1000
// These values are taken from ATSC A/65C Sec 7.1
// (all values in ms)
#define PSIP_MAX_CYCLE_TIME_MGT 150 + CYCLE_TIME_FUDGEFACTOR
#define PSIP_MAX_CYCLE_TIME_VCT 400 + CYCLE_TIME_FUDGEFACTOR
// These values are taken from ATSC A/65C Sec 4.1
#define PSIP_TABLE_TYPE_MGT 0xc7
#define PSIP_TABLE_TYPE_TVCT 0xc8
#define PSIP_TABLE_TYPE_CVCT 0xc9
NitSection::NitSection( QPtrList<Transponder> *tp, bool *end, bool *ok, int anum, int tnum ) : KaffeineDVBsection( anum, tnum )
{
@ -158,6 +174,9 @@ bool NitSection::tableNIT( unsigned char* buf )
fprintf(stderr," Found frequency list.\n");
freqListDesc( buf, trans );
break;
case 0x79 :
S2satelliteDesc( buf, trans );
break;
default :
break;
}
@ -211,18 +230,53 @@ void NitSection::satelliteDesc( unsigned char* buf, Transponder *trans )
trans->pol = 'v';
else
trans->pol = 'h';
switch ( getBits(buf,70,2) ) {
case 0 : trans->modulation = QAM_AUTO; break;
case 1 : trans->modulation = QPSK; break;
case 2 : trans->modulation = PSK_8; break;
case 3 : trans->modulation = QAM_16; break;
}
s = t.setNum( getBits(buf,72,28), 16 );
trans->sr = s.toInt();
trans->sr /=10;
switch ( getBits(buf,100,4) ) {
case 0 : trans->coderateH = FEC_AUTO; break;
case 1 : trans->coderateH = FEC_1_2; break;
case 2 : trans->coderateH = FEC_2_3; break;
case 3 : trans->coderateH = FEC_3_4; break;
case 4 : trans->coderateH = FEC_5_6; break;
case 5 : trans->coderateH = FEC_7_8; break;
case 6 : trans->coderateH = FEC_8_9; break;
case 7 : trans->coderateH = FEC_NONE; break;
case 7 : trans->coderateH = FEC_3_5; break;
case 8 : trans->coderateH = FEC_4_5; break;
case 9 : trans->coderateH = FEC_9_10; break;
case 15 : trans->coderateH = FEC_NONE; break;
}
if ( getBits(buf,69,1) ) {
fprintf(stderr,"!!!!!!!!!!!!!!!!!! Found S2 MODULATION SYSTEM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
trans->S2 = 1;
switch ( getBits(buf,67,2) ) {
case 0 : trans->rolloff = ROLLOFF_35; break;
case 1 : trans->rolloff = ROLLOFF_25; break;
case 2 : trans->rolloff = ROLLOFF_20; break;
}
}
}
void NitSection::S2satelliteDesc( unsigned char* buf, Transponder *trans )
{
fprintf(stderr,"!!!!!!!!!!!!!!!!!! Found S2 DESCRIPTOR !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
int scrambling_sequence_selector = getBits(buf,16,1);
int multiple_input_stream_flag = getBits(buf,17,1);
int backwards_compatibility_indicator = getBits(buf,18,1);
int scrambling_sequence_index = 0;
if ( scrambling_sequence_selector )
scrambling_sequence_index = getBits(buf,30,18);
int input_stream_identifier = 0;
if ( multiple_input_stream_flag )
input_stream_identifier = getBits(buf,48,8);
}
@ -246,13 +300,17 @@ void NitSection::cableDesc( unsigned char* buf, Transponder *trans )
trans->sr = s.toInt();
trans->sr /=10;
switch ( getBits(buf,100,4) ) {
case 0 : trans->coderateH = FEC_AUTO; break;
case 1 : trans->coderateH = FEC_1_2; break;
case 2 : trans->coderateH = FEC_2_3; break;
case 3 : trans->coderateH = FEC_3_4; break;
case 4 : trans->coderateH = FEC_5_6; break;
case 5 : trans->coderateH = FEC_7_8; break;
case 6 : trans->coderateH = FEC_8_9; break;
case 7 : trans->coderateH = FEC_NONE; break;
case 7 : trans->coderateH = FEC_3_5; break;
case 8 : trans->coderateH = FEC_4_5; break;
case 9 : trans->coderateH = FEC_9_10; break;
case 15 : trans->coderateH = FEC_NONE; break;
}
}
@ -456,6 +514,7 @@ bool DVBsi::tablePMT( unsigned char* buf )
while ( length>4 ) {
audio=ac3=false;
lang="";
type = getBits(buf,0,8);
pid = getBits(buf,11,13);
if ( type==1/*mpeg1*/ || type==2/*mpeg2*/ || type==16/*mpeg4*/ || type==27/*h264*/ ) {
@ -466,6 +525,11 @@ bool DVBsi::tablePMT( unsigned char* buf )
if ( type==3 || type==4 ) {
audio = true;
}
if (type == 0x81) {
// AC3 was added in ATSC A/52B (See A3.1 "Stream Type")
audio = true;
ac3 = true;
}
loop = getBits(buf,28,12);
buf +=5;
length -=(5+loop);
@ -499,6 +563,7 @@ bool DVBsi::tablePMT( unsigned char* buf )
}
break;
case 0x6a :
case 0x81 :
audio = true;
ac3 = true;
break;
@ -637,7 +702,204 @@ bool DVBsi::getSection( int pid, int tid, int timeout, int sid )
return true;
}
bool DVBsi::parseMGT( int pid, int tid, int timeout, int sid )
{
unsigned char buf[4096];
int n=0;
int skip=0;
bool vct_found = false;
fprintf(stderr, "parseMGT called for 0x%02x 0x%02x\n", pid, tid);
if ( !setFilter( pid, tid, timeout ) )
return false;
if ( poll(pf,1,timeout)>0 ){
if ( pf[0].revents & POLLIN ){
n = read( fdDemux, buf, 4096 );
skip = 0;
}
else
skip++;
}
else
skip++;
if ( skip || n<4 ) {
fprintf(stderr,"\nInvalid section length or timeout: pid=%d\n\n", pid);
stopFilter();
return false;
}
// Parse the Master Guide Table Section
unsigned int protocol_version = getBits(buf,64,8);
unsigned int tables_defined = getBits(buf,72,16);
fprintf(stderr, "protocol_version = %d\n", protocol_version);
fprintf(stderr, "tables_defined = %d\n", tables_defined);
// Now let's go through the table entries....
unsigned char *t_entry = &buf[88/8];
for (unsigned int t = 0; t < tables_defined; t++) {
unsigned int table_type;
unsigned int table_pid;
unsigned int table_version_number;
unsigned int table_number_bytes;
unsigned int table_number_des_length;
table_type = getBits(t_entry, 0, 16);
table_pid = getBits(t_entry, 19, 13);
table_version_number = getBits(t_entry, 35, 5);
table_number_bytes = getBits(t_entry, 40, 32);
table_number_des_length = getBits(t_entry, 76, 12);
fprintf(stderr,
"MGT entry type=0x%04x pid=0x%04x ver=%d sz=%d\n",
table_type, table_pid, table_version_number,
table_number_bytes);
if (table_type == 0x0000 || table_type == 0x0001) {
// TVCT table found
vct_table = PSIP_TABLE_TYPE_TVCT;
vct_found = true;
} else if (table_type == 0x0002 ||
table_type == 0x0003) {
// CVCT table found
vct_table = PSIP_TABLE_TYPE_CVCT;
vct_found = true;
}
t_entry += (11 + table_number_des_length);
}
stopFilter();
return vct_found;
}
bool DVBsi::parseVCT( int pid, int tid, int timeout, int sid )
{
unsigned char buf[4096];
int n=0;
int skip=0;
fprintf(stderr, "parseVCT called for 0x%02x 0x%02x\n", pid, tid);
if ( !setFilter( pid, tid, timeout ) )
return false;
if ( poll(pf,1,timeout)>0 ){
if ( pf[0].revents & POLLIN ){
n = read( fdDemux, buf, 4096 );
skip = 0;
}
else
skip++;
}
else
skip++;
if ( skip || n<4 ) {
fprintf(stderr,"\nInvalid section length or timeout: pid=%d\n\n", pid);
stopFilter();
return false;
}
// Parse the Virtual Channel Table Section
unsigned int protocol_version = getBits(buf,64,8);
unsigned int num_channels = getBits(buf,72,8);
fprintf(stderr, "protocol_version = %d\n", protocol_version);
fprintf(stderr, "num_channels = %d\n", num_channels);
// Now let's go through the table entries....
unsigned char *t_entry = &buf[80/8];
for (unsigned int t = 0; t < num_channels; t++) {
char short_name[8];
unsigned int major_channel_num;
unsigned int minor_channel_num;
unsigned int modulation_mode;
unsigned int channel_tsid;
unsigned int program_number;
unsigned int access_controlled;
unsigned int hidden;
unsigned int service_type;
unsigned int source_id;
unsigned int reserved;
unsigned int descriptors_length;
// Short name
// Yes, I need a real UCS-2 to UTF-8 conversion here...
memset(short_name, 0, sizeof(short_name));
snprintf(short_name, sizeof(short_name), "%c%c%c%c%c%c%c",
t_entry[1],t_entry[3],t_entry[5],t_entry[7],
t_entry[9],t_entry[11],t_entry[13]);
reserved = getBits(t_entry, 112, 4);
major_channel_num = getBits(t_entry, 116, 10);
minor_channel_num = getBits(t_entry, 126, 10);
modulation_mode = getBits(t_entry, 136, 8);
channel_tsid = getBits(t_entry, 176, 16);
program_number = getBits(t_entry, 192, 16);
access_controlled = getBits(t_entry, 210, 1);
hidden = getBits(t_entry, 211, 1);
service_type = getBits(t_entry, 218, 6);
source_id = getBits(t_entry, 224, 16);
reserved = getBits(t_entry, 240, 6);
descriptors_length = getBits(t_entry, 246, 10);
fprintf(stderr, "short name=%s\n", short_name);
fprintf(stderr, "reserved=0x%04x\n", reserved);
fprintf(stderr, "major=%d\n", major_channel_num);
fprintf(stderr, "minor=%d\n", minor_channel_num);
fprintf(stderr, "modulation mode=0x%02x\n", modulation_mode);
fprintf(stderr, "channel_tsid=0x%04x\n", channel_tsid);
fprintf(stderr, "program_number=0x%04x\n", program_number);
fprintf(stderr, "access_controlled=0x%01x\n", access_controlled);
fprintf(stderr, "hidden=0x%01x\n", hidden);
fprintf(stderr, "service_type=0x%02x\n", service_type);
fprintf(stderr, "source_id=0x%04x\n", source_id);
fprintf(stderr, "des length=%d\n", descriptors_length);
ChannelDesc *desc = new ChannelDesc();
desc->tp.tsid = channel_tsid;
desc->name = QString("%1-%2 %3").arg(major_channel_num).arg(minor_channel_num).arg(short_name);
desc->sid = program_number;
if (access_controlled == 1)
desc->fta = 1;
else
desc->fta = 0; // 0 for free
// Algorithm taken from ATSC A/65C Sec 4.2
// However, the algorithm doesn't appear correct, as it
// truncates out data. For example, both 68-1 and 4-1 would
// yield the same one_part_number
desc->num = (major_channel_num << 10) + minor_channel_num;
fprintf(stderr, "channel num=%d\n", desc->num);
// ATSC A/65C Sec 6.3.1 Table 6.7
if (service_type == 0x01) {
// Analog television (not supported)
} else if (service_type == 0x02) {
// ATSC Video
desc->type = 1;
} else if (service_type == 0x03) {
// ATSC Audio
desc->type = 2;
} else if (service_type == 0x02) {
// ATSC Data only service (not supported)
} else if (service_type > 0x05 && service_type < 0x3f) {
// Reserved (not supported)
} else {
// Unknown
}
// Now add the new channel to the list (if supported)
if ((desc->type == 1 || desc->type == 2) && hidden == 0) {
channels.append( desc );
} else {
fprintf(stderr, "Not adding channel\n");
delete desc;
}
// Advance to the next entry
t_entry += (32 + descriptors_length);
}
stopFilter();
return true;
}
void DVBsi::stop()
{
@ -701,7 +963,24 @@ void DVBsi::timerEvent( QTimerEvent *e )
}
}
// See ATSC standard A/65c for info on PSIP and what all these acronyms are...
bool DVBsi::handle_atsc_transponder() {
// Loop through the MGT to get the list of PIDS for virtual channels
if (parseMGT(PSIP_BASE_PID, PSIP_TABLE_TYPE_MGT,
PSIP_MAX_CYCLE_TIME_MGT) == false) {
// We couldn't find the MGT
fprintf(stderr, "Could not find MGT in stream. Cannot continue\n");
return false;
};
// Now look at the TVCT for info on the individual channels found
if (parseVCT(PSIP_BASE_PID, vct_table,
PSIP_MAX_CYCLE_TIME_VCT) == false) {
fprintf(stderr, "Could not parse VCT in stream. Cannot continue\n");
return false;
}
return true;
}
void DVBsi::run()
{
@ -744,12 +1023,22 @@ void DVBsi::run()
indexChannels = j;
fprintf(stderr,"Transponders: %d/%d\n", i+1, transponders.count() );
if ( scanMode ) {
nitEnded = false;
ns = new NitSection( &transponders, &nitEnded, &ok, adapter, tuner ); //NIT
fprintf(stderr,"scanMode=%d\n", scanMode);
if ( chan.tp.type == FE_ATSC ) {
// Separate out the ATSC scanning so that we
// don't interfere with existing DVB support
if (!handle_atsc_transponder())
continue;
}
else {
printf("it's dvb %d!\n", chan.tp.type);
if ( scanMode ) {
nitEnded = false;
ns = new NitSection( &transponders, &nitEnded, &ok, adapter, tuner ); //NIT
}
getSection( 0x11, 0x42 ); //SDT
}
if ( !getSection( 0x11, 0x42 ) ) //SDT
continue;
if ( !isRunning ) {
out();
return;
@ -822,7 +1111,7 @@ void DVBsi::run()
}
// !!!! only there for debugging !!!!!!!!!!
bool DVBsi::listChannels()
{
QString s,t;

@ -36,6 +36,7 @@ public:
bool getSection( int pid, int tid, int timeout=5000 );
bool tableNIT( unsigned char* buf );
void satelliteDesc( unsigned char* buf, Transponder *trans );
void S2satelliteDesc( unsigned char* buf, Transponder *trans );
void cableDesc( unsigned char* buf, Transponder *trans );
void terrestrialDesc( unsigned char* buf, Transponder *trans );
void freqListDesc( unsigned char* buf, Transponder *trans );
@ -66,6 +67,11 @@ public:
bool tablePMT( unsigned char* buf );
void serviceDesc( unsigned char* buf, ChannelDesc *desc );
// ATSC related methods
virtual bool handle_atsc_transponder();
virtual bool parseMGT( int pid, int tid, int timeout=5000, int sid=0 );
virtual bool parseVCT( int pid, int tid, int timeout=5000, int sid=0 );
QPtrList<ChannelDesc> channels;
QPtrList<Transponder> transponders;
DvbStream *dvb;
@ -90,6 +96,9 @@ private:
int scanMode;
NitSection *ns;
/* ATSC related */
int vct_table;
signals:
void end( bool );

@ -43,6 +43,7 @@
#include <klocale.h>
#include <kapplication.h>
#include <kmessagebox.h>
#include "dvbstream.h"
#include "dvbevents.h"
@ -100,13 +101,23 @@ void DvbStream::probeCam()
int ci_type=0;
if ( camProbed )
return;
if ( (ci_type=DvbCam::probe( dvbDevice->adapter, 0 ))>0 )
cam = new DvbCam( dvbDevice->adapter, 0, dvbDevice->tuner, ci_type );
if ( (ci_type=DvbCam::probe( dvbDevice->adapter, 0 ))>0 ) {
cam = new DvbCam( dvbDevice->adapter, 0, dvbDevice->tuner, ci_type, dvbDevice->camMaxService );
dvbDevice->hasCAM = true;
}
camProbed = true;
}
void DvbStream::showCamDialog()
{
if ( cam )
dvbDevice->camMaxService = cam->showCamDialog();
}
QStringList DvbStream::getSources( bool all )
{
if ( !all ) {
@ -143,6 +154,8 @@ bool DvbStream::canSource( ChannelDesc *chan )
else
return false;
}
if ( chan->tp.S2 && !dvbDevice->doS2 )
return false;
int i;
for ( i=0; i<dvbDevice->numLnb; i++ ) {
if ( dvbDevice->lnb[i].source.contains(chan->tp.source) )
@ -153,6 +166,13 @@ bool DvbStream::canSource( ChannelDesc *chan )
int DvbStream::getPriority()
{
return dvbDevice->priority;
}
int DvbStream::getSatPos( const QString &src )
{
int i;
@ -174,7 +194,7 @@ bool DvbStream::openFe()
fprintf(stderr,"openFe: fdFrontend != 0\n");
return false;
}
fdFrontend = open( frontendName.ascii(), O_RDWR );
fdFrontend = open( frontendName.ascii(), O_RDWR /*| O_NONBLOCK*/ );
if ( fdFrontend<0 ) {
perror("openFe:");
fdFrontend = 0;
@ -308,7 +328,6 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr )
{
unsigned long lof=0;
int res, hiband=0;
struct dvb_frontend_parameters feparams;
struct dvb_frontend_info fe_info;
fe_status_t status;
unsigned long freq=chan->tp.freq;
@ -317,6 +336,14 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr )
int rotorMove = 0;
int loop=0, i;
struct dtv_property cmdargs[20];
struct dtv_properties cmdseq;
int inversion;
int bandwidth;
if ( chan->tp.S2 && !dvbDevice->doS2 )
return false;
closeFe();
if ( !openFe() )
return false;
@ -333,18 +360,45 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr )
freq*=1000;
srate*=1000;
QTime t1 = QTime::currentTime();
if ( chan->tp.inversion==INVERSION_AUTO ) {
if ( fe_info.caps & FE_CAN_INVERSION_AUTO )
inversion = chan->tp.inversion;
else {
fprintf(stderr,"Can NOT inversion_auto\n");
inversion = INVERSION_OFF;
}
}
else
inversion=chan->tp.inversion;
switch( fe_info.type ) {
case FE_OFDM : {
QString s = fe_info.name;
//if ( s.contains("TerraTec/qanu USB2.0 Highspeed DVB-T Receiver") ) // cinergyT2 hack
// freq+=167000;
if (freq < 1000000)
freq*=1000UL;
feparams.frequency=freq;
feparams.u.ofdm.bandwidth=chan->tp.bandwidth;
feparams.u.ofdm.code_rate_HP=chan->tp.coderateH;
feparams.u.ofdm.code_rate_LP=chan->tp.coderateL;
feparams.u.ofdm.constellation=chan->tp.modulation;
feparams.u.ofdm.transmission_mode=chan->tp.transmission;
feparams.u.ofdm.guard_interval=chan->tp.guard;
feparams.u.ofdm.hierarchy_information=chan->tp.hierarchy;
cmdargs[0].cmd = DTV_DELIVERY_SYSTEM; cmdargs[0].u.data = SYS_DVBT;
cmdargs[1].cmd = DTV_FREQUENCY; cmdargs[1].u.data = freq;
cmdargs[2].cmd = DTV_MODULATION; cmdargs[2].u.data = chan->tp.modulation;
cmdargs[3].cmd = DTV_CODE_RATE_HP; cmdargs[3].u.data = chan->tp.coderateH;
cmdargs[4].cmd = DTV_CODE_RATE_LP; cmdargs[4].u.data = chan->tp.coderateL;
cmdargs[5].cmd = DTV_GUARD_INTERVAL; cmdargs[5].u.data = chan->tp.guard;
cmdargs[6].cmd = DTV_TRANSMISSION_MODE; cmdargs[6].u.data = chan->tp.transmission;
cmdargs[7].cmd = DTV_HIERARCHY; cmdargs[7].u.data = chan->tp.hierarchy;
if ( chan->tp.bandwidth==BANDWIDTH_8_MHZ )
bandwidth = 8000000;
else if ( chan->tp.bandwidth==BANDWIDTH_7_MHZ )
bandwidth = 7000000;
else if ( chan->tp.bandwidth==BANDWIDTH_6_MHZ )
bandwidth = 6000000;
cmdargs[8].cmd = DTV_BANDWIDTH_HZ; cmdargs[8].u.data = bandwidth;
cmdargs[9].cmd = DTV_INVERSION; cmdargs[9].u.data = inversion;
cmdargs[10].cmd = DTV_TUNE;
cmdseq.num = 11;
cmdseq.props = cmdargs;
fprintf(stderr,"tuning DVB-T to %lu Hz\n", freq);
fprintf(stderr,"inv:%d bw:%d fecH:%d fecL:%d mod:%d tm:%d gi:%d hier:%d\n", chan->tp.inversion,
chan->tp.bandwidth, chan->tp.coderateH, chan->tp.coderateL, chan->tp.modulation,
@ -352,11 +406,16 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr )
break;
}
case FE_QAM : {
cmdargs[0].cmd = DTV_DELIVERY_SYSTEM; cmdargs[0].u.data = SYS_DVBC_ANNEX_AC;
cmdargs[1].cmd = DTV_FREQUENCY; cmdargs[1].u.data = freq;
cmdargs[2].cmd = DTV_MODULATION; cmdargs[2].u.data = chan->tp.modulation;
cmdargs[3].cmd = DTV_SYMBOL_RATE; cmdargs[3].u.data = srate;
cmdargs[4].cmd = DTV_INNER_FEC; cmdargs[4].u.data = chan->tp.coderateH;
cmdargs[5].cmd = DTV_INVERSION; cmdargs[5].u.data = inversion;
cmdargs[6].cmd = DTV_TUNE;
cmdseq.num = 7;
cmdseq.props = cmdargs;
fprintf(stderr,"tuning DVB-C to %lu\n", freq);
feparams.frequency=freq;
feparams.u.qam.symbol_rate = srate;
feparams.u.qam.fec_inner = chan->tp.coderateH;
feparams.u.qam.modulation = chan->tp.modulation;
fprintf(stderr,"inv:%d sr:%lu fecH:%d mod:%d\n", chan->tp.inversion,
srate, chan->tp.coderateH, chan->tp.modulation );
break;
@ -384,51 +443,78 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr )
lof = (dvbDevice->lnb[lnbPos].loFreq*1000);
}
if ( freq<lof )
feparams.frequency = ( lof-freq );
freq = ( lof-freq );
else
feparams.frequency = ( freq-lof );
freq = ( freq-lof );
}
else
feparams.frequency=freq;
feparams.u.qpsk.symbol_rate=srate;
feparams.u.qpsk.fec_inner=chan->tp.coderateH;
fprintf(stderr,"inv:%d fecH:%d\n", chan->tp.inversion, chan->tp.coderateH );
fprintf(stderr,"inv:%d fecH:%d mod:%d\n", chan->tp.inversion, chan->tp.coderateH, chan->tp.modulation );
if ( setDiseqc( lnbPos, chan, hiband, rotorMove, dvr )!=0 ) {
closeFe();
return false;
}
fprintf( stderr, "Diseqc settings time = %d ms\n", t1.msecsTo( QTime::currentTime() ) );
t1 = QTime::currentTime();
if ( chan->tp.S2 ) {
fprintf(stderr,"\nTHIS IS DVB-S2 >>>>>>>>>>>>>>>>>>>\n");
cmdargs[0].cmd = DTV_DELIVERY_SYSTEM; cmdargs[0].u.data = SYS_DVBS2;
cmdargs[1].cmd = DTV_FREQUENCY; cmdargs[1].u.data = freq;
cmdargs[2].cmd = DTV_MODULATION; cmdargs[2].u.data = chan->tp.modulation;
cmdargs[3].cmd = DTV_SYMBOL_RATE; cmdargs[3].u.data = srate;
cmdargs[4].cmd = DTV_INNER_FEC; cmdargs[4].u.data = chan->tp.coderateH;
cmdargs[5].cmd = DTV_PILOT; cmdargs[5].u.data = PILOT_AUTO;
cmdargs[6].cmd = DTV_ROLLOFF; cmdargs[6].u.data = chan->tp.rolloff;
cmdargs[7].cmd = DTV_INVERSION; cmdargs[7].u.data = inversion;
cmdargs[8].cmd = DTV_TUNE;
cmdseq.num = 9;
cmdseq.props = cmdargs;
}
else {
cmdargs[0].cmd = DTV_DELIVERY_SYSTEM; cmdargs[0].u.data = SYS_DVBS;
cmdargs[1].cmd = DTV_FREQUENCY; cmdargs[1].u.data = freq;
cmdargs[2].cmd = DTV_MODULATION; cmdargs[2].u.data = chan->tp.modulation;
if ( chan->tp.modulation==QAM_AUTO )
cmdargs[2].u.data = QPSK;
cmdargs[3].cmd = DTV_SYMBOL_RATE; cmdargs[3].u.data = srate;
cmdargs[4].cmd = DTV_INNER_FEC; cmdargs[4].u.data = chan->tp.coderateH;
cmdargs[5].cmd = DTV_INVERSION; cmdargs[5].u.data = inversion;
cmdargs[6].cmd = DTV_TUNE;
cmdseq.num = 7;
cmdseq.props = cmdargs;
}
break;
}
case FE_ATSC : {
cmdargs[0].cmd = DTV_DELIVERY_SYSTEM; cmdargs[0].u.data = SYS_ATSC;
cmdargs[1].cmd = DTV_FREQUENCY; cmdargs[1].u.data = freq;
cmdargs[2].cmd = DTV_MODULATION; cmdargs[2].u.data = chan->tp.modulation;
cmdargs[3].cmd = DTV_INVERSION; cmdargs[3].u.data = inversion;
cmdargs[4].cmd = DTV_TUNE;
cmdseq.num = 5;
cmdseq.props = cmdargs;
fprintf(stderr,"tuning ATSC to %lu\n", freq);
feparams.frequency=freq;
feparams.u.vsb.modulation = chan->tp.modulation;
fprintf(stderr,"inv:%d mod:%d\n", chan->tp.inversion, chan->tp.modulation );
break;
}
}
if ( chan->tp.inversion==INVERSION_AUTO ) {
if ( fe_info.caps & FE_CAN_INVERSION_AUTO )
feparams.inversion=chan->tp.inversion;
else {
fprintf(stderr,"Can NOT inversion_auto\n");
feparams.inversion=INVERSION_OFF;
}
}
else
feparams.inversion=chan->tp.inversion;
if ( rotorMove )
if ( rotorMove ) {
if ( ioctl( fdFrontend, FE_SET_PROPERTY, &cmdseq )<0 ) {
perror("ERROR tuning\n");
closeFe();
return false;
}
moveRotor( lnbPos, chan, hiband, dvr );
loop = 2;
}
while ( loop>-1 ) {
if (ioctl(fdFrontend,FE_SET_FRONTEND,&feparams) < 0) {
perror("ERROR tuning \n");
if ( ioctl( fdFrontend, FE_SET_PROPERTY, &cmdseq )<0 ) {
perror("ERROR tuning\n");
closeFe();
return false;
}
for ( i=0; i<(dvbDevice->tuningTimeout/100); i++ ) {
QTime lockTime = QTime::currentTime();
do {
usleep( 100000 );
fprintf( stderr, "." );
if ( ioctl( fdFrontend, FE_READ_STATUS, &status )==-1 ) {
@ -440,7 +526,7 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr )
loop = 0;
break;
}
}
} while ( lockTime.msecsTo( QTime::currentTime() )<=dvbDevice->tuningTimeout );
fprintf(stderr,"\n");
--loop;
}
@ -451,6 +537,8 @@ bool DvbStream::tuneDvb( ChannelDesc *chan, bool dvr )
return false;
}
fprintf( stderr, "Tuning time = %d ms\n", t1.msecsTo( QTime::currentTime() ) );
if ( rotorMove )
dvbDevice->lnb[lnbPos].currentSource = chan->tp.source;
@ -496,6 +584,23 @@ int DvbStream::setDiseqc( int switchPos, ChannelDesc *chan, int hiband, int &rot
int i;
int voltage18 = ( (chan->tp.pol=='H')||(chan->tp.pol=='h') );
int ci = 4 * switchPos + 2 * hiband + (voltage18 ? 1 : 0);
bool secMini = false;
bool hasRotor = false;
bool hasSwitch = true;
if ( dvbDevice->numLnb<2 )
hasSwitch = false;
if ( dvbDevice->lnb[switchPos].rotorType!=0 && dvbDevice->lnb[switchPos].rotorType!=3 )
hasRotor = true;
if ( dvbDevice->numLnb==2 && dvbDevice->secMini )
secMini = true;
if ( dvbDevice->secTwice )
diseqcTwice = 2;
else
diseqcTwice = 1;
fprintf( stderr, "DiSEqC: switch pos %i, %sV, %sband (index %d)\n", switchPos, voltage18 ? "18" : "13", hiband ? "hi" : "lo", ci );
if ( ci < 0 || ci >= (int)(sizeof(switchCmd)/sizeof(struct dvb_diseqc_master_cmd)) )
@ -507,85 +612,108 @@ int DvbStream::setDiseqc( int switchPos, ChannelDesc *chan, int hiband, int &rot
if ( ioctl(fdFrontend, FE_SET_VOLTAGE, ci%2 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13) )
perror("FE_SET_VOLTAGE failed");
fprintf( stderr, "DiSEqC: %02x %02x %02x %02x %02x %02x\n", switchCmd[ci].msg[0], switchCmd[ci].msg[1], switchCmd[ci].msg[2], switchCmd[ci].msg[3], switchCmd[ci].msg[4], switchCmd[ci].msg[5] );
for ( i=0; i<2; ++i ) {
usleep(15*1000);
if ( ioctl(fdFrontend, FE_DISEQC_SEND_MASTER_CMD, &switchCmd[ci]) )
perror("FE_DISEQC_SEND_MASTER_CMD failed");
}
QString msg;
if ( dvbDevice->lnb[switchPos].rotorType!=0 && chan->tp.source!=dvbDevice->lnb[switchPos].currentSource ) {
int i, index=-1;
double angle=0.0, oldAngle=0.0;
fprintf( stderr, "Driving rotor to %s\n", chan->tp.source.ascii() );
for ( i=0; i<(int)dvbDevice->lnb[switchPos].source.count(); i++ ) {
if ( dvbDevice->lnb[switchPos].source[i]==chan->tp.source ) {
index = i;
break;
if ( hasSwitch ) {
if ( !secMini ) {
fprintf( stderr, "DiSEqC: %02x %02x %02x %02x %02x %02x\n", switchCmd[ci].msg[0], switchCmd[ci].msg[1], switchCmd[ci].msg[2], switchCmd[ci].msg[3], switchCmd[ci].msg[4], switchCmd[ci].msg[5] );
for ( i=0; i<diseqcTwice; ++i ) {
usleep(15*1000);
if ( ioctl(fdFrontend, FE_DISEQC_SEND_MASTER_CMD, &switchCmd[ci]) )
perror("FE_DISEQC_SEND_MASTER_CMD failed");
}
}
angle = getSourceAngle( chan->tp.source );
if ( dvbDevice->lnb[switchPos].rotorType==1 ) {
fprintf( stderr, "Rotor: gotoX=%f\n", angle );
gotoX( angle );
}
else {
int pos = dvbDevice->lnb[switchPos].position[index];
fprintf( stderr, "Rotor: gotoN=%d\n", pos );
rotorCommand( 9, pos );
}
if ( dvbDevice->lnb[switchPos].currentSource.isEmpty() ) {
rotor = 10;
msg = i18n("Moving rotor from unknown position...");
}
else {
oldAngle = getSourceAngle( dvbDevice->lnb[switchPos].currentSource );
fprintf( stderr, "old rotor pos: %f °\n", oldAngle );
fprintf( stderr, "new rotor pos: %f °\n", angle );
angle = fabs(angle-oldAngle);
fprintf( stderr, "Rotation angle: %f °\n", angle );
if ( voltage18 )
rotor = (int)(angle*dvbDevice->lnb[switchPos].speed18v)+1;
else
rotor = (int)(angle*dvbDevice->lnb[switchPos].speed13v)+1;
msg = i18n("Moving rotor...");
fprintf( stderr, "DiSEqC: mini_diseqc\n" );
for ( i=0; i<diseqcTwice; ++i ) {
usleep(15*1000);
if ( ioctl(fdFrontend, FE_DISEQC_SEND_BURST, (ci/4)%2 ? SEC_MINI_B : SEC_MINI_A) )
perror("FE_DISEQC_SEND_BURST failed");
}
}
fprintf( stderr, "Rotation time: %d sec.\n", rotor );
}
if ( rotor ) {
int j;
if ( !dvr ) {
for ( j=0; j<(rotor*2); j++ ) {
usleep( 500000 );
}
if ( hasRotor && chan->tp.source!=dvbDevice->lnb[switchPos].currentSource ) {
rotor = 1;
return 0;
}
if ( (ci/2)%2 ) {
usleep(15*1000);
if ( ioctl(fdFrontend, FE_SET_TONE, SEC_TONE_ON) )
perror("FE_SET_TONE failed");
}
return 0;
}
void DvbStream::moveRotor( int switchPos, ChannelDesc *chan, int hiband, bool dvr )
{
int i, j, index=-1;
double angle=0.0, oldAngle=0.0;
int rotor=0;
int voltage18 = ( (chan->tp.pol=='H')||(chan->tp.pol=='h') );
int ci = 4 * switchPos + 2 * hiband + (voltage18 ? 1 : 0);
QString msg;
fprintf( stderr, "Driving rotor to %s\n", chan->tp.source.ascii() );
for ( i=0; i<(int)dvbDevice->lnb[switchPos].source.count(); i++ ) {
if ( dvbDevice->lnb[switchPos].source[i]==chan->tp.source ) {
index = i;
break;
}
else {
QProgressDialog progress( msg, i18n("Cancel"), rotor*2, 0, "progress", true );
for ( j=0; j<(rotor*2); j++ ) {
progress.setProgress( j );
qApp->processEvents();
if ( progress.wasCanceled() )
break;
usleep( 500000 );
}
progress.setProgress( rotor*2 );
}
angle = getSourceAngle( chan->tp.source );
if ( dvbDevice->lnb[switchPos].rotorType==1 ) {
fprintf( stderr, "Rotor: gotoX=%f\n", angle );
gotoX( angle );
}
else {
int pos = dvbDevice->lnb[switchPos].position[index];
fprintf( stderr, "Rotor: gotoN=%d\n", pos );
rotorCommand( 9, pos );
}
if ( dvbDevice->lnb[switchPos].currentSource.isEmpty() ) {
rotor = 10;
msg = i18n("Moving rotor from unknown position...");
}
else {
oldAngle = getSourceAngle( dvbDevice->lnb[switchPos].currentSource );
fprintf( stderr, "old rotor pos: %f °\n", oldAngle );
fprintf( stderr, "new rotor pos: %f °\n", angle );
angle = fabs(angle-oldAngle);
fprintf( stderr, "Rotation angle: %f °\n", angle );
if ( voltage18 )
rotor = (int)(angle*dvbDevice->lnb[switchPos].speed18v)+1;
else
rotor = (int)(angle*dvbDevice->lnb[switchPos].speed13v)+1;
msg = i18n("Moving rotor...");
}
fprintf( stderr, "Rotation time: %d sec.\n", rotor );
if ( !dvr ) {
for ( j=0; j<(rotor*2); j++ ) {
usleep( 500000 );
}
}
else {
QProgressDialog progress( msg, i18n("Cancel"), rotor*2, 0, "progress", true );
for ( j=0; j<(rotor*2); j++ ) {
progress.setProgress( j );
qApp->processEvents();
if ( progress.wasCanceled() )
break;
usleep( 500000 );
}
progress.setProgress( rotor*2 );
qApp->processEvents();
}
for ( i=0; i<2; ++i ) {
if ( (ci/2)%2 ) {
usleep(15*1000);
if ( ioctl(fdFrontend, FE_DISEQC_SEND_BURST, (ci/4)%2 ? SEC_MINI_B : SEC_MINI_A) )
perror("FE_DISEQC_SEND_BURST failed");
if ( ioctl(fdFrontend, FE_SET_TONE, SEC_TONE_ON) )
perror("FE_SET_TONE failed");
}
usleep(15*1000);
if ( ioctl(fdFrontend, FE_SET_TONE, (ci/2)%2 ? SEC_TONE_ON : SEC_TONE_OFF) )
perror("FE_SET_TONE failed");
return 0;
}
@ -681,7 +809,7 @@ void DvbStream::rotorCommand( int cmd, int n1, int n2, int n3 )
};
int i;
for ( i=0; i<2; ++i ) {
for ( i=0; i<diseqcTwice; ++i ) {
usleep(15*1000);
if ( ioctl( fdFrontend, FE_DISEQC_SEND_MASTER_CMD, &cmds[cmd] ) )
perror("Rotor : FE_DISEQC_SEND_MASTER_CMD failed");
@ -803,28 +931,33 @@ bool DvbStream::hasVideo()
void DvbStream::run()
{
unsigned char buf[188];
int READSIZE = 188*20;
int BUFSIZE = 188*100;
int WSIZE = 188*64;
unsigned char buf[READSIZE];
unsigned char thBuf[BUFSIZE];
int n, i, thWrite=0;
int WSIZE=188*8;
DVBout *o=0;
signal( SIGPIPE, SIG_IGN );
while ( isRunning ) {
if ( poll( &pfd, 1, 100 ) ) {
n = read( fdDvr, buf, 188 );
if ( n==188 ) {
n = read( fdDvr, buf, READSIZE );
if ( n && !(n%188) ) {
//fprintf( stderr, "DVR0: read : %d\n", n );
memcpy( thBuf+thWrite, buf, n );
thWrite+=n;
if ( thWrite==WSIZE ) {
if ( thWrite>=WSIZE ) {
for ( i=0; i<(int)out.count(); i++ )
out.at(i)->process( thBuf, WSIZE );
out.at(i)->process( thBuf, thWrite );
thWrite = 0;
}
}
else
fprintf( stderr, "DVR0: read failed : %d\n", n );
}
else
usleep(1000);
if ( waitPause>0 ) {
o = 0;
@ -917,19 +1050,11 @@ void DvbStream::recordEnded( DVBout *o, RecTimer* t, bool kill )
if ( kill ) {
removePids( o );
if ( cam )
cam->stopService( &(o->channel) );
removeOut( o );
if ( out.count()==0 )
stop();
else if ( cam ) {
for ( i=0; i<(int)out.count(); i++ ) {
if ( out.at(i)->channel.fta ) {
i=-1;
break;
}
}
if ( i!=-1 )
cam->stop();
}
}
recordingState();
if ( t )
@ -986,6 +1111,8 @@ void DvbStream::stopBroadcast()
}
for ( i=0; i<(int)p.count(); i++ ) {
removePids( p.at(i) );
if ( cam )
cam->stopService( &(p.at(i)->channel) );
removeOut( p.at(i) );
}
if ( out.count()==0 )
@ -1002,7 +1129,7 @@ int DvbStream::canStartBroadcast( bool &live, ChannelDesc *chan )
for ( i=0; i<(int)out.count(); i++ ) {
if ( (chan->tp!=out.at(i)->channel.tp) && out.at(i)->hasRec() )
return ErrIsRecording;
if ( cam && out.at(i)->hasRec() && out.at(i)->channel.fta && chan->fta && out.at(i)->channel.sid!=chan->sid )
if ( chan->fta && cam && !cam->canPlay( chan ) )
return ErrCamUsed;
if ( out.at(i)->hasLive() && chan->tp!=out.at(i)->channel.tp )
live = true;
@ -1070,6 +1197,8 @@ bool DvbStream::startBroadcast( QPtrList<ChannelDesc> *list, Ts2Rtp *rtp )
else {
broadcastList.append( new ChannelDesc( *list->at(i) ) );
no++;
if ( list->at(i)->fta && cam )
cam->startService( list->at(i) );
}
}
}
@ -1102,15 +1231,11 @@ int DvbStream::canStartTimer( bool &live, ChannelDesc *chan )
return ErrIsRecording;
if ( (o->channel.name==chan->name) && o->hasRec() )
return ErrIsRecording;
if ( (chan->tp==o->channel.tp) && o->hasRec() ) {
if ( chan->fta && cam && o->channel.fta )
return ErrCamUsed;
}
if ( chan->fta && cam && !cam->canPlay( chan ) )
return ErrCamUsed;
if ( o->hasLive() ) {
if ( chan->tp!=o->channel.tp )
live = true;
else if ( cam && chan->fta && o->channel.fta )
live = true;
}
}
return ret;
@ -1194,8 +1319,8 @@ bool DvbStream::startTimer( ChannelDesc *chan, QString path, int maxsize, RecTim
}
fprintf(stderr,"NOUT: %d\n", out.count() );
if ( chan->fta && cam && ( ((cam->running() && chan->sid!=cam->serviceId()) || !cam->running()) ) )
cam->restart( chan->sid );
if ( chan->fta && cam )
cam->startService( chan );
startReading();
@ -1205,7 +1330,7 @@ bool DvbStream::startTimer( ChannelDesc *chan, QString path, int maxsize, RecTim
int DvbStream::goLive( ChannelDesc *chan, const QString &pipeName )
int DvbStream::goLive( ChannelDesc *chan, const QString &pipeName, int ringBufSize )
{
int i;
bool stop=false;
@ -1216,10 +1341,8 @@ int DvbStream::goLive( ChannelDesc *chan, const QString &pipeName )
return ErrIsRecording;
if ( (chan->tp!=out.at(i)->channel.tp) && out.at(i)->hasBroadcast() )
return ErrIsBroadcasting;
if ( (chan->tp==out.at(i)->channel.tp) && (out.at(i)->hasBroadcast() || out.at(i)->hasRec())) {
if ( chan->fta && cam && cam->running() && (cam->serviceId()!=chan->sid) )
return ErrCamUsed;
}
if ( chan->fta && cam && !cam->canPlay( chan ) )
return ErrCamUsed;
if ( out.at(i)->channel.name==chan->name )
o = out.at(i);
}
@ -1259,11 +1382,11 @@ int DvbStream::goLive( ChannelDesc *chan, const QString &pipeName )
else
i = 0;
o->goLive( pipeName );
o->goLive( pipeName, ringBufSize );
fprintf(stderr,"NOUT: %d\n", out.count() );
if ( chan->fta && cam && !cam->running() )
cam->restart( chan->sid );
if ( chan->fta && cam )
cam->startService( chan );
startReading();
return i;
@ -1307,17 +1430,12 @@ void DvbStream::stopLive( ChannelDesc *chan )
}
for ( i=0; i<(int)p.count(); i++ ) {
removePids( p.at(i) );
if ( cam )
cam->stopService( &(p.at(i)->channel) );
removeOut( p.at(i) );
}
fprintf(stderr,"Live stopped\n");
if ( cam ) {
for ( i=0; i<(int)out.count(); i++ ) {
if ( out.at(i)->channel.fta )
camUsed = true;
}
}
if ( cam && !camUsed )
cam->stop();
if ( out.count()==0 && chan->tp!=currentTransponder )
stop();
}
@ -1343,8 +1461,6 @@ void DvbStream::stop()
wait();
fprintf(stderr,"dvbstream::run() terminated\n");
}
if ( cam )
cam->stop();
dvbEvents->stop();
stopFrontend();
}
@ -1381,7 +1497,6 @@ DvbStream::~DvbStream()
{
stop();
if ( cam ) {
cam->stop();
delete cam;
}
delete dvbEvents;

@ -62,10 +62,11 @@ public :
void setPlug( KaffeineDvbPlugin *p );
QStringList getSources( bool all=false );
bool canSource( ChannelDesc *chan );
int getPriority();
bool tuneDvb( ChannelDesc *chan, bool dvr=true );
void stopFrontend();
virtual void run();
int goLive( ChannelDesc *chan, const QString &pipeName );
int goLive( ChannelDesc *chan, const QString &pipeName, int ringBufSize );
void preStopLive();
void stopLive( ChannelDesc *chan );
void stop();
@ -89,8 +90,9 @@ public :
bool hasLive();
bool liveIsRecording();
int getSNR();
void probeCam();
void showCamDialog();
unsigned char thBuf[188*10];
struct pollfd pfd;
DVBevents *dvbEvents;
@ -109,6 +111,7 @@ protected:
private :
int setDiseqc( int switchPos, ChannelDesc *chan, int hiband, int &rotor, bool dvr );
void moveRotor( int switchPos, ChannelDesc *chan, int hiband, bool dvr );
void rotorCommand( int cmd, int n1=0, int n2=0, int n3=0 );
void gotoX( double azimuth );
double getAzimuth( double angle );
@ -119,7 +122,6 @@ private :
void removeOut( DVBout *o );
void recordingState();
void startReading();
void probeCam();
bool openFe();
bool closeFe();
void connectStatus( bool con );
@ -143,6 +145,7 @@ private :
QString timeShiftFileName;
DvbCam *cam;
bool camProbed;
int diseqcTwice;
KaffeineDvbPlugin *plug;
signals:

@ -2,10 +2,11 @@ noinst_LTLIBRARIES = libdvbapi.la
INCLUDES = -I$(top_srcdir)/kaffeine/src/input/dvb/lib
libdvbapi_la_SOURCES = diseqc.c \
libdvbapi_la_SOURCES = dvbaudio.c \
dvbca.c \
dvbdemux.c \
dvbfe.c \
dvbnet.c
dvbnet.c \
dvbvideo.c
CFLAGS = -g -O2 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC

@ -0,0 +1,50 @@
/*
* libdvbnet - a DVB network support library
*
* Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/dvb/audio.h>
#include <errno.h>
#include "dvbaudio.h"
int dvbaudio_open(int adapter, int audiodeviceid)
{
char filename[PATH_MAX+1];
int fd;
sprintf(filename, "/dev/dvb/adapter%i/audio%i", adapter, audiodeviceid);
if ((fd = open(filename, O_RDWR)) < 0) {
// if that failed, try a flat /dev structure
sprintf(filename, "/dev/dvb%i.audio%i", adapter, audiodeviceid);
fd = open(filename, O_RDWR);
}
return fd;
}
int dvbaudio_set_bypass(int fd, int bypass)
{
return ioctl(fd, AUDIO_SET_BYPASS_MODE, bypass);
}

@ -0,0 +1,55 @@
/*
* libdvbnet - a DVB network support library
*
* Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef LIBDVBAUDIO_H
#define LIBDVBAUDIO_H 1
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
/**
* Open a DVB audio device.
*
* @param adapter DVB adapter ID.
* @param audiodeviceid Id of audio device of that adapter to open.
* @return A unix file descriptor on success, or -1 on failure.
*/
extern int dvbaudio_open(int adapter, int audiodeviceid);
/**
* Control audio bypass - i.e. output decoded audio, or the raw bitstream (e.g. AC3).
*
* @param fd Audio device opened with dvbaudio_open().
* @param bypass 1=> enable bypass, 0=> disable.
* @return 0 on success, nonzero on failure.
*/
extern int dvbaudio_set_bypass(int fd, int bypass);
// FIXME: this is a stub library
#ifdef __cplusplus
}
#endif
#endif // LIBDVBAUDIO_H

@ -128,6 +128,12 @@ int dvbdemux_set_pes_filter(int fd, int pid,
filter.output = DMX_OUT_TS_TAP;
break;
#ifdef DMX_OUT_TSDEMUX_TAP
case DVBDEMUX_OUTPUT_TS_DEMUX:
filter.output = DMX_OUT_TSDEMUX_TAP;
break;
#endif
default:
return -EINVAL;
}
@ -201,6 +207,12 @@ int dvbdemux_set_pid_filter(int fd, int pid,
filter.output = DMX_OUT_TS_TAP;
break;
#ifdef DMX_OUT_TSDEMUX_TAP
case DVBDEMUX_OUTPUT_TS_DEMUX:
filter.output = DMX_OUT_TSDEMUX_TAP;
break;
#endif
default:
return -EINVAL;
}

@ -55,6 +55,7 @@ extern "C"
#define DVBDEMUX_OUTPUT_DECODER 0
#define DVBDEMUX_OUTPUT_DEMUX 1
#define DVBDEMUX_OUTPUT_DVR 2
#define DVBDEMUX_OUTPUT_TS_DEMUX 3
/**
* PES types.
@ -65,6 +66,7 @@ extern "C"
#define DVBDEMUX_PESTYPE_SUBTITLE 3
#define DVBDEMUX_PESTYPE_PCR 4
/**
* Open a demux device. Can be called multiple times. These let you setup a
* single filter per FD. It can can also be read() from if you use a section
@ -78,8 +80,8 @@ extern "C"
extern int dvbdemux_open_demux(int adapter, int demuxdevice, int nonblocking);
/**
* Open a DVR device. May be opened for writing once, or multiple times in readonly
* mode. It is used to either write() transport stream data to be demuxed
* Open a DVR device. May be opened for writing or reading once.
* It is used to either write() transport stream data to be demuxed
* (if input == DVBDEMUX_INPUT_DVR), or to read() a stream of demuxed data
* (if output == DVBDEMUX_OUTPUT_DVR).
*

@ -2,6 +2,7 @@
* libdvbfe - a DVB frontend library
*
* Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
* Copyright (C) 2005 Manu Abraham <abraham.manu@gmail.com>
* Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
*
* This library is free software; you can redistribute it and/or
@ -26,14 +27,16 @@
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <linux/dvb/frontend.h>
#include <libdvbmisc/dvbmisc.h>
#include "dvbfe.h"
#define GET_INFO_MIN_DELAY_US 100000
int verbose = 0;
static int dvbfe_spectral_inversion_to_kapi[][2] =
{
@ -128,6 +131,7 @@ static int dvbfe_dvbt_hierarchy_to_kapi[][2] =
{ -1, -1 }
};
static int lookupval(int val, int reverse, int table[][2])
{
int i =0;
@ -149,19 +153,16 @@ static int lookupval(int val, int reverse, int table[][2])
}
struct dvbfe_handle_prv {
struct dvbfe_handle {
int fd;
dvbfe_type_t type;
enum dvbfe_type type;
char *name;
struct timeval nextinfotime;
struct dvbfe_info cachedinfo;
int cachedreturnval;
};
dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly)
struct dvbfe_handle *dvbfe_open(int adapter, int frontend, int readonly)
{
char filename[PATH_MAX+1];
struct dvbfe_handle_prv *fehandle;
struct dvbfe_handle *fehandle;
int fd;
struct dvb_frontend_info info;
@ -188,8 +189,8 @@ dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly)
}
// setup structure
fehandle = (struct dvbfe_handle_prv*) malloc(sizeof(struct dvbfe_handle_prv));
memset(fehandle, 0, sizeof(struct dvbfe_handle_prv));
fehandle = (struct dvbfe_handle*) malloc(sizeof(struct dvbfe_handle));
memset(fehandle, 0, sizeof(struct dvbfe_handle));
fehandle->fd = fd;
switch(info.type) {
case FE_QPSK:
@ -214,99 +215,118 @@ dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly)
return fehandle;
}
void dvbfe_close(dvbfe_handle_t _fehandle)
void dvbfe_close(struct dvbfe_handle *fehandle)
{
struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
close(fehandle->fd);
free(fehandle->name);
free(fehandle);
}
int dvbfe_get_info(dvbfe_handle_t _fehandle, dvbfe_info_mask_t querymask, struct dvbfe_info *result)
extern int dvbfe_get_info(struct dvbfe_handle *fehandle,
enum dvbfe_info_mask querymask,
struct dvbfe_info *result,
enum dvbfe_info_querytype querytype,
int timeout)
{
int returnval = 0;
fe_status_t status;
struct dvb_frontend_parameters kparams;
struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
struct timeval curtime;
// limit how often this is called to reduce bus traffic
gettimeofday(&curtime, NULL);
if ((curtime.tv_sec < fehandle->nextinfotime.tv_sec) ||
((curtime.tv_sec == fehandle->nextinfotime.tv_sec) && (curtime.tv_usec < fehandle->nextinfotime.tv_usec))) {
memcpy(result, &fehandle->cachedinfo, sizeof(struct dvbfe_info));
return fehandle->cachedreturnval;
}
struct dvb_frontend_event kevent;
int ok = 0;
// retrieve the requested values
memset(result, 0, sizeof(result));
result->type = fehandle->type;
result->name = fehandle->name;
if (querymask & DVBFE_INFO_LOCKSTATUS) {
if (!ioctl(fehandle->fd, FE_READ_STATUS, &status)) {
returnval |= DVBFE_INFO_LOCKSTATUS;
if (status & FE_HAS_SIGNAL)
result->signal = 1;
if (status & FE_HAS_CARRIER)
result->carrier = 1;
result->type = fehandle->type;
if (status & FE_HAS_VITERBI)
result->viterbi = 1;
switch(querytype) {
case DVBFE_INFO_QUERYTYPE_IMMEDIATE:
if (querymask & DVBFE_INFO_LOCKSTATUS) {
if (!ioctl(fehandle->fd, FE_READ_STATUS, &kevent.status)) {
returnval |= DVBFE_INFO_LOCKSTATUS;
}
}
if (querymask & DVBFE_INFO_FEPARAMS) {
if (!ioctl(fehandle->fd, FE_GET_FRONTEND, &kevent.parameters)) {
returnval |= DVBFE_INFO_FEPARAMS;
}
}
break;
if (status & FE_HAS_SYNC)
result->sync = 1;
case DVBFE_INFO_QUERYTYPE_LOCKCHANGE:
{
struct pollfd pollfd;
pollfd.fd = fehandle->fd;
pollfd.events = POLLIN | POLLERR;
ok = 1;
if (poll(&pollfd, 1, timeout) < 0)
ok = 0;
if (pollfd.revents & POLLERR)
ok = 0;
if (!(pollfd.revents & POLLIN))
ok = 0;
}
if (status & FE_HAS_LOCK)
result->lock = 1;
if (ok &&
((querymask & DVBFE_INFO_LOCKSTATUS) ||
(querymask & DVBFE_INFO_FEPARAMS))) {
if (!ioctl(fehandle->fd, FE_GET_EVENT, &kevent)) {
if (querymask & DVBFE_INFO_LOCKSTATUS)
returnval |= DVBFE_INFO_LOCKSTATUS;
if (querymask & DVBFE_INFO_FEPARAMS)
returnval |= DVBFE_INFO_FEPARAMS;
}
}
break;
}
if (querymask & DVBFE_INFO_FEPARAMS) {
if (!ioctl(fehandle->fd, FE_GET_FRONTEND, &kparams)) {
returnval |= DVBFE_INFO_FEPARAMS;
result->feparams.frequency = kparams.frequency;
result->feparams.inversion = lookupval(kparams.inversion, 1, dvbfe_spectral_inversion_to_kapi);
switch(fehandle->type) {
case FE_QPSK:
result->feparams.u.dvbs.symbol_rate = kparams.u.qpsk.symbol_rate;
result->feparams.u.dvbs.fec_inner =
lookupval(kparams.u.qpsk.fec_inner, 1, dvbfe_code_rate_to_kapi);
break;
case FE_QAM:
result->feparams.u.dvbc.symbol_rate = kparams.u.qam.symbol_rate;
result->feparams.u.dvbc.fec_inner =
lookupval(kparams.u.qam.fec_inner, 1, dvbfe_code_rate_to_kapi);
result->feparams.u.dvbc.modulation =
lookupval(kparams.u.qam.modulation, 1, dvbfe_dvbc_mod_to_kapi);
break;
if (returnval & DVBFE_INFO_LOCKSTATUS) {
result->signal = kevent.status & FE_HAS_SIGNAL ? 1 : 0;
result->carrier = kevent.status & FE_HAS_CARRIER ? 1 : 0;
result->viterbi = kevent.status & FE_HAS_VITERBI ? 1 : 0;
result->sync = kevent.status & FE_HAS_SYNC ? 1 : 0;
result->lock = kevent.status & FE_HAS_LOCK ? 1 : 0;
}
case FE_OFDM:
result->feparams.u.dvbt.bandwidth =
lookupval(kparams.u.ofdm.bandwidth, 1, dvbfe_dvbt_bandwidth_to_kapi);
result->feparams.u.dvbt.code_rate_HP =
lookupval(kparams.u.ofdm.code_rate_HP, 1, dvbfe_code_rate_to_kapi);
result->feparams.u.dvbt.code_rate_LP =
lookupval(kparams.u.ofdm.code_rate_LP, 1, dvbfe_code_rate_to_kapi);
result->feparams.u.dvbt.constellation =
lookupval(kparams.u.ofdm.constellation, 1, dvbfe_dvbt_const_to_kapi);
result->feparams.u.dvbt.transmission_mode =
lookupval(kparams.u.ofdm.transmission_mode, 1, dvbfe_dvbt_transmit_mode_to_kapi);
result->feparams.u.dvbt.guard_interval =
lookupval(kparams.u.ofdm.guard_interval, 1, dvbfe_dvbt_guard_interval_to_kapi);
result->feparams.u.dvbt.hierarchy_information =
lookupval(kparams.u.ofdm.hierarchy_information, 1, dvbfe_dvbt_hierarchy_to_kapi);
break;
if (returnval & DVBFE_INFO_FEPARAMS) {
result->feparams.frequency = kevent.parameters.frequency;
result->feparams.inversion = lookupval(kevent.parameters.inversion, 1, dvbfe_spectral_inversion_to_kapi);
switch(fehandle->type) {
case FE_QPSK:
result->feparams.u.dvbs.symbol_rate = kevent.parameters.u.qpsk.symbol_rate;
result->feparams.u.dvbs.fec_inner =
lookupval(kevent.parameters.u.qpsk.fec_inner, 1, dvbfe_code_rate_to_kapi);
break;
case FE_ATSC:
result->feparams.u.atsc.modulation =
lookupval(kparams.u.vsb.modulation, 1, dvbfe_atsc_mod_to_kapi);
break;
}
}
case FE_QAM:
result->feparams.u.dvbc.symbol_rate = kevent.parameters.u.qam.symbol_rate;
result->feparams.u.dvbc.fec_inner =
lookupval(kevent.parameters.u.qam.fec_inner, 1, dvbfe_code_rate_to_kapi);
result->feparams.u.dvbc.modulation =
lookupval(kevent.parameters.u.qam.modulation, 1, dvbfe_dvbc_mod_to_kapi);
break;
case FE_OFDM:
result->feparams.u.dvbt.bandwidth =
lookupval(kevent.parameters.u.ofdm.bandwidth, 1, dvbfe_dvbt_bandwidth_to_kapi);
result->feparams.u.dvbt.code_rate_HP =
lookupval(kevent.parameters.u.ofdm.code_rate_HP, 1, dvbfe_code_rate_to_kapi);
result->feparams.u.dvbt.code_rate_LP =
lookupval(kevent.parameters.u.ofdm.code_rate_LP, 1, dvbfe_code_rate_to_kapi);
result->feparams.u.dvbt.constellation =
lookupval(kevent.parameters.u.ofdm.constellation, 1, dvbfe_dvbt_const_to_kapi);
result->feparams.u.dvbt.transmission_mode =
lookupval(kevent.parameters.u.ofdm.transmission_mode, 1, dvbfe_dvbt_transmit_mode_to_kapi);
result->feparams.u.dvbt.guard_interval =
lookupval(kevent.parameters.u.ofdm.guard_interval, 1, dvbfe_dvbt_guard_interval_to_kapi);
result->feparams.u.dvbt.hierarchy_information =
lookupval(kevent.parameters.u.ofdm.hierarchy_information, 1, dvbfe_dvbt_hierarchy_to_kapi);
break;
case FE_ATSC:
result->feparams.u.atsc.modulation =
lookupval(kevent.parameters.u.vsb.modulation, 1, dvbfe_atsc_mod_to_kapi);
break;
}
}
if (querymask & DVBFE_INFO_BER) {
if (!ioctl(fehandle->fd, FE_READ_BER, &result->ber))
returnval |= DVBFE_INFO_BER;
@ -324,24 +344,15 @@ int dvbfe_get_info(dvbfe_handle_t _fehandle, dvbfe_info_mask_t querymask, struct
returnval |= DVBFE_INFO_UNCORRECTED_BLOCKS;
}
// setup for next poll
gettimeofday(&fehandle->nextinfotime, NULL);
fehandle->nextinfotime.tv_usec += GET_INFO_MIN_DELAY_US;
if (fehandle->nextinfotime.tv_usec >= 1000000) {
fehandle->nextinfotime.tv_usec -= 1000000;
fehandle->nextinfotime.tv_sec++;
}
memcpy(&fehandle->cachedinfo, result, sizeof(struct dvbfe_info));
fehandle->cachedreturnval = returnval;
// done
return returnval;
}
int dvbfe_set(dvbfe_handle_t _fehandle, struct dvbfe_parameters *params, int timeout)
int dvbfe_set(struct dvbfe_handle *fehandle,
struct dvbfe_parameters *params,
int timeout)
{
struct dvb_frontend_parameters kparams;
struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
int res;
struct timeval endtime;
fe_status_t status;
@ -428,320 +439,123 @@ int dvbfe_set(dvbfe_handle_t _fehandle, struct dvbfe_parameters *params, int tim
return -ETIMEDOUT;
}
void dvbfe_poll(dvbfe_handle_t fehandle)
int dvbfe_get_pollfd(struct dvbfe_handle *handle)
{
// no implementation required yet
return handle->fd;
}
int dvbfe_set_22k_tone(struct dvbfe_handle *fehandle, enum dvbfe_sec_tone_mode tone)
{
int ret = 0;
switch (tone) {
case DVBFE_SEC_TONE_OFF:
ret = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_OFF);
break;
case DVBFE_SEC_TONE_ON:
ret = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_ON);
break;
default:
print(verbose, ERROR, 1, "Invalid command !");
break;
}
if (ret == -1)
print(verbose, ERROR, 1, "IOCTL failed !");
return ret;
}
int dvbfe_diseqc_command(dvbfe_handle_t _fehandle, char *command)
int dvbfe_set_tone_data_burst(struct dvbfe_handle *fehandle, enum dvbfe_sec_mini_cmd minicmd)
{
int i = 0;
int waittime;
int status;
struct dvb_diseqc_master_cmd master_cmd;
unsigned int tmpcmd[6];
struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
char value_s[20];
int value_i;
int addr;
while(command[i]) {
/* kill whitespace */
if (isspace(command[i])) {
i++;
continue;
}
int ret = 0;
switch(command[i]) {
case 't':
if ((status = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_OFF)) != 0)
return status;
break;
case 'T':
if ((status = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_ON)) != 0)
return status;
break;
case '_':
if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_OFF)) != 0)
return status;
break;
switch (minicmd) {
case DVBFE_SEC_MINI_A:
ret = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_A);
break;
case DVBFE_SEC_MINI_B:
ret = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_B);
break;
default:
print(verbose, ERROR, 1, "Invalid command");
break;
}
if (ret == -1)
print(verbose, ERROR, 1, "IOCTL failed");
case 'v':
if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_13)) != 0)
return status;
break;
return ret;
}
case 'V':
if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_18)) != 0)
return status;
break;
int dvbfe_set_voltage(struct dvbfe_handle *fehandle, enum dvbfe_sec_voltage voltage)
{
int ret = 0;
case 'A':
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_A)) != 0)
return status;
break;
switch (voltage) {
case DVBFE_SEC_VOLTAGE_OFF:
ret = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_OFF);
break;
case DVBFE_SEC_VOLTAGE_13:
ret = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_13);
break;
case DVBFE_SEC_VOLTAGE_18:
ret = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_18);
break;
default:
print(verbose, ERROR, 1, "Invalid command");
break;
}
if (ret == -1)
print(verbose, ERROR, 1, "IOCTL failed");
case 'B':
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_B)) != 0)
return status;
break;
return ret;
}
case '+':
ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 1);
/* don't care if this one is not supported */
break;
int dvbfe_set_high_lnb_voltage(struct dvbfe_handle *fehandle, int on)
{
switch (on) {
case 0:
ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 0);
break;
default:
ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 1);
break;
}
return 0;
}
case '-':
ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 0);
/* don't care if this one is not supported */
break;
int dvbfe_do_dishnetworks_legacy_command(struct dvbfe_handle *fehandle, unsigned int cmd)
{
int ret = 0;
case 'W':
waittime = atoi(command + i + 1);
if (waittime == 0) {
return -EINVAL;
}
usleep(waittime * 1000);
while(command[i] && !isspace(command[i]))
i++;
break;
ret = ioctl(fehandle->fd, FE_DISHNETWORK_SEND_LEGACY_CMD, cmd);
if (ret == -1)
print(verbose, ERROR, 1, "IOCTL failed");
case '.': // extended command
{
i++;
if (!strncmp(command+i, "D(", 2)) {
i += 2;
master_cmd.msg_len =
sscanf(command+i, "%x %x %x %x %x %x",
tmpcmd, tmpcmd+1, tmpcmd+2, tmpcmd+3, tmpcmd+4, tmpcmd+5);
if (master_cmd.msg_len == 0)
return -EINVAL;
master_cmd.msg[0] = tmpcmd[0];
master_cmd.msg[1] = tmpcmd[1];
master_cmd.msg[2] = tmpcmd[2];
master_cmd.msg[3] = tmpcmd[3];
master_cmd.msg[4] = tmpcmd[4];
master_cmd.msg[5] = tmpcmd[5];
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
return status;
} else if (!strncmp(command+i, "Dband(", 6)) {
if (sscanf(command+i+6, "%i %2s", &addr, value_s) != 2)
return -EINVAL;
if (!strncmp(value_s, "lo", 2)) {
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x20;
master_cmd.msg_len = 3;
} else if (!strncmp(value_s, "hi", 2)) {
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x24;
master_cmd.msg_len = 3;
} else {
return -EINVAL;
}
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
return status;
} else if ((!strncmp(command+i, "Dpolarisation(", 14) ||
(!strncmp(command+i, "Dpolarization(", 14)))) {
if (sscanf(command+i+14, "%i %1s", &addr, value_s) != 2)
return -EINVAL;
switch(*value_s) {
case 'H':
case 'L':
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x25;
master_cmd.msg_len = 3;
break;
case 'V':
case 'R':
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x21;
master_cmd.msg_len = 3;
break;
default:
return -EINVAL;
}
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
return status;
} else if (!strncmp(command+i, "Dsatellite_position(", 20)) {
if (sscanf(command+i+20, "%i %1s", &addr, value_s) != 2)
return -EINVAL;
switch(*value_s) {
case 'A':
case 'C':
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x22;
master_cmd.msg_len = 3;
break;
case 'B':
case 'D':
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x26;
master_cmd.msg_len = 3;
break;
default:
return -EINVAL;
}
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
return status;
} else if (!strncmp(command+i, "Dswitch_option(", 15)) {
if (sscanf(command+i+15, "%i %1s", &addr, value_s) != 2)
return -EINVAL;
switch(*value_s) {
case 'A':
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x23;
master_cmd.msg_len = 3;
break;
case 'B':
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x27;
master_cmd.msg_len = 3;
break;
default:
return -EINVAL;
}
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
return status;
} else if (!strncmp(command+i, "Dport_pins(", 11)) {
int mask;
if (sscanf(command+i+11, "%i %i %i", &addr, &mask, &value_i) != 3)
return -EINVAL;
if (mask & 0x0f) {
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x38;
master_cmd.msg[3] = ((mask & 0x0f) << 4) | (value_i & 0x0f);
master_cmd.msg_len = 4;
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
return status;
}
if (mask & 0xf0) {
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x39;
master_cmd.msg[3] = (mask & 0xf0) | ((value_i & 0xf0) >> 4);
master_cmd.msg_len = 4;
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
return status;
}
} else if (!strncmp(command+i, "Dgoto_preset(", 13)) {
if (sscanf(command+i+13, "%i %i", &addr, &value_i) != 2)
return -EINVAL;
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x3b;
master_cmd.msg[3] = value_i;
master_cmd.msg_len = 4;
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
return status;
} else if (!strncmp(command+i, "Dgoto_angle(", 12)) {
int integer = 0;
int fraction = 0;
char *tmp;
if (sscanf(command+i+12, "%i %s", &addr, value_s) != 2)
return -EINVAL;
// parse the integer and fractional parts using fixed point
integer = atoi(value_s);
tmp = strchr(value_s, '.');
if (tmp != NULL) {
tmp++;
tmp[3] = 0;
fraction = ((atoi(tmp) * 16000) / 1000000) & 0xf;
}
// generate the command
master_cmd.msg[0] = 0xe0;
master_cmd.msg[1] = addr;
master_cmd.msg[2] = 0x6e;
if (integer < -256) {
return -EINVAL;
} else if (integer < 0) {
integer = -integer;
master_cmd.msg[3] = 0xf0;
} else if (integer < 256) {
master_cmd.msg[3] = 0x00;
} else if (integer < 512) {
integer -= 256;
master_cmd.msg[3] = 0x10;
} else {
return -EINVAL;
}
master_cmd.msg[3] |= ((integer / 16) & 0x0f);
integer = integer % 16;
master_cmd.msg[4] |= ((integer & 0x0f) << 4) | fraction;
master_cmd.msg_len = 5;
if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
return status;
} else if (!strncmp(command+i, "dishnetworks(", 13)) {
if (sscanf(command+i+13, "%i", tmpcmd) != 1)
return -EINVAL;
if ((status = ioctl(fehandle->fd, FE_DISHNETWORK_SEND_LEGACY_CMD, tmpcmd)) != 0)
return status;
}
return ret;
}
/* skip to the end... */
while(command[i] && (command[i] != ')'))
i++;
break;
}
int dvbfe_do_diseqc_command(struct dvbfe_handle *fehandle, uint8_t *data, uint8_t len)
{
int ret = 0;
struct dvb_diseqc_master_cmd diseqc_message;
if (len > 6)
return -EINVAL;
default:
return -EINVAL;
}
diseqc_message.msg_len = len;
memcpy(diseqc_message.msg, data, len);
i++;
}
ret = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &diseqc_message);
if (ret == -1)
print(verbose, ERROR, 1, "IOCTL failed");
return 0;
return ret;
}
int dvbfe_diseqc_read(dvbfe_handle_t _fehandle, int timeout, unsigned char *buf, unsigned int len)
int dvbfe_diseqc_read(struct dvbfe_handle *fehandle, int timeout, unsigned char *buf, unsigned int len)
{
struct dvb_diseqc_slave_reply reply;
int result;
struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
if (len > 4)
len = 4;

@ -2,6 +2,7 @@
* libdvbfe - a DVB frontend library
*
* Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
* Copyright (C) 2005 Manu Abraham <abraham.manu@gmail.com>
* Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
*
* This library is free software; you can redistribute it and/or
@ -32,27 +33,20 @@ extern "C"
/**
* The types of frontend we support.
*/
typedef enum dvbfe_type {
enum dvbfe_type {
DVBFE_TYPE_DVBS,
DVBFE_TYPE_DVBC,
DVBFE_TYPE_DVBT,
DVBFE_TYPE_ATSC,
} dvbfe_type_t;
typedef enum dvbfe_polarization {
DVBFE_POLARIZATION_H,
DVBFE_POLARIZATION_V,
DVBFE_POLARIZATION_L,
DVBFE_POLARIZATION_R,
} dvbfe_polarization_t;
};
typedef enum dvbfe_spectral_inversion {
enum dvbfe_spectral_inversion {
DVBFE_INVERSION_OFF,
DVBFE_INVERSION_ON,
DVBFE_INVERSION_AUTO
} dvbfe_spectral_inversion_t;
};
typedef enum dvbfe_code_rate {
enum dvbfe_code_rate {
DVBFE_FEC_NONE,
DVBFE_FEC_1_2,
DVBFE_FEC_2_3,
@ -63,9 +57,9 @@ typedef enum dvbfe_code_rate {
DVBFE_FEC_7_8,
DVBFE_FEC_8_9,
DVBFE_FEC_AUTO
} dvbfe_code_rate_t;
};
typedef enum dvbfe_dvbt_const {
enum dvbfe_dvbt_const {
DVBFE_DVBT_CONST_QPSK,
DVBFE_DVBT_CONST_QAM_16,
DVBFE_DVBT_CONST_QAM_32,
@ -73,106 +67,121 @@ typedef enum dvbfe_dvbt_const {
DVBFE_DVBT_CONST_QAM_128,
DVBFE_DVBT_CONST_QAM_256,
DVBFE_DVBT_CONST_AUTO
} dvbfe_dvbt_const_t;
};
typedef enum dvbfe_dvbc_mod {
enum dvbfe_dvbc_mod {
DVBFE_DVBC_MOD_QAM_16,
DVBFE_DVBC_MOD_QAM_32,
DVBFE_DVBC_MOD_QAM_64,
DVBFE_DVBC_MOD_QAM_128,
DVBFE_DVBC_MOD_QAM_256,
DVBFE_DVBC_MOD_AUTO,
} dvbfe_dvbc_mod_t;
};
typedef enum dvbfe_atsc_mod {
enum dvbfe_atsc_mod {
DVBFE_ATSC_MOD_QAM_64,
DVBFE_ATSC_MOD_QAM_256,
DVBFE_ATSC_MOD_VSB_8,
DVBFE_ATSC_MOD_VSB_16,
DVBFE_ATSC_MOD_AUTO
} dvbfe_atsc_mod_t;
};
typedef enum dvbfe_dvbt_transmit_mode {
enum dvbfe_dvbt_transmit_mode {
DVBFE_DVBT_TRANSMISSION_MODE_2K,
DVBFE_DVBT_TRANSMISSION_MODE_8K,
DVBFE_DVBT_TRANSMISSION_MODE_AUTO
} dvbfe_dvbt_transmit_mode_t;
};
typedef enum dvbfe_dvbt_bandwidth {
enum dvbfe_dvbt_bandwidth {
DVBFE_DVBT_BANDWIDTH_8_MHZ,
DVBFE_DVBT_BANDWIDTH_7_MHZ,
DVBFE_DVBT_BANDWIDTH_6_MHZ,
DVBFE_DVBT_BANDWIDTH_AUTO
} dvbfe_dvbt_bandwidth_t;
};
typedef enum dvbfe_dvbt_guard_interval {
enum dvbfe_dvbt_guard_interval {
DVBFE_DVBT_GUARD_INTERVAL_1_32,
DVBFE_DVBT_GUARD_INTERVAL_1_16,
DVBFE_DVBT_GUARD_INTERVAL_1_8,
DVBFE_DVBT_GUARD_INTERVAL_1_4,
DVBFE_DVBT_GUARD_INTERVAL_AUTO
} dvbfe_dvbt_guard_interval_t;
};
typedef enum dvbfe_dvbt_hierarchy {
enum dvbfe_dvbt_hierarchy {
DVBFE_DVBT_HIERARCHY_NONE,
DVBFE_DVBT_HIERARCHY_1,
DVBFE_DVBT_HIERARCHY_2,
DVBFE_DVBT_HIERARCHY_4,
DVBFE_DVBT_HIERARCHY_AUTO
} dvbfe_dvbt_hierarchy_t;
};
/**
* Structure used to store and communicate frontend parameters.
*/
struct dvbfe_parameters {
uint32_t frequency;
dvbfe_spectral_inversion_t inversion;
enum dvbfe_spectral_inversion inversion;
union {
struct {
uint32_t symbol_rate;
dvbfe_code_rate_t fec_inner;
dvbfe_polarization_t polarization;
enum dvbfe_code_rate fec_inner;
} dvbs;
struct {
uint32_t symbol_rate;
dvbfe_code_rate_t fec_inner;
dvbfe_dvbc_mod_t modulation;
enum dvbfe_code_rate fec_inner;
enum dvbfe_dvbc_mod modulation;
} dvbc;
struct {
dvbfe_dvbt_bandwidth_t bandwidth;
dvbfe_code_rate_t code_rate_HP;
dvbfe_code_rate_t code_rate_LP;
dvbfe_dvbt_const_t constellation;
dvbfe_dvbt_transmit_mode_t transmission_mode;
dvbfe_dvbt_guard_interval_t guard_interval;
dvbfe_dvbt_hierarchy_t hierarchy_information;
enum dvbfe_dvbt_bandwidth bandwidth;
enum dvbfe_code_rate code_rate_HP;
enum dvbfe_code_rate code_rate_LP;
enum dvbfe_dvbt_const constellation;
enum dvbfe_dvbt_transmit_mode transmission_mode;
enum dvbfe_dvbt_guard_interval guard_interval;
enum dvbfe_dvbt_hierarchy hierarchy_information;
} dvbt;
struct {
dvbfe_atsc_mod_t modulation;
enum dvbfe_atsc_mod modulation;
} atsc;
} u;
};
enum dvbfe_sec_voltage {
DVBFE_SEC_VOLTAGE_13,
DVBFE_SEC_VOLTAGE_18,
DVBFE_SEC_VOLTAGE_OFF
};
enum dvbfe_sec_tone_mode {
DVBFE_SEC_TONE_ON,
DVBFE_SEC_TONE_OFF
};
enum dvbfe_sec_mini_cmd {
DVBFE_SEC_MINI_A,
DVBFE_SEC_MINI_B
};
/**
* Mask of values used in the dvbfe_get_info() call.
*/
typedef enum dvbfe_info_mask {
enum dvbfe_info_mask {
DVBFE_INFO_LOCKSTATUS = 0x01,
DVBFE_INFO_FEPARAMS = 0x02,
DVBFE_INFO_BER = 0x04,
DVBFE_INFO_SIGNAL_STRENGTH = 0x08,
DVBFE_INFO_SNR = 0x10,
DVBFE_INFO_UNCORRECTED_BLOCKS = 0x20,
} dvbfe_info_mask_t;
};
/**
* Structure containing values used by the dvbfe_get_info() call.
*/
struct dvbfe_info {
dvbfe_type_t type; /* always retrieved */
enum dvbfe_type type; /* always retrieved */
const char *name; /* always retrieved */
unsigned int signal : 1; /* } DVBFE_INFO_LOCKSTATUS */
unsigned int carrier : 1; /* } */
@ -186,10 +195,24 @@ struct dvbfe_info {
uint32_t ucblocks; /* DVBFE_INFO_UNCORRECTED_BLOCKS */
};
/**
* Possible types of query used in dvbfe_get_info.
*
* DVBFE_INFO_QUERYTYPE_IMMEDIATE - interrogate frontend for most up to date values.
* DVBFE_INFO_QUERYTYPE_LOCKCHANGE - return details from queued lock status
* change events, or wait for one to occur
* if none are queued.
*/
enum dvbfe_info_querytype {
DVBFE_INFO_QUERYTYPE_IMMEDIATE,
DVBFE_INFO_QUERYTYPE_LOCKCHANGE,
};
/**
* Frontend handle datatype.
*/
typedef void *dvbfe_handle_t;
struct dvbfe_handle;
/**
* Open a DVB frontend.
@ -199,18 +222,21 @@ typedef void *dvbfe_handle_t;
* @param readonly If 1, frontend will be opened in readonly mode only.
* @return A handle on success, or NULL on failure.
*/
extern dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly);
extern struct dvbfe_handle *dvbfe_open(int adapter, int frontend, int readonly);
/**
* Close a DVB frontend.
*
* @param fehandle Handle opened with dvbfe_open().
*/
extern void dvbfe_close(dvbfe_handle_t handle);
extern void dvbfe_close(struct dvbfe_handle *handle);
/**
* Set the frontend tuning parameters.
*
* Note: this function provides only the basic tuning operation; you might want to
* investigate dvbfe_set_sec() in sec.h for a unified device tuning operation.
*
* @param fehandle Handle opened with dvbfe_open().
* @param params Params to set.
* @param timeout <0 => wait forever for lock. 0=>return immediately, >0=>
@ -218,14 +244,9 @@ extern void dvbfe_close(dvbfe_handle_t handle);
* @return 0 on locked (or if timeout==0 and everything else worked), or
* nonzero on failure (including no lock).
*/
extern int dvbfe_set(dvbfe_handle_t fehandle, struct dvbfe_parameters *params, int timeout);
/**
* Call this function regularly from a loop to maintain the frontend lock.
*
* @param fehandle Handle opened with dvbfe_open().
*/
extern void dvbfe_poll(dvbfe_handle_t fehandle);
extern int dvbfe_set(struct dvbfe_handle *fehandle,
struct dvbfe_parameters *params,
int timeout);
/**
* Retrieve information about the frontend.
@ -233,62 +254,66 @@ extern void dvbfe_poll(dvbfe_handle_t fehandle);
* @param fehandle Handle opened with dvbfe_open().
* @param querymask ORed bitmask of desired DVBFE_INFO_* values.
* @param result Where to put the retrieved results.
* @param querytype Type of query requested.
* @param timeout Timeout in ms to use if querytype==lockchange (0=>no timeout, <0=> wait forever).
* @return ORed bitmask of DVBFE_INFO_* indicating which values were read successfully.
*/
extern int dvbfe_get_info(dvbfe_handle_t fehandle, dvbfe_info_mask_t querymask, struct dvbfe_info *result);
extern int dvbfe_get_info(struct dvbfe_handle *fehandle,
enum dvbfe_info_mask querymask,
struct dvbfe_info *result,
enum dvbfe_info_querytype querytype,
int timeout);
/**
* Execute a DISEQC command string.
*
* A diseqc command consists of a sequence of the following codes, separated by
* whitespace:
* Simple commands:
* t - turn 22kHz tone off.
* T - turn 22kHz tone on.
* _ - set voltage to 0v (i.e. off).
* v - set voltage to 13v.
* V - set voltage to 18v.
* + - Enable high LNB voltage.
* - - Disable high LNB voltage.
* A - send DISEQC mini command A.
* B - send DISEQC mini command B.
* Wii - Delay for ii milliseconds.
*
* Extended commands:
* .dishnetworks(<value>) - Send a dish networks legacy command <value>
* .D(<value> ...) - Send a raw diseqc master command. The command may be up
* to 6 bytes long.
* .Dband(<addr> <lo|hi>) - Set frequency band hi or lo.
* .Dpolarisation(<addr> <V|H|L|R>) - Set polarisation.
* .Dsatellite_position(<addr> <A|B>) - Set "satellite position" input switch.
* .Dswitch_option(<addr> <A|B>) - Set "switch option" input switch.
* .Dport_pins(<addr> <mask> <value>) - Set all input switches. Mask and value
* are hex-ascii 8 bit bytes. Only bits with a corresponding '1' in mask
* will be changed.
* .Dgoto_preset(<addr> <index>) - Set a positioner to a preset index (integer)
* .Dgoto_angle(<addr> <angle>) - Set a positioner to a given angle
* (e.g. 49.6). The angle may range between -180 to 496. It may include a
* fractional part.
*
* All integer values use standard notation - no prefix=>decimal, 0x=>hex etc.
*
* Set <addr> to 0 if you just have a simple DISEQC setup (e.g. one switch). See
* the DISEQC specification at http://www.eutelsat.org/ for full information.
*
* Comments begin with '#' - any characters after this will be ignored
* to the end of the line.
*
* Examples:
* S-19.2E 11700000 V 9750000 t v W15 .D(E0 10 38 F0) W15 A W15 t
* S-19.2E 99999999 V 10600000 t v W15 .D(E0 10 38 F1) W15 A W15 T
* S-19.2E 11700000 H 9750000 t V W15 .D(E0 10 38 F2) W15 A W15 t
* S-19.2E 99999999 H 10600000 t V W15 .D(E0 10 38 F3) W15 A W15 T
* Get a file descriptor for polling for lock status changes.
*
* @param fehandle Handle opened with dvbfe_open().
* @param command Command to execute.
* @return 0 on success, nonzero on failure.
* @return FD for polling.
*/
extern int dvbfe_get_pollfd(struct dvbfe_handle *handle);
/**
* Tone/Data Burst control
* @param fehandle Handle opened with dvbfe_open().
* @param tone, SEC_TONE_ON/SEC_TONE_OFF
*/
extern int dvbfe_set_22k_tone(struct dvbfe_handle *handle, enum dvbfe_sec_tone_mode tone);
/**
* 22khz Tone control
* @param fehandle Handle opened with dvbfe_open().
* @param adapter, minicmd, SEC_MINI_A/SEC_MINI_B
*/
extern int dvbfe_set_tone_data_burst(struct dvbfe_handle *handle, enum dvbfe_sec_mini_cmd minicmd);
/**
* Voltage control
* @param fehandle Handle opened with dvbfe_open().
* @param polarization, SEC_VOLTAGE_13/SEC_VOLTAGE_18/SEC_VOLTAGE_OFF
*/
extern int dvbfe_set_voltage(struct dvbfe_handle *handle, enum dvbfe_sec_voltage voltage);
/**
* High LNB voltage control (increases voltage by 1v to compensate for long cables)
* @param fehandle Handle opened with dvbfe_open().
* @param on 1 to enable, 0 to disable.
*/
extern int dvbfe_set_high_lnb_voltage(struct dvbfe_handle *fehandle, int on);
/**
* Send a legacy Dish Networks command
* @param fehandle Handle opened with dvbfe_open().
* @param cmd, the command to send
*/
extern int dvbfe_do_dishnetworks_legacy_command(struct dvbfe_handle *handle, unsigned int cmd);
/**
* Send a DiSEqC Command
* @param fehandle Handle opened with dvbfe_open().
* @param data, a pointer to am array containing the data to be sent.
* @param len Length of data in bytes, max 6 bytes.
*/
extern int dvbfe_diseqc_command(dvbfe_handle_t fehandle, char *command);
extern int dvbfe_do_diseqc_command(struct dvbfe_handle *handle, uint8_t *data, uint8_t len);
/**
* Read a DISEQC response from the frontend.
@ -299,7 +324,7 @@ extern int dvbfe_diseqc_command(dvbfe_handle_t fehandle, char *command);
* @param len Number of bytes in buffer.
* @return >= 0 on success (number of received bytes), <0 on failure.
*/
extern int dvbfe_diseqc_read(dvbfe_handle_t fehandle, int timeout, unsigned char *buf, unsigned int len);
extern int dvbfe_diseqc_read(struct dvbfe_handle *fehandle, int timeout, unsigned char *buf, unsigned int len);
#ifdef __cplusplus
}

@ -44,9 +44,10 @@ int dvbnet_open(int adapter, int netdeviceid)
return fd;
}
int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation)
int dvbnet_add_interface(int fd, uint16_t pid, enum dvbnet_encap encapsulation)
{
struct dvb_net_if params;
int status;
memset(&params, 0, sizeof(params));
params.pid = pid;
@ -63,10 +64,14 @@ int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation)
default:
return -EINVAL;
}
return ioctl(fd, NET_ADD_IF, &params);
status = ioctl(fd, NET_ADD_IF, &params);
if (status < 0)
return status;
return params.if_num;
}
int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, int *encapsulation)
int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, enum dvbnet_encap *encapsulation)
{
struct dvb_net_if info;
int res;

@ -31,10 +31,10 @@ extern "C"
/**
* Possible encapsulations of data.
*/
typedef enum dvbnet_encap {
enum dvbnet_encap {
DVBNET_ENCAP_MPE,
DVBNET_ENCAP_ULE,
} dvbnet_encap_t;
};
/**
* The maximum allowed number of dvb network devices per adapter netdevice.
@ -56,9 +56,9 @@ extern int dvbnet_open(int adapter, int netdeviceid);
* @param fd FD opened with libdvbnet_open().
* @param pid PID of the stream containing the network data.
* @param encapsulation Encapsulation type of the stream (one of DVBNET_ENCAP_*).
* @return 0 on success, nonzero on failure.
* @return Index of new interface on success, < 0 on failure.
*/
extern int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation);
extern int dvbnet_add_interface(int fd, uint16_t pid, enum dvbnet_encap encapsulation);
/**
* Get details of a DVBNET interface.
@ -69,7 +69,7 @@ extern int dvbnet_add_interface(int fd, uint16_t pid, int encapsulation);
* @param encapsulation The encapsulation of the interface (DVBNET_ENCAP_*).
* @return 0 on success, nonzero on failure.
*/
extern int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, int *encapsulation);
extern int dvbnet_get_interface(int fd, int ifnum, uint16_t *pid, enum dvbnet_encap *encapsulation);
/**
* Remove a DVBNET interface.

@ -0,0 +1,46 @@
/*
* libdvbnet - a DVB network support library
*
* Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/param.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/dvb/video.h>
#include <errno.h>
#include "dvbvideo.h"
int dvbvideo_open(int adapter, int videodeviceid)
{
char filename[PATH_MAX+1];
int fd;
sprintf(filename, "/dev/dvb/adapter%i/video%i", adapter, videodeviceid);
if ((fd = open(filename, O_RDWR)) < 0) {
// if that failed, try a flat /dev structure
sprintf(filename, "/dev/dvb%i.video%i", adapter, videodeviceid);
fd = open(filename, O_RDWR);
}
return fd;
}

@ -0,0 +1,46 @@
/*
* libdvbnet - a DVB network support library
*
* Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef LIBDVBVIDEO_H
#define LIBDVBVIDEO_H 1
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
/**
* Open a DVB video device.
*
* @param adapter DVB adapter ID.
* @param videodeviceid Id of video device of that adapter to open.
* @return A unix file descriptor on success, or -1 on failure.
*/
extern int dvbvideo_open(int adapter, int videodeviceid);
// FIXME: this is a stub library
#ifdef __cplusplus
}
#endif
#endif // LIBDVBVIDEO_H

@ -16,6 +16,9 @@ libdvben50221_la_SOURCES = asn_1.c \
en50221_app_teletext.c \
en50221_app_utils.c \
en50221_session.c \
en50221_transport.c
en50221_transport.c \
en50221_stdcam.c \
en50221_stdcam_llci.c \
en50221_stdcam_hlci.c
CFLAGS = -g -O2 -DLOG_LEVEL=1 -Wall -Wshadow -Wpointer-arith -Wstrict-prototypes -fPIC

@ -2,8 +2,8 @@
ASN.1 routines, implementation for libdvben50221
an implementation for the High Level Common Interface
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
@ -17,65 +17,67 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include "asn_1.h"
int asn_1_decode(uint16_t *length, uint8_t *asn_1_array, uint32_t asn_1_array_len)
int asn_1_decode(uint16_t * length, uint8_t * asn_1_array,
uint32_t asn_1_array_len)
{
uint8_t length_field;
if (asn_1_array_len < 1)
return -1;
if (asn_1_array_len < 1)
return -1;
length_field = asn_1_array[0];
if (length_field < 0x80) {
if (length_field < 0x80) {
// there is only one word
*length = length_field & 0x7f;
return 1;
} else if (length_field == 0x81) {
if (asn_1_array_len < 2)
return -1;
*length = asn_1_array[1];
return 2;
} else if (length_field == 0x82) {
if (asn_1_array_len < 3)
return -1;
*length = (asn_1_array[1] << 8) | asn_1_array[2];
return 3;
}
return -1;
return 1;
} else if (length_field == 0x81) {
if (asn_1_array_len < 2)
return -1;
*length = asn_1_array[1];
return 2;
} else if (length_field == 0x82) {
if (asn_1_array_len < 3)
return -1;
*length = (asn_1_array[1] << 8) | asn_1_array[2];
return 3;
}
return -1;
}
int asn_1_encode(uint16_t length, uint8_t *asn_1_array, uint32_t asn_1_array_len)
int asn_1_encode(uint16_t length, uint8_t * asn_1_array,
uint32_t asn_1_array_len)
{
if (length < 0x80) {
if (asn_1_array_len < 1)
return -1;
if (length < 0x80) {
if (asn_1_array_len < 1)
return -1;
asn_1_array[0] = length & 0x7f;
return 1;
asn_1_array[0] = length & 0x7f;
return 1;
} else if (length < 0x100) {
if (asn_1_array_len < 2)
return -1;
asn_1_array[0] = 0x81;
asn_1_array[1] = length;
return 2;
} else {
if (asn_1_array_len < 3)
return -1;
asn_1_array[0] = 0x82;
asn_1_array[1] = length >> 8;
asn_1_array[2] = length;
return 3;
if (asn_1_array_len < 2)
return -1;
asn_1_array[0] = 0x81;
asn_1_array[1] = length;
return 2;
} else {
if (asn_1_array_len < 3)
return -1;
asn_1_array[0] = 0x82;
asn_1_array[1] = length >> 8;
asn_1_array[2] = length;
return 3;
}
// never reached
// never reached
}

@ -2,8 +2,8 @@
ASN.1 routines, implementation for libdvben50221
an implementation for the High Level Common Interface
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
@ -17,25 +17,25 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __ASN_1_H__
#define __ASN_1_H__
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
#include <stdlib.h>
#include <stdint.h>
int asn_1_decode(uint16_t *length, uint8_t *asn_1_array, uint32_t asn_1_array_len);
int asn_1_encode(uint16_t length, uint8_t *asn_1_array, uint32_t asn_1_array_len);
int asn_1_decode(uint16_t * length, uint8_t * asn_1_array,
uint32_t asn_1_array_len);
int asn_1_encode(uint16_t length, uint8_t * asn_1_array,
uint32_t asn_1_array_len);
#ifdef __cplusplus
}
#endif
#endif

@ -2,7 +2,7 @@
en50221 encoder An implementation for libdvb
an implementation for the en50221 transport layer
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
@ -18,7 +18,7 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
@ -28,106 +28,107 @@
#include "en50221_app_tags.h"
#include "asn_1.h"
struct en50221_app_ai_private {
struct en50221_app_send_functions *funcs;
struct en50221_app_ai {
struct en50221_app_send_functions *funcs;
en50221_app_ai_callback callback;
void *callback_arg;
en50221_app_ai_callback callback;
void *callback_arg;
pthread_mutex_t lock;
pthread_mutex_t lock;
};
static int en50221_app_ai_parse_app_info(struct en50221_app_ai_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length);
static int en50221_app_ai_parse_app_info(struct en50221_app_ai *ai,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data,
uint32_t data_length);
en50221_app_ai en50221_app_ai_create(struct en50221_app_send_functions *funcs)
struct en50221_app_ai *en50221_app_ai_create(struct en50221_app_send_functions *funcs)
{
struct en50221_app_ai_private *private = NULL;
struct en50221_app_ai *ai = NULL;
// create structure and set it up
private = malloc(sizeof(struct en50221_app_ai_private));
if (private == NULL) {
return NULL;
}
private->funcs = funcs;
private->callback = NULL;
// create structure and set it up
ai = malloc(sizeof(struct en50221_app_ai));
if (ai == NULL) {
return NULL;
}
ai->funcs = funcs;
ai->callback = NULL;
pthread_mutex_init(&private->lock, NULL);
pthread_mutex_init(&ai->lock, NULL);
// done
return private;
// done
return ai;
}
void en50221_app_ai_destroy(en50221_app_ai ai)
void en50221_app_ai_destroy(struct en50221_app_ai *ai)
{
struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai;
pthread_mutex_destroy(&private->lock);
free(private);
pthread_mutex_destroy(&ai->lock);
free(ai);
}
void en50221_app_ai_register_callback(en50221_app_ai ai, en50221_app_ai_callback callback, void *arg)
void en50221_app_ai_register_callback(struct en50221_app_ai *ai,
en50221_app_ai_callback callback,
void *arg)
{
struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai;
pthread_mutex_lock(&private->lock);
private->callback = callback;
private->callback_arg = arg;
pthread_mutex_unlock(&private->lock);
pthread_mutex_lock(&ai->lock);
ai->callback = callback;
ai->callback_arg = arg;
pthread_mutex_unlock(&ai->lock);
}
int en50221_app_ai_enquiry(en50221_app_ai ai, uint16_t session_number)
int en50221_app_ai_enquiry(struct en50221_app_ai *ai,
uint16_t session_number)
{
struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai;
uint8_t data[4];
uint8_t data[4];
data[0] = (TAG_APP_INFO_ENQUIRY >> 16) & 0xFF;
data[1] = (TAG_APP_INFO_ENQUIRY >> 8) & 0xFF;
data[2] = TAG_APP_INFO_ENQUIRY & 0xFF;
data[3] = 0;
data[0] = (TAG_APP_INFO_ENQUIRY >> 16) & 0xFF;
data[1] = (TAG_APP_INFO_ENQUIRY >> 8) & 0xFF;
data[2] = TAG_APP_INFO_ENQUIRY & 0xFF;
data[3] = 0;
return private->funcs->send_data(private->funcs->arg, session_number, data, 4);
return ai->funcs->send_data(ai->funcs->arg, session_number, data, 4);
}
int en50221_app_ai_entermenu(en50221_app_ai ai, uint16_t session_number)
int en50221_app_ai_entermenu(struct en50221_app_ai *ai,
uint16_t session_number)
{
struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai;
uint8_t data[4];
uint8_t data[4];
data[0] = (TAG_ENTER_MENU >> 16) & 0xFF;
data[1] = (TAG_ENTER_MENU >> 8) & 0xFF;
data[2] = TAG_ENTER_MENU & 0xFF;
data[3] = 0;
data[0] = (TAG_ENTER_MENU >> 16) & 0xFF;
data[1] = (TAG_ENTER_MENU >> 8) & 0xFF;
data[2] = TAG_ENTER_MENU & 0xFF;
data[3] = 0;
return private->funcs->send_data(private->funcs->arg, session_number, data, 4);
return ai->funcs->send_data(ai->funcs->arg, session_number, data, 4);
}
int en50221_app_ai_message(en50221_app_ai ai,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data, uint32_t data_length)
int en50221_app_ai_message(struct en50221_app_ai *ai,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t * data, uint32_t data_length)
{
struct en50221_app_ai_private *private = (struct en50221_app_ai_private *) ai;
(void) resource_id;
// get the tag
if (data_length < 3) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
switch(tag)
{
case TAG_APP_INFO:
return en50221_app_ai_parse_app_info(private, slot_id, session_number, data+3, data_length-3);
}
print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
return -1;
(void) resource_id;
// get the tag
if (data_length < 3) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
switch (tag) {
case TAG_APP_INFO:
return en50221_app_ai_parse_app_info(ai, slot_id,
session_number,
data + 3,
data_length - 3);
}
print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
return -1;
}
@ -136,50 +137,55 @@ int en50221_app_ai_message(en50221_app_ai ai,
static int en50221_app_ai_parse_app_info(struct en50221_app_ai_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length)
static int en50221_app_ai_parse_app_info(struct en50221_app_ai *ai,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data,
uint32_t data_length)
{
// parse the length field
int length_field_len;
uint16_t asn_data_length;
if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
print(LOG_LEVEL, ERROR, 1, "Received data with invalid length from module on slot %02x\n", slot_id);
return -1;
}
// check it
if (asn_data_length < 6) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
if (asn_data_length > (data_length - length_field_len)) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint8_t *app_info = data + length_field_len;
// parse the fields
uint8_t application_type = app_info[0];
uint16_t application_manufacturer = (app_info[1] << 8) | app_info[2];
uint16_t manufacturer_code = (app_info[3] << 8) | app_info[4];
uint8_t menu_string_length = app_info[5];
uint8_t *menu_string = app_info + 6;
// check the menu_string_length
if (menu_string_length > (asn_data_length-6)) {
print(LOG_LEVEL, ERROR, 1, "Received bad menu string length - adjusting\n");
menu_string_length = asn_data_length-6;
}
// tell the app
pthread_mutex_lock(&private->lock);
en50221_app_ai_callback cb = private->callback;
void *cb_arg = private->callback_arg;
pthread_mutex_unlock(&private->lock);
if (cb) {
return cb(cb_arg, slot_id, session_number, application_type,
application_manufacturer, manufacturer_code, menu_string_length, menu_string);
}
return 0;
// parse the length field
int length_field_len;
uint16_t asn_data_length;
if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
print(LOG_LEVEL, ERROR, 1,
"Received data with invalid length from module on slot %02x\n",
slot_id);
return -1;
}
// check it
if (asn_data_length < 6) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
if (asn_data_length > (data_length - length_field_len)) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint8_t *app_info = data + length_field_len;
// parse the fields
uint8_t application_type = app_info[0];
uint16_t application_manufacturer = (app_info[1] << 8) | app_info[2];
uint16_t manufacturer_code = (app_info[3] << 8) | app_info[4];
uint8_t menu_string_length = app_info[5];
uint8_t *menu_string = app_info + 6;
// check the menu_string_length
if (menu_string_length > (asn_data_length - 6)) {
print(LOG_LEVEL, ERROR, 1,
"Received bad menu string length - adjusting\n");
menu_string_length = asn_data_length - 6;
}
// tell the app
pthread_mutex_lock(&ai->lock);
en50221_app_ai_callback cb = ai->callback;
void *cb_arg = ai->callback_arg;
pthread_mutex_unlock(&ai->lock);
if (cb) {
return cb(cb_arg, slot_id, session_number,
application_type, application_manufacturer,
manufacturer_code, menu_string_length,
menu_string);
}
return 0;
}

@ -2,7 +2,7 @@
en50221 encoder An implementation for libdvb
an implementation for the en50221 transport layer
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
@ -18,15 +18,14 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __EN50221_APPLICATION_AI_H__
#define __EN50221_APPLICATION_AI_H__
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
#include <stdlib.h>
@ -52,15 +51,19 @@ extern "C"
* @param menu_string The menu string itself.
* @return 0 on success, -1 on failure.
*/
typedef int (*en50221_app_ai_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
uint8_t application_type, uint16_t application_manufacturer,
uint16_t manufacturer_code, uint8_t menu_string_length,
uint8_t *menu_string);
typedef int (*en50221_app_ai_callback) (void *arg,
uint8_t slot_id,
uint16_t session_number,
uint8_t application_type,
uint16_t application_manufacturer,
uint16_t manufacturer_code,
uint8_t menu_string_length,
uint8_t * menu_string);
/**
* Opaque type representing an application information resource.
*/
typedef void *en50221_app_ai;
struct en50221_app_ai;
/**
* Create an instance of an application information resource.
@ -68,14 +71,14 @@ typedef void *en50221_app_ai;
* @param funcs Send functions to use.
* @return Instance, or NULL on failure.
*/
extern en50221_app_ai en50221_app_ai_create(struct en50221_app_send_functions *funcs);
extern struct en50221_app_ai *en50221_app_ai_create(struct en50221_app_send_functions *funcs);
/**
* Destroy an instance of an application information resource.
*
* @param ai Instance to destroy.
*/
extern void en50221_app_ai_destroy(en50221_app_ai ai);
extern void en50221_app_ai_destroy(struct en50221_app_ai *ai);
/**
* Register a callback for reception of application_info objects.
@ -84,7 +87,9 @@ extern void en50221_app_ai_destroy(en50221_app_ai ai);
* @param callback Callback function.
* @param arg Private argument passed during calls to the callback.
*/
extern void en50221_app_ai_register_callback(en50221_app_ai ai, en50221_app_ai_callback, void *arg);
extern void en50221_app_ai_register_callback(struct en50221_app_ai *ai,
en50221_app_ai_callback,
void *arg);
/**
* send a enquiry for the app_info provided by a module
@ -93,7 +98,8 @@ extern void en50221_app_ai_register_callback(en50221_app_ai ai, en50221_app_ai_c
* @param session_number Session to send on.
* @return 0 on success, -1 on failure.
*/
extern int en50221_app_ai_enquiry(en50221_app_ai ai, uint16_t session_number);
extern int en50221_app_ai_enquiry(struct en50221_app_ai *ai,
uint16_t session_number);
/**
* send a enter_menu tag, this will make the application
@ -103,7 +109,8 @@ extern int en50221_app_ai_enquiry(en50221_app_ai ai, uint16_t session_number);
* @param session_number Session to send on.
* @return 0 on success, -1 on failure.
*/
extern int en50221_app_ai_entermenu(en50221_app_ai ai, uint16_t session_number);
extern int en50221_app_ai_entermenu(struct en50221_app_ai *ai,
uint16_t session_number);
/**
* Pass data received for this resource into it for parsing.
@ -116,14 +123,14 @@ extern int en50221_app_ai_entermenu(en50221_app_ai ai, uint16_t session_number);
* @param data_length Length of data in bytes.
* @return 0 on success, -1 on failure.
*/
extern int en50221_app_ai_message(en50221_app_ai ai,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data, uint32_t data_length);
extern int en50221_app_ai_message(struct en50221_app_ai *ai,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data,
uint32_t data_length);
#ifdef __cplusplus
}
#endif
#endif

@ -2,7 +2,7 @@
en50221 encoder An implementation for libdvb
an implementation for the en50221 transport layer
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
@ -18,7 +18,7 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
@ -28,152 +28,153 @@
#include "en50221_app_tags.h"
#include "asn_1.h"
struct en50221_app_auth_private {
struct en50221_app_send_functions *funcs;
struct en50221_app_auth {
struct en50221_app_send_functions *funcs;
en50221_app_auth_request_callback callback;
void *callback_arg;
en50221_app_auth_request_callback callback;
void *callback_arg;
pthread_mutex_t lock;
pthread_mutex_t lock;
};
static int en50221_app_auth_parse_request(struct en50221_app_auth_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length);
static int en50221_app_auth_parse_request(struct en50221_app_auth *private,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data,
uint32_t data_length);
en50221_app_auth en50221_app_auth_create(struct en50221_app_send_functions *funcs)
struct en50221_app_auth *en50221_app_auth_create(struct en50221_app_send_functions *funcs)
{
struct en50221_app_auth_private *private = NULL;
struct en50221_app_auth *auth = NULL;
// create structure and set it up
private = malloc(sizeof(struct en50221_app_auth_private));
if (private == NULL) {
return NULL;
}
private->funcs = funcs;
private->callback = NULL;
// create structure and set it up
auth = malloc(sizeof(struct en50221_app_auth));
if (auth == NULL) {
return NULL;
}
auth->funcs = funcs;
auth->callback = NULL;
pthread_mutex_init(&private->lock, NULL);
pthread_mutex_init(&auth->lock, NULL);
// done
return private;
// done
return auth;
}
void en50221_app_auth_destroy(en50221_app_auth auth)
void en50221_app_auth_destroy(struct en50221_app_auth *auth)
{
struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth;
pthread_mutex_destroy(&private->lock);
free(private);
pthread_mutex_destroy(&auth->lock);
free(auth);
}
void en50221_app_auth_register_request_callback(en50221_app_auth auth,
en50221_app_auth_request_callback callback, void *arg)
void en50221_app_auth_register_request_callback(struct en50221_app_auth *auth,
en50221_app_auth_request_callback callback, void *arg)
{
struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth;
pthread_mutex_lock(&private->lock);
private->callback = callback;
private->callback_arg = arg;
pthread_mutex_unlock(&private->lock);
pthread_mutex_lock(&auth->lock);
auth->callback = callback;
auth->callback_arg = arg;
pthread_mutex_unlock(&auth->lock);
}
int en50221_app_auth_send(en50221_app_auth auth,
uint16_t session_number,
uint16_t auth_protocol_id, uint8_t *auth_data,
uint32_t auth_data_length)
int en50221_app_auth_send(struct en50221_app_auth *auth,
uint16_t session_number,
uint16_t auth_protocol_id, uint8_t * auth_data,
uint32_t auth_data_length)
{
struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth;
uint8_t buf[10];
// the header
buf[0] = (TAG_AUTH_RESP >> 16) & 0xFF;
buf[1] = (TAG_AUTH_RESP >> 8) & 0xFF;
buf[2] = TAG_AUTH_RESP & 0xFF;
// encode the length field
int length_field_len;
if ((length_field_len = asn_1_encode(auth_data_length+2, buf+3, 3)) < 0) {
return -1;
}
// the phase_id
buf[3+length_field_len] = auth_protocol_id>>8;
buf[3+length_field_len+1] = auth_protocol_id;
// build the iovecs
struct iovec iov[2];
iov[0].iov_base = buf;
iov[0].iov_len = 3+length_field_len+2;
iov[1].iov_base = auth_data;
iov[1].iov_len = auth_data_length;
// sendit
return private->funcs->send_datav(private->funcs->arg, session_number, iov, 2);
uint8_t buf[10];
// the header
buf[0] = (TAG_AUTH_RESP >> 16) & 0xFF;
buf[1] = (TAG_AUTH_RESP >> 8) & 0xFF;
buf[2] = TAG_AUTH_RESP & 0xFF;
// encode the length field
int length_field_len;
if ((length_field_len = asn_1_encode(auth_data_length + 2, buf + 3, 3)) < 0) {
return -1;
}
// the phase_id
buf[3 + length_field_len] = auth_protocol_id >> 8;
buf[3 + length_field_len + 1] = auth_protocol_id;
// build the iovecs
struct iovec iov[2];
iov[0].iov_base = buf;
iov[0].iov_len = 3 + length_field_len + 2;
iov[1].iov_base = auth_data;
iov[1].iov_len = auth_data_length;
// sendit
return auth->funcs->send_datav(auth->funcs->arg, session_number,
iov, 2);
}
int en50221_app_auth_message(en50221_app_auth auth,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data, uint32_t data_length)
int en50221_app_auth_message(struct en50221_app_auth *auth,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t * data, uint32_t data_length)
{
struct en50221_app_auth_private *private = (struct en50221_app_auth_private *) auth;
(void) resource_id;
// get the tag
if (data_length < 3) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
switch(tag)
{
case TAG_AUTH_REQ:
return en50221_app_auth_parse_request(private, slot_id, session_number, data+3, data_length-3);
}
print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
return -1;
(void) resource_id;
// get the tag
if (data_length < 3) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
switch (tag) {
case TAG_AUTH_REQ:
return en50221_app_auth_parse_request(auth, slot_id,
session_number,
data + 3,
data_length - 3);
}
print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
return -1;
}
static int en50221_app_auth_parse_request(struct en50221_app_auth_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length)
static int en50221_app_auth_parse_request(struct en50221_app_auth *auth,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data,
uint32_t data_length)
{
// first of all, decode the length field
uint16_t asn_data_length;
int length_field_len;
if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
return -1;
}
// check it
if (asn_data_length < 2) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
if (asn_data_length > (data_length-length_field_len)) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint8_t *auth_data = data + length_field_len;
// process it
uint16_t auth_protocol_id = (auth_data[0]<<8) | auth_data[1];
// tell the app
pthread_mutex_lock(&private->lock);
en50221_app_auth_request_callback cb = private->callback;
void *cb_arg = private->callback_arg;
pthread_mutex_unlock(&private->lock);
if (cb) {
return cb(cb_arg, slot_id, session_number, auth_protocol_id, auth_data+2, asn_data_length-2);
}
return 0;
// first of all, decode the length field
uint16_t asn_data_length;
int length_field_len;
if ((length_field_len = asn_1_decode(&asn_data_length, data, data_length)) < 0) {
print(LOG_LEVEL, ERROR, 1, "ASN.1 decode error\n");
return -1;
}
// check it
if (asn_data_length < 2) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
if (asn_data_length > (data_length - length_field_len)) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint8_t *auth_data = data + length_field_len;
// process it
uint16_t auth_protocol_id = (auth_data[0] << 8) | auth_data[1];
// tell the app
pthread_mutex_lock(&auth->lock);
en50221_app_auth_request_callback cb = auth->callback;
void *cb_arg = auth->callback_arg;
pthread_mutex_unlock(&auth->lock);
if (cb) {
return cb(cb_arg, slot_id, session_number,
auth_protocol_id, auth_data + 2,
asn_data_length - 2);
}
return 0;
}

@ -2,7 +2,7 @@
en50221 encoder An implementation for libdvb
an implementation for the en50221 transport layer
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
@ -18,15 +18,14 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __EN50221_APPLICATION_auth_H__
#define __EN50221_APPLICATION_auth_H__
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
#include <stdlib.h>
@ -46,14 +45,17 @@ extern "C"
* @param auth_data_lenghth Number of bytes.
* @return 0 on success, -1 on failure.
*/
typedef int (*en50221_app_auth_request_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
uint16_t auth_protcol_id, uint8_t *auth_data,
uint32_t auth_data_length);
typedef int (*en50221_app_auth_request_callback) (void *arg,
uint8_t slot_id,
uint16_t session_number,
uint16_t auth_protcol_id,
uint8_t *auth_data,
uint32_t auth_data_length);
/**
* Opaque type representing a auth resource.
*/
typedef void *en50221_app_auth;
struct en50221_app_auth;
/**
* Create an instance of the auth resource.
@ -61,14 +63,14 @@ typedef void *en50221_app_auth;
* @param funcs Send functions to use.
* @return Instance, or NULL on failure.
*/
extern en50221_app_auth en50221_app_auth_create(struct en50221_app_send_functions *funcs);
extern struct en50221_app_auth *en50221_app_auth_create(struct en50221_app_send_functions *funcs);
/**
* Destroy an instance of the auth resource.
*
* @param auth Instance to destroy.
*/
extern void en50221_app_auth_destroy(en50221_app_auth auth);
extern void en50221_app_auth_destroy(struct en50221_app_auth *auth);
/**
* Register the callback for when we receive a request.
@ -77,8 +79,9 @@ extern void en50221_app_auth_destroy(en50221_app_auth auth);
* @param callback The callback. Set to NULL to remove the callback completely.
* @param arg Private data passed as arg0 of the callback.
*/
extern void en50221_app_auth_register_request_callback(en50221_app_auth auth,
en50221_app_auth_request_callback callback, void *arg);
extern void en50221_app_auth_register_request_callback(struct en50221_app_auth *auth,
en50221_app_auth_request_callback callback,
void *arg);
/**
* Send an auth response to the CAM.
@ -90,10 +93,11 @@ extern void en50221_app_auth_register_request_callback(en50221_app_auth auth,
* @param auth_data_length Number of bytes.
* @return 0 on success, -1 on failure.
*/
extern int en50221_app_auth_send(en50221_app_auth auth,
uint16_t session_number,
uint16_t auth_protocol_id, uint8_t *auth_data,
uint32_t auth_data_length);
extern int en50221_app_auth_send(struct en50221_app_auth *auth,
uint16_t session_number,
uint16_t auth_protocol_id,
uint8_t *auth_data,
uint32_t auth_data_length);
/**
* Pass data received for this resource into it for parsing.
@ -106,14 +110,14 @@ extern int en50221_app_auth_send(en50221_app_auth auth,
* @param data_length Length of data in bytes.
* @return 0 on success, -1 on failure.
*/
extern int en50221_app_auth_message(en50221_app_auth auth,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data, uint32_t data_length);
extern int en50221_app_auth_message(struct en50221_app_auth *auth,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data,
uint32_t data_length);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

@ -2,7 +2,7 @@
en50221 encoder An implementation for libdvb
an implementation for the en50221 transport layer
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
@ -18,15 +18,14 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __EN50221_APPLICATION_ca_H__
#define __EN50221_APPLICATION_ca_H__
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
#include <stdlib.h>
@ -60,24 +59,24 @@ extern "C"
* PMT reply structure.
*/
struct en50221_app_pmt_reply {
uint16_t program_number;
EBIT3(uint8_t reserved_1 : 2; ,
uint8_t version_number : 5; ,
uint8_t current_next_indicator : 1; )
EBIT2(uint8_t CA_enable_flag : 1; ,
uint8_t CA_enable : 7; )
/* struct en50221_app_pmt_stream streams[] */
} __attribute__((packed));
uint16_t program_number;
EBIT3(uint8_t reserved_1 : 2;,
uint8_t version_number : 5;,
uint8_t current_next_indicator : 1;);
EBIT2(uint8_t CA_enable_flag : 1;,
uint8_t CA_enable : 7;);
/* struct en50221_app_pmt_stream streams[] */
} __attribute__ ((packed));
/**
* A stream within a pmt reply structure.
*/
struct en50221_app_pmt_stream {
EBIT2(uint16_t reserved_1 : 3; ,
uint16_t es_pid :13; )
EBIT2(uint8_t CA_enable_flag : 1; ,
uint8_t CA_enable : 7; )
} __attribute__((packed));
EBIT2(uint16_t reserved_1 : 3;,
uint16_t es_pid :13;);
EBIT2(uint8_t CA_enable_flag : 1;,
uint8_t CA_enable : 7;);
} __attribute__ ((packed));
/**
* Convenience iterator for the streams field of the en50221_app_pmt_reply structure.
@ -102,9 +101,11 @@ struct en50221_app_pmt_stream {
* @param ca_ids Pointer to list of ca_system_ids.
* @return 0 on success, -1 on failure.
*/
typedef int (*en50221_app_ca_info_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
uint32_t ca_id_count,
uint16_t *ca_ids);
typedef int (*en50221_app_ca_info_callback) (void *arg,
uint8_t slot_id,
uint16_t session_number,
uint32_t ca_id_count,
uint16_t * ca_ids);
/**
* Type definition for pmt_reply - called when we receive a pmt_reply.
@ -116,14 +117,16 @@ typedef int (*en50221_app_ca_info_callback)(void *arg, uint8_t slot_id, uint16_t
* @param reply_size Total size of the struct en50221_app_pmt_reply in bytes.
* @return 0 on success, -1 on failure.
*/
typedef int (*en50221_app_ca_pmt_reply_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
struct en50221_app_pmt_reply *reply,
uint32_t reply_size);
typedef int (*en50221_app_ca_pmt_reply_callback) (void *arg,
uint8_t slot_id,
uint16_t session_number,
struct en50221_app_pmt_reply *reply,
uint32_t reply_size);
/**
* Opaque type representing a ca resource.
*/
typedef void *en50221_app_ca;
struct en50221_app_ca;
/**
* Create an instance of the ca resource.
@ -131,14 +134,14 @@ typedef void *en50221_app_ca;
* @param funcs Send functions to use.
* @return Instance, or NULL on failure.
*/
extern en50221_app_ca en50221_app_ca_create(struct en50221_app_send_functions *funcs);
extern struct en50221_app_ca *en50221_app_ca_create(struct en50221_app_send_functions *funcs);
/**
* Destroy an instance of the ca resource.
*
* @param ca Instance to destroy.
*/
extern void en50221_app_ca_destroy(en50221_app_ca ca);
extern void en50221_app_ca_destroy(struct en50221_app_ca *ca);
/**
* Register the callback for when we receive a ca info.
@ -147,8 +150,9 @@ extern void en50221_app_ca_destroy(en50221_app_ca ca);
* @param callback The callback. Set to NULL to remove the callback completely.
* @param arg Private data passed as arg0 of the callback.
*/
extern void en50221_app_ca_register_info_callback(en50221_app_ca ca,
en50221_app_ca_info_callback callback, void *arg);
extern void en50221_app_ca_register_info_callback(struct en50221_app_ca *ca,
en50221_app_ca_info_callback callback,
void *arg);
/**
* Register the callback for when we receive a pmt_reply.
@ -157,8 +161,9 @@ extern void en50221_app_ca_register_info_callback(en50221_app_ca ca,
* @param callback The callback. Set to NULL to remove the callback completely.
* @param arg Private data passed as arg0 of the callback.
*/
extern void en50221_app_ca_register_pmt_reply_callback(en50221_app_ca ca,
en50221_app_ca_pmt_reply_callback callback, void *arg);
extern void en50221_app_ca_register_pmt_reply_callback(struct en50221_app_ca *ca,
en50221_app_ca_pmt_reply_callback callback,
void *arg);
/**
* Send a ca_info_req to the CAM.
@ -167,8 +172,8 @@ extern void en50221_app_ca_register_pmt_reply_callback(en50221_app_ca ca,
* @param session_number Session number to send it on.
* @return 0 on success, -1 on failure.
*/
extern int en50221_app_ca_info_enq(en50221_app_ca ca,
uint16_t session_number);
extern int en50221_app_ca_info_enq(struct en50221_app_ca *ca,
uint16_t session_number);
/**
* Send a ca_pmt structure to the CAM.
@ -179,10 +184,10 @@ extern int en50221_app_ca_info_enq(en50221_app_ca ca,
* @param ca_pmt_length Length of ca_pmt structure in bytes.
* @return 0 on success, -1 on failure.
*/
extern int en50221_app_ca_pmt(en50221_app_ca ca,
uint16_t session_number,
uint8_t *ca_pmt,
uint32_t ca_pmt_length);
extern int en50221_app_ca_pmt(struct en50221_app_ca *ca,
uint16_t session_number,
uint8_t * ca_pmt,
uint32_t ca_pmt_length);
/**
* Transform a libucsi PMT into a binary structure for sending to a CAM.
@ -197,10 +202,11 @@ extern int en50221_app_ca_pmt(en50221_app_ca ca,
* @return Number of bytes used, or -1 on error.
*/
extern int en50221_ca_format_pmt(struct mpeg_pmt_section *pmt,
uint8_t *data,
uint32_t data_length,
int move_ca_descriptors,
uint8_t ca_pmt_list_management, uint8_t ca_pmt_cmd_id);
uint8_t * data,
uint32_t data_length,
int move_ca_descriptors,
uint8_t ca_pmt_list_management,
uint8_t ca_pmt_cmd_id);
/**
* Pass data received for this resource into it for parsing.
@ -213,38 +219,42 @@ extern int en50221_ca_format_pmt(struct mpeg_pmt_section *pmt,
* @param data_length Length of data in bytes.
* @return 0 on success, -1 on failure.
*/
extern int en50221_app_ca_message(en50221_app_ca ca,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data, uint32_t data_length);
extern int en50221_app_ca_message(struct en50221_app_ca *ca,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data,
uint32_t data_length);
static inline struct en50221_app_pmt_stream *
en50221_app_pmt_reply_streams_first(struct en50221_app_pmt_reply *reply, uint32_t reply_size)
en50221_app_pmt_reply_streams_first(struct en50221_app_pmt_reply *reply,
uint32_t reply_size)
{
uint32_t pos = sizeof(struct en50221_app_pmt_reply);
uint32_t pos = sizeof(struct en50221_app_pmt_reply);
if (pos >= reply_size)
return NULL;
if (pos >= reply_size)
return NULL;
return (struct en50221_app_pmt_stream *)((uint8_t *)reply+ pos);
return (struct en50221_app_pmt_stream *) ((uint8_t *) reply + pos);
}
static inline struct en50221_app_pmt_stream *
en50221_app_pmt_reply_streams_next(struct en50221_app_pmt_reply * reply,
struct en50221_app_pmt_stream * pos,
uint32_t reply_size)
en50221_app_pmt_reply_streams_next(struct en50221_app_pmt_reply *reply,
struct en50221_app_pmt_stream *pos,
uint32_t reply_size)
{
uint8_t *end = (uint8_t*) reply + reply_size;
uint8_t *next = (uint8_t *) pos + sizeof(struct en50221_app_pmt_stream);
uint8_t *end = (uint8_t *) reply + reply_size;
uint8_t *next =
(uint8_t *) pos +
sizeof(struct en50221_app_pmt_stream);
if (next >= end)
return NULL;
if (next >= end)
return NULL;
return (struct en50221_app_pmt_stream *) next;
return (struct en50221_app_pmt_stream *) next;
}
#ifdef __cplusplus

@ -2,7 +2,7 @@
en50221 encoder An implementation for libdvb
an implementation for the en50221 transport layer
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
@ -18,7 +18,7 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
@ -29,108 +29,109 @@
#include "en50221_app_tags.h"
#include "asn_1.h"
struct en50221_app_datetime_private {
struct en50221_app_send_functions *funcs;
struct en50221_app_datetime {
struct en50221_app_send_functions *funcs;
en50221_app_datetime_enquiry_callback callback;
void *callback_arg;
en50221_app_datetime_enquiry_callback callback;
void *callback_arg;
pthread_mutex_t lock;
pthread_mutex_t lock;
};
static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length);
static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime *datetime,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data,
uint32_t data_length);
en50221_app_datetime en50221_app_datetime_create(struct en50221_app_send_functions *funcs)
struct en50221_app_datetime *en50221_app_datetime_create(struct en50221_app_send_functions *funcs)
{
struct en50221_app_datetime_private *private = NULL;
struct en50221_app_datetime *datetime = NULL;
// create structure and set it up
private = malloc(sizeof(struct en50221_app_datetime_private));
if (private == NULL) {
return NULL;
}
private->funcs = funcs;
private->callback = NULL;
// create structure and set it up
datetime = malloc(sizeof(struct en50221_app_datetime));
if (datetime == NULL) {
return NULL;
}
datetime->funcs = funcs;
datetime->callback = NULL;
pthread_mutex_init(&private->lock, NULL);
pthread_mutex_init(&datetime->lock, NULL);
// done
return private;
// done
return datetime;
}
void en50221_app_datetime_destroy(en50221_app_datetime datetime)
void en50221_app_datetime_destroy(struct en50221_app_datetime *datetime)
{
struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime;
pthread_mutex_destroy(&private->lock);
free(private);
pthread_mutex_destroy(&datetime->lock);
free(datetime);
}
void en50221_app_datetime_register_enquiry_callback(en50221_app_datetime datetime,
en50221_app_datetime_enquiry_callback callback, void *arg)
void en50221_app_datetime_register_enquiry_callback(struct en50221_app_datetime *datetime,
en50221_app_datetime_enquiry_callback callback,
void *arg)
{
struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime;
pthread_mutex_lock(&private->lock);
private->callback = callback;
private->callback_arg = arg;
pthread_mutex_unlock(&private->lock);
pthread_mutex_lock(&datetime->lock);
datetime->callback = callback;
datetime->callback_arg = arg;
pthread_mutex_unlock(&datetime->lock);
}
int en50221_app_datetime_send(en50221_app_datetime datetime,
uint16_t session_number,
time_t utc_time,
int time_offset)
int en50221_app_datetime_send(struct en50221_app_datetime *datetime,
uint16_t session_number,
time_t utc_time, int time_offset)
{
struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime;
uint8_t data[11];
int data_length;
data[0] = (TAG_DATE_TIME >> 16) & 0xFF;
data[1] = (TAG_DATE_TIME >> 8) & 0xFF;
data[2] = TAG_DATE_TIME & 0xFF;
if (time_offset != -1) {
data[3] = 7;
unixtime_to_dvbdate(utc_time, data+4);
data[9] = time_offset >> 8;
data[10] = time_offset;
data_length = 11;
} else {
data[3] = 5;
unixtime_to_dvbdate(utc_time, data+4);
data_length = 9;
}
return private->funcs->send_data(private->funcs->arg, session_number, data, data_length);
uint8_t data[11];
int data_length;
data[0] = (TAG_DATE_TIME >> 16) & 0xFF;
data[1] = (TAG_DATE_TIME >> 8) & 0xFF;
data[2] = TAG_DATE_TIME & 0xFF;
if (time_offset != -1) {
data[3] = 7;
unixtime_to_dvbdate(utc_time, data + 4);
data[9] = time_offset >> 8;
data[10] = time_offset;
data_length = 11;
} else {
data[3] = 5;
unixtime_to_dvbdate(utc_time, data + 4);
data_length = 9;
}
return datetime->funcs->send_data(datetime->funcs->arg,
session_number, data,
data_length);
}
int en50221_app_datetime_message(en50221_app_datetime datetime,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data, uint32_t data_length)
int en50221_app_datetime_message(struct en50221_app_datetime *datetime,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t * data, uint32_t data_length)
{
struct en50221_app_datetime_private *private = (struct en50221_app_datetime_private *) datetime;
(void) resource_id;
// get the tag
if (data_length < 3) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
switch(tag)
{
case TAG_DATE_TIME_ENQUIRY:
return en50221_app_datetime_parse_enquiry(private, slot_id, session_number, data+3, data_length-3);
}
print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
return -1;
(void) resource_id;
// get the tag
if (data_length < 3) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
switch (tag) {
case TAG_DATE_TIME_ENQUIRY:
return en50221_app_datetime_parse_enquiry(datetime,
slot_id,
session_number,
data + 3,
data_length - 3);
}
print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
return -1;
}
@ -142,28 +143,31 @@ int en50221_app_datetime_message(en50221_app_datetime datetime,
static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length)
static int en50221_app_datetime_parse_enquiry(struct en50221_app_datetime *datetime,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data,
uint32_t data_length)
{
// validate data
if (data_length != 2) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
if (data[0] != 1) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint8_t response_interval = data[1];
// tell the app
pthread_mutex_lock(&private->lock);
en50221_app_datetime_enquiry_callback cb = private->callback;
void *cb_arg = private->callback_arg;
pthread_mutex_unlock(&private->lock);
if (cb) {
return cb(cb_arg, slot_id, session_number, response_interval);
}
return 0;
// validate data
if (data_length != 2) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
if (data[0] != 1) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint8_t response_interval = data[1];
// tell the app
pthread_mutex_lock(&datetime->lock);
en50221_app_datetime_enquiry_callback cb = datetime->callback;
void *cb_arg = datetime->callback_arg;
pthread_mutex_unlock(&datetime->lock);
if (cb) {
return cb(cb_arg, slot_id, session_number,
response_interval);
}
return 0;
}

@ -2,7 +2,7 @@
en50221 encoder An implementation for libdvb
an implementation for the en50221 transport layer
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
@ -18,15 +18,14 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __EN50221_APPLICATION_DATETIME_H__
#define __EN50221_APPLICATION_DATETIME_H__
#ifdef __cplusplus
extern "C"
{
extern "C" {
#endif
#include <stdlib.h>
@ -44,13 +43,15 @@ extern "C"
* @param response_interval Response interval requested by CAM.
* @return 0 on success, -1 on failure.
*/
typedef int (*en50221_app_datetime_enquiry_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
uint8_t response_interval);
typedef int (*en50221_app_datetime_enquiry_callback) (void *arg,
uint8_t slot_id,
uint16_t session_number,
uint8_t response_interval);
/**
* Opaque type representing a datetime resource.
*/
typedef void *en50221_app_datetime;
struct en50221_app_datetime;
/**
* Create an instance of the datetime resource.
@ -58,14 +59,15 @@ typedef void *en50221_app_datetime;
* @param funcs Send functions to use.
* @return Instance, or NULL on failure.
*/
extern en50221_app_datetime en50221_app_datetime_create(struct en50221_app_send_functions *funcs);
extern struct en50221_app_datetime
*en50221_app_datetime_create(struct en50221_app_send_functions *funcs);
/**
* Destroy an instance of the datetime resource.
*
* @param datetime Instance to destroy.
*/
extern void en50221_app_datetime_destroy(en50221_app_datetime datetime);
extern void en50221_app_datetime_destroy(struct en50221_app_datetime *datetime);
/**
* Register the callback for when we receive a enquiry request.
@ -74,8 +76,9 @@ extern void en50221_app_datetime_destroy(en50221_app_datetime datetime);
* @param callback The callback. Set to NULL to remove the callback completely.
* @param arg Private data passed as arg0 of the callback.
*/
extern void en50221_app_datetime_register_enquiry_callback(en50221_app_datetime datetime,
en50221_app_datetime_enquiry_callback callback, void *arg);
extern void en50221_app_datetime_register_enquiry_callback(struct en50221_app_datetime *datetime,
en50221_app_datetime_enquiry_callback callback,
void *arg);
/**
* Send the time to the CAM.
@ -87,10 +90,10 @@ extern void en50221_app_datetime_register_enquiry_callback(en50221_app_datetime
* UTC and local time in minutes.
* @return 0 on success, -1 on failure.
*/
extern int en50221_app_datetime_send(en50221_app_datetime datetime,
uint16_t session_number,
time_t utc_time,
int time_offset);
extern int en50221_app_datetime_send(struct en50221_app_datetime *datetime,
uint16_t session_number,
time_t utc_time,
int time_offset);
/**
* Pass data received for this resource into it for parsing.
@ -103,14 +106,14 @@ extern int en50221_app_datetime_send(en50221_app_datetime datetime,
* @param data_length Length of data in bytes.
* @return 0 on success, -1 on failure.
*/
extern int en50221_app_datetime_message(en50221_app_datetime datetime,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data, uint32_t data_length);
extern int en50221_app_datetime_message(struct en50221_app_datetime *datetime,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data,
uint32_t data_length);
#ifdef __cplusplus
}
#endif
#endif

@ -2,7 +2,7 @@
en50221 encoder An implementation for libdvb
an implementation for the en50221 transport layer
Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
Copyright (C) 2004, 2005 Manu Abraham <abraham.manu@gmail.com>
Copyright (C) 2005 Julian Scheel (julian at jusst dot de)
Copyright (C) 2006 Andrew de Quincey (adq_dvb@lidskialf.net)
@ -18,7 +18,7 @@
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <string.h>
@ -28,137 +28,144 @@
#include "en50221_app_tags.h"
#include "asn_1.h"
struct en50221_app_dvb_private {
struct en50221_app_send_functions *funcs;
struct en50221_app_dvb {
struct en50221_app_send_functions *funcs;
en50221_app_dvb_tune_callback tune_callback;
void *tune_callback_arg;
en50221_app_dvb_tune_callback tune_callback;
void *tune_callback_arg;
en50221_app_dvb_replace_callback replace_callback;
void *replace_callback_arg;
en50221_app_dvb_replace_callback replace_callback;
void *replace_callback_arg;
en50221_app_dvb_clear_replace_callback clear_replace_callback;
void *clear_replace_callback_arg;
en50221_app_dvb_clear_replace_callback clear_replace_callback;
void *clear_replace_callback_arg;
pthread_mutex_t lock;
pthread_mutex_t lock;
};
static int en50221_app_dvb_parse_tune(struct en50221_app_dvb_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length);
static int en50221_app_dvb_parse_tune(struct en50221_app_dvb *dvb,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data,
uint32_t data_length);
static int en50221_app_dvb_parse_replace(struct en50221_app_dvb_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length);
static int en50221_app_dvb_parse_replace(struct en50221_app_dvb *dvb,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data,
uint32_t data_length);
static int en50221_app_dvb_parse_clear_replace(struct en50221_app_dvb_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length);
static int en50221_app_dvb_parse_clear_replace(struct en50221_app_dvb *dvb,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data,
uint32_t data_length);
en50221_app_dvb en50221_app_dvb_create(struct en50221_app_send_functions *funcs)
struct en50221_app_dvb *en50221_app_dvb_create(struct en50221_app_send_functions *funcs)
{
struct en50221_app_dvb_private *private = NULL;
// create structure and set it up
private = malloc(sizeof(struct en50221_app_dvb_private));
if (private == NULL) {
return NULL;
}
private->funcs = funcs;
private->tune_callback = NULL;
private->replace_callback = NULL;
private->clear_replace_callback = NULL;
pthread_mutex_init(&private->lock, NULL);
// done
return private;
struct en50221_app_dvb *dvb = NULL;
// create structure and set it up
dvb = malloc(sizeof(struct en50221_app_dvb));
if (dvb == NULL) {
return NULL;
}
dvb->funcs = funcs;
dvb->tune_callback = NULL;
dvb->replace_callback = NULL;
dvb->clear_replace_callback = NULL;
pthread_mutex_init(&dvb->lock, NULL);
// done
return dvb;
}
void en50221_app_dvb_destroy(en50221_app_dvb dvb)
void en50221_app_dvb_destroy(struct en50221_app_dvb *dvb)
{
struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
pthread_mutex_destroy(&private->lock);
free(private);
pthread_mutex_destroy(&dvb->lock);
free(dvb);
}
void en50221_app_dvb_register_tune_callback(en50221_app_dvb dvb,
en50221_app_dvb_tune_callback callback, void *arg)
void en50221_app_dvb_register_tune_callback(struct en50221_app_dvb *dvb,
en50221_app_dvb_tune_callback callback,
void *arg)
{
struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
pthread_mutex_lock(&private->lock);
private->tune_callback = callback;
private->tune_callback_arg = arg;
pthread_mutex_unlock(&private->lock);
pthread_mutex_lock(&dvb->lock);
dvb->tune_callback = callback;
dvb->tune_callback_arg = arg;
pthread_mutex_unlock(&dvb->lock);
}
void en50221_app_dvb_register_replace_callback(en50221_app_dvb dvb,
en50221_app_dvb_replace_callback callback, void *arg)
void en50221_app_dvb_register_replace_callback(struct en50221_app_dvb *dvb,
en50221_app_dvb_replace_callback callback,
void *arg)
{
struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
pthread_mutex_lock(&private->lock);
private->replace_callback = callback;
private->replace_callback_arg = arg;
pthread_mutex_unlock(&private->lock);
pthread_mutex_lock(&dvb->lock);
dvb->replace_callback = callback;
dvb->replace_callback_arg = arg;
pthread_mutex_unlock(&dvb->lock);
}
void en50221_app_dvb_register_clear_replace_callback(en50221_app_dvb dvb,
en50221_app_dvb_clear_replace_callback callback, void *arg)
void en50221_app_dvb_register_clear_replace_callback(struct en50221_app_dvb *dvb,
en50221_app_dvb_clear_replace_callback callback,
void *arg)
{
struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
pthread_mutex_lock(&private->lock);
private->clear_replace_callback = callback;
private->clear_replace_callback_arg = arg;
pthread_mutex_unlock(&private->lock);
pthread_mutex_lock(&dvb->lock);
dvb->clear_replace_callback = callback;
dvb->clear_replace_callback_arg = arg;
pthread_mutex_unlock(&dvb->lock);
}
int en50221_app_dvb_ask_release(en50221_app_dvb dvb, uint16_t session_number)
int en50221_app_dvb_ask_release(struct en50221_app_dvb *dvb,
uint16_t session_number)
{
struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
uint8_t data[4];
uint8_t data[4];
data[0] = (TAG_ASK_RELEASE >> 16) & 0xFF;
data[1] = (TAG_ASK_RELEASE >> 8) & 0xFF;
data[2] = TAG_ASK_RELEASE & 0xFF;
data[3] = 0;
data[0] = (TAG_ASK_RELEASE >> 16) & 0xFF;
data[1] = (TAG_ASK_RELEASE >> 8) & 0xFF;
data[2] = TAG_ASK_RELEASE & 0xFF;
data[3] = 0;
return private->funcs->send_data(private->funcs->arg, session_number, data, 4);
return dvb->funcs->send_data(dvb->funcs->arg, session_number, data, 4);
}
int en50221_app_dvb_message(en50221_app_dvb dvb,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t *data, uint32_t data_length)
int en50221_app_dvb_message(struct en50221_app_dvb *dvb,
uint8_t slot_id,
uint16_t session_number,
uint32_t resource_id,
uint8_t * data, uint32_t data_length)
{
struct en50221_app_dvb_private *private = (struct en50221_app_dvb_private *) dvb;
(void) resource_id;
// get the tag
if (data_length < 3) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
switch(tag)
{
case TAG_TUNE:
return en50221_app_dvb_parse_tune(private, slot_id, session_number, data+3, data_length-3);
case TAG_REPLACE:
return en50221_app_dvb_parse_replace(private, slot_id, session_number, data+3, data_length-3);
case TAG_CLEAR_REPLACE:
return en50221_app_dvb_parse_clear_replace(private, slot_id, session_number, data+3, data_length-3);
}
print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
return -1;
(void) resource_id;
// get the tag
if (data_length < 3) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint32_t tag = (data[0] << 16) | (data[1] << 8) | data[2];
switch (tag) {
case TAG_TUNE:
return en50221_app_dvb_parse_tune(dvb, slot_id,
session_number, data + 3,
data_length - 3);
case TAG_REPLACE:
return en50221_app_dvb_parse_replace(dvb, slot_id,
session_number,
data + 3,
data_length - 3);
case TAG_CLEAR_REPLACE:
return en50221_app_dvb_parse_clear_replace(dvb, slot_id,
session_number,
data + 3,
data_length - 3);
}
print(LOG_LEVEL, ERROR, 1, "Received unexpected tag %x\n", tag);
return -1;
}
@ -170,94 +177,106 @@ int en50221_app_dvb_message(en50221_app_dvb dvb,
static int en50221_app_dvb_parse_tune(struct en50221_app_dvb_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length)
static int en50221_app_dvb_parse_tune(struct en50221_app_dvb *dvb,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data, uint32_t data_length)
{
// validate data
if (data_length < 9) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
if (data[0] != 8) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint8_t *tune_data = data+1;
// parse it
uint16_t network_id = (tune_data[0] << 8) | tune_data[1];
uint16_t original_network_id = (tune_data[2] << 8) | tune_data[3];
uint16_t transport_stream_id = (tune_data[4] << 8) | tune_data[5];
uint16_t service_id = (tune_data[6] << 8) | tune_data[7];
// tell the app
pthread_mutex_lock(&private->lock);
en50221_app_dvb_tune_callback cb = private->tune_callback;
void *cb_arg = private->tune_callback_arg;
pthread_mutex_unlock(&private->lock);
if (cb) {
return cb(cb_arg, slot_id, session_number, network_id, original_network_id, transport_stream_id, service_id);
}
return 0;
// validate data
if (data_length < 9) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
if (data[0] != 8) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint8_t *tune_data = data + 1;
// parse it
uint16_t network_id = (tune_data[0] << 8) | tune_data[1];
uint16_t original_network_id = (tune_data[2] << 8) | tune_data[3];
uint16_t transport_stream_id = (tune_data[4] << 8) | tune_data[5];
uint16_t service_id = (tune_data[6] << 8) | tune_data[7];
// tell the app
pthread_mutex_lock(&dvb->lock);
en50221_app_dvb_tune_callback cb = dvb->tune_callback;
void *cb_arg = dvb->tune_callback_arg;
pthread_mutex_unlock(&dvb->lock);
if (cb) {
return cb(cb_arg, slot_id, session_number, network_id,
original_network_id, transport_stream_id,
service_id);
}
return 0;
}
static int en50221_app_dvb_parse_replace(struct en50221_app_dvb_private *private,
uint8_t slot_id, uint16_t session_number,
uint8_t *data, uint32_t data_length)
static int en50221_app_dvb_parse_replace(struct en50221_app_dvb *dvb,
uint8_t slot_id,
uint16_t session_number,
uint8_t * data,
uint32_t data_length)
{
// validate data
if (data_length < 6) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
if (data[0] != 5) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint8_t *replace_data = data+1;
// parse it
uint8_t replacement_ref = replace_data[0];
uint16_t replace_pid = ((replace_data[1] & 0x1f)<<8) | replace_data[2];
uint16_t replacement_pid = ((replace_data[3] & 0x1f)<<8) | replace_data[4];
// tell the app
pthread_mutex_lock(&private->lock);
en50221_app_dvb_replace_callback cb = private->replace_callback;
void *cb_arg = private->replace_callback_arg;
pthread_mutex_unlock(&private->lock);
if (cb) {
return cb(cb_arg, slot_id, session_number, replacement_ref, replace_pid, replacement_pid);
}
return 0;
// validate data
if (data_length < 6) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
if (data[0] != 5) {
print(LOG_LEVEL, ERROR, 1, "Received short data\n");
return -1;
}
uint8_t *replace_data = data + 1;
// parse it
uint8_t replacement_ref = replace_data[0];
uint16_t replace_pid =
((replace_data[1] & 0x1f) << 8) | replace_data[2];
uint16_t replacement_pid =
((replace_data[3] & 0x1f) << 8) | replace_data[4];
// tell the app
pthread_mutex_lock(&dvb->lock);
en50221_app_dvb_replace_callback cb = dvb->replace_callback;
void *cb_arg = dvb->replace_callback_arg;
pthread_mutex_unlock(&dvb->lock);
if (cb) {
return cb(cb_arg, slot_id, session_number, replacement_ref,
replace_pid, replacement_pid);
}
return 0;
}
<