ITANetAudioStreamingClient.cpp 8.05 KB
Newer Older
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
1 2 3 4 5
#include "ITANetAudioStreamingClient.h"

#include "ITANetAudioClient.h"
#include "ITANetAudioMessage.h"
#include "ITANetAudioProtocol.h"
Dipl.-Ing. Jonas Stienen's avatar
Running  
Dipl.-Ing. Jonas Stienen committed
6

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
7
#include <ITANetAudioStream.h>
8 9
#include <ITADataLog.h>
#include <ITAClock.h>
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
10 11

#include <VistaInterProcComm/Connections/VistaConnectionIP.h>
12
#include <VistaInterProcComm/Concurrency/VistaPriority.h>
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
13
#include <VistaBase/VistaStreamUtils.h>
14
#include <VistaBase/VistaTimeUtils.h>
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
15

16 17 18 19 20 21 22 23
//! Audio streaming log item
struct ITAClientLog : public ITALogDataBase
{
	inline static std::ostream& outputDesc( std::ostream& os )
	{
		os << "BlockId";
		os << "\t" << "WorldTimeStamp";
		os << "\t" << "ProtocolStatus";
24
		os << "\t" << "TransmittedRingBufferFreeSamples";
25 26 27 28 29 30 31 32 33
		os << "\t" << "FreeSamples";
		os << std::endl;
		return os;
	};

	inline std::ostream& outputData( std::ostream& os ) const
	{
		os << uiBlockId;
		os << "\t" << std::setprecision( 12 ) << dWorldTimeStamp;
34 35
		os << "\t" << sProtocolStatus;
		os << "\t" << ( bTransmittedRingBufferFreeSamples ? "true" : "false" );
36 37 38 39 40 41 42
		os << "\t" << iFreeSamples;
		os << std::endl;
		return os;
	};

	unsigned int uiBlockId; //!< Block identifier (audio streaming)
	double dWorldTimeStamp;
43 44
	std::string sProtocolStatus;
	bool bTransmittedRingBufferFreeSamples;
45 46 47 48 49 50 51
	int iFreeSamples;

};

class ITABufferedDataLoggerImplClient : public ITABufferedDataLogger < ITAClientLog > {};


Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
52
CITANetAudioStreamingClient::CITANetAudioStreamingClient( CITANetAudioStream* pParent )
53
	: m_pStream( pParent )
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
54 55
	, m_pConnection( NULL )
	, m_bStopIndicated( false )
56
	, m_bStopped( false )
57 58 59
	, m_iStreamingBlockId( 0 )
	, m_dServerClockSyncRequestTimeInterval( 0.1f )
	, m_dServerClockSyncLastSyncTime( 0.0f )
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
60
	, m_bDebuggingEnabled( false )
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
61
{
Dipl.-Ing. Jonas Stienen's avatar
Running  
Dipl.-Ing. Jonas Stienen committed
62
	m_pClient = new CITANetAudioClient();
Jonas Stienen's avatar
Jonas Stienen committed
63
		 
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
64
	m_sfReceivingBuffer.init( pParent->GetNumberOfChannels(), pParent->GetRingBufferSize(), false );
65

66
	m_pMessage = new CITANetAudioMessage( VistaSerializingToolset::SWAPS_MULTIBYTE_VALUES );
Jonas Stienen's avatar
Jonas Stienen committed
67 68 69

	m_pClientLogger = new ITABufferedDataLoggerImplClient();
	SetClientLoggerBaseName( "ITANetAudioStreamingClient" );
70

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
71
	// Careful with this.
72
	//SetPriority( VistaPriority::VISTA_MID_PRIORITY );
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
73 74 75 76
}

CITANetAudioStreamingClient::~CITANetAudioStreamingClient()
{
77 78 79
	if( GetIsConnected() )
		Disconnect();

80
	StopGently( false );
81

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
82 83 84 85 86 87 88 89
	if( GetIsDebuggingEnabled() )
	{
		vstr::out() << "[ ITANetAudioStreamingClient ] Processing statistics: " << m_swTryReadBlockStats.ToString() << std::endl;
		vstr::out() << "[ ITANetAudioStreamingClient ] Try-read access statistics: " << m_swTryReadAccessStats.ToString() << std::endl;
	}
	else
		m_pClientLogger->setOutputFile( "" ); // disable output

90 91 92
	delete m_pClientLogger;
	delete m_pClient;
	delete m_pMessage;
93

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
94 95 96 97
}

