false
.
+ * This allows browsers/clients to use the same codec avoiding transcoding in the media server.
+ * If the browser/client is not compatible with the specified codec and {@link #allowTranscoding(boolean)}
+ * is false
and exception will occur.
*
+ * If forcedVideoCodec is set to NONE, no codec will be forced.
*/
public SessionProperties.Builder forcedVideoCodec(VideoCodec forcedVideoCodec) {
this.forcedVideoCodec = forcedVideoCodec;
@@ -156,15 +157,8 @@ public class SessionProperties {
}
/**
- *
- * Call this method to define if you want to allowTranscoding or not. If you define it as
- * as false
, the default video codec VP8 will be used for all browsers, and the media
- * server will not do any transcoding. If you define it as true
, transcoding can be
- * executed by the media server when necessary.
- *
- * If you want to set a different video codec, you can configure it
- * by calling {@link #forcedVideoCodec(VideoCodec)} to your preferred one.
- *
+ * Call this method to define if you want to allow transcoding in the media server or not
+ * when {@link #forcedVideoCodec(VideoCodec)} is not compatible with the browser/client.
*/
public SessionProperties.Builder allowTranscoding(boolean allowTranscoding) {
this.allowTranscoding = allowTranscoding;
@@ -270,20 +264,15 @@ public class SessionProperties {
}
/**
- *
- * Defines which video codec is being forced to be used when
- * {@link io.openvidu.java.client.SessionProperties.Builder#allowTranscoding(boolean)}
- * has been set to false
+ * Defines which video codec is being forced to be used in the browser/client
*/
public VideoCodec forcedVideoCodec() {
return this.forcedVideoCodec;
}
/**
- *
- * Defines if transcoding is allowed or not. If this method returns false
, a video codec
- * will be forcibly used for all browsers (See
- * {@link io.openvidu.java.client.SessionProperties.Builder#forcedVideoCodec(VideoCodec)}).
+ * Defines if transcoding is allowed or not when {@link #forcedVideoCodec}
+ * is not a compatible codec with the browser/client.
*/
public boolean isTranscodingAllowed() {
return this.allowTranscoding;
diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/VideoCodec.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/VideoCodec.java
index 9f6e002f..3f088fa1 100644
--- a/openvidu-java-client/src/main/java/io/openvidu/java/client/VideoCodec.java
+++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/VideoCodec.java
@@ -21,5 +21,5 @@ package io.openvidu.java.client;
* See {@link io.openvidu.java.client.SessionProperties.Builder#forcedVideoCodec(VideoCodec)}
*/
public enum VideoCodec {
- VP8, VP9, H264
+ VP8, VP9, H264, NONE
}
\ No newline at end of file
diff --git a/openvidu-node-client/src/SessionProperties.ts b/openvidu-node-client/src/SessionProperties.ts
index df45ac41..91e182c8 100644
--- a/openvidu-node-client/src/SessionProperties.ts
+++ b/openvidu-node-client/src/SessionProperties.ts
@@ -19,6 +19,7 @@ import { MediaMode } from './MediaMode';
import { Recording } from './Recording';
import { RecordingLayout } from './RecordingLayout';
import { RecordingMode } from './RecordingMode';
+import { VideoCodec } from './VideoCodec';
/**
* See [[OpenVidu.createSession]]
@@ -65,23 +66,20 @@ export interface SessionProperties {
*/
customSessionId?: string;
- /**
- * Call this method to define which video codec do you want to be forcibly used for this session.
- * This allows browsers to use the same codec avoiding transcoding in the media server.
- * To force this video codec you need to set [[allowTranscoding]] to false
.
- */
- forcedVideoCodec?: string;
+ /**
+ * It defines which video codec do you want to be forcibly used for this session.
+ * This allows browsers/clients to use the same codec avoiding transcoding in the media server.
+ * If the browser/client is not compatible with the specified codec and [[allowTranscoding]]
+ * is false
and exception will occur.
+ *
+ * If forcedVideoCodec is set to NONE, no codec will be forced.
+ */
+ forcedVideoCodec?: VideoCodec;
/**
- * Call this method to define if you want to allowTranscoding or not. If you define it as
- * as false
, the default video codec VP8 will be used for all browsers, and the media
- * server will not do any transcoding. If you define it as true
, transcoding can be
- * executed by the media server when necessary.
- *
- * If you want to set a different video codec, you can configure it
- * by calling [[forcedVideoCodec]] to your preferred one.
- *
- */
+ * It defines if you want to allow transcoding in the media server or not
+ * when [[forcedVideoCodec]] is not compatible with the browser/client.
+ */
allowTranscoding?: boolean;
}
diff --git a/openvidu-node-client/src/VideoCodec.ts b/openvidu-node-client/src/VideoCodec.ts
index e1077f77..464bef34 100644
--- a/openvidu-node-client/src/VideoCodec.ts
+++ b/openvidu-node-client/src/VideoCodec.ts
@@ -5,6 +5,7 @@ export enum VideoCodec {
VP8 = 'VP8',
VP9 = 'VP9',
- H264 = 'H264'
+ H264 = 'H264',
+ NONE = 'NONE'
}
\ No newline at end of file
diff --git a/openvidu-server/deployments/ce/docker-compose/.env b/openvidu-server/deployments/ce/docker-compose/.env
index 29ac0cb5..fe1e7693 100644
--- a/openvidu-server/deployments/ce/docker-compose/.env
+++ b/openvidu-server/deployments/ce/docker-compose/.env
@@ -137,6 +137,13 @@ OPENVIDU_SESSIONS_GARBAGE_INTERVAL=900
# (property 'OPENVIDU_SESSIONS_GARBAGE_INTERVAL' to 0) this property is ignored
OPENVIDU_SESSIONS_GARBAGE_THRESHOLD=3600
+# All sessions of OpenVidu will try to force this codec. If OPENVIDU_ALLOW_TRANSCODING=true
+# when a codec can not be forced, transcoding will be allowed
+# OPENVIDU_FORCED_CODEC=VP8
+
+# Allow transcoding if codec specified in OPENVIDU_FORCED_CODEC can not be applied
+# OPENVIDU_ALLOW_TRANSCODING=false
+
# Call Detail Record enabled
# Whether to enable Call Detail Record or not
# Values: true | false
diff --git a/openvidu-server/deployments/pro/docker-compose/openvidu-server-pro/.env b/openvidu-server/deployments/pro/docker-compose/openvidu-server-pro/.env
index 056cf286..458697fa 100644
--- a/openvidu-server/deployments/pro/docker-compose/openvidu-server-pro/.env
+++ b/openvidu-server/deployments/pro/docker-compose/openvidu-server-pro/.env
@@ -178,6 +178,13 @@ OPENVIDU_STREAMS_VIDEO_MAX_SEND_BANDWIDTH=1000
# 0 means unconstrained
OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH=300
+# All sessions of OpenVidu will try to force this codec. If OPENVIDU_ALLOW_TRANSCODING=true
+# when a codec can not be forced, transcoding will be allowed
+# OPENVIDU_FORCED_CODEC=VP8
+
+# Allow transcoding if codec specified in OPENVIDU_FORCED_CODEC can not be applied
+# OPENVIDU_ALLOW_TRANSCODING=false
+
# true to enable OpenVidu Webhook service. false' otherwise
# Values: true | false
OPENVIDU_WEBHOOK=false
diff --git a/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java b/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java
index 1beb6a41..e2b27fe0 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/config/OpenviduConfig.java
@@ -37,6 +37,10 @@ import java.util.Map;
import javax.annotation.PostConstruct;
+import com.google.gson.Gson;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonSyntaxException;
+
import org.apache.commons.io.FilenameUtils;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
@@ -48,11 +52,8 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
-import com.google.gson.Gson;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonSyntaxException;
-
import io.openvidu.java.client.OpenViduRole;
+import io.openvidu.java.client.VideoCodec;
import io.openvidu.server.OpenViduServer;
import io.openvidu.server.cdr.CDREventName;
import io.openvidu.server.config.Dotenv.DotenvFormatException;
@@ -176,6 +177,10 @@ public class OpenviduConfig {
protected int openviduSessionsGarbageThreshold;
+ private VideoCodec openviduForcedCodec;
+
+ private boolean openviduAllowTranscoding;
+
private String dotenvPath;
// Derived properties
@@ -190,6 +195,14 @@ public class OpenviduConfig {
return this.coturnRedisDbname;
}
+ public boolean isOpenviduAllowingTranscoding() {
+ return openviduAllowTranscoding;
+ }
+
+ public VideoCodec getOpenviduForcedCodec() {
+ return openviduForcedCodec;
+ }
+
public String getCoturnDatabasePassword() {
return this.coturnRedisPassword;
}
@@ -335,20 +348,20 @@ public class OpenviduConfig {
public OpenViduRole[] getRolesFromRecordingNotification() {
OpenViduRole[] roles;
switch (this.openviduRecordingNotification) {
- case none:
- roles = new OpenViduRole[0];
- break;
- case moderator:
- roles = new OpenViduRole[] { OpenViduRole.MODERATOR };
- break;
- case publisher_moderator:
- roles = new OpenViduRole[] { OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
- break;
- case all:
- roles = new OpenViduRole[] { OpenViduRole.SUBSCRIBER, OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
- break;
- default:
- roles = new OpenViduRole[] { OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
+ case none:
+ roles = new OpenViduRole[0];
+ break;
+ case moderator:
+ roles = new OpenViduRole[] { OpenViduRole.MODERATOR };
+ break;
+ case publisher_moderator:
+ roles = new OpenViduRole[] { OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
+ break;
+ case all:
+ roles = new OpenViduRole[] { OpenViduRole.SUBSCRIBER, OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
+ break;
+ default:
+ roles = new OpenViduRole[] { OpenViduRole.PUBLISHER, OpenViduRole.MODERATOR };
}
return roles;
}
@@ -500,6 +513,9 @@ public class OpenviduConfig {
openviduSessionsGarbageInterval = asNonNegativeInteger("OPENVIDU_SESSIONS_GARBAGE_INTERVAL");
openviduSessionsGarbageThreshold = asNonNegativeInteger("OPENVIDU_SESSIONS_GARBAGE_THRESHOLD");
+ openviduForcedCodec = asEnumValue("OPENVIDU_FORCED_CODEC", VideoCodec.class);
+ openviduAllowTranscoding = asBoolean("OPENVIDU_ALLOW_TRANSCODING");
+
kmsUrisList = checkKmsUris();
checkCoturnIp();
diff --git a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java
index fb4399b7..27a7fd32 100644
--- a/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java
+++ b/openvidu-server/src/main/java/io/openvidu/server/kurento/core/KurentoSessionManager.java
@@ -371,20 +371,26 @@ public class KurentoSessionManager extends SessionManager {
KurentoMediaOptions kurentoOptions = (KurentoMediaOptions) mediaOptions;
KurentoParticipant kParticipant = (KurentoParticipant) participant;
KurentoSession kSession = kParticipant.getSession();
-
- // Modify sdp if transcoding is not allowed
- if(!kSession.getSessionProperties().isTranscodingAllowed()) {
- VideoCodec forcedVideoCodec = kSession.getSessionProperties().forcedVideoCodec();
+ boolean isTranscodingAllowed = kSession.getSessionProperties().isTranscodingAllowed();
+ VideoCodec forcedVideoCodec = kSession.getSessionProperties().forcedVideoCodec();
+
+ // Modify sdp if forced codec is defined
+ if (forcedVideoCodec != VideoCodec.NONE) {
String sdpOffer = kurentoOptions.sdpOffer;
-
try {
- kurentoOptions.sdpOffer = modifySdpToForceCodec(forcedVideoCodec, sdpOffer);
+ log.debug("PARTICIPANT '{}' in Session '{}' SDP Offer before munging: \n {}",
+ participant.getParticipantPublicId(), kSession.getSessionId(), kurentoOptions.sdpOffer);
+ kurentoOptions.sdpOffer = this.sdpMunging.setCodecPreference(forcedVideoCodec, sdpOffer);
} catch (OpenViduException e) {
- String errorMessage = "Error forcing codec: ''" + forcedVideoCodec + "', for publisher on Session: '" + kSession.getSessionId()
- + "'\nException: " + e.getMessage() + "\nSDP:\n" + sdpOffer;
- throw new OpenViduException(Code.FORCED_CODEC_NOT_FOUND_IN_SDPOFFER, errorMessage);
+ String errorMessage = "Error forcing codec: '" + forcedVideoCodec + "', for PARTICIPANT"
+ + participant.getParticipantPublicId() + "' publishing in Session: '"
+ + kSession.getSessionId() + "'\nException: " + e.getMessage() + "\nSDP:\n" + sdpAnswer;
+ if(!isTranscodingAllowed) {
+ throw new OpenViduException(Code.FORCED_CODEC_NOT_FOUND_IN_SDPOFFER, errorMessage);
+ }
+ log.info("Codec: '" + forcedVideoCodec + "' is not supported for PARTICIPANT: '" + participant.getParticipantPublicId()
+ + " publishing in Session: '" + kSession.getSessionId() + "'. Transcoding will be allowed");
}
-
}
log.debug(
@@ -418,7 +424,7 @@ public class KurentoSessionManager extends SessionManager {
}
sdpAnswer = kParticipant.publishToRoom(kurentoOptions.sdpOffer, kurentoOptions.doLoopback, false);
-
+
if (sdpAnswer == null) {
OpenViduException e = new OpenViduException(Code.MEDIA_SDP_ERROR_CODE,
"Error generating SDP response for publishing user " + participant.getParticipantPublicId());
@@ -582,16 +588,25 @@ public class KurentoSessionManager extends SessionManager {
KurentoParticipant kParticipant = (KurentoParticipant) participant;
session = ((KurentoParticipant) participant).getSession();
Participant senderParticipant = session.getParticipantByPublicId(senderName);
+ boolean isTranscodingAllowed = session.getSessionProperties().isTranscodingAllowed();
+ VideoCodec forcedVideoCodec = session.getSessionProperties().forcedVideoCodec();
- // Modify sdp if transcoding is not allowed
- if (!session.getSessionProperties().isTranscodingAllowed()) {
- VideoCodec forcedVideoCodec = session.getSessionProperties().forcedVideoCodec();
+ // Modify sdp if forced codec is defined
+ if (forcedVideoCodec != VideoCodec.NONE) {
try {
- sdpAnswer = this.modifySdpToForceCodec(forcedVideoCodec, sdpAnswer);
+ log.debug("PARTICIPANT '{}' in Session '{}' SDP Answer before munging: \n {}",
+ participant.getParticipantPublicId(), session.getSessionId(), sdpAnswer);
+ sdpAnswer = this.sdpMunging.setCodecPreference(forcedVideoCodec, sdpAnswer);
} catch (OpenViduException e) {
- String errorMessage = "Error forcing codec: ''" + forcedVideoCodec + "', for subscriber on Session: '"
+ String errorMessage = "Error forcing codec: '" + forcedVideoCodec + "', for PARTICIPANT: '"
+ + participant.getParticipantPublicId() + "' subscribing in Session: '"
+ session.getSessionId() + "'\nException: " + e.getMessage() + "\nSDP:\n" + sdpAnswer;
- throw new OpenViduException(Code.FORCED_CODEC_NOT_FOUND_IN_SDPOFFER, errorMessage);
+
+ if(!isTranscodingAllowed) {
+ throw new OpenViduException(Code.FORCED_CODEC_NOT_FOUND_IN_SDPOFFER, errorMessage);
+ }
+ log.info("Codec: '" + forcedVideoCodec + "' is not supported for PARTICIPANT: '" + participant.getParticipantPublicId()
+ + " subscribing in Session: '" + session.getSessionId() + "'. Transcoding will be allowed");
}
}
@@ -1126,19 +1141,26 @@ public class KurentoSessionManager extends SessionManager {
KurentoParticipant kParticipant = (KurentoParticipant) participant;
KurentoSession kSession = kParticipant.getSession();
boolean isPublisher = streamId.equals(participant.getPublisherStreamId());
+ boolean isTranscodingAllowed = kSession.getSessionProperties().isTranscodingAllowed();
+ VideoCodec forcedVideoCodec = kSession.getSessionProperties().forcedVideoCodec();
- // Modify sdp if transcoding is not allowed
- if (!kSession.getSessionProperties().isTranscodingAllowed()) {
- VideoCodec forcedVideoCodec = kSession.getSessionProperties().forcedVideoCodec();
+ // Modify sdp if forced codec is defined
+ if (forcedVideoCodec != VideoCodec.NONE) {
try {
- sdpString = modifySdpToForceCodec(forcedVideoCodec, sdpString);
+ log.debug("PARTICIPANT '{}' in Session '{}' reconnecting SDP before munging: \n {}",
+ participant.getParticipantPublicId(), kSession.getSessionId(), sdpString);
+ sdpString = sdpMunging.setCodecPreference(forcedVideoCodec, sdpString);
} catch (OpenViduException e) {
- String errorMessage = "Error on reconnecting and forcing codec: ''" + forcedVideoCodec + "', for "
- + (isPublisher ? "publisher" : "subscriber") + " on Session: '" + kSession.getSessionId()
- + "'\nException: " + e.getMessage() + "\nSDP:\n" + sdpString;
- throw new OpenViduException(Code.FORCED_CODEC_NOT_FOUND_IN_SDPOFFER, errorMessage);
+ String errorMessage = "Error in reconnect and forcing codec: '" + forcedVideoCodec + "', for PARTICIPANT: '"
+ + participant.getParticipantPublicId() + "' " + (isPublisher ? "publishing" : "subscribing")
+ + " in Session: '" + kSession.getSessionId() + "'\nException: "
+ + e.getMessage() + "\nSDP:\n" + sdpString;
+ if(!isTranscodingAllowed) {
+ throw new OpenViduException(Code.FORCED_CODEC_NOT_FOUND_IN_SDPOFFER, errorMessage);
+ }
+ log.info("Codec: '" + forcedVideoCodec + "' is not supported for PARTICIPANT: '" + participant.getParticipantPublicId()
+ + "' " + (isPublisher ? "publishing" : "subscribing") + " in Session: '" + kSession.getSessionId() + "'. Transcoding will be allowed");
}
-
}
if (isPublisher) {
@@ -1243,14 +1265,4 @@ public class KurentoSessionManager extends SessionManager {
filter.removeEventListener(pub.removeListener(eventType));
}
}
-
-
- private String modifySdpToForceCodec(VideoCodec codec, String sdpOffer) {
- // Modify sdpOffer if transcoding is not allowed
- String modSdpOffer = this.sdpMunging.setCodecPreference(codec, sdpOffer);
- if (modSdpOffer != null) {
- sdpOffer = modSdpOffer;
- }
- return sdpOffer;
- }
}
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 e773c314..76b1470b 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
@@ -158,12 +158,12 @@ public class SessionRestController {
if (forcedVideoCodec != null) {
builder = builder.forcedVideoCodec(VideoCodec.valueOf(forcedVideoCodec));
} else {
- builder = builder.forcedVideoCodec(VideoCodec.VP8);
+ builder = builder.forcedVideoCodec(openviduConfig.getOpenviduForcedCodec());
}
if (allowTranscoding != null) {
builder = builder.allowTranscoding(allowTranscoding);
} else {
- builder = builder.allowTranscoding(false);
+ builder = builder.allowTranscoding(openviduConfig.isOpenviduAllowingTranscoding());
}
} catch (IllegalArgumentException e) {
diff --git a/openvidu-server/src/main/resources/application.properties b/openvidu-server/src/main/resources/application.properties
index 48b9859a..2ae45ad0 100644
--- a/openvidu-server/src/main/resources/application.properties
+++ b/openvidu-server/src/main/resources/application.properties
@@ -42,6 +42,9 @@ OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH=300
OPENVIDU_SESSIONS_GARBAGE_INTERVAL=900
OPENVIDU_SESSIONS_GARBAGE_THRESHOLD=3600
+OPENVIDU_FORCED_CODEC=VP8
+OPENVIDU_ALLOW_TRANSCODING=false
+
COTURN_REDIS_IP=127.0.0.1
COTURN_REDIS_DBNAME=0
COTURN_REDIS_PASSWORD=turn
diff --git a/openvidu-testapp/src/app/components/dialogs/session-properties-dialog/session-properties-dialog.component.html b/openvidu-testapp/src/app/components/dialogs/session-properties-dialog/session-properties-dialog.component.html
index bf816c9b..e9eb8de6 100644
--- a/openvidu-testapp/src/app/components/dialogs/session-properties-dialog/session-properties-dialog.component.html
+++ b/openvidu-testapp/src/app/components/dialogs/session-properties-dialog/session-properties-dialog.component.html
@@ -42,7 +42,7 @@