%%%%%%%%%%%%%%%%%%%%%%%%%%% JavaScript - Loopback stats %%%%%%%%%%%%%%%%%%%%%%%%%%% .. warning:: Bower dependencies are not yet upgraded for Kurento 7.0.0. Kurento tutorials that use pure browser JavaScript need to be rewritten to drop the deprecated Bower service and instead use a web resource packer. This has not been done, so these tutorials won't be able to download the dependencies they need to work. PRs would be appreciated! This web application extends :doc:`the Hello World tutorial <./tutorial-helloworld>` showing how statistics are collected. .. note:: Web browsers require using *HTTPS* to enable WebRTC, so the web server must use SSL and a certificate file. For instructions, check :ref:`features-security-js-https`. For convenience, this tutorial already provides dummy self-signed certificates (which will cause a security warning in the browser). Running this example ==================== First of all, install Kurento Media Server: :doc:`/user/installation`. Start the media server and leave it running in the background. Install :term:`Node.js`, :term:`Bower`, and a web server in your system: .. code-block:: shell curl -sSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt-get install -y nodejs sudo npm install -g bower sudo npm install -g http-server Here, we suggest using the simple Node.js ``http-server``, but you could use any other web server. You also need the source code of this tutorial. Clone it from GitHub, then start the web server: .. code-block:: shell git clone https://github.com/Kurento/kurento.git cd kurento/tutorials/javascript-browser/loopback-stats/ git checkout main bower install http-server -p 8443 --ssl --cert keys/server.crt --key keys/server.key When your web server is up and running, use a WebRTC compatible browser (Firefox, Chrome) to open the tutorial page: * If KMS is running in your local machine: .. code-block:: text https://localhost:8443/ * If KMS is running in a remote machine: .. code-block:: text https://localhost:8443/index.html?ws_uri=ws://{KMS_HOST}:8888/kurento .. note:: By default, this tutorial works out of the box by using non-secure WebSocket (``ws://``) to establish a client connection between the browser and KMS. This only works for ``localhost``. *It will fail if the web server is remote*. If you want to run this tutorial from a **remote web server**, then you have to do 3 things: 1. Configure **Secure WebSocket** in KMS. For instructions, check :ref:`features-security-kms-wss`. 2. In *index.js*, change the ``ws_uri`` to use Secure WebSocket (``wss://`` instead of ``ws://``) and the correct KMS port (TCP 8433 instead of TCP 8888). 3. As explained in the link from step 1, if you configured KMS to use Secure WebSocket with a self-signed certificate you now have to browse to ``https://{KMS_HOST}:8433/kurento`` and click to accept the untrusted certificate. Understanding this example ========================== The logic of the application is quite simple: the local stream is sent to the Kurento Media Server, which returns it back to the client without modifications. To implement this behavior we need to create a `Media Pipeline`:term: composed by the `Media Element`:term: **WebRtcEndpoint**, which holds the capability of exchanging full-duplex (bidirectional) WebRTC media flows. This media element is connected to itself so any received media (from browser) is send back (to browser). Using method ``getStats`` the application shows all stats of element **WebRtcEndpoint**. The complete source code of this demo can be found in `GitHub `_. JavaScript Logic ================ This demo follows a *Single Page Application* architecture (`SPA`:term:). The interface is the following HTML page: `index.html `_. This web page links two Kurento JavaScript libraries: * **kurento-client.js** : Implementation of the Kurento JavaScript Client. * **kurento-utils.js** : Kurento utility library aimed to simplify the WebRTC management in the browser. In addition, these two JavaScript libraries are also required: * **Bootstrap** : Web framework for developing responsive web sites. * **jquery.js** : Cross-platform JavaScript library designed to simplify the client-side scripting of HTML. * **adapter.js** : WebRTC JavaScript utility library maintained by Google that abstracts away browser differences. * **ekko-lightbox** : Module for Bootstrap to open modal images, videos, and galleries. * **demo-console** : Custom JavaScript console. The specific logic of this demo is coded in the following JavaScript page: `index.js `_. In this file, there is a function which is called when the green button labeled as *Start* in the GUI is clicked. .. sourcecode:: js var startButton = document.getElementById("start"); startButton.addEventListener("click", function() { var options = { localVideo: videoInput, remoteVideo: videoOutput }; webRtcPeer = kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv(options, function(error) { if(error) return onError(error) this.generateOffer(onOffer) }); [...] } The function *WebRtcPeer.WebRtcPeerSendrecv* hides internal details (i.e. PeerConnection and getUserStream) and makes possible to start a full-duplex WebRTC communication, using the HTML video tag with id *videoInput* to show the video camera (local stream) and the video tag *videoOutput* to show the remote stream provided by the Kurento Media Server. Inside this function, a call to *generateOffer* is performed. This function accepts a callback in which the SDP offer is received. In this callback we create an instance of the *KurentoClient* class that will manage communications with the Kurento Media Server. So, we need to provide the URI of its WebSocket endpoint. In this example, we assume it's listening in port TCP 8433 at the same host than the HTTP serving the application. .. sourcecode:: js [...] var args = getopts(location.search, { default: { ws_uri: 'wss://' + location.hostname + ':8433/kurento', ice_servers: undefined } }); [...] kurentoClient(args.ws_uri, function(error, client){ [...] }; Once we have an instance of ``kurentoClient``, the following step is to create a *Media Pipeline*, as follows: .. sourcecode:: js client.create("MediaPipeline", function(error, _pipeline){ [...] }); If everything works correctly, we have an instance of a media pipeline (variable ``pipeline`` in this example). With this instance, we are able to create *Media Elements*. In this example we just need a *WebRtcEndpoint*. Then, this media elements is connected itself: .. sourcecode:: js pipeline.create("WebRtcEndpoint", function(error, webRtc) { if (error) return onError(error); webRtcEndpoint = webRtc; setIceCandidateCallbacks(webRtcPeer, webRtc, onError) webRtc.processOffer(sdpOffer, function(error, sdpAnswer) { if (error) return onError(error); webRtc.gatherCandidates(onError); webRtcPeer.processAnswer(sdpAnswer, onError); }); webRtc.connect(webRtc, function(error) { if (error) return onError(error); console.log("Loopback established"); webRtcEndpoint.on('MediaStateChanged', function(event) { if (event.newState == "CONNECTED") { console.log("MediaState is CONNECTED ... printing stats...") activateStatsTimeout(); } }); }); }); .. note:: The :term:`TURN` and :term:`STUN` servers to be used can be configured simply adding the parameter ``ice_servers`` to the application URL, as follows: .. sourcecode:: bash https://localhost:8443/index.html?ice_servers=[{"urls":"stun:stun1.example.net"},{"urls":"stun:stun2.example.net"}] https://localhost:8443/index.html?ice_servers=[{"urls":"turn:turn.example.org","username":"user","credential":"myPassword"}] Dependencies ============ Demo dependencies are located in file `bower.json `_. `Bower`:term: is used to collect them. .. sourcecode:: js "dependencies": { "kurento-client": "7.3.0", "kurento-utils": "7.3.0" } .. note:: You can find the latest version of Kurento JavaScript Client at `Bower `_.