RTCP stream in HTML throught WebSocket
Published: 2021-07-31 17:32:03

In this article we will create an application that will output the RTCP stream to an HTML page

To convert video we will use the [node-rtsp-stream](https://github.com/kyriesent/node-rtsp-stream) server, it will convert **RTCP** to **MPEG1** and pass the result to **WebSocket**. Internally it uses [ffmpeg](https://ffmpeg.org/) so you will need to install it

We will use [jsmpeg](https://github.com/phoboslab/jsmpeg) to display the video on the page

Download [minified version of jsmpeg](https://github.com/phoboslab/jsmpeg/blob/master/jsmpeg.min.js) and put it in the _libs_ folder next to the _index.html_ file

Also to change the link to the stream we need [Express](https://github.com/expressjs/express)

![Architecture overview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zjb7gwz3n2syslhlelg8.png)

So we need to implement a server on **Node.js** which will, at the request of the client, start the transformation of the stream and response with a link as a result

## Implementing the server

Create a folder where the server will be stored and install the dependencies

```bash
mkdir socket-server && cs socket-server
npm init -y
npm i node-rtsp-stream express cors
```

Let’s write code in which we will create an **express** application with the */start* route, which when called will create a new instance of the streaming server with a given link to the stream

```javascript
const express = require('express')
const cors = require('cors')
const Stream = require('node-rtsp-stream')

const app = express()

app.use(cors())
app.use(express.json())

const port = 3000
const wsPort = 9999

let stream = null

app.post('/start', function (req, res) {
  if (stream !== null) {
    stream.stop()
    stream = null
  }

  const { streamUrl } = req.body

  try {
    stream = new Stream({
      name: 'videoStream',
      streamUrl: streamUrl,
      wsPort: wsPort,
      ffmpegOptions: {
        '-stats': '',
        '-r': 30,
      },
    })
    res.json({ url: `ws://127.0.0.1:${wsPort}` })
  } catch (e) {
    console.error(e)
  }
})

app.listen(port, () => {
  console.log(
    `server listening commands at http://127.0.0.1:${port} and serve stream at ws://127.0.0.1:${wsPort}`
  )
})
```

### Run the server

```bash
node index.js
server listening commands at http://127.0.0.1:3000
```

The server started successfully, to start the broadcast you need to send a **POST** request with a link to the stream to the address _http://127.0.0.1:3000/start_

## Implementing the client

Create a simple _index.html_ file where we’ll add a container for embedding the video stream. The entry field for the link to the **RTCP** stream and the button to start playing a new stream, as well as don’t forget to connect _jsmpeg_ to play the video and _index.js_, which will contain all the logic

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="css/main.css" />
    <title>Video Stream</title>
  </head>
  <body>
    <div id="container" class="player">
      <div id="video-container" class="video"></div>
      <div class="stream-input">
        <input
          id="stream-url-input"
          type="text"
          name="stream-url-input"
          value="rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov"
          placeholder="stream url"
        />
        <input id="stream-play-btn" type="button" value="Play" />
      </div>
    </div>
  </body>
  <script type="text/javascript" src="libs/jsmpeg.min.js"></script>
  <script type="text/javascript" src="js/index.js"></script>
</html>
```

### Write the logic

When the _Play_ button pressed, send a request with the _streamUrl_ parameter to _/start_ route of our server, upon receiving a reply we create a player that plays the video with the link given by the server response

```js
;(function () {
  let jsmpegPlayer
  const streamInput = document.getElementById('stream-url-input')
  const playBtn = document.getElementById('stream-play-btn')
  const videoContainer = document.getElementById('video-container')

  playBtn.onclick = () => {
    const streamUrl = streamInput.value
    fetch('http://127.0.0.1:3000/start', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json;charset=utf-8',
      },
      body: JSON.stringify({ streamUrl }),
    })
      .then((response) => response.json())
      .then((data) => {
        if (jsmpegPlayer) {
          jsmpegPlayer.stop()
          jsmpegPlayer.destroy()
        }

        const canvas = document.createElement('canvas')
        canvas.id = 'jsmpeg-player'
        videoContainer.app(canvas)

        jsmpegPlayer = new JSMpeg.Player(data.url, {
          canvas,
          autoplay: true,
        })
      })
  }
})()
```

## Try!

![Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p4g9zurdtaifd95k8uyi.gif)

As you can see the streaming video appears with a pretty long delay, about 12 seconds. This may be enough, but if you want to reduce the delay of the stream and get closer to real time read the next article in which we will try to reduce that delay

**Complete code** can be found on [GitHub](https://github.com/Gerpea/rtcp-stream-app)