Develop an SRT client and server in Node.js

Eyevinn Technology
4 min readJun 30, 2020

--

In the previous blog post we presented our contribution back to the SRT Alliance by providing a native addon to support Secure Reliable Transport protocol in Node.js. Based on these SRT SDK bindings we can provide a higher abstraction layer to the protocol with custom Readable and Writable streams in Node.js. In this post we will describe a sample client / server implementation based on the NPM library @eyevinn/srt.

Create a new Node.js project:

npm init

You can call it for example my-project and use defaults for the remaining options.

Install the NPM library providing the SRT SDK bindings.

npm install --save @eyevinn/srt

This will download the SRT SDK source code and compile locally on your computer. The compiled version of the SDK library is then found in the directory ./node_modules/@eyevinn/srt/deps/build/ and this is also where you find the include files etc. Be aware that if you already have the SRT SDK installed on your computer the NPM library is built against the downloaded version and not the one globally installed on your computer.

The Server

Once downloaded and installed we will create a new Javascript file that we call server.js. Open you favorite editor and type in the following:

const fs = require('fs');
const dest = fs.createWriteStream('./output');
const { SRTReadStream } = require('@eyevinn/srt');
const srt = new SRTReadStream('0.0.0.0', 1234);
srt.listen(readStream => {
console.log("Client connected");
readStream.pipe(dest);
});
srt.on('end', () => {
console.log("Client disconnected");
});
console.log("Waiting for client to connect");

Let’s break this up and explain what each line does.

const fs = require('fs');
const dest = fs.createWriteStream('./output');

These two lines will create a Node.js writable stream where the data is written to disk and a file we call ‘output’.

const { SRTReadStream } = require('@eyevinn/srt');

The above line exposes the SRTReadStream class which is a custom readable stream that provides a high level layer to the low-level SRT SDK. This custom readable stream is purely developed in Javascript and uses the low-level bindings. Nothing prevents you from using the low-level functions as described in the previous post if you want to. This is to provide an API for application developers not necessarily interested in the details of the SRT SDK.

const srt = new SRTReadStream('0.0.0.0', 1234);
srt.listen(readStream => {
console.log("Client connected");
readStream.pipe(dest);
});

When creating an object from the SRTReadStream class you only need to provide what interface and port to bind the SRT server socket to. When a client connects a Readable stream for this connection is returned. This is like any type of Readable stream where you for example can pipe the output to another stream. And as in our example here we will pipe the data to the Writable stream that writes the data to the file ‘output’.

The Client

Now let us create the client. Open a file that we name client.js and insert the following code.

const fs = require('fs');
const source = fs.createReadStream(process.argv[2], { highWaterMark: 1316 });
const { SRTWriteStream } = require('@eyevinn/srt');
const srt = new SRTWriteStream('127.0.0.1', 1234);
srt.connect(writeStream => {
source.pipe(writeStream);
});
process.on('SIGINT', () => {
console.log("Closing connection");
srt.close();
});

This looks very familiar to the server code, and yes it is, but instead of opening a Readable SRT stream we will open a Writable SRT stream.

const fs = require('fs');
const source = fs.createReadStream(process.argv[2], { highWaterMark: 1316 });

Instead of now writing to a file we will read a file from disk that we will send over the SRT line to the server we created. We provide the filename as the second argument and limit the chunksize, in this case, to 1316. 1316 is 7 times the size of an MPEG-TS packet which is a suitable number if it is MPEG-TS framed data to transport. In this example it doesn’t really matter but is useful when you want to interpret the data on the server side. Something we will describe in another blog post.

const srt = new SRTWriteStream('127.0.0.1', 1234);
srt.connect(writeStream => {
source.pipe(writeStream);
});

So, now let us connect to the server, that we will assume in this case is running on the same computer. The realistic use case is of course that the server is sitting somewhere else on the Internet. An exercise left to the reader. Once a connection is established we get a customable Writable stream that we can pipe data to. We will use the Readable filesystem stream that we created. And to gracefully be able to abort the transfer we just add the following interrupt handler:

process.on('SIGINT', () => {
console.log("Closing connection");
srt.close();
});

Now everything is in place, let us try this out. Open a terminal window where you start the server:

$ node server.js
Waiting for client to connect

And then open another terminal window where you start the client

$ node client.js FILE.mp4

And voila! You now have transferred media using Secure Reliable Transport with code written in Node.js.

This blog was provided by an Eyevinn Video-Dev Team, and if you have any further questions and comments on this post drop a comment below or tweet the post author on Twitter (@JonasBirme).

Eyevinn Technology is leading specialists in video technology and media distribution, and proud organizer of the yearly nordic conference Streaming Tech Sweden.

--

--

Eyevinn Technology

We are consultants sharing the passion for the technology for a media consumer of the future.