openviu-testapp: on-demand turn configuration

pull/73/head
pabloFuente 2018-06-08 11:07:38 +02:00
parent b480eca0af
commit d8c98e0901
7 changed files with 171 additions and 61 deletions

View File

@ -535,11 +535,36 @@ export class Stream {
} }
private getIceServersConf(): RTCIceServer[] | undefined { private getIceServersConf(): RTCIceServer[] | undefined {
return !!this.session.openvidu.advancedConfiguration.iceServers ? let returnValue;
this.session.openvidu.advancedConfiguration.iceServers : if (!!this.session.openvidu.advancedConfiguration.iceServers) {
!!this.session.openvidu.turnCredentials ? returnValue = this.session.openvidu.advancedConfiguration.iceServers === 'freeice' ?
[this.session.openvidu.turnCredentials] : undefined :
undefined; this.session.openvidu.advancedConfiguration.iceServers;
} else if (this.session.openvidu.turnCredentials) {
returnValue = [this.session.openvidu.turnCredentials];
} else {
returnValue = undefined;
}
return returnValue;
} }
// tslint:disable:no-string-literal
/*getSelectedIceCandidate() {
return new Promise((resolve, reject) => {
const connectionDetails = {};
this.getRTCPeerConnection().getStats(null).then(stats => {
stats.result().forEach((report) => {
const selectedCandidatePair = report[Object.keys(report).filter(key => { return report[key].selected; })[0]]
, localICE = stats[selectedCandidatePair.localCandidateId]
, remoteICE = stats[selectedCandidatePair.remoteCandidateId];
connectionDetails['LocalAddress'] = [localICE.ipAddress, localICE.portNumber].join(':');
connectionDetails['RemoteAddress'] = [remoteICE.ipAddress, remoteICE.portNumber].join(':');
connectionDetails['LocalCandidateType'] = localICE.candidateType;
connectionDetails['RemoteCandidateType'] = remoteICE.candidateType;
resolve(connectionDetails);
});
});
});
}*/
} }

View File

