diff --git a/CMakeLists.txt b/CMakeLists.txt index e09aa9c454a261b8dbb823df35f3a0040fb097a9..c88c3ea29b499c03aa1da8aaa8503d8c88a8a2af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,23 +110,21 @@ endif( ) if( ITA_DATA_SOURCES_WITH_NET_AUDIO ) list( APPEND ITADataSourcesHeader - "include/ITANetAudioClient.h" - "include/ITANetAudioMessage.h" - "include/ITANetAudioProtocol.h" - "include/ITANetAudioServer.h" "include/ITANetAudioStream.h" - "include/ITANetAudioStreamingClient.h" "include/ITANetAudioStreamingServer.h" - "include/ITANetAudioStreamingClient.h" ) list( APPEND ITADataSourcesSources "src/ITANetAudioClient.cpp" + "src/ITANetAudioClient.h" "src/ITANetAudioMessage.cpp" - "src/ITANetAudioProtocol.cpp" + "src/ITANetAudioMessage.h" + "src/ITANetAudioProtocol.h" + "src/ITANetAudioServer.cpp" + "src/ITANetAudioServer.h" "src/ITANetAudioStream.cpp" "src/ITANetAudioStreamingClient.cpp" + "src/ITANetAudioStreamingClient.h" "src/ITANetAudioStreamingServer.cpp" - "src/ITANetAudioServer.cpp" ) endif( ) diff --git a/include/ITANetAudioStream.h b/include/ITANetAudioStream.h index 28dac53fc9e3a266c9cec8a619f0ef8b3d901925..510844dfc9fe488a52e801b97d657a1b2bfa6c6e 100644 --- a/include/ITANetAudioStream.h +++ b/include/ITANetAudioStream.h @@ -26,9 +26,6 @@ #include #include -#include -#include -using namespace std; class CITANetAudioStreamingClient; @@ -38,7 +35,7 @@ class ITABufferedDataLoggerImplAudio; //! Network audio stream /** - * Audio streaming for a signal source that is connected via TCP/IP. + * Audio streaming for a signal source that is connected via TCP/IP or UDP. * The network audio stream behaves like a client and receives samples * from a network audio stream server, CITANetAudioStreamingSearver. * @@ -46,11 +43,13 @@ class ITABufferedDataLoggerImplAudio; * block the streaming processing, because it is decoupled from the * network connection and forwards samples from an internal ring buffer. * If the buffer runs out of samples, zeros will be return. If the buffer - * overruns, the sample server will be suspendeb by blocking the network + * overruns, the sample server will be suspended by blocking the network * data flow. * - * Latency can be managed by either providing a small ring buffer or - * oversizing the ring buffer and requesting a target latency. + * Latency can be managed by either providing a small ring buffer and + * constantly filling it uo, or by oversizing the internal ring buffer + * only pushing samples to meet a target latency. This has to be + * implemented by the server. * * \note not thread-safe */ @@ -58,7 +57,21 @@ class ITA_DATA_SOURCES_API CITANetAudioStream : public ITADatasource { public: //! Constructor of a network audio stream + /** + * @param[in] iChannels Number of channels + * @param[in] dSamplingRate Sampling rate + * @param[in] iBufferSize Size of audio streaming buffer + * @param[in] iRingBufferCapacity Internal ring buffer + * + * The ring buffer capacity should be roughly 6-10 buffer sizes long for short audio streaming buffers, + * and can go down to one block in case of higher audio buffer sizes. + * + * The streaming parameters have to match with the server settings (yes also buffer size, that of the audio streaming context) + * + * @note Accept for more memory usage, oversizing the buffer does not require more CPU. + */ CITANetAudioStream( int iChannels, double dSamplingRate, int iBufferSize, int iRingBufferCapacity = 2048 ); + virtual ~CITANetAudioStream(); //! Network streaming status of client @@ -68,17 +81,19 @@ public: STOPPED, //!< Client not connected to a server and streaming stopped, i.e. not receiving samples by choice CONNECTED, //!< Client is connected to a sample server (and potentially receives samples) STREAMING, //!< - BUFFER_UNDERRUN, - BUFFER_OVERRUN, + BUFFER_UNDERRUN, //!< Client internal audio buffer ran out of samples + BUFFER_OVERRUN, //!< Client internal audio ring buffer is full }; //! Connect a streaming server /** - * @sAddress[in] Server address IP, i.e. 127.0.0.1 + * @sAddress[in] Server address IP (127.0.0.1, localhost, etc.) * @iPort[in] Server socket port, defaults to 12480 + * @return True, if connection could be established and streaming parameters match */ bool Connect( const std::string& sAddress, int iPort = 12480 ); + //! Disconnct safely from server void Disconnect(); //! Returns the connection status @@ -87,27 +102,48 @@ public: */ bool GetIsConnected() const; - //! Sets the minimal latency possible + //! Returns the minimal latency possible (single block) /** - * Real-time network audio is considered to process at lowest latency possible. - * However, this implementation requires at least one block. Hence latency is - * depending on sampling rate and block length. - * - * @sa GetMinimumLatencySamples() - * @sa GetMinimumLatencySamples() + * @return Minimum latency in seconds */ float GetMinimumLatencySeconds() const; + //! Returns the maximum latency possible (entire ring buffer used) + /** + * @return Maximum latency in seconds + */ float GetMaximumLatencySeconds() const; + + //! Returns the minimum latency possible (single block) + /** + * @return Minimum latency in samples + */ int GetMinimumLatencySamples() const; + + //! Returns the maximum latency possible (entire ring buffer used) + /** + * @return Maximum latency in samples + */ int GetMaximumLatencySamples() const; //! Returns the NetAudio streaming logger base name std::string GetNetAudioStreamLoggerBaseName() const; //! Sets the NetAudio streaming logger base name + /** + * If debugging is enabled, all debugging files will be named + * with this suffix. + * @param[in] sBaseName Base name string + * + */ void SetNetAudioStreamingLoggerBaseName( const std::string& sBaseName ); + //! Enabled/disables export of loggers + void SetDebuggingEnabled( bool bEnabled ); + + //! Logging export flag getter + bool GetIsDebuggingEnabled() const; + //! Returns (static) size of ring buffer /** * @return Number of maximum samples that can be hold by internal ring buffer @@ -200,6 +236,7 @@ private: ITABufferedDataLoggerImplStream* m_pAudioStreamLogger; //!< Logging for the audio stream ITABufferedDataLoggerImplNet* m_pNetworkStreamLogger; //!< Logging for the network stream std::string m_sNetAudioStreamLoggerBaseName; + bool m_bDebuggingEnabled; int m_iAudioStreamingBlockID; //!< Audio streaming block id int m_iNetStreamingBlockID; //!< Network streaming block id diff --git a/include/ITANetAudioStreamingServer.h b/include/ITANetAudioStreamingServer.h index 2bbbc9efa42110fc530754565f5decf2d1b4457e..20d73ce7530dd96f6c7505a5c362c74f8e8eb685 100644 --- a/include/ITANetAudioStreamingServer.h +++ b/include/ITANetAudioStreamingServer.h @@ -21,8 +21,6 @@ #include -#include -#include #include #include @@ -40,31 +38,25 @@ class CITANetAudioServer; class CITANetAudioMessage; class VistaTCPSocket; class ITABufferedDataLoggerImplServer; +class VistaConnectionIP; -//! Network audio sample server (for connecting a net audio stream) +//! Network audio streaming server (for connecting a net audio stream) with an ITADataSource connection /** - * Audio sample transmitter for a networked signal source that can connect via TCP/IP. - * - * \sa CITANetAudioStream - * \note not thread-safe - */ + * Audio sample transmitter for a networked signal source that can connect via TCP/IP. + * + * @sa CITANetAudioStream, CITANetAudioSampleServer + * @note not thread-safe + */ class ITA_DATA_SOURCES_API CITANetAudioStreamingServer : public VistaThreadLoop { public: - enum UpdateStrategy - { - AUTO = 1, //!< Automatic update rate based on sample rate and block length of client (default) - ADAPTIVE, //!< Adaptive update rate, adjusts for drifting clocks - CONSTANT, //!< Set a user-defined update rate (may cause forced pausing of sample feeding or dropouts on client side) - }; - CITANetAudioStreamingServer(); ~CITANetAudioStreamingServer(); //! Start to listen on a socket (blocking) - bool Start(const std::string& sAddress, const int iPort, const double dTimeIntervalCientSendStatus); + bool Start( const std::string& sAddress, const int iPort, const double dTimeIntervalCientSendStatus ); bool IsClientConnected() const; std::string GetNetworkAddress() const; int GetNetworkPort() const; @@ -76,12 +68,17 @@ public: int GetNetStreamBlocklength() const; int GetNetStreamNumberOfChannels() const; double GetNetStreamSampleRate() const; + + + //! Enabled/disables export of loggers + void SetDebuggingEnabled( bool bEnabled ); + + //! Logging export flag getter + bool GetIsDebuggingEnabled() const; int GetSendingBlockLength() const; void SetSendingBlockLength( const int iSendingBlockLength ); - void SetAutomaticUpdateRate(); - void SetTargetLatencySamples( const int iTargetLatency ); int GetTargetLatencySamples() const; @@ -99,20 +96,21 @@ private: ITADatasource* m_pInputStream; VistaConnectionIP* m_pConnection; - CITANetAudioProtocol::StreamingParameters m_oServerParams; CITANetAudioMessage* m_pMessage; - int iServerBlockId; ITABufferedDataLoggerImplServer* m_pServerLogger; std::string m_sServerLogBaseName; ITAStopWatch m_swTryReadBlockStats, m_swTryReadAccessStats; + bool m_bDebuggingEnabled; + + int m_iServerBlockId; + double m_dLastTimeStamp; - int m_iUpdateStrategy; - int m_iEstimatedClientRingBufferFreeSamples; int m_iTargetLatencySamples; - int m_iMaxSendBlocks; + int m_iEstimatedClientRingBufferFreeSamples; + int m_iClientRingBufferSize; int m_iSendingBlockLength; - double m_dLastTimeStamp; + int m_iMaxSendBlocks; friend class CITANetAudioServer; }; diff --git a/src/ITANetAudioClient.cpp b/src/ITANetAudioClient.cpp index faa1efd2b99a44bf5ad8b3d4e46f03198a6c53f7..1eb7510f13c923068e2543d7accd1a110ad2190d 100644 --- a/src/ITANetAudioClient.cpp +++ b/src/ITANetAudioClient.cpp @@ -1,8 +1,7 @@ -#include +#include "ITANetAudioClient.h" -#include -#include #include +#include #include diff --git a/include/ITANetAudioClient.h b/src/ITANetAudioClient.h similarity index 100% rename from include/ITANetAudioClient.h rename to src/ITANetAudioClient.h diff --git a/src/ITANetAudioMessage.cpp b/src/ITANetAudioMessage.cpp index 6f139b292f38067deac6718a93dc59ef501d1c30..01a7db4987fc3c37898d8d5dba27d865afa0a193 100644 --- a/src/ITANetAudioMessage.cpp +++ b/src/ITANetAudioMessage.cpp @@ -1,14 +1,15 @@ -#include +#include "ITANetAudioMessage.h" + +#include +#include #include #include #include #include -#include -#include -#include #include +#include #include #include #include @@ -58,6 +59,7 @@ CITANetAudioMessage::CITANetAudioMessage( VistaSerializingToolset::ByteOrderSwap , m_pConnection( NULL ) , m_iBytesReceivedTotal( 0 ) , m_sMessageLoggerBaseName( "ITANetAudioMessage" ) + , m_bDebuggingEnabled( false ) { m_pMessageLogger = new ITABufferedDataLoggerImplProtocol(); m_pMessageLogger->setOutputFile( m_sMessageLoggerBaseName + ".log" ); @@ -200,8 +202,8 @@ bool CITANetAudioMessage::ReadMessage( int timeout ) VistaType::sint32 nMessagePayloadSize; int nBytesRead = m_pConnection->ReadInt32( nMessagePayloadSize ); - oLog.nMessagePayloadSize = nMessagePayloadSize; assert( nBytesRead == sizeof( VistaType::sint32 ) ); + oLog.nMessagePayloadSize = nMessagePayloadSize; #if NET_AUDIO_SHOW_TRAFFIC vstr::out() << "CITANetAudioMessage [ Reading ] Expecting " << nMessagePayloadSize << " bytes message payload" << std::endl; #endif @@ -368,6 +370,8 @@ VistaConnectionIP* CITANetAudioMessage::GetConnection() const void CITANetAudioMessage::ClearConnection() { m_pConnection = NULL; + if( GetIsDebuggingEnabled() == false ) + m_pMessageLogger->setOutputFile( "" ); // disable output delete m_pMessageLogger; } @@ -461,4 +465,14 @@ void CITANetAudioMessage::SetMessageLoggerBaseName( const std::string& sBaseName std::string CITANetAudioMessage::GetMessageLoggerBaseName() const { return m_sMessageLoggerBaseName; -} \ No newline at end of file +} + +void CITANetAudioMessage::SetDebuggingEnabled( bool bEnabled ) +{ + m_bDebuggingEnabled = bEnabled; +} + +bool CITANetAudioMessage::GetIsDebuggingEnabled() const +{ + return m_bDebuggingEnabled; +} diff --git a/include/ITANetAudioMessage.h b/src/ITANetAudioMessage.h similarity index 92% rename from include/ITANetAudioMessage.h rename to src/ITANetAudioMessage.h index bf3c00a9db4245bd2f23fccbd7e4b1e4bc661643..cc99d796d67707d979d5e559fc73b8aa292aa5d4 100644 --- a/include/ITANetAudioMessage.h +++ b/src/ITANetAudioMessage.h @@ -21,11 +21,12 @@ #include +#include "ITANetAudioProtocol.h" + // ITA includes #include #include #include -#include // Vista includes #include @@ -97,6 +98,8 @@ public: void SetMessageLoggerBaseName( const std::string& ); std::string GetMessageLoggerBaseName() const; + void SetDebuggingEnabled( bool bEnabled ); + bool GetIsDebuggingEnabled() const; private: int m_nMessageType; @@ -111,6 +114,7 @@ private: ITABufferedDataLoggerImplProtocol* m_pMessageLogger; std::string m_sMessageLoggerBaseName; + bool m_bDebuggingEnabled; }; #endif // INCLUDE_WATCHER_ITA_NET_AUDIO_MESSAGE diff --git a/src/ITANetAudioProtocol.cpp b/src/ITANetAudioProtocol.cpp index 73d3d8152bae4c1d9a62b8c5182af1a95ef830b1..19e8d713a031a9425758a73265cd5f5d781cba23 100644 --- a/src/ITANetAudioProtocol.cpp +++ b/src/ITANetAudioProtocol.cpp @@ -1,3 +1,3 @@ -#include +#include "ITANetAudioProtocol.h" // @todo remove (all inline implemented) \ No newline at end of file diff --git a/include/ITANetAudioProtocol.h b/src/ITANetAudioProtocol.h similarity index 94% rename from include/ITANetAudioProtocol.h rename to src/ITANetAudioProtocol.h index b5936cfe8015095334351159574a6ad6e71abec5..8ccfc45a227556312ad26704b7d0bf30b3e40736 100644 --- a/include/ITANetAudioProtocol.h +++ b/src/ITANetAudioProtocol.h @@ -54,6 +54,7 @@ public: static const int NP_SERVER_OPEN = 200; static const int NP_SERVER_CLOSE = 201; + static const int NP_SERVER_REFUSED_INVALID_PARAMETERS = 202; static const int NP_SERVER_GET_RINGBUFFER_FREE_SAMPLES = 211; static const int NP_SERVER_SENDING_SAMPLES = 222; @@ -69,6 +70,7 @@ public: case NP_CLIENT_CLOSE: return "CLIENT_CLOSE"; case NP_CLIENT_SENDING_RINGBUFFER_FREE_SAMPLES: return "CLIENT_SENDING_RINGBUFFER_FREE_SAMPLES"; case NP_SERVER_OPEN: return "SERVER_OPEN"; + case NP_SERVER_REFUSED_INVALID_PARAMETERS: return "NP_SERVER_REFUSED_INVALID_PARAMETERS"; case NP_SERVER_CLOSE: return "SERVER_CLOSE"; case NP_SERVER_GET_RINGBUFFER_FREE_SAMPLES: return "SERVER_GET_RINGBUFFER_FREE_SAMPLES"; case NP_SERVER_SENDING_SAMPLES: return "SERVER_SENDING_SAMPLES"; diff --git a/src/ITANetAudioServer.cpp b/src/ITANetAudioServer.cpp index 7a06cf709fa50eb37b5a9afebfe86b3d2c6849e7..8cf62211ee825d7d457940d118e1630249c1e5eb 100644 --- a/src/ITANetAudioServer.cpp +++ b/src/ITANetAudioServer.cpp @@ -1,6 +1,7 @@ -#include +#include "ITANetAudioServer.h" +#include "ITANetAudioProtocol.h" + #include -#include // ITA includes #include @@ -29,9 +30,9 @@ CITANetAudioServer::CITANetAudioServer() CITANetAudioServer::~CITANetAudioServer() { + m_pSocket = NULL; delete m_pConnection; delete m_pServer; - delete m_pSocket; } std::string CITANetAudioServer::GetServerAddress() const diff --git a/include/ITANetAudioServer.h b/src/ITANetAudioServer.h similarity index 97% rename from include/ITANetAudioServer.h rename to src/ITANetAudioServer.h index 1fb399a78128113f0c3616a02cd202013545230f..0c44614682f90cd2226fa3793bf098dbf0031a8f 100644 --- a/include/ITANetAudioServer.h +++ b/src/ITANetAudioServer.h @@ -21,8 +21,6 @@ #include -#include - #include #include @@ -65,4 +63,5 @@ private: std::string m_sServerAddress; }; + #endif // INCLUDE_WATCHER_ITA_NET_AUDIO_SERVER diff --git a/src/ITANetAudioStream.cpp b/src/ITANetAudioStream.cpp index 173188d1691b9ce5c1239975ce7a8d277146ee18..648b58d3e4a5aaecc9bc04f1b8aa2e05fc54c4ae 100644 --- a/src/ITANetAudioStream.cpp +++ b/src/ITANetAudioStream.cpp @@ -1,19 +1,19 @@ #include -#include +#include "ITANetAudioStreamingClient.h" // ITA includes #include #include #include #include -#include // Vista includes #include // STL includes #include +#include #include @@ -97,6 +97,7 @@ CITANetAudioStream::CITANetAudioStream(int iChannels, double dSamplingRate, int , m_iWriteCursor( 0 ) // always ahead, i.e. iWriteCursor >= iReadCursor if unwrapped , m_iAudioStreamingBlockID( 0 ) , m_iNetStreamingBlockID( 0 ) + , m_bDebuggingEnabled( false ) { if( iBufferSize > iRingBufferCapacity ) ITA_EXCEPT1( INVALID_PARAMETER, "Ring buffer capacity can not be smaller than Target Sample Latency." ); @@ -114,6 +115,12 @@ CITANetAudioStream::CITANetAudioStream(int iChannels, double dSamplingRate, int CITANetAudioStream::~CITANetAudioStream() { + if( GetIsDebuggingEnabled() == false ) + { + m_pAudioStreamLogger->setOutputFile( "" ); // Disables file storing + m_pNetworkStreamLogger->setOutputFile( "" ); // Disables file storing + } + delete m_pAudioStreamLogger; delete m_pNetworkStreamLogger; delete m_pNetAudioStreamingClient; @@ -246,8 +253,6 @@ void CITANetAudioStream::IncrementBlockPointer() oLog.uiBlockId = ++m_iAudioStreamingBlockID; oLog.iFreeSamples = GetRingBufferFreeSamples( ); m_pAudioStreamLogger->log( oLog ); - - //m_pNetAudioStreamingClient->TriggerBlockIncrement(); } int CITANetAudioStream::Transmit( const ITASampleFrame& sfNewSamples, int iNumSamples ) @@ -382,3 +387,14 @@ void CITANetAudioStream::SetNetAudioStreamingLoggerBaseName( const std::string& m_pNetworkStreamLogger->setOutputFile( GetNetAudioStreamLoggerBaseName() + "_NetworkStream.log" ); m_pNetAudioStreamingClient->SetClientLoggerBaseName( sBaseName ); } + +void CITANetAudioStream::SetDebuggingEnabled( bool bEnabled ) +{ + m_bDebuggingEnabled = bEnabled; + m_pNetAudioStreamingClient->SetDebuggingEnabled( bEnabled ); +} + +bool CITANetAudioStream::GetIsDebuggingEnabled() const +{ + return m_bDebuggingEnabled; +} diff --git a/src/ITANetAudioStreamingClient.cpp b/src/ITANetAudioStreamingClient.cpp index 834780adc8333c0f995320b24826a53b39756df7..656efe15491fc44bc518e6ea8a9062ecfe175b5c 100644 --- a/src/ITANetAudioStreamingClient.cpp +++ b/src/ITANetAudioStreamingClient.cpp @@ -1,7 +1,9 @@ -#include +#include "ITANetAudioStreamingClient.h" + +#include "ITANetAudioClient.h" +#include "ITANetAudioMessage.h" +#include "ITANetAudioProtocol.h" -#include -#include #include #include #include @@ -55,20 +57,18 @@ CITANetAudioStreamingClient::CITANetAudioStreamingClient( CITANetAudioStream* pP , m_iStreamingBlockId( 0 ) , m_dServerClockSyncRequestTimeInterval( 0.1f ) , m_dServerClockSyncLastSyncTime( 0.0f ) + , m_bDebuggingEnabled( false ) { m_pClient = new CITANetAudioClient(); - m_oParams.iChannels = pParent->GetNumberOfChannels(); - m_oParams.dSampleRate = pParent->GetSampleRate(); - m_oParams.iBlockSize = pParent->GetBlocklength(); - m_oParams.iRingBufferSize = pParent->GetRingBufferSize(); - m_sfReceivingBuffer.init( m_oParams.iChannels, m_oParams.iRingBufferSize, false ); + m_sfReceivingBuffer.init( pParent->GetNumberOfChannels(), pParent->GetRingBufferSize(), false ); m_pMessage = new CITANetAudioMessage( VistaSerializingToolset::SWAPS_MULTIBYTE_VALUES ); m_pClientLogger = new ITABufferedDataLoggerImplClient(); SetClientLoggerBaseName( "ITANetAudioStreamingClient" ); + // Careful with this. //SetPriority( VistaPriority::VISTA_MID_PRIORITY ); } @@ -79,12 +79,18 @@ CITANetAudioStreamingClient::~CITANetAudioStreamingClient() StopGently( false ); + 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 + delete m_pClientLogger; delete m_pClient; delete m_pMessage; - vstr::out() << "[ ITANetAudioStreamingClient ] Processing statistics: " << m_swTryReadBlockStats.ToString() << std::endl; - vstr::out() << "[ ITANetAudioStreamingClient ] Try-read access statistics: " << m_swTryReadAccessStats.ToString() << std::endl; } bool CITANetAudioStreamingClient::Connect( const std::string& sAddress, int iPort ) @@ -103,23 +109,41 @@ bool CITANetAudioStreamingClient::Connect( const std::string& sAddress, int iPor m_pMessage->ResetMessage(); m_pMessage->SetConnection( m_pConnection ); + CITANetAudioProtocol::StreamingParameters oParams; + oParams.dSampleRate = m_pStream->GetSampleRate(); + oParams.iBlockSize = m_pStream->GetBlocklength(); + oParams.iChannels= m_pStream->GetNumberOfChannels(); + oParams.iRingBufferSize = m_pStream->GetRingBufferSize(); + // Validate streaming parameters of server and client m_pMessage->SetMessageType( CITANetAudioProtocol::NP_CLIENT_OPEN ); - m_pMessage->WriteStreamingParameters( m_oParams ); + m_pMessage->WriteStreamingParameters( oParams ); m_pMessage->WriteMessage(); m_pMessage->ResetMessage(); while( !m_pMessage->ReadMessage( 0 ) ); - assert( m_pMessage->GetMessageType() == CITANetAudioProtocol::NP_SERVER_OPEN ); + int iMsgType = m_pMessage->GetMessageType(); + if( iMsgType == CITANetAudioProtocol::NP_SERVER_OPEN ) + { + // Clock sync vars + m_dServerClockSyncRequestTimeInterval = m_pMessage->ReadDouble(); + m_dServerClockSyncLastSyncTime = 0; - // Clock sync vars - m_dServerClockSyncRequestTimeInterval = m_pMessage->ReadDouble(); - m_dServerClockSyncLastSyncTime = 0; - - Run(); + Run(); - return true; + 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; } bool CITANetAudioStreamingClient::LoopBody() @@ -232,6 +256,17 @@ void CITANetAudioStreamingClient::SetClientLoggerBaseName( const std::string& sB m_pMessage->SetMessageLoggerBaseName( GetClientLoggerBaseName() + "_Messages" ); } +void CITANetAudioStreamingClient::SetDebuggingEnabled( bool bEnabled ) +{ + m_bDebuggingEnabled = bEnabled; + m_pMessage->SetDebuggingEnabled( bEnabled ); +} + +bool CITANetAudioStreamingClient::GetIsDebuggingEnabled() const +{ + return m_bDebuggingEnabled; +} + bool CITANetAudioStreamingClient::GetIsConnected() const { return m_pClient->GetIsConnected(); diff --git a/include/ITANetAudioStreamingClient.h b/src/ITANetAudioStreamingClient.h similarity index 94% rename from include/ITANetAudioStreamingClient.h rename to src/ITANetAudioStreamingClient.h index dc86313253070e6c547a0f00b11a7947640e8ca0..742dbd154e56bf74c2a4428b8ebb5db5a1d6649c 100644 --- a/include/ITANetAudioStreamingClient.h +++ b/src/ITANetAudioStreamingClient.h @@ -21,8 +21,6 @@ #include -#include - #include #include #include @@ -38,6 +36,7 @@ class CITANetAudioMessage; class CITANetAudioProtocol; class CITANetAudioStream; class ITABufferedDataLoggerImplClient; +class VistaConnectionIP; //! Network audio streaming client /** @@ -63,6 +62,9 @@ public: std::string GetClientLoggerBaseName() const; void SetClientLoggerBaseName( const std::string& ); + void SetDebuggingEnabled( bool bEnabled ); + bool GetIsDebuggingEnabled() const; + protected: void TriggerBlockIncrement(); @@ -75,9 +77,7 @@ private: VistaConnectionIP* m_pConnection; ITASampleFrame m_sfReceivingBuffer; //!< Buffer incoming data - - CITANetAudioProtocol::StreamingParameters m_oParams; - + bool m_bStopIndicated; bool m_bStopped; @@ -89,6 +89,7 @@ private: ITABufferedDataLoggerImplClient* m_pClientLogger; std::string m_sClientLoggerBaseName; ITAStopWatch m_swTryReadBlockStats, m_swTryReadAccessStats; + bool m_bDebuggingEnabled; friend class CITANetAudioStream; }; diff --git a/src/ITANetAudioStreamingServer.cpp b/src/ITANetAudioStreamingServer.cpp index 7a2070602f6213e45ad06b738d69174e9d7606de..c6093a4788b9643d5d0d90fe8826b46fa67d2838 100644 --- a/src/ITANetAudioStreamingServer.cpp +++ b/src/ITANetAudioStreamingServer.cpp @@ -1,10 +1,10 @@ #include -#include -#include + +#include "ITANetAudioServer.h" +#include "ITANetAudioMessage.h" // ITA includes #include -#include #include #include #include @@ -58,27 +58,36 @@ class ITABufferedDataLoggerImplServer : public ITABufferedDataLogger < ITAServer CITANetAudioStreamingServer::CITANetAudioStreamingServer() : m_pInputStream( NULL ) - , m_iUpdateStrategy( AUTO ) , m_pConnection( NULL ) , m_pNetAudioServer( new CITANetAudioServer() ) , m_dLastTimeStamp( 0 ) , m_iTargetLatencySamples( -1 ) , m_sServerLogBaseName( "ITANetAudioStreamingServer" ) + , m_bDebuggingEnabled( false ) + , m_iMaxSendBlocks( 40 ) + , m_iServerBlockId( 0 ) + , m_iEstimatedClientRingBufferFreeSamples( 0 ) + , m_iClientRingBufferSize( 0 ) { - iServerBlockId = 0; - m_iMaxSendBlocks = 40; - m_iEstimatedClientRingBufferFreeSamples = 0; - + // Careful with this: //SetPriority( VistaPriority::VISTA_MID_PRIORITY ); } CITANetAudioStreamingServer::~CITANetAudioStreamingServer() { delete m_pNetAudioServer; + + + if( GetIsDebuggingEnabled() ) + { + vstr::out() << "[ ITANetAudioStreamingServer ] Processing statistics: " << m_swTryReadBlockStats.ToString() << std::endl; + vstr::out() << "[ ITANetAudioStreamingServer ] Try-read access statistics: " << m_swTryReadAccessStats.ToString() << std::endl; + } + else + m_pServerLogger->setOutputFile( "" ); // disables export + delete m_pServerLogger; - vstr::out() << "[ ITANetAudioStreamingServer ] Processing statistics: " << m_swTryReadBlockStats.ToString() << std::endl; - vstr::out() << "[ ITANetAudioStreamingServer ] Try-read access statistics: " << m_swTryReadAccessStats.ToString() << std::endl; } bool CITANetAudioStreamingServer::Start(const std::string& sAddress, int iPort, double dTimeIntervalCientSendStatus) @@ -101,42 +110,47 @@ bool CITANetAudioStreamingServer::Start(const std::string& sAddress, int iPort, assert( m_pMessage->GetMessageType() == CITANetAudioProtocol::NP_CLIENT_OPEN ); CITANetAudioProtocol::StreamingParameters oClientParams = m_pMessage->ReadStreamingParameters(); - bool bOK = false; - m_oServerParams.iRingBufferSize = oClientParams.iRingBufferSize; - m_oServerParams.iBlockSize = oClientParams.iBlockSize; - m_iEstimatedClientRingBufferFreeSamples = m_oServerParams.iRingBufferSize; + CITANetAudioProtocol::StreamingParameters oServerParams; + oServerParams.iRingBufferSize = oClientParams.iRingBufferSize; + oServerParams.iBlockSize = m_pInputStream->GetBlocklength(); + oServerParams.dSampleRate = m_pInputStream->GetSampleRate(); + oServerParams.iChannels = m_pInputStream->GetNumberOfChannels(); + + m_iEstimatedClientRingBufferFreeSamples = oServerParams.iRingBufferSize; + m_iClientRingBufferSize = oClientParams.iRingBufferSize; + m_iSendingBlockLength = oServerParams.iBlockSize; + m_sfTempTransmitBuffer.init( m_pInputStream->GetNumberOfChannels(), oServerParams.iRingBufferSize, true ); + + m_pServerLogger = new ITABufferedDataLoggerImplServer(); + m_pServerLogger->setOutputFile( m_sServerLogBaseName + "_Server.log" ); m_dLastTimeStamp = ITAClock::getDefaultClock()->getTime(); - if( m_oServerParams == oClientParams ) + + if( oServerParams == oClientParams ) { - bOK = true; + m_pMessage->SetMessageType( CITANetAudioProtocol::NP_SERVER_OPEN ); + m_pMessage->WriteDouble( dTimeIntervalCientSendStatus ); + m_pMessage->WriteMessage(); + #ifdef NET_AUDIO_SHOW_TRAFFIC vstr::out() << "[ITANetAudioStreamingServer] Server and client parameters matched. Will resume with streaming" << std::endl; #endif + + Run(); // Start thread loop + + return true; } else { + m_pMessage->SetMessageType( CITANetAudioProtocol::NP_SERVER_REFUSED_INVALID_PARAMETERS ); + m_pMessage->WriteMessage(); + #ifdef NET_AUDIO_SHOW_TRAFFIC vstr::out() << "[ITANetAudioStreamingServer] Server and client parameters mismatch detected. Will notify client and stop." << std::endl; #endif -} - - m_pServerLogger = new ITABufferedDataLoggerImplServer(); - m_pServerLogger->setOutputFile( m_sServerLogBaseName + "_Server.log" ); - - m_pMessage->SetMessageType( CITANetAudioProtocol::NP_SERVER_OPEN ); - m_pMessage->WriteDouble( dTimeIntervalCientSendStatus ); - m_pMessage->WriteMessage(); - - - m_iSendingBlockLength = m_pInputStream->GetBlocklength(); - m_sfTempTransmitBuffer.init( m_pInputStream->GetNumberOfChannels(), m_oServerParams.iRingBufferSize, true ); - - if( bOK ) - Run(); - - return bOK; + return false; + } } bool CITANetAudioStreamingServer::LoopBody() @@ -145,11 +159,11 @@ bool CITANetAudioStreamingServer::LoopBody() ITAServerLog oLog; oLog.dWorldTimeStamp = dNow; - oLog.uiBlockId = ++iServerBlockId; + oLog.uiBlockId = ++m_iServerBlockId; oLog.iTransmittedSamples = 0; // Sending Samples - int iEstimatedClientRingBufferTargetLatencyFreeSamples = m_iEstimatedClientRingBufferFreeSamples - ( m_oServerParams.iRingBufferSize - m_iTargetLatencySamples ); + int iEstimatedClientRingBufferTargetLatencyFreeSamples = m_iEstimatedClientRingBufferFreeSamples - ( m_iClientRingBufferSize - m_iTargetLatencySamples ); if (iEstimatedClientRingBufferTargetLatencyFreeSamples >= m_iSendingBlockLength) { @@ -252,9 +266,6 @@ void CITANetAudioStreamingServer::SetInputStream( ITADatasource* pInStream ) ITA_EXCEPT1( MODAL_EXCEPTION, "Streaming loop already running, can not change input stream" ); m_pInputStream = pInStream; - m_oServerParams.dSampleRate = m_pInputStream->GetSampleRate(); - m_oServerParams.iBlockSize = m_pInputStream->GetBlocklength(); - m_oServerParams.iChannels = m_pInputStream->GetNumberOfChannels(); } ITADatasource* CITANetAudioStreamingServer::GetInputStream() const @@ -282,16 +293,25 @@ int CITANetAudioStreamingServer::GetNetStreamNumberOfChannels() const return m_sfTempTransmitBuffer.channels(); } -void CITANetAudioStreamingServer::SetAutomaticUpdateRate() +void CITANetAudioStreamingServer::SetDebuggingEnabled( bool bEnabled ) +{ + m_bDebuggingEnabled = bEnabled; +} + +bool CITANetAudioStreamingServer::GetIsDebuggingEnabled() const { - m_iUpdateStrategy = AUTO; + return m_bDebuggingEnabled; } void CITANetAudioStreamingServer::SetTargetLatencySamples( const int iTargetLatency ) { // Streaming already set up? - if( IsClientConnected() && m_iTargetLatencySamples < m_oServerParams.iBlockSize ) - ITA_EXCEPT1( INVALID_PARAMETER, "Target latency has to be at least the block size of the audio streaming at client side." ); + if( IsClientConnected() ) + ITA_EXCEPT1( MODAL_EXCEPTION, "Server not connected, client ring buffer unkown" ); + + if( m_pInputStream ) + if( m_iTargetLatencySamples < m_pInputStream->GetBlocklength() ) + ITA_EXCEPT1( INVALID_PARAMETER, "Target latency has to be at least the block size of the audio streaming at client side." ); m_iTargetLatencySamples = iTargetLatency; } diff --git a/tests/NetAudio/CMakeLists.txt b/tests/NetAudio/CMakeLists.txt index 8354b74bf3ec66cda5d24a977a689317b58a7ea4..871d8d0ee06ab2c356e4794458a895b46b68f433 100644 --- a/tests/NetAudio/CMakeLists.txt +++ b/tests/NetAudio/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required( VERSION 2.9 ) +cmake_minimum_required( VERSION 2.9 ) project( ITANetAudioTests ) list( APPEND CMAKE_MODULE_PATH "$ENV{VISTA_CMAKE_COMMON}" ) @@ -72,12 +73,12 @@ vista_install_all_dlls( bin ) set_property( TARGET ITANetAudioTest PROPERTY FOLDER "ITACoreLibs/Tests/ITADataSources/NetAudio" ) if( NOT DEFINED ITA_NETAUDIO_SERVER_WITH_TESTS ) - set( ITA_NETAUDIO_SERVER_WITH_TESTS "default value" CACHE STRING "localhost 12480 44100 32 2" ) + set( ITA_NETAUDIO_SERVER_WITH_TESTS "localhost 12480 44100 32 2" CACHE STRING "default value") endif( ) if( NOT DEFINED ITA_NETAUDIO_CLIENT_WITH_TESTS ) - set( ITA_NETAUDIO_CLIENT_WITH_TESTS "default value" CACHE STRING "localhost 12480 44100 32 2 3200" ) + set( ITA_NETAUDIO_CLIENT_WITH_TESTS "localhost 12480 44100 32 2 3200" CACHE STRING "default value" ) endif( ) -vista_set_target_msvc_arguments( ITANetAudioStreamingPortaudioClientTest ITA_NETAUDIO_CLIENT_WITH_TESTS ) -vista_set_target_msvc_arguments( ITANetAudioStreamingClientTest ITA_NETAUDIO_CLIENT_WITH_TESTS ) -vista_set_target_msvc_arguments( ITANetAudioStreamingServerTest ITA_NETAUDIO_SERVER_WITH_TESTS ) +vista_set_target_msvc_arguments( ITANetAudioStreamingPortaudioClientTest ${ITA_NETAUDIO_CLIENT_WITH_TESTS} ) +vista_set_target_msvc_arguments( ITANetAudioStreamingClientTest ${ITA_NETAUDIO_CLIENT_WITH_TESTS} ) +vista_set_target_msvc_arguments( ITANetAudioStreamingServerTest ${ITA_NETAUDIO_SERVER_WITH_TESTS} ) diff --git a/tests/NetAudio/ITANetAudioStreamingClientTest.cpp b/tests/NetAudio/ITANetAudioStreamingClientTest.cpp index 8138c77b267093a6bc3405f9a967aeb43e719a65..1925c667dff4e1efd3f562d12fc75fd566ecb97d 100644 --- a/tests/NetAudio/ITANetAudioStreamingClientTest.cpp +++ b/tests/NetAudio/ITANetAudioStreamingClientTest.cpp @@ -14,10 +14,10 @@ using namespace std; -string g_sServerName = "137.226.61.85"; +string g_sServerName = "localhost"; int g_iServerPort = 12480; double g_dSampleRate = 44100.0; -int g_iBlockLength = 32; +int g_iBlockLength = 512; int g_iChannels = 2; int g_iTargetLatencySamples = 2 * g_iBlockLength; // 1.4512ms int g_iRingBufferSize = 2 * g_iTargetLatencySamples; @@ -62,6 +62,7 @@ int main( int argc, char* argv[] ) ss << "_RB" << g_iRingBufferSize; ss << "_SB" << g_iSendingBlockLength; oNetAudioStream.SetNetAudioStreamingLoggerBaseName( ss.str() ); + oNetAudioStream.SetDebuggingEnabled( true ); ITAStreamPatchbay oPatchbay( g_dSampleRate, g_iBlockLength ); oPatchbay.AddInput( &oNetAudioStream ); @@ -77,7 +78,7 @@ int main( int argc, char* argv[] ) cout << "Will attempt to connect to '" << g_sServerName << "' on port " << g_iServerPort << endl; ITAsioInitializeLibrary(); - ITAsioInitializeDriver( "ASIO MADIface USB" ); + ITAsioInitializeDriver( "ASIO4ALL v2" ); long lBuffersize, lDummy; ITAsioGetBufferSize( &lDummy, &lDummy, &lBuffersize, &lDummy ); diff --git a/tests/NetAudio/ITANetAudioStreamingPortaudioClientTest.cpp b/tests/NetAudio/ITANetAudioStreamingPortaudioClientTest.cpp index 3c340f8621ca06294d3705ceb5614b5609eabee3..bfcbe5a24934711d3bb93f71ca12cb89dbe3068f 100644 --- a/tests/NetAudio/ITANetAudioStreamingPortaudioClientTest.cpp +++ b/tests/NetAudio/ITANetAudioStreamingPortaudioClientTest.cpp @@ -32,6 +32,7 @@ int main(int argc, char* argv[]) int iBufferSize = atoi(argv[6]); CITANetAudioStream oNetAudioStream( iChannels, dSampleRate, iBlockLength, iBlockLength*16 ); + oNetAudioStream.SetDebuggingEnabled( true ); ITAStreamPatchbay oPatchbay( dSampleRate, iBlockLength ); oPatchbay.AddInput( &oNetAudioStream ); int iOutputID = oPatchbay.AddOutput( 2 ); @@ -72,4 +73,4 @@ int main(int argc, char* argv[]) ITAPA.Finalize(); return 0; -} \ No newline at end of file +} diff --git a/tests/NetAudio/ITANetAudioStreamingServerTest.cpp b/tests/NetAudio/ITANetAudioStreamingServerTest.cpp index 8aee386c5b292608e99543a65bc16d52c9afecfa..231ee2653d46a02c7976019ee4e9bf5c6eef9d34 100644 --- a/tests/NetAudio/ITANetAudioStreamingServerTest.cpp +++ b/tests/NetAudio/ITANetAudioStreamingServerTest.cpp @@ -1,8 +1,9 @@ #include -#include #include #include #include +#include + #include #include @@ -11,16 +12,17 @@ using namespace std; -string g_sServerName = "137.226.61.85"; +string g_sServerName = "localhost"; int g_iServerPort = 12480; double g_dSampleRate = 44100.0; -int g_iBlockLength = 32; -int g_iChannels = 2; +int g_iBlockLength = 512; +int g_iChannels = 1; int g_iTargetLatencySamples = 4 * g_iBlockLength; // 1.4512ms int g_iRingBufferSize = 2 * g_iTargetLatencySamples; int g_iSendingBlockLength = 8; double g_dClientStatusMessageTimeout = 0.001; // seconds string g_sFileName = "gershwin-mono.wav"; +bool g_bDebuggingEnabled = true; int main( int argc, char** argv ) { @@ -71,13 +73,20 @@ int main( int argc, char** argv ) ss << "_RB" << g_iRingBufferSize; ss << "_SB" << g_iSendingBlockLength; oStreamingServer.SetServerLogBaseName( ss.str() ); + oStreamingServer.SetDebuggingEnabled( g_bDebuggingEnabled ); oStreamingServer.SetInputStream( &oMuliplier ); oStreamingServer.SetTargetLatencySamples( g_iTargetLatencySamples ); oStreamingServer.SetSendingBlockLength( g_iSendingBlockLength ); cout << "Starting net audio server and waiting for connections on '" << g_sServerName << "' on port " << g_iServerPort << endl; - oStreamingServer.Start( g_sServerName, g_iServerPort, g_dClientStatusMessageTimeout ); + if( oStreamingServer.Start( g_sServerName, g_iServerPort, g_dClientStatusMessageTimeout ) ) + cout << "Client connected, sending samples." << endl; + else + { + cerr << "Connection failed or streaming refused, aborting." << endl; + return 255; + } while( !oStreamingServer.IsClientConnected() ) VistaTimeUtils::Sleep( 100 ); diff --git a/tests/NetAudio/ITANetAudioTest.cpp b/tests/NetAudio/ITANetAudioTest.cpp index 226a238d35c04148a9c2686478f756e06e021fe8..64001117daf63d1a8f4baddb9beb7bf945c5bf6b 100644 --- a/tests/NetAudio/ITANetAudioTest.cpp +++ b/tests/NetAudio/ITANetAudioTest.cpp @@ -1,9 +1,4 @@ -#include -#include -#include - #include -#include #include #include #include @@ -18,21 +13,25 @@ #include #include +#include +#include +#include + using namespace std; const static string g_sServerName = "localhost"; const static string g_sInputFilePath = "gershwin-mono.wav"; const static int g_iServerPort = 12480; const static double g_dSampleRate = 44100; -const static int g_iBlockLength = 32; +const static int g_iBlockLength = 512; const static int g_iChannels = 2; const static int g_iTargetLatencySamples = g_iBlockLength * 1; const static int g_iRingerBufferCapacity = g_iBlockLength * 5; const static double g_dDuration = 10.0f; const static double g_dSyncTimout = 0.001f; const static bool g_bUseASIO = true; -//const static string g_sAudioInterface = "ASIO4ALL v2"; -const static string g_sAudioInterface = "ASIO Hammerfall DSP"; +const static string g_sAudioInterface = "ASIO4ALL v2"; +//const static string g_sAudioInterface = "ASIO Hammerfall DSP"; class CServer : public VistaThread { @@ -40,6 +39,7 @@ public: inline CServer( const string& sInputFilePath ) { pStreamingServer = new CITANetAudioStreamingServer; + pStreamingServer->SetDebuggingEnabled( true ); pStreamingServer->SetTargetLatencySamples( g_iTargetLatencySamples ); pStreamingServer->SetServerLogBaseName( "ITANetAudioTest_Server" ); @@ -84,6 +84,7 @@ void run_test() // Client dumping received stream and mixing down to two channels CITANetAudioStream oNetAudioStream( g_iChannels, g_dSampleRate, g_iBlockLength, g_iRingerBufferCapacity ); oNetAudioStream.SetNetAudioStreamingLoggerBaseName( "ITANetAudioTest_Client" ); + oNetAudioStream.SetDebuggingEnabled( true ); ITAStreamPatchbay oPatchbay( g_dSampleRate, g_iBlockLength ); oPatchbay.AddInput( &oNetAudioStream );