ITANetAudioStream.h 8.49 KB
Newer Older
1 2 3 4 5
/*
 * ----------------------------------------------------------------
 *
 *		ITA core libs
 *		(c) Copyright Institute of Technical Acoustics (ITA)
6
 *		RWTH Aachen University, Germany, 2015-2017
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 * ----------------------------------------------------------------
 *				    ____  __________  _______
 *				   //  / //__   ___/ //  _   |
 *				  //  /    //  /    //  /_|  |
 *				 //  /    //  /    //  ___   |
 *				//__/    //__/    //__/   |__|
 *
 * ----------------------------------------------------------------
 *
 */

#ifndef INCLUDE_WATCHER_ITA_NET_AUDIO_STREAM
#define INCLUDE_WATCHER_ITA_NET_AUDIO_STREAM

#include <ITADataSourcesDefinitions.h>

#include <ITADataSource.h>
#include <ITASampleFrame.h>

#include <string>
#include <vector>
29

30

31
class CITANetAudioStreamingClient;
32 33
class ITABufferedDataLoggerImplStream;
class ITABufferedDataLoggerImplNet;
34
class ITABufferedDataLoggerImplAudio;
35 36 37

//! Network audio stream
/**
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
38
  * Audio streaming for a signal source that is connected via TCP/IP or UDP.
39 40 41 42 43 44 45
  * The network audio stream behaves like a client and receives samples
  * from a network audio stream server, CITANetAudioStreamingSearver.
  * 
  * The stream will always work within a streaming context and will never
  * 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
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
46
  * overruns, the sample server will be suspended by blocking the network
47 48
  * data flow.
  *
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
49 50 51 52
  * 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.
53 54 55
  *
  * \note not thread-safe
  */
