mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server+clients: add new forcedVideoCodecResolved session property
Fill a new SessionProperties member "forcedVideoCodecResolved" to contain the resolved value of "forcedVideoCodec", once the new MEDIA_SERVER_PREFERRED has been taken into account and translated into the appropriate option for each media server. The logic to decide how to translate MEDIA_SERVER_PREFERRED into a concrete forcedVideoCodec value is placed once in the REST entry point of session creation (SessionRestController.java). Afterwards, SessionProperties is just used as a simple storage for all session features, and serialized / passed around between server and client.pull/667/head
parent
0262c85ac0
commit
0cb9180ec5
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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 <code>forcedVideoCodec</code>, 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;
|
||||
}
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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 <code>forcedVideoCodec</code>, 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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue