openvidu-testapp API REST features

pull/73/head
pabloFuente 2018-05-18 12:46:41 +02:00
parent 65fb9505e9
commit f0a53a7701
10 changed files with 295 additions and 38 deletions

View File

@ -18,7 +18,8 @@ import {
MatChipsModule, MatChipsModule,
MatExpansionModule, MatExpansionModule,
MatSlideToggleModule, MatSlideToggleModule,
MatSidenavModule MatSidenavModule,
MatFormFieldModule
} from '@angular/material'; } from '@angular/material';
@NgModule({ @NgModule({
@ -41,7 +42,8 @@ import {
MatChipsModule, MatChipsModule,
MatExpansionModule, MatExpansionModule,
MatSlideToggleModule, MatSlideToggleModule,
MatSidenavModule MatSidenavModule,
MatFormFieldModule
], ],
}) })
export class AppMaterialModule { } export class AppMaterialModule { }

View File

@ -10,13 +10,15 @@ import { AppComponent } from './app.component';
import { TestSessionsComponent } from './components/test-sessions/test-sessions.component'; import { TestSessionsComponent } from './components/test-sessions/test-sessions.component';
import { TestApirestComponent } from './components/test-apirest/test-apirest.component'; import { TestApirestComponent } from './components/test-apirest/test-apirest.component';
import { OpenviduInstanceComponent } from './components/openvidu-instance/openvidu-instance.component'; import { OpenviduInstanceComponent } from './components/openvidu-instance/openvidu-instance.component';
import { ExtensionDialogComponent } from './components/openvidu-instance/extension-dialog.component'; import { ExtensionDialogComponent } from './components/dialogs/extension-dialog.component';
import { LocalRecordingDialogComponent } from './components/test-sessions/local-recording-dialog.component'; import { LocalRecordingDialogComponent } from './components/dialogs/local-recording-dialog.component';
import { OpenviduRestService } from './services/openvidu-rest.service'; import { OpenviduRestService } from './services/openvidu-rest.service';
import { OpenviduParamsService } from './services/openvidu-params.service'; import { OpenviduParamsService } from './services/openvidu-params.service';
import { TestFeedService } from './services/test-feed.service'; import { TestFeedService } from './services/test-feed.service';
import { MuteSubscribersService } from './services/mute-subscribers.service'; import { MuteSubscribersService } from './services/mute-subscribers.service';
import { SessionPropertiesDialogComponent } from './components/dialogs/session-properties-dialog.component';
import { SessionApiDialogComponent } from './components/dialogs/session-api-dialog.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -25,6 +27,8 @@ import { MuteSubscribersService } from './services/mute-subscribers.service';
TestSessionsComponent, TestSessionsComponent,
TestApirestComponent, TestApirestComponent,
ExtensionDialogComponent, ExtensionDialogComponent,
SessionPropertiesDialogComponent,
SessionApiDialogComponent,
LocalRecordingDialogComponent LocalRecordingDialogComponent
], ],
imports: [ imports: [
@ -43,6 +47,8 @@ import { MuteSubscribersService } from './services/mute-subscribers.service';
], ],
entryComponents: [ entryComponents: [
ExtensionDialogComponent, ExtensionDialogComponent,
SessionPropertiesDialogComponent,
SessionApiDialogComponent,
LocalRecordingDialogComponent LocalRecordingDialogComponent
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]

View File

@ -0,0 +1,112 @@
import { Component, Inject } from '@angular/core';
import { MatDialog, MAT_DIALOG_DATA, MatDialogConfig, MatDialogRef } from '@angular/material';
import { Session } from 'openvidu-browser';
import { OpenVidu as OpenViduAPI } from 'openvidu-node-client';
@Component({
selector: 'app-session-properties-dialog',
template: `
<div>
<h2 mat-dialog-title>API REST</h2>
<mat-dialog-content>
<button mat-button (click)="startRecording()">Start recording</button>
<button mat-button (click)="listRecordings()">List recordings</button>
<mat-divider></mat-divider>
<mat-form-field>
<input matInput placeholder="recordingId" [(ngModel)]="recordingId">
</mat-form-field>
<button mat-button (click)="stopRecording()" [disabled]="!recordingId">Stop recording</button>
<button mat-button (click)="getRecording()" [disabled]="!recordingId">Get recording</button>
<button mat-button (click)="deleteRecording()" [disabled]="!recordingId">Delete recording</button>
<mat-form-field *ngIf="!!response" id="response-text-area">
<textarea [(ngModel)]="response" matInput readonly></textarea>
</mat-form-field>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button [mat-dialog-close]="undefined">CLOSE</button>
</mat-dialog-actions>
</div>
`,
styles: [
'#response-text-area { width: 100%; color: #808080; }',
'#response-text-area textarea { resize: none; }',
'mat-dialog-content button, mat-divider { margin-bottom: 5px; }',
]
})
export class SessionApiDialogComponent {
OV: OpenViduAPI;
sessionId: string;
recordingId: string;
response: string;
constructor(public dialogRef: MatDialogRef<SessionApiDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data) {
this.OV = data.openVidu;
this.sessionId = data.sessionId;
}
startRecording() {
console.log('Starting recording');
this.OV.startRecording(this.sessionId)
.then(recording => {
this.response = 'Recording started [' + recording.id + ']';
})
.catch(error => {
this.response = 'Error [' + error.message + ']';
});
}
stopRecording() {
console.log('Stopping recording');
this.OV.stopRecording(this.recordingId)
.then(recording => {
this.response = 'Recording stopped [' + recording.id + ']';
})
.catch(error => {
this.response = 'Error [' + error.message + ']';
});
}
getRecording() {
console.log('Getting recording');
this.OV.getRecording(this.recordingId)
.then(recording => {
this.response = 'Recording got [' + recording.id + ']';
})
.catch(error => {
this.response = 'Error [' + error.message + ']';
});
}
listRecordings() {
console.log('Listing recordings');
this.OV.listRecordings()
.then(recordingList => {
let recordingIds = '';
recordingList.forEach((rec, index) => {
recordingIds += rec.id;
if (index !== recordingList.length - 1) {
recordingIds += ', ';
}
});
this.response = 'Recording list [' + recordingIds + ']';
})
.catch(error => {
this.response = 'Error [' + error.message + ']';
});
}
deleteRecording() {
console.log('Deleting recording');
this.OV.deleteRecording(this.recordingId)
.then(() => {
this.response = 'Recording deleted';
})
.catch(error => {
this.response = 'Error [' + error.message + ']';
});
}
}

View File

@ -0,0 +1,64 @@
import { Component, Inject } from '@angular/core';
import { MatDialog, MAT_DIALOG_DATA, MatDialogConfig, MatDialogRef } from '@angular/material';
import { SessionProperties, MediaMode, RecordingMode, RecordingLayout } from 'openvidu-node-client';
@Component({
selector: 'app-session-properties-dialog',
template: `
<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>
</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 {
sessionProperties: SessionProperties;
private mediaMode = MediaMode;
private recordingMode = RecordingMode;
private defaultRecordingLayout = RecordingLayout;
constructor(public dialogRef: MatDialogRef<SessionPropertiesDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: SessionProperties) {
this.sessionProperties = data;
}
enumToArray(enumerator: any) {
return Object.keys(enumerator);
}
}

View File

@ -18,11 +18,14 @@ mat-card.session-card {
} }
.session-form mat-form-field { .session-form mat-form-field {
width: 130px; width: 110px;
} }
.join-card { .join-card {
width: fit-content; width: fit-content;
min-height: 215px;
padding-top: 20px;
padding-bottom: 10px;
} }
.join-card mat-card-content { .join-card mat-card-content {
@ -33,6 +36,7 @@ mat-card.session-card {
border: 1px solid #e1e1e1; border: 1px solid #e1e1e1;
padding: 10px 15px 10px 15px; padding: 10px 15px 10px 15px;
background: #ffffff; background: #ffffff;
margin-top: 5px;
} }
.inner-card h4 { .inner-card h4 {
@ -93,7 +97,7 @@ mat-radio-button {
.event-list-div { .event-list-div {
display: inline-block; display: inline-block;
width: 130px; width: 130px;
height: 183.5px; height: 180px;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
} }
@ -133,6 +137,20 @@ mat-expansion-panel-header {
padding: 0 7px 0 9px !important; padding: 0 7px 0 9px !important;
} }
.secure-div mat-checkbox { .mat-icon-custom {
padding-right: 10px; width: 29px;
height: 29px;
line-height: 18px;
}
.mat-icon-custom-ic {
width: 20px;
height: 20px;
font-size: 20px;
line-height: 20px;
}
.session-btns-div {
margin-top: -14px;
margin-right: -14px;
} }

View File

@ -6,14 +6,7 @@
<mat-card-content> <mat-card-content>
<form class="session-form"> <form class="session-form">
<div class="secure-div"> <div fxLayout="row">
<mat-checkbox class="secure-session-checkbox" [disabled]="session" [(ngModel)]="secureSession" name="secureSession">SECURE</mat-checkbox>
<mat-form-field>
<input class="tokenInput" matInput placeholder="TOKEN" name="tokenInput" [(ngModel)]="tokenInput" [disabled]="!secureSession">
</mat-form-field>
</div>
<div>
<mat-form-field style="margin-right: 10px"> <mat-form-field style="margin-right: 10px">
<input matInput placeholder="Session name" name="sessionName" [(ngModel)]="sessionName" [disabled]="session"> <input matInput placeholder="Session name" name="sessionName" [(ngModel)]="sessionName" [disabled]="session">
</mat-form-field> </mat-form-field>
@ -21,6 +14,16 @@
<mat-form-field> <mat-form-field>
<input matInput placeholder="Client data" name="clientData" [(ngModel)]="clientData" [disabled]="session"> <input matInput placeholder="Client data" name="clientData" [(ngModel)]="clientData" [disabled]="session">
</mat-form-field> </mat-form-field>
<div fxLayout="column" class="session-btns-div">
<button mat-icon-button title="Session properties" id="session-settings-btn" class="mat-icon-custom" (click)="openSessionPropertiesDialog()" [disabled]="session">
<mat-icon class="mat-icon-custom-ic" aria-label="Session properties button">settings</mat-icon>
</button>
<button mat-icon-button title="Session API" id="session-api-btn" class="mat-icon-custom" (click)="openSessionApiDialog()">
<mat-icon class="mat-icon-custom-ic" aria-label="Session API button">cloud_circle</mat-icon>
</button>
</div>
</div> </div>
<div> <div>

View File

@ -9,11 +9,21 @@ import {
LocalRecorder, VideoInsertMode, StreamEvent, ConnectionEvent, LocalRecorder, VideoInsertMode, StreamEvent, ConnectionEvent,
SessionDisconnectedEvent, SignalEvent, RecordingEvent, VideoElementEvent SessionDisconnectedEvent, SignalEvent, RecordingEvent, VideoElementEvent
} from 'openvidu-browser'; } from 'openvidu-browser';
import {
OpenVidu as OpenViduAPI,
Session as SessionAPI,
SessionProperties as SessionPropertiesAPI,
MediaMode,
RecordingMode,
RecordingLayout
} from 'openvidu-node-client';
import { MatDialog, MatDialogRef } from '@angular/material'; import { MatDialog, MatDialogRef } from '@angular/material';
import { ExtensionDialogComponent } from './extension-dialog.component'; import { ExtensionDialogComponent } from '../dialogs/extension-dialog.component';
import { LocalRecordingDialogComponent } from '../test-sessions/local-recording-dialog.component'; import { LocalRecordingDialogComponent } from '../dialogs/local-recording-dialog.component';
import { TestFeedService } from '../../services/test-feed.service'; import { TestFeedService } from '../../services/test-feed.service';
import { MuteSubscribersService } from '../../services/mute-subscribers.service'; import { MuteSubscribersService } from '../../services/mute-subscribers.service';
import { SessionPropertiesDialogComponent } from '../dialogs/session-properties-dialog.component';
import { SessionApiDialogComponent } from '../dialogs/session-api-dialog.component';
declare var $: any; declare var $: any;
@ -47,10 +57,8 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
sessionConf: SessionConf; sessionConf: SessionConf;
// Session join data // Session join data
secureSession = false;
clientData: string; clientData: string;
sessionName: string; sessionName: string;
tokenInput: string;
// Session options // Session options
subscribeTo; subscribeTo;
@ -79,12 +87,21 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
disableActiveVideo = false; disableActiveVideo = false;
disableRadioButtons = false; disableRadioButtons = false;
// OpenVidu objects // OpenVidu Browser objects
OV: OpenVidu; OV: OpenVidu;
session: Session; session: Session;
publisher: Publisher; publisher: Publisher;
subscribers = {}; subscribers = {};
// OpenVidu Node Client objects
sessionProperties: SessionPropertiesAPI = {
mediaMode: MediaMode.ROUTED,
recordingMode: RecordingMode.MANUAL,
defaultRecordingLayout: RecordingLayout.BEST_FIT,
defaultCustomLayout: '',
customSessionId: ''
};
// Session audio and video status // Session audio and video status
audioMuted = false; audioMuted = false;
videoMuted = false; videoMuted = false;
@ -108,7 +125,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
constructor( constructor(
private changeDetector: ChangeDetectorRef, private changeDetector: ChangeDetectorRef,
private extensionDialog: MatDialog, private dialog: MatDialog,
private recordDialog: MatDialog, private recordDialog: MatDialog,
private testFeedService: TestFeedService, private testFeedService: TestFeedService,
private muteSubscribersService: MuteSubscribersService, private muteSubscribersService: MuteSubscribersService,
@ -171,17 +188,9 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
this.leaveSession(); this.leaveSession();
} }
let token; this.getToken().then(token => {
this.joinSessionShared(token);
if (this.secureSession) { });
token = this.tokenInput;
} else {
token = 'wss://'
+ this.removeHttps(this.openviduUrl)
+ '?sessionId=' + this.sessionName
+ '&secret=' + this.openviduSecret;
}
this.joinSessionShared(token);
} }
private joinSessionShared(token): void { private joinSessionShared(token): void {
@ -580,7 +589,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
console.warn(err); console.warn(err);
this.openviduError = err; this.openviduError = err;
if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') { if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') {
this.extensionDialog.open(ExtensionDialogComponent, { this.dialog.open(ExtensionDialogComponent, {
data: { url: err.message }, data: { url: err.message },
disableClose: true, disableClose: true,
width: '250px' width: '250px'
@ -856,7 +865,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
console.warn(err); console.warn(err);
this.openviduError = err; this.openviduError = err;
if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') { if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') {
this.extensionDialog.open(ExtensionDialogComponent, { this.dialog.open(ExtensionDialogComponent, {
data: { url: err.message }, data: { url: err.message },
disableClose: true, disableClose: true,
width: '250px' width: '250px'
@ -905,7 +914,7 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
console.error(err); console.error(err);
this.openviduError = err; this.openviduError = err;
if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') { if (err.name === 'SCREEN_EXTENSION_NOT_INSTALLED') {
this.extensionDialog.open(ExtensionDialogComponent, { this.dialog.open(ExtensionDialogComponent, {
data: { url: err.message }, data: { url: err.message },
disableClose: true, disableClose: true,
width: '250px' width: '250px'
@ -1027,4 +1036,47 @@ export class OpenviduInstanceComponent implements OnInit, OnChanges, OnDestroy {
}); });
} }
openSessionPropertiesDialog() {
this.sessionProperties.customSessionId = this.sessionName;
const dialogRef = this.dialog.open(SessionPropertiesDialogComponent, {
data: this.sessionProperties,
width: '235px'
});
dialogRef.afterClosed().subscribe((result: SessionPropertiesAPI) => {
if (!!result) {
this.sessionProperties = result;
if (!!this.sessionProperties.customSessionId) {
this.sessionName = this.sessionProperties.customSessionId;
}
}
document.getElementById('session-settings-btn').classList.remove('cdk-program-focused');
});
}
openSessionApiDialog() {
const dialogRef = this.dialog.open(SessionApiDialogComponent, {
data: {
openVidu: new OpenViduAPI(this.openviduUrl, this.openviduSecret),
sessionId: !!this.session ? this.session.sessionId : this.sessionName
},
width: '280px'
});
dialogRef.afterClosed().subscribe((result: string) => {
document.getElementById('session-api-btn').classList.remove('cdk-program-focused');
});
}
getToken(): Promise<string> {
const OV_NodeClient = new OpenViduAPI(this.openviduUrl, this.openviduSecret);
if (!this.sessionProperties.customSessionId) {
this.sessionProperties.customSessionId = this.sessionName;
}
return OV_NodeClient.createSession(this.sessionProperties)
.then(session_NodeClient => {
return session_NodeClient.generateToken();
});
}
} }

View File

@ -61,7 +61,7 @@
<div id="table-row" fxLayout="row" fxLayoutGap="20px" fxLayoutAlign="start"> <div id="table-row" fxLayout="row" fxLayoutGap="20px" fxLayoutAlign="start">
<div fxLayout="column" fxFlex="65" fxFlexAlign="start" fxFill> <div fxLayout="column" fxFlex="65" fxFlexAlign="start" fxFill>
<table> <table class="api-rest-table">
<tr> <tr>
<th *ngIf="this.data.length > 1">Selection</th> <th *ngIf="this.data.length > 1">Selection</th>
<th class="first-col">Session IDs</th> <th class="first-col">Session IDs</th>