56
class ITA_DATA_SOURCES_API CITANetAudioStream : public ITADatasource
57 58
{
public:
59
	//! Constructor of a network audio stream
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
60 61 62 63 64 65 66 67 68 69 70 71 72
	/**
	  * @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.
	  */
73
	CITANetAudioStream( int iChannels, double dSamplingRate, int iBufferSize, int iRingBufferCapacity = 2048 );
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
74

75 76
	virtual ~CITANetAudioStream();

77
	//! Network streaming status of client
78 79
	enum StreamingStatus
	{
80 81 82 83
		INVALID = -1, //!< Invalid status, for exception detection
		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, //!< 
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
84 85
		BUFFER_UNDERRUN, //!< Client internal audio buffer ran out of samples
		BUFFER_OVERRUN, //!< Client internal audio ring buffer is full
86 87
	};

88 89
	//! Connect a streaming server
	/**
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
90
	  * @sAddress[in] Server address IP (127.0.0.1, localhost, etc.)
91
	  * @iPort[in] Server socket port, defaults to 12480
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
92
	  * @return True, if connection could be established and streaming parameters match
93 94 95
	  */
	bool Connect( const std::string& sAddress, int iPort = 12480 );

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
96
	//! Disconnct safely from server
97 98
	void Disconnect();

99 100 101 102
	//! Returns the connection status
	/**
	  * @return True, if connected
	  */
103
	bool GetIsConnected() const;
104

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
105
	//! Returns the minimal latency possible (single block)
106
	/**
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
107
	  * @return Minimum latency in seconds
108
	  */
109
	float GetMinimumLatencySeconds() const;
110

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
111 112 113 114
	//! Returns the maximum latency possible (entire ring buffer used)
	/**
	  * @return Maximum latency in seconds
	  */
115
	float GetMaximumLatencySeconds() const;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
116 117 118 119 120
	
	//! Returns the minimum latency possible (single block)
	/**
	  * @return Minimum latency in samples
	  */
121
	int GetMinimumLatencySamples() const;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
122 123 124 125 126

	//! Returns the maximum latency possible (entire ring buffer used)
	/**
	  * @return Maximum latency in samples
	  */
127 128
	int GetMaximumLatencySamples() const;

Jonas Stienen's avatar
Jonas Stienen committed
129 130 131 132
	//! Returns the NetAudio streaming logger base name
	std::string GetNetAudioStreamLoggerBaseName() const;

	//! Sets the NetAudio streaming logger base name
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
133 134 135 136 137 138
	/**
	  * If debugging is enabled, all debugging files will be named
	  * with this suffix.
	  * @param[in] sBaseName Base name string
	  * 
	  */
Jonas Stienen's avatar
Jonas Stienen committed
139
	void SetNetAudioStreamingLoggerBaseName( const std::string& sBaseName );
140

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
141
	//! Enabled/disables export of loggers
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
142
	void SetDebuggingEnabled( bool bEnabled );
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
143 144

	//! Logging export flag getter
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
145
	bool GetIsDebuggingEnabled() const;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
146

147
	//! Returns (static) size of ring buffer
148 149 150
	/**
	  * @return Number of maximum samples that can be hold by internal ring buffer
	  */
151
	int GetRingBufferSize() const;
152 153

	//! Returns true if ring buffer is full
154 155 156
	/**
	  * @return True, if ring buffer full (down to the last sample, not smaller that block size)
	  */
157 158 159
	bool GetIsRingBufferFull() const;

	//! Returns true if ring buffer is empty
160 161 162
	/**
	  * @return True, if ring buffer empty (down to the last sample, not smaller that block size)
	  */
163
	bool GetIsRingBufferEmpty() const;
164
	
165
	//! Returns block size
166
	unsigned int GetBlocklength() const;
167 168

	//! Returns number of channels
169
	unsigned int GetNumberOfChannels() const;
170 171

	//! Returns sampling rate
172
	double GetSampleRate() const;
173 174 175 176 177 178

	//! Audio streaming block read for a given channel
	/** 
	  * This method is called by the streaming context for each channel, also providing stream infos.
	  * It copies samples out of the ring buffer, but does not touch the read/write cursors.
	  */
179
	const float* GetBlockPointer( unsigned int uiChannel, const ITAStreamInfo* );
180 181 182 183 184 185 186 187 188
	
	//! Audio streaming block increment
	/**
	  * This method updates the read curser and forwards it by one block. This operations
	  * frees samples out of the ring buffer. It also triggersan event
	  * to indicate that the ring buffer readable sample number has been decreased.
	  * Depending on the network streaming settings, the trigger will be forwarded
	  * to the server to inform about the number of free samples, that can be re-filled.
	  */
189 190
	void IncrementBlockPointer();

Jonas Stienen's avatar
Jonas Stienen committed
191

192
protected:
193
	//! This method is called by the networkg client and pushes samples into the ring buffer
194
	/**
195 196 197 198
	  * If samples fit ring buffer, the rite curser will be increased by iNumSamples, hence
	  * the number of free (writable) samples decreases.
	  *
	  * @param[in] sfNewSamples Sample frame with new samples to be appended to the ring buffer
199 200
	  * \param iNumSamples samples to be read from the sample frame (must be smaller or equal length)
	  *
201 202 203
	  * @return Number of free samples in ring buffer
	  *
	  * @note This method is not called out of the audio streaming context but out of the network context.
204
	  */
205 206
	int Transmit( const ITASampleFrame& sfNewSamples, int iNumSamples );

207 208 209 210 211 212
	//! Returns samples that can be read from ring buffer
	/**
	* @return Readable samples between read and write cursor.
	*/
	int GetRingBufferAvailableSamples() const;

213
	//! Returns free samples between write and read cursor
214 215 216
	/**
	* @return Free samples between write and read cursor.
	*/
217
	int GetRingBufferFreeSamples() const;
218

219 220 221
	//! Returns a string for the streaming status identifier
	static std::string GetStreamingStatusString( int iStreamingStatus );

222
private:
223
	CITANetAudioStreamingClient* m_pNetAudioStreamingClient; //!< Audio streaming network client
224

225 226
	double m_dSampleRate; //!< Sampling rate
	ITASampleFrame m_sfOutputStreamBuffer; //!< Output samples temp buffer (audio context)
227 228

	int m_iReadCursor; //!< Cursor where samples will be consumed from ring buffer on next block
229 230
	int m_iWriteCursor; //!< Cursor where samples will be fed into ring buffer from net audio producer (always ahead)
	bool m_bRingBufferFull; //!< Indicator if ring buffer is full (and read cursor equals write cursor)
231
	ITASampleFrame m_sfRingBuffer; //!< Ring buffer
232

233
	int m_iStreamingStatus; //!< Current streaming status
234
	double m_dLastStreamingTimeCode;
235

Jonas Stienen's avatar
Jonas Stienen committed
236 237 238
	ITABufferedDataLoggerImplStream* m_pAudioStreamLogger; //!< Logging for the audio stream
	ITABufferedDataLoggerImplNet* m_pNetworkStreamLogger; //!< Logging for the network stream
	std::string m_sNetAudioStreamLoggerBaseName;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
239
	bool m_bDebuggingEnabled;
Jonas Stienen's avatar
Jonas Stienen committed
240

241 242
	int m_iAudioStreamingBlockID; //!< Audio streaming block id
	int m_iNetStreamingBlockID; //!< Network streaming block id
243 244
	
	friend class CITANetAudioStreamingClient;
245 246 247
};

#endif // INCLUDE_WATCHER_ITA_NET_AUDIO_STREAM