@ -20,7 +20,7 @@ export interface OpenViduAdvancedConfiguration {
/** /**
* Array of [RTCIceServer](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer) to be used by OpenVidu Browser instead of the default free ice server array (got from [freeice](https://github.com/DamonOehlman/freeice) library) * Array of [RTCIceServer](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceServer) to be used by OpenVidu Browser instead of the default free ice server array (got from [freeice](https://github.com/DamonOehlman/freeice) library)
*/ */
iceServers?: RTCIceServer[]; iceServers?: RTCIceServer[] | string;
/** /**
* URL to a custom screen share extension for Chrome (always based on ours: [openvidu-screen-sharing-chrome-extension](https://github.com/OpenVidu/openvidu-screen-sharing-chrome-extension)) to be used instead of the default one. * URL to a custom screen share extension for Chrome (always based on ours: [openvidu-screen-sharing-chrome-extension](https://github.com/OpenVidu/openvidu-screen-sharing-chrome-extension)) to be used instead of the default one.

View File

@ -3257,7 +3257,8 @@
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -3278,12 +3279,14 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -3298,17 +3301,20 @@
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -3425,7 +3431,8 @@
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -3437,6 +3444,7 @@
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -3451,6 +3459,7 @@
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
@ -3458,12 +3467,14 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.2.4", "version": "2.2.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.1", "safe-buffer": "^5.1.1",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -3482,6 +3493,7 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -3562,7 +3574,8 @@
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -3574,6 +3587,7 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -3659,7 +3673,8 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.1", "version": "5.1.1",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -3695,6 +3710,7 @@
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -3714,6 +3730,7 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -3757,12 +3774,14 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.2", "version": "3.0.2",
"bundled": true, "bundled": true,
"dev": true "dev": true,
"optional": true
} }
} }
}, },

View File

@ -0,0 +1,28 @@
mat-radio-button {
margin-left: 5px;
font-size: 14px;
}
mat-radio-button:first-child {
margin-left: 0;
}
#turn-conf-label {
display: block;
font-size: 12px;
color: rgba(0, 0, 0, 0.54);
font-weight: 400;
margin-bottom: 5px;
}
.not-manual {
padding-top: 6px;
padding-bottom: 15px;
}
#manual-turn-div {
margin-top: 10px;
padding: 5px;
border: 1px solid #00000026;
border-radius: 3px;
}

View File

@ -0,0 +1,55 @@
<div>
<h2 mat-dialog-title>Session properties</h2>
<mat-dialog-content>
<mat-form-field>
<mat-select placeholder="MediaMode" [(ngModel)]="sessionProperties.mediaMode">
<mat-option *ngFor="let enumerator of enumToArray(mediaMode)" [value]="enumerator">
{{ enumerator }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-select placeholder="RecordingMode" [(ngModel)]="sessionProperties.recordingMode">
<mat-option *ngFor="let enumerator of enumToArray(recordingMode)" [value]="enumerator">
{{ enumerator }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-select placeholder="DefaultRecordingLayout" [(ngModel)]="sessionProperties.defaultRecordingLayout">
<mat-option *ngFor="let enumerator of enumToArray(defaultRecordingLayout)" [value]="enumerator">
{{ enumerator }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="this.sessionProperties.defaultRecordingLayout === 'CUSTOM'">
<input matInput placeholder="DefaultCustomLayout" [(ngModel)]="sessionProperties.defaultCustomLayout">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="CustomSessionId" [(ngModel)]="sessionProperties.customSessionId">
</mat-form-field>
<label id="turn-conf-label">Turn configuration</label>
<div [class.not-manual]="turnConf !== 'manual'">
<mat-radio-group name="Turn configuration" [(ngModel)]="turnConf">
<mat-radio-button value="auto">Auto</mat-radio-button>
<mat-radio-button value="freeice">Freeice</mat-radio-button>
<mat-radio-button value="manual">Manual</mat-radio-button>
</mat-radio-group>
<div *ngIf="turnConf === 'manual'" id="manual-turn-div">
<mat-form-field style="width: 100%">
<input matInput placeholder="url" [(ngModel)]="manualTurnConf.urls[0]">
</mat-form-field>
<mat-form-field style="width: 49%; padding-right: 2px">
<input matInput placeholder="user" [(ngModel)]="manualTurnConf.username">
</mat-form-field>
<mat-form-field style="width: 49%; padding-left: 2px">
<input matInput placeholder="pass" [(ngModel)]="manualTurnConf.credential">
</mat-form-field>
</div>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button [mat-dialog-close]="undefined">CANCEL</button>
<button mat-button [mat-dialog-close]="{sessionProperties: sessionProperties, turnConf: turnConf, manualTurnConf: manualTurnConf}">SAVE</button>
</mat-dialog-actions>
</div>

View File

@ -5,56 +5,24 @@ import { SessionProperties, MediaMode, RecordingMode, RecordingLayout } from 'op
@Component({ @Component({
selector: 'app-session-properties-dialog', selector: 'app-session-properties-dialog',
template: ` templateUrl: './session-properties-dialog.component.html',
<div> styleUrls: ['./session-properties-dialog.component.css']
<h2 mat-dialog-title>Session properties</h2>
<mat-dialog-content>
<mat-form-field>
<mat-select placeholder="MediaMode" [(ngModel)]="sessionProperties.mediaMode">
<mat-option *ngFor="let enumerator of enumToArray(mediaMode)" [value]="enumerator">
{{ enumerator }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-select placeholder="RecordingMode" [(ngModel)]="sessionProperties.recordingMode">
<mat-option *ngFor="let enumerator of enumToArray(recordingMode)" [value]="enumerator">
{{ enumerator }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-select placeholder="DefaultRecordingLayout" [(ngModel)]="sessionProperties.defaultRecordingLayout">
<mat-option *ngFor="let enumerator of enumToArray(defaultRecordingLayout)" [value]="enumerator">
{{ enumerator }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field *ngIf="this.sessionProperties.defaultRecordingLayout === 'CUSTOM'">
<input matInput placeholder="DefaultCustomLayout" [(ngModel)]="sessionProperties.defaultCustomLayout">
</mat-form-field>
<mat-form-field>
<input matInput placeholder="CustomSessionId" [(ngModel)]="sessionProperties.customSessionId">
</mat-form-field>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button [mat-dialog-close]="undefined">CANCEL</button>
<button mat-button [mat-dialog-close]="sessionProperties">SAVE</button>
</mat-dialog-actions>
</div>
`
}) })
export class SessionPropertiesDialogComponent { export class SessionPropertiesDialogComponent {
sessionProperties: SessionProperties; sessionProperties: SessionProperties;
turnConf: string;
manualTurnConf: RTCIceServer = {};
mediaMode = MediaMode; mediaMode = MediaMode;
recordingMode = RecordingMode; recordingMode = RecordingMode;
defaultRecordingLayout = RecordingLayout; defaultRecordingLayout = RecordingLayout;
constructor(public dialogRef: MatDialogRef<SessionPropertiesDialogComponent>, constructor(public dialogRef: MatDialogRef<SessionPropertiesDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: SessionProperties) { @Inject(MAT_DIALOG_DATA) public data) {
this.sessionProperties = data; this.sessionProperties = data.sessionProperties;
this.turnConf = data.turnConf;
this.manualTurnConf = data.manualTurnConf;
} }
enumToArray(enumerator: any) { enumToArray(enumerator: any) {

View File

@ -112,6 +112,9 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
publisherStopSpeaking: false publisherStopSpeaking: false
}; };
turnConf = 'auto';
manualTurnConf: RTCIceServer = { urls: [] };
events: OpenViduEvent[] = []; events: OpenViduEvent[] = [];
openviduError: any; openviduError: any;
@ -183,6 +186,12 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
this.OV = new OpenVidu(); this.OV = new OpenVidu();
if (this.turnConf === 'freeice') {
this.OV.setAdvancedConfiguration({ iceServers: 'freeice' });
} else if (this.turnConf === 'manual') {
this.OV.setAdvancedConfiguration({ iceServers: [this.manualTurnConf] });
}
this.session = this.OV.initSession(); this.session = this.OV.initSession();
this.updateSessionEvents({ this.updateSessionEvents({
@ -471,16 +480,22 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
openSessionPropertiesDialog() { openSessionPropertiesDialog() {
this.sessionProperties.customSessionId = this.sessionName; this.sessionProperties.customSessionId = this.sessionName;
const dialogRef = this.dialog.open(SessionPropertiesDialogComponent, { const dialogRef = this.dialog.open(SessionPropertiesDialogComponent, {
data: this.sessionProperties, data: {
width: '235px' sessionProperties: this.sessionProperties,
turnConf: this.turnConf,
manualTurnConf: this.manualTurnConf
},
width: '280px'
}); });
dialogRef.afterClosed().subscribe((result: SessionPropertiesAPI) => { dialogRef.afterClosed().subscribe((result) => {
if (!!result) { if (!!result) {
this.sessionProperties = result; this.sessionProperties = result.sessionProperties;
if (!!this.sessionProperties.customSessionId) { if (!!this.sessionProperties.customSessionId) {
this.sessionName = this.sessionProperties.customSessionId; this.sessionName = this.sessionProperties.customSessionId;
} }
this.turnConf = result.turnConf;
this.manualTurnConf = result.manualTurnConf;
} }
document.getElementById('session-settings-btn-' + this.index).classList.remove('cdk-program-focused'); document.getElementById('session-settings-btn-' + this.index).classList.remove('cdk-program-focused');
}); });