bool CITANetAudioStreamingClient::Connect( const std::string& sAddress, int iPort )
{
Dipl.-Ing. Jonas Stienen's avatar
Running  
Dipl.-Ing. Jonas Stienen committed
98
	if( GetIsConnected() )
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
99
		return false;
100

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
101 102
	if( !m_pClient->Connect( sAddress, iPort ) )
		ITA_EXCEPT1( INVALID_PARAMETER, "Could not connect to " + sAddress );
103

104 105
	if( !m_pClient->GetIsConnected() )
		return false;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
106

107
	m_pConnection = m_pClient->GetConnection();
108

109
	m_pMessage->ResetMessage();
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
110 111
	m_pMessage->SetConnection( m_pConnection );

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
112 113 114 115 116 117
	CITANetAudioProtocol::StreamingParameters oParams;
	oParams.dSampleRate = m_pStream->GetSampleRate();
	oParams.iBlockSize = m_pStream->GetBlocklength();
	oParams.iChannels= m_pStream->GetNumberOfChannels();
	oParams.iRingBufferSize = m_pStream->GetRingBufferSize();

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
118 119
	// Validate streaming parameters of server and client
	m_pMessage->SetMessageType( CITANetAudioProtocol::NP_CLIENT_OPEN );
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
120
	m_pMessage->WriteStreamingParameters( oParams );
121 122
	m_pMessage->WriteMessage();
	m_pMessage->ResetMessage();
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
123

124
	while( !m_pMessage->ReadMessage( 0 ) );
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
125

126 127 128 129 130 131
	int iMsgType = m_pMessage->GetMessageType();
	if( iMsgType == CITANetAudioProtocol::NP_SERVER_OPEN )
	{
		// Clock sync vars
		m_dServerClockSyncRequestTimeInterval = m_pMessage->ReadDouble();
		m_dServerClockSyncLastSyncTime = 0;
132

133
		Run();
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
134

135 136 137 138 139 140 141 142 143 144 145 146
		return true;
	}
	else if( iMsgType == CITANetAudioProtocol::NP_SERVER_REFUSED_INVALID_PARAMETERS )
	{
		ITA_EXCEPT1( INVALID_PARAMETER, "Server refused connection due to invalid streaming parameters (mismatching block size or sampling rate)" );
	}
	else
	{
		ITA_EXCEPT1( INVALID_PARAMETER, "Server connection could not be established, unrecognized answer received." );
	}
     
    return false;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
147 148 149 150
}

