How To install feed from your live stream in node-media-server.
Tags: javascript, mediaserver, nodemediaserver, node
Published: 2023-12-08 06:20:06


## Introduction:
In the dynamic world of digital content, live streaming has emerged as a powerful and engaging way to connect with audiences in real-time. Whether you're a content creator, educator, or simply someone looking to share experiences as they happen, setting up a reliable live streaming infrastructure is crucial. In this comprehensive guide, we'll walk you through the process of creating a Node Media Server, seamlessly pushing your live stream with FFmpeg, and even show you how to download the feed in the widely used HLS (HTTP Live Streaming) format.

## Prerequisites

1. Node.js : Make Sure to install the node.js in your system. If you do not already installed node.js then you can download from the link - {% embed https://nodejs.org/en/download %}

2. FFmpeg : Download the FFmpeg module in your pc. You can download FFmpeg from - {% embed https://ffmpeg.org/download.html %}

## Modules Used 

1. Node-Media-Server 

Node Media Server (NMS) is a powerful and extensible media server built on top of Node.js, a server-side JavaScript runtime. Developed to meet the demands of modern live streaming applications, NMS provides support for various streaming protocols, including Real-Time Messaging Protocol (RTMP), HTTP Live Streaming (HLS), and more.

You can download through vscode terminal by following command

```
npm install node-media-server
```

2. fluent-ffmpeg 

fluent-ffmpeg is a Node.js module that provides a fluent interface for working with FFmpeg. It allows developers to use FFmpeg capabilities in a more user-friendly and JavaScript-oriented manner, making it easier to construct complex multimedia processing pipelines.

You can download through vscode terminal by following command

```
 npm install fluent-ffmpeg 
```

3. Moment

Moment.js is a lightweight and versatile JavaScript library for parsing, validating, manipulating, and formatting dates and times. It simplifies working with dates in JavaScript, providing a consistent and user-friendly API for various date-related operations.

You can download through vscode terminal by following command
```
 npm install moment
```


Now We are all set to start our node-media-server project.


Step 1 : Configure our node-media-server.

First you need to import the node-media-server. By using 

``` 
const nms = require('node-media-server)
```

Then we need to write the configurations for node-media server

```
 const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 60,
    ping_timeout: 30,
  },
  http: {
    port: 8000,
    mediaroot: "./media",
    allow_origin: "*",
  },
};
```

These are the basic configurations for rtmp(real time messaging protocol) feed and hls(http live streaming) feed. The rtmp configs contains of the -

**port**

port number **1935** which is by default port number. You can change it to the available port number.

**chunk_size**

This parameter represents the size of the data chunks that will be used during streaming. Here, it is set to 60000 bytes. 
Here, **chunk_size: 60000** indicates that the server will use a chunk size of 60,000 bytes for RTMP streaming. Adjusting this value allows you to fine-tune the trade-off between latency, efficiency, and other factors based on the specific requirements of your streaming application. Different streaming platforms or protocols may have their own guidelines or default values for chunk sizes.

**gop_cache**

The Group of Pictures (GOP) is a key concept in video compression. It represents a group of consecutive frames in a video stream where the inter-frame compression is applied. The GOP structure typically consists of three types of frames: I-frames (keyframes), P-frames (predicted frames), and B-frames (bidirectional frames).

Setting gop_cache to true in the context of an RTMP server, such as with the configuration for node-media-server, means that the server will cache GOP frames. Caching GOP frames can have several benefits: Improved Seeking Performance, Reduce Bandwidth Usage, Stability in Video Playback.

**ping**

It sets the interval for sending ping messages to clients, in seconds. Here, it's set to 60 seconds.

**ping_timeout**

The timeout duration for ping responses from clients, in seconds. If a client doesn't respond within this timeout, it may be considered disconnected. Here, it's set to 30 seconds.

**http**

This configurations is for http live streaming it contains of -

**port**

Here also the port number is by default set to 8000 and we can change it as per our requirements

**mediaroot**

It is set to "./media" that means it indicates that the media files are expected to be located in the "./media" directory. The media server will serve content from this directory.

**For example** 

if you have a file named "video.mp4" in the "./media" directory, it would be accessible through the media server at a URL like http://localhost:8000/video.mp4.

So, the mediaroot setting allows you to define the base directory where your media files are stored, and the media server uses this information to serve content to clients or to incorporate it into a streaming workflow. This setting is crucial for the media server to know where to look for and serve media files.

**allow_origin**

It defines the value of the Access-Control-Allow-Origin header, which controls which domains can make requests to the server. Here, it's set to "*" which means any domain is allowed.


Now we need to make an instance of the node-media-server - 
```
const nms = new NodeMediaServer(config);
```

Now our node-media-server is set and now the second step is to download the feed on specific time-interval.

**Step : 2**

Take your static live url in a variable and set the directory in which you want to save your feed recordings - 

```
const inputURL = "Your RTMP url";
const outputDir = "./output/"; 
```

Now further going ahead check for the directory if it is already exist or not :- 

```
if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir);
}
``` 

Here the "fs"(file streaming) is an inbuilt module of node.js you only need to import it in your file :- 

```
 const fs = require('fs') 
```

**Step : 3**

Make a function which will save our recordings in our repository -

``` 
  function saveStream() {
  const epochTime = moment().format("HH_mm_ss");
  const outputFilename = `${outputDir}${epochTime}.m3u8`;

  ffmpeg(inputURL)
    .inputFormat("flv")
        .outputOptions([
        `-hls_segment_filename ${tsFileName}.ts`,        
        // "-hls_time 900",
        "-hls_time 30",
        "-hls_list_size 5",
        // "-t 900",
        "-t 30",
        "-f hls",
        ])
    .output(outputFilename)
    .on("end", () => {
      console.log(`Saved stream to ${outputFilename}`);
    })
    .on("error", (err) => {
      console.error("Error:", err);
    })
    .run();
}

saveStream();
```

This function will save our rtmp feed to our directory this function is simple. Firslty, we take the time when the streaming starts and make our recording file name.

```
  const epochTime = moment().format("HH_mm_ss");
  const outputFilename = `${outputDir}${epochTime}.m3u8`;
```

Then, we take the rtmp url and save it in the hls format using fluent ffmpeg module : 

```
  ffmpeg(inputURL)
    .inputFormat("flv")
    .outputOptions([
        "-hls_time 25",   
        "-hls_list_size 5",
        "-t 30",       
        "-f hls",
    ])
    .output(outputFilename)
    .on("end", () => {
      console.log(`Saved stream to ${outputFilename}`);
    })
    .on("error", (err) => {
      console.error("Error:", err);
    })
    .run();
```

this whole code will take the rtmp url and then it will convert it into hls format. The output format contains : 

**hls_time** - Sets the duration of each segment in the HLS playlist to 25 seconds.

**hls_list_size** - Sets the maximum number of playlist entries (segments) to 5.

**-t 30** - Set the duration of the feed which is getting saved(in seconds)

**-f hls** - It is specifying the output format as hls

Then we are saving the processed file in our directory with 

```
 .output(outputFilename)
```

Final part of the function is Event Handling when our processed output is getting saved in our file then it will give us a log otherwise it will throw an error.

```
.on("end", () => {
      console.log(`Saved stream to ${outputFilename}`);
    })
    .on("error", (err) => {
      console.error("Error:", err);
    })
```
Lastly Executing our ffmpeg command with -

```
.run()
```

After setting everything call the function and set the interval as per your requirements I set it on the 30sec of interval. (to save the memory give the interval as same as your output file duration)

```
saveStream();

setInterval(saveStream, 30000);
```

Lastly, Handle event of post publish. Post publish will trigger when the stream is starting on node-media-server. Here I gave a condition because I am giving static URL - 

```
nms.on('postPublish', (_, streamPath, _params) => {
  if (streamPath.endsWith('1efa24f9-0cd0-47c5-b604-c7e3ee118302')) {
    saveStream();
  }
});
```
Finally, Everything is all set now we can run our instance of node-meda-server so that it can run our script. From this our node-media-server will run.

```
nms.run();
```
Our final code will something like this -

```
const NodeMediaServer = require("node-media-server");
const fs = require("fs");
const moment = require('moment')
const ffmpeg = require("fluent-ffmpeg");

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 60,
    ping_timeout: 30,
  },
  http: {
    port: 8000,
    mediaroot: "./media",
    allow_origin: "*",
  },
};

const nms = new NodeMediaServer(config);

const inputURL =
  "rtmp://media5.ambicam.com:1938/live/1efa24f9-0cd0-47c5-b604-c7e3ee118302";
const outputDir = "./output/";

if (!fs.existsSync(outputDir)) {
  fs.mkdirSync(outputDir);
}

function saveStream() {
  const epochTime =  moment().format("HH_mm_ss"); 
  const outputFilename = `${outputDir}${epochTime}.m3u8`;

  ffmpeg(inputURL)
    .inputFormat("flv")
    .outputOptions([
        "-hls_time 25",   
        "-hls_list_size 5",
        "-t 30",       
        "-f hls",
    ])
    .output(outputFilename)
    .on("end", () => {
      console.log(`Saved stream to ${outputFilename}`);
    })
    .on("error", (err) => {
      console.error("Error:", err);
    })
    .run();
}

saveStream();

setInterval(saveStream, 30000);

nms.on('postPublish', (_, streamPath, _params) => {
  if (streamPath.endsWith('1efa24f9-0cd0-47c5-b604-c7e3ee118302')) {
    saveStream();
  }
});

nms.run();

```

**Conclusion**

In this tutorial, we embarked on a journey to set up a basic Node Media Server (NMS) instance, catering to beginners in the realm of video streaming. We covered the essentials from installing the node-media-server package to configuring a simple server instance capable of handling video streams.

One of the highlights of our exploration was the introduction of a straightforward mechanism to save video feeds at specific time intervals. This feature adds an extra layer of functionality to your streaming setup, enabling you to capture and store your content for future reference or archival purposes.