Commit fb8c1310 authored by Damien Lucas's avatar Damien Lucas

. dvbreader.cpp: cosmetic changes

. asiinput* asireader*: add a very basic asiinput and reader to use with
    Linear Systems Ltd.'s DVB Master driver. Still a lot of work and tests
    to do. I did not perform yet any compatibility tests with other
    transmitters.
parent 4636637e
......@@ -111,6 +111,16 @@ TCPREADER_CCFLAGS = @TCPREADER_CCFLAGS@
TCPREADER_DCFLAGS = @TCPREADER_DCFLAGS@
TCPREADER_LCFLAGS = @TCPREADER_LCFLAGS@
ASIINPUT_LIB = @ASIINPUT_LIB@
ASIINPUT_CCFLAGS = @ASIINPUT_CCFLAGS@
ASIINPUT_DCFLAGS = @ASIINPUT_DCFLAGS@
ASIINPUT_LCFLAGS = @ASIINPUT_LCFLAGS@
ASIREADER_LIB = @ASIREADER_LIB@
ASIREADER_CCFLAGS = @ASIREADER_CCFLAGS@
ASIREADER_DCFLAGS = @ASIREADER_DCFLAGS@
ASIREADER_LCFLAGS = @ASIREADER_LCFLAGS@
BUILTINS_LIB = $(patsubst %,$$%_LIB,$(shell echo ${BUILTINS} | tr '[a-z]' '[A-Z]'))
VLS_LIB += $(BUILTINS_LIB)
......
......@@ -436,6 +436,34 @@ then
fi
fi
dnl
dnl ASI module
dnl
AC_ARG_ENABLE(asi,
AC_HELP_STRING(--enable-asi, ASI support (default disabled)))
AC_ARG_WITH(asi,
AC_HELP_STRING(--with-asi=[PATH], path to ASI header files))
if test x$enable_asi = xyes
then
dnl Test for asi.h
AC_MSG_CHECKING(for ASI headers in ${with_asi})
if test "x$with_asi" != x
then
test_CFLAGS="-I${with_asi}"
fi
save_CPPFLAGS="${CPPFLAGS}"
CPPFLAGS="${save_CPPFLAGS} ${test_CFLAGS}"
AC_CHECK_HEADERS([asi.h],
[ASIINPUT_CCFLAGS="${ASIINPUT_CCFLAGS} ${test_CFLAGS}"
ASIREADER_CCFLAGS="${ASIREADER_CCFLAGS} ${test_CFLAGS}"],
[AC_MSG_ERROR([Could not find ASI headers])])
CPPFLAGS="${save_CPPFLAGS}"
dnl No test for lib.
PLUGINS="${PLUGINS} asiinput asireader"
fi
dnl
dnl Main sources checks
dnl
......@@ -560,6 +588,16 @@ AC_SUBST(TCPREADER_CCFLAGS)
AC_SUBST(TCPREADER_DCFLAGS)
AC_SUBST(TCPREADER_LCFLAGS)
AC_SUBST(ASIINPUT_LIB)
AC_SUBST(ASIINPUT_CCFLAGS)
AC_SUBST(ASIINPUT_DCFLAGS)
AC_SUBST(ASIINPUT_LCFLAGS)
AC_SUBST(ASIREADER_LIB)
AC_SUBST(ASIREADER_CCFLAGS)
AC_SUBST(ASIREADER_DCFLAGS)
AC_SUBST(ASIREADER_LCFLAGS)
AC_SUBST(MANAGER_EXTRA_FLAG)
AC_SUBST(VLS_LCFLAGS)
AC_SUBST(VLS_LIB)
......
################################################################################
# "tcp" input Makefile
#-------------------------------------------------------------------------------
# (c)1999-2003 VideoLAN
# $Id: Makefile,v 1.1 2003/08/31 11:46:16 nitrox Exp $
################################################################################
################################################################################
# Common options
################################################################################
ifeq ($(shell [ ! -r ../../../Makefile.opts ] && echo 1),)
include ../../../Makefile.opts
endif
################################################################################
# Files description
################################################################################
#
# Input name
#
MODULE=asiinput
#
# Source files
#
MODULE_SRC=asiinput.cpp \
MODULE_LIB+=$(ASIINPUT_LIB)
MODULE_DCFLAGS+=$(ASIINPUT_DCFLAGS)
MODULE_LCFLAGS+=$(ASIINPUT_LCFLAGS)
MODULE_CCFLAGS+=$(ASIINPUT_CCFLAGS)
################################################################################
# Makefile skeleton
################################################################################
include ../../../Makefile.module
################################################################################
# Notes
################################################################################
# Look at the Makefile.module file for more information.
/*******************************************************************************
* asiinput.cpp: Input for ASI boards
*-------------------------------------------------------------------------------
* (c)2003 Anevia
* $Id: asiinput.cpp,v 1.1 2003/08/31 11:46:16 nitrox Exp $
*
* Authors: Damien Lucas <damien.lucas@anevia.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 the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*----------------------------------------------------------------------------
* This input is for work with an ASI board.
* Thus it only contains the real-time device streaming functions
*******************************************************************************/
//------------------------------------------------------------------------------
// Preamble
//------------------------------------------------------------------------------
#include "../../core/defs.h"
#include "../../core/core.h"
#include <sys/sysctl.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "../../mpeg/mpeg.h"
#include "../../mpeg/ts.h"
#include "../../mpeg/rtp.h"
#include "../../server/program.h"
#include "../../server/buffer.h"
#include "../../server/output.h"
#include "../../server/channel.h"
#include "../../server/broadcast.h"
#include "../../server/request.h"
#include "../../server/input.h"
#include "../../server/tsstreamer.h"
#include "../../mpeg/reader.h"
#include "../../mpeg/trickplay.h"
#include "../../mpeg/converter.h"
#include <asi.h>
#include "asiinput.h"
//------------------------------------------------------------------------------
// Library declaration
//------------------------------------------------------------------------------
#ifdef __PLUGIN__
GENERATE_LIB_ARGS(C_AsiInputModule, handle);
#endif
//------------------------------------------------------------------------------
// Builtin declaration
//------------------------------------------------------------------------------
#ifdef __BUILTIN__
C_Module* NewBuiltin_asiinput(handle hLog)
{
return new C_AsiInputModule(hLog);
}
#endif
/*******************************************************************************
* C_AsiInput class
********************************************************************************
*
*******************************************************************************/
//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
C_AsiInput::C_AsiInput(C_Module* pModule, const C_String& strName)
: C_Input(pModule, strName)
{
m_hFd = 0;
}
//------------------------------------------------------------------------------
// Destructor
//------------------------------------------------------------------------------
C_AsiInput::~C_AsiInput()
{
}
//------------------------------------------------------------------------------
// Initialization
//------------------------------------------------------------------------------
void C_AsiInput::OnInit()
{
unsigned int iBufSize;
int iDeviceType;
int iMode;
int iInvSynchro;
int iDoubleSynchro;
C_Application* pApp = C_Application::GetApp();
ASSERT(pApp);
/* Retrieve configuration parameters */
C_String strInvSynchro = pApp->GetSetting(GetName() + ".synchro", "none");
if( strInvSynchro == "0x47" ) iInvSynchro = 0;
else if ( strInvSynchro == "0xb8" ) iInvSynchro = 1;
else iInvSynchro = -1;
C_String strDblSynchro = pApp->GetSetting(GetName() +
".doublesynchro", "none");
if ( strDblSynchro == "disable" ) iDoubleSynchro = 0;
else if ( strDblSynchro == "enable" ) iDoubleSynchro = 1;
else iDoubleSynchro = -1;
m_strDeviceName = pApp->GetSetting(GetName() + ".device", "/dev/asirx0");
int iPid = -1;
// Wow, so many stuffs to do here --nitrox
try
{
/* 1. Open the file */
OpenDevice();
/* 2. Get the receiver capabilities */
GetReceiverCapabilities();
/* 3. Get the sysctl key (device type) */
iDeviceType = GetDeviceType();
/* 4. Get the buffer size */
iBufSize = GetBufferSize(iDeviceType);
/* 5. Get the receiver operating mode */
iMode = GetReceiverOperatingMode(iDeviceType);
/* 6. Get the packet timestamp mode */
GetPacketTimestampMode(iDeviceType);
/* 7. Enable/Disable synchronisation on 0xb8 */
SetInvSynchro(iInvSynchro);
/* 8. Enable/Disable double packet synchronization */
SetDoubleSynchro(iDoubleSynchro);
/* 9. Set the PID counter */
SetPIDCounter(iPid, iMode);
}
catch(E_Exception e)
{
if(m_hFd>0) close(m_hFd);
throw E_Exception(GEN_ERR, e.Dump());
}
C_String* pStr = new C_String("asi");
m_vProgramNames.Add(pStr);
Log(m_hLog, LOG_NOTE, "Added program '" + *pStr+"'");
}
//------------------------------------------------------------------------------
// Destruction
//------------------------------------------------------------------------------
void C_AsiInput::OnDestroy()
{
return;
}
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
C_List<C_Program> C_AsiInput::OnGetAvailablePgrms()
{
C_List<C_Program> cPgrmList;
for(unsigned int ui = 0; ui < m_vProgramNames.Size(); ui++)
{
C_Program* pProgram = new C_Program(m_vProgramNames[ui]);
ASSERT(pProgram);
cPgrmList.PushEnd(pProgram);
}
return cPgrmList;
}
//------------------------------------------------------------------------------
// Start the reception of the given program
//------------------------------------------------------------------------------
void C_AsiInput::OnStartStreaming(C_Broadcast* pBroadcast)
{
C_String strReaderType = "asi";
// Only TS streams are sent through ASI interfaces.
C_String strConverterType = "ts2ts";
// You cannot control trickplay since ASI is a real-time device
C_String strTrickPlayType = "normal";
uint16_t uiSize;
// Create the netlist and the fifo
const C_Channel* pChannel = pBroadcast->GetChannel();
C_NetList* pTsProvider = new C_NetList(3*3*797);
uiSize = pTsProvider->Capacity() - pChannel->GetBuffCapacity()-2;
C_SyncFifo* pBuffer = new C_SyncFifo(uiSize);
// Create the reader
C_MpegReader* pReader;
C_MpegReaderModule* pReaderModule = (C_MpegReaderModule*)
C_Application::GetModuleManager()
->GetModule("mpegreader",
strReaderType);
if(pReaderModule)
{
pReader = pReaderModule->NewMpegReader(pBroadcast);
}
else
{
throw E_Exception(GEN_ERR, "Module mpegreader:" + strConverterType +
" not present");
}
// Create the converter
C_MpegConverter* pConverter;
C_MpegConverterModule* pConverterModule = (C_MpegConverterModule*)
C_Application::GetModuleManager()
->GetModule("mpegconverter",
strConverterType);
if(pConverterModule)
{
C_MpegConverterConfig cConfig;
cConfig.m_hLog = m_hLog;
cConfig.m_pBroadcast = pBroadcast;
cConfig.m_pReader = pReader;
cConfig.m_pTsProvider = pTsProvider;
cConfig.m_pEventHandler = m_pEventHandler;
pConverter = pConverterModule->NewMpegConverter(cConfig);
ASSERT(pConverter);
}
else
{
throw E_Exception(GEN_ERR, "Module mpegconverter:" +
strConverterType + " not present");
}
pReader->SetConverter(pConverter);
// Create the trickplay
C_TrickPlay* pTrickPlay;
C_TrickPlayModule* pTrickPlayModule = (C_TrickPlayModule*)
C_Application::GetModuleManager()
->GetModule("trickplay",
strTrickPlayType);
if (pTrickPlayModule)
{
C_TrickPlayConfig cTrickPlayConfig;
cTrickPlayConfig.m_hLog = m_hLog;
cTrickPlayConfig.m_pBroadcast = pBroadcast;
cTrickPlayConfig.m_pReader = pReader;
cTrickPlayConfig.m_pHandler = pBuffer;
cTrickPlayConfig.m_iInitFill = 0;
cTrickPlayConfig.m_pEventHandler = m_pEventHandler;
cTrickPlayConfig.m_pTsProvider = pTsProvider;
cTrickPlayConfig.m_pConverter = pConverter;
pTrickPlay = pTrickPlayModule->NewTrickPlay(cTrickPlayConfig);
ASSERT(pTrickPlay);
}
else
{
throw E_Exception(GEN_ERR,
"Module TrickPlay:" + strTrickPlayType +
" not present");
}
// Create the streamer
C_TsStreamer* pStreamer = new C_TsStreamer(m_hLog, pBroadcast,
pTsProvider, pBuffer,
m_pEventHandler, true, true);
ASSERT(pStreamer);
m_cTrickPlay.Add(pBroadcast, pTrickPlay);
m_cStreamers.Add(pBroadcast, pStreamer);
m_cConverters.Add(pBroadcast, pConverter);
try
{
pTrickPlay->Create();
pStreamer->Create();
}
catch(E_Exception e)
{
pStreamer->Stop();
pTrickPlay->Stop();
//Unregister the 2 thread and delete them
m_cTrickPlay.Delete(pBroadcast);
m_cStreamers.Delete(pBroadcast);
throw E_Exception(GEN_ERR, "unable to start streaming of program "+
pBroadcast->GetProgram()->GetName(), e);
}
return;
}
//------------------------------------------------------------------------------
// Resume the reception of the given program
//------------------------------------------------------------------------------
void C_AsiInput::OnResumeStreaming(C_Broadcast* pBroadcast)
{
throw E_Exception(GEN_ERR, "Resuming ASI program not available");
return;
}
//------------------------------------------------------------------------------
// Suspend the reception of the given program
//------------------------------------------------------------------------------
void C_AsiInput::OnSuspendStreaming(C_Broadcast* pBroadcast)
{
throw E_Exception(GEN_ERR, "Suspending ASI program not available");
return;
}
//------------------------------------------------------------------------------
// Forward the reception of the given program with specified speed
//------------------------------------------------------------------------------
void C_AsiInput::OnForwardStreaming(C_Broadcast* pBroadcast, int speed)
{
throw E_Exception(GEN_ERR, "Forwarding in ASI program not available");
return;
}
//------------------------------------------------------------------------------
// Rewind the reception of the given program with specified speed
//------------------------------------------------------------------------------
void C_AsiInput::OnRewindStreaming(C_Broadcast* pBroadcast, int speed)
{
throw E_Exception(GEN_ERR, "Rewinding in ASI program not available");
return;
}
//------------------------------------------------------------------------------
// Stop the reception of the given program
//------------------------------------------------------------------------------
void C_AsiInput::OnStopStreaming(C_Broadcast* pBroadcast)
{
ASSERT(pBroadcast);
// Find the reader and the streamer that receive the pgrm
C_TrickPlay* pTrickPlay = m_cTrickPlay.Remove(pBroadcast);
ASSERT(pTrickPlay);
C_TsStreamer* pStreamer = m_cStreamers.Remove(pBroadcast);
ASSERT(pStreamer);
C_MpegConverter* pConverter = m_cConverters.Remove(pBroadcast);
ASSERT(pConverter);
// Stop the threads
try
{
pStreamer->Stop();
pTrickPlay->Stop();
delete pTrickPlay;
delete pConverter;
delete pStreamer; // streamer MUST be deleted last
}
catch(E_Exception e)
{
throw E_Exception(GEN_ERR, "Unable to stop streaming of program "+
pBroadcast->GetProgram()->GetName(), e);
}
return;
}
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
void C_AsiInput::OnUpdateProgram(C_String strProgram,
C_String strFileName, C_String strType)
{
throw E_Exception(GEN_ERR, "Updating ASI programs not implemented");
}
//------------------------------------------------------------------------------
//
//------------------------------------------------------------------------------
void C_AsiInput::OnDeleteProgram(C_String strProgram)
{
throw E_Exception(GEN_ERR, "Deleting program not implemented");
}
//Local private functions
//TODO documentation about them !
void C_AsiInput::OpenDevice()
{
m_hFd = open (m_strDeviceName.GetString(), O_RDONLY | O_LARGEFILE, 0);
if ( m_hFd < 0 )
throw E_Exception(GEN_ERR, "Unable to open ASI device");
}
void C_AsiInput::GetReceiverCapabilities()
{
if (ioctl (m_hFd, ASI_IOC_RXGETCAP, &m_iCap) < 0)
{
throw E_Exception(GEN_ERR,
"Unable to get the ASI receiver capabilities");
}
}
int C_AsiInput::GetDeviceType()
{
struct stat sBuf;
memset(&sBuf, 0, sizeof(sBuf));
if (fstat (m_hFd, &sBuf) < 0)
{
throw E_Exception(GEN_ERR,
"Unable to get the file status for ASI receiver");
}
return 1 + (sBuf.st_rdev & 0x00ff);
}
unsigned int C_AsiInput::GetBufferSize(int iDeviceType)
{
unsigned int iBufSize;
int iName[4] = {CTL_DEV, DEV_ASI, iDeviceType, DEV_ASI_BUFSIZE};
unsigned int iLen = sizeof (iBufSize);
if (sysctl (iName, sizeof (iName) / sizeof (int), &iBufSize,
&iLen, NULL, 0) < 0)
{
throw E_Exception(GEN_ERR, "Unable to get the ASI receiver "
"buffer size");
}
return iBufSize;
}
int C_AsiInput::GetReceiverOperatingMode(int iDeviceType)
{
int iMode;
int iName[4] = {CTL_DEV, DEV_ASI, iDeviceType, DEV_ASI_MODE};
if (m_iCap & ASI_CAP_RX_SYNC)
{
iName[3] = DEV_ASI_MODE;
unsigned int iLen = sizeof (iMode);
if (sysctl (iName, sizeof (iName) / sizeof (int), &iMode, &iLen,
NULL, 0) < 0)
{
throw E_Exception(GEN_ERR, "Unable to get the ASI receiver "
"operating mode");
}
}
else
{
iMode = ASI_CTL_RX_MODE_RAW;
}
switch(iMode)
{
case ASI_CTL_RX_MODE_RAW:
LogDbg(m_hLog, "Receiving in raw mode.");
break;
case ASI_CTL_RX_MODE_188:
LogDbg(m_hLog, "Synchronizing on 188-byte packets.");
break;
case ASI_CTL_RX_MODE_204:
LogDbg(m_hLog, "Synchronizing on 204-byte packets.");
break;
case ASI_CTL_RX_MODE_AUTO:
LogDbg(m_hLog, "Synchronizing on detected packet size.");
break;
case ASI_CTL_RX_MODE_AUTOMAKE188:
LogDbg(m_hLog, "Synchronizing on 204-byte packets (stripping).");
break;
default:
Log(m_hLog, LOG_WARN, "Receiving in unknown mode.");
break;
}
return iMode;
}
int C_AsiInput::GetPacketTimestampMode(int iDeviceType)
{
int iTimeStamps;
int iName[]={CTL_DEV, DEV_ASI, iDeviceType, DEV_ASI_TIMESTAMPS};
if (m_iCap & ASI_CAP_RX_TIMESTAMPS)
{
unsigned int iLen = sizeof (iTimeStamps);
if (sysctl (iName, sizeof (iName) / sizeof (int),
&iTimeStamps, &iLen, NULL, 0) < 0)
{
throw E_Exception(GEN_ERR, "Unable to get the packet"
"timestamping mode");
}
}
else
{
iTimeStamps = 0;
}
if ( iTimeStamps == 1 )
LogDbg(m_hLog, "Appending an 8B timestamp to each packet");
else if ( iTimeStamps == 2 )
LogDbg(m_hLog, "Prepending an 8B timestamp to each packet");
return iTimeStamps;
}
void C_AsiInput::SetInvSynchro(int iInvSynchro)
{
if ( iInvSynchro < 0 ) return;
switch (iInvSynchro)
{
case 0:
LogDbg(m_hLog, "Synchronizing on 0x47 packets");
break;
case 1:
if (!(m_iCap & ASI_CAP_RX_INVSYNC))
{
throw E_Exception(GEN_ERR, "Synchronisation on 0xb8 not "
"supported");
}
LogDbg(m_hLog, "Synchronizing on both 0xb8 and 0x47 packets");
break;
default:
throw E_Exception(GEN_ERR, "Invalid 0xb8 packet synchro mode");
break;
}
if (ioctl (m_hFd, ASI_IOC_RXSETINVSYNC, &iInvSynchro) < 0)
{
throw E_Exception(GEN_ERR, "Unable to set the 0xb8 packet synchro"
" mode");
}
return;
}
void C_AsiInput::SetDoubleSynchro(int iDoubleSynchro)
{
if ( iDoubleSynchro < 0 ) return;
switch(iDoubleSynchro)
{
case 0:
LogDbg(m_hLog, "Disabling double packet synchronization.");
break;
case 1:
if (!(m_iCap & ASI_CAP_RX_DSYNC))
{
throw E_Exception(GEN_ERR, "Double packet synchronization "
"not supported");
}
else
{
LogDbg(m_hLog, "Enabling double packet synchronization.");
}
break;
default:
throw E_Exception(GEN_ERR, "Invalid double packet synchronization"
" mode");
break;
}
if (ioctl (m_hFd, ASI_IOC_RXSETDSYNC, &iDoubleSynchro) < 0)
{
throw E_Exception(GEN_ERR, "Unable to set the double packet "
"synchronization mode");
}
}
void C_AsiInput::SetPIDCounter(int iPid, int iMode)
{
if (iPid >= 0)
{
if ( iMode == ASI_CTL_RX_MODE_RAW )
{
throw E_Exception(GEN_ERR, "PID counter not supported in"
" raw mode");
}
if ( m_iCap & ASI_CAP_RX_PIDCOUNTER )
{
if ( ioctl (m_hFd, ASI_IOC_RXSETPID0, &iPid) < 0 )
{
throw E_Exception(GEN_ERR, "Unable to set the PID counter");
}
else
{
LogDbg(m_hLog, "Counting PID " + iPid);
}
}
else
{
throw E_Exception(GEN_ERR, "PID counter not supported");
}
}
else
{
LogDbg(m_hLog, "Ignoring the PID counter");
}
}
void C_AsiInput::SetBufferSize(int iDeviceType, int iBuffSize)
{
int iName[]={CTL_DEV, DEV_ASI, iDeviceType, DEV_ASI_BUFSIZE};
int iLen = sizeof (