bool CITANetAudioStreamingClient::LoopBody()
{
151
	if( !GetIsConnected() )
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
152 153
		return true;

154
	ITAClientLog oLog;
155 156
	oLog.uiBlockId = ++m_iStreamingBlockId;
	oLog.iFreeSamples = m_pStream->GetRingBufferFreeSamples();
157 158
	oLog.sProtocolStatus = CITANetAudioProtocol::GetNPMessageID( CITANetAudioProtocol::NP_CLIENT_IDLE );
	oLog.bTransmittedRingBufferFreeSamples = false;
159 160

	oLog.dWorldTimeStamp = ITAClock::getDefaultClock()->getTime();
161 162 163 164 165 166

	if( m_bStopIndicated && !m_bStopped )
	{
		m_pMessage->ResetMessage();
		m_pMessage->SetMessageType( CITANetAudioProtocol::NP_CLIENT_CLOSE );
		m_pMessage->WriteMessage();
167 168 169 170 171 172 173 174 175 176

		while( true )
		{
			m_pMessage->ResetMessage();
			m_pMessage->ReadMessage( 0 );
			int iMsgType = m_pMessage->GetMessageType();
			if( iMsgType == CITANetAudioProtocol::NP_SERVER_CLOSE )
				break;
		}

177 178 179 180 181 182 183 184
		m_bStopped = true;
		m_pMessage->SetConnection( NULL );

		while( GetIsConnected() )
			VistaTimeUtils::Sleep( 100 );

		return true;
	}
Anne's avatar
Anne committed
185

186 187
	// Try-read message (blocking for a timeout of 1ms)
	m_pMessage->ResetMessage();
188 189
	m_swTryReadBlockStats.start();
	m_swTryReadAccessStats.start();
190
	if( m_pMessage->ReadMessage( 1 ) )
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
191
	{
192
		m_swTryReadAccessStats.stop();
193

Jonas Stienen's avatar
Jonas Stienen committed
194 195 196 197 198 199 200
		int iMsgType = m_pMessage->GetMessageType();
		switch( iMsgType )
		{
		case CITANetAudioProtocol::NP_SERVER_SENDING_SAMPLES:
			m_pMessage->ReadSampleFrame( &m_sfReceivingBuffer );
			if( m_pStream->GetRingBufferFreeSamples() >= m_sfReceivingBuffer.GetLength() )
				m_pStream->Transmit( m_sfReceivingBuffer, m_sfReceivingBuffer.GetLength() );
201
#ifdef NET_AUDIO_SHOW_TRAFFIC
202
			vstr::out() << "[ITANetAudioStreamingClient] Received " << m_sfReceivingBuffer.GetLength() << " samples" << std::endl;
203
#endif
Jonas Stienen's avatar
Jonas Stienen committed
204
			break;
205

Jonas Stienen's avatar
Jonas Stienen committed
206 207 208 209 210 211
		case CITANetAudioProtocol::NP_SERVER_GET_RINGBUFFER_FREE_SAMPLES:
			m_pMessage->ReadBool();
			m_pMessage->SetMessageType( CITANetAudioProtocol::NP_CLIENT_SENDING_RINGBUFFER_FREE_SAMPLES );
			m_pMessage->WriteInt( m_pStream->GetRingBufferFreeSamples() );
			m_pMessage->WriteMessage();
			break;
212

Jonas Stienen's avatar
Jonas Stienen committed
213 214 215
		case CITANetAudioProtocol::NP_SERVER_CLOSE:
			Disconnect();
			break;
216

Jonas Stienen's avatar
Jonas Stienen committed
217 218 219
		default:
			vstr::out() << "[ITANetAudioStreamingServer] Unkown protocol type : " << iMsgType << std::endl;
			break;
220

221
		}
Jonas Stienen's avatar
Jonas Stienen committed
222

223
		// Also log message type on incoming message
224
		oLog.sProtocolStatus = CITANetAudioProtocol::GetNPMessageID( iMsgType );
225

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
226
	}
227 228
	if( m_swTryReadBlockStats.started() )
		m_swTryReadBlockStats.stop();
229 230 231 232

	// Send ring buffer free samples occasionally (as requested by server)
	const double dNow = ITAClock::getDefaultClock()->getTime();
	if( ( m_dServerClockSyncLastSyncTime + m_dServerClockSyncRequestTimeInterval ) < dNow )
233
	{
234 235 236 237
		m_pMessage->SetMessageType( CITANetAudioProtocol::NP_CLIENT_SENDING_RINGBUFFER_FREE_SAMPLES );
		m_pMessage->WriteInt( m_pStream->GetRingBufferFreeSamples() );
		m_pMessage->WriteMessage();
		m_dServerClockSyncLastSyncTime = dNow;
238
		oLog.bTransmittedRingBufferFreeSamples = true;
239
	}
240 241

	m_pClientLogger->log( oLog );
242
	
243
	return false;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
244 245
}

Jonas Stienen's avatar
Jonas Stienen committed
246 247 248 249 250 251 252 253 254
std::string CITANetAudioStreamingClient::GetClientLoggerBaseName() const
{
	return m_sClientLoggerBaseName;
}

void CITANetAudioStreamingClient::SetClientLoggerBaseName( const std::string& sBaseName )
{
	m_sClientLoggerBaseName = sBaseName;

Anne Heimes's avatar
Anne Heimes committed
255
	m_pClientLogger->setOutputFile( m_sClientLoggerBaseName + "_Client.log" );
256
	m_pMessage->SetMessageLoggerBaseName( GetClientLoggerBaseName() + "_Messages" );
Jonas Stienen's avatar
Jonas Stienen committed
257 258
}

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
259 260 261 262 263 264 265 266 267 268 269
void CITANetAudioStreamingClient::SetDebuggingEnabled( bool bEnabled )
{
	m_bDebuggingEnabled = bEnabled;
	m_pMessage->SetDebuggingEnabled( bEnabled );
}

bool CITANetAudioStreamingClient::GetIsDebuggingEnabled() const
{
	return m_bDebuggingEnabled;
}

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
270 271 272 273
bool CITANetAudioStreamingClient::GetIsConnected() const
{
	return m_pClient->GetIsConnected();
}
274 275 276 277 278

void CITANetAudioStreamingClient::Disconnect()
{
	m_bStopIndicated = true;

279 280
	while( !m_bStopped )
		VistaTimeUtils::Sleep( 100 );
281

282
	m_pConnection = NULL;
Anne Heimes's avatar
bugfix  
Anne Heimes committed
283
	m_pMessage->ClearConnection();
284
	m_pClient->Disconnect();
285
	m_bStopIndicated = false;
286
	m_bStopped = false;
287
}