In this article we explain how to set up multi-user WebRTC video broadcasting from a browser via your own rebroadcasting server. We will broadcast from the Google Chrome browser and a usual USB web camera. To broadcast the video we create a Streamer HTML page, and for playback we make a Player HTML page.

Broadcast diagram

Browser1 – broadcaster. It connects to the server and broadcasts the video from the web camera.
Browser2, Browser3, Browser4 – spectators. They connect and receive the video for playback. To rebroadcast video streams via WebRTC we use Web Call Server.

Broadcast-diagram

The idea is clear, so let’s start writing the code. We create two HTML pages. The first is streamer.html, it will send a video stream to the server. The second is player.html, it will play the stream from the server.

Streamer – HTML

<html>
<head>
   <script language="javascript" src="https://flashphoner.com/downloads/builds/flashphoner_client/wcs_api-2.0/current/flashphoner.js"></script>
</head>
<body onLoad="init()">
<h1>The streamer</h1>
<div id="localVideo" style="width:320px;height:240px;border: 1px solid"></div>
<input type="button" value="start" onClick="start()"/>
<p id="status"></p>
</body>
</html>

The template of the Streamer html page uses the following fragments:

1) The flashphoner.js script

This script is the main script of the JavaScript API. You can find it in the last build of the Web SDK.

<script type="text/javascript" src="https://flashphoner.com/downloads/builds/flashphoner_client/wcs_api-2.0/current/flashphoner.js"></script>

2) The localVideo div element is a block where the video captured from the web camera is displayed.

<div id="localVideo" style="width:320px;height:240px;border: 1px solid"></div>

3) The Start button that runs broadcasting by invoking the start() function.

<input type="button" value="start" onClick="start()"/>

4) Pay attention: the body tag has the onLoad handler that invokes the initialization function.

<body onLoad="init()">

5) The element with id = status is used to display statuses.

<p id="status"></p>

Streamer – JavaScript

Now, to the JavaScript code. We deliberately do not use JQuery, Bootstrap or any other frameworks to keep the code minimalistic:

var localVideo;
  
function init(){
   Flashphoner.init();
   localVideo = document.getElementById("localVideo");
}
  
function start() {
   Flashphoner.createSession({urlServer: "wss://wcs5-eu.flashphoner.com:8443"}).on(Flashphoner.constants.SESSION_STATUS.ESTABLISHED, function (session) {
       //session connected, start streaming
       startStreaming(session);
   }).on(Flashphoner.constants.SESSION_STATUS.DISCONNECTED, function () {
       setStatus("DISCONNECTED");
   }).on(Flashphoner.constants.SESSION_STATUS.FAILED, function () {
       setStatus("FAILED");
   });
}
  
function startStreaming(session) {
   session.createStream({
       name: "stream222",
       display: localVideo,
       cacheLocalResources: true,
       receiveVideo: false,
       receiveAudio: false
   }).on(Flashphoner.constants.STREAM_STATUS.PUBLISHING, function (publishStream) {
       setStatus(Flashphoner.constants.STREAM_STATUS.PUBLISHING);
   }).on(Flashphoner.constants.STREAM_STATUS.UNPUBLISHED, function () {
       setStatus(Flashphoner.constants.STREAM_STATUS.UNPUBLISHED);
   }).on(Flashphoner.constants.STREAM_STATUS.FAILED, function () {
       setStatus(Flashphoner.constants.STREAM_STATUS.FAILED);
   }).publish();
}
  
function setStatus(status) {
   document.getElementById("status").innerHTML = status;
}

This example has as few as four functions:

1) init

Initializes the JavaScript API and retrieves a link to the localVideo div element.

2) start

This function establishes connection to the server via the websockets protocol. Connection address is: wss://domain:8443, where domain is the domain name of your WCS server (we assume the server is already installed, configured and has a dedicated domain, for instance webrtc.mycompany.com. The port TCP 8443 must be open for incoming connections).

From the code of this function is evident that the next action after we receive the ESTABLISHED status is calling for the startStreaming function and sending the stream to the server.

3) startStreaming

Here, we create a new Stream object using the API function: session.createStream();. When creating a stream the following parameters are passed:

  • streamName – the name of a video stream
  • display – the div element where the video captured for this stream from the web camera should display

The unique name for a stream is recommended, but for the sake of testing we simply use stream222.

4) setStatus

This function displays the session status or the stream status on the HTML page.

Let’s put the script into a separate file named streamer.js. The code of streamer.html now looks as:

<html>
<head>
   <script language="javascript" src="https://flashphoner.com/downloads/builds/flashphoner_client/wcs_api-2.0/current/flashphoner.js"></script>
   <script language="javascript" src="streamer.js"></script>
</head>
<body onLoad="init()">
<h1>The streamer</h1>
<div id="localVideo" style="width:320px;height:240px;border: 1px solid"></div>
<input type="button" value="start" onClick="start()"/>
<p id="status"></p>
</body>
</html>

Streamer – testing

Finally, we’ve got a mini streaming application that consists of three scripts:

  • streaming.html
  • streaming.js
  • flashphoner.js

To start testing, we copy our scripts to the web server. We use Apache 2 with typical /var/www/html as a web server.

As a result, our working streamer looks as shown on the screenshot below. After clicking the Start button, a connection is established to the server, and the WebRTC video stream is sent to the server:

Streamer_testing

To make sure the stream is indeed sent, switch to the chrome://webrtc-internals tab. Here, we can watch in real-time what happens to the video stream, and trace such parameters as bitrate, resolution, frame rate, packers sent, RTT and many others.

testing_streamer

