getSessionIdToken(@RequestBody String sessionNameParam,
+ HttpSession httpSession) throws ParseException {
+
+ JSONObject sessionJSON = (JSONObject) new JSONParser().parse(sessionNameParam);
+
+ // The video-call to connect ("TUTORIAL")
+ String sessionName = (String) sessionJSON.get("session");
+
+ // Role associated to this user
+ OpenViduRole role = LoginController.users.get(httpSession.getAttribute("loggedUser")).role;
+
+ // Optional data to be passed to other users when this user connects to the video-call
+ // In this case, a JSON with the value we stored in the HttpSession object on login
+ String serverData = "{\"serverData\": \"" + httpSession.getAttribute("loggedUser") + "\"}";
+
+ JSONObject responseJson = new JSONObject();
+ ```
+
+ Just after that an _if-else_ statement comes into play: does the session "TUTORIAL" already exitsts?
+ ```java
+ if (this.mapSessions.get(sessionName) != null) { ...
+ ```
+ In this case it doesn't because 'publisher1' is the first user connecting to it. So we focus on the _else_ branch:
+
+ ```java
+ else {
+ // New session: return a new sessionId and a new token
+ try {
+
+ // Create a new OpenVidu Session
+ Session session = this.openVidu.createSession();
+ // Get the sessionId
+ String sessionId = session.getSessionId();
+ // Generate a new token with the recently retrieved serverData and role
+ String token = session.generateToken(new
+ TokenOptions.Builder().data(serverData).role(role).build());
+
+ // Store the session and the token in our collections
+ this.mapSessions.put(sessionName, session);
+ this.mapSessionIdsTokens.put(sessionId, new ConcurrentHashMap<>());
+ this.mapSessionIdsTokens.get(sessionId).put(token, OpenViduRole.PUBLISHER);
+
+ // Prepare the response with the sessionId and the token
+ responseJson.put(0, sessionId);
+ responseJson.put(1, token);
+
+ // Return the response to the client
+ return new ResponseEntity<>(responseJson, HttpStatus.OK);
+
+ } catch (Exception e) {
+ // If error generate an error message and return it to client
+ return getErrorResponse(e);
+ }
+ }
+ ```
+ We are almost there! Now in `app.js` we can init a new Session with _sessionId_ and connect to it with _token_:
+
+ ```javascript
+ // --- 1) Get an OpenVidu object and init a session with the retrieved sessionId ---
+
+ OV = new OpenVidu();
+ session = OV.initSession(sessionId);
+
+
+ // --- 2) Specify the actions when events take place ---
+
+ // On every new Stream received...
+ session.on('streamCreated', function (event) {
+
+ // Subscribe to the Stream to receive it
+ // HTML video will be appended to element with 'subscriber' id
+ var subscriber = session.subscribe(event.stream, 'subscriber');
+
+ // When the HTML video has been appended to DOM...
+ subscriber.on('videoElementCreated', function (event) {
+
+ // Add a new element for the user's name and nickname just below its video
+ appendUserData(event.element, subscriber.stream.connection);
+ });
+ });
+
+ // On every Stream destroyed...
+ session.on('streamDestroyed', function (event) {
+ // Delete the HTML element with the user's nickname
+ removeUserData(event.stream.connection);
+ });
+
+
+ // --- 3) Connect to the session passing the retrieved token and some more data from
+ // the client (in this case a JSON with the nickname chosen by the user) ---
+
+ session.connect(token, '{"clientData": "' + $("#participantName").val() + '"}', function (err) {
+
+ // If the connection is successful, initialize a publisher and publish to the session
+ if (!err) {
+
+ // Here we check somehow if the user has at least 'PUBLISHER' role before
+ // trying to publish its stream. Even if someone modified the client's code and
+ // published the stream, it won't work if the token sent in Session.connect
+ // method doesn't belong to a 'PUBLIHSER' role
+ if (isPublisher()) {
+
+ // --- 4) Get your own camera stream and publish it ---
+
+ var publisher = OV.initPublisher('publisher', {
+ audio: true,
+ video: true,
+ quality: 'MEDIUM'
+ });
+
+
+ // --- 5) Publish your stream ---
+
+ session.publish(publisher);
+
+ } else {
+ console.warn('You don\'t have permissions to publish');
+ }
+ } else {
+ console.warn('Error connecting to the session:', error.code, error.message);
+ }
+
+ // HTML shows session page ...
+
+ });
+ ```
+ The user will now see its own video on the page. The connection to the session has completed!
+
+
+3. **Another user connects to the video-call**
+The process would be exactly the same as before until `SessionController.java` executes `getSessionIdAndToken()` method. Now session 'TUTORIAL' already exists, so in the _if-else_ statement the _if_ branch would be the one executed:
+
+ ```java
+ if (this.mapSessions.get(sessionName) != null) {
+ // Session already exists: return existing sessionId and a new token
+ try {
+
+ // Get the existing sessionId from our collection with
+ // the sessionName param ("TUTORIAL")
+ String sessionId = this.mapSessions.get(sessionName).getSessionId();
+ // Generate a new token with the recently retrieved serverData and role
+ String token = this.mapSessions.get(sessionName)
+ .generateToken(new
+ TokenOptions.Builder().data(serverData).role(role).build());
+
+ // Update our collection storing the new token
+ this.mapSessionIdsTokens.get(sessionId).put(token, OpenViduRole.PUBLISHER);
+
+ // Prepare the response with the sessionId and the token
+ responseJson.put(0, sessionId);
+ responseJson.put(1, token);
+
+ // Return the response to the client
+ return new ResponseEntity<>(responseJson, HttpStatus.OK);
+
+ } catch (Exception e) {
+ // If error generate an error message and return it to client
+ return getErrorResponse(e);
+ }
+ }
+ ```
+ The code executed in `app.js` would be also the same. After the `Session.publish()` method has been succesful, both users will be seeing each other's video, as well as the username and the nickname below it.
+
+4. **Users leave the video-call**
+
+ After a while both users decide to leave the session. Here is where the last HTTP operation takes place: we must let the backend know that certain user has left the session so it can update the collections with the active sessions and tokens.
+ In `app.js` we run the following HTTP POST operation:
+
+ ```javascript
+ function removeUser() {
+ // Body of POST request with the name of the session and the token of the leaving user
+ var jsonBody = JSON.stringify({
+ 'sessionName': sessionName,
+ 'token': token
+ });
+
+ // Send POST request
+ httpRequest('POST', '/api-sessions/remove-user', jsonBody,
+ 'User couldn\'t be removed from session', function successCallback(response) {
+ console.warn(userName + ' correctly removed from session ' + sessionName);
+ });
+ }
+ ```
+ And in `SessionController.java` we update the collections:
+
+ ```java
+ @RequestMapping(value = "/api-sessions/remove-user", method = RequestMethod.POST)
+ public ResponseEntity removeUser(@RequestBody String sessionNameToken,
+ HttpSession httpSession) throws Exception {
+
+ // Retrieve the params from BODY
+ JSONObject sessionNameTokenJSON = (JSONObject) new JSONParser().parse(sessionNameToken);
+ String sessionName = (String) sessionNameTokenJSON.get("sessionName");
+ String token = (String) sessionNameTokenJSON.get("token");
+
+ // If the session exists ("TUTORIAL" in this case)
+ if (this.mapSessions.get(sessionName) != null) {
+ String sessionId = this.mapSessions.get(sessionName).getSessionId();
+
+ if (this.mapSessionIdsTokens.containsKey(sessionId)) {
+ // If the token exists
+ if (this.mapSessionIdsTokens.get(sessionId).remove(token) != null) {
+ // Token has been removed
+ if (this.mapSessionIdsTokens.get(sessionId).isEmpty()) {
+ // Last user left: session "TUTORIAL" must be removed
+ this.mapSessions.remove(sessionName);
+ }
+ return new ResponseEntity<>(HttpStatus.OK);
+ } else {
+ // The TOKEN wasn't valid
+ return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ } else {
+ // The SESSIONID wasn't valid
+ return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ } else {
+ // The SESSION does not exist
+ return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+ }
+ ```
+ When the last user leaves the session `this.mapSessions.remove(sessionName);` will be executed: this means the session is empty and that it is going to be closed. The _sessionId_ and all _token_ params associated to it will be invalidated.
+
+---
+
+> At this point we have covered all the important code from the tutorial. With this scenario we have seen the most common use-case, but you can modify whatever you want to suit your needs. And remember that this is one single approach, using certain technologies: **you can implement your frontend and your backend as you want**. The only actual requirements are getting ***sessionId*** and ***token*** params from ***openvidu-server*** and using them along with ***openvidu-browser*** to connect your clients to the sessions.
\ No newline at end of file