├── .gitignore ├── README.md ├── bower.json ├── index.html ├── js ├── index.js └── live.js └── live.html /.gitignore: -------------------------------------------------------------------------------- 1 | /bower_components/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebRTC Server Side Video Recording Kurento 2 | 3 | This is the sample texting application created to test live recording from WebRTC Browser side to Kurento Media Server. Here two files are with different persopose to each are created `index.html` and `index.js`. 4 | 5 | The one file `index.html` is used to record video and save that video to Kurento Media Server, it executes it's javascript code from `index.js`. And the another file `live.html` is used to stream any existing video to browser, it executes it's javascript code from `live.js`. 6 | 7 | ## Steps to follow 8 | * Pre-Requirements 9 | * Install http-server 10 | * Install bower packages 11 | * Configuration Changes 12 | * Run with http-server 13 | 14 | ## Pre-Requirements 15 | * [Node.js](https://nodejs.org) 16 | * [Bower](https://bower.io/) 17 | * [Kurento Server](http://www.kurento.org/) 18 | 19 | ## Install http-server 20 | 21 | [http-server](https://www.npmjs.com/package/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. 22 | 23 | `npm install http-server -g` 24 | 25 | ## Install bower packages 26 | 27 | If you don't have bower installed then you can install with this command: `npm install -g bower` 28 | 29 | There are few dependent libraries which needs to be downloaded via bower 30 | 31 | `bower install` 32 | 33 | ## Configuration Changes 34 | 35 | Set variable values for kurento server's IP, Port and file location with file name (which is being record and saved) on `js/index.js` 36 | 37 | ```javascript 38 | var kurentoIp = '192.168.31.133', // replace this with your kurento server IP 39 | kurentoPort = '8888', // replace this with your kurento server port 40 | fileSavePath = 'file:///tmp/abc.webm'; // replace this with your path & file name 41 | ``` 42 | 43 | Set variable values for kurento server's IP, Port and file location with file name (which is already exist to stream) on `js/live.js` 44 | 45 | ```javascript 46 | var kurentoIp = '192.168.31.133', // replace this with your kurento server IP 47 | kurentoPort = '8888', // replace this with your kurento server port 48 | fileSavePath = 'file:///tmp/abc.webm'; // replace this with your path & file name 49 | ``` 50 | 51 | ## Run with http-server 52 | 53 | Now we are going to browse this files by running http-server on port `8443` 54 | 55 | `http-server -p 8443` 56 | 57 | Now you can browse files at [`http://localhost:8443/`](http://localhost:8443/) -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webrtc-server-side-video-recording-kurento", 3 | "homepage": "https://github.com/ankur2194/webrtc-server-side-video-recording-kurento", 4 | "description": "An Application which is recording video directly from web (browser) to server (Kurento Media Server) -- Testing App", 5 | "main": "index.html", 6 | "keywords": [ 7 | "webrtc", 8 | "video", 9 | "recording", 10 | "kurento", 11 | "server-side-recording" 12 | ], 13 | "authors": [ 14 | "Ankur Patel " 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/ankur2194/webrtc-server-side-video-recording-kurento.git" 19 | }, 20 | "license": "MIT", 21 | "ignore": [ 22 | "**/.*", 23 | "node_modules", 24 | "bower_components", 25 | "test", 26 | "tests" 27 | ], 28 | "dependencies": { 29 | "adapter.js": "v0.2.9", 30 | "co": "~3.0.7", 31 | "kurento-client": "master", 32 | "kurento-utils": "master", 33 | "jquery": "^3.3.1" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | WebRTC Video Recording Server Side with Kuretno Media Server 18 | 19 | 20 | 21 |
22 |
23 |

WebRTC Video Recording Server Side with Kuretno Media Server

24 |
25 |
26 | 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 |
35 |

Local Video

36 |
37 | 38 |
39 |
40 |
41 |

Remote Video

