summaryrefslogtreecommitdiffstats
path: root/Src/VodHandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/VodHandler.cpp')
-rw-r--r--Src/VodHandler.cpp1128
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 );
+}