commit bd5f2a65915408e869519ba4e8c562828b210a93 Author: Ubuntu Date: Fri May 25 18:58:19 2018 +0000 init project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2efe191 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea/ +node_modules/ +npm-debug.log +static/bower_components +keys/ \ No newline at end of file diff --git a/.package.json.swp b/.package.json.swp new file mode 100644 index 0000000..b1c7525 Binary files /dev/null and b/.package.json.swp differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..1d74cdb --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ +[![License badge](https://img.shields.io/badge/license-LGPL-blue.svg)](http://www.gnu.org/licenses/lgpl-2.1.html) +[![Documentation badge](https://readthedocs.org/projects/fiware-orion/badge/?version=latest)](http://doc-kurento.readthedocs.org/en/latest/) +[![Docker badge](https://img.shields.io/docker/pulls/fiware/orion.svg)](https://hub.docker.com/r/fiware/stream-oriented-kurento/) +[![Support badge]( https://img.shields.io/badge/support-sof-yellowgreen.svg)](http://stackoverflow.com/questions/tagged/kurento) + +[![][KurentoImage]][Kurento] + +Copyright © 2013-2016 [Kurento]. Licensed under [LGPL v2.1 License]. + +kurento-one2many-call +===================== + +Kurento Java Tutorial: WebRTC one to many video call. + +Running this tutorial +--------------------- + +In order to run this tutorial, please read the following [instructions]. + +What is Kurento +--------------- + +Kurento is an open source software project providing a platform suitable +for creating modular applications with advanced real-time communication +capabilities. For knowing more about Kurento, please visit the Kurento +project website: http://www.kurento.org. + +Kurento is part of [FIWARE]. For further information on the relationship of +FIWARE and Kurento check the [Kurento FIWARE Catalog Entry] + +Kurento is part of the [NUBOMEDIA] research initiative. + +Documentation +------------- + +The Kurento project provides detailed [documentation] including tutorials, +installation and development guides. A simplified version of the documentation +can be found on [readthedocs.org]. The [Open API specification] a.k.a. Kurento +Protocol is also available on [apiary.io]. + +Source +------ + +Code for other Kurento projects can be found in the [GitHub Kurento Group]. + +News and Website +---------------- + +Check the [Kurento blog] +Follow us on Twitter @[kurentoms]. + +Issue tracker +------------- + +Issues and bug reports should be posted to the [GitHub Kurento bugtracker] + +Licensing and distribution +-------------------------- + +Software associated to Kurento is provided as open source under GNU Library or +"Lesser" General Public License, version 2.1 (LGPL-2.1). Please check the +specific terms and conditions linked to this open source license at +http://opensource.org/licenses/LGPL-2.1. Please note that software derived as a +result of modifying the source code of Kurento software in order to fix a bug +or incorporate enhancements is considered a derivative work of the product. +Software that merely uses or aggregates (i.e. links to) an otherwise unmodified +version of existing software is not considered a derivative work. + +Contribution policy +------------------- + +You can contribute to the Kurento community through bug-reports, bug-fixes, new +code or new documentation. For contributing to the Kurento community, drop a +post to the [Kurento Public Mailing List] providing full information about your +contribution and its value. In your contributions, you must comply with the +following guidelines + +* You must specify the specific contents of your contribution either through a + detailed bug description, through a pull-request or through a patch. +* You must specify the licensing restrictions of the code you contribute. +* For newly created code to be incorporated in the Kurento code-base, you must + accept Kurento to own the code copyright, so that its open source nature is + guaranteed. +* You must justify appropriately the need and value of your contribution. The + Kurento project has no obligations in relation to accepting contributions + from third parties. +* The Kurento project leaders have the right of asking for further + explanations, tests or validations of any code contributed to the community + before it being incorporated into the Kurento code-base. You must be ready to + addressing all these kind of concerns before having your code approved. + +Support +------- + +The Kurento project provides community support through the [Kurento Public +Mailing List] and through [StackOverflow] using the tags *kurento* and +*fiware-kurento*. + +Before asking for support, please read first the [Kurento Netiquette Guidelines] + +[documentation]: http://www.kurento.org/documentation +[FIWARE]: http://www.fiware.org +[GitHub Kurento bugtracker]: https://github.com/Kurento/bugtracker/issues +[GitHub Kurento Group]: https://github.com/kurento +[kurentoms]: http://twitter.com/kurentoms +[Kurento]: http://kurento.org +[Kurento Blog]: http://www.kurento.org/blog +[Kurento FIWARE Catalog Entry]: http://catalogue.fiware.org/enablers/stream-oriented-kurento +[Kurento Netiquette Guidelines]: http://www.kurento.org/blog/kurento-netiquette-guidelines +[Kurento Public Mailing list]: https://groups.google.com/forum/#!forum/kurento +[KurentoImage]: https://secure.gravatar.com/avatar/21a2a12c56b2a91c8918d5779f1778bf?s=120 +[LGPL v2.1 License]: http://www.gnu.org/licenses/lgpl-2.1.html +[NUBOMEDIA]: http://www.nubomedia.eu +[StackOverflow]: http://stackoverflow.com/search?q=kurento +[Read-the-docs]: http://read-the-docs.readthedocs.org/ +[readthedocs.org]: http://kurento.readthedocs.org/ +[Open API specification]: http://kurento.github.io/doc-kurento/ +[apiary.io]: http://docs.streamoriented.apiary.io/ +[instructions]: http://www.kurento.org/docs/current/tutorials/node/tutorial-one2many.html diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ad93dac --- /dev/null +++ b/package-lock.json @@ -0,0 +1,822 @@ +{ + "name": "kurento-one2many-call", + "version": "6.2.2-dev", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz", + "integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=", + "requires": { + "mime-types": "2.1.18", + "negotiator": "0.5.3" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + }, + "arraybuffer.slice": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", + "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "async": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.0.1.tgz", + "integrity": "sha1-twnMAoCpw28J9FNr6CPIOKkEniU=", + "requires": { + "lodash": "4.17.10" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + }, + "backoff": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.3.0.tgz", + "integrity": "sha1-7nx+OAk/kuRyhZ22NedlJFT8Ieo=" + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "requires": { + "callsite": "1.0.0" + } + }, + "bindings": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", + "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=" + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + }, + "bower": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/bower/-/bower-1.8.4.tgz", + "integrity": "sha1-54dqB23rgTf30GUl3F6MZtuC8oo=", + "dev": true + }, + "bufferutil": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.2.1.tgz", + "integrity": "sha1-N75dNuHgZJIiHmjUdLGsWOUQy9c=", + "requires": { + "bindings": "1.2.1", + "nan": "2.10.0" + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + }, + "commander": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.1.0.tgz", + "integrity": "sha1-0SG7roYNmZKj1Re6lvVliOR8Z4E=" + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + }, + "component-emitter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", + "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=" + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + }, + "content-disposition": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz", + "integrity": "sha1-QoT+auBjCHRjnkToCkGMKTQTXp4=" + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.2.tgz", + "integrity": "sha1-cv7D0k5Io0Mgc9kMEmQgBQYQBLE=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "crc": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.2.1.tgz", + "integrity": "sha1-XZyPt3okXNXsopHl0tAFM0urAII=" + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + } + }, + "depd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", + "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=" + }, + "destroy": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.3.tgz", + "integrity": "sha1-tDO0ck5x/YVR2YhRdIUcX8N34sk=" + }, + "ee-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.0.tgz", + "integrity": "sha1-ag18YiHkkP7v2S7D9EHJzozQl/Q=" + }, + "engine.io": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.5.tgz", + "integrity": "sha512-j1DWIcktw4hRwrv6nWx++5nFH2X64x16MAG2P0Lmi5Dvdfi3I+Jhc7JKJIdAmDJa+5aZ/imHV7dWRPy2Cqjh3A==", + "requires": { + "accepts": "1.3.3", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "ws": "1.1.5" + }, + "dependencies": { + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "requires": { + "mime-types": "2.1.18", + "negotiator": "0.6.1" + } + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + } + } + }, + "engine.io-client": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.5.tgz", + "integrity": "sha512-AYTgHyeVUPitsseqjoedjhYJapNVoSPShbZ+tEUX9/73jgZ/Z3sUlJf9oYgdEBBdVhupUpUqSxH0kBCXlQnmZg==", + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "2.3.3", + "engine.io-parser": "1.3.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parsejson": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "1.1.5", + "xmlhttprequest-ssl": "1.5.3", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + } + } + }, + "engine.io-parser": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz", + "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=", + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.6", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary": "0.1.7", + "wtf-8": "1.0.0" + } + }, + "error-tojson": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/error-tojson/-/error-tojson-0.0.1.tgz", + "integrity": "sha1-p7GqlP/ADpB4wuuibiBL2Hzyy7k=" + }, + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" + }, + "escape-html": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.1.tgz", + "integrity": "sha1-GBoobq05ejmpKFfPsdQwUuNWv/A=" + }, + "etag": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.6.0.tgz", + "integrity": "sha1-i8ssavElTEgd/IuZfJBu9ORCwgc=", + "requires": { + "crc": "3.2.1" + } + }, + "express": { + "version": "4.12.4", + "resolved": "https://registry.npmjs.org/express/-/express-4.12.4.tgz", + "integrity": "sha1-j+wlECVbxrLlgQfEgjnA+jB8GqI=", + "requires": { + "accepts": "1.2.13", + "content-disposition": "0.5.0", + "content-type": "1.0.4", + "cookie": "0.1.2", + "cookie-signature": "1.0.6", + "debug": "2.2.0", + "depd": "1.0.1", + "escape-html": "1.0.1", + "etag": "1.6.0", + "finalhandler": "0.3.6", + "fresh": "0.2.4", + "merge-descriptors": "1.0.0", + "methods": "1.1.2", + "on-finished": "2.2.1", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.3", + "proxy-addr": "1.0.10", + "qs": "2.4.2", + "range-parser": "1.0.3", + "send": "0.12.3", + "serve-static": "1.9.3", + "type-is": "1.6.16", + "utils-merge": "1.0.0", + "vary": "1.0.1" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "finalhandler": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.3.6.tgz", + "integrity": "sha1-2vnEFhsbBuABRmsUEd/baXO+E4s=", + "requires": { + "debug": "2.2.0", + "escape-html": "1.0.1", + "on-finished": "2.2.1" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.4.tgz", + "integrity": "sha1-NYJJkgbJcjcUGQ7ddLRgT+tKYUw=" + }, + "has-binary": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", + "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", + "requires": { + "isarray": "0.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.5.tgz", + "integrity": "sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isbuffer": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/isbuffer/-/isbuffer-0.0.0.tgz", + "integrity": "sha1-OMFG2d9Si4v5sHAcPUPPEt8/w5s=" + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" + }, + "kurento-client": { + "version": "github:Kurento/kurento-client-js#efb160e85a4b1f376307fe1979c9fbcb5f978393", + "requires": { + "async": "2.0.1", + "error-tojson": "0.0.1", + "es6-promise": "4.2.4", + "extend": "3.0.1", + "inherits": "2.0.3", + "kurento-client-core": "github:Kurento/kurento-client-core-js#2160f8e6938f138b52b72a5c5c354d1e5fce1ca0", + "kurento-client-elements": "github:Kurento/kurento-client-elements-js#cbd1ff67fbf0faddc9f6f266bb33e449bc9e1f81", + "kurento-client-filters": "github:Kurento/kurento-client-filters-js#51308da53e432a2db9559dcdb308d87951417bf0", + "kurento-jsonrpc": "github:Kurento/kurento-jsonrpc-js#827827bbeb557e1c1901f5a562c4c700b9a51401", + "minimist": "1.2.0", + "promise": "7.1.1", + "promisecallback": "0.0.4", + "reconnect-ws": "github:KurentoForks/reconnect-ws#f287385d75861654528c352e60221f95c9209f8a" + }, + "dependencies": { + "kurento-client-core": { + "version": "github:Kurento/kurento-client-core-js#2160f8e6938f138b52b72a5c5c354d1e5fce1ca0" + }, + "kurento-client-elements": { + "version": "github:Kurento/kurento-client-elements-js#cbd1ff67fbf0faddc9f6f266bb33e449bc9e1f81" + }, + "kurento-client-filters": { + "version": "github:Kurento/kurento-client-filters-js#51308da53e432a2db9559dcdb308d87951417bf0" + }, + "kurento-jsonrpc": { + "version": "github:Kurento/kurento-jsonrpc-js#827827bbeb557e1c1901f5a562c4c700b9a51401", + "requires": { + "bufferutil": "1.2.1", + "inherits": "2.0.3", + "utf-8-validate": "1.2.2", + "ws": "1.1.5" + } + }, + "reconnect-core": { + "version": "github:KurentoForks/reconnect-core#921d43e91578abb2fb2613f585c010c1939cf734", + "requires": { + "backoff": "2.3.0" + } + }, + "reconnect-ws": { + "version": "github:KurentoForks/reconnect-ws#f287385d75861654528c352e60221f95c9209f8a", + "requires": { + "reconnect-core": "github:KurentoForks/reconnect-core#921d43e91578abb2fb2613f585c010c1939cf734", + "websocket-stream": "0.5.1" + } + } + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz", + "integrity": "sha1-IWnPdTjhsMyH+4jhUC2EdLv3mGQ=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "requires": { + "mime-db": "1.33.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" + }, + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" + }, + "negotiator": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz", + "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g=" + }, + "object-assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + }, + "on-finished": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.2.1.tgz", + "integrity": "sha1-XIXBzDYpn3gCllP2Z/J7a5nrwCk=", + "requires": { + "ee-first": "1.1.0" + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + }, + "parsejson": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", + "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", + "requires": { + "better-assert": "1.0.2" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "requires": { + "better-assert": "1.0.2" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "requires": { + "better-assert": "1.0.2" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-to-regexp": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.3.tgz", + "integrity": "sha1-IbmrgidCed4lsVbqCP0SylG4rss=" + }, + "promise": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.1.1.tgz", + "integrity": "sha1-SJZUxpJha4qlWwck+oCbt9tJxb8=", + "requires": { + "asap": "2.0.6" + } + }, + "promisecallback": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/promisecallback/-/promisecallback-0.0.4.tgz", + "integrity": "sha1-uTTxPATkQ2IrTWbeTkLqX2zmbnQ=" + }, + "proxy-addr": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.10.tgz", + "integrity": "sha1-DUCoL4Afw1VWfS7LZe/j8HfxIcU=", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.0.5" + } + }, + "qs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-2.4.2.tgz", + "integrity": "sha1-9854jld33wtQENp/fE5zujJHD1o=" + }, + "range-parser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz", + "integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU=" + }, + "send": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/send/-/send-0.12.3.tgz", + "integrity": "sha1-zRLcWP3iHk+RkCs5sv2gWnptm9w=", + "requires": { + "debug": "2.2.0", + "depd": "1.0.1", + "destroy": "1.0.3", + "escape-html": "1.0.1", + "etag": "1.6.0", + "fresh": "0.2.4", + "mime": "1.3.4", + "ms": "0.7.1", + "on-finished": "2.2.1", + "range-parser": "1.0.3" + } + }, + "serve-static": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.9.3.tgz", + "integrity": "sha1-X42gcyOtOF/z3FQfGnkXsuQ261c=", + "requires": { + "escape-html": "1.0.1", + "parseurl": "1.3.2", + "send": "0.12.3", + "utils-merge": "1.0.0" + } + }, + "socket.io": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.4.tgz", + "integrity": "sha1-L37O3DORvy1cc+KR/iM+bjTU3QA=", + "requires": { + "debug": "2.3.3", + "engine.io": "1.8.5", + "has-binary": "0.1.7", + "object-assign": "4.1.0", + "socket.io-adapter": "0.5.0", + "socket.io-client": "1.7.4", + "socket.io-parser": "2.3.1" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + } + } + }, + "socket.io-adapter": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", + "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", + "requires": { + "debug": "2.3.3", + "socket.io-parser": "2.3.1" + }, + "dependencies": { + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + } + } + }, + "socket.io-client": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.4.tgz", + "integrity": "sha1-7J+CA1btme9tNX8HVtZIcXvdQoE=", + "requires": { + "backo2": "1.0.2", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "2.3.3", + "engine.io-client": "1.8.5", + "has-binary": "0.1.7", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseuri": "0.0.5", + "socket.io-parser": "2.3.1", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "debug": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", + "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", + "requires": { + "ms": "0.7.2" + } + }, + "ms": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + } + } + }, + "socket.io-parser": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", + "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", + "requires": { + "component-emitter": "1.1.2", + "debug": "2.2.0", + "isarray": "0.0.1", + "json3": "3.3.2" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tinycolor": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tinycolor/-/tinycolor-0.0.1.tgz", + "integrity": "sha1-MgtaUtg6u1l42Bo+iH1K77FaYWQ=" + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.18" + } + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" + }, + "utf-8-validate": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.2.2.tgz", + "integrity": "sha1-i7hxpHQeCFxwSHynrNvX1tNgKes=", + "requires": { + "bindings": "1.2.1", + "nan": "2.4.0" + }, + "dependencies": { + "nan": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz", + "integrity": "sha1-+zxZ1F/k7/4hXwuJD4rfbrMtIjI=" + } + } + }, + "utils-merge": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + }, + "vary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz", + "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA=" + }, + "websocket-stream": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/websocket-stream/-/websocket-stream-0.5.1.tgz", + "integrity": "sha1-YizR8FZvuEzgpNb4VFJvPcTXDkg=", + "requires": { + "isbuffer": "0.0.0", + "through": "2.3.8", + "ws": "0.4.32" + }, + "dependencies": { + "nan": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-1.0.0.tgz", + "integrity": "sha1-riT4hQgY1mL8q1rPfzuVv6oszzg=" + }, + "ws": { + "version": "0.4.32", + "resolved": "https://registry.npmjs.org/ws/-/ws-0.4.32.tgz", + "integrity": "sha1-eHphVEFPPJntg8V3IVOyD+sM7DI=", + "requires": { + "commander": "2.1.0", + "nan": "1.0.0", + "options": "0.0.6", + "tinycolor": "0.0.1" + } + } + } + }, + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "requires": { + "options": "0.0.6", + "ultron": "1.0.2" + } + }, + "wtf-8": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", + "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=" + }, + "xmlhttprequest-ssl": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", + "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=" + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..aa48dbe --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "kurento-one2many-call", + "version": "6.2.2-dev", + "private": true, + "scripts": { + "postinstall": "cd static && bower install" + }, + "dependencies": { + "express": "~4.12.4", + "kurento-client": "Kurento/kurento-client-js", + "minimist": "^1.1.1", + "socket.io": "^1.4.5" + }, + "devDependencies": { + "bower": "^1.4.1" + } +} diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..256c5cd --- /dev/null +++ b/run.sh @@ -0,0 +1,3 @@ +pm2 delete server + +pm2 start server.js --name server diff --git a/server.js b/server.js new file mode 100755 index 0000000..3dea732 --- /dev/null +++ b/server.js @@ -0,0 +1,446 @@ +/* + * (C) Copyright 2014-2015 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. + * + */ + +var path = require('path'); +var url = require('url'); +var express = require('express'); +var minimist = require('minimist'); +var kurento = require('kurento-client'); +var fs = require('fs'); +var http = require('http'); +var socketio = require('socket.io'); + +var argv = minimist(process.argv.slice(2), { + default: { + as_uri: 'http://localhost:8443/', + ws_uri: 'ws://localhost:8888/kurento' + } +}); + + + +var app = express(); + +/* + * Definition of global variables. + */ +var candidatesQueue = {}; +var kurentoClient = null; +var noPresenterMessage = 'No active presenter. Try again later...'; +var anotherPresenterIsActive = "Another user is currently acting as presenter. Try again later ..."; + +var rooms = []; + + +/* + * Server startup + */ +var asUrl = url.parse(argv.as_uri); +var port = asUrl.port; +var server = http.createServer(app); +var io = socketio(server); + +server.listen(port, function() { + console.log('Open ' + url.format(asUrl) + ' with a WebRTC capable browser'); +}); + + +/* + * Rooms related methods + */ + +function getRoom(socket) { + if (rooms[socket.room] == undefined) { + createRoom(socket.room); + } + return rooms[socket.room]; +} + +function createRoom(room) { + rooms[room] = { + presenter: null, + pipeline: null, + viewers: [], + chat: [] + }; +} + +function joinRoom(socket, data) { + // leave all other socket.id rooms + while(socket.rooms.length) { + socket.leave(socket.rooms[0]); + } + + // join new socket.io room + socket.join(data.room); + socket.room = data.room; + socket.username = data.username; + + socket.emit('joinedRoom'); + + console.log('Join room: ' + data.room + ' with username ' + data.username); +} + +function newChatMessage(socket, message){ + var message = {message: message, username: socket.username} + io.in(socket.room).emit('chat:newMessage', message) + + var room = getRoom(socket); + room.chat.push(message); + + if (room.chat.length > 30) + room.chat.shift() +} + +/* + * Define possible actions which we'll send thru Websocket + */ +function acceptPeerResponse(peerType, sdpAnswer) { + return { + id : peerType + 'Response', + response : 'accepted', + sdpAnswer : sdpAnswer + }; +} + +function rejectPeerResponse(peerType, reason) { + return { + id : peerType + 'Response', + response : 'rejected', + message : reason + }; +} + +/* + * Socket pipeline + */ +io.on('connection', function(socket) { + console.log('Connection received with sessionId - ' + socket.id); + + socket.on('error', function(error) { + console.error('Connection ' + socket.id + ' error', error); + stop(socket); + }); + + socket.on('disconnect', function() { + console.log('Connection ' + socket.id + ' closed'); + stop(socket); + }); + + // Handle events from clients + socket.on('presenter', function (data) { + startPresenter(socket, data.sdpOffer, function(error, sdpAnswer) { + var response = (error) ? rejectPeerResponse('presenter', error) : acceptPeerResponse('presenter', sdpAnswer); + socket.emit(response.id, response); + if (!error) { + console.log(socket.username + ' starting publishing to ' + socket.room + ' room'); + socket.broadcast.emit('streamStarted'); + } + }); + }); + + socket.on('viewer', function (data){ + startViewer(socket, data.sdpOffer, function(error, sdpAnswer) { + response = (error) ? rejectPeerResponse('viewer', error) : acceptPeerResponse('viewer', sdpAnswer); + socket.emit(response.id, response); + }); + }); + + socket.on('stop', function(){ + stop(socket); + }); + + socket.on('onIceCandidate', function (data){ + onIceCandidate(socket, data.candidate); + }); + + socket.on('subscribeToStream', function (data){ + joinRoom(socket, data); + var room = getRoom(socket); + if (room.presenter) { + socket.emit('streamStarted'); + } + }); + + socket.on('joinRoom', function (data){ + joinRoom(socket, data) + }); + + + // Chat methods + socket.on('chat:newMessage', function(message) { + newChatMessage(socket, message); + }); + + socket.on('chat:loadMessages', function() { + var room = getRoom(socket); + + socket.emit('chat:messages', room.chat); + }); +}); + + + +/* + * Definition of functions + */ + +// Recover kurentoClient for the first time. +function getKurentoClient(callback) { + if (kurentoClient !== null) { + return callback(null, kurentoClient); + } + + kurento(argv.ws_uri, function(error, _kurentoClient) { + if (error) { + console.log("Could not find media server at address " + argv.ws_uri); + return callback("Could not find media server at address" + argv.ws_uri + + ". Exiting with error " + error); + } + + kurentoClient = _kurentoClient; + callback(null, kurentoClient); + }); +} + +function startPresenter(socket, sdpOffer, callback) { + clearCandidatesQueue(socket); + + var room = getRoom(socket); + if (room.presenter !== null) { + stop(socket); + return callback(anotherPresenterIsActive); + } + + room.presenter = { + webRtcEndpoint : null, + id: socket.id + }; + + getKurentoClient(function(error, kurentoClient) { + if (error) { + stop(socket); + return callback(error); + } + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + kurentoClient.create('MediaPipeline', function(error, pipeline) { + if (error) { + stop(socket); + return callback(error); + } + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + room.pipeline = pipeline; + pipeline.create('WebRtcEndpoint', function(error, webRtcEndpoint) { + if (error) { + stop(socket); + return callback(error); + } + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + room.presenter.webRtcEndpoint = webRtcEndpoint; + + if (candidatesQueue[socket.id]) { + while(candidatesQueue[socket.id].length) { + var candidate = candidatesQueue[socket.id].shift(); + webRtcEndpoint.addIceCandidate(candidate); + } + } + + webRtcEndpoint.on('OnIceCandidate', function(event) { + var candidate = kurento.register.complexTypes.IceCandidate(event.candidate); + socket.emit('iceCandidate', { candidate : candidate }); + }); + + webRtcEndpoint.processOffer(sdpOffer, function(error, sdpAnswer) { + if (error) { + stop(socket); + return callback(error); + } + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + callback(null, sdpAnswer); + }); + + webRtcEndpoint.gatherCandidates(function(error) { + if (error) { + stop(socket); + return callback(error); + } + }); + }); + }); + }); +} + +function startViewer(socket, sdpOffer, callback) { + clearCandidatesQueue(socket); + + var room = getRoom(socket); + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + room.pipeline.create('WebRtcEndpoint', function(error, webRtcEndpoint) { + if (error) { + stop(socket); + return callback(error); + } + room.viewers[socket.id] = { + "webRtcEndpoint" : webRtcEndpoint, + "socket" : socket + }; + + if (room.presenter === null) { + stop(socket); + return callback(noPresenterMessage); + } + + if (candidatesQueue[socket.id]) { + while(candidatesQueue[socket.id].length) { + var candidate = candidatesQueue[socket.id].shift(); + webRtcEndpoint.addIceCandidate(candidate); + } + } + + webRtcEndpoint.on('OnIceCandidate', function(event) { + var candidate = kurento.register.complexTypes.IceCandidate(event.candidate); + socket.emit('iceCandidate', { candidate : candidate }); + }); + + webRtcEndpoint.processOffer(sdpOffer, function(error, sdpAnswer) { + if (error) { + stop(socket.id); + return callback(error); + } + if (room.presenter === null) { + stop(socket.id); + return callback(noPresenterMessage); + } + + room.presenter.webRtcEndpoint.connect(webRtcEndpoint, function(error) { + if (error) { + stop(socket.id); + return callback(error); + } + if (room.presenter === null) { + stop(socket.id); + return callback(noPresenterMessage); + } + + callback(null, sdpAnswer); + webRtcEndpoint.gatherCandidates(function(error) { + if (error) { + stop(socket.id); + return callback(error); + } + }); + }); + }); + }); +} + +function clearCandidatesQueue(socket) { + if (candidatesQueue[socket.id]) { + delete candidatesQueue[socket.id]; + } +} + +function stop(socket) { + var room = getRoom(socket); + + if (room.presenter !== null && room.presenter.id == socket.id) { + stopPresenter(socket); + } else if (room.viewers[socket.id]) { + stopViewing(socket); + } +} + +function stopPresenter(socket){ + var room = getRoom(socket); + var viewers = room.viewers; + + for (var i in viewers) { + var viewer = viewers[i]; + if (viewer.socket) { + clearCandidatesQueue(socket); + viewer.webRtcEndpoint.release(); + viewer.socket.emit('stopCommunication'); + } + } + + room.presenter.webRtcEndpoint.release(); + room.presenter = null; + room.pipeline.release(); + room.viewers = []; +} + +function stopViewing(socket){ + var room = getRoom(socket); + + clearCandidatesQueue(socket.id); + room.viewers[socket.id].webRtcEndpoint.release(); + delete room.viewers[socket.id]; +} + +function onIceCandidate(socket, _candidate) { + var room = getRoom(socket); + + var candidate = kurento.register.complexTypes.IceCandidate(_candidate); + + if (room.presenter && room.presenter.id === socket.id && room.presenter.webRtcEndpoint) { + console.info('Sending presenter candidate'); + room.presenter.webRtcEndpoint.addIceCandidate(candidate); + } + else if (room.viewers[socket.id] && room.viewers[socket.id].webRtcEndpoint) { + console.info('Sending viewer candidate'); + room.viewers[socket.id].webRtcEndpoint.addIceCandidate(candidate); + } + else { + console.info('Queueing candidate'); + if (!candidatesQueue[socket.id]) { + candidatesQueue[socket.id] = []; + } + candidatesQueue[socket.id].push(candidate); + } +} + +app.use(function (req, res, next) { + // Website you wish to allow to connect + res.setHeader('Access-Control-Allow-Origin', '*'); + + next(); +}); + +app.use(express.static(path.join(__dirname, 'static'))); diff --git a/static/.bower.json.swp b/static/.bower.json.swp new file mode 100644 index 0000000..c784b8b Binary files /dev/null and b/static/.bower.json.swp differ diff --git a/static/bower.json b/static/bower.json new file mode 100644 index 0000000..3d40a54 --- /dev/null +++ b/static/bower.json @@ -0,0 +1,29 @@ +{ + "name": "kurento-one2many-call", + "description": "Kurento Browser JavaScript Tutorial", + "authors": [ + "Kurento " + ], + "main": "index.html", + "moduleType": [ + "globals" + ], + "license": "LGPL", + "homepage": "http://www.kurento.org/", + "private": true, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "adapter.js": "v0.2.9", + "bootstrap": "~3.3.0", + "ekko-lightbox": "~3.3.0", + "demo-console": "1.5.1", + "kurento-utils": "master", + "socket.io-client": "^1.4.5" + } +} diff --git a/static/css/kurento.css b/static/css/kurento.css new file mode 100644 index 0000000..1aaf342 --- /dev/null +++ b/static/css/kurento.css @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2014-2015 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 { + min-height: 120px; + max-height: 360px; +} + +#videoContainer { + position: absolute; + float: left; +} + +#videoBig { + width: 640px; + height: 480px; + top: 0; + left: 0; + z-index: 1; +} + +div#videoSmall { + width: 240px; + height: 180px; + padding: 0px; + position: absolute; + top: 15px; + left: 400px; + cursor: pointer; + z-index: 10; + padding: 0px; +} + +div.dragged { + cursor: all-scroll !important; + border-color: blue !important; + z-index: 10 !important; +} diff --git a/static/img/kurento.png b/static/img/kurento.png new file mode 100644 index 0000000..6f1a4ad Binary files /dev/null and b/static/img/kurento.png differ diff --git a/static/img/naevatec.png b/static/img/naevatec.png new file mode 100644 index 0000000..05ee704 Binary files /dev/null and b/static/img/naevatec.png differ diff --git a/static/img/pipeline.png b/static/img/pipeline.png new file mode 100644 index 0000000..3360c0d Binary files /dev/null and b/static/img/pipeline.png differ diff --git a/static/img/spinner.gif b/static/img/spinner.gif new file mode 100644 index 0000000..8be8ba3 Binary files /dev/null and b/static/img/spinner.gif differ diff --git a/static/img/transparent-1px.png b/static/img/transparent-1px.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/static/img/transparent-1px.png differ diff --git a/static/img/urjc.gif b/static/img/urjc.gif new file mode 100644 index 0000000..cd8a770 Binary files /dev/null and b/static/img/urjc.gif differ diff --git a/static/img/webrtc.png b/static/img/webrtc.png new file mode 100644 index 0000000..d47e2e4 Binary files /dev/null and b/static/img/webrtc.png differ diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..035a0d3 --- /dev/null +++ b/static/index.html @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Kurento + + + +
+ +
+ +
+ + + + + + diff --git a/static/js/index.js b/static/js/index.js new file mode 100644 index 0000000..1b02b92 --- /dev/null +++ b/static/js/index.js @@ -0,0 +1,205 @@ +/* + * (C) Copyright 2014-2015 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. + * + */ + +//var ws = new WebSocket('wss://' + location.host + '/one2many'); + + +var video; +var webRtcPeer; +var socket; +var autoView = true; +var room; + +$(function() { + socket = io(); + console = new Console(); + video = $('#video')[0]; + room = $('#roomName'); + + $('#call').on('click', function(e) { presenter(); e.preventDefault(); } ); + $('#viewer').on('click', function(e) { viewer(); e.preventDefault(); } ); + $('#terminate').on('click', function(e) { stop(); e.preventDefault();} ); + + +socket.on('connect', function(){ + console.log('Connected to socket'); + + socket.emit('subscribeToStream', currentRoom()); +}); + +socket.on('disconnect', function(){ + console.log('Disconnected from socket'); + dispose(); +}); + +socket.on('presenterResponse', function(data) { + presenterResponse(data); +}); + +socket.on('viewerResponse', function(data) { + viewerResponse(data); +}); + +socket.on('stopCommunication', function(data) { + console.log('stopCommunication'); + dispose(); +}); + +socket.on('iceCandidate', function(data) { + webRtcPeer.addIceCandidate(data.candidate) +}); + +socket.on('streamStarted', function(data) { + if (autoView) { + viewer(); + } +}); + +}); +function presenterResponse(message) { + if (message.response != 'accepted') { + var errorMsg = message.message ? message.message : 'Unknown error'; + console.warn('Call not accepted for the following reason: ' + errorMsg); + dispose(); + } else { + webRtcPeer.processAnswer(message.sdpAnswer); + } +} + +function viewerResponse(message) { + if (message.response != 'accepted') { + var errorMsg = message.message ? message.message : 'Unknown error'; + console.warn('Call not accepted for the following reason: ' + errorMsg); + dispose(); + } else { + webRtcPeer.processAnswer(message.sdpAnswer); + } +} + +function onError(obj) { + console.log(obj); +} + +function presenter() { + if (!webRtcPeer) { + showSpinner(video); + + var options = { + localVideo: video, + onicecandidate : onIceCandidate + }; + + webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerSendonly(options, function(error) { + if(error) return onError(error); + + this.generateOffer(onOfferPresenter); + }); + } +} + +function onOfferPresenter(error, offerSdp) { + if (error) return onError(error); + + var message = { + sdpOffer : offerSdp, + room: currentRoom() + }; + + socket.emit('presenter', message); +} + +function viewer() { + autoView = true; + if (!webRtcPeer) { + showSpinner(video); + + var options = { + remoteVideo: video, + onicecandidate : onIceCandidate + }; + + webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, function(error) { + if(error) return onError(error); + + this.generateOffer(onOfferViewer); + }); + } +} + +function onOfferViewer(error, offerSdp) { + if (error) return onError(error); + + var message = { + sdpOffer : offerSdp, + room: currentRoom() + }; + socket.emit('viewer', message); +} + +function onIceCandidate(candidate) { + //console.log('Local candidate' + JSON.stringify(candidate)); + socket.emit('onIceCandidate', {candidate : candidate}); +} + +function stop() { + autoView = false; + if (webRtcPeer) { + socket.emit('stop'); + dispose(); + } +} + +function dispose() { + if (webRtcPeer) { + webRtcPeer.dispose(); + webRtcPeer = null; + } + hideSpinner(video); +} + +function sendMessage(payload) { + var event = payload.id, + message = payload; + console.log('Sending message - ' + event + ': ', message); + + socket.emit(event, payload); +} + +function showSpinner() { + for (var i = 0; i < arguments.length; i++) { + arguments[i].poster = './img/transparent-1px.png'; + arguments[i].style.background = 'center transparent url("./img/spinner.gif") no-repeat'; + } +} + +function hideSpinner() { + for (var i = 0; i < arguments.length; i++) { + arguments[i].src = ''; + arguments[i].poster = './img/webrtc.png'; + arguments[i].style.background = ''; + } +} + +function currentRoom() { + return $('#roomName').val(); +} + +/** + * Lightbox utility (to display media pipeline image in a modal dialog) + */ +$(document).delegate('*[data-toggle="lightbox"]', 'click', function(event) { + event.preventDefault(); + $(this).ekkoLightbox(); +});