/*
* Video On Demand Samples
*
* Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG
*
* 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, see .
*
* You may also obtain this software under a propriety license from Microchip.
* Please contact Microchip for further information.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include "Console.h"
#include "VodHandler.h"
#include "SourceFile.h"
#include "SourceFileConverted.h"
#include "AutoLock.h"
using namespace std;
#define MAX_IPC_PAYLOAD_LEN (65000)
#define VOD_VERSION_MAJOR ((uint8_t)3)
#define VOD_VERSION_MINOR ((uint8_t)0)
#define VOD_VERSION_BUGFIX ((uint8_t)4)
#define VOD_VERSION_BUILD ((uint8_t)0)
#define IPC_PORT_NUMBER_VOD (5544)
#define FBLOCK_VOD (17)
#define FUNC_VOD_SELECT_FILE (1)
#define FUNC_VOD_PLAYMODE (2)
#define FUNC_VOD_TIMEPOSITION (3)
#define FUNC_VOD_REPETITION (4)
#define FUNC_VOD_SERVERVERSION (5)
#define FUNC_VOD_MEDIAPID (6)
#define FUNC_VOD_FILE_LIST (7)
#define FUNC_VOD_NEW_INDEPEND_STREAM (8)
#define FUNC_VOD_FAKE_MODE (99)
#define IPC_PORT_NUMBER_NM (5533)
#define FBLOCK_NETWORK_MANAGER (10)
#define FUNC_NM_SERVERVERSION (1)
#define FUNC_NM_SUBSCRIBE_MCM (2)
#define FUNC_NM_UNSUBSCRIBE_MCM (3)
#define FUNC_NM_RECEIVED_MCM (4)
#define FUNC_NM_SEND_MCM_ADR (5)
#define FUNC_NM_SEND_MCM_DEV (6)
#define FUNC_NM_COUNTER_ROUTE (10)
#define FUNC_NM_CONNECTION_LIST (100)
static CVodHandler *s_mainClass = NULL;
CVodHandler::CVodHandler() : CThread( "CVodHandler", false ), valuesCleared( false ), statisticIsEnabled( false ),
infoContainer( NULL )
{
searchPath[0] = '.';
searchPath[0] = '\0';
pthread_mutex_init( &infoContainerMutex, NULL );
mostIpcVod = new CMostIpc( IPC_PORT_NUMBER_VOD, true );
vodSelectFile_Set = new CMsgFilter( FBLOCK_VOD, FUNC_VOD_SELECT_FILE,
CMostMsg::OP_SET, OnVodSelectFile_Set );
mostIpcVod->RegisterMessageHandler( vodSelectFile_Set );
vodPlayMode_Set = new CMsgFilter( FBLOCK_VOD, FUNC_VOD_PLAYMODE, CMostMsg::OP_SET,
OnVodPlayMode_Set );
mostIpcVod->RegisterMessageHandler( vodPlayMode_Set );
vodTimePostion_Set = new CMsgFilter( FBLOCK_VOD, FUNC_VOD_TIMEPOSITION,
CMostMsg::OP_SET, OnVodTimePosition_Set );
mostIpcVod->RegisterMessageHandler( vodTimePostion_Set );
vodRepetition_Set = new CMsgFilter( FBLOCK_VOD, FUNC_VOD_REPETITION,
CMostMsg::OP_SET, OnVodRepetition_Set );
mostIpcVod->RegisterMessageHandler( vodRepetition_Set );
vodServerVersion_Get = new CMsgFilter( FBLOCK_VOD, FUNC_VOD_SERVERVERSION,
CMostMsg::OP_GET, OnVodServerVersion_Get );
mostIpcVod->RegisterMessageHandler( vodServerVersion_Get );
vodMediaPid_Get = new CMsgFilter( FBLOCK_VOD, FUNC_VOD_MEDIAPID,
CMostMsg::OP_GET, OnVodMediaPid_Get );
mostIpcVod->RegisterMessageHandler( vodMediaPid_Get );
vodFileList_Get = new CMsgFilter( FBLOCK_VOD, FUNC_VOD_FILE_LIST,
CMostMsg::OP_GET, OnVodFileList_Get );
mostIpcVod->RegisterMessageHandler( vodFileList_Get );
vodIndependStream_SetGet = new CMsgFilter( FBLOCK_VOD, FUNC_VOD_NEW_INDEPEND_STREAM,
CMostMsg::OP_SETGET, OnVodIndependentStream_SetGet );
mostIpcVod->RegisterMessageHandler( vodIndependStream_SetGet );
vodFakeMode_Set = new CMsgFilter( FBLOCK_VOD, FUNC_VOD_FAKE_MODE,
CMostMsg::OP_SET, OnFakeMode_Set );
mostIpcVod->RegisterMessageHandler( vodFakeMode_Set );
mostIpcNm = new CMostIpc( 0, false );
nmServerVersion_Status = new CMsgFilter( FBLOCK_NETWORK_MANAGER, FUNC_NM_SERVERVERSION,
CMostMsg::OP_STATUS, OnNmServerVersion_Status );
mostIpcNm->RegisterMessageHandler( nmServerVersion_Status );
nmConnectionList_Status = new CMsgFilter( FBLOCK_NETWORK_MANAGER, FUNC_NM_CONNECTION_LIST,
CMostMsg::OP_STATUS, OnNmConnectionList_Status );
mostIpcNm->RegisterMessageHandler( nmConnectionList_Status );
RegisterBroadcastFiles( SelectFileType_Radio );
RegisterBroadcastFiles( SelectFileType_Navigation );
RegisterBroadcastFiles( SelectFileType_Cluster );
}
CVodHandler::~CVodHandler()
{
Stop();
if( NULL != mostIpcVod )
{
delete mostIpcVod;
mostIpcVod = NULL;
}
if( NULL != vodSelectFile_Set )
{
delete vodSelectFile_Set;
vodSelectFile_Set = NULL;
}
if( NULL != vodPlayMode_Set )
{
delete vodPlayMode_Set;
vodPlayMode_Set = NULL;
}
if( NULL != vodTimePostion_Set )
{
delete vodTimePostion_Set;
vodTimePostion_Set = NULL;
}
if( NULL != vodRepetition_Set )
{
delete vodRepetition_Set;
vodRepetition_Set = NULL;
}
if( NULL != vodServerVersion_Get )
{
delete vodServerVersion_Get;
vodServerVersion_Get = NULL;
}
if( NULL != vodMediaPid_Get )
{
delete vodMediaPid_Get;
vodMediaPid_Get = NULL;
}
if( NULL != vodFileList_Get )
{
delete vodFileList_Get;
vodFileList_Get = NULL;
}
if( NULL != vodFakeMode_Set )
{
delete vodFakeMode_Set;
vodFakeMode_Set = NULL;
}
if( NULL != mostIpcNm )
{
delete mostIpcNm;
mostIpcNm = NULL;
}
if( NULL != nmServerVersion_Status )
{
delete nmServerVersion_Status;
nmServerVersion_Status = NULL;
}
if( NULL != nmConnectionList_Status )
{
delete nmConnectionList_Status;
nmConnectionList_Status = NULL;
}
pthread_mutex_lock( &infoContainerMutex );
if ( NULL != infoContainer )
{
delete infoContainer;
infoContainer = NULL;
}
pthread_mutex_unlock( &infoContainerMutex );
broadcastFiles.RemoveAll( true );
allMultiplexer.RemoveAll(true);
ignoreCdevPatterns.RemoveAll( true );
}
bool CVodHandler::ExistsFile( const char *pFileName )
{
struct stat64 buffer;
return ( stat64( pFileName, &buffer ) == 0 );
}
CMultiplexer *CVodHandler::GetMultiplexer( const char* deviceName )
{
if ( NULL == deviceName )
return NULL;
for( uint32_t i = 0; i < allMultiplexer.Size(); i++ )
{
CMultiplexer *t = allMultiplexer[i];
if (NULL == t)
continue;
if ( 0 == strcmp( deviceName, t->GetDriverName() ) )
{
return t;
}
}
return NULL;
}
const char *CVodHandler::GetSubPath( SelectFileType_t fileType )
{
switch( fileType )
{
case SelectFileType_Video:
return "video";
case SelectFileType_Audio:
return "audio";
case SelectFileType_Radio:
return "radio";
case SelectFileType_Navigation:
return "navigation";
case SelectFileType_Cluster:
return "cluster";
default:
return "";
}
}
void CVodHandler::RegisterBroadcastFiles( SelectFileType_t fileType )
{
DIR *d;
struct dirent *dir;
char fullPath[200];
snprintf( fullPath, sizeof ( fullPath ), "%s/%s", searchPath, GetSubPath( fileType ) );
d = opendir( fullPath );
if( d )
{
while( ( dir = readdir( d ) ) != NULL )
{
if( DT_REG == dir->d_type || DT_LNK == dir->d_type )
{
BroadcastEntry_t *entry = ( BroadcastEntry_t * )malloc( sizeof ( BroadcastEntry_t ) );
if( NULL != entry )
{
snprintf( entry->fileName, sizeof ( entry->fileName ), "%s/%s", fullPath, dir->d_name );
char *ext = rindex(dir->d_name, '.');
if (ext && !strcasecmp(ext, ".ts"))
entry->sourceFile = new CSourceFile( entry->fileName, false );
else
entry->sourceFile = new CSourceFileConverted( entry->fileName, false );
broadcastFiles.PushBack( entry );
}
}
}
}
}
CMultiplexer *CVodHandler::GetMultiplexer( const uint8_t *mac )
{
volatile CAutoLock autoLock( &infoContainerMutex );
if( NULL == mac )
{
ConsolePrintf( PRIO_ERROR,
RED"GetMultiplexer was called with invalid parameters."RESETCOLOR"\n" );
return NULL;
}
if( NULL == infoContainer )
return NULL;
CMultiplexer *pMultiplexer = NULL;
char macAddr[20];
snprintf( ( char * )&macAddr, sizeof( macAddr ), "%02X-%02X-%02X-%02X-%02X-%02X", mac[0], mac[1], mac[2], mac[3],
mac[4], mac[5] );
uint32_t sinkCount = infoContainer->GetAllInfoAmount();
uint32_t mostInstance = 0xFFFFFFFF;
uint32_t mostConnectionLabel = 0xFFFFFFFF;
for (uint32_t i = 0; i < sinkCount; i++)
{
CConnectionInfo *con = infoContainer->GetInfo(i);
if ( ( NULL != con ) && ( NULL != con->macAddr ) && ( 0 == strcmp( con->macAddr->ToString(), macAddr ) ) )
{
pMultiplexer = GetMultiplexer( con->deviceName );
if ( NULL != pMultiplexer )
{
break;
}
else if ( ( EP_Isochron == con->dataType ) ||
( EP_Synchron == con->dataType && con->reservedBandwidth > 4 ) )
{
mostInstance = con->mostInstance;
mostConnectionLabel = con->mostConnectionLabel;
break;
}
}
}
if( NULL == pMultiplexer && ( 0xFFFFFFFF != mostInstance ) && ( 0xFFFFFFFF != mostConnectionLabel ) )
{
for (uint32_t i = 0; i < sinkCount; i++)
{
CConnectionInfo *con = infoContainer->GetInfo(i);
if ( NULL != con && con->mostInstance == mostInstance && con->mostConnectionLabel == mostConnectionLabel )
{
pMultiplexer = GetMultiplexer( con->deviceName );
if ( NULL != pMultiplexer )
break;
}
}
}
if( NULL == pMultiplexer )
{
ConsolePrintf( PRIO_ERROR, RED"CVodHandler::GetMultiplexer: Could not get Multiplexer for MAC: %s"RESETCOLOR"\n", macAddr );
}
return pMultiplexer;
}
void CVodHandler::OnVodSelectFile_Set( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg || pMsg->GetPayloadLen() < 8 )
{
ConsolePrintf( PRIO_ERROR, RED"OnVodSelectFile_Set parameters are invalid.\n"\
"This could happen, if the client uses an outdated version of the IPC,"\
" try to update your client."RESETCOLOR"\n" );
return;
}
uint8_t *mac = pMsg->GetPayload();
SelectFileType_t fileType = ( SelectFileType_t )pMsg->GetPayload()[6];
char *movieName = ( char * )&pMsg->GetPayload()[7];
ConsolePrintf( PRIO_HIGH, "OnVodSelectFile_Set IP=%s MAC=%02X-%02X-%02X-%02X-%02X-%02X type=%d video:'%s'\n",
pAddr->GetInetAddress(), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], fileType, movieName );
s_mainClass->StreamFile( mac, fileType, movieName );
}
void CVodHandler::OnVodPlayMode_Set( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg || pMsg->GetPayloadLen() < 7 )
{
ConsolePrintf( PRIO_ERROR, RED"OnVodPlayMode_Set parameters are invalid.\n"\
"This could happen, if the client uses an outdated version of the IPC,"\
" try to update your client."RESETCOLOR"\n" );
return;
}
uint8_t *mac = pMsg->GetPayload();
bool isPaused = 0 != pMsg->GetPayload()[6];
ConsolePrintf( PRIO_HIGH, "OnVodPlayMode_IP=%s MAC=%02X-%02X-%02X-%02X-%02X-%02X paused:'%d'\n",
pAddr->GetInetAddress(), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], isPaused );
s_mainClass->SetPause( mac, isPaused );
}
void CVodHandler::OnVodTimePosition_Set( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg || pMsg->GetPayloadLen() < 8 )
{
ConsolePrintf( PRIO_ERROR, RED"OnVodTimePosition_Set parameters are invalid.\n"\
"This could happen, if the client uses an outdated version of the IPC,"\
" try to update your client."RESETCOLOR"\n" );
return;
}
uint8_t *mac = pMsg->GetPayload();
uint16_t perMil = *( ( uint16_t * )&pMsg->GetPayload()[6] );
ConsolePrintf( PRIO_HIGH, "OnVodTimePosition_IP=%s MAC=%02X-%02X-%02X-%02X-%02X-%02X TimePos=%d/1000\n",
pAddr->GetInetAddress(), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], perMil );
s_mainClass->SetTimePos( mac, perMil );
}
void CVodHandler::OnVodRepetition_Set( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg || pMsg->GetPayloadLen() < 7 )
{
ConsolePrintf( PRIO_ERROR, RED"OnVodRepetition_Set parameters are invalid\n"\
"This could happen, if the client uses an outdated version of the IPC,"\
" try to update your client."RESETCOLOR"\n" );
return;
}
uint8_t *mac = pMsg->GetPayload();
bool isRepeated = 0 != pMsg->GetPayload()[6];
ConsolePrintf( PRIO_HIGH, "OnVodRepetition_IP=%s MAC=%02X-%02X-%02X-%02X-%02X-%02X repeated=%d\n",
pAddr->GetInetAddress(), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], isRepeated );
s_mainClass->SetRepetition( mac, isRepeated );
}
void CVodHandler::OnVodServerVersion_Get( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg || pMsg->GetPayloadLen() < 6 )
{
ConsolePrintf( PRIO_ERROR, RED"OnVodServerVersion_Get parameters are invalid.\n"\
"This could happen, if the client uses an outdated version of the IPC,"\
" try to update your client."RESETCOLOR"\n" );
return;
}
uint8_t *mac = pMsg->GetPayload();
ConsolePrintf( PRIO_HIGH,
GREEN"MOST-IPC Client connected (asked for server version). IP=%s MAC=%02X-%02X-%02X-%02X-%02X-%02X "RESETCOLOR
"\n", pAddr->GetInetAddress(), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
const uint8_t version[] =
{
VOD_VERSION_MAJOR, VOD_VERSION_MINOR,
VOD_VERSION_BUGFIX, VOD_VERSION_BUILD
};
CMostMsgTx *mostMsg = new CMostMsgTx( pAddr, //Addr
FBLOCK_VOD, // nFBlock
0, // nInst
FUNC_VOD_SERVERVERSION, // nFunc
CMostMsg::OP_STATUS, // nOpType
sizeof ( version ), //nPayloadLen
version, //Payload
500, //nTimeoutMs
NULL, //MessageSentCB
NULL ); //UserContext
s_mainClass->mostIpcVod->SendMsg( mostMsg );
mostMsg->RemoveReference();
}
void CVodHandler::OnVodMediaPid_Get( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg || pMsg->GetPayloadLen() < 6 )
{
ConsolePrintf( PRIO_ERROR, RED"OnVodMediaPid_Get parameters are invalid.\n"\
"This could happen, if the client uses an outdated version of the IPC,"\
" try to update your client."RESETCOLOR"\n" );
return;
}
uint8_t *mac = pMsg->GetPayload();
uint16_t videoPid = 0x100 + mac[5];
uint16_t audioPid = 0x200 + mac[5];
uint16_t pmtPid = 0x300 + mac[5];
uint8_t payload[6];
payload[0] = videoPid / 256;
payload[1] = videoPid % 256;
payload[2] = audioPid / 256;
payload[3] = audioPid % 256;
payload[4] = pmtPid / 256;
payload[5] = pmtPid % 256;
ConsolePrintf( PRIO_MEDIUM,
GREEN"MOST-IPC Client asked for PIDs. IP=%s MAC=%02X-%02X-%02X-%02X-%02X-%02X"\
" video-pid=%X audio-pid=%X pmt-pid=%X."RESETCOLOR"\n", pAddr->GetInetAddress(), mac[0], mac[1], mac[2],
mac[3], mac[4], mac[5], videoPid, audioPid, pmtPid );
CMostMsgTx *mostMsg = new CMostMsgTx( pAddr, //Addr
FBLOCK_VOD, // nFBlock
0, // nInst
FUNC_VOD_MEDIAPID, // nFunc
CMostMsg::OP_STATUS, // nOpType
sizeof ( payload ), //nPayloadLen
payload, //Payload
500, //nTimeoutMs
NULL, //MessageSentCB
NULL ); //UserContext
s_mainClass->mostIpcVod->SendMsg( mostMsg );
mostMsg->RemoveReference();
}
void CVodHandler::OnVodFileList_Get( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg || pMsg->GetPayloadLen() < 6 )
{
ConsolePrintf( PRIO_ERROR, RED"OnVodFileList_Get parameters are invalid.\n"\
"This could happen, if the client uses an outdated version of the IPC, "\
" try to update your client."RESETCOLOR"\n" );
return;
}
uint8_t *mac = pMsg->GetPayload();
SelectFileType_t fileType = ( SelectFileType_t )pMsg->GetPayload()[6];
ConsolePrintf( PRIO_MEDIUM,
GREEN"MOST-IPC Client asked for File List IP=%s MAC=%02X-%02X-%02X-%02X-%02X-%02X."RESETCOLOR"\n",
pAddr->GetInetAddress(), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
DIR *d;
struct dirent *dir;
char fullPath[200];
char *payload = ( char * )calloc( 1, MAX_IPC_PAYLOAD_LEN );
if( NULL == payload )
return;
snprintf( fullPath, sizeof( fullPath ), "%s/%s", s_mainClass->searchPath, GetSubPath( fileType ) );
d = opendir( fullPath );
ConsolePrintfStart( PRIO_LOW, "Available Files:\n" );
ConsolePrintfContinue( "File Name\n" );
ConsolePrintfContinue( "----------------------------------------\n" );
bool isFirst = true;
if( d )
{
while( ( dir = readdir( d ) ) != NULL )
{
char *ext = rindex(dir->d_name, '.');
if (ext && !strcasecmp(ext, ".ts"))
{
ConsolePrintfContinue( "%s\n", dir->d_name );
if( ( strlen( payload ) + strlen( dir->d_name ) + 1 ) < MAX_IPC_PAYLOAD_LEN )
{
if ( !isFirst )
strcat( payload, ":" );
isFirst = false;
strcat( payload, dir->d_name );
}
}
}
}
ConsolePrintfExit( "----------------------------------------\n" );
CMostMsgTx *mostMsg = new CMostMsgTx( pAddr, //Addr
FBLOCK_VOD, // nFBlock
0, // nInst
FUNC_VOD_FILE_LIST, // nFunc
CMostMsg::OP_STATUS, // nOpType
( strlen( payload ) + 1 ), //nPayloadLen
( uint8_t * )payload, //Payload
500, //nTimeoutMs
NULL, //MessageSentCB
NULL ); //UserContext
s_mainClass->mostIpcVod->SendMsg( mostMsg );
free( payload );
mostMsg->RemoveReference();
}
void CVodHandler::OnVodIndependentStream_SetGet( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg || pMsg->GetPayloadLen() < 2 )
{
ConsolePrintf( PRIO_ERROR, RED"OnVodIndependentStream_SetGet parameters are invalid.\n"RESETCOLOR"\n" );
return;
}
uint8_t *payload = pMsg->GetPayload();
uint8_t cdevIndex = payload[0];
uint8_t streamIndex = payload[1];
uint8_t responseOpType = CMostMsg::OP_ERROR;
uint8_t responsePayloadLength = 2;
uint8_t responsePayload[8];
responsePayload[0] = cdevIndex;
responsePayload[1] = streamIndex;
if (s_mainClass->CreateMacIndependentStream(cdevIndex, streamIndex, &responsePayload[2]))
{
responseOpType = CMostMsg::OP_STATUS;
responsePayloadLength = sizeof(responsePayload);
}
CMostMsgTx *mostMsg = new CMostMsgTx( pAddr, //Addr
FBLOCK_VOD, // nFBlock
0, // nInst
FUNC_VOD_NEW_INDEPEND_STREAM, // nFunc
responseOpType, // nOpType
responsePayloadLength, //nPayloadLen
responsePayload, //Payload
500, //nTimeoutMs
NULL, //MessageSentCB
NULL ); //UserContext
s_mainClass->mostIpcVod->SendMsg( mostMsg );
mostMsg->RemoveReference();
}
void CVodHandler::OnFakeMode_Set( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg || pMsg->GetPayloadLen() < 7 )
{
ConsolePrintf( PRIO_ERROR, RED"OnFakeMode_Set parameters are invalid.\n"\
"This could happen, if the client uses an outdated version of the IPC, "\
" try to update your client."RESETCOLOR"\n" );
return;
}
uint8_t *mac = pMsg->GetPayload();
uint8_t fakeSinks = pMsg->GetPayload()[6];
ConsolePrintf( PRIO_MEDIUM,
GREEN"MOST-IPC Client IP=%s MAC=%02X-%02X-%02X-%02X-%02X-%02X hast started"\
" %d fake sinks"RESETCOLOR"\n", pAddr->GetInetAddress(), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
fakeSinks );
s_mainClass->CreateSampleStreams( fakeSinks );
}
void CVodHandler::OnNmServerVersion_Status( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg )
{
ConsolePrintf( PRIO_ERROR, RED"OnNmServerVersion_Status parameters are invalid."RESETCOLOR"\n" );
return;
}
if( !s_mainClass->networkManagerFound )
{
s_mainClass->networkManagerFound = true;
strncpy( s_mainClass->networkManagerIP, pAddr->GetInetAddress(), sizeof ( s_mainClass->networkManagerIP ) );
}
if( pMsg->GetPayloadLen() >= 4 )
{
uint8_t *p = pMsg->GetPayload();
ConsolePrintf( PRIO_HIGH, "Got Network Manager version V%02d.%02d.%02d.%02d\n", p[0], p[1], p[2], p[3] );
}
}
void CVodHandler::OnNmConnectionList_Status( CMsgAddr *pAddr, CMostMsg *pMsg )
{
if( NULL == s_mainClass || NULL == pAddr || NULL == pMsg )
{
ConsolePrintf( PRIO_ERROR, RED"OnNmConnectionList_Status parameters are invalid."RESETCOLOR"\n" );
return;
}
volatile CAutoLock autoLock( &s_mainClass->infoContainerMutex );
CConnectionInfoContainer *container = new CConnectionInfoContainer();
if( !container->DeserializeFromString( ( char * )pMsg->GetPayload() ) )
{
ConsolePrintf( PRIO_ERROR, RED"Failed to parse connection list"RESETCOLOR"\n" );
delete container;
return;
}
container->PrintTable( false, false );
if( 0 == container->GetAllInfoAmount() )
{
ConsolePrintf( PRIO_MEDIUM, "No data in connection list, ignoring..\n" );
delete container;
return;
}
CMultiplexer *multiplexer;
for( uint32_t i = 0; i < container->GetAmountOfCDevs(); i++ )
{
CConnectionInfo *info = container->GetConnectionInfoOfCdev( i );
if( NULL == info )
continue;
if( NULL != s_mainClass->GetMultiplexer( info->deviceName ) )
{
ConsolePrintf( PRIO_LOW, "Multiplexer exists for device: '%s', ignoring\n", info->deviceName );
continue;
}
ConsolePrintfStart( PRIO_MEDIUM, "CDev: %s, Type: %d, Direction: %s, MAC: %s, Buffer:%d", info->deviceName,
info->dataType, ( info->isTX ? "TX" : "RX" ), info->macAddr->ToString(), info->bufferSize );
bool ignored = false;
for (uint32_t i = 0; i < s_mainClass->ignoreCdevPatterns.Size(); i++)
{
char *pattern = s_mainClass->ignoreCdevPatterns[i];
if ( NULL == pattern )
continue;
if ( NULL != strstr(info->deviceName, pattern) )
{
ignored = true;
break;
}
}
if( ( !ignored && info->isTX ) && ( ( EP_Isochron == info->dataType ) ||
( EP_Synchron == info->dataType && info->reservedBandwidth > 4 ) ) )
{
ConsolePrintfExit( ", creating Multiplexer.\n" );
try
{
multiplexer = new CMultiplexer( info->deviceName, info->bufferSize );
s_mainClass->allMultiplexer.PushBack( multiplexer );
}
catch( int e )
{
ConsolePrintf( PRIO_ERROR, RED"Failed to instance Multiplexer!"\
" Err-Code:%d"RESETCOLOR"\n", e );
}
}
else
{
ConsolePrintfExit( ", will be ignored.\n" );
}
}
if( NULL != s_mainClass->infoContainer )
delete s_mainClass->infoContainer;
s_mainClass->infoContainer = container;
}
CVodHandler *CVodHandler::GetInstance()
{
if( NULL == s_mainClass )
s_mainClass = new CVodHandler();
return s_mainClass;
}
void CVodHandler::DestroyInstance()
{
if( NULL != s_mainClass )
{
delete s_mainClass;
s_mainClass = NULL;
}
}
void CVodHandler::SetSearchPath( const char *pSearchPath )
{
if( NULL == pSearchPath )
return;
strncpy( searchPath, pSearchPath, sizeof ( searchPath ) );
RegisterBroadcastFiles( SelectFileType_Radio );
RegisterBroadcastFiles( SelectFileType_Navigation );
RegisterBroadcastFiles( SelectFileType_Cluster );
}
void CVodHandler::SetCdevIgnorePattern( const char *pIgnorePattern )
{
if (NULL == pIgnorePattern)
return;
char *str = (char *)malloc(strlen(pIgnorePattern) + 1);
strcpy(str, pIgnorePattern);
ignoreCdevPatterns.PushBack(str);
}
bool CVodHandler::StreamFile( const uint8_t *mac, SelectFileType_t fileType, const char *fileName )
{
if( NULL == mac || NULL == fileName || 0 == strlen( fileName ) )
{
ConsolePrintf( PRIO_ERROR,
RED"StreamFile was called with invalid parameters."RESETCOLOR"\n" );
return false;
}
char fullPath[200];
snprintf( fullPath, sizeof ( fullPath ), "%s/%s/%s", searchPath, GetSubPath( fileType ), fileName );
if( !ExistsFile( fullPath ) )
{
ConsolePrintf( PRIO_ERROR, RED"File was not found: '%s'"RESETCOLOR"\n", fullPath );
return false;
}
CMultiplexer *pMultiplexer = GetMultiplexer( mac );
if( NULL == pMultiplexer )
{
ConsolePrintf( PRIO_ERROR, RED"Could not get Multiplexer for MAC=%02X-%02X-%02X-%02X-%02X-%02X"RESETCOLOR"\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] );
return false;
}
CSource *pSource = NULL;
for( uint32_t i = 0; i < broadcastFiles.Size(); i++ )
{
BroadcastEntry_t *entry = broadcastFiles[i];
if( NULL != entry && ( 0 == strcmp( fullPath, entry->fileName ) ) )
pSource = entry->sourceFile;
}
if( NULL == pSource )
{
char *ext = rindex(fullPath, '.');
if (ext && !strcasecmp(ext, ".ts"))
pSource = new CSourceFile( fullPath, true );
else
pSource = new CSourceFileConverted( fullPath, true );
}
CMacAddr macAdress;
macAdress.CopyValuesFromByteArray( mac );
pMultiplexer->PlayStream( &macAdress, pSource );
return true;
}
bool CVodHandler::SetPause( const uint8_t *mac, bool isPaused )
{
CMultiplexer *pMultiplexer = GetMultiplexer( mac );
if( NULL == pMultiplexer )
return false;
CMacAddr macAdress;
macAdress.CopyValuesFromByteArray( mac );
pMultiplexer->SetPause( &macAdress, isPaused );
return true;
}
bool CVodHandler::SetRepetition( const uint8_t *mac, bool isRepeated )
{
CMultiplexer *pMultiplexer = GetMultiplexer( mac );
if( NULL == pMultiplexer )
return false;
CMacAddr macAdress;
macAdress.CopyValuesFromByteArray( mac );
pMultiplexer->SetRepetition( &macAdress, isRepeated );
return true;
}
bool CVodHandler::SetTimePos( const uint8_t *mac, uint16_t timePosPerMile )
{
CMultiplexer *pMultiplexer = GetMultiplexer( mac );
if( NULL == pMultiplexer )
return false;
CMacAddr macAddress;
macAddress.CopyValuesFromByteArray( mac );
pMultiplexer->SetPos( &macAddress, timePosPerMile );
return true;
}
bool CVodHandler::StopStream( const uint8_t *mac )
{
CMultiplexer *pMultiplexer = GetMultiplexer( mac );
if( NULL == pMultiplexer )
return false;
CMacAddr macAddress;
macAddress.CopyValuesFromByteArray( mac );
pMultiplexer->StopStream( &macAddress );
return true;
}
void CVodHandler::ToggleStatisticsPrint()
{
statisticIsEnabled = !statisticIsEnabled;
if (statisticIsEnabled)
Start();
else
Stop();
valuesCleared = false;
ConsolePrintf( PRIO_HIGH, "Cyclic printing of statistic informations: %d\n", statisticIsEnabled );
}
void CVodHandler::NM_SendServerVersionGetRequest( const char *ip )
{
CMsgAddr *msgAddr = new CMsgAddr( ip, IPC_PORT_NUMBER_NM, IpcUdp_V2_0 );
CMostMsgTx *mostMsg = new CMostMsgTx( msgAddr,
FBLOCK_NETWORK_MANAGER,
0,
FUNC_NM_SERVERVERSION,
CMostMsg::OP_GET,
0,
NULL,
500,
NULL,
NULL );
s_mainClass->mostIpcNm->SendMsg( mostMsg );
mostMsg->RemoveReference();
}
void CVodHandler::ConnectToNetworkManager()
{
do
{
NM_SendServerVersionGetRequest( "10.0.0.255" );
NM_SendServerVersionGetRequest( "127.0.0.1" );
sleep( 1 );
if( !networkManagerFound )
ConsolePrintf( PRIO_ERROR, YELLOW"No Network Manager found, retrying.."RESETCOLOR"\n" );
}
while( !networkManagerFound );
}
void CVodHandler::GetConnectionListFromNetworkManager()
{
if( !networkManagerFound )
{
ConsolePrintf( PRIO_ERROR,
RED"GetConnectionListFromNetworkManager called without server found, aborting.."RESETCOLOR
"\n" );
return;
}
CMsgAddr *msgAddr = new CMsgAddr( networkManagerIP, IPC_PORT_NUMBER_NM, IpcTcp_V2_0 );
CMostMsgTx *mostMsg = new CMostMsgTx( msgAddr,
FBLOCK_NETWORK_MANAGER,
0,
FUNC_NM_CONNECTION_LIST,
CMostMsg::OP_GET,
0,
NULL,
500,
NULL,
NULL );
s_mainClass->mostIpcNm->SendMsg( mostMsg );
mostMsg->RemoveReference();
}
bool CVodHandler::CreateMacIndependentStream(uint8_t cdevIndex, uint8_t streamIndex, uint8_t *outMac)
{
volatile CAutoLock autoLock( &infoContainerMutex );
if (NULL == outMac)
{
ConsolePrintf( PRIO_ERROR, RED"CreateMacIndependentStream NULL was passed to parameters"RESETCOLOR"\n" );
return false;
}
if( !networkManagerFound )
{
ConsolePrintf( PRIO_ERROR, RED"CreateMacIndependentStream called without"\
" server found, aborting.."RESETCOLOR"\n" );
return false;
}
if( NULL == infoContainer )
{
ConsolePrintf( PRIO_ERROR, RED"CreateMacIndependentStream called without any"\
" info stored, aborting.."RESETCOLOR"\n" );
return false;
}
CMultiplexer *multiplexer = allMultiplexer[cdevIndex];
if (NULL == multiplexer)
{
ConsolePrintf( PRIO_ERROR, RED"CreateMacIndependentStream with invalid CDEV index:%d"\
RESETCOLOR"\n", cdevIndex );
return false;
}
for( uint32_t i = 0; NULL != infoContainer && i < infoContainer->GetAllInfoAmount(); i++ )
{
CConnectionInfo *info = infoContainer->GetInfo( i );
if (NULL == info || NULL == info->deviceName || 0 != strcmp(info->deviceName, multiplexer->GetDriverName()))
continue;
outMac[0] = 0x2A;
outMac[1] = 0x11;
outMac[2] = 0x11;
outMac[3] = 0x11;
outMac[4] = (uint8_t)(i & 0xFF);
outMac[5] = streamIndex;
CMacAddr mac;
mac.CopyValuesFromByteArray(outMac);
CConnectionInfo *fake = infoContainer->GetInfo( &mac, streamIndex, info->mostInstance, false );
if( NULL == fake )
{
ConsolePrintf( PRIO_ERROR, RED"CreateMacIndependentStream failed to create"\
" new Info object.."RESETCOLOR"\n" );
return false;
}
fake->mostInstance = info->mostInstance;
fake->dataType = info->dataType;
fake->reservedBandwidth = info->reservedBandwidth;
fake->mostConnectionLabel = info->mostConnectionLabel;
fake->deviceType = 0xAFE;
fake->inSocketCreated = true;
fake->outSocketCreated = true;
fake->socketsConnected = true;
return true;
}
ConsolePrintf( PRIO_ERROR, RED"CreateMacIndependentStream failed to get"\
" valid Multiplexer for CDEV index: %d"RESETCOLOR"\n", cdevIndex );
return false;
}
void CVodHandler::CreateSampleStreams( uint8_t amount )
{
volatile CAutoLock autoLock( &infoContainerMutex );
if( !networkManagerFound )
{
ConsolePrintf( PRIO_ERROR, RED"CreateSampleStreams called without"\
" server found, aborting.."RESETCOLOR"\n" );
return;
}
if( NULL == infoContainer )
{
ConsolePrintf( PRIO_ERROR, RED"CreateSampleStreams called without any"\
" info stored, aborting.."RESETCOLOR"\n" );
return;
}
uint32_t cdevs = infoContainer->GetAmountOfCDevs();
uint32_t cdevPos = 0;
static uint32_t pidNr = 0x40;
static int32_t lastFileCnt = -1;
for( uint8_t i = 0; i < amount; i++ )
{
char fullPath[200];
snprintf( fullPath, sizeof ( fullPath ), "%s/video/test-%d.ts", searchPath, ++lastFileCnt );
bool ignored;
CConnectionInfo *info = NULL;
do
{
ignored = false;
if( ( cdevPos % cdevs ) == 0 )
++pidNr;
info = infoContainer->GetConnectionInfoOfCdev( cdevPos );
if( NULL == info )
{
ConsolePrintf( PRIO_ERROR, RED"CreateSampleStreams failed to get"\
" info.."RESETCOLOR"\n" );
return;
}
for (uint32_t i = 0; i < s_mainClass->ignoreCdevPatterns.Size(); i++)
{
char *pattern = s_mainClass->ignoreCdevPatterns[i];
if ( NULL == pattern )
continue;
if ( NULL != strstr( info->deviceName, pattern ) )
{
if( ++cdevPos >= cdevs )
cdevPos = 0;
ignored = true;
break;
}
}
}
while(ignored);
CMultiplexer *mp = GetMultiplexer(info->deviceName);
if( NULL == mp )
{
ConsolePrintf( PRIO_ERROR, RED"CreateSampleStreams failed to get"\
" valid Multiplexer for device name: %s"RESETCOLOR"\n", info->deviceName );
return;
}
//Create fake sink entry
CMacAddr *macAddr = new CMacAddr( 0xAF,0xFE,0,0,cdevPos, pidNr );
ConsolePrintf( PRIO_HIGH, "Will add file '%s' to Multiplexer with MAC: %s to CDEV: %s\n",
fullPath, macAddr->ToString(), info->deviceName );
CConnectionInfo *fake = infoContainer->GetInfo( macAddr, 47, info->mostInstance, false );
if( NULL == fake )
{
ConsolePrintf( PRIO_ERROR, RED"CreateSampleStreams failed to create"\
" new Info object.."RESETCOLOR"\n" );
return;
}
fake->mostInstance = info->mostInstance;
fake->dataType = info->dataType;
fake->reservedBandwidth = info->reservedBandwidth;
fake->mostConnectionLabel = info->mostConnectionLabel;
fake->deviceType = 0xAFE;
fake->inSocketCreated = true;
fake->outSocketCreated = true;
fake->socketsConnected = true;
char *ext = rindex(fullPath, '.');
if (ext && !strcasecmp(ext, ".ts"))
mp->PlayStream( fake->macAddr, new CSourceFile( fullPath, true ) );
else
mp->PlayStream( fake->macAddr, new CSourceFileConverted( fullPath, true ) );
mp->SetRepetition( fake->macAddr, true );
if( ++cdevPos >= cdevs )
cdevPos = 0;
}
ConsolePrintf( PRIO_HIGH, GREEN"CreateSampleStreams created %d sample streams.."\
RESETCOLOR"\n", amount );
infoContainer->PrintTable( false, false );
}
void CVodHandler::Run()
{
#define THREAD_SLEEP_TIME_IN_SEC 1
if( statisticIsEnabled )
{
if( !valuesCleared )
{
valuesCleared = true;
}
uint64_t allBytesWritten = 0;
ConsolePrintfStart( PRIO_HIGH, "==============Statistic Start==============\n" );
pthread_mutex_lock( &infoContainerMutex );
for( uint32_t i = 0; NULL != infoContainer && i < infoContainer->GetAllInfoAmount(); i++ )
{
bool success = false;
CMultiplexer::MultiplexStats_t stats;
CConnectionInfo *info = infoContainer->GetInfo( i );
if( NULL == info || NULL == info->macAddr || ( ( EP_Isochron != info->dataType ) &&
( EP_Synchron == info->dataType && info->reservedBandwidth <= 4 ) ) )
continue;
CConnectionInfo *remoteInfo =
infoContainer->GetRemoteConnectionInfoByMacAddress( info->macAddr->GetBytes() );
if( NULL == remoteInfo || remoteInfo == info )
continue;
CMultiplexer *multiplexer = GetMultiplexer( remoteInfo->deviceName );
if( NULL == multiplexer )
continue;
success = multiplexer->GetStatistics( info->macAddr, &stats );
if( success )
{
allBytesWritten += stats.bytesSent + stats.bytesStuffed;
ConsolePrintfContinue( "Device:%s, Stream %s, sent:%lld (kBit/s), stuffed:%lld (kBit/s),"\
" read:%lld (kBit/s), PCR-error:%lld, Buf Ovfl-error:%lld, "\
"Buf Unfl-error:%lld, TS-error:%lld\n", multiplexer->GetDriverName(),
info->macAddr->ToString(), ( 8 * stats.bytesSent / 1000 / THREAD_SLEEP_TIME_IN_SEC ), ( 8 *
stats.bytesStuffed / 1000 / THREAD_SLEEP_TIME_IN_SEC ), ( 8 * stats.bytesRead / 1000 /
THREAD_SLEEP_TIME_IN_SEC ), stats.errPcr, stats.errBufOverflow, stats.errBufUnderflow,
stats.errTs );
}
}
for( uint32_t i = 0; NULL != infoContainer && i < infoContainer->GetAmountOfCDevs(); i++ )
{
bool success = false;
CMultiplexer::MultiplexStats_t stats;
CConnectionInfo *info = infoContainer->GetConnectionInfoOfCdev( i );
if( NULL == info )
continue;
CMultiplexer *multiplexer = GetMultiplexer( info->deviceName );
if( NULL == multiplexer )
continue;
success = multiplexer->GetStatistics( info->macAddr, &stats );
if( success )
{
allBytesWritten += stats.bytesSent + stats.bytesStuffed;
ConsolePrintfContinue( "Device:%s, Stream %s, sent:%lld (kBit/s), stuffed:%lld (kBit/s),"\
" read:%lld (kBit/s), PCR-error:%lld, Buf Ovfl-error:%lld, "\
"Buf Unfl-error:%lld, TS-error:%lld\n", multiplexer->GetDriverName(),
info->macAddr->ToString(), ( 8 * stats.bytesSent / 1000 / THREAD_SLEEP_TIME_IN_SEC ), ( 8 *
stats.bytesStuffed / 1000 / THREAD_SLEEP_TIME_IN_SEC ), ( 8 * stats.bytesRead / 1000 /
THREAD_SLEEP_TIME_IN_SEC ), stats.errPcr, stats.errBufOverflow, stats.errBufUnderflow,
stats.errTs );
}
}
pthread_mutex_unlock( &infoContainerMutex );
ConsolePrintfContinue( "Overall sent performance of all streams: %lld (kBit/s)\n", ( 8 * allBytesWritten /
1000 / THREAD_SLEEP_TIME_IN_SEC ) );
ConsolePrintfExit( "===============Statistic End===============\n" );
}
usleep( THREAD_SLEEP_TIME_IN_SEC * 1000000 );
}