So, our streamer is working, and the WebRTC video stream is being sent to the server correctly. Now we can fetch it from there. To receive and play the stream, we create a new page, player.html

Player – HTML

The player page source can be copy-pasted from the streamer except that we will use the player.js script instead of streamer.js, and instead of localVideo, we set id = remoteVideo to our div element.

<html>
<head>
   <script language="javascript" src="https://flashphoner.com/downloads/builds/flashphoner_client/wcs_api-2.0/current/flashphoner.js"></script>
   <script language="javascript" src="player.js"></script>
</head>
<body onLoad="init()">
<h1>The player</h1>
<div id="remoteVideo" style="width:320px;height:240px;border: 1px solid"></div>
<input type="button" value="start" onClick="start()"/>
<p id="status"></p>
</body>
</html>

Player – JavaScript

The script of the player has some differences, but the approach is still the sameL we initialize the Flashphoner API, and when the Start button is clicked, a connection is established to the server via the websocket protocol. Then, we wait for the ESTABLISHED event and play the stream.

Here is the list of differences between player.js and streamer.js:

remoteVideo is used instead of localVideo

  • After establishing connection start
  • Playback is invoked instead of startStreaming
  • When creating the stream using the createStream() method we pass receiveAudio=true and receiveVideo=true parameters
  • We invoke the play() method instead of publish()
var remoteVideo;
  
function init(){
   Flashphoner.init();
   remoteVideo = document.getElementById("remoteVideo");
}
  
function start() {
   Flashphoner.createSession({urlServer: "wss://wcs5-eu.flashphoner.com:8443"}).on(Flashphoner.constants.SESSION_STATUS.ESTABLISHED, function (session) {
       //session connected, start streaming
       startPlayback(session);
   }).on(Flashphoner.constants.SESSION_STATUS.DISCONNECTED, function () {
       setStatus("DISCONNECTED");
   }).on(Flashphoner.constants.SESSION_STATUS.FAILED, function () {
       setStatus("FAILED");
   });
}
  
function startPlayback(session) {
   session.createStream({
       name: "stream222",
       display: remoteVideo,
       cacheLocalResources: true,
       receiveVideo: true,
       receiveAudio: true
   }).on(Flashphoner.constants.STREAM_STATUS.PLAYING, function (playStream) {
       setStatus(Flashphoner.constants.STREAM_STATUS.PLAYING);
   }).on(Flashphoner.constants.STREAM_STATUS.STOPPED, function () {
       setStatus(Flashphoner.constants.STREAM_STATUS.STOPPED);
   }).on(Flashphoner.constants.STREAM_STATUS.FAILED, function () {
       setStatus(Flashphoner.constants.STREAM_STATUS.FAILED);
   }).play();
}
  
function setStatus(status) {
   document.getElementById("status").innerHTML = status;
}

As a result, we receive a WebRTC player consisting of two scripts:

  • player.html
  • player.js

Don’t forget that for the player to operate it also needs the flashphoner.js API file, so we copy player file to the same folder on the server.

Finally, our application for WebRTC online broadcasting consists of five files:

  • streamer.html
  • streamer.js
  • player.html
  • player.js
  • flashphoner.js

Let’s get back to testing and send a video stream with streamer.html again. After that, open a new browser tab with player.html in it and click Start.

Player_HTML

So, the broadcast is successful – we have received a WebRTC video stream to the player. Now we can connect to the same video stream from other devices or simply open multiple browser tabs each fetching the same video stream.

HTML_player

So we have sent a video stream to the server and shared as “one-to-many”. Put simply, we implemented a very simple multi-connection video broadcasting.

3 minutes

Let’s try to deploy a video broadcasting in 3 minutes assuming that:

1) We have Web Call Server 5 to rebroadcast video streams already installed and SSL is configured. Without properly configured SSL / HTTPS, broadcasting will not work in Google Chrome , because the access to web camera and microphone must be secure, and the page where you test the broadcasting must be opened via HTTPS. Port TCP 8443 is open and ready to accept connections via the wss:// protocol.

2) Am HTTP server, for example Apache, is already installed and configured. The web server is configured to work via HTTPS and has FTP/SFTP/SSH access to upload and download test scripts.

WCS5 and Apache can be installed on the same system or on different servers. Apache simply returns content as HTML pages and scripts, and WCS5 services video connections.

To run testing without installing anything, you can use the demo server at wss://wcs5-eu.flashphoner.com:8443 – it is open for connects and testing.

Minute 1

Upload test scripts and unpack to the /var/www/html folder on the web server.

wget https://flashphoner.com//downloads/examples/webrtc-broadcasting-example-0.5.15.1977.2088.tar.gz
tar -xzf webrtc-broadcasting-example-0.5.15.1977.2088.tar.gz

Minute 2

Open streamer.js and player.js scripts for editing, find and replace:

wss://wcs5-eu.flashphoner.com:8443

to

wss://domain.com:8443

where domain.com is the domain name of your server where WCS5 is installed

Minute 3

Open streamer.html in a browser via https:// and click Start. Open player.html in a new tab and click Start.

Web camera broadcasting is ready. Now, you can make changes to the examples and test many-to-many publishing of multiple streams from streamers and subsequent broadcasting of them to players.

References

  1. Initial installing and configuring of Web Call Server 5
  2. Web SDK for WCS5
  3. Download the source code of the broadcasting example
  4. WebRTC statistics in chrome://webrtc-internals

Web Call Server 5 is a streaming media server that supports WebRTC, RTMP and other protocols to develop web applications and mobile applications with low latency video. The server includes Web SDK, Android SDK and iOS SDK to develop cross-platform video chats, online video broadcasts, IP camera broadcasts and other streaming video applications for browsers and mobile devices.