TCP Writer


  • Plugin name : TCP Writer
  • Version : 0.2
  • Author : Jussi T. Lindgren
  • Company : Inria
  • Short description : Send input stream out via a TCP socket
  • Documentation template generation date : Jan 9 2018


This box works as a TCP server that writes its input stream out to a TCP socket with minimal header information and encoding.

The main motivation for this box is to allow external applications to receive information in a simple manner from OpenViBE without requiring unusual dependencies such as VRPN.


1) If the outputs of the box are raw numeric values, the box first sends every connecting client eight variables of uint32: format version number (in network byte order), endianness of the stream (in network byte order, 0==unknown, 1==little, 2==big, 3==pdp), sampling frequency of the signal, the number of channels, the number of samples per chunk and three variables of padding, 8*4=32 bytes in total. The last 6 variables are in the byte order of the stream. Note that only those variables will be non-zero that are meaningful for the input in question.

Header layout as a table,

| Name                | Type          | Bytes from start |
| ------------------- | ------------- | ---------------- |
| Format version      | uint32        | 0                |
| Endianness          | uint32        | 4                |
| Sampling frequency  | uint32        | 8                |
| Number of channels  | uint32        | 12               |
| Samples per chunk   | uint32        | 16               |
| Reserved0           | uint32        | 20               |
| Reserved1           | uint32        | 24               |
| Reserved2           | uint32        | 28               |

1b) If the output is chosen as hex string or descriptive string (these are valid for Stimulation input only), no header is sent.

2) After the possible global header, the data itself is sent. The data is a stream of float64 chunks for Signal and StreamedMatrix. Each chunk is a matrix [nChannels x nSamples], sent in row-major order, i.e. all samples for one channel are sent in a sequence (a row), then all samples of the next channel (next row), and so on. This is the same order that OpenViBE uses internally for signal chunks.

Signal/matrix data layout as a table (k = nSamples, n = nChannels),

| Name                  | Type          | Bytes from start   |
| --------------------  | ------------- | ------------------ |
| Channel 1, sample 1   | float64       | 32 + (k*0+0)*8     |
| Channel 1, sample 2   | float64       | 32 + (k*0+1)*8     |
| ...                   | ...           | ...                |
| Channel 1, sample k   | float64       | 32 + (k*0+(k-1))*8 | 
| Channel 2, sample 1   | float64       | 32 + (k*1+0)*8     |
| Channel 2, sample 2   | float64       | 32 + (k*1+1)*8     |
| ...                   | ...           | ...                |
| Channel 1, sample k+1 | float64       | 32 + (k*n+0)*8     |
| ...                   | ...           | ....               |

For Stimulations, the data is a sequence of uint64 if the user chooses raw output, or char strings otherwise.

Multiple clients can connect to the socket of the box. The box keeps sending data to each client until either the scenario is stopped or that client disconnects. When kernel calls box::process() at time t, all clients connected before or at t, get forwarded the chunks that are pending in box::process() at time t. Note that the information how long time has elapsed between the acquisition or scenario startup and the client connection is not currently relayed by TCP Writer.


1. Input 1

The supported input stream types are StreamedMatrix, Signal and Stimulations. The stream type of the input can be changed by the user.

  • Type identifier : Streamed matrix (0x544a003e, 0x6dcba5f6)


1. Port

Port denotes the TCP port that will accept the client connections. Default is 5678.

  • Type identifier : Integer (0x007deef9, 0x2f3e95c6)
  • Default value : [ 5678 ]

2. Output format

If the input is Stimulations, this setting can change the format the stimulations are sent in to the TCP socket. The choices are raw uint64, hex string, or a descriptive string. For other inputs, this setting is ignored.

  • Type identifier : Raw output (0x77d3e238, 0xb954ec48)
  • Default value : [ Raw ]


There is an example application 'openvibe-examples-openvibe-to-tcpip' that can be used to receive data from this box. The application is intended to be used together with the 'tcp-writer.xml' box tutorial.

Another way to test the box is to connect to the socket of the box with a 'telnet' application and redirect the telnet output to a file.

It is also possible to use Acquisition Server's Generic Raw Telnet Reader to read data from the box. In that case, set Start Skip to 32 and header and footer skips to 0, and data format to float64. Remember to also set the number of channels and the sampling frequency correctly. This information is not read from the stream by the Generic Raw Telnet Reader.


The box performs no little-endian/big-endian conversions. The data is sent raw in the native format of the host system. The host endianness is encoded into the sent header.

The box sends signal data as chunks with the same chunk size as the stream has.

The box supports only 2 dimensional matrices. To send 1 dimensional matrix, you can try to upgrade it to 2 dimensions with Matrix Transpose box. The box cannot be used to send more than 2 dimensions presently.

The box writes to all the sockets synchronously in the process() call and drops no data. If the connection is too slow to accommodate the data flow, the box will lag.

Detected transmission errors will cause a disconnection of the client.

Streamed Matrix can be recognized from the TCPWriter header by the sampling rate 0. If the stream is a signal, the sampling rate is a positive number. Raw stimulation streams have channel and sample counts per buffer 0 as well.

Known issues: Note that it can be difficult to time-synchronize signals and stimulations exactly on the client side when the client receives data from two TCP Writer boxes. Maintaining such synchronization was not a design goal of this box. If you need synchronized streams, it is advised to build the connection with LabStreamingLayer: Use LSL Export box and include LSL support in the client.