/* * 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 . * * 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 ); }