42 |
43 | 44 |
45 |
46 |
47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /js/index.js: -------------------------------------------------------------------------------- 1 | var kurentoIp = '192.168.31.133', // replace this with your kurento server IP 2 | kurentoPort = '8888', // replace this with your kurento server port 3 | fileSavePath = 'file:///tmp/abc.webm'; // replace this with your path & file name 4 | 5 | var args = { 6 | ws_uri: 'ws://' + kurentoIp + ':' + kurentoPort + '/kurento', 7 | file_uri: fileSavePath 8 | }; 9 | 10 | var localVideo, 11 | remoteVideo, 12 | webRtcPeer, 13 | client, 14 | pipeline; 15 | 16 | const IDLE = 0; 17 | const DISABLED = 1; 18 | const CALLING = 2; 19 | 20 | function setStatus(nextState) { 21 | switch (nextState) { 22 | case IDLE: 23 | $('#start').attr('disabled', false); 24 | $('#stop').attr('disabled', true); 25 | break; 26 | 27 | case CALLING: 28 | $('#start').attr('disabled', true); 29 | $('#stop').attr('disabled', false); 30 | break; 31 | 32 | case DISABLED: 33 | $('#start').attr('disabled', true); 34 | $('#stop').attr('disabled', true); 35 | break; 36 | } 37 | } 38 | 39 | window.onload = function () { 40 | localVideo = document.getElementById('localVideo'); 41 | remoteVideo = document.getElementById('remoteVideo'); 42 | 43 | setStatus(IDLE); 44 | } 45 | 46 | function start() { 47 | setStatus(DISABLED); 48 | 49 | webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv({ 50 | localVideo: localVideo, 51 | remoteVideo: remoteVideo 52 | }, (error) => { 53 | if (error) return onError(error); 54 | webRtcPeer.generateOffer(onStartOffer); 55 | }); 56 | } 57 | 58 | function stop() { 59 | if (webRtcPeer) { 60 | webRtcPeer.dispose(); 61 | webRtcPeer = null; 62 | } 63 | 64 | if (pipeline) { 65 | pipeline.release(); 66 | pipeline = null; 67 | } 68 | 69 | setStatus(IDLE); 70 | } 71 | 72 | function onStartOffer(error, sdpOffer) { 73 | if (error) return onError(error); 74 | 75 | co(function* () { 76 | try { 77 | if (!client) 78 | client = yield kurentoClient(args.ws_uri); 79 | 80 | pipeline = yield client.create('MediaPipeline'); 81 | var webRtc = yield pipeline.create('WebRtcEndpoint'); 82 | setIceCandidateCallbacks(webRtcPeer, webRtc, onError); 83 | var recorder = yield pipeline.create('RecorderEndpoint', { uri: args.file_uri }); 84 | yield webRtc.connect(recorder); 85 | yield webRtc.connect(webRtc); 86 | yield recorder.record(); 87 | var sdpAnswer = yield webRtc.processOffer(sdpOffer); 88 | webRtc.gatherCandidates(onError); 89 | webRtcPeer.processAnswer(sdpAnswer); 90 | 91 | setStatus(CALLING); 92 | } catch (e) { 93 | onError(e); 94 | } 95 | })(); 96 | } 97 | 98 | function onError(error) { 99 | if (error) { 100 | console.error(error); 101 | stop(); 102 | } 103 | } 104 | 105 | function setIceCandidateCallbacks(webRtcPeer, webRtcEp, onerror) { 106 | webRtcPeer.on('icecandidate', function (candidate) { 107 | candidate = kurentoClient.getComplexType('IceCandidate')(candidate); 108 | webRtcEp.addIceCandidate(candidate, onerror); 109 | }); 110 | 111 | webRtcEp.on('OnIceCandidate', function (event) { 112 | var candidate = event.candidate; 113 | webRtcPeer.addIceCandidate(candidate, onerror); 114 | }); 115 | } -------------------------------------------------------------------------------- /js/live.js: -------------------------------------------------------------------------------- 1 | var kurentoIp = '192.168.31.133', // replace this with your kurento server IP 2 | kurentoPort = '8888', // replace this with your kurento server port 3 | fileSavePath = 'file:///tmp/abc.webm'; // replace this with your path & file name 4 | 5 | var args = { 6 | ws_uri: 'ws://' + kurentoIp + ':' + kurentoPort + '/kurento', 7 | file_uri: fileSavePath 8 | }; 9 | 10 | var remoteVideo, 11 | webRtcPeer, 12 | client, 13 | pipeline; 14 | 15 | const IDLE = 0; 16 | const DISABLED = 1; 17 | const CALLING = 2; 18 | const PLAYING = 3; 19 | 20 | function setStatus(nextState) { 21 | switch (nextState) { 22 | case IDLE: 23 | $('#stop').attr('disabled', true); 24 | $('#play').attr('disabled', false); 25 | break; 26 | 27 | case CALLING: 28 | $('#stop').attr('disabled', false); 29 | $('#play').attr('disabled', true); 30 | break; 31 | 32 | case PLAYING: 33 | $('#stop').attr('disabled', false); 34 | $('#play').attr('disabled', true); 35 | break; 36 | 37 | case DISABLED: 38 | $('#stop').attr('disabled', true); 39 | $('#play').attr('disabled', true); 40 | break; 41 | } 42 | } 43 | 44 | window.onload = function () { 45 | remoteVideo = document.getElementById('remoteVideo'); 46 | 47 | setStatus(IDLE); 48 | } 49 | 50 | function play() { 51 | setStatus(DISABLED); 52 | 53 | webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly({ 54 | remoteVideo: remoteVideo 55 | }, (error) => { 56 | if (error) return onError(error); 57 | webRtcPeer.generateOffer(onPlayOffer); 58 | }); 59 | } 60 | 61 | function onPlayOffer(error, sdpOffer) { 62 | if (error) return onError(error); 63 | 64 | co(function* () { 65 | try { 66 | if (!client) 67 | client = yield kurentoClient(args.ws_uri); 68 | 69 | pipeline = yield client.create('MediaPipeline'); 70 | var webRtc = yield pipeline.create('WebRtcEndpoint'); 71 | setIceCandidateCallbacks(webRtcPeer, webRtc, onError); 72 | var player = yield pipeline.create('PlayerEndpoint', { uri: args.file_uri }); 73 | player.on('EndOfStream', stop); 74 | yield player.connect(webRtc); 75 | var sdpAnswer = yield webRtc.processOffer(sdpOffer); 76 | webRtc.gatherCandidates(onError); 77 | webRtcPeer.processAnswer(sdpAnswer); 78 | yield player.play(); 79 | setStatus(PLAYING); 80 | } 81 | catch (e) { 82 | onError(e); 83 | } 84 | })(); 85 | } 86 | 87 | function stop() { 88 | if (webRtcPeer) { 89 | webRtcPeer.dispose(); 90 | webRtcPeer = null; 91 | } 92 | 93 | if (pipeline) { 94 | pipeline.release(); 95 | pipeline = null; 96 | } 97 | 98 | setStatus(IDLE); 99 | } 100 | 101 | function onError(error) { 102 | if (error) { 103 | console.error(error); 104 | stop(); 105 | } 106 | } 107 | 108 | function setIceCandidateCallbacks(webRtcPeer, webRtcEp, onerror) { 109 | webRtcPeer.on('icecandidate', function (candidate) { 110 | candidate = kurentoClient.getComplexType('IceCandidate')(candidate); 111 | webRtcEp.addIceCandidate(candidate, onerror); 112 | }); 113 | 114 | webRtcEp.on('OnIceCandidate', function (event) { 115 | var candidate = event.candidate; 116 | webRtcPeer.addIceCandidate(candidate, onerror); 117 | }); 118 | } -------------------------------------------------------------------------------- /live.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | WebRTC Video Recording Server Side with Kuretno Media Server 18 | 19 | 20 | 21 |
22 |
23 |

Live Preview of Recording

24 |
25 |
26 | 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 40 |
41 |

Remote Video

42 |
43 | 44 |
45 |
46 |
47 |
48 | 49 | 50 | --------------------------------------------------------------------------------