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 6bd50536..451d3862 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 @@ -662,16 +662,17 @@ public class Session { this.sessionId = responseJson.get("id").getAsString(); this.createdAt = responseJson.get("createdAt").getAsLong(); - // forcedVideoCodec and allowTranscoding values are configured in OpenVidu - // Server via configuration or session + // Values that get filled by OpenVidu Server from its global or per-session configuration VideoCodec forcedVideoCodec = VideoCodec.valueOf(responseJson.get("forcedVideoCodec").getAsString()); + VideoCodec forcedVideoCodecResolved = VideoCodec + .valueOf(responseJson.get("forcedVideoCodecResolved").getAsString()); Boolean allowTranscoding = responseJson.get("allowTranscoding").getAsBoolean(); - SessionProperties responseProperties = new SessionProperties.Builder() - .customSessionId(properties.customSessionId()).mediaMode(properties.mediaMode()) + SessionProperties responseProperties = new SessionProperties.Builder().mediaMode(properties.mediaMode()) .recordingMode(properties.recordingMode()) .defaultRecordingProperties(properties.defaultRecordingProperties()) - .mediaNode(properties.mediaNode()).forcedVideoCodec(forcedVideoCodec) + .customSessionId(properties.customSessionId()).mediaNode(properties.mediaNode()) + .forcedVideoCodec(forcedVideoCodec).forcedVideoCodecResolved(forcedVideoCodecResolved) .allowTranscoding(allowTranscoding).build(); this.properties = responseProperties; @@ -719,6 +720,9 @@ public class Session { if (json.has("forcedVideoCodec")) { builder.forcedVideoCodec(VideoCodec.valueOf(json.get("forcedVideoCodec").getAsString())); } + if (json.has("forcedVideoCodecResolved")) { + builder.forcedVideoCodecResolved(VideoCodec.valueOf(json.get("forcedVideoCodecResolved").getAsString())); + } if (json.has("allowTranscoding")) { builder.allowTranscoding(json.get("allowTranscoding").getAsBoolean()); } diff --git a/openvidu-java-client/src/main/java/io/openvidu/java/client/SessionProperties.java b/openvidu-java-client/src/main/java/io/openvidu/java/client/SessionProperties.java index 10392c77..4ca54a22 100644 --- a/openvidu-java-client/src/main/java/io/openvidu/java/client/SessionProperties.java +++ b/openvidu-java-client/src/main/java/io/openvidu/java/client/SessionProperties.java @@ -30,6 +30,7 @@ public class SessionProperties { private String customSessionId; private String mediaNode; private VideoCodec forcedVideoCodec; + private VideoCodec forcedVideoCodecResolved; private Boolean allowTranscoding; /** @@ -43,6 +44,7 @@ public class SessionProperties { private String customSessionId = ""; private String mediaNode; private VideoCodec forcedVideoCodec = VideoCodec.MEDIA_SERVER_PREFERRED; + private VideoCodec forcedVideoCodecResolved = VideoCodec.NONE; private Boolean allowTranscoding = false; /** @@ -51,7 +53,8 @@ public class SessionProperties { */ public SessionProperties build() { return new SessionProperties(this.mediaMode, this.recordingMode, this.defaultRecordingProperties, - this.customSessionId, this.mediaNode, this.forcedVideoCodec, this.allowTranscoding); + this.customSessionId, this.mediaNode, this.forcedVideoCodec, this.forcedVideoCodecResolved, + this.allowTranscoding); } /** @@ -126,14 +129,25 @@ public class SessionProperties { * If defined here, this parameter has prevalence over * OPENVIDU_STREAMS_FORCED_VIDEO_CODEC. * - * Default is {@link VideoCodec#VP8} for Kurento, and - * {@link VideoCodec#NONE} for mediasoup. + * Default is {@link VideoCodec#MEDIA_SERVER_PREFERRED}. */ public SessionProperties.Builder forcedVideoCodec(VideoCodec forcedVideoCodec) { this.forcedVideoCodec = forcedVideoCodec; return this; } + /** + * Actual video codec that will be forcibly used for this session. + * This is the same as forcedVideoCodec, except when its + * value is {@link VideoCodec#MEDIA_SERVER_PREFERRED}: in that case, + * OpenVidu Server will fill this property with a resolved value, + * depending on what is the configured media server. + */ + public SessionProperties.Builder forcedVideoCodecResolved(VideoCodec forcedVideoCodec) { + this.forcedVideoCodecResolved = forcedVideoCodec; + return this; + } + /** * Call this method to define if you want to allow transcoding in the media * server or not when {@link #forcedVideoCodec(VideoCodec)} is not compatible @@ -159,13 +173,14 @@ public class SessionProperties { private SessionProperties(MediaMode mediaMode, RecordingMode recordingMode, RecordingProperties defaultRecordingProperties, String customSessionId, String mediaNode, - VideoCodec forcedVideoCodec, Boolean allowTranscoding) { + VideoCodec forcedVideoCodec, VideoCodec forcedVideoCodecResolved, Boolean allowTranscoding) { this.mediaMode = mediaMode; this.recordingMode = recordingMode; this.defaultRecordingProperties = defaultRecordingProperties; this.customSessionId = customSessionId; this.mediaNode = mediaNode; this.forcedVideoCodec = forcedVideoCodec; + this.forcedVideoCodecResolved = forcedVideoCodecResolved; this.allowTranscoding = allowTranscoding; } @@ -222,12 +237,24 @@ public class SessionProperties { } /** - * Defines which video codec is being forced to be used in the browser/client + * Defines which video codec is being forced to be used in the browser/client. + * This is the raw value that was configured. It might get resolved into a + * different one for actual usage in the server. */ public VideoCodec forcedVideoCodec() { return this.forcedVideoCodec; } + /** + * Defines which video codec is being forced to be used in the browser/client. + * This is the resolved value, for actual usage in the server. + * + * @hidden + */ + public VideoCodec forcedVideoCodecResolved() { + return this.forcedVideoCodecResolved; + } + /** * Defines if transcoding is allowed or not when {@link #forcedVideoCodec} is * not a compatible codec with the browser/client. @@ -238,20 +265,23 @@ public class SessionProperties { public JsonObject toJson() { JsonObject json = new JsonObject(); - json.addProperty("mediaMode", mediaMode().name()); - json.addProperty("recordingMode", recordingMode().name()); - json.addProperty("customSessionId", customSessionId()); - json.add("defaultRecordingProperties", defaultRecordingProperties.toJson()); - if (mediaNode() != null && !mediaNode().isEmpty()) { + json.addProperty("mediaMode", this.mediaMode.name()); + json.addProperty("recordingMode", this.recordingMode.name()); + json.add("defaultRecordingProperties", this.defaultRecordingProperties.toJson()); + json.addProperty("customSessionId", this.customSessionId); + if (this.mediaNode != null && !this.mediaNode.isEmpty()) { JsonObject mediaNodeJson = new JsonObject(); - mediaNodeJson.addProperty("id", mediaNode()); + mediaNodeJson.addProperty("id", this.mediaNode); json.add("mediaNode", mediaNodeJson); } - if (forcedVideoCodec() != null) { - json.addProperty("forcedVideoCodec", forcedVideoCodec().name()); + if (this.forcedVideoCodec != null) { + json.addProperty("forcedVideoCodec", this.forcedVideoCodec.name()); } - if (isTranscodingAllowed() != null) { - json.addProperty("allowTranscoding", isTranscodingAllowed()); + if (this.forcedVideoCodecResolved != null) { + json.addProperty("forcedVideoCodecResolved", this.forcedVideoCodecResolved.name()); + } + if (this.allowTranscoding != null) { + json.addProperty("allowTranscoding", this.allowTranscoding); } return json; } diff --git a/openvidu-node-client/src/Session.ts b/openvidu-node-client/src/Session.ts index 718709b5..9ca089a2 100644 --- a/openvidu-node-client/src/Session.ts +++ b/openvidu-node-client/src/Session.ts @@ -490,6 +490,7 @@ export class Session { this.properties.defaultRecordingProperties = res.data.defaultRecordingProperties; this.properties.mediaNode = res.data.mediaNode; this.properties.forcedVideoCodec = res.data.forcedVideoCodec; + this.properties.forcedVideoCodecResolved = res.data.forcedVideoCodecResolved; this.properties.allowTranscoding = res.data.allowTranscoding; this.sanitizeDefaultSessionProperties(this.properties); resolve(this.sessionId); @@ -533,6 +534,7 @@ export class Session { recordingMode: json.recordingMode, defaultRecordingProperties: json.defaultRecordingProperties, forcedVideoCodec: json.forcedVideoCodec, + forcedVideoCodecResolved: json.forcedVideoCodecResolved, allowTranscoding: json.allowTranscoding }; this.sanitizeDefaultSessionProperties(this.properties); @@ -548,6 +550,9 @@ export class Session { if (json.forcedVideoCodec == null) { delete this.properties.forcedVideoCodec; } + if (json.forcedVideoCodecResolved == null) { + delete this.properties.forcedVideoCodecResolved; + } if (json.allowTranscoding == null) { delete this.properties.allowTranscoding; } @@ -655,9 +660,12 @@ export class Session { props.mediaMode = (props.mediaMode != null) ? props.mediaMode : MediaMode.ROUTED; props.recordingMode = (props.recordingMode != null) ? props.recordingMode : RecordingMode.MANUAL; props.customSessionId = (props.customSessionId != null) ? props.customSessionId : ''; - props.mediaNode = (props.mediaNode != null) ? props.mediaNode : undefined; - props.forcedVideoCodec = props.forcedVideoCodec; - props.allowTranscoding = props.allowTranscoding; + + // Remove null values: either set, or undefined + props.mediaNode = props.mediaNode ?? undefined; + props.forcedVideoCodec = props.forcedVideoCodec ?? undefined; + props.forcedVideoCodecResolved = props.forcedVideoCodecResolved ?? undefined; + props.allowTranscoding = props.allowTranscoding ?? undefined; if (!props.defaultRecordingProperties) { props.defaultRecordingProperties = {}; diff --git a/openvidu-node-client/src/SessionProperties.ts b/openvidu-node-client/src/SessionProperties.ts index adb4b145..9b23203a 100644 --- a/openvidu-node-client/src/SessionProperties.ts +++ b/openvidu-node-client/src/SessionProperties.ts @@ -78,11 +78,21 @@ export interface SessionProperties { * If defined here, this parameter has prevalence over * OPENVIDU_STREAMS_FORCED_VIDEO_CODEC. * - * Default is [[VideoCodec.VP8]] for Kurento, and - * [[VideoCodec.NONE]] for mediasoup. + * Default is [[VideoCodec.MEDIA_SERVER_PREFERRED]]. */ forcedVideoCodec?: VideoCodec; + /** + * Actual video codec that will be forcibly used for this session. + * This is the same as forcedVideoCodec, except when its value + * is [[VideoCodec.MEDIA_SERVER_PREFERRED]]: in that case, OpenVidu Server + * will fill this property with a resolved value, depending on what is the + * configured media server. + * + * @hidden + */ + forcedVideoCodecResolved?: VideoCodec; + /** * It defines if you want to allow transcoding in the media server or not * when [[forcedVideoCodec]] is not compatible with the browser/client. 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 e2fa865d..da0bd0fa 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 @@ -380,7 +380,7 @@ public class KurentoSessionManager extends SessionManager { KurentoParticipant kParticipant = (KurentoParticipant) participant; KurentoSession kSession = kParticipant.getSession(); boolean isTranscodingAllowed = kSession.getSessionProperties().isTranscodingAllowed(); - VideoCodec forcedVideoCodec = kSession.getSessionProperties().forcedVideoCodec(); + VideoCodec forcedVideoCodec = kSession.getSessionProperties().forcedVideoCodecResolved(); final String streamId = kParticipant.generateStreamId(kurentoOptions); @@ -392,22 +392,6 @@ public class KurentoSessionManager extends SessionManager { log.warn("AllowTranscoding has no effect if the Media Server is not Kurento"); } - // Set appropriate value for the ForcedVideoCodec feature. - if (forcedVideoCodec == VideoCodec.MEDIA_SERVER_PREFERRED) { - final MediaServer mediaServer = openviduConfig.getMediaServer(); - switch (mediaServer) { - case mediasoup: - forcedVideoCodec = VideoCodec.NONE; - break; - case kurento: - default: - forcedVideoCodec = VideoCodec.VP8; - break; - } - - log.info("Media Server: {}, selected ForcedVideoCodec value: {}", mediaServer, forcedVideoCodec); - } - // Modify sdp if forced codec is defined if (forcedVideoCodec != VideoCodec.NONE && !participant.isIpcam()) { kurentoOptions.sdpOffer = sdpMunging.forceCodec(kurentoOptions.sdpOffer, participant, true, false, @@ -613,7 +597,7 @@ public class KurentoSessionManager extends SessionManager { WebrtcDebugEventType.sdpOffer, sdpOffer)); boolean isTranscodingAllowed = session.getSessionProperties().isTranscodingAllowed(); - VideoCodec forcedVideoCodec = session.getSessionProperties().forcedVideoCodec(); + VideoCodec forcedVideoCodec = session.getSessionProperties().forcedVideoCodecResolved(); // Modify server's SDPOffer if forced codec is defined if (forcedVideoCodec != VideoCodec.NONE && !participant.isIpcam()) { @@ -679,7 +663,7 @@ public class KurentoSessionManager extends SessionManager { // Client initiated negotiation. sdpString is the SDP Offer of the client boolean isTranscodingAllowed = session.getSessionProperties().isTranscodingAllowed(); - VideoCodec forcedVideoCodec = session.getSessionProperties().forcedVideoCodec(); + VideoCodec forcedVideoCodec = session.getSessionProperties().forcedVideoCodecResolved(); String sdpOffer = sdpString; // Modify sdp if forced codec is defined @@ -1236,7 +1220,7 @@ public class KurentoSessionManager extends SessionManager { private String mungeSdpOffer(Session kSession, Participant participant, String sdpOffer, boolean isPublisher) { boolean isTranscodingAllowed = kSession.getSessionProperties().isTranscodingAllowed(); - VideoCodec forcedVideoCodec = kSession.getSessionProperties().forcedVideoCodec(); + VideoCodec forcedVideoCodec = kSession.getSessionProperties().forcedVideoCodecResolved(); // Modify sdp if forced codec is defined if (forcedVideoCodec != VideoCodec.NONE && !participant.isIpcam()) { return sdpMunging.forceCodec(sdpOffer, participant, isPublisher, true, isTranscodingAllowed, 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 6e9e9889..cc7d40e1 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 @@ -726,20 +726,31 @@ public class SessionRestController { if (params != null) { + // Obtain primitive values from the params map String mediaModeString; String recordingModeString; - String forcedVideoCodec; + String forcedVideoCodecStr; Boolean allowTranscoding; try { mediaModeString = (String) params.get("mediaMode"); recordingModeString = (String) params.get("recordingMode"); customSessionId = (String) params.get("customSessionId"); - forcedVideoCodec = (String) params.get("forcedVideoCodec"); + forcedVideoCodecStr = (String) params.get("forcedVideoCodec"); allowTranscoding = (Boolean) params.get("allowTranscoding"); } catch (ClassCastException e) { throw new Exception("Type error in some parameter: " + e.getMessage()); } + // Parse obtained values into actual types + VideoCodec forcedVideoCodec = null; + try { + forcedVideoCodec = VideoCodec.valueOf(forcedVideoCodecStr); + } catch (NullPointerException e) { + // Not an error: "forcedVideoCodec" was not provided in params. + } catch (IllegalArgumentException e) { + throw new Exception("Invalid value for parameter 'forcedVideoCodec': " + e.getMessage()); + } + try { // Safe parameter retrieval. Default values if not defined if (recordingModeString != null) { @@ -761,11 +772,25 @@ public class SessionRestController { } builder = builder.customSessionId(customSessionId); } - if (forcedVideoCodec != null) { - builder = builder.forcedVideoCodec(VideoCodec.valueOf(forcedVideoCodec)); - } else { - builder = builder.forcedVideoCodec(openviduConfig.getOpenviduForcedCodec()); + + if (forcedVideoCodec == null) { + forcedVideoCodec = openviduConfig.getOpenviduForcedCodec(); } + builder = builder.forcedVideoCodec(forcedVideoCodec); + if (forcedVideoCodec == VideoCodec.MEDIA_SERVER_PREFERRED) { + switch (openviduConfig.getMediaServer()) { + case mediasoup: + builder = builder.forcedVideoCodecResolved(VideoCodec.NONE); + break; + case kurento: + default: + builder = builder.forcedVideoCodecResolved(VideoCodec.VP8); + break; + } + } else { + builder = builder.forcedVideoCodecResolved(forcedVideoCodec); + } + if (allowTranscoding != null) { builder = builder.allowTranscoding(allowTranscoding); } else { diff --git a/openvidu-server/src/main/java/io/openvidu/server/utils/SDPMunging.java b/openvidu-server/src/main/java/io/openvidu/server/utils/SDPMunging.java index c30febce..b4a4803f 100644 --- a/openvidu-server/src/main/java/io/openvidu/server/utils/SDPMunging.java +++ b/openvidu-server/src/main/java/io/openvidu/server/utils/SDPMunging.java @@ -187,7 +187,7 @@ public class SDPMunging { return mungedSdpOffer; } else { throw new OpenViduException(Code.FORCED_CODEC_NOT_FOUND_IN_SDPOFFER, - "Codec not supported by Media Server"); + "Codec not supported by Media Server: " + forcedVideoCodec); } } catch (OpenViduException e) {