getSessionIdToken(@RequestBody String sessionNameParam,
HttpSession httpSession) throws ParseException {
// Check the user is logged ...
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") + "\"}";
// Build tokenOptions object with the serverData and the role
TokenOptions tokenOptions = new TokenOptions.Builder().data(serverData).role(role).build();
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 created tokenOptions
String token = session.generateToken(tokenOptions);
// 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 name and 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 wouldn'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 ---
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 created tokenOptions
String token = this.mapSessions.get(sessionName).generateToken(tokenOptions);
// 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 also be 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. Apart from calling `leaveSession()` (and therefore `session.disconnect()`) to destroy the connection on openvidu-server, we need to run the last HTTP operation: 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. To sum up, `session.disconnect()` updates our openvidu-server and the POST operation updates our backend.
For the POST operation, in `app.js` we run:
```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 {
// Check the user is logged ...
// 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 just one of the many possible approaches: **you can implement your frontend and your backend as you want**.
>
> The only actual requirements are getting ***sessionId*** and ***token*** params from ***openvidu-server*** (by using one of the available clients or with the REST API) and using them along with ***openvidu-browser*** to connect your clients to the sessions.