mirror of https://github.com/OpenVidu/openvidu.git
openvidu-server, browser: Add Simulcast Publisher config (#680)
Simulcast is a per-Publisher configuration that allows to enable Simulcast senders on the client's PeerConnection of each sender. Simulcast is a WebRTC feature that sends multiple simultaneous streams with different video qualities, in order to let the media server decide which quality is best for which Subscriber on the receiving side. Enabled by default.pull/681/head
parent
2d93abbd02
commit
8e5f5d4cf4
|
@ -109,6 +109,10 @@ export class OpenVidu {
|
|||
* @hidden
|
||||
*/
|
||||
mediaServer: string;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
videoSimulcast: boolean;
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
|
@ -257,6 +261,7 @@ export class OpenVidu {
|
|||
publishVideo: (typeof properties.publishVideo !== 'undefined') ? properties.publishVideo : true,
|
||||
resolution: (typeof MediaStreamTrack !== 'undefined' && properties.videoSource instanceof MediaStreamTrack) ? undefined : ((typeof properties.resolution !== 'undefined') ? properties.resolution : '640x480'),
|
||||
videoSource: (typeof properties.videoSource !== 'undefined') ? properties.videoSource : undefined,
|
||||
videoSimulcast: properties.videoSimulcast,
|
||||
filter: properties.filter
|
||||
};
|
||||
} else {
|
||||
|
|
|
@ -1540,6 +1540,7 @@ export class Session extends EventDispatcher {
|
|||
this.openvidu.role = opts.role;
|
||||
this.openvidu.finalUserId = opts.finalUserId;
|
||||
this.openvidu.mediaServer = opts.mediaServer;
|
||||
this.openvidu.videoSimulcast = opts.videoSimulcast;
|
||||
this.capabilities = {
|
||||
subscribe: true,
|
||||
publish: this.openvidu.role !== 'SUBSCRIBER',
|
||||
|
|
|
@ -938,7 +938,8 @@ export class Stream {
|
|||
audio: this.hasAudio,
|
||||
video: this.hasVideo,
|
||||
},
|
||||
simulcast: this.session.openvidu.advancedConfiguration.enableSimulcastExperimental || false,
|
||||
simulcast:
|
||||
this.outboundStreamOpts.publisherProperties.videoSimulcast ?? this.session.openvidu.videoSimulcast,
|
||||
onIceCandidate: this.connection.sendIceCandidate.bind(this.connection),
|
||||
onIceConnectionStateException: (exceptionName: ExceptionEventName, message: string, data?: any) => { this.session.emitEvent('exception', [new ExceptionEvent(this.session, exceptionName, this, message, data)]) },
|
||||
iceServers: this.getIceServersConf(),
|
||||
|
@ -946,6 +947,11 @@ export class Stream {
|
|||
mediaServer: this.session.openvidu.mediaServer
|
||||
};
|
||||
|
||||
if (this.session.openvidu.mediaServer !== 'mediasoup') {
|
||||
// Simulcast is only supported by mediasoup
|
||||
config.simulcast = false;
|
||||
}
|
||||
|
||||
if (reconnect) {
|
||||
this.disposeWebRtcPeer();
|
||||
}
|
||||
|
|
|
@ -33,5 +33,6 @@ export interface LocalConnectionOptions {
|
|||
turnCredential: string;
|
||||
version: string;
|
||||
mediaServer: string;
|
||||
videoSimulcast: boolean;
|
||||
life: number;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,11 +71,4 @@ export interface OpenViduAdvancedConfiguration {
|
|||
*/
|
||||
noStreamPlayingEventExceptionTimeout?: number;
|
||||
|
||||
/**
|
||||
* Whether to enable simulcast for Publishers or not.
|
||||
*
|
||||
* Default to `false`.
|
||||
*/
|
||||
enableSimulcastExperimental?: boolean;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,16 @@ export interface PublisherProperties {
|
|||
*/
|
||||
videoSource?: string | MediaStreamTrack | boolean;
|
||||
|
||||
/**
|
||||
* Send Simulcast video.
|
||||
* Publishers will encode duplicate video streams with different qualities,
|
||||
* so the media server is able to select the most appropriate quality stream
|
||||
* for each Subscriber.
|
||||
* This setting is honored only if OpenVidu Server was configured to use the
|
||||
* mediasoup media server. Otherwise, Simulcast will be disabled.
|
||||
*/
|
||||
videoSimulcast?: boolean;
|
||||
|
||||
/**
|
||||
* **WARNING**: experimental option. This property may change in the near future
|
||||
*
|
||||
|
@ -89,4 +99,4 @@ export interface PublisherProperties {
|
|||
*/
|
||||
filter?: Filter;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -160,6 +160,7 @@ public class ProtocolElements {
|
|||
public static final String PARTICIPANTJOINED_SESSION_PARAM = "session";
|
||||
public static final String PARTICIPANTJOINED_VERSION_PARAM = "version";
|
||||
public static final String PARTICIPANTJOINED_MEDIASERVER_PARAM = "mediaServer";
|
||||
public static final String PARTICIPANTJOINED_SIMULCAST_PARAM = "videoSimulcast";
|
||||
public static final String PARTICIPANTJOINED_RECORD_PARAM = "record";
|
||||
public static final String PARTICIPANTJOINED_ROLE_PARAM = "role";
|
||||
public static final String PARTICIPANTJOINED_COTURNIP_PARAM = "coturnIp";
|
||||
|
|
|
@ -247,6 +247,16 @@ OPENVIDU_STREAMS_VIDEO_MAX_SEND_BANDWIDTH=1000
|
|||
# 0 means unconstrained
|
||||
OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH=300
|
||||
|
||||
# Send Simulcast video.
|
||||
# Publishers will encode duplicate video streams with different qualities,
|
||||
# so the media server is able to select the most appropriate quality stream
|
||||
# for each Subscriber.
|
||||
# This setting is honored only if OpenVidu Server was configured to use the
|
||||
# mediasoup media server. Otherwise, Simulcast will be disabled.
|
||||
# Values: true | false
|
||||
# Default: true
|
||||
#OPENVIDU_STREAMS_VIDEO_SIMULCAST=true
|
||||
|
||||
# All sessions of OpenVidu will try to force this codec. If OPENVIDU_STREAMS_ALLOW_TRANSCODING=true
|
||||
# when a codec can not be forced, transcoding will be allowed
|
||||
# Values: VP8, VP9, H264, NONE
|
||||
|
|
|
@ -217,8 +217,13 @@ public class OpenviduConfig {
|
|||
private boolean isTurnadminAvailable = false;
|
||||
|
||||
// Media Server properties
|
||||
|
||||
private MediaServer mediaServerInfo = MediaServer.kurento;
|
||||
|
||||
// Media properties
|
||||
|
||||
private boolean streamsVideoSimulcast = false;
|
||||
|
||||
// Plain config properties getters
|
||||
|
||||
public String getCoturnDatabaseDbname() {
|
||||
|
@ -281,6 +286,10 @@ public class OpenviduConfig {
|
|||
this.mediaServerInfo = mediaServerInfo;
|
||||
}
|
||||
|
||||
public boolean isStreamsVideoSimulcast() {
|
||||
return this.streamsVideoSimulcast;
|
||||
}
|
||||
|
||||
public String getOpenViduRecordingPath() {
|
||||
return this.openviduRecordingPath;
|
||||
}
|
||||
|
|
|
@ -165,6 +165,19 @@ public class SessionEventsHandler {
|
|||
result.addProperty(ProtocolElements.PARTICIPANTJOINED_MEDIASERVER_PARAM,
|
||||
this.openviduConfig.getMediaServer().name());
|
||||
|
||||
switch (this.openviduConfig.getMediaServer()) {
|
||||
case mediasoup:
|
||||
// mediasoup supports simulcast
|
||||
result.addProperty(ProtocolElements.PARTICIPANTJOINED_SIMULCAST_PARAM,
|
||||
this.openviduConfig.isStreamsVideoSimulcast());
|
||||
break;
|
||||
case kurento:
|
||||
default:
|
||||
// Kurento does not support simulcast
|
||||
result.addProperty(ProtocolElements.PARTICIPANTJOINED_SIMULCAST_PARAM, false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (participant.getToken() != null) {
|
||||
result.addProperty(ProtocolElements.PARTICIPANTJOINED_RECORD_PARAM, participant.getToken().record());
|
||||
if (participant.getToken().getRole() != null) {
|
||||
|
|
|
@ -114,6 +114,7 @@ public class ConfigRestController {
|
|||
json.addProperty("OPENVIDU_STREAMS_VIDEO_MIN_RECV_BANDWIDTH", openviduConfig.getVideoMinRecvBandwidth());
|
||||
json.addProperty("OPENVIDU_STREAMS_VIDEO_MAX_SEND_BANDWIDTH", openviduConfig.getVideoMaxSendBandwidth());
|
||||
json.addProperty("OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH", openviduConfig.getVideoMinSendBandwidth());
|
||||
json.addProperty("OPENVIDU_STREAMS_VIDEO_SIMULCAST", openviduConfig.isStreamsVideoSimulcast());
|
||||
json.addProperty("OPENVIDU_STREAMS_FORCED_VIDEO_CODEC", openviduConfig.getOpenviduForcedCodec().name());
|
||||
json.addProperty("OPENVIDU_STREAMS_ALLOW_TRANSCODING", openviduConfig.isOpenviduAllowingTranscoding());
|
||||
json.addProperty("OPENVIDU_SESSIONS_GARBAGE_INTERVAL", openviduConfig.getSessionGarbageInterval());
|
||||
|
|
|
@ -147,6 +147,12 @@
|
|||
"description": "Minimum video bandwidth sent from OpenVidu Server to clients, in kbps. 0 means unconstrained",
|
||||
"defaultValue": 300
|
||||
},
|
||||
{
|
||||
"name": "OPENVIDU_STREAMS_VIDEO_SIMULCAST",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Send Simulcast video.",
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"name": "OPENVIDU_STREAMS_FORCED_VIDEO_CODEC",
|
||||
"type": "java.lang.String",
|
||||
|
|
|
@ -42,6 +42,7 @@ OPENVIDU_STREAMS_VIDEO_MAX_RECV_BANDWIDTH=1000
|
|||
OPENVIDU_STREAMS_VIDEO_MIN_RECV_BANDWIDTH=300
|
||||
OPENVIDU_STREAMS_VIDEO_MAX_SEND_BANDWIDTH=1000
|
||||
OPENVIDU_STREAMS_VIDEO_MIN_SEND_BANDWIDTH=300
|
||||
OPENVIDU_STREAMS_VIDEO_SIMULCAST=true
|
||||
OPENVIDU_STREAMS_FORCED_VIDEO_CODEC=VP8
|
||||
OPENVIDU_STREAMS_ALLOW_TRANSCODING=false
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<mat-checkbox [(ngModel)]="publisherProperties.publishAudio" (click)="publisherProperties.publishAudio = !publisherProperties.publishAudio">Publish audio</mat-checkbox>
|
||||
<mat-checkbox [(ngModel)]="publisherProperties.publishVideo" (click)="publisherProperties.publishVideo = !publisherProperties.publishVideo">Publish video</mat-checkbox>
|
||||
<mat-checkbox [(ngModel)]="publisherProperties.mirror" (click)="publisherProperties.mirror = !publisherProperties.mirror">Mirror</mat-checkbox>
|
||||
<mat-checkbox [(ngModel)]="publisherProperties.videoSimulcast" (click)="publisherProperties.videoSimulcast = !publisherProperties.videoSimulcast">Video Simulcast</mat-checkbox>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-form-field>
|
||||
<input matInput placeholder="Audio source" [(ngModel)]="audioSource" [disabled]="(publisherProperties.audioSource === false)">
|
||||
|
@ -52,4 +53,4 @@
|
|||
<button id="close-btn" mat-button [mat-dialog-close]="initValue">CANCEL</button>
|
||||
<button id="save-btn" mat-button [mat-dialog-close]="setCloseValue()">SAVE</button>
|
||||
</mat-dialog-actions>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -121,7 +121,8 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
|||
resolution: '640x480',
|
||||
mirror: true,
|
||||
publishAudio: true,
|
||||
publishVideo: true
|
||||
publishVideo: true,
|
||||
videoSimulcast: true
|
||||
};
|
||||
|
||||
publisherPropertiesAux: PublisherProperties;
|
||||
|
@ -230,9 +231,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
this.OV = new OpenVidu();
|
||||
|
||||
const advancedConfiguration: OpenViduAdvancedConfiguration = {
|
||||
enableSimulcastExperimental: false
|
||||
};
|
||||
const advancedConfiguration: OpenViduAdvancedConfiguration = {};
|
||||
if (this.turnConf === 'freeice') {
|
||||
advancedConfiguration.iceServers = 'freeice';
|
||||
} else if (this.turnConf === 'manual') {
|
||||
|
|
Loading…
Reference in New Issue