diff --git a/openvidu-basic-java/.gitignore b/openvidu-basic-java/.gitignore
new file mode 100644
index 00000000..950fc085
--- /dev/null
+++ b/openvidu-basic-java/.gitignore
@@ -0,0 +1,24 @@
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+target/
diff --git a/openvidu-basic-java/pom.xml b/openvidu-basic-java/pom.xml
new file mode 100644
index 00000000..8407db05
--- /dev/null
+++ b/openvidu-basic-java/pom.xml
@@ -0,0 +1,52 @@
+
+ 4.0.0
+
+ io.openvidu
+ openvidu-basic-java
+ 2.22.0
+ jar
+
+ openvidu-basic-java
+ https://github.com/OpenVidu/openvidu-tutorials/tree/master/openvidu-basic-java
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.7.0
+
+
+
+ UTF-8
+ 1.8
+ io.openvidu.basic.java.App
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ io.openvidu
+ openvidu-java-client
+ 2.22.0
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/openvidu-basic-java/src/main/java/io/openvidu/basic/java/App.java b/openvidu-basic-java/src/main/java/io/openvidu/basic/java/App.java
new file mode 100644
index 00000000..51d38690
--- /dev/null
+++ b/openvidu-basic-java/src/main/java/io/openvidu/basic/java/App.java
@@ -0,0 +1,13 @@
+package io.openvidu.basic.java;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class App {
+
+ public static void main(String[] args) {
+ SpringApplication.run(App.class, args);
+ }
+
+}
diff --git a/openvidu-basic-java/src/main/java/io/openvidu/basic/java/Controller.java b/openvidu-basic-java/src/main/java/io/openvidu/basic/java/Controller.java
new file mode 100644
index 00000000..f46ebd78
--- /dev/null
+++ b/openvidu-basic-java/src/main/java/io/openvidu/basic/java/Controller.java
@@ -0,0 +1,72 @@
+package io.openvidu.basic.java;
+
+import java.util.Map;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import io.openvidu.java.client.Connection;
+import io.openvidu.java.client.ConnectionProperties;
+import io.openvidu.java.client.OpenVidu;
+import io.openvidu.java.client.OpenViduHttpException;
+import io.openvidu.java.client.OpenViduJavaClientException;
+import io.openvidu.java.client.Session;
+import io.openvidu.java.client.SessionProperties;
+
+@RestController
+public class Controller {
+
+ @Value("${OPENVIDU_URL}")
+ private String OPENVIDU_URL;
+
+ @Value("${OPENVIDU_SECRET}")
+ private String OPENVIDU_SECRET;
+
+ private OpenVidu openvidu;
+
+ private Utils utils = new Utils();
+
+ @PostConstruct
+ public void init() {
+ this.openvidu = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET);
+ }
+
+ /**
+ * @param params The Session properties
+ * @return The Session ID
+ */
+ @PostMapping("/session")
+ public ResponseEntity initializeSession(@RequestBody Map params)
+ throws OpenViduJavaClientException, OpenViduHttpException {
+ SessionProperties properties = utils.generateSessionProperties(params);
+ Session session = openvidu.createSession(properties);
+ return new ResponseEntity<>(session.getSessionId(), HttpStatus.OK);
+ }
+
+ /**
+ * @param sessionId The Session in which to create the Connection
+ * @param params The Connection properties
+ * @return The Token associated to the Connection
+ */
+ @PostMapping("/session/{sessionId}/connection")
+ public ResponseEntity createConnection(@PathVariable("sessionId") String sessionId,
+ @RequestBody Map params) throws OpenViduJavaClientException, OpenViduHttpException {
+ openvidu.fetch();
+ Session session = openvidu.getActiveSessions().stream().filter(s -> sessionId.equals(s.getSessionId()))
+ .findFirst().orElse(null);
+ if (session == null) {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+ ConnectionProperties properties = utils.generateConnectionProperties(params);
+ Connection connection = session.createConnection(properties);
+ return new ResponseEntity<>(connection.getToken(), HttpStatus.OK);
+ }
+
+}
diff --git a/openvidu-basic-java/src/main/java/io/openvidu/basic/java/Utils.java b/openvidu-basic-java/src/main/java/io/openvidu/basic/java/Utils.java
new file mode 100644
index 00000000..990eb4ae
--- /dev/null
+++ b/openvidu-basic-java/src/main/java/io/openvidu/basic/java/Utils.java
@@ -0,0 +1,146 @@
+package io.openvidu.basic.java;
+
+import java.util.List;
+import java.util.Map;
+
+import io.openvidu.java.client.ConnectionProperties;
+import io.openvidu.java.client.ConnectionType;
+import io.openvidu.java.client.IceServerProperties;
+import io.openvidu.java.client.KurentoOptions;
+import io.openvidu.java.client.MediaMode;
+import io.openvidu.java.client.OpenViduRole;
+import io.openvidu.java.client.Recording.OutputMode;
+import io.openvidu.java.client.RecordingLayout;
+import io.openvidu.java.client.RecordingMode;
+import io.openvidu.java.client.RecordingProperties;
+import io.openvidu.java.client.SessionProperties;
+import io.openvidu.java.client.VideoCodec;
+
+/**
+ * This class transforms raw REST API parameters to OpenVidu Java SDK classes
+ */
+public class Utils {
+
+ public SessionProperties generateSessionProperties(Map params) {
+ SessionProperties.Builder builder = new SessionProperties.Builder();
+ if (params.containsKey("mediaMode")) {
+ builder.mediaMode(MediaMode.valueOf((String) params.get("mediaMode")));
+ }
+ if (params.containsKey("recordingMode")) {
+ builder.recordingMode(RecordingMode.valueOf((String) params.get("recordingMode")));
+ }
+ if (params.containsKey("customSessionId")) {
+ builder.customSessionId((String) params.get("customSessionId"));
+ }
+ if (params.containsKey("forcedVideoCodec")) {
+ builder.forcedVideoCodec(VideoCodec.valueOf((String) params.get("forcedVideoCodec")));
+ }
+ if (params.containsKey("allowTranscoding")) {
+ builder.allowTranscoding((Boolean) params.get("allowTranscoding"));
+ }
+ if (params.containsKey("defaultRecordingProperties")) {
+ RecordingProperties.Builder defaultRecordingProperties = new RecordingProperties.Builder();
+ Map recordingProperties = (Map) params.get("defaultRecordingProperties");
+ if (recordingProperties.containsKey("name")) {
+ defaultRecordingProperties.name((String) recordingProperties.get("name"));
+ }
+ if (recordingProperties.containsKey("hasAudio")) {
+ defaultRecordingProperties.hasAudio((boolean) recordingProperties.get("hasAudio"));
+ }
+ if (recordingProperties.containsKey("hasVideo")) {
+ defaultRecordingProperties.hasVideo((boolean) recordingProperties.get("hasVideo"));
+ }
+ if (recordingProperties.containsKey("outputMode")) {
+ defaultRecordingProperties
+ .outputMode(OutputMode.valueOf((String) recordingProperties.get("outputMode")));
+ }
+ if (recordingProperties.containsKey("recordingLayout")) {
+ defaultRecordingProperties
+ .recordingLayout(RecordingLayout.valueOf((String) recordingProperties.get("recordingLayout")));
+ }
+ if (recordingProperties.containsKey("resolution")) {
+ defaultRecordingProperties.resolution((String) recordingProperties.get("resolution"));
+ }
+ if (recordingProperties.containsKey("frameRate")) {
+ defaultRecordingProperties.frameRate((int) recordingProperties.get("frameRate"));
+ }
+ if (recordingProperties.containsKey("shmSize")) {
+ defaultRecordingProperties.shmSize((long) recordingProperties.get("shmSize"));
+ }
+ if (recordingProperties.containsKey("ignoreFailedStreams")) {
+ defaultRecordingProperties
+ .ignoreFailedStreams((boolean) recordingProperties.get("ignoreFailedStreams"));
+ }
+ if (recordingProperties.containsKey("mediaNode")) {
+ Map mediaNodeInfo = (Map) recordingProperties.get("mediaNode");
+ if (mediaNodeInfo.containsKey("id")) {
+ defaultRecordingProperties.mediaNode((String) mediaNodeInfo.get("id"));
+ }
+ }
+ }
+ return builder.build();
+ }
+
+ public ConnectionProperties generateConnectionProperties(Map params) {
+ ConnectionProperties.Builder builder = new ConnectionProperties.Builder();
+ if (params.containsKey("type")) {
+ builder.type(ConnectionType.valueOf((String) params.get("type")));
+ }
+ if (params.containsKey("data")) {
+ builder.data((String) params.get("data"));
+ }
+ if (params.containsKey("record")) {
+ builder.record((boolean) params.get("record"));
+ }
+ if (params.containsKey("role")) {
+ builder.role(OpenViduRole.valueOf((String) params.get("role")));
+ }
+ if (params.containsKey("rtspUri")) {
+ builder.rtspUri((String) params.get("rtspUri"));
+ }
+ if (params.containsKey("adaptativeBitrate")) {
+ builder.adaptativeBitrate((boolean) params.get("adaptativeBitrate"));
+ }
+ if (params.containsKey("onlyPlayWithSubscribers")) {
+ builder.onlyPlayWithSubscribers((boolean) params.get("onlyPlayWithSubscribers"));
+ }
+ if (params.containsKey("networkCache")) {
+ builder.networkCache((int) params.get("networkCache"));
+ }
+ if (params.containsKey("kurentoOptions")) {
+ Map kurentoOptions = (Map) params.get("kurentoOptions");
+ KurentoOptions.Builder kurentoOptionsBuilder = new KurentoOptions.Builder();
+ if (kurentoOptions.containsKey("videoMaxRecvBandwidth")) {
+ kurentoOptionsBuilder.videoMaxRecvBandwidth((int) kurentoOptions.get("videoMaxRecvBandwidth"));
+ }
+ if (kurentoOptions.containsKey("videoMinRecvBandwidth")) {
+ kurentoOptionsBuilder.videoMinRecvBandwidth((int) kurentoOptions.get("videoMinRecvBandwidth"));
+ }
+ if (kurentoOptions.containsKey("videoMaxSendBandwidth")) {
+ kurentoOptionsBuilder.videoMaxSendBandwidth((int) kurentoOptions.get("videoMaxSendBandwidth"));
+ }
+ if (kurentoOptions.containsKey("videoMinSendBandwidth")) {
+ kurentoOptionsBuilder.videoMinSendBandwidth((int) kurentoOptions.get("videoMinSendBandwidth"));
+ }
+ if (kurentoOptions.containsKey("allowedFilters")) {
+ List allowedFiltersList = (List) kurentoOptions.get("allowedFilters");
+ String[] allowedFiltersArray = allowedFiltersList.stream().toArray(String[]::new);
+ kurentoOptionsBuilder.allowedFilters(allowedFiltersArray);
+ }
+ builder.kurentoOptions(kurentoOptionsBuilder.build());
+ }
+ if (params.containsKey("customIceServers")) {
+ List