diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java
index 8b7da5d8..2239dcce 100644
--- a/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java
+++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/Session.java
@@ -25,11 +25,6 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonSyntaxException;
-
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpDelete;
@@ -40,6 +35,12 @@ import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonNull;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
+
public class Session {
private static final Logger log = LoggerFactory.getLogger(Session.class);
@@ -120,8 +121,22 @@ public class Session {
JsonObject json = new JsonObject();
json.addProperty("session", this.sessionId);
- json.addProperty("role", tokenOptions.getRole().name());
- json.addProperty("data", tokenOptions.getData());
+
+ if (tokenOptions.getData() != null) {
+ json.addProperty("data", tokenOptions.getData());
+ } else {
+ json.add("data", JsonNull.INSTANCE);
+ }
+ if (tokenOptions.getRole() != null) {
+ json.addProperty("role", tokenOptions.getRole().name());
+ } else {
+ json.add("role", JsonNull.INSTANCE);
+ }
+ if (tokenOptions.record() != null) {
+ json.addProperty("record", tokenOptions.record());
+ } else {
+ json.add("record", JsonNull.INSTANCE);
+ }
if (tokenOptions.getKurentoOptions() != null) {
JsonObject kurentoOptions = new JsonObject();
if (tokenOptions.getKurentoOptions().getVideoMaxRecvBandwidth() != null) {
diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/TokenOptions.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/TokenOptions.java
index 96c39fd6..41ba60af 100644
--- a/openvidu-java-client/src/main/java/io/openvidu/java/client/TokenOptions.java
+++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/TokenOptions.java
@@ -24,6 +24,7 @@ public class TokenOptions {
private String data;
private OpenViduRole role;
+ private Boolean record;
private KurentoOptions kurentoOptions;
/**
@@ -33,15 +34,16 @@ public class TokenOptions {
*/
public static class Builder {
- private String data = "";
- private OpenViduRole role = OpenViduRole.PUBLISHER;
+ private String data;
+ private OpenViduRole role;
+ private Boolean record;
private KurentoOptions kurentoOptions;
/**
* Builder for {@link io.openvidu.java.client.TokenOptions}
*/
public TokenOptions build() {
- return new TokenOptions(this.data, this.role, this.kurentoOptions);
+ return new TokenOptions(this.data, this.role, this.record, this.kurentoOptions);
}
/**
@@ -79,6 +81,17 @@ public class TokenOptions {
return this;
}
+ /**
+ * Call this method to flag the streams published by the participant
+ * owning this token to be recorded or not. This only affects INDIVIDUAL recording. If not set by default will be true
+ */
+ public Builder record(boolean record) {
+ this.record = record;
+ return this;
+ }
+
/**
* Call this method to set a {@link io.openvidu.java.client.KurentoOptions}
* object for this token
@@ -90,9 +103,10 @@ public class TokenOptions {
}
- private TokenOptions(String data, OpenViduRole role, KurentoOptions kurentoOptions) {
+ private TokenOptions(String data, OpenViduRole role, Boolean record, KurentoOptions kurentoOptions) {
this.data = data;
this.role = role;
+ this.record = record;
this.kurentoOptions = kurentoOptions;
}
@@ -110,6 +124,16 @@ public class TokenOptions {
return this.role;
}
+ /**
+ * Whether the streams published by the participant owning this token will be
+ * recorded or not. This only affects INDIVIDUAL recording
+ */
+ public Boolean record() {
+ return this.record;
+ }
+
/**
* Returns the Kurento options assigned to this token
*/
diff --git a/openvidu-node-client/src/Session.ts b/openvidu-node-client/src/Session.ts
index 3b5b4486..25c56470 100644
--- a/openvidu-node-client/src/Session.ts
+++ b/openvidu-node-client/src/Session.ts
@@ -105,9 +105,10 @@ export class Session {
const data = JSON.stringify({
session: this.sessionId,
- role: (!!tokenOptions && !!tokenOptions.role) ? tokenOptions.role : OpenViduRole.PUBLISHER,
- data: (!!tokenOptions && !!tokenOptions.data) ? tokenOptions.data : '',
- kurentoOptions: (!!tokenOptions && !!tokenOptions.kurentoOptions) ? tokenOptions.kurentoOptions : {},
+ data: (!!tokenOptions && !!tokenOptions.data) ? tokenOptions.data : null,
+ role: (!!tokenOptions && !!tokenOptions.role) ? tokenOptions.role : null,
+ record: !!tokenOptions ? tokenOptions.record : null,
+ kurentoOptions: (!!tokenOptions && !!tokenOptions.kurentoOptions) ? tokenOptions.kurentoOptions : null
});
axios.post(
diff --git a/openvidu-node-client/src/TokenOptions.ts b/openvidu-node-client/src/TokenOptions.ts
index 910cd657..99a42b2d 100644
--- a/openvidu-node-client/src/TokenOptions.ts
+++ b/openvidu-node-client/src/TokenOptions.ts
@@ -32,9 +32,18 @@ export interface TokenOptions {
/**
* The role assigned to this token
+ *
+ * @default PUBLISHER
*/
role?: OpenViduRole;
+ /**
+ * Whether to record the streams published by the participant owning this token or not. This only affects [INDIVIDUAL recording](/en/stable/advanced-features/recording#selecting-streams-to-be-recorded)
+ *
+ * @default true
+ */
+ record?: boolean;
+
/**
* **WARNING**: experimental option. This interface may change in the near future
*
diff --git a/openvidu-server/docker/openvidu-recording/scripts/composed.sh b/openvidu-server/docker/openvidu-recording/scripts/composed.sh
index fe70c076..78e6b41a 100644
--- a/openvidu-server/docker/openvidu-recording/scripts/composed.sh
+++ b/openvidu-server/docker/openvidu-recording/scripts/composed.sh
@@ -47,7 +47,7 @@ fi
touch xvfb.log
chmod 777 xvfb.log
- xvfb-run --auto-servernum --server-args="-ac -screen 0 ${RESOLUTION}x24 -noreset" google-chrome --kiosk --start-maximized --test-type --no-sandbox --disable-infobars --disable-gpu --disable-popup-blocking --window-size=$WIDTH,$HEIGHT --window-position=0,0 --no-first-run --ignore-certificate-errors --autoplay-policy=no-user-gesture-required $DEBUG_CHROME_FLAGS $URL &> xvfb.log &
+ xvfb-run --auto-servernum --server-args="-ac -screen 0 ${RESOLUTION}x24 -noreset" google-chrome --kiosk --start-maximized --test-type --no-sandbox --disable-infobars --disable-gpu --disable-popup-blocking --window-size=$WIDTH,$HEIGHT --window-position=0,0 --no-first-run --ignore-certificate-errors --disable-dev-shm-usage --autoplay-policy=no-user-gesture-required $DEBUG_CHROME_FLAGS $URL &> xvfb.log &
touch stop
chmod 777 /recordings
diff --git a/openvidu-server/docker/openvidu-recording/scripts/composed_quick_start.sh b/openvidu-server/docker/openvidu-recording/scripts/composed_quick_start.sh
index 68fd2aab..9ded1ae6 100644
--- a/openvidu-server/docker/openvidu-recording/scripts/composed_quick_start.sh
+++ b/openvidu-server/docker/openvidu-recording/scripts/composed_quick_start.sh
@@ -30,7 +30,7 @@ if [[ -z "${COMPOSED_QUICK_START_ACTION}" ]]; then
touch xvfb.log
chmod 777 xvfb.log
- xvfb-run --auto-servernum --server-args="-ac -screen 0 ${RESOLUTION}x24 -noreset" google-chrome --kiosk --start-maximized --test-type --no-sandbox --disable-infobars --disable-gpu --disable-popup-blocking --window-size=$WIDTH,$HEIGHT --window-position=0,0 --no-first-run --ignore-certificate-errors --autoplay-policy=no-user-gesture-required --enable-logging --v=1 $DEBUG_CHROME_FLAGS $URL &> xvfb.log &
+ xvfb-run --auto-servernum --server-args="-ac -screen 0 ${RESOLUTION}x24 -noreset" google-chrome --kiosk --start-maximized --test-type --no-sandbox --disable-infobars --disable-gpu --disable-popup-blocking --window-size=$WIDTH,$HEIGHT --window-position=0,0 --no-first-run --ignore-certificate-errors --disable-dev-shm-usage --autoplay-policy=no-user-gesture-required --enable-logging --v=1 $DEBUG_CHROME_FLAGS $URL &> xvfb.log &
chmod 777 /recordings
until pids=$(pidof Xvfb)
diff --git a/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java b/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java
index a81943f1..85c8b3bb 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/OpenViduServer.java
@@ -50,7 +50,6 @@ import io.openvidu.server.config.OpenviduConfig.Error;
import io.openvidu.server.core.SessionEventsHandler;
import io.openvidu.server.core.SessionManager;
import io.openvidu.server.core.TokenGenerator;
-import io.openvidu.server.core.TokenGeneratorDefault;
import io.openvidu.server.coturn.CoturnCredentialsService;
import io.openvidu.server.coturn.CoturnCredentialsServiceFactory;
import io.openvidu.server.kurento.core.KurentoParticipantEndpointConfig;
@@ -157,7 +156,7 @@ public class OpenViduServer implements JsonRpcConfigurer {
@ConditionalOnMissingBean
@DependsOn("openviduConfig")
public TokenGenerator tokenGenerator() {
- return new TokenGeneratorDefault();
+ return new TokenGenerator();
}
@Bean
diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/Session.java b/openvidu-server/src/main/java/io/openvidu/server/core/Session.java
index bf0c0807..10509e5a 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/core/Session.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/core/Session.java
@@ -60,6 +60,7 @@ public class Session implements SessionInterface {
protected volatile boolean closed = false;
protected AtomicInteger activePublishers = new AtomicInteger(0);
+ protected AtomicInteger activeIndividualRecordedPublishers = new AtomicInteger(0);
/**
* This lock protects the following operations with read lock: [REST API](POST
@@ -145,12 +146,22 @@ public class Session implements SessionInterface {
return activePublishers.get();
}
- public void registerPublisher() {
- this.activePublishers.incrementAndGet();
+ public int getActiveIndividualRecordedPublishers() {
+ return activeIndividualRecordedPublishers.get();
}
- public void deregisterPublisher() {
+ public void registerPublisher(Participant participant) {
+ this.activePublishers.incrementAndGet();
+ if (participant.getToken().record()) {
+ activeIndividualRecordedPublishers.incrementAndGet();
+ }
+ }
+
+ public void deregisterPublisher(Participant participant) {
this.activePublishers.decrementAndGet();
+ if (participant.getToken().record()) {
+ activeIndividualRecordedPublishers.decrementAndGet();
+ }
}
public void storeToken(Token token) {
diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java b/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java
index a72f1166..454dca23 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/core/SessionManager.java
@@ -297,13 +297,13 @@ public abstract class SessionManager {
return sessionNotActive;
}
- public String newToken(Session session, OpenViduRole role, String serverMetadata,
+ public String newToken(Session session, OpenViduRole role, String serverMetadata, boolean record,
KurentoTokenOptions kurentoTokenOptions) throws Exception {
if (!formatChecker.isServerMetadataFormatCorrect(serverMetadata)) {
log.error("Data invalid format");
throw new OpenViduException(Code.GENERIC_ERROR_CODE, "Data invalid format");
}
- Token tokenObj = tokenGenerator.generateToken(session.getSessionId(), role, serverMetadata,
+ Token tokenObj = tokenGenerator.generateToken(session.getSessionId(), role, serverMetadata, record,
kurentoTokenOptions);
session.storeToken(tokenObj);
session.showTokens("Token created");
@@ -312,7 +312,8 @@ public abstract class SessionManager {
public Token newTokenForInsecureUser(Session session, String token, String serverMetadata) throws Exception {
Token tokenObj = new Token(token, OpenViduRole.PUBLISHER, serverMetadata != null ? serverMetadata : "",
- this.openviduConfig.isTurnadminAvailable() ? this.coturnCredentialsService.createUser() : null, null);
+ this.openviduConfig.isTurnadminAvailable() ? this.coturnCredentialsService.createUser() : null, true,
+ null);
session.storeToken(tokenObj);
session.showTokens("Token created for insecure user");
return tokenObj;
diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/Token.java b/openvidu-server/src/main/java/io/openvidu/server/core/Token.java
index feeb99af..1124afea 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/core/Token.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/core/Token.java
@@ -27,6 +27,7 @@ public class Token {
private OpenViduRole role;
private String serverMetadata = "";
private TurnCredentials turnCredentials;
+ private boolean record = true;
private KurentoTokenOptions kurentoTokenOptions;
@@ -35,11 +36,12 @@ public class Token {
}
public Token(String token, OpenViduRole role, String serverMetadata, TurnCredentials turnCredentials,
- KurentoTokenOptions kurentoTokenOptions) {
+ boolean record, KurentoTokenOptions kurentoTokenOptions) {
this.token = token;
this.role = role;
this.serverMetadata = serverMetadata;
this.turnCredentials = turnCredentials;
+ this.record = record;
this.kurentoTokenOptions = kurentoTokenOptions;
}
@@ -50,7 +52,7 @@ public class Token {
public void setToken(String token) {
this.token = token;
}
-
+
public OpenViduRole getRole() {
return role;
}
@@ -63,6 +65,10 @@ public class Token {
return turnCredentials;
}
+ public boolean record() {
+ return record;
+ }
+
public KurentoTokenOptions getKurentoTokenOptions() {
return kurentoTokenOptions;
}
diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/TokenGenerator.java b/openvidu-server/src/main/java/io/openvidu/server/core/TokenGenerator.java
index 472f4ee8..13149582 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/core/TokenGenerator.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/core/TokenGenerator.java
@@ -17,12 +17,45 @@
package io.openvidu.server.core;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
import io.openvidu.java.client.OpenViduRole;
+import io.openvidu.server.OpenViduServer;
+import io.openvidu.server.config.OpenviduBuildInfo;
+import io.openvidu.server.config.OpenviduConfig;
+import io.openvidu.server.coturn.CoturnCredentialsService;
+import io.openvidu.server.coturn.TurnCredentials;
import io.openvidu.server.kurento.core.KurentoTokenOptions;
-public interface TokenGenerator {
+public class TokenGenerator {
- public Token generateToken(String sessionId, OpenViduRole role, String serverMetadata,
- KurentoTokenOptions kurentoTokenOptions) throws Exception;
+ @Autowired
+ private CoturnCredentialsService coturnCredentialsService;
+ @Autowired
+ protected OpenviduConfig openviduConfig;
+
+ @Autowired
+ protected OpenviduBuildInfo openviduBuildConfig;
+
+ public Token generateToken(String sessionId, OpenViduRole role, String serverMetadata, boolean record,
+ KurentoTokenOptions kurentoTokenOptions) throws Exception {
+ String token = OpenViduServer.wsUrl;
+ token += "?sessionId=" + sessionId;
+ token += "&token=" + IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
+ + RandomStringUtils.randomAlphanumeric(15);
+ token += "&role=" + role.name();
+ token += "&version=" + openviduBuildConfig.getOpenViduServerVersion();
+ TurnCredentials turnCredentials = null;
+ if (this.openviduConfig.isTurnadminAvailable()) {
+ turnCredentials = coturnCredentialsService.createUser();
+ if (turnCredentials != null) {
+ token += "&coturnIp=" + openviduConfig.getCoturnIp();
+ token += "&turnUsername=" + turnCredentials.getUsername();
+ token += "&turnCredential=" + turnCredentials.getCredential();
+ }
+ }
+ return new Token(token, role, serverMetadata, turnCredentials, record, kurentoTokenOptions);
+ }
}
diff --git a/openvidu-server/src/main/java/io/openvidu/server/core/TokenGeneratorDefault.java b/openvidu-server/src/main/java/io/openvidu/server/core/TokenGeneratorDefault.java
deleted file mode 100644
index eeb46563..00000000
--- a/openvidu-server/src/main/java/io/openvidu/server/core/TokenGeneratorDefault.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * (C) Copyright 2017-2020 OpenVidu (https://openvidu.io)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package io.openvidu.server.core;
-
-import org.apache.commons.lang3.RandomStringUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-
-import io.openvidu.java.client.OpenViduRole;
-import io.openvidu.server.OpenViduServer;
-import io.openvidu.server.config.OpenviduBuildInfo;
-import io.openvidu.server.config.OpenviduConfig;
-import io.openvidu.server.coturn.CoturnCredentialsService;
-import io.openvidu.server.coturn.TurnCredentials;
-import io.openvidu.server.kurento.core.KurentoTokenOptions;
-
-public class TokenGeneratorDefault implements TokenGenerator {
-
- @Autowired
- private CoturnCredentialsService coturnCredentialsService;
-
- @Autowired
- protected OpenviduConfig openviduConfig;
-
- @Autowired
- protected OpenviduBuildInfo openviduBuildConfig;
-
- @Override
- public Token generateToken(String sessionId, OpenViduRole role, String serverMetadata,
- KurentoTokenOptions kurentoTokenOptions) throws Exception {
- String token = OpenViduServer.wsUrl;
- token += "?sessionId=" + sessionId;
- token += "&token=" + IdentifierPrefixes.TOKEN_ID + RandomStringUtils.randomAlphabetic(1).toUpperCase()
- + RandomStringUtils.randomAlphanumeric(15);
- token += "&role=" + role.name();
- token += "&version=" + openviduBuildConfig.getOpenViduServerVersion();
- TurnCredentials turnCredentials = null;
- if (this.openviduConfig.isTurnadminAvailable()) {
- turnCredentials = coturnCredentialsService.createUser();
- if (turnCredentials != null) {
- token += "&coturnIp=" + openviduConfig.getCoturnIp();
- token += "&turnUsername=" + turnCredentials.getUsername();
- token += "&turnCredential=" + turnCredentials.getCredential();
- }
- }
- return new Token(token, role, serverMetadata, turnCredentials, kurentoTokenOptions);
- }
-}
diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java
index 45017756..1c212da4 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoParticipant.java
@@ -181,7 +181,7 @@ public class KurentoParticipant extends Participant {
this.session.getSessionId());
if (this.openviduConfig.isRecordingModuleEnabled()
- && this.recordingManager.sessionIsBeingRecorded(session.getSessionId())) {
+ && this.recordingManager.sessionIsBeingRecorded(session.getSessionId()) && this.token.record()) {
this.recordingManager.startOneIndividualStreamRecording(session, null, null, this);
}
@@ -504,7 +504,7 @@ public class KurentoParticipant extends Participant {
}
releaseElement(getParticipantPublicId(), publisher.getEndpoint());
this.streaming = false;
- this.session.deregisterPublisher();
+ this.session.deregisterPublisher(this);
endpointConfig.getCdr().stopPublisher(this.getParticipantPublicId(), publisher.getStreamId(), reason);
publisher = null;
diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java
index e0ad8cb4..64bd7349 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSession.java
@@ -88,7 +88,7 @@ public class KurentoSession extends Session {
}
public void newPublisher(Participant participant) {
- registerPublisher();
+ registerPublisher(participant);
log.debug("SESSION {}: Virtually subscribed other participants {} to new publisher {}", sessionId,
participants.values(), participant.getParticipantPublicId());
}
diff --git a/openvidu-server/src/main/java/io/openvidu/server/recording/service/ComposedQuickStartRecordingService.java b/openvidu-server/src/main/java/io/openvidu/server/recording/service/ComposedQuickStartRecordingService.java
index 3f529772..c5325740 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/recording/service/ComposedQuickStartRecordingService.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/recording/service/ComposedQuickStartRecordingService.java
@@ -97,7 +97,7 @@ public class ComposedQuickStartRecordingService extends ComposedRecordingService
log.info("Stopping COMPOSED_QUICK_START ({}) recording {} of session {}. Reason: {}",
recording.hasAudio() ? "video + audio" : "audio-only", recording.getId(), recording.getSessionId(),
RecordingManager.finalReason(reason));
- log.info("Container for session {} still being ready for new recordings", session.getSessionId());
+ log.info("Container for session {} still being ready for new recordings", recording.getSessionId());
String containerId = this.sessionsContainers.get(recording.getSessionId());
@@ -119,10 +119,7 @@ public class ComposedQuickStartRecordingService extends ComposedRecordingService
recording = updateRecordingAttributes(recording);
- final String folderPath = this.openviduConfig.getOpenViduRecordingPath() + recording.getId() + "/";
- final String metadataFilePath = folderPath + RecordingManager.RECORDING_ENTITY_FILE + recording.getId();
- this.sealRecordingMetadataFileAsReady(recording, recording.getSize(), recording.getDuration(),
- metadataFilePath);
+ this.sealRecordingMetadataFileAsReady(recording, recording.getSize(), recording.getDuration(), getMetadataFilePath(recording));
cleanRecordingMaps(recording);
final long timestamp = System.currentTimeMillis();
diff --git a/openvidu-server/src/main/java/io/openvidu/server/recording/service/ComposedRecordingService.java b/openvidu-server/src/main/java/io/openvidu/server/recording/service/ComposedRecordingService.java
index a645e6d2..8ecc5c1d 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/recording/service/ComposedRecordingService.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/recording/service/ComposedRecordingService.java
@@ -103,7 +103,6 @@ public class ComposedRecordingService extends RecordingService {
@Override
public Recording stopRecording(Session session, Recording recording, EndReason reason) {
- recording = this.sealRecordingMetadataFileAsStopped(recording);
if (recording.hasVideo()) {
return this.stopRecordingWithVideo(session, recording, reason);
} else {
@@ -297,10 +296,8 @@ public class ComposedRecordingService extends RecordingService {
stopAndRemoveRecordingContainer(recording, containerId, 30);
recording = updateRecordingAttributes(recording);
- final String folderPath = this.openviduConfig.getOpenViduRecordingPath() + recording.getId() + "/";
- final String metadataFilePath = folderPath + RecordingManager.RECORDING_ENTITY_FILE + recording.getId();
this.sealRecordingMetadataFileAsReady(recording, recording.getSize(), recording.getDuration(),
- metadataFilePath);
+ getMetadataFilePath(recording));
cleanRecordingMaps(recording);
final long timestamp = System.currentTimeMillis();
diff --git a/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingManager.java b/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingManager.java
index 41b901f7..14654f68 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingManager.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingManager.java
@@ -279,8 +279,7 @@ public class RecordingManager {
this.sessionHandler.sendRecordingStartedNotification(session, recording);
}
if (session.getActivePublishers() == 0) {
- // Init automatic recording stop if there are now publishers when starting
- // recording
+ // Init automatic recording stop if no publishers when starting the recording
log.info("No publisher in session {}. Starting {} seconds countdown for stopping recording",
session.getSessionId(), this.openviduConfig.getOpenviduRecordingAutostopTimeout());
this.initAutomaticRecordingStopThread(session);
@@ -310,6 +309,8 @@ public class RecordingManager {
recording = this.sessionsRecordings.get(session.getSessionId());
}
+ recording = ((RecordingService) singleStreamRecordingService).sealRecordingMetadataFileAsStopped(recording);
+
final long timestamp = System.currentTimeMillis();
this.cdr.recordRecordingStatusChanged(recording, reason, timestamp, Status.stopped);
cdr.recordRecordingStopped(recording, reason, timestamp);
diff --git a/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingService.java b/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingService.java
index 15317a07..385899e3 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingService.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/recording/service/RecordingService.java
@@ -175,6 +175,10 @@ public abstract class RecordingService {
protected OpenViduException failStartRecording(Session session, Recording recording, String errorMessage) {
log.error("Recording start failed for session {}: {}", session.getSessionId(), errorMessage);
recording.setStatus(io.openvidu.java.client.Recording.Status.failed);
+
+ sealRecordingMetadataFileAsReady(recording, recording.getSize(), recording.getDuration(),
+ getMetadataFilePath(recording));
+
this.recordingManager.startingRecordings.remove(recording.getId());
this.recordingManager.sessionsRecordingsStarting.remove(session.getSessionId());
this.stopRecording(session, recording, null);
@@ -186,6 +190,11 @@ public abstract class RecordingService {
this.recordingManager.startedRecordings.remove(recording.getId());
}
+ protected String getMetadataFilePath(Recording recording) {
+ final String folderPath = this.openviduConfig.getOpenViduRecordingPath() + recording.getId() + "/";
+ return folderPath + RecordingManager.RECORDING_ENTITY_FILE + recording.getId();
+ }
+
/**
* Simple wrapper for returning update RecordingProperties and a free
* recordingId when starting a new recording
diff --git a/openvidu-server/src/main/java/io/openvidu/server/recording/service/SingleStreamRecordingService.java b/openvidu-server/src/main/java/io/openvidu/server/recording/service/SingleStreamRecordingService.java
index 1691d833..406a0048 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/recording/service/SingleStreamRecordingService.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/recording/service/SingleStreamRecordingService.java
@@ -98,11 +98,11 @@ public class SingleStreamRecordingService extends RecordingService {
activeRecorders.put(session.getSessionId(), new ConcurrentHashMap());
storedRecorders.put(session.getSessionId(), new ConcurrentHashMap());
- final int activePublishers = session.getActivePublishers();
- final CountDownLatch recordingStartedCountdown = new CountDownLatch(activePublishers);
+ int activePublishersToRecord = session.getActiveIndividualRecordedPublishers();
+ final CountDownLatch recordingStartedCountdown = new CountDownLatch(activePublishersToRecord);
for (Participant p : session.getParticipants()) {
- if (p.isStreaming()) {
+ if (p.isStreaming() && p.getToken().record()) {
MediaProfileSpecType profile = null;
try {
@@ -139,7 +139,6 @@ public class SingleStreamRecordingService extends RecordingService {
@Override
public Recording stopRecording(Session session, Recording recording, EndReason reason) {
- recording = this.sealRecordingMetadataFileAsStopped(recording);
return this.stopRecording(session, recording, reason, 0);
}
diff --git a/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java b/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java
index 76b1470b..2f833abf 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/rest/SessionRestController.java
@@ -149,7 +149,7 @@ public class SessionRestController {
if (customSessionId != null && !customSessionId.isEmpty()) {
if (!sessionManager.formatChecker.isValidCustomSessionId(customSessionId)) {
return this.generateErrorResponse(
- "Parameter \"customSessionId\" is wrong. Must be an alphanumeric string",
+ "Parameter 'customSessionId' is wrong. Must be an alphanumeric string [a-zA-Z0-9_-]",
"/api/sessions", HttpStatus.BAD_REQUEST);
}
builder = builder.customSessionId(customSessionId);
@@ -345,10 +345,12 @@ public class SessionRestController {
String sessionId;
String roleString;
String metadata;
+ Boolean record;
try {
sessionId = (String) params.get("session");
roleString = (String) params.get("role");
metadata = (String) params.get("data");
+ record = (Boolean) params.get("record");
} catch (ClassCastException e) {
return this.generateErrorResponse("Type error in some parameter", "/api/tokens", HttpStatus.BAD_REQUEST);
}
@@ -398,17 +400,19 @@ public class SessionRestController {
}
metadata = (metadata != null) ? metadata : "";
+ record = (record != null) ? record : true;
// While closing a session tokens can't be generated
if (session.closingLock.readLock().tryLock()) {
try {
- String token = sessionManager.newToken(session, role, metadata, kurentoTokenOptions);
+ String token = sessionManager.newToken(session, role, metadata, record, kurentoTokenOptions);
JsonObject responseJson = new JsonObject();
responseJson.addProperty("id", token);
responseJson.addProperty("session", sessionId);
responseJson.addProperty("role", role.toString());
responseJson.addProperty("data", metadata);
+ responseJson.addProperty("record", record);
responseJson.addProperty("token", token);
if (kurentoOptions != null) {
@@ -500,28 +504,36 @@ public class SessionRestController {
HttpStatus.BAD_REQUEST);
}
+ if (name != null && !name.isEmpty()) {
+ if (!sessionManager.formatChecker.isValidRecordingName(name)) {
+ return this.generateErrorResponse(
+ "Parameter 'name' is wrong. Must be an alphanumeric string [a-zA-Z0-9_-]", "/api/sessions",
+ HttpStatus.BAD_REQUEST);
+ }
+ }
+
OutputMode finalOutputMode = OutputMode.COMPOSED;
RecordingLayout recordingLayout = null;
if (outputModeString != null && !outputModeString.isEmpty()) {
try {
finalOutputMode = OutputMode.valueOf(outputModeString);
} catch (Exception e) {
- return this.generateErrorResponse("Type error in some parameter", "/api/recordings/start",
+ return this.generateErrorResponse("Type error in parameter 'outputMode'", "/api/recordings/start",
HttpStatus.BAD_REQUEST);
}
}
if (RecordingUtils.IS_COMPOSED(finalOutputMode)) {
if (resolution != null && !sessionManager.formatChecker.isAcceptableRecordingResolution(resolution)) {
return this.generateErrorResponse(
- "Wrong \"resolution\" parameter. Acceptable values from 100 to 1999 for both width and height",
+ "Wrong 'resolution' parameter. Acceptable values from 100 to 1999 for both width and height",
"/api/recordings/start", HttpStatus.UNPROCESSABLE_ENTITY);
}
if (recordingLayoutString != null && !recordingLayoutString.isEmpty()) {
try {
recordingLayout = RecordingLayout.valueOf(recordingLayoutString);
} catch (Exception e) {
- return this.generateErrorResponse("Type error in some parameter", "/api/recordings/start",
- HttpStatus.BAD_REQUEST);
+ return this.generateErrorResponse("Type error in parameter 'recordingLayout'",
+ "/api/recordings/start", HttpStatus.BAD_REQUEST);
}
}
}
diff --git a/openvidu-server/src/main/java/io/openvidu/server/utils/FormatChecker.java b/openvidu-server/src/main/java/io/openvidu/server/utils/FormatChecker.java
index 05748411..267d8f9f 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/utils/FormatChecker.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/utils/FormatChecker.java
@@ -30,8 +30,15 @@ public class FormatChecker {
}
public boolean isValidCustomSessionId(String customSessionId) {
- // Alphanumeric string
- return customSessionId.matches("[a-zA-Z0-9_-]+");
+ return isValidAlphanumeric(customSessionId);
+ }
+
+ public boolean isValidRecordingName(String recodingName) {
+ return isValidAlphanumeric(recodingName);
+ }
+
+ private boolean isValidAlphanumeric(String str) {
+ return str.matches("[a-zA-Z0-9_-]+");
}
}
diff --git a/openvidu-server/src/test/java/io/openvidu/server/test/integration/SessionGarbageCollectorIntegrationTest.java b/openvidu-server/src/test/java/io/openvidu/server/test/integration/SessionGarbageCollectorIntegrationTest.java
index 6b1527c8..a5e2e2e9 100644
--- a/openvidu-server/src/test/java/io/openvidu/server/test/integration/SessionGarbageCollectorIntegrationTest.java
+++ b/openvidu-server/src/test/java/io/openvidu/server/test/integration/SessionGarbageCollectorIntegrationTest.java
@@ -115,7 +115,7 @@ public class SessionGarbageCollectorIntegrationTest {
}
private void joinParticipant(String sessionId, String token) {
- Token t = new Token(token, OpenViduRole.PUBLISHER, "SERVER_METADATA", null, null);
+ Token t = new Token(token, OpenViduRole.PUBLISHER, "SERVER_METADATA", null, true, null);
String uuid = UUID.randomUUID().toString();
String participantPrivateId = "PARTICIPANT_PRIVATE_ID_" + uuid;
String finalUserId = "FINAL_USER_ID_" + uuid;
diff --git a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java
index 865621e0..2ae83957 100644
--- a/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java
+++ b/openvidu-test-e2e/src/test/java/io/openvidu/test/e2e/OpenViduTestAppE2eTest.java
@@ -934,9 +934,13 @@ public class OpenViduTestAppE2eTest {
user.getEventManager().waitUntilEventReaches("streamCreated", 2);
user.getEventManager().waitUntilEventReaches("streamPlaying", 2);
+ // Give some time for the screen sharing warning to stop resizing the viewport
+ Thread.sleep(3000);
+
// Unpublish video
final CountDownLatch latch1 = new CountDownLatch(2);
user.getEventManager().on("streamPropertyChanged", (event) -> {
+ System.out.println(event.toString());
threadAssertions.add("videoActive".equals(event.get("changedProperty").getAsString()));
threadAssertions.add(!event.get("newValue").getAsBoolean());
latch1.countDown();
@@ -960,6 +964,7 @@ public class OpenViduTestAppE2eTest {
// Unpublish audio
final CountDownLatch latch2 = new CountDownLatch(2);
user.getEventManager().on("streamPropertyChanged", (event) -> {
+ System.out.println(event.toString());
threadAssertions.add("audioActive".equals(event.get("changedProperty").getAsString()));
threadAssertions.add(!event.get("newValue").getAsBoolean());
latch2.countDown();
@@ -992,9 +997,11 @@ public class OpenViduTestAppE2eTest {
+ "}";
System.out.println("Publisher dimensions: " + event.get("newValue").getAsJsonObject().toString());
System.out.println("Real dimensions of viewport: " + expectedDimensions);
- threadAssertions.add("videoDimensions".equals(event.get("changedProperty").getAsString()));
- threadAssertions.add(expectedDimensions.equals(event.get("newValue").getAsJsonObject().toString()));
- latch3.countDown();
+ if ("videoDimensions".equals(event.get("changedProperty").getAsString())) {
+ if (expectedDimensions.equals(event.get("newValue").getAsJsonObject().toString())) {
+ latch3.countDown();
+ }
+ }
});
user.getDriver().manage().window().setSize(new Dimension(newWidth, newHeight));
@@ -1009,7 +1016,7 @@ public class OpenViduTestAppE2eTest {
user.getEventManager().waitUntilEventReaches("streamPropertyChanged", 6);
- if (!latch3.await(5000, TimeUnit.MILLISECONDS)) {
+ if (!latch3.await(6000, TimeUnit.MILLISECONDS)) {
gracefullyLeaveParticipants(2);
fail();
return;
@@ -1018,11 +1025,6 @@ public class OpenViduTestAppE2eTest {
System.out.println(getBase64Screenshot(user));
user.getEventManager().off("streamPropertyChanged");
- log.info("Thread assertions: {}", threadAssertions.toString());
- for (Iterator iter = threadAssertions.iterator(); iter.hasNext();) {
- Assert.assertTrue("Some Event property was wrong", iter.next());
- iter.remove();
- }
gracefullyLeaveParticipants(2);
}
@@ -1347,8 +1349,15 @@ public class OpenViduTestAppE2eTest {
final String sessionName = "TestSession";
final String recordingName = "CUSTOM_NAME";
- user.getDriver().findElement(By.id("auto-join-checkbox")).click();
+ // Connect 2 users. One of them not recorded
user.getDriver().findElement(By.id("one2one-btn")).click();
+ user.getDriver().findElement(By.id("session-settings-btn-0")).click();
+ Thread.sleep(1000);
+ user.getDriver().findElement(By.id("record-checkbox")).click();
+ user.getDriver().findElement(By.id("save-btn")).click();
+ Thread.sleep(1000);
+
+ user.getDriver().findElements(By.className("join-btn")).forEach(el -> el.sendKeys(Keys.ENTER));
user.getEventManager().waitUntilEventReaches("connectionCreated", 4);
user.getEventManager().waitUntilEventReaches("accessAllowed", 2);
@@ -1416,7 +1425,7 @@ public class OpenViduTestAppE2eTest {
String recPath = recordingsPath + sessionName + "/";
Recording recording = new OpenVidu(OPENVIDU_URL, OPENVIDU_SECRET).getRecording(sessionName);
- this.checkIndividualRecording(recPath, recording, 2, "opus", "vp8", true);
+ this.checkIndividualRecording(recPath, recording, 1, "opus", "vp8", true);
// Try to get the stopped recording
user.getDriver().findElement(By.id("get-recording-btn")).click();
diff --git a/openvidu-testapp/package.json b/openvidu-testapp/package.json
index bf2e5bbe..65c58b8d 100644
--- a/openvidu-testapp/package.json
+++ b/openvidu-testapp/package.json
@@ -16,7 +16,7 @@
"core-js": "3.4.7",
"hammerjs": "2.0.8",
"openvidu-browser": "2.15.0",
- "openvidu-node-client": "2.11.0",
+ "openvidu-node-client": "2.15.0",
"rxjs": "6.5.3",
"zone.js": "0.10.2"
},