diff options
Diffstat (limited to 'Src/VodHandler.cpp')
-rw-r--r-- | Src/VodHandler.cpp | 1128 |
1 files changed, 1128 insertions, 0 deletions
diff --git a/Src/VodHandler.cpp b/Src/VodHandler.cpp new file mode 100644 index 0000000..98ead21 --- /dev/null +++ b/Src/VodHandler.cpp @@ -0,0 +1,1128 @@ +/* + * 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 3 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 <http://www.gnu.org/licenses/>. + * + * You may also obtain this software under a propriety license from Microchip. + * Please contact Microchip for further information. + * + */ + +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#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 ); +} |