diff --git a/openvidu-recording-java/pom.xml b/openvidu-recording-java/pom.xml index 7ba8537c..66c6d30d 100644 --- a/openvidu-recording-java/pom.xml +++ b/openvidu-recording-java/pom.xml @@ -95,7 +95,7 @@ io.openvidu openvidu-java-client - 1.8.0 + 2.0.0 diff --git a/openvidu-recording-java/src/main/java/io/openvidu/js/java/MyRestController.java b/openvidu-recording-java/src/main/java/io/openvidu/js/java/MyRestController.java index 10d426da..db61edbd 100644 --- a/openvidu-recording-java/src/main/java/io/openvidu/js/java/MyRestController.java +++ b/openvidu-recording-java/src/main/java/io/openvidu/js/java/MyRestController.java @@ -1,9 +1,11 @@ package io.openvidu.js.java; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; @@ -16,9 +18,10 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; -import io.openvidu.java.client.Archive; +import io.openvidu.java.client.Recording; import io.openvidu.java.client.OpenVidu; -import io.openvidu.java.client.OpenViduException; +import io.openvidu.java.client.OpenViduHttpException; +import io.openvidu.java.client.OpenViduJavaClientException; import io.openvidu.java.client.Session; import io.openvidu.java.client.TokenOptions; import io.openvidu.java.client.OpenViduRole; @@ -27,13 +30,19 @@ import io.openvidu.java.client.OpenViduRole; @RequestMapping("/api") public class MyRestController { - OpenVidu openVidu; + // OpenVidu object as entrypoint of the SDK + private OpenVidu openVidu; + // Collection to pair session names and OpenVidu Session objects private Map mapSessions = new ConcurrentHashMap<>(); - private Map> mapSessionIdsTokens = new ConcurrentHashMap<>(); + // Collection to pair session names and tokens (the inner Map pairs tokens and role associated) + private Map> mapSessionNamesTokens = new ConcurrentHashMap<>(); + // Collection to pair session names and recording objects private Map sessionRecordings = new ConcurrentHashMap<>(); + // URL where our OpenVidu server is listening private String OPENVIDU_URL; + // Secret shared with our OpenVidu server private String SECRET; public MyRestController(@Value("${openvidu.secret}") String secret, @Value("${openvidu.url}") String openviduUrl) { @@ -46,15 +55,15 @@ public class MyRestController { /*** Session API ***/ /*******************/ - @RequestMapping(value = "/get-sessionid-token", method = RequestMethod.POST) - public ResponseEntity getSessionIdToken(@RequestBody String sessionNameParam) throws ParseException { + @RequestMapping(value = "/get-token", method = RequestMethod.POST) + public ResponseEntity getToken(@RequestBody String sessionNameParam) throws ParseException { System.out.println("Getting sessionId and token | {sessionName}=" + sessionNameParam); JSONObject sessionJSON = (JSONObject) new JSONParser().parse(sessionNameParam); // The video-call to connect ("TUTORIAL") - String sessionName = (String) sessionJSON.get("session"); + String sessionName = (String) sessionJSON.get("sessionName"); // Role associated to this user OpenViduRole role = OpenViduRole.PUBLISHER; @@ -65,22 +74,18 @@ public class MyRestController { JSONObject responseJson = new JSONObject(); if (this.mapSessions.get(sessionName) != null) { - // Session already exists: return existing sessionId and a new token + // Session already exists System.out.println("Existing session " + sessionName); 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, role); + this.mapSessionNamesTokens.get(sessionName).put(token, role); - // Prepare the response with the sessionId and the token - responseJson.put(0, sessionId); - responseJson.put(1, token); + // Prepare the response with the token + responseJson.put(0, token); // Return the response to the client return new ResponseEntity<>(responseJson, HttpStatus.OK); @@ -91,25 +96,22 @@ public class MyRestController { } } else { - // New session: return a new sessionId and token + // New session System.out.println("New session " + sessionName); 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, role); + this.mapSessionNamesTokens.put(sessionName, new ConcurrentHashMap<>()); + this.mapSessionNamesTokens.get(sessionName).put(token, role); // Prepare the response with the sessionId and the token - responseJson.put(0, sessionId); - responseJson.put(1, token); + responseJson.put(0, token); // Return the response to the client return new ResponseEntity<>(responseJson, HttpStatus.OK); @@ -131,30 +133,23 @@ public class MyRestController { 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 the session exists + if (this.mapSessions.get(sessionName) != null && this.mapSessionNamesTokens.get(sessionName) != null) { - if (this.mapSessionIdsTokens.containsKey(sessionId)) { - // If the token exists - if (this.mapSessionIdsTokens.get(sessionId).remove(token) != null) { - // User left the session - if (this.mapSessionIdsTokens.get(sessionId).isEmpty() - && !this.sessionRecordings.containsKey(sessionId)) { - // Last user left and recording is not taking place: session must be removed - this.mapSessions.remove(sessionName); - } - return new ResponseEntity<>(HttpStatus.OK); - } else { - // The TOKEN wasn't valid - System.out.println("Problems in the app server: the TOKEN wasn't valid"); - return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); + // If the token exists + if (this.mapSessionNamesTokens.get(sessionName).remove(token) != null) { + // User left the session + if (this.mapSessionNamesTokens.get(sessionName).isEmpty()) { + // Last user left: session must be removed + this.mapSessions.remove(sessionName); } + return new ResponseEntity<>(HttpStatus.OK); } else { - // The SESSIONID wasn't valid - System.out.println("Problems in the app server: the SESSIONID wasn't valid"); + // The TOKEN wasn't valid + System.out.println("Problems in the app server: the TOKEN wasn't valid"); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } + } else { // The SESSION does not exist System.out.println("Problems in the app server: the SESSION does not exist"); @@ -174,10 +169,10 @@ public class MyRestController { System.out.println("Starting recording | {sessionId}=" + sessionId); try { - Archive archive = this.openVidu.startRecording(sessionId); + Recording recording = this.openVidu.startRecording(sessionId); this.sessionRecordings.put(sessionId, true); - return new ResponseEntity<>(archive, HttpStatus.OK); - } catch (OpenViduException e) { + return new ResponseEntity<>(getJsonFromRecording(recording), HttpStatus.OK); + } catch (OpenViduJavaClientException | OpenViduHttpException e) { return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); } } @@ -190,10 +185,10 @@ public class MyRestController { System.out.println("Stoping recording | {recordingId}=" + recordingId); try { - Archive archive = this.openVidu.stopRecording(recordingId); - this.sessionRecordings.remove(archive.getSessionId()); - return new ResponseEntity<>(archive, HttpStatus.OK); - } catch (OpenViduException e) { + Recording recording = this.openVidu.stopRecording(recordingId); + this.sessionRecordings.remove(recording.getSessionId()); + return new ResponseEntity<>(getJsonFromRecording(recording), HttpStatus.OK); + } catch (OpenViduJavaClientException | OpenViduHttpException e) { return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); } } @@ -208,7 +203,7 @@ public class MyRestController { try { this.openVidu.deleteRecording(recordingId); return new ResponseEntity<>(HttpStatus.OK); - } catch (OpenViduException e) { + } catch (OpenViduJavaClientException | OpenViduHttpException e) { return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); } } @@ -219,9 +214,9 @@ public class MyRestController { System.out.println("Getting recording | {recordingId}=" + recordingId); try { - Archive archive = this.openVidu.getRecording(recordingId); - return new ResponseEntity<>(archive, HttpStatus.OK); - } catch (OpenViduException e) { + Recording recording = this.openVidu.getRecording(recordingId); + return new ResponseEntity<>(getJsonFromRecording(recording), HttpStatus.OK); + } catch (OpenViduJavaClientException | OpenViduHttpException e) { return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); } } @@ -232,13 +227,15 @@ public class MyRestController { System.out.println("Listing recordings"); try { - List archives = this.openVidu.listRecordings(); - return new ResponseEntity<>(archives, HttpStatus.OK); - } catch (OpenViduException e) { + List recordings = this.openVidu.listRecordings(); + + return new ResponseEntity<>(getJsonArrayFromRecordingList(recordings), HttpStatus.OK); + } catch (OpenViduJavaClientException | OpenViduHttpException e) { return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); } } + @SuppressWarnings("unchecked") private ResponseEntity getErrorResponse(Exception e) { JSONObject json = new JSONObject(); json.put("cause", e.getCause()); @@ -247,4 +244,30 @@ public class MyRestController { return new ResponseEntity<>(json, HttpStatus.INTERNAL_SERVER_ERROR); } + @SuppressWarnings("unchecked") + private JSONObject getJsonFromRecording(Recording recording) { + JSONObject json = new JSONObject(); + json.put("createdAt", recording.getCreatedAt()); + json.put("duration", recording.getDuration()); + json.put("hasAudio", recording.hasAudio()); + json.put("hasVideo", recording.hasVideo()); + json.put("id", recording.getId()); + json.put("recordingLayout", recording.getRecordingLayout()); + json.put("name", recording.getName()); + json.put("sessionId", recording.getSessionId()); + json.put("size", recording.getSize()); + json.put("status", recording.getStatus()); + json.put("url", recording.getUrl()); + return json; + } + + @SuppressWarnings("unchecked") + private JSONArray getJsonArrayFromRecordingList(Collection recordings) { + JSONArray array = new JSONArray(); + for (Recording recording : recordings) { + array.add(getJsonFromRecording(recording)); + } + return array; + } + } diff --git a/openvidu-recording-java/src/main/resources/application.properties b/openvidu-recording-java/src/main/resources/application.properties index a5cec57d..2463c1ef 100644 --- a/openvidu-recording-java/src/main/resources/application.properties +++ b/openvidu-recording-java/src/main/resources/application.properties @@ -5,5 +5,5 @@ server.ssl.key-store-password: openvidu server.ssl.key-store-type: JKS server.ssl.key-alias: openvidu-selfsigned -openvidu.url: https://localhost:8443/ +openvidu.url: https://localhost:4443/ openvidu.secret: MY_SECRET diff --git a/openvidu-recording-java/src/main/resources/static/app.js b/openvidu-recording-java/src/main/resources/static/app.js index 351bc15c..20510773 100644 --- a/openvidu-recording-java/src/main/resources/static/app.js +++ b/openvidu-recording-java/src/main/resources/static/app.js @@ -1,88 +1,94 @@ var OV; var session; -var sessionId; -var token; var sessionName; +var token; var numVideos = 0; /* OPENVIDU METHODS */ function joinSession() { - getSessionIdAndToken(function () { + getToken(function () { - // --- 1) Get an OpenVidu object and init a session with the retrieved sessionId --- + // --- 1) Get an OpenVidu object --- OV = new OpenVidu(); - session = OV.initSession(sessionId); + // --- 2) Init a session --- - // --- 2) Specify the actions when events take place --- + session = OV.initSession(); + + // --- 3) Specify the actions when events take place in the session --- // On every new Stream received... - session.on('streamCreated', function (event) { + session.on('streamCreated', (event) => { // Subscribe to the Stream to receive it // HTML video will be appended to element with 'video-container' id var subscriber = session.subscribe(event.stream, 'video-container'); // When the HTML video has been appended to DOM... - subscriber.on('videoElementCreated', function (event) { + subscriber.on('videoElementCreated', (event) => { // Add a new HTML element for the user's name and nickname over its video updateNumVideos(1); }); // When the HTML video has been appended to DOM... - subscriber.on('videoElementDestroyed', function (event) { + subscriber.on('videoElementDestroyed', (event) => { // Add a new HTML element for the user's name and nickname over its video updateNumVideos(-1); }); }); - // --- 3) Connect to the session passing the retrieved token --- + // --- 4) 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, null, function (error) { + session.connect(token) + .then(() => { - // If the connection is successful, initialize a publisher and publish to the session - if (!error) { + // --- 5) Set page layout for active call --- - // --- 4) Get your own camera stream --- + $('#session-title').text(sessionName); + $('#join').hide(); + $('#session').show(); + + // --- 6) Get your own camera stream --- var publisher = OV.initPublisher('video-container', { - audio: true, // Whether you want to transmit audio or not - video: true, // Whether you want to transmit video or not - audioActive: true, // Whether you want to start the publishing with your audio unmuted or muted - videoActive: true, // Whether you want to start the publishing with your video enabled or disabled - quality: 'MEDIUM', // The quality of your video ('LOW', 'MEDIUM', 'HIGH') - screen: false // true to get your screen as video source instead of your camera + audioSource: undefined, // The source of audio. If undefined default microphone + videoSource: undefined, // The source of video. If undefined default webcam + publishAudio: true, // Whether you want to start publishing with your audio unmuted or not + publishVideo: true, // Whether you want to start publishing with your video enabled or not + resolution: '640x480', // The resolution of your video + frameRate: 30, // The frame rate of your video + insertMode: 'APPEND', // How the video is inserted in the target element 'video-container' + mirror: false // Whether to mirror your local video or not }); + // --- 7) Specify the actions when events take place in our publisher --- + // When our HTML video has been added to DOM... - publisher.on('videoElementCreated', function (event) { + publisher.on('videoElementCreated', (event) => { updateNumVideos(1); $(event.element).prop('muted', true); // Mute local video }); // When the HTML video has been appended to DOM... - publisher.on('videoElementDestroyed', function (event) { + publisher.on('videoElementDestroyed', (event) => { // Add a new HTML element for the user's name and nickname over its video updateNumVideos(-1); }); - // --- 5) Publish your stream --- + // --- 8) Publish your stream --- session.publish(publisher); - } else { + }) + .catch(error => { console.warn('There was an error connecting to the session:', error.code, error.message); - } - }); - - $('#session-title').text(sessionName); - $('#join').hide(); - $('#session').show(); + }); return false; }); @@ -90,7 +96,7 @@ function joinSession() { function leaveSession() { - // 6) Leave the session by calling 'disconnect' method over the Session object + // --- 9) Leave the session by calling 'disconnect' method over the Session object --- session.disconnect(); session = null; @@ -106,33 +112,32 @@ function leaveSession() { /* APPLICATION REST METHODS */ -function getSessionIdAndToken(callback) { +function getToken(callback) { sessionName = $("#sessionName").val(); // Video-call chosen by the user - var jsonBody = JSON.stringify({ // Body of POST request - 'session': sessionName - }); - - // Send POST request - httpRequest('POST', 'api/get-sessionid-token', jsonBody, 'Request of SESSIONID and TOKEN gone WRONG:', function successCallback(response) { - sessionId = response[0]; // Get sessionId from response - token = response[1]; // Get token from response - console.warn('Request of SESSIONID and TOKEN gone WELL (SESSIONID:' + sessionId + ", TOKEN:" + token + ")"); - callback(); // Continue the join operation - }); + httpRequest( + 'POST', + 'api/get-token', + {sessionName: sessionName}, + 'Request of TOKEN gone WRONG:', + (response) => { + token = response[0]; // Get token from response + console.warn('Request of TOKEN gone WELL (TOKEN:' + token + ')'); + callback(token); // Continue the join operation + } + ); } 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/remove-user', jsonBody, 'User couldn\'t be removed from session', function successCallback(response) { - console.warn("User correctly removed from session"); - }); + httpRequest( + 'POST', + 'api/remove-user', + {sessionName: sessionName, token: token}, + 'User couldn\'t be removed from session', + (response) => { + console.warn("You have been removed from session " + sessionName); + } + ); } function httpRequest(method, url, body, errorMsg, callback) { @@ -141,7 +146,7 @@ function httpRequest(method, url, body, errorMsg, callback) { http.open(method, url, true); http.setRequestHeader('Content-type', 'application/json'); http.addEventListener('readystatechange', processRequest, false); - http.send(body); + http.send(JSON.stringify(body)); function processRequest() { if (http.readyState == 4) { @@ -163,48 +168,69 @@ function httpRequest(method, url, body, errorMsg, callback) { var recordingId; function startRecording() { - var jsonBody = JSON.stringify({ - 'session': session.sessionId - }); - httpRequest('POST', 'api/recording/start', jsonBody, 'Start recording WRONG', function successCallback(response) { - console.log(response); - recordingId = response.id; - $('#text-area').text(JSON.stringify(response, null, "\t")); - }); + httpRequest( + 'POST', + 'api/recording/start', + {session: session.sessionId}, + 'Start recording WRONG', + (response) => { + console.log(response); + recordingId = response.id; + $('#text-area').text(JSON.stringify(response, null, "\t")); + } + ); } function stopRecording() { - var jsonBody = JSON.stringify({ - 'recording': recordingId - }); - httpRequest('POST', 'api/recording/stop', jsonBody, 'Stop recording WRONG', function successCallback(response) { - console.log(response); - $('#text-area').text(JSON.stringify(response, null, "\t")); - }); + httpRequest( + 'POST', + 'api/recording/stop', + {recording: recordingId}, + 'Stop recording WRONG', + (response) => { + console.log(response); + $('#text-area').text(JSON.stringify(response, null, "\t")); + } + ); } function deleteRecording() { - var jsonBody = JSON.stringify({ - 'recording': recordingId - }); - httpRequest('DELETE', 'api/recording/delete', jsonBody, 'Delete recording WRONG', function successCallback() { - console.log("DELETE ok"); - $('#text-area').text("DELETE ok"); - }); + httpRequest( + 'DELETE', + 'api/recording/delete', + {recording: recordingId}, + 'Delete recording WRONG', + () => { + console.log("DELETE ok"); + $('#text-area').text("DELETE ok"); + } + ); } function getRecording() { - httpRequest('GET', 'api/recording/get/' + recordingId, '', 'Get recording WRONG', function successCallback(response) { - console.log(response); - $('#text-area').text(JSON.stringify(response, null, "\t")); - }); + httpRequest( + 'GET', + 'api/recording/get/' + recordingId, + {}, + 'Get recording WRONG', + (response) => { + console.log(response); + $('#text-area').text(JSON.stringify(response, null, "\t")); + } + ); } function listRecordings() { - httpRequest('GET', 'api/recording/list', '', 'List recordings WRONG', function successCallback(response) { - console.log(response); - $('#text-area').text(JSON.stringify(response, null, "\t")); - }); + httpRequest( + 'GET', + 'api/recording/list', + {}, + 'List recordings WRONG', + (response) => { + console.log(response); + $('#text-area').text(JSON.stringify(response, null, "\t")); + } + ); } /* APPLICATION REST METHODS */ diff --git a/openvidu-recording-java/src/main/resources/static/index.html b/openvidu-recording-java/src/main/resources/static/index.html index 9fafc009..69640063 100644 --- a/openvidu-recording-java/src/main/resources/static/index.html +++ b/openvidu-recording-java/src/main/resources/static/index.html @@ -7,17 +7,14 @@ - - - + + + - +