diff --git a/.gitignore b/.gitignore index 8a91253..3783cbf 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .settings/ *~ bower_components/ +.DS_Store diff --git a/kurento-hello-world-recorder-generator/bower.json b/kurento-hello-world-recorder-generator/bower.json new file mode 100644 index 0000000..057255d --- /dev/null +++ b/kurento-hello-world-recorder-generator/bower.json @@ -0,0 +1,30 @@ +{ + "name": "kurento-hello-world", + "version": "5.0.4-dev", + "description": "Kurento Browser JavaScript Tutorial 1: Hello World (WebRTC in loopback)", + "authors": [ + "Kurento " + ], + "main": "index.html", + "moduleType": [ + "globals" + ], + "license": "LGPL", + "homepage": "http://www.kurento.org/", + "private": true, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "ekko-lightbox": "~3.1.4", + "html5shiv": "~3.7.2", + "respond": "~1.4.2", + "co": "~3.0.7", + "kurento-client": "develop", + "kurento-utils": "develop" + } +} diff --git a/kurento-hello-world-recorder-generator/css/kurento.css b/kurento-hello-world-recorder-generator/css/kurento.css new file mode 100644 index 0000000..4cd4f38 --- /dev/null +++ b/kurento-hello-world-recorder-generator/css/kurento.css @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2014 Kurento (http://kurento.org/) + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser General Public License + * (LGPL) version 2.1 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-2.1.html + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ +@CHARSET "UTF-8"; + +html { + position: relative; + min-height: 100%; +} + +body { + padding-top: 40px; + body +} + +video,#console { + display: block; + font-size: 14px; + line-height: 1.42857143; + color: #555; + background-color: #fff; + background-image: none; + border: 1px solid #ccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + -webkit-transition: border-color ease-in-out .15s, box-shadow + ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} + +#console { + overflow-y: auto; + width: 100%; + height: 120px; +} + +.col-md-2 { + width: 80px; + padding-top: 190px; +} diff --git a/kurento-hello-world-recorder-generator/external/adapter.js b/kurento-hello-world-recorder-generator/external/adapter.js new file mode 100644 index 0000000..ff9344e --- /dev/null +++ b/kurento-hello-world-recorder-generator/external/adapter.js @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ + +/* More information about these options at jshint.com/docs/options */ +/* global mozRTCIceCandidate, mozRTCPeerConnection, +mozRTCSessionDescription, webkitRTCPeerConnection */ +/* exported trace */ + +'use strict'; + +var RTCPeerConnection = null; +var getUserMedia = null; +var attachMediaStream = null; +var reattachMediaStream = null; +var webrtcDetectedBrowser = null; +var webrtcDetectedVersion = null; + +function trace(text) { + // This function is used for logging. + if (text[text.length - 1] === '\n') { + text = text.substring(0, text.length - 1); + } + console.log((window.performance.now() / 1000).toFixed(3) + ': ' + text); +} + +function maybeFixConfiguration(pcConfig) { + if (!pcConfig) { + return; + } + for (var i = 0; i < pcConfig.iceServers.length; i++) { + if (pcConfig.iceServers[i].hasOwnProperty('urls')) { + pcConfig.iceServers[i].url = pcConfig.iceServers[i].urls; + delete pcConfig.iceServers[i].urls; + } + } +} + +if (navigator.mozGetUserMedia) { + console.log('This appears to be Firefox'); + + webrtcDetectedBrowser = 'firefox'; + + webrtcDetectedVersion = + parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10); + + // The RTCPeerConnection object. + RTCPeerConnection = function(pcConfig, pcConstraints) { + // .urls is not supported in FF yet. + maybeFixConfiguration(pcConfig); + return new mozRTCPeerConnection(pcConfig, pcConstraints); + }; + + // The RTCSessionDescription object. + window.RTCSessionDescription = mozRTCSessionDescription; + + // The RTCIceCandidate object. + window.RTCIceCandidate = mozRTCIceCandidate; + + // getUserMedia shim (only difference is the prefix). + // Code from Adam Barth. + getUserMedia = navigator.mozGetUserMedia.bind(navigator); + navigator.getUserMedia = getUserMedia; + + // Creates ICE server from the URL for FF. + window.createIceServer = function(url, username, password) { + var iceServer = null; + var urlParts = url.split(':'); + if (urlParts[0].indexOf('stun') === 0) { + // Create ICE server with STUN URL. + iceServer = { + 'url': url + }; + } else if (urlParts[0].indexOf('turn') === 0) { + if (webrtcDetectedVersion < 27) { + // Create iceServer with turn url. + // Ignore the transport parameter from TURN url for FF version <=27. + var turnUrlParts = url.split('?'); + // Return null for createIceServer if transport=tcp. + if (turnUrlParts.length === 1 || + turnUrlParts[1].indexOf('transport=udp') === 0) { + iceServer = { + 'url': turnUrlParts[0], + 'credential': password, + 'username': username + }; + } + } else { + // FF 27 and above supports transport parameters in TURN url, + // So passing in the full url to create iceServer. + iceServer = { + 'url': url, + 'credential': password, + 'username': username + }; + } + } + return iceServer; + }; + + window.createIceServers = function(urls, username, password) { + var iceServers = []; + // Use .url for FireFox. + for (var i = 0; i < urls.length; i++) { + var iceServer = + window.createIceServer(urls[i], username, password); + if (iceServer !== null) { + iceServers.push(iceServer); + } + } + return iceServers; + }; + + // Attach a media stream to an element. + attachMediaStream = function(element, stream) { + console.log('Attaching media stream'); + element.mozSrcObject = stream; + }; + + reattachMediaStream = function(to, from) { + console.log('Reattaching media stream'); + to.mozSrcObject = from.mozSrcObject; + }; + +} else if (navigator.webkitGetUserMedia) { + console.log('This appears to be Chrome'); + + webrtcDetectedBrowser = 'chrome'; + // Temporary fix until crbug/374263 is fixed. + // Setting Chrome version to 999, if version is unavailable. + var result = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./); + if (result !== null) { + webrtcDetectedVersion = parseInt(result[2], 10); + } else { + webrtcDetectedVersion = 999; + } + + // Creates iceServer from the url for Chrome M33 and earlier. + window.createIceServer = function(url, username, password) { + var iceServer = null; + var urlParts = url.split(':'); + if (urlParts[0].indexOf('stun') === 0) { + // Create iceServer with stun url. + iceServer = { + 'url': url + }; + } else if (urlParts[0].indexOf('turn') === 0) { + // Chrome M28 & above uses below TURN format. + iceServer = { + 'url': url, + 'credential': password, + 'username': username + }; + } + return iceServer; + }; + + // Creates iceServers from the urls for Chrome M34 and above. + window.createIceServers = function(urls, username, password) { + var iceServers = []; + if (webrtcDetectedVersion >= 34) { + // .urls is supported since Chrome M34. + iceServers = { + 'urls': urls, + 'credential': password, + 'username': username + }; + } else { + for (var i = 0; i < urls.length; i++) { + var iceServer = + window.createIceServer(urls[i], username, password); + if (iceServer !== null) { + iceServers.push(iceServer); + } + } + } + return iceServers; + }; + + // The RTCPeerConnection object. + RTCPeerConnection = function(pcConfig, pcConstraints) { + // .urls is supported since Chrome M34. + if (webrtcDetectedVersion < 34) { + maybeFixConfiguration(pcConfig); + } + return new webkitRTCPeerConnection(pcConfig, pcConstraints); + }; + + // Get UserMedia (only difference is the prefix). + // Code from Adam Barth. + getUserMedia = navigator.webkitGetUserMedia.bind(navigator); + navigator.getUserMedia = getUserMedia; + + // Attach a media stream to an element. + attachMediaStream = function(element, stream) { + if (typeof element.srcObject !== 'undefined') { + element.srcObject = stream; + } else if (typeof element.mozSrcObject !== 'undefined') { + element.mozSrcObject = stream; + } else if (typeof element.src !== 'undefined') { + element.src = URL.createObjectURL(stream); + } else { + console.log('Error attaching stream to element.'); + } + }; + + reattachMediaStream = function(to, from) { + to.src = from.src; + }; +} else { + console.log('Browser does not appear to be WebRTC-capable'); +} diff --git a/kurento-hello-world-recorder-generator/img/kurento.png b/kurento-hello-world-recorder-generator/img/kurento.png new file mode 100644 index 0000000..6f1a4ad Binary files /dev/null and b/kurento-hello-world-recorder-generator/img/kurento.png differ diff --git a/kurento-hello-world-recorder-generator/img/naevatec.png b/kurento-hello-world-recorder-generator/img/naevatec.png new file mode 100644 index 0000000..05ee704 Binary files /dev/null and b/kurento-hello-world-recorder-generator/img/naevatec.png differ diff --git a/kurento-hello-world-recorder-generator/img/pipeline.png b/kurento-hello-world-recorder-generator/img/pipeline.png new file mode 100644 index 0000000..bd3adcb Binary files /dev/null and b/kurento-hello-world-recorder-generator/img/pipeline.png differ diff --git a/kurento-hello-world-recorder-generator/img/spinner.gif b/kurento-hello-world-recorder-generator/img/spinner.gif new file mode 100644 index 0000000..8be8ba3 Binary files /dev/null and b/kurento-hello-world-recorder-generator/img/spinner.gif differ diff --git a/kurento-hello-world-recorder-generator/img/transparent-1px.png b/kurento-hello-world-recorder-generator/img/transparent-1px.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/kurento-hello-world-recorder-generator/img/transparent-1px.png differ diff --git a/kurento-hello-world-recorder-generator/img/urjc.gif b/kurento-hello-world-recorder-generator/img/urjc.gif new file mode 100644 index 0000000..cd8a770 Binary files /dev/null and b/kurento-hello-world-recorder-generator/img/urjc.gif differ diff --git a/kurento-hello-world-recorder-generator/img/webrtc.png b/kurento-hello-world-recorder-generator/img/webrtc.png new file mode 100644 index 0000000..d47e2e4 Binary files /dev/null and b/kurento-hello-world-recorder-generator/img/webrtc.png differ diff --git a/kurento-hello-world-recorder-generator/index.html b/kurento-hello-world-recorder-generator/index.html new file mode 100644 index 0000000..b3b1170 --- /dev/null +++ b/kurento-hello-world-recorder-generator/index.html @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kurento Tutorial: Loopback with recording using generators + + + +
+ +
+
+ +
+
+

Local stream

+ +
+ +
+

Remote stream

+ +
+
+
+
+ +
+
+
+
+ + + + + diff --git a/kurento-hello-world-recorder-generator/js/console.js b/kurento-hello-world-recorder-generator/js/console.js new file mode 100644 index 0000000..840d567 --- /dev/null +++ b/kurento-hello-world-recorder-generator/js/console.js @@ -0,0 +1,91 @@ +/* + * (C) Copyright 2013 Kurento (http://kurento.org/) + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser General Public License + * (LGPL) version 2.1 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl-2.1.html + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + */ + +/** + * Object that piggy-back the browser console and show their messages on a DIV + * + * Inspired by Node.js ClIM module (https://github.com/epeli/node-clim) + * + * @constructor + * + * @param {String} + * id: id attribute of the DIV tag where to show the messages + * @param console: + * reference to the original browser console + */ +function Console(id, console) { + var div = document.getElementById(id); + + function createMessage(msg, color) { + // Sanitize the input + msg = msg.toString().replace(/= 34) { + // .urls is supported since Chrome M34. + iceServers = { + 'urls': urls, + 'credential': password, + 'username': username + }; + } else { + for (var i = 0; i < urls.length; i++) { + var iceServer = + window.createIceServer(urls[i], username, password); + if (iceServer !== null) { + iceServers.push(iceServer); + } + } + } + return iceServers; + }; + + // The RTCPeerConnection object. + RTCPeerConnection = function(pcConfig, pcConstraints) { + // .urls is supported since Chrome M34. + if (webrtcDetectedVersion < 34) { + maybeFixConfiguration(pcConfig); + } + return new webkitRTCPeerConnection(pcConfig, pcConstraints); + }; + + // Get UserMedia (only difference is the prefix). + // Code from Adam Barth. + getUserMedia = navigator.webkitGetUserMedia.bind(navigator); + navigator.getUserMedia = getUserMedia; + + // Attach a media stream to an element. + attachMediaStream = function(element, stream) { + if (typeof element.srcObject !== 'undefined') { + element.srcObject = stream; + } else if (typeof element.mozSrcObject !== 'undefined') { + element.mozSrcObject = stream; + } else if (typeof element.src !== 'undefined') { + element.src = URL.createObjectURL(stream); + } else { + console.log('Error attaching stream to element.'); + } + }; + + reattachMediaStream = function(to, from) { + to.src = from.src; + }; +} else { + console.log('Browser does not appear to be WebRTC-capable'); +} diff --git a/kurento-hello-world/index.html b/kurento-hello-world/index.html index 2367afd..ac3af8c 100644 --- a/kurento-hello-world/index.html +++ b/kurento-hello-world/index.html @@ -9,23 +9,21 @@ +href="bower_components/bootstrap/dist/css/bootstrap.min.css"> +href="bower_components/ekko-lightbox/dist/ekko-lightbox.min.css"> + + + - - - - + + + + + diff --git a/kurento-hello-world/js/index.js b/kurento-hello-world/js/index.js index c139230..64717e4 100644 --- a/kurento-hello-world/js/index.js +++ b/kurento-hello-world/js/index.js @@ -18,6 +18,7 @@ const ws_uri = 'ws://' + location.hostname + ':8888/kurento'; var videoInput; var videoOutput; var webRtcPeer; +var pipeline; window.onload = function() { console = new Console('console', console); @@ -31,6 +32,10 @@ function start() { } function stop() { + if(pipeline){ + pipeline.release(); + pipeline = null; + } if (webRtcPeer) { webRtcPeer.dispose(); } @@ -43,9 +48,11 @@ function onOffer(sdpOffer){ kurentoClient(ws_uri, function(error, kurentoClient) { if(error) return onError(error); - kurentoClient.create("MediaPipeline", function(error, pipeline) { + kurentoClient.create("MediaPipeline", function(error, p) { if(error) return onError(error); + pipeline = p; + pipeline.create("WebRtcEndpoint", function(error, webRtc){ if(error) return onError(error); @@ -67,6 +74,7 @@ function onOffer(sdpOffer){ function onError(error){ console.error(error); + stop(); } function showSpinner() {