The biggest benefit of server side recording is while the video is recording and due to any reason the client browser closed or client got disconnected, the video which was recorded till the time was saved on server and we do not loose those footage.
Another reason about choosing server side recording is minimizing the process of uploading / saving video on server after recording it from browser. WebRTC capable for recording video on browser but after recording video another step take place which is uploading that video to server. Solution of recording video on server side removed that step.
To do it there are a media server required so web app directly get connected to media server and record video. Kurento I found as easiest solution for creating media server. I used my ubuntu VM as media server by installing Kurento.
You can check out the steps of making a ubuntu server to media server with Kurento here: Install Kurento in Ubuntu to create Media Server
Now to demonstrate I have create a test app, which you can can see on GitHub: GitHub – WebRTC Server Side Video Recording
Pre-Requirements
There are some pre-requirements to run this code.
- Node.js
- Bower
- Kurento Media Server (Create your own: Install Kurento in Ubuntu to create Media Server)
Install http-server
http-server is a simple, zero-configuration command-line http server. It is powerful enough for production usage, but it’s simple and hackable enough to be used for testing, local development, and learning.
npm install http-server -g
Bower File
Now create bower file with name “bower.json”
{
"name": "webrtc-server-side-video-recording-kurento",
"homepage": "https://github.com/ankur2194/webrtc-server-side-video-recording-kurento",
"description": "An Application which is recording video directly from web (browser) to server (Kurento Media Server) -- Testing App",
"main": "index.html",
"keywords": [
"webrtc",
"video",
"recording",
"kurento",
"server-side-recording"
],
"authors": [
"Ankur Patel <ankur2194@gmail.com>"
],
"repository": {
"type": "git",
"url": "https://github.com/ankur2194/webrtc-server-side-video-recording-kurento.git"
},
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"adapter.js": "v0.2.9",
"co": "~3.0.7",
"kurento-client": "master",
"kurento-utils": "master",
"jquery": "^3.3.1"
}
}
Install bower packages
If you don’t have bower installed then you can install with this command:
npm install -g bower
There are few dependent libraries which needs to be downloaded via bower
bower install
Font-end Code
Let’s code some basic front-end design which will help on Recording Video.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="0">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="/bower_components/adapter.js/adapter.js"></script>
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/co/co.js"></script>
<script src="/bower_components/kurento-client/js/kurento-client.min.js"></script>
<script src="/bower_components/kurento-utils/js/kurento-utils.min.js"></script>
<script src="/js/index.js"></script>
<title>WebRTC Video Recording Server Side with Kuretno Media Server</title>
</head>
<body>
<header>
<div style="text-align: center;">
<h1>WebRTC Video Recording Server Side with Kuretno Media Server</h1>
</div>
</header>
<div>
<div style="max-width: 1005px; margin: auto;">
<div>
<button id="start" onclick="start(); return false;">Start</button>
<button id="stop" onclick="stop(); return false;">Stop</button>
<hr />
</div>
<div style="max-width: 500px; display: inline-block;">
<h2 style="margin: 0; padding: 5px;">Local Video</h2>
<div style="border: solid 1px black; padding: 10px;">
<video id="localVideo" width="480px" height="360px" autoplay></video>
</div>
</div>
<div style="max-width: 500px; display: inline-block;">
<h2 style="margin: 0; padding: 5px;">Remote Video</h2>
<div style="border: solid 1px black; padding: 10px;">
<video id="remoteVideo" width="480px" height="360px" autoplay></video>
</div>
</div>
</div>
</div>
</body>
</html>
Now, note here that, we have linked few JavaScript files, which are from bower and one is custom JavaScript file “index.js”
<script src="/bower_components/adapter.js/adapter.js"></script>
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/co/co.js"></script>
<script src="/bower_components/kurento-client/js/kurento-client.min.js"></script>
<script src="/bower_components/kurento-utils/js/kurento-utils.min.js"></script>
<script src="/js/index.js"></script>
You may also notice that there are buttons and video elements placed for control and preview.
<button id="start" onclick="start(); return false;">Start</button>
<button id="stop" onclick="stop(); return false;">Stop</button>
<video id="localVideo" width="480px" height="360px" autoplay></video>
<video id="remoteVideo" width="480px" height="360px" autoplay></video>
Next create “index.js” file inside “js” folder, which will connect to Kurento Media Server as well as manage recording according to controls on Front-end.
var kurentoIp = '192.168.31.133', // replace this with your kurento server IP
kurentoPort = '8888', // replace this with your kurento server port
fileSavePath = 'file:///tmp/abc.webm'; // replace this with your path & file name
var args = {
ws_uri: 'ws://' + kurentoIp + ':' + kurentoPort + '/kurento',
file_uri: fileSavePath
};
var localVideo,
remoteVideo,
webRtcPeer,
client,
pipeline;
const IDLE = 0;
const DISABLED = 1;
const CALLING = 2;
function setStatus(nextState) {
switch (nextState) {
case IDLE:
$('#start').attr('disabled', false);
$('#stop').attr('disabled', true);
break;
case CALLING:
$('#start').attr('disabled', true);
$('#stop').attr('disabled', false);
break;
case DISABLED:
$('#start').attr('disabled', true);
$('#stop').attr('disabled', true);
break;
}
}
window.onload = function () {
localVideo = document.getElementById('localVideo');
remoteVideo = document.getElementById('remoteVideo');
setStatus(IDLE);
}
function start() {
setStatus(DISABLED);
webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv({
localVideo: localVideo,
remoteVideo: remoteVideo
}, (error) => {
if (error) return onError(error);
webRtcPeer.generateOffer(onStartOffer);
});
}
function stop() {
if (webRtcPeer) {
webRtcPeer.dispose();
webRtcPeer = null;
}
if (pipeline) {
pipeline.release();
pipeline = null;
}
setStatus(IDLE);
}
function onStartOffer(error, sdpOffer) {
if (error) return onError(error);
co(function* () {
try {
if (!client)
client = yield kurentoClient(args.ws_uri);
pipeline = yield client.create('MediaPipeline');
var webRtc = yield pipeline.create('WebRtcEndpoint');
setIceCandidateCallbacks(webRtcPeer, webRtc, onError);
var recorder = yield pipeline.create('RecorderEndpoint', { uri: args.file_uri });
yield webRtc.connect(recorder);
yield webRtc.connect(webRtc);
yield recorder.record();
var sdpAnswer = yield webRtc.processOffer(sdpOffer);
webRtc.gatherCandidates(onError);
webRtcPeer.processAnswer(sdpAnswer);
setStatus(CALLING);
} catch (e) {
onError(e);
}
})();
}
function onError(error) {
if (error) {
console.error(error);
stop();
}
}
function setIceCandidateCallbacks(webRtcPeer, webRtcEp, onerror) {
webRtcPeer.on('icecandidate', function (candidate) {
candidate = kurentoClient.getComplexType('IceCandidate')(candidate);
webRtcEp.addIceCandidate(candidate, onerror);
});
webRtcEp.on('OnIceCandidate', function (event) {
var candidate = event.candidate;
webRtcPeer.addIceCandidate(candidate, onerror);
});
}
In this “index.js” you have to make sure that the initial variables are containing correct values.
var kurentoIp = '192.168.31.133', // replace this with your kurento server IP
kurentoPort = '8888', // replace this with your kurento server port
fileSavePath = 'file:///tmp/abc.webm'; // replace this with your path & file name
“setStatus()” function used for set button enable / disable.
“start()” function used for start recording.
“stop()” function used for stop recording.
“onError()” function used to handle errors.
Run with http-server
Now we are going to browse this files by running http-server on port 8443
http-server -p 8443
Now you can browse files at http://localhost:8443/
Here you also have to make sure that whatever path you use to save recorded file, it should be writable.
Hello, I followed all your steps.
I’ve installed Kurento on google cloud VM and it also working by show status LISTEN on both ports: (8888 & 8433).
The problem is I cannot connect to server.
I also try to test if it works by using this:
wscat -c ws://35.239.105.245:8888/kurento
and No luck. it said error: connect ETIMEDOUT 35.239.105.245:8888
I really stuck with this, do you know any solutions?
Well, I guess you are trying to connect from other server or from your local system.
You have to open 8888 port on your Google Cloud Server, so it can be connected